From 0a28c57f1d3eec2eb660d5d91911543e1ad88d5a Mon Sep 17 00:00:00 2001 From: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Date: Sat, 25 May 2024 04:04:46 +0000 Subject: [PATCH 1/6] refactor(ghjk.ts): replace secureConfig with hack.ts --- README.md | 4 +- check.ts | 1 + deno.jsonc | 1 + examples/envs/ghjk.ts | 31 ++++ examples/kitchen/ghjk.ts | 100 +++++++++++ examples/protoc/ghjk.ts | 7 - examples/tasks/ghjk.ts | 6 +- files/deno/worker.ts | 2 +- files/mod.ts | 156 +++++++++-------- ghjk.ts | 22 +-- hack.ts | 21 +++ mod.ts | 350 ++++++++++++++++++++++++--------------- modules/tasks/deno.ts | 2 +- tests/envHooks.ts | 4 +- tests/envs.ts | 14 +- tests/ports.ts | 40 +++-- tests/reloadHooks.ts | 20 ++- tests/tasks.ts | 15 +- tests/utils.ts | 68 ++------ utils/mod.ts | 13 ++ 20 files changed, 555 insertions(+), 322 deletions(-) create mode 100644 examples/envs/ghjk.ts create mode 100644 examples/kitchen/ghjk.ts delete mode 100644 examples/protoc/ghjk.ts create mode 100644 hack.ts diff --git a/README.md b/README.md index 80bf19a1..63eb8ea1 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,9 @@ for tasks that are meant to be common dependencies of other tasks. ### Secure configs -Certain options are configured through the `secureConfig` object. +To improve ergonmoics, the typescript ghjkfile implementation exports simple functions and objects that mutate some global variable. +This also means that any script you import, if it knows the URL of the exact ghjk implementation you're using, can import this authoring module and mess with your ghjkfile. +Certain options for your file are thus only read from an export called `secureConfig` that'll host some of the more sensetive configurations. These include: ```ts import { env, stdSecureConfig } from "https://.../ghjk/mod.ts"; diff --git a/check.ts b/check.ts index d2fd45a2..0e1f3662 100755 --- a/check.ts +++ b/check.ts @@ -6,6 +6,7 @@ import { $ } from "./utils/mod.ts"; const files = (await Array.fromAsync( $.path(import.meta.url).parentOrThrow().expandGlob("**/*.ts", { exclude: [ + ".git", "play.ts", ".ghjk/**", ".deno-dir/**", diff --git a/deno.jsonc b/deno.jsonc index a2187dd4..310d5082 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -6,6 +6,7 @@ }, "fmt": { "exclude": [ + "*.md", "**/*.md", ".ghjk/**", ".deno-dir/**", diff --git a/examples/envs/ghjk.ts b/examples/envs/ghjk.ts new file mode 100644 index 00000000..3a2e7c5d --- /dev/null +++ b/examples/envs/ghjk.ts @@ -0,0 +1,31 @@ +export { sophon } from "../../hack.ts"; +import { config, env, install, task } from "../../hack.ts"; +import * as ports from "../../ports/mod.ts"; + +config({ + // we can change which environment + // is activated by default for example + // when we enter the directory + defaultEnv: "main", + // set the env all others envs will by + // default inherit from + defaultBaseEnv: "main", +}); + +env("test", { + installs: [ports.unzip()], +}); + +env("ci") + .install(ports.opentofu_ghrel()); + +// top level `install` calls just +// go to an enviroment called "main" +install(ports.protoc()); + +// we can modify "main" directly +env("main") + // hooks execute when environments are + // activated/deactivated in interactive shells + .onEnter(task(($) => $`echo enter`)) + .onExit(task(($) => $`echo exit`)); diff --git a/examples/kitchen/ghjk.ts b/examples/kitchen/ghjk.ts new file mode 100644 index 00000000..a8eed12b --- /dev/null +++ b/examples/kitchen/ghjk.ts @@ -0,0 +1,100 @@ +import { stdDeps } from "../../files/mod.ts"; +import { file } from "../../mod.ts"; +import * as ports from "../../ports/mod.ts"; + +const ghjk = file({ + // configre an empty env so that no ports are avail by default in our workdir + defaultEnv: "empty", + envs: [{ name: "empty", inherit: false }], + // we wan't all other envs to start from empty unless they opt otherwise + defaultBaseEnv: "empty", + + // we won't use the following for now + // but they pretty much configure the "main" env + allowedBuildDeps: [], + installs: [], + stdDeps: true, + enableRuntimes: true, + // tasks aren't attached to envs + // but have their own env + tasks: [], +}); + +// we need this export for this file to be a valid ghjkfile +// it's the one thing used by the ghjk host implementation to +// interact with your ghjkfile +export const sophon = ghjk.sophon; + +const { install, env, task } = ghjk; + +// we can configure main like this as well +env("main") + // provision env vars to be acccessbile in the env + .var("RUST_LOG", "info,actix=warn") + // provision programs to be avail in the env + .install(ports.jq_ghrel()) + .allowedBuildDeps([ + // ports can use the following installs at build time + // very WIP mechanism but this is meant to prevent ports from + // pulling whatever dependency they want at build time unless + // explicityl allowed to do so + ports.cpy_bs({ version: "3.8.18", releaseTag: "20240224" }), + ports.node({}), + ports.rust({ version: "stable" }), + // add the std deps including the runtime ports. + // These includes node and python but still, precedence is given + // to our configuration of those ports above + ...stdDeps({ enableRuntimes: true }), + ]); + +// these top level installs go to the main env as well +install( + ports.rust({ version: "stable" }), + ports.protoc(), +); + +const ci = env("ci", { + // this inherits from main so it gets protoc and curl + inherit: "main", + // extra installs + installs: [ports.jq_ghrel()], + // it has extra allowed deps + allowedBuildDeps: [ports.node()], + // more env vars + vars: { + CI: 1, + }, + desc: "do ci stuff", +}); + +// tasks are invocable from the cli +task("install-app", ($) => $`cargo fetch`); + +task("build-app", { + dependsOn: "install-app", + // the task's env inherits from ci + inherit: ci.name, + // it can add more items to that env + installs: [], + // vars + vars: { + RUST_BACKTRACE: 1, + }, + // allowed build deps + allowedBuildDeps: [ports.zstd()], + desc: "build the app", + fn: async ($) => { + await $`cargo build -p app`; + // we can access tar here from the ci env + await $`tar xcv ./target/debug/app -o app.tar.gz`; + }, +}); + +env("dev") + .inherit("main") + // we can set tasks to run on activation/decativation + .onEnter(task(($) => $`echo enter`)) + .onEnter(task({ + workingDir: "..", + fn: ($) => $`ls`, + })); diff --git a/examples/protoc/ghjk.ts b/examples/protoc/ghjk.ts deleted file mode 100644 index a194ecf7..00000000 --- a/examples/protoc/ghjk.ts +++ /dev/null @@ -1,7 +0,0 @@ -export { ghjk } from "../../mod.ts"; -import { install } from "../../mod.ts"; -import protoc from "../../ports/protoc.ts"; - -install( - protoc(), -); diff --git a/examples/tasks/ghjk.ts b/examples/tasks/ghjk.ts index 225ed3a7..e4d5808a 100644 --- a/examples/tasks/ghjk.ts +++ b/examples/tasks/ghjk.ts @@ -1,5 +1,5 @@ -export { ghjk } from "../../mod.ts"; -import { logger, task } from "../../mod.ts"; +export { sophon } from "../../hack.ts"; +import { logger, task } from "../../hack.ts"; import * as ports from "../../ports/mod.ts"; task("greet", async ($, { argv: [name] }) => { @@ -9,7 +9,7 @@ task("greet", async ($, { argv: [name] }) => { const ha = task({ name: "ha", installs: [ports.protoc()], - envVars: { STUFF: "stuffier" }, + vars: { STUFF: "stuffier" }, async fn($) { await $`echo $STUFF; protoc --version; diff --git a/files/deno/worker.ts b/files/deno/worker.ts index 57c8201d..f6e641f0 100644 --- a/files/deno/worker.ts +++ b/files/deno/worker.ts @@ -37,7 +37,7 @@ async function serializeConfig(uri: string, envVars: Record) { const { setup: setupLogger } = await import("../../utils/logger.ts"); setupLogger(); const mod = await import(uri); - const rawConfig = await mod.ghjk.getConfig(uri, mod.secureConfig); + const rawConfig = await mod.sophon.getConfig(uri, mod.secureConfig); const config = JSON.parse(JSON.stringify(rawConfig)); return { config, diff --git a/files/mod.ts b/files/mod.ts index 7a04da23..61421e69 100644 --- a/files/mod.ts +++ b/files/mod.ts @@ -46,7 +46,7 @@ import type { export type EnvDefArgs = { name: string; installs?: InstallConfigFat[]; - allowedPortDeps?: AllowedPortDep[]; + allowedBuildDeps?: (InstallConfigFat | AllowedPortDep)[]; /** * If true or not set, will base the task's env on top * of the default env (usually `main`). If false, will build on @@ -55,7 +55,7 @@ export type EnvDefArgs = { */ inherit?: string | boolean; desc?: string; - vars?: Record; + vars?: Record; /** * Task to execute when environment is activated. */ @@ -84,10 +84,10 @@ export type TaskFn = ( export type TaskDefArgs = { name?: string; desc?: string; - dependsOn?: string[]; + dependsOn?: string | string[]; workingDir?: string | Path; - envVars?: Record; - allowedPortDeps?: AllowedPortDep[]; + vars?: Record; + allowedBuildDeps?: (InstallConfigFat | AllowedPortDep)[]; installs?: InstallConfigFat[]; inherit?: string | boolean; }; @@ -160,10 +160,13 @@ export class Ghjkfile { logger(import.meta).debug("install added", config); } - setAllowedPortDeps(setId: string, deps: AllowedPortDep[]) { + setAllowedPortDeps( + setId: string, + deps: (InstallConfigFat | AllowedPortDep)[], + ) { const set = this.#getSet(setId); set.allowedDeps = Object.fromEntries( - deps.map(( + reduceAllowedDeps(deps).map(( dep, ) => [dep.manifest.name, dep]), ); @@ -224,8 +227,8 @@ export class Ghjkfile { if (args.installs) { env.install(...args.installs); } - if (args.allowedPortDeps) { - env.allowedPortDeps(args.allowedPortDeps); + if (args.allowedBuildDeps) { + env.allowedBuildDeps(args.allowedBuildDeps); } if (args.desc) { env.desc(args.desc); @@ -259,22 +262,22 @@ export class Ghjkfile { } toConfig( - { defaultEnv, defaultBaseEnv, masterPortDepAllowList }: { + { defaultEnv, defaultBaseEnv }: { defaultEnv: string; defaultBaseEnv: string; ghjkfileUrl: string; - masterPortDepAllowList: AllowedPortDep[]; }, ) { + // make sure referenced envs exist + this.addEnv({ name: defaultEnv }); + this.addEnv({ name: defaultBaseEnv }); try { const envsConfig = this.#processEnvs(defaultEnv, defaultBaseEnv); const tasksConfig = this.#processTasks( envsConfig, defaultBaseEnv, ); - const portsConfig = this.#processInstalls( - masterPortDepAllowList ?? stdDeps(), - ); + const portsConfig = this.#processInstalls(); const config: SerializedConfig = { blackboard: Object.fromEntries(this.#bb.entries()), @@ -333,7 +336,7 @@ export class Ghjkfile { const final = finalizer(); const envBaseResolved = typeof final.inherit === "string" ? final.inherit - : final.inherit && defaultBaseEnv != final.name + : (final.inherit !== false) && defaultBaseEnv != final.name ? defaultBaseEnv : null; all[final.name] = { ...final, envBaseResolved }; @@ -408,10 +411,10 @@ export class Ghjkfile { }; const hooks = [ ...final.onEnterHookTasks.map( - (key) => [key, "hook.onEnter.posixExec"] as const, + (key) => [key, "hook.onEnter.ghjkTask"] as const, ), ...final.onExitHookTasks.map( - (key) => [key, "hook.onExit.posixExec"] as const, + (key) => [key, "hook.onExit.ghjkTask"] as const, ), ].map(([taskKey, ty]) => { const task = this.#tasks.get(taskKey); @@ -425,8 +428,7 @@ export class Ghjkfile { } if (task.ty == "denoFile@v1") { const prov: InlineTaskHookProvision = { - ty: "inline.hook.ghjkTask", - finalTy: ty, + ty, taskKey, }; return prov; @@ -494,9 +496,9 @@ export class Ghjkfile { ); for (const [key, args] of this.#tasks) { if (args.dependsOn && args.dependsOn.length > 0) { - const depKeys = args.dependsOn.map((nameOrKey) => - nameToKey[nameOrKey] ?? nameOrKey - ); + const depKeys = + (Array.isArray(args.dependsOn) ? args.dependsOn : [args.dependsOn]) + .map((nameOrKey) => nameToKey[nameOrKey] ?? nameOrKey); deps.set(key, depKeys); for (const depKey of depKeys) { const depRevDeps = revDeps.get(depKey); @@ -522,37 +524,45 @@ export class Ghjkfile { const args = this.#tasks.get(key)!; const { workingDir, desc, dependsOn, inherit } = args; - const envBaseResolved = typeof inherit === "string" - ? inherit - : inherit - ? defaultBaseEnv - : null; - - const envBaseRecipe = envBaseResolved - ? envsConfig.envs[envBaseResolved] - : null; - const taskEnvRecipe: EnvRecipe = { provides: [], }; - const taskInstallSet: InstallSet = { installs: args.installs ?? [], allowedDeps: Object.fromEntries( - (args.allowedPortDeps ?? []).map((dep) => [dep.manifest.name, dep]), + reduceAllowedDeps(args.allowedBuildDeps ?? []).map(( + dep, + ) => [dep.manifest.name, dep]), ), }; - const mergedEnvVars = args.envVars ?? {}; + const envBaseResolved = typeof inherit === "string" + ? inherit + : (inherit !== false) + ? defaultBaseEnv + : null; + + const envBaseRecipe = envBaseResolved + ? envsConfig.envs[envBaseResolved] + : null; + + const mergedEnvVars = args.vars ?? {}; if (envBaseRecipe) { for ( const prov of envBaseRecipe .provides as ( | WellKnownProvision | InstallSetRefProvision + | InlineTaskHookProvision )[] ) { - if (prov.ty == "posix.envVar") { + // task envs don't need hooks + if ( + prov.ty == "hook.onEnter.ghjkTask" || + prov.ty == "hook.onExit.ghjkTask" + ) { + continue; + } else if (prov.ty == "posix.envVar") { if (!mergedEnvVars[prov.key]) { mergedEnvVars[prov.key] = prov.val; } @@ -591,7 +601,11 @@ export class Ghjkfile { ...Object.entries(mergedEnvVars).map(( [key, val], ) => { - const prov: WellKnownProvision = { ty: "posix.envVar", key, val }; + const prov: WellKnownProvision = { + ty: "posix.envVar", + key, + val: val.toString(), + }; return prov; }), ); @@ -606,9 +620,14 @@ export class Ghjkfile { ? workingDir.toString() : workingDir, desc, - dependsOn: dependsOn?.map((keyOrHash) => - localToFinalKey[nameToKey[keyOrHash] ?? keyOrHash] - ), + ...dependsOn + ? { + dependsOn: (Array.isArray(dependsOn) ? dependsOn : [dependsOn]) + ?.map((keyOrHash) => + localToFinalKey[nameToKey[keyOrHash] ?? keyOrHash] + ), + } + : {}, envHash, }; const taskHash = objectHash(def); @@ -670,12 +689,16 @@ export class Ghjkfile { env.provides = env.provides.map( (prov) => { if ( - prov.ty == "inline.hook.ghjkTask" + prov.ty == "hook.onEnter.ghjkTask" || + prov.ty == "hook.onExit.ghjkTask" ) { + logger().warn("caught"); const inlineProv = prov as InlineTaskHookProvision; const taskKey = localToFinalKey[inlineProv.taskKey]; const out: WellKnownProvision = { - ty: inlineProv.finalTy, + ty: /onEnter/.test(prov.ty) + ? "hook.onEnter.posixExec" + : "hook.onExit.posixExec", program: "ghjk", arguments: ["x", taskKey], }; @@ -689,28 +712,13 @@ export class Ghjkfile { return moduleConfig; } - #processInstalls(masterAllowList: AllowedPortDep[]) { + #processInstalls() { const out: PortsModuleConfigHashed = { sets: {}, }; - const masterPortDepAllowList = Object.fromEntries( - masterAllowList.map((dep) => [dep.manifest.name, dep] as const), - ); for ( const [setId, set] of this.#installSets.entries() ) { - for (const [portName, _] of Object.entries(set.allowedDeps)) { - if (!masterPortDepAllowList[portName]) { - throw new Error( - `"${portName}" is in allowedPortDeps list of install set "${setId}" but not in the masterPortDepAllowList`, - ); - } - } - for (const [name, hash] of Object.entries(masterPortDepAllowList)) { - if (!set.allowedDeps[name]) { - set.allowedDeps[name] = hash; - } - } out.sets[setId] = { installs: set.installs.map((inst) => this.#addToBlackboard(inst)), allowedDeps: this.#addToBlackboard(Object.fromEntries( @@ -741,7 +749,7 @@ export class EnvBuilder { #installSetId: string; #file: Ghjkfile; #inherit: string | boolean = true; - #vars: Record = {}; + #vars: Record = {}; #desc?: string; #onEnterHookTasks: string[] = []; #onExitHookTasks: string[] = []; @@ -757,7 +765,9 @@ export class EnvBuilder { name: this.name, installSetId: this.#installSetId, inherit: this.#inherit, - vars: this.#vars, + vars: Object.fromEntries( + Object.entries(this.#vars).map(([key, val]) => [key, val.toString()]), + ), desc: this.#desc, onExitHookTasks: this.#onExitHookTasks, onEnterHookTasks: this.#onEnterHookTasks, @@ -780,9 +790,10 @@ export class EnvBuilder { } /** + * Configure the build time deps allowed to be used by ports. * This is treated as a single set and will replace previously any configured set. */ - allowedPortDeps(deps: AllowedPortDep[]) { + allowedBuildDeps(deps: (AllowedPortDep | InstallConfigFat)[]) { this.#file.setAllowedPortDeps(this.#installSetId, deps); return this; } @@ -798,7 +809,7 @@ export class EnvBuilder { /** * Add multiple environment variable. */ - vars(envVars: Record) { + vars(envVars: Record) { Object.assign(this.#vars, envVars); return this; } @@ -870,9 +881,22 @@ function task$( } type InlineTaskHookProvision = Provision & { - ty: "inline.hook.ghjkTask"; - finalTy: - | "hook.onEnter.posixExec" - | "hook.onExit.posixExec"; + ty: "hook.onExit.ghjkTask" | "hook.onEnter.ghjkTask"; taskKey: string; }; + +export function reduceAllowedDeps( + deps: (AllowedPortDep | InstallConfigFat)[], +): AllowedPortDep[] { + return deps.map( + (dep: any) => { + const res = portsValidators.allowedPortDep.safeParse(dep); + if (res.success) return res.data; + const out: AllowedPortDep = { + manifest: dep.port, + defaultInst: thinInstallConfig(dep), + }; + return portsValidators.allowedPortDep.parse(out); + }, + ); +} diff --git a/ghjk.ts b/ghjk.ts index e5589430..97244623 100644 --- a/ghjk.ts +++ b/ghjk.ts @@ -1,7 +1,12 @@ -export { ghjk } from "./mod.ts"; -import { $, env, install, stdSecureConfig, task } from "./mod.ts"; +export { sophon } from "./hack.ts"; +import { config, install } from "./hack.ts"; import * as ports from "./ports/mod.ts"; +config({ + defaultBaseEnv: "test", + enableRuntimes: true, +}); + // these are just for quick testing install(); @@ -11,16 +16,3 @@ install( ports.pipi({ packageName: "pre-commit" })[0], ports.cpy_bs(), ); - -env("main") - .onEnter(task(($) => $`echo enter`)) - .onExit(task(($) => $`echo exit`)); - -env("test", { - installs: [ports.protoc()], -}); - -export const secureConfig = stdSecureConfig({ - enableRuntimes: true, - defaultBaseEnv: "test", -}); diff --git a/hack.ts b/hack.ts new file mode 100644 index 00000000..38bf5d12 --- /dev/null +++ b/hack.ts @@ -0,0 +1,21 @@ +//! This file allows an easy way to start with the typescript ghjkfile +//! but is generally insecure for serious usage. +//! +//! If your ghjkfile imports a malicious module, the module could +//! import the functions defined herin and mess with your ghjkfile. +//! +//! For example, it could set `rm -rf / --no-preserve-root` to your +//! main env entry hook! + +export * from "./mod.ts"; +import { file } from "./mod.ts"; + +const { + sophon, + task, + env, + install, + config, +} = file(); + +export { config, env, install, sophon, task }; diff --git a/mod.ts b/mod.ts index 23aa2837..4f9771f4 100644 --- a/mod.ts +++ b/mod.ts @@ -1,165 +1,243 @@ -//! This module is intended to be re-exported by `ghjk.ts` config scripts. Please -//! avoid importing elsewhere at it has side-effects. +//! This module is intended to be re-exported by `ghjk.ts` config scripts. // TODO: harden most of the items in here import "./setup_logger.ts"; -import { zod } from "./deps/common.ts"; // ports specific imports -import portsValidators from "./modules/ports/types.ts"; import type { AllowedPortDep, InstallConfigFat, } from "./modules/ports/types.ts"; import logger from "./utils/logger.ts"; -import { $, thinInstallConfig } from "./utils/mod.ts"; -import { EnvBuilder, Ghjkfile, stdDeps } from "./files/mod.ts"; +import { $ } from "./utils/mod.ts"; +import { + EnvBuilder, + Ghjkfile, + reduceAllowedDeps, + stdDeps, +} from "./files/mod.ts"; import type { DenoTaskDefArgs, EnvDefArgs, TaskFn } from "./files/mod.ts"; // WARN: this module has side-effects and only ever import // types from it import type { ExecTaskArgs } from "./modules/tasks/deno.ts"; -const DEFAULT_BASE_ENV_NAME = "main"; +export type { DenoTaskDefArgs, EnvDefArgs, TaskFn } from "./files/mod.ts"; +export { $, logger, stdDeps }; -const file = new Ghjkfile(); -const mainEnv = file.addEnv({ - name: DEFAULT_BASE_ENV_NAME, - inherit: false, - allowedPortDeps: stdDeps(), - desc: "the default default environment.", -}); +export type AddEnv = { + (args: EnvDefArgs): EnvBuilder; + (name: string, args?: Omit): EnvBuilder; +}; -export type { DenoTaskDefArgs, EnvDefArgs, TaskFn } from "./files/mod.ts"; -export { $, logger, stdDeps, stdSecureConfig }; - -// FIXME: ses.lockdown to freeze primoridials -// freeze the object to prevent malicious tampering of the secureConfig -export const ghjk = Object.freeze({ - getConfig: Object.freeze( - ( - ghjkfileUrl: string, - secureConfig: DenoFileSecureConfig | undefined, - ) => { - const defaultEnv = secureConfig?.defaultEnv ?? DEFAULT_BASE_ENV_NAME; - const defaultBaseEnv = secureConfig?.defaultBaseEnv ?? - DEFAULT_BASE_ENV_NAME; - return file.toConfig({ - defaultEnv, - defaultBaseEnv, - ghjkfileUrl, - masterPortDepAllowList: secureConfig?.masterPortDepAllowList ?? - stdDeps(), - }); - }, - ), - execTask: Object.freeze( - // TODO: do we need to source the default base env from - // the secure config here? - (args: ExecTaskArgs) => file.execTask(args), - ), -}); - -/* - * Provision a port install in the `main` environment. +/** + * Provision a port install in the `main` env. */ -export function install(...configs: InstallConfigFat[]) { - mainEnv.install(...configs); -} +export type AddInstall = { + (...configs: InstallConfigFat[]): void; +}; /** * Define and register a task. */ -export function task(args: DenoTaskDefArgs): string; -export function task(name: string, args: Omit): string; -export function task( - name: string, - fn: TaskFn, - args?: Omit, -): string; -export function task(fn: TaskFn, args?: Omit): string; -export function task( - nameOrArgsOrFn: string | DenoTaskDefArgs | TaskFn, - argsOrFn?: Omit | TaskFn, - argsMaybe?: Omit, -): string { - let args: DenoTaskDefArgs; - if (typeof nameOrArgsOrFn == "object") { - args = nameOrArgsOrFn; - } else if (typeof nameOrArgsOrFn == "function") { - args = { - ...(argsOrFn ?? {}), - fn: nameOrArgsOrFn, - }; - } else if (typeof argsOrFn == "object") { - args = { ...argsOrFn, name: nameOrArgsOrFn }; - } else if (argsOrFn) { - args = { - ...(argsMaybe ?? {}), - name: nameOrArgsOrFn, - fn: argsOrFn, - }; - } else { - args = { - name: nameOrArgsOrFn, - }; - } - return file.addTask({ ...args, ty: "denoFile@v1" }); -} +export type AddTask = { + (args: DenoTaskDefArgs): string; + (name: string, args: Omit): string; + (fn: TaskFn, args?: Omit): string; + ( + name: string, + fn: TaskFn, + args?: Omit, + ): string; +}; -export function env(args: EnvDefArgs): EnvBuilder; -export function env(name: string, args?: Omit): EnvBuilder; -export function env( - nameOrArgs: string | EnvDefArgs, - argsMaybe?: Omit, -): EnvBuilder { - const args = typeof nameOrArgs == "object" - ? nameOrArgs - : { ...argsMaybe, name: nameOrArgs }; - return file.addEnv(args); -} +export type FileArgs = { + /** + * The env to activate by default. When entering the working + * directory for example. + */ + defaultEnv?: string; + /** + * The default env all envs inherit from. + */ + defaultBaseEnv?: string; + /** + * Additional ports that can be used as build time dependencies. + */ + allowedBuildDeps?: (InstallConfigFat | AllowedPortDep)[]; + /** + * Wether or not use the default set of allowed build dependencies. + * If set, {@link enableRuntimes} is ignored but {@link allowedBuildDeps} + * is still respected. + * True by default. + */ + stdDeps?: boolean; + /** + * (unstable) Allow runtimes from std deps to be used as build time dependencies. + */ + enableRuntimes?: boolean; + /** + * Installs to add to the main env. + */ + installs?: InstallConfigFat[]; + /** + * Tasks to expose to the CLI. + */ + tasks?: DenoTaskDefArgs[]; + /** + * Different envs availaible to the CLI. + */ + envs?: EnvDefArgs[]; +}; -const denoFileSecureConfig = zod.object({ - masterPortDepAllowList: zod.array(portsValidators.allowedPortDep).nullish(), - // TODO: move into envs/types - defaultEnv: zod.string().nullish(), - defaultBaseEnv: zod.string().nullish(), -}); -/* - * This is a secure sections of the config intended to be direct exports - * from the config script instead of the global variable approach the - * main [`GhjkConfig`] can take. - */ -export type DenoFileSecureConfig = zod.input< - typeof denoFileSecureConfig ->; -export type DenoFileSecureConfigX = zod.input< - typeof denoFileSecureConfig +type SecureConfigArgs = Omit< + FileArgs, + "envs" | "tasks" | "installs" >; -function stdSecureConfig( - args: { - additionalAllowedPorts?: (InstallConfigFat | AllowedPortDep)[]; - enableRuntimes?: boolean; - } & Pick, -) { - const { additionalAllowedPorts, enableRuntimes = false } = args; - const out: DenoFileSecureConfig = { - ...args, - masterPortDepAllowList: [ - ...stdDeps({ enableRuntimes }), - ...additionalAllowedPorts?.map( - (dep: any) => { - const res = portsValidators.allowedPortDep.safeParse(dep); - if (res.success) return res.data; - const out: AllowedPortDep = { - manifest: dep.port, - defaultInst: thinInstallConfig(dep), - }; - return portsValidators.allowedPortDep.parse(out); - }, - ) ?? [], - ], +export function file( + args: FileArgs = {}, +): { + sophon: Readonly; + install: AddInstall; + task: AddTask; + env: AddEnv; + config(args: SecureConfigArgs): void; +} { + const defaultBuildDepsSet: AllowedPortDep[] = []; + + // this replaces the allowedBuildDeps contents according to the + // args. Written to be called multilple times to allow + // replacement. + const replaceDefaultBuildDeps = (args: SecureConfigArgs) => { + // empty out the array first + defaultBuildDepsSet.length = 0; + defaultBuildDepsSet.push( + ...reduceAllowedDeps(args.allowedBuildDeps ?? []), + ); + const seenPorts = new Set( + defaultBuildDepsSet.map((dep) => dep.manifest.name), + ); + // if the user explicitly passes a port config, we let + // it override any ports of the same kind from the std library + for ( + const dep + of (args.stdDeps || args.stdDeps === undefined || args.stdDeps === null) + ? stdDeps({ enableRuntimes: args.enableRuntimes ?? false }) + : [] + ) { + if (seenPorts.has(dep.manifest.name)) { + continue; + } + defaultBuildDepsSet.push(dep); + } + }; + + // populate the bulid deps by the default args first + replaceDefaultBuildDeps(args); + + const DEFAULT_BASE_ENV_NAME = "main"; + + const file = new Ghjkfile(); + const mainEnv = file.addEnv({ + name: DEFAULT_BASE_ENV_NAME, + inherit: false, + installs: args.installs, + // the default build deps will be used + // as the allow set for the main env as well + // NOTE: this approach allows the main env to + // disassociate itself from the default set + // if the user invokes `allowedBuildDeps` + // on its EnvBuilder + allowedBuildDeps: defaultBuildDepsSet, + desc: "the default default environment.", + }); + for (const env of args.envs ?? []) { + file.addEnv(env); + } + for (const task of args.tasks ?? []) { + file.addTask({ ...task, ty: "denoFile@v1" }); + } + + // FIXME: ses.lockdown to freeze primoridials + // freeze the object to prevent malicious tampering of the secureConfig + const sophon = Object.freeze({ + getConfig: Object.freeze( + ( + ghjkfileUrl: string, + ) => { + return file.toConfig({ + ghjkfileUrl, + defaultEnv: args.defaultEnv ?? DEFAULT_BASE_ENV_NAME, + defaultBaseEnv: args.defaultBaseEnv ?? + DEFAULT_BASE_ENV_NAME, + }); + }, + ), + execTask: Object.freeze( + // TODO: do we need to source the default base env from + // the secure config here? + (args: ExecTaskArgs) => file.execTask(args), + ), + }); + + // we return a bunch of functions here + // to ease configuring the main environment + // including overloads + return { + sophon, + + install(...configs: InstallConfigFat[]) { + mainEnv.install(...configs); + }, + + task( + nameOrArgsOrFn: string | DenoTaskDefArgs | TaskFn, + argsOrFn?: Omit | TaskFn, + argsMaybe?: Omit, + ) { + let args: DenoTaskDefArgs; + if (typeof nameOrArgsOrFn == "object") { + args = nameOrArgsOrFn; + } else if (typeof nameOrArgsOrFn == "function") { + args = { + ...(argsOrFn ?? {}), + fn: nameOrArgsOrFn, + }; + } else if (typeof argsOrFn == "object") { + args = { ...argsOrFn, name: nameOrArgsOrFn }; + } else if (argsOrFn) { + args = { + ...(argsMaybe ?? {}), + name: nameOrArgsOrFn, + fn: argsOrFn, + }; + } else { + args = { + name: nameOrArgsOrFn, + }; + } + return file.addTask({ ...args, ty: "denoFile@v1" }); + }, + + env( + nameOrArgs: string | EnvDefArgs, + argsMaybe?: Omit, + ) { + const args = typeof nameOrArgs == "object" + ? nameOrArgs + : { ...argsMaybe, name: nameOrArgs }; + return file.addEnv(args); + }, + + config( + a: SecureConfigArgs, + ) { + replaceDefaultBuildDeps(a); + args = { + ...args, + ...a, + }; + }, }; - return out; } diff --git a/modules/tasks/deno.ts b/modules/tasks/deno.ts index e3c0003d..fe246012 100644 --- a/modules/tasks/deno.ts +++ b/modules/tasks/deno.ts @@ -61,7 +61,7 @@ async function importAndExec( args: ExecTaskArgs, ) { const mod = await import(uri); - await mod.ghjk.execTask(args); + await mod.sophon.execTask(args); return true; } diff --git a/tests/envHooks.ts b/tests/envHooks.ts index cf20e562..283ae22f 100644 --- a/tests/envHooks.ts +++ b/tests/envHooks.ts @@ -78,8 +78,8 @@ const cases: CustomE2eTestCase[] = [ harness(cases.map((testCase) => ({ ...testCase, tsGhjkfileStr: ` -export { ghjk } from "$ghjk/mod.ts"; -import { task, env } from "$ghjk/mod.ts"; +export { sophon } from "$ghjk/hack.ts"; +import { task, env } from "$ghjk/hack.ts"; env("main") .onEnter(task($ => $\`/bin/sh -c 'echo remark > marker'\`)) diff --git a/tests/envs.ts b/tests/envs.ts index 0be9b369..343c1b7e 100644 --- a/tests/envs.ts +++ b/tests/envs.ts @@ -5,9 +5,8 @@ import { genTsGhjkFile, harness, } from "./utils.ts"; -import { stdSecureConfig } from "../mod.ts"; import dummy from "../ports/dummy.ts"; -import type { DenoFileSecureConfig } from "../mod.ts"; +import type { FileArgs } from "../mod.ts"; type CustomE2eTestCase = & Omit @@ -18,7 +17,7 @@ type CustomE2eTestCase = & ( | { envs: EnvDefArgs[]; - secureConfig?: DenoFileSecureConfig; + secureConfig?: FileArgs; } | { ghjkTs: string; @@ -184,7 +183,7 @@ const cases: CustomE2eTestCase[] = [ name: "default_env_loader", ePoint: "fish", envs: envVarTestEnvs, - secureConfig: stdSecureConfig({ defaultEnv: "yuki" }), + secureConfig: { defaultEnv: "yuki" }, stdin: ` set fish_trace 1 # env base is false for "yuki" and thus no vars from "main" @@ -198,7 +197,12 @@ test "$HUMM" = "Soul Lady"; or exit 108 harness(cases.map((testCase) => ({ ...testCase, tsGhjkfileStr: "ghjkTs" in testCase ? testCase.ghjkTs : genTsGhjkFile( - { envDefs: testCase.envs, secureConf: testCase.secureConfig }, + { + secureConf: { + ...testCase.secureConfig, + envs: testCase.envs, + }, + }, ), ePoints: [{ cmd: testCase.ePoint, stdin: testCase.stdin }], name: `envs/${testCase.name}`, diff --git a/tests/ports.ts b/tests/ports.ts index 0a312dd7..9e5f34a7 100644 --- a/tests/ports.ts +++ b/tests/ports.ts @@ -1,5 +1,5 @@ import "../setup_logger.ts"; -import { DenoFileSecureConfig, stdSecureConfig } from "../mod.ts"; +import { FileArgs } from "../mod.ts"; import { E2eTestCase, genTsGhjkFile, harness } from "./utils.ts"; import * as ports from "../ports/mod.ts"; import dummy from "../ports/dummy.ts"; @@ -9,7 +9,7 @@ import { testTargetPlatform } from "./utils.ts"; type CustomE2eTestCase = Omit & { ePoint: string; installConf: InstallConfigFat | InstallConfigFat[]; - secureConf?: DenoFileSecureConfig; + secureConf?: FileArgs; }; // order tests by download size to make failed runs less expensive const cases: CustomE2eTestCase[] = [ @@ -97,18 +97,18 @@ const cases: CustomE2eTestCase[] = [ name: "npmi-node-gyp", installConf: ports.npmi({ packageName: "node-gyp" }), ePoint: `node-gyp --version`, - secureConf: stdSecureConfig({ + secureConf: { enableRuntimes: true, - }), + }, }, // node + more megs { name: "npmi-jco", installConf: ports.npmi({ packageName: "@bytecodealliance/jco" }), ePoint: `jco --version`, - secureConf: stdSecureConfig({ + secureConf: { enableRuntimes: true, - }), + }, }, // 42 megs { @@ -159,6 +159,9 @@ const cases: CustomE2eTestCase[] = [ name: "pipi-poetry", installConf: ports.pipi({ packageName: "poetry" }), ePoint: `poetry --version`, + secureConf: { + enableRuntimes: true, + }, }, // rustup + 600 megs { @@ -199,9 +202,12 @@ harness(cases.map((testCase) => ({ ...testCase, tsGhjkfileStr: genTsGhjkFile( { - installConf: testCase.installConf, - secureConf: testCase.secureConf, - taskDefs: [], + secureConf: { + ...testCase.secureConf, + installs: Array.isArray(testCase.installConf) + ? testCase.installConf + : [testCase.installConf], + }, }, ), ePoints: [ @@ -209,14 +215,14 @@ harness(cases.map((testCase) => ({ cmd: [...`env ${sh}`.split(" "), `"${testCase.ePoint}"`], })), /* // FIXME: better tests for the `InstallDb` - // installs db means this shouldn't take too long - // as it's the second sync - { - cmd: [ - ..."env".split(" "), - "bash -c 'timeout 1 ghjk envs cook'", - ], - }, */ + // installs db means this shouldn't take too long + // as it's the second sync + { + cmd: [ + ..."env".split(" "), + "bash -c 'timeout 1 ghjk envs cook'", + ], + }, */ ], name: `ports/${testCase.name}`, }))); diff --git a/tests/reloadHooks.ts b/tests/reloadHooks.ts index b26f1e51..d9192a3a 100644 --- a/tests/reloadHooks.ts +++ b/tests/reloadHooks.ts @@ -202,15 +202,17 @@ harness(cases.map((testCase) => ({ ...testCase, tsGhjkfileStr: genTsGhjkFile( { - envDefs: [ - { - name: "main", - installs: testCase.installConf ? testCase.installConf : [dummy()], - }, - { - name: "test", - }, - ], + secureConf: { + envs: [ + { + name: "main", + installs: testCase.installConf ? testCase.installConf : [dummy()], + }, + { + name: "test", + }, + ], + }, }, ), ePoints: [{ cmd: testCase.ePoint, stdin: testCase.stdin }], diff --git a/tests/tasks.ts b/tests/tasks.ts index cb8cf352..c85f8bf1 100644 --- a/tests/tasks.ts +++ b/tests/tasks.ts @@ -2,7 +2,6 @@ import "../setup_logger.ts"; import { E2eTestCase, genTsGhjkFile, harness, type TaskDef } from "./utils.ts"; import * as ghjk from "../mod.ts"; import * as ports from "../ports/mod.ts"; -import { stdSecureConfig } from "../mod.ts"; type CustomE2eTestCase = & Omit @@ -36,7 +35,7 @@ test (ghjk x greet world) = "Hello world from $PWD!"`, name: "env_vars", tasks: [{ name: "greet", - envVars: { + vars: { LUNA: "moon", SOL: "sun", }, @@ -67,7 +66,7 @@ ghjk x protoc`, name: "test", // pipi depends on cpy_bs installs: [...ports.pipi({ packageName: "pre-commit" })], - allowedPortDeps: ghjk.stdDeps({ enableRuntimes: true }), + allowedBuildDeps: ghjk.stdDeps({ enableRuntimes: true }), fn: async ($) => { await $`pre-commit --version`; }, @@ -123,8 +122,8 @@ test (cat eddy) = 'ed edd eddy' { name: "anon", ghjkTs: ` -export { ghjk } from "$ghjk/mod.ts"; -import { task } from "$ghjk/mod.ts"; +export { sophon } from "$ghjk/hack.ts"; +import { task } from "$ghjk/hack.ts"; task({ dependsOn: [ @@ -151,10 +150,10 @@ harness(cases.map((testCase) => ({ ...testCase, tsGhjkfileStr: "ghjkTs" in testCase ? testCase.ghjkTs : genTsGhjkFile( { - taskDefs: testCase.tasks, - secureConf: stdSecureConfig({ + secureConf: { + tasks: testCase.tasks, enableRuntimes: testCase.enableRuntimesOnMasterPDAL, - }), + }, }, ), ePoints: [{ cmd: testCase.ePoint, stdin: testCase.stdin }], diff --git a/tests/utils.ts b/tests/utils.ts index ad15166a..766709ec 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -2,13 +2,8 @@ import { defaultInstallArgs, install } from "../install/mod.ts"; import { std_url } from "../deps/dev.ts"; import { std_async } from "../deps/dev.ts"; import { $, dbg, importRaw } from "../utils/mod.ts"; -import type { InstallConfigFat } from "../modules/ports/types.ts"; import logger from "../utils/logger.ts"; -import type { - DenoFileSecureConfig, - DenoTaskDefArgs, - EnvDefArgs, -} from "../mod.ts"; +import type { DenoTaskDefArgs, FileArgs } from "../mod.ts"; export type { EnvDefArgs } from "../mod.ts"; import { ALL_OS } from "../port.ts"; import { ALL_ARCH } from "../port.ts"; @@ -181,35 +176,23 @@ export type TaskDef = & Required>; export function genTsGhjkFile( - { installConf, secureConf, taskDefs, envDefs }: { - installConf?: InstallConfigFat | InstallConfigFat[]; - secureConf?: DenoFileSecureConfig; - taskDefs?: TaskDef[]; - envDefs?: EnvDefArgs[]; + { secureConf }: { + secureConf?: FileArgs; }, ) { - const installConfArray = installConf - ? Array.isArray(installConf) ? installConf : [installConf] - : []; - - const serializedPortsInsts = JSON.stringify( - installConfArray, - (_, val) => - typeof val == "string" - // we need to escape a json string embedded in a js string - // 2x - ? val.replaceAll(/\\/g, "\\\\") - : val, - ); - const serializedSecConf = JSON.stringify( // undefined is not recognized by JSON.parse // so we stub it with null - secureConf ?? null, + { + ...secureConf, + tasks: [], + }, + // we need to escape a json string embedded in a js string + // 2x (_, val) => typeof val == "string" ? val.replaceAll(/\\/g, "\\\\") : val, ); - const tasks = (taskDefs ?? []).map( + const tasks = (secureConf?.tasks ?? []).map( (def) => { const stringifiedSection = JSON.stringify( def, @@ -219,41 +202,24 @@ export function genTsGhjkFile( return $.dedent` ghjk.task({ ...JSON.parse(\`${stringifiedSection}\`), - fn: ${def.fn.toString()} - })`; - }, - ).join("\n"); - - const envs = (envDefs ?? []).map( - (def) => { - const stringifiedSection = JSON.stringify( - def, - (_, val) => - typeof val == "string" ? val.replaceAll(/\\/g, "\\\\") : val, - ); - return $.dedent` - ghjk.env({ - ...JSON.parse(\`${stringifiedSection}\`), + fn: ${def.fn?.toString()} })`; }, ).join("\n"); return ` -export { ghjk } from "$ghjk/mod.ts"; -import * as ghjk from "$ghjk/mod.ts"; +import { file } from "$ghjk/mod.ts"; + const confStr = \` -${serializedPortsInsts} +${serializedSecConf} \`; const confObj = JSON.parse(confStr); -ghjk.install(...confObj) +const ghjk = file(confObj); -const secConfStr = \` -${serializedSecConf} -\`; -export const secureConfig = JSON.parse(secConfStr); +export const sophon = ghjk.sophon; ${tasks} -${envs} + `; } diff --git a/utils/mod.ts b/utils/mod.ts index df1f8a6b..f9659be4 100644 --- a/utils/mod.ts +++ b/utils/mod.ts @@ -196,6 +196,19 @@ export const $ = dax.build$( requestBuilder: new dax.RequestBuilder() .showProgress(Deno.stderr.isTerminal()), extras: { + mapObject< + O, + V2, + >( + obj: O, + map: (key: keyof O, val: O[keyof O]) => [string, V2], + ): Record { + return Object.fromEntries( + Object.entries(obj as object).map(([key, val]) => + map(key as keyof O, val as O[keyof O]) + ), + ); + }, exponentialBackoff(initialDelayMs: number) { let delay = initialDelayMs; let attempt = 0; From c2ea07cbd1c48d40e429fb2ef819c588c95f569c Mon Sep 17 00:00:00 2001 From: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Date: Thu, 30 May 2024 02:50:49 +0000 Subject: [PATCH 2/6] docs: improve README --- .ghjk/deno.lock | 643 ------------------ .ghjk/lock.json | 67 +- README.md | 106 +-- examples/kitchen/ghjk.ts | 11 +- files/mod.ts | 31 +- ghjk.ts | 2 +- hack.ts | 85 ++- mod.ts | 76 ++- modules/ports/mod.ts | 4 +- modules/ports/sync.ts | 8 +- modules/ports/types.ts | 2 +- tests/envHooks.ts | 4 +- .../{modules/ports => }/portsOutdatedTest.ts | 31 +- tests/reloadHooks.ts | 4 +- 14 files changed, 235 insertions(+), 839 deletions(-) delete mode 100644 .ghjk/deno.lock rename tests/{modules/ports => }/portsOutdatedTest.ts (74%) diff --git a/.ghjk/deno.lock b/.ghjk/deno.lock deleted file mode 100644 index 579f4faf..00000000 --- a/.ghjk/deno.lock +++ /dev/null @@ -1,643 +0,0 @@ -{ - "version": "3", - "packages": { - "specifiers": { - "jsr:@david/dax@0.41.0": "jsr:@david/dax@0.41.0", - "jsr:@david/which@0.3": "jsr:@david/which@0.3.0", - "jsr:@david/which@^0.4.1": "jsr:@david/which@0.4.1", - "jsr:@ghjk/dax@0.40.2-alpha-ghjk": "jsr:@ghjk/dax@0.40.2-alpha-ghjk", - "jsr:@std/assert@^0.221.0": "jsr:@std/assert@0.221.0", - "jsr:@std/bytes@^0.221.0": "jsr:@std/bytes@0.221.0", - "jsr:@std/fmt@^0.221.0": "jsr:@std/fmt@0.221.0", - "jsr:@std/fs@0.221.0": "jsr:@std/fs@0.221.0", - "jsr:@std/io@0.221.0": "jsr:@std/io@0.221.0", - "jsr:@std/io@^0.221.0": "jsr:@std/io@0.221.0", - "jsr:@std/path@0.221.0": "jsr:@std/path@0.221.0", - "jsr:@std/path@^0.221.0": "jsr:@std/path@0.221.0", - "jsr:@std/streams@0.221.0": "jsr:@std/streams@0.221.0", - "npm:@noble/hashes@1.4.0": "npm:@noble/hashes@1.4.0", - "npm:multiformats@13.1.0": "npm:multiformats@13.1.0", - "npm:zod-validation-error": "npm:zod-validation-error@3.1.0_zod@3.22.4", - "npm:zod-validation-error@3.2.0": "npm:zod-validation-error@3.2.0_zod@3.22.4", - "npm:zod-validation-error@3.3.0": "npm:zod-validation-error@3.3.0_zod@3.22.4" - }, - "jsr": { - "@david/dax@0.41.0": { - "integrity": "9e1ecf66a0415962cc8ad3ba4e3fa93ce0f1a1cc797dd95c36fdfb6977dc7fc8", - "dependencies": [ - "jsr:@david/which@^0.4.1", - "jsr:@std/fmt@^0.221.0", - "jsr:@std/fs@0.221.0", - "jsr:@std/io@0.221.0", - "jsr:@std/path@0.221.0", - "jsr:@std/streams@0.221.0" - ] - }, - "@david/which@0.3.0": { - "integrity": "6bdb62c40ac90edcf328e854fa8103a8db21e7c326089cbe3c3a1cf7887d3204" - }, - "@david/which@0.4.1": { - "integrity": "896a682b111f92ab866cc70c5b4afab2f5899d2f9bde31ed00203b9c250f225e" - }, - "@ghjk/dax@0.40.2-alpha-ghjk": { - "integrity": "87bc93e9947779cb2f3922fe277e21ea8c716de804b2627f80ba9e7bc3d0d019", - "dependencies": [ - "jsr:@david/which@0.3", - "jsr:@std/fmt@^0.221.0", - "jsr:@std/fs@0.221.0", - "jsr:@std/io@0.221.0", - "jsr:@std/path@0.221.0", - "jsr:@std/streams@0.221.0" - ] - }, - "@std/assert@0.221.0": { - "integrity": "a5f1aa6e7909dbea271754fd4ab3f4e687aeff4873b4cef9a320af813adb489a" - }, - "@std/bytes@0.221.0": { - "integrity": "64a047011cf833890a4a2ab7293ac55a1b4f5a050624ebc6a0159c357de91966" - }, - "@std/fmt@0.221.0": { - "integrity": "379fed69bdd9731110f26b9085aeb740606b20428ce6af31ef6bd45ef8efa62a" - }, - "@std/fs@0.221.0": { - "integrity": "028044450299de8ed5a716ade4e6d524399f035513b85913794f4e81f07da286", - "dependencies": [ - "jsr:@std/assert@^0.221.0", - "jsr:@std/path@^0.221.0" - ] - }, - "@std/io@0.221.0": { - "integrity": "faf7f8700d46ab527fa05cc6167f4b97701a06c413024431c6b4d207caa010da", - "dependencies": [ - "jsr:@std/assert@^0.221.0", - "jsr:@std/bytes@^0.221.0" - ] - }, - "@std/path@0.221.0": { - "integrity": "0a36f6b17314ef653a3a1649740cc8db51b25a133ecfe838f20b79a56ebe0095", - "dependencies": [ - "jsr:@std/assert@^0.221.0" - ] - }, - "@std/streams@0.221.0": { - "integrity": "47f2f74634b47449277c0ee79fe878da4424b66bd8975c032e3afdca88986e61", - "dependencies": [ - "jsr:@std/io@^0.221.0" - ] - } - }, - "npm": { - "@noble/hashes@1.4.0": { - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dependencies": {} - }, - "multiformats@13.1.0": { - "integrity": "sha512-HzdtdBwxsIkzpeXzhQ5mAhhuxcHbjEHH+JQoxt7hG/2HGFjjwyolLo7hbaexcnhoEuV4e0TNJ8kkpMjiEYY4VQ==", - "dependencies": {} - }, - "zod-validation-error@3.1.0_zod@3.22.4": { - "integrity": "sha512-zujS6HqJjMZCsvjfbnRs7WI3PXN39ovTcY1n8a+KTm4kOH0ZXYsNiJkH1odZf4xZKMkBDL7M2rmQ913FCS1p9w==", - "dependencies": { - "zod": "zod@3.22.4" - } - }, - "zod-validation-error@3.2.0_zod@3.22.4": { - "integrity": "sha512-cYlPR6zuyrgmu2wRTdumEAJGuwI7eHVHGT+VyneAQxmRAKtGRL1/7pjz4wfLhz4J05f5qoSZc3rGacswgyTjjw==", - "dependencies": { - "zod": "zod@3.22.4" - } - }, - "zod-validation-error@3.3.0_zod@3.22.4": { - "integrity": "sha512-Syib9oumw1NTqEv4LT0e6U83Td9aVRk9iTXPUQr1otyV1PuXQKOvOwhMNqZIq5hluzHP2pMgnOmHEo7kPdI2mw==", - "dependencies": { - "zod": "zod@3.22.4" - } - }, - "zod@3.22.4": { - "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", - "dependencies": {} - } - } - }, - "remote": { - "https://deno.land/std@0.116.0/_util/assert.ts": "2f868145a042a11d5ad0a3c748dcf580add8a0dbc0e876eaa0026303a5488f58", - "https://deno.land/std@0.116.0/_util/os.ts": "dfb186cc4e968c770ab6cc3288bd65f4871be03b93beecae57d657232ecffcac", - "https://deno.land/std@0.116.0/fs/walk.ts": "31464d75099aa3fc7764212576a8772dfabb2692783e6eabb910f874a26eac54", - "https://deno.land/std@0.116.0/path/_constants.ts": "1247fee4a79b70c89f23499691ef169b41b6ccf01887a0abd131009c5581b853", - "https://deno.land/std@0.116.0/path/_interface.ts": "1fa73b02aaa24867e481a48492b44f2598cd9dfa513c7b34001437007d3642e4", - "https://deno.land/std@0.116.0/path/_util.ts": "2e06a3b9e79beaf62687196bd4b60a4c391d862cfa007a20fc3a39f778ba073b", - "https://deno.land/std@0.116.0/path/common.ts": "f41a38a0719a1e85aa11c6ba3bea5e37c15dd009d705bd8873f94c833568cbc4", - "https://deno.land/std@0.116.0/path/glob.ts": "ea87985765b977cc284b92771003b2070c440e0807c90e1eb0ff3e095911a820", - "https://deno.land/std@0.116.0/path/mod.ts": "4465dc494f271b02569edbb4a18d727063b5dbd6ed84283ff906260970a15d12", - "https://deno.land/std@0.116.0/path/posix.ts": "34349174b9cd121625a2810837a82dd8b986bbaaad5ade690d1de75bbb4555b2", - "https://deno.land/std@0.116.0/path/separator.ts": "8fdcf289b1b76fd726a508f57d3370ca029ae6976fcde5044007f062e643ff1c", - "https://deno.land/std@0.116.0/path/win32.ts": "11549e8c6df8307a8efcfa47ad7b2a75da743eac7d4c89c9723a944661c8bd2e", - "https://deno.land/std@0.120.0/_wasm_crypto/crypto.js": "5c283a80e1059d16589b79fa026be5fb0a28424302a99487cadceef8c17f8afa", - "https://deno.land/std@0.120.0/_wasm_crypto/crypto.wasm.js": "0e6df3c18beb1187b442ec7f0a03df4d18b21212172d6b4a50ee4816404771d7", - "https://deno.land/std@0.120.0/_wasm_crypto/mod.ts": "7d02009ef3ddc953c8f90561d213e02fa0a6f3eaed9b8baf0c241c8cbeec1ed3", - "https://deno.land/std@0.120.0/crypto/mod.ts": "5760510eaa0b250f78cce81ce92d83cf8c40e9bb3c3efeedd4ef1a5bb0801ef4", - "https://deno.land/std@0.120.0/encoding/ascii85.ts": "b42b041e9c668afa356dd07ccf69a6b3ee49b9ae080fdf3b03f0ac3981f4d1e6", - "https://deno.land/std@0.120.0/encoding/base64.ts": "0b58bd6477214838bf711eef43eac21e47ba9e5c81b2ce185fe25d9ecab3ebb3", - "https://deno.land/std@0.196.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee", - "https://deno.land/std@0.196.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56", - "https://deno.land/std@0.196.0/console/_data.json": "cf2cc9d039a192b3adbfe64627167c7e6212704c888c25c769fc8f1709e1e1b8", - "https://deno.land/std@0.196.0/console/_rle.ts": "56668d5c44f964f1b4ff93f21c9896df42d6ee4394e814db52d6d13f5bb247c7", - "https://deno.land/std@0.196.0/console/unicode_width.ts": "10661c0f2eeab802d16b8b85ed8825bbc573991bbfb6affed32dc1ff994f54f9", - "https://deno.land/std@0.196.0/fmt/colors.ts": "a7eecffdf3d1d54db890723b303847b6e0a1ab4b528ba6958b8f2e754cf1b3bc", - "https://deno.land/std@0.213.0/archive/_common.ts": "85edd5cdd4324833f613c1bc055f8e2f935cc9229c6b3044421268d9959997ef", - "https://deno.land/std@0.213.0/archive/untar.ts": "7677c136f2188cd8c33363ccaaee6e77d4ca656cca3e2093d08de8f294d4353d", - "https://deno.land/std@0.213.0/assert/assert.ts": "bec068b2fccdd434c138a555b19a2c2393b71dfaada02b7d568a01541e67cdc5", - "https://deno.land/std@0.213.0/assert/assertion_error.ts": "9f689a101ee586c4ce92f52fa7ddd362e86434ffdf1f848e45987dc7689976b8", - "https://deno.land/std@0.213.0/bytes/concat.ts": "9cac3b4376afbef98ff03588eb3cf948e0d1eb6c27cfe81a7651ab6dd3adc54a", - "https://deno.land/std@0.213.0/bytes/copy.ts": "f29c03168853720dfe82eaa57793d0b9e3543ebfe5306684182f0f1e3bfd422a", - "https://deno.land/std@0.213.0/fmt/colors.ts": "aeaee795471b56fc62a3cb2e174ed33e91551b535f44677f6320336aabb54fbb", - "https://deno.land/std@0.213.0/fs/_create_walk_entry.ts": "5d9d2aaec05bcf09a06748b1684224d33eba7a4de24cf4cf5599991ca6b5b412", - "https://deno.land/std@0.213.0/fs/_get_file_info_type.ts": "da7bec18a7661dba360a1db475b826b18977582ce6fc9b25f3d4ee0403fe8cbd", - "https://deno.land/std@0.213.0/fs/_is_same_path.ts": "709c95868345fea051c58b9e96af95cff94e6ae98dfcff2b66dee0c212c4221f", - "https://deno.land/std@0.213.0/fs/_is_subdir.ts": "c68b309d46cc8568ed83c000f608a61bbdba0943b7524e7a30f9e450cf67eecd", - "https://deno.land/std@0.213.0/fs/_to_path_string.ts": "29bfc9c6c112254961d75cbf6ba814d6de5349767818eb93090cecfa9665591e", - "https://deno.land/std@0.213.0/fs/copy.ts": "dc0f68c4b6c3b090bfdb909387e309f6169b746bd713927c9507c9ef545d71f6", - "https://deno.land/std@0.213.0/fs/empty_dir.ts": "4f01e6d56e2aa8d90ad60f20bc25601f516b00f6c3044cdf6863a058791d91aa", - "https://deno.land/std@0.213.0/fs/ensure_dir.ts": "dffff68de0d10799b5aa9e39dec4e327e12bbd29e762292193684542648c4aeb", - "https://deno.land/std@0.213.0/fs/ensure_file.ts": "ac5cfde94786b0284d2c8e9f7f9425269bea1b2140612b4aea1f20b508870f59", - "https://deno.land/std@0.213.0/fs/ensure_link.ts": "d42af2edefeaa9817873ec6e46dc5d209ac4d744f8c69c5ecc2dffade78465b6", - "https://deno.land/std@0.213.0/fs/ensure_symlink.ts": "aee3f1655700f60090b4a3037f5b6c07ab37c36807cccad746ce89987719e6d2", - "https://deno.land/std@0.213.0/fs/eol.ts": "c9807291f78361d49fd986a9be04654610c615c5e2ec63d748976197d30ff206", - "https://deno.land/std@0.213.0/fs/exists.ts": "d2757ef764eaf5c6c5af7228e8447db2de42ab084a2dae540097f905723d83f5", - "https://deno.land/std@0.213.0/fs/expand_glob.ts": "a64e4ab51f62780f764789c9cdeacc862d221e35207fb81170a980ccc22868e3", - "https://deno.land/std@0.213.0/fs/mod.ts": "107f5afa4424c2d3ce2f7e9266173198da30302c69af662c720115fe504dc5ee", - "https://deno.land/std@0.213.0/fs/move.ts": "39e0d7ccb88a566d20b949712020e766b15ef1ec19159573d11f949bd677909c", - "https://deno.land/std@0.213.0/fs/walk.ts": "f04cc83ad3b27b5a5d078c831a01c7406069474bf280d5db015d937149a60128", - "https://deno.land/std@0.213.0/internal/warn_on_deprecated_api.ts": "0708590b803a3c4462bbd89ee8b9a1b3fe941a7679ee3cfc332227a69b5c36f1", - "https://deno.land/std@0.213.0/io/_common.ts": "36705cdb4dfcd338d6131bca1b16e48a4d5bf0d1dada6ce397268e88c17a5835", - "https://deno.land/std@0.213.0/io/_constants.ts": "3c7ad4695832e6e4a32e35f218c70376b62bc78621ef069a4a0a3d55739f8856", - "https://deno.land/std@0.213.0/io/buf_reader.ts": "ccbd43ace0a9eebbd5e1b4765724b79da79d1e28b90c2b08537b99192da4a1f7", - "https://deno.land/std@0.213.0/io/buf_writer.ts": "bf68b9c74b1bccf51b9960c54db5eec60e7e3d922c7c62781b0d3971770021ba", - "https://deno.land/std@0.213.0/io/buffer.ts": "79182995c8340ece2fa8763a8da86d282c507e854921d0a4c2ba7425c63609ef", - "https://deno.land/std@0.213.0/io/copy.ts": "63c6a4acf71fb1e89f5e47a7b3b2972f9d2c56dd645560975ead72db7eb23f61", - "https://deno.land/std@0.213.0/io/copy_n.ts": "e4a169b8965b69e6a05175d06bf14565caa91266143ec895e54e95b6cdb27cf2", - "https://deno.land/std@0.213.0/io/limited_reader.ts": "2b3e6c2d134bbbabbc918584db5fd2f8b21091843357f75af0d9f262cb5c94c1", - "https://deno.land/std@0.213.0/io/mod.ts": "571384032c5f60530542a28f2e8b0e73e47e87eca77056ba7e2363f4d4a4573a", - "https://deno.land/std@0.213.0/io/multi_reader.ts": "ca8a7813208a3393dfaed75894d955fe58a38c21b880e69839a4e0547eadbf61", - "https://deno.land/std@0.213.0/io/read_all.ts": "876c1cb20adea15349c72afc86cecd3573335845ae778967aefb5e55fe5a8a4a", - "https://deno.land/std@0.213.0/io/read_delim.ts": "fb0884d97adc398877c6f59e1d1450be12e078790f52845fae7876dc119bb8f6", - "https://deno.land/std@0.213.0/io/read_int.ts": "6ada4e0eec5044982df530e4de804e32ae757a2c318b57eba622d893841ffe2a", - "https://deno.land/std@0.213.0/io/read_lines.ts": "34555eaa25269f6cfb9a842a03daedc9eae4f8295c8f933bd2b1639274ce89e3", - "https://deno.land/std@0.213.0/io/read_long.ts": "199cba44526464f8499e1f3d96008d513bcadc8e5665356a9b84425cac6b16ad", - "https://deno.land/std@0.213.0/io/read_range.ts": "a0c930ea61fdc3ea5520be4df34a7927fe8a2d6da9b04bfaa7b9588ef2e1a718", - "https://deno.land/std@0.213.0/io/read_short.ts": "73777709ad41b6faeff3638c275a329cc820c1082f4dad07909f48875a35a71d", - "https://deno.land/std@0.213.0/io/read_string_delim.ts": "8c604ceea5c3c7ab244583570b467ce194238ace6d49b1d47f25d4f75de86d59", - "https://deno.land/std@0.213.0/io/slice_long_to_bytes.ts": "9769174a8f3b4449f1e1af1a79f78e58ef84d0aaf2f457e1fdc31a01f92439b7", - "https://deno.land/std@0.213.0/io/string_reader.ts": "b0176211e61e235a684abef722e7ecc7a6481238ba264f1a7b199b8a1d2a62f5", - "https://deno.land/std@0.213.0/io/string_writer.ts": "4fe4dcbdadff11c726bf79b0239e14fa9b1e8468a795b465622e4dbd6c1f819c", - "https://deno.land/std@0.213.0/io/to_readable_stream.ts": "ed03a44a1ec1cc55a85a857acf6cac472035298f6f3b6207ea209f93b4aefb39", - "https://deno.land/std@0.213.0/io/to_writable_stream.ts": "ef422e0425963c8a1e0481674e66c3023da50f0acbe5ef51ec9789efc3c1e2ed", - "https://deno.land/std@0.213.0/io/types.ts": "748bbb3ac96abda03594ef5a0db15ce5450dcc6c0d841c8906f8b10ac8d32c96", - "https://deno.land/std@0.213.0/io/write_all.ts": "24aac2312bb21096ae3ae0b102b22c26164d3249dff96dbac130958aa736f038", - "https://deno.land/std@0.213.0/log/base_handler.ts": "924b370558d561f4e728295ebcb392224e36061542c7ad2e5b48c8e29614c27f", - "https://deno.land/std@0.213.0/log/console_handler.ts": "75653acd6932fb97c7121f63336b39de3f072e329874d66f05abcb2a7f514558", - "https://deno.land/std@0.213.0/log/file_handler.ts": "7b58c7017117ae290700b0e23f21573c1dc8ba8b5d4978d8aa0b8e05742d75e2", - "https://deno.land/std@0.213.0/log/formatters.ts": "5491ac778cf404a9379025bef33565644eb10b6a1f8083aba2595887d49edf15", - "https://deno.land/std@0.213.0/log/handlers.ts": "ff5b5d8293ca5d452acfb2e7c214f527ad953aaab4036219b818a3b859944b08", - "https://deno.land/std@0.213.0/log/levels.ts": "3746b311bc5cd28340fe7b563002f94508ace565592e9f4730f8b07916f189a6", - "https://deno.land/std@0.213.0/log/logger.ts": "32ad896c88182ee9cbe2a579afb09b48ed642a2bfaa3f3b2fb8009314ab18855", - "https://deno.land/std@0.213.0/log/mod.ts": "d8a8ebca268767a610d686d7f3c5c97096121ff3bc7ebec71ab7dd73cc52231b", - "https://deno.land/std@0.213.0/log/rotating_file_handler.ts": "dc0333959ff725ac1f43b741ababa9fef074f658a60c65235d12e44952085fbe", - "https://deno.land/std@0.213.0/path/_common/assert_path.ts": "2ca275f36ac1788b2acb60fb2b79cb06027198bc2ba6fb7e163efaedde98c297", - "https://deno.land/std@0.213.0/path/_common/basename.ts": "569744855bc8445f3a56087fd2aed56bdad39da971a8d92b138c9913aecc5fa2", - "https://deno.land/std@0.213.0/path/_common/common.ts": "6157c7ec1f4db2b4a9a187efd6ce76dcaf1e61cfd49f87e40d4ea102818df031", - "https://deno.land/std@0.213.0/path/_common/constants.ts": "dc5f8057159f4b48cd304eb3027e42f1148cf4df1fb4240774d3492b5d12ac0c", - "https://deno.land/std@0.213.0/path/_common/dirname.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8", - "https://deno.land/std@0.213.0/path/_common/format.ts": "92500e91ea5de21c97f5fe91e178bae62af524b72d5fcd246d6d60ae4bcada8b", - "https://deno.land/std@0.213.0/path/_common/from_file_url.ts": "d672bdeebc11bf80e99bf266f886c70963107bdd31134c4e249eef51133ceccf", - "https://deno.land/std@0.213.0/path/_common/glob_to_reg_exp.ts": "2007aa87bed6eb2c8ae8381adcc3125027543d9ec347713c1ad2c68427330770", - "https://deno.land/std@0.213.0/path/_common/normalize.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8", - "https://deno.land/std@0.213.0/path/_common/normalize_string.ts": "dfdf657a1b1a7db7999f7c575ee7e6b0551d9c20f19486c6c3f5ff428384c965", - "https://deno.land/std@0.213.0/path/_common/relative.ts": "faa2753d9b32320ed4ada0733261e3357c186e5705678d9dd08b97527deae607", - "https://deno.land/std@0.213.0/path/_common/strip_trailing_separators.ts": "7024a93447efcdcfeaa9339a98fa63ef9d53de363f1fbe9858970f1bba02655a", - "https://deno.land/std@0.213.0/path/_common/to_file_url.ts": "7f76adbc83ece1bba173e6e98a27c647712cab773d3f8cbe0398b74afc817883", - "https://deno.land/std@0.213.0/path/_interface.ts": "a1419fcf45c0ceb8acdccc94394e3e94f99e18cfd32d509aab514c8841799600", - "https://deno.land/std@0.213.0/path/_os.ts": "8fb9b90fb6b753bd8c77cfd8a33c2ff6c5f5bc185f50de8ca4ac6a05710b2c15", - "https://deno.land/std@0.213.0/path/basename.ts": "5d341aadb7ada266e2280561692c165771d071c98746fcb66da928870cd47668", - "https://deno.land/std@0.213.0/path/common.ts": "03e52e22882402c986fe97ca3b5bb4263c2aa811c515ce84584b23bac4cc2643", - "https://deno.land/std@0.213.0/path/constants.ts": "0c206169ca104938ede9da48ac952de288f23343304a1c3cb6ec7625e7325f36", - "https://deno.land/std@0.213.0/path/dirname.ts": "85bd955bf31d62c9aafdd7ff561c4b5fb587d11a9a5a45e2b01aedffa4238a7c", - "https://deno.land/std@0.213.0/path/extname.ts": "593303db8ae8c865cbd9ceec6e55d4b9ac5410c1e276bfd3131916591b954441", - "https://deno.land/std@0.213.0/path/format.ts": "98fad25f1af7b96a48efb5b67378fcc8ed77be895df8b9c733b86411632162af", - "https://deno.land/std@0.213.0/path/from_file_url.ts": "911833ae4fd10a1c84f6271f36151ab785955849117dc48c6e43b929504ee069", - "https://deno.land/std@0.213.0/path/glob.ts": "04510962905d4b1513b44da9cb195914e0fa46c24359f6feaca20848d797dcb0", - "https://deno.land/std@0.213.0/path/glob_to_regexp.ts": "83c5fd36a8c86f5e72df9d0f45317f9546afa2ce39acaafe079d43a865aced08", - "https://deno.land/std@0.213.0/path/is_absolute.ts": "4791afc8bfd0c87f0526eaa616b0d16e7b3ab6a65b62942e50eac68de4ef67d7", - "https://deno.land/std@0.213.0/path/is_glob.ts": "a65f6195d3058c3050ab905705891b412ff942a292bcbaa1a807a74439a14141", - "https://deno.land/std@0.213.0/path/join.ts": "ae2ec5ca44c7e84a235fd532e4a0116bfb1f2368b394db1c4fb75e3c0f26a33a", - "https://deno.land/std@0.213.0/path/join_globs.ts": "e9589869a33dc3982101898ee50903db918ca00ad2614dbe3934d597d7b1fbea", - "https://deno.land/std@0.213.0/path/mod.ts": "ffeaccb713dbe6c72e015b7c767f753f8ec5fbc3b621ff5eeee486ffc2c0ddda", - "https://deno.land/std@0.213.0/path/normalize.ts": "4155743ccceeed319b350c1e62e931600272fad8ad00c417b91df093867a8352", - "https://deno.land/std@0.213.0/path/normalize_glob.ts": "98ee8268fad271193603271c203ae973280b5abfbdd2cbca1053fd2af71869ca", - "https://deno.land/std@0.213.0/path/parse.ts": "65e8e285f1a63b714e19ef24b68f56e76934c3df0b6e65fd440d3991f4f8aefb", - "https://deno.land/std@0.213.0/path/posix/_util.ts": "1e3937da30f080bfc99fe45d7ed23c47dd8585c5e473b2d771380d3a6937cf9d", - "https://deno.land/std@0.213.0/path/posix/basename.ts": "39ee27a29f1f35935d3603ccf01d53f3d6e0c5d4d0f84421e65bd1afeff42843", - "https://deno.land/std@0.213.0/path/posix/common.ts": "26f60ccc8b2cac3e1613000c23ac5a7d392715d479e5be413473a37903a2b5d4", - "https://deno.land/std@0.213.0/path/posix/constants.ts": "93481efb98cdffa4c719c22a0182b994e5a6aed3047e1962f6c2c75b7592bef1", - "https://deno.land/std@0.213.0/path/posix/dirname.ts": "6535d2bdd566118963537b9dda8867ba9e2a361015540dc91f5afbb65c0cce8b", - "https://deno.land/std@0.213.0/path/posix/extname.ts": "8d36ae0082063c5e1191639699e6f77d3acf501600a3d87b74943f0ae5327427", - "https://deno.land/std@0.213.0/path/posix/format.ts": "185e9ee2091a42dd39e2a3b8e4925370ee8407572cee1ae52838aed96310c5c1", - "https://deno.land/std@0.213.0/path/posix/from_file_url.ts": "951aee3a2c46fd0ed488899d024c6352b59154c70552e90885ed0c2ab699bc40", - "https://deno.land/std@0.213.0/path/posix/glob_to_regexp.ts": "54d3ff40f309e3732ab6e5b19d7111d2d415248bcd35b67a99defcbc1972e697", - "https://deno.land/std@0.213.0/path/posix/is_absolute.ts": "cebe561ad0ae294f0ce0365a1879dcfca8abd872821519b4fcc8d8967f888ede", - "https://deno.land/std@0.213.0/path/posix/is_glob.ts": "8a8b08c08bf731acf2c1232218f1f45a11131bc01de81e5f803450a5914434b9", - "https://deno.land/std@0.213.0/path/posix/join.ts": "aef88d5fa3650f7516730865dbb951594d1a955b785e2450dbee93b8e32694f3", - "https://deno.land/std@0.213.0/path/posix/join_globs.ts": "ee2f4676c5b8a0dfa519da58b8ade4d1c4aa8dd3fe35619edec883ae9df1f8c9", - "https://deno.land/std@0.213.0/path/posix/mod.ts": "563a18c2b3ddc62f3e4a324ff0f583e819b8602a72ad880cb98c9e2e34f8db5b", - "https://deno.land/std@0.213.0/path/posix/normalize.ts": "baeb49816a8299f90a0237d214cef46f00ba3e95c0d2ceb74205a6a584b58a91", - "https://deno.land/std@0.213.0/path/posix/normalize_glob.ts": "65f0138fa518ef9ece354f32889783fc38cdf985fb02dcf1c3b14fa47d665640", - "https://deno.land/std@0.213.0/path/posix/parse.ts": "d5bac4eb21262ab168eead7e2196cb862940c84cee572eafedd12a0d34adc8fb", - "https://deno.land/std@0.213.0/path/posix/relative.ts": "3907d6eda41f0ff723d336125a1ad4349112cd4d48f693859980314d5b9da31c", - "https://deno.land/std@0.213.0/path/posix/resolve.ts": "bac20d9921beebbbb2b73706683b518b1d0c1b1da514140cee409e90d6b2913a", - "https://deno.land/std@0.213.0/path/posix/separator.ts": "c9ecae5c843170118156ac5d12dc53e9caf6a1a4c96fc8b1a0ab02dff5c847b0", - "https://deno.land/std@0.213.0/path/posix/to_file_url.ts": "7aa752ba66a35049e0e4a4be5a0a31ac6b645257d2e031142abb1854de250aaf", - "https://deno.land/std@0.213.0/path/posix/to_namespaced_path.ts": "28b216b3c76f892a4dca9734ff1cc0045d135532bfd9c435ae4858bfa5a2ebf0", - "https://deno.land/std@0.213.0/path/relative.ts": "ab739d727180ed8727e34ed71d976912461d98e2b76de3d3de834c1066667add", - "https://deno.land/std@0.213.0/path/resolve.ts": "a6f977bdb4272e79d8d0ed4333e3d71367cc3926acf15ac271f1d059c8494d8d", - "https://deno.land/std@0.213.0/path/separator.ts": "c6c890507f944a1f5cb7d53b8d638d6ce3cf0f34609c8d84a10c1eaa400b77a9", - "https://deno.land/std@0.213.0/path/to_file_url.ts": "88f049b769bce411e2d2db5bd9e6fd9a185a5fbd6b9f5ad8f52bef517c4ece1b", - "https://deno.land/std@0.213.0/path/to_namespaced_path.ts": "b706a4103b104cfadc09600a5f838c2ba94dbcdb642344557122dda444526e40", - "https://deno.land/std@0.213.0/path/windows/_util.ts": "d5f47363e5293fced22c984550d5e70e98e266cc3f31769e1710511803d04808", - "https://deno.land/std@0.213.0/path/windows/basename.ts": "e2dbf31d1d6385bfab1ce38c333aa290b6d7ae9e0ecb8234a654e583cf22f8fe", - "https://deno.land/std@0.213.0/path/windows/common.ts": "26f60ccc8b2cac3e1613000c23ac5a7d392715d479e5be413473a37903a2b5d4", - "https://deno.land/std@0.213.0/path/windows/constants.ts": "5afaac0a1f67b68b0a380a4ef391bf59feb55856aa8c60dfc01bd3b6abb813f5", - "https://deno.land/std@0.213.0/path/windows/dirname.ts": "33e421be5a5558a1346a48e74c330b8e560be7424ed7684ea03c12c21b627bc9", - "https://deno.land/std@0.213.0/path/windows/extname.ts": "165a61b00d781257fda1e9606a48c78b06815385e7d703232548dbfc95346bef", - "https://deno.land/std@0.213.0/path/windows/format.ts": "bbb5ecf379305b472b1082cd2fdc010e44a0020030414974d6029be9ad52aeb6", - "https://deno.land/std@0.213.0/path/windows/from_file_url.ts": "ced2d587b6dff18f963f269d745c4a599cf82b0c4007356bd957cb4cb52efc01", - "https://deno.land/std@0.213.0/path/windows/glob_to_regexp.ts": "6dcd1242bd8907aa9660cbdd7c93446e6927b201112b0cba37ca5d80f81be51b", - "https://deno.land/std@0.213.0/path/windows/is_absolute.ts": "4a8f6853f8598cf91a835f41abed42112cebab09478b072e4beb00ec81f8ca8a", - "https://deno.land/std@0.213.0/path/windows/is_glob.ts": "8a8b08c08bf731acf2c1232218f1f45a11131bc01de81e5f803450a5914434b9", - "https://deno.land/std@0.213.0/path/windows/join.ts": "e0b3356615c1a75c56ebb6a7311157911659e11fd533d80d724800126b761ac3", - "https://deno.land/std@0.213.0/path/windows/join_globs.ts": "ee2f4676c5b8a0dfa519da58b8ade4d1c4aa8dd3fe35619edec883ae9df1f8c9", - "https://deno.land/std@0.213.0/path/windows/mod.ts": "7d6062927bda47c47847ffb55d8f1a37b0383840aee5c7dfc93984005819689c", - "https://deno.land/std@0.213.0/path/windows/normalize.ts": "78126170ab917f0ca355a9af9e65ad6bfa5be14d574c5fb09bb1920f52577780", - "https://deno.land/std@0.213.0/path/windows/normalize_glob.ts": "179c86ba89f4d3fe283d2addbe0607341f79ee9b1ae663abcfb3439db2e97810", - "https://deno.land/std@0.213.0/path/windows/parse.ts": "b9239edd892a06a06625c1b58425e199f018ce5649ace024d144495c984da734", - "https://deno.land/std@0.213.0/path/windows/relative.ts": "3e1abc7977ee6cc0db2730d1f9cb38be87b0ce4806759d271a70e4997fc638d7", - "https://deno.land/std@0.213.0/path/windows/resolve.ts": "75b2e3e1238d840782cee3d8864d82bfaa593c7af8b22f19c6422cf82f330ab3", - "https://deno.land/std@0.213.0/path/windows/separator.ts": "e51c5522140eff4f8402617c5c68a201fdfa3a1a8b28dc23587cff931b665e43", - "https://deno.land/std@0.213.0/path/windows/to_file_url.ts": "1cd63fd35ec8d1370feaa4752eccc4cc05ea5362a878be8dc7db733650995484", - "https://deno.land/std@0.213.0/path/windows/to_namespaced_path.ts": "4ffa4fb6fae321448d5fe810b3ca741d84df4d7897e61ee29be961a6aac89a4c", - "https://deno.land/std@0.213.0/semver/_constants.ts": "90879e4ea94a34c49c8ecea3d9c06e13e61ecb7caca80c8f289139440ca9835a", - "https://deno.land/std@0.213.0/semver/_shared.ts": "8d44684775cde4a64bd6bdb99b51f3bc59ed65f10af78ca136cc2eab3f6716f1", - "https://deno.land/std@0.213.0/semver/comparator_format.ts": "41f00b1275923317fa3f7c39df58fa7f62f541b0f231134c1655bc8a42965393", - "https://deno.land/std@0.213.0/semver/comparator_intersects.ts": "dc231c5ebded8e88b8355a33edfbd228e36a08384848d73c15d394833384ee8f", - "https://deno.land/std@0.213.0/semver/comparator_max.ts": "2038cded7cce886e2c81926acb97f625908707f2d66864b603493b9674e2bd58", - "https://deno.land/std@0.213.0/semver/comparator_min.ts": "453d3e449aaee4d59acc9b36fe77eddfcb0c4097ffe7efe11eb2a04a64cc520d", - "https://deno.land/std@0.213.0/semver/compare.ts": "e507146fd997d33ae5abc2675e8b24a1ea84b50ddc9918cb8ddc1b1911c97011", - "https://deno.land/std@0.213.0/semver/constants.ts": "52dde17ff45479fbdc6b3a7198224e02a2deb9cb4f99ac6592c9727173f13a83", - "https://deno.land/std@0.213.0/semver/difference.ts": "be4f01b7745406408a16b708185a48c1c652cc87e0244b12a5ca75c5585db668", - "https://deno.land/std@0.213.0/semver/eq.ts": "7aaffb5d841dee589fa81e18d54fb4aec065feaa701f58214f89e17edbcf5da5", - "https://deno.land/std@0.213.0/semver/equals.ts": "8b9b18260c9a55feee9d3f9250fba345be922380f2e8f8009e455c394ce5e81d", - "https://deno.land/std@0.213.0/semver/format.ts": "26d3a357ac5abd73dee0fe7dbbac6107fbdce0a844370c7b1bcb673c92e46bf6", - "https://deno.land/std@0.213.0/semver/format_range.ts": "d472a7f743cf0290beebed90d1e6d8f1b5e93d91c03f3503e869f18931acd156", - "https://deno.land/std@0.213.0/semver/greater_or_equal.ts": "89c26f68070896944676eb9704cbb617febc6ed693720282741d6859c3d1fe80", - "https://deno.land/std@0.213.0/semver/greater_than.ts": "d8c4a227cd28ea80a1de9c80215d7f3f95786fe1b196f0cb5ec91d6567adad27", - "https://deno.land/std@0.213.0/semver/gt.ts": "e9a7b3e80eaf07fa949daf2622ed0be6f863d972f744557107fbfce7d6786624", - "https://deno.land/std@0.213.0/semver/gte.ts": "2f6deabbeb5c716d916d80bf6c0cfabbb00e0eb12c34420f2cf96dbb85fdc0f7", - "https://deno.land/std@0.213.0/semver/gtr.ts": "50cde7d0a05416f2a8b9d5125848e141eba474755d8c0e852ab2dfd22443ad2c", - "https://deno.land/std@0.213.0/semver/increment.ts": "427a043be71d6481e45c1a3939b955e800924d70779cb297b872d9cbf9f0e46d", - "https://deno.land/std@0.213.0/semver/is_comparator.ts": "895e7ecff33d23d7a465074a76b2341eda430f84c4817199f7492c5393e2e54f", - "https://deno.land/std@0.213.0/semver/is_semver.ts": "57914027d6141e593eb04418aaabbfd6f4562a1c53c6c33a1743fa50ada8d849", - "https://deno.land/std@0.213.0/semver/is_semver_range.ts": "1e4602ed91d5d7228e63765ab4d28042ee358304155a0eeb562871d030cabaee", - "https://deno.land/std@0.213.0/semver/less_or_equal.ts": "7dbf8190f37f3281048c30cf11e072a7af18685534ae88d295baa170b485bd90", - "https://deno.land/std@0.213.0/semver/less_than.ts": "b0c7902c54cecadcc7c1c80afc2f6a0f1bf0b3f53c8d2bfd11f01a3a414cccfe", - "https://deno.land/std@0.213.0/semver/lt.ts": "42b40467018e72e6637c68dde5439960a2db366e1edd730a8bb60a432d30f703", - "https://deno.land/std@0.213.0/semver/lte.ts": "678b9919c5abe85a7917f6815e74a323788f4a81f5da64d329b34cb32bb788c6", - "https://deno.land/std@0.213.0/semver/ltr.ts": "57ee19e33c90883d953e22255c0e02bfc8f682c610e32aab0a76db45a6cd159c", - "https://deno.land/std@0.213.0/semver/max_satisfying.ts": "1008802c70eaa6d13a9455f0bda7fcfbd0dd53d837d87930b8520411670d2766", - "https://deno.land/std@0.213.0/semver/min_satisfying.ts": "ad035539bb23c3d9545d5e9508123cd84be4ec47331acc23574795a3ae6c460e", - "https://deno.land/std@0.213.0/semver/mod.ts": "6c8c5aba6f9c1499e5e2bc1b1272d13157ed1f438296a095a14b8d321e805b59", - "https://deno.land/std@0.213.0/semver/neq.ts": "8c8c474249aa43331cc3d2a93ff0e824792f4fe823b674c79c50b778b06331a9", - "https://deno.land/std@0.213.0/semver/not_equals.ts": "17147a6f68b9d14f4643c1e2150378ccf6954710309f9618f75b411752a8e13d", - "https://deno.land/std@0.213.0/semver/outside.ts": "9953ed5935a1bc79b9d8e6258fa1717281a33bd5501f2ee0bc0fe6ed80b310b9", - "https://deno.land/std@0.213.0/semver/parse.ts": "2ba215c9aa3c71be753570724cfad75cc81972f0026dc81836ea3d1986112066", - "https://deno.land/std@0.213.0/semver/parse_comparator.ts": "94accf91b8c68c083a2fb932ff3afa81fb01cd5ce007d4e679f59ec86be3a132", - "https://deno.land/std@0.213.0/semver/parse_range.ts": "3242441370743df07919ca340be719acd9655311fa6a18e115761dfe562fc5ca", - "https://deno.land/std@0.213.0/semver/range_format.ts": "1d9f3a1b8176be0e49698929143da0e6a1b84f2581eb750e2cf17d7a0b6fac6c", - "https://deno.land/std@0.213.0/semver/range_intersects.ts": "461ce0045852511bbfe9204483ddbee897c4fb5557fc707e055edf98f15d5d30", - "https://deno.land/std@0.213.0/semver/range_max.ts": "c0eba7c51f462470bc3822227df57e0153deeacf47a4c40d5c27790fddd6cb92", - "https://deno.land/std@0.213.0/semver/range_min.ts": "37b9664103d5202c91f6228e8d7ac4ea508d7867f40a686dbe211e2a57f3efff", - "https://deno.land/std@0.213.0/semver/sort.ts": "b97c4f392cf688e27d304dc437b1a4d7278fbf5d2554ad6e51f64db6cc405c09", - "https://deno.land/std@0.213.0/semver/test_comparator.ts": "85476901a71fe8a09520902d85e1c573ce60a353846f8bbf6667e9518686591b", - "https://deno.land/std@0.213.0/semver/test_range.ts": "88de9dab0d61c82fd0861d50eabe72f0f27f29f3df4d50e83f36e09c1c3cd8a6", - "https://deno.land/std@0.213.0/semver/types.ts": "c85eb042ba22c69d62194ea7e535c3c104d0e9af75316b6315379101b4a7ef66", - "https://deno.land/std@0.213.0/streams/_common.ts": "4f9f2958d853b9a456be033631dabb7519daa68ee4d02caf53e2ecbffaf5805f", - "https://deno.land/std@0.213.0/streams/buffer.ts": "71120cceddacab2eb47a2f2908c64e82e79ac089506649bd41412042fcc97773", - "https://deno.land/std@0.213.0/streams/byte_slice_stream.ts": "5bbdcadb118390affa9b3d0a0f73ef8e83754f59bb89df349add669dd9369713", - "https://deno.land/std@0.213.0/streams/copy.ts": "442d1d647ce7daf350dd989797dd2eea51ec8ad3b3a6851fcdaf7ef44a387c71", - "https://deno.land/std@0.213.0/streams/delimiter_stream.ts": "45271f9db844e8e501a6df75b946cd2a5e01663de0e9ccf26b92996983e0cdbe", - "https://deno.land/std@0.213.0/streams/early_zip_readable_streams.ts": "21f5cf6dd36381c6a50c31a7727b5bd219f6382bbb7a413418595c3e466c4d14", - "https://deno.land/std@0.213.0/streams/iterate_reader.ts": "bd79a18de211449e5140e8f705e195c3e0e79020d752a64cd0a1d4b829b14633", - "https://deno.land/std@0.213.0/streams/limited_bytes_transform_stream.ts": "b22a45a337374e863c4eb1867ec6b8ad3e68620a6c52fe837746060ea610e6f1", - "https://deno.land/std@0.213.0/streams/limited_transform_stream.ts": "4c47da5ca38a30fa9f33b0f1a61d4548e7f52a9a58c294b0f430f680e44cc543", - "https://deno.land/std@0.213.0/streams/merge_readable_streams.ts": "9c541012e130d6e36086b6b8c197078a6053f5446367e33f233b71858a2c03cc", - "https://deno.land/std@0.213.0/streams/mod.ts": "cbe5466def4eb5e44a628df7be4700f7e2f88ac8b7d82cf3d769cfef5233aca4", - "https://deno.land/std@0.213.0/streams/read_all.ts": "b39b7d56b3ef9c0f78bbde82244ab3663b4adc1dee1be6ec97c0117f033c884c", - "https://deno.land/std@0.213.0/streams/readable_stream_from_reader.ts": "4289a63836f73901441c1879f2be76eea2a983920f4b10a4a9b8a6d8c29ece56", - "https://deno.land/std@0.213.0/streams/reader_from_iterable.ts": "cf7785e518beaaba1dfb3ff4ae854bb76499bbc1f013910af6402ec7643bf769", - "https://deno.land/std@0.213.0/streams/reader_from_stream_reader.ts": "f981cf94a42133e5c6ace8c3b500565750806c4fc9802262ee63746abc528b0d", - "https://deno.land/std@0.213.0/streams/text_delimiter_stream.ts": "ef0d7898cea4a9fff850173ed9f3d2cf9e42ba858d8175bd89fe851c8dfa6a6e", - "https://deno.land/std@0.213.0/streams/text_line_stream.ts": "21f33d3922e019ec1a1676474beb543929cb564ec99b69cd2654e029e0f45bd5", - "https://deno.land/std@0.213.0/streams/to_array_buffer.ts": "1a9c07c4a396ce557ab205c44415815ab13b614fed94a12f62b80f8e650c726d", - "https://deno.land/std@0.213.0/streams/to_blob.ts": "bf5daaae50fa8f57e0c8bfd7474ebac16ac09e130e3d01ef2947ae5153912b4a", - "https://deno.land/std@0.213.0/streams/to_json.ts": "b6a908d0da7cd30956e5fbbfa7460747e50b8f307d1041282ed6fe9070d579ee", - "https://deno.land/std@0.213.0/streams/to_text.ts": "6f93593bdfc2cea5cca39755ea5caf0d4092580c0a713dfe04a1e85c60df331f", - "https://deno.land/std@0.213.0/streams/to_transform_stream.ts": "4c4836455ef89bab9ece55975ee3a819f07d3d8b0e43101ec7f4ed033c8a2b61", - "https://deno.land/std@0.213.0/streams/writable_stream_from_writer.ts": "62f2712d3a7bebd981fca8bd5140192c37450f9c4aa94283f7ca833e46bc7485", - "https://deno.land/std@0.213.0/streams/write_all.ts": "3170620e750c1eaf43ac9e216669f55df762e2dc827d8b8a920b4f64a803c362", - "https://deno.land/std@0.213.0/streams/writer_from_stream_writer.ts": "b0e39ef607dfdc5abdfb627edf61a9672809463e2bb022afcbaf0cd006c40feb", - "https://deno.land/std@0.213.0/streams/zip_readable_streams.ts": "53eb10d7557539b489bd858907aab6dd28247f074b3446573801de3150cb932e", - "https://deno.land/std@0.213.0/url/_strip.ts": "928fe9af16d7c5bf24816d1e90d84bfe702f3e059f9d63509b5a37087e947800", - "https://deno.land/std@0.213.0/url/basename.ts": "a2e6ef35d44da3764551cbc61cdd39004c778aaedc7a6c2559e571f018c42daa", - "https://deno.land/std@0.213.0/url/dirname.ts": "0915864aac7d2d0413c90dff7841b18b29c83ed102fa340e760af1fb2c0ad26c", - "https://deno.land/std@0.213.0/url/extname.ts": "b247eac636161c5e263220c6e5116ed10e0c1702b5e90fad258a88c0b3b6bf98", - "https://deno.land/std@0.213.0/url/join.ts": "00c7e9088cafaa24963ce4081119e58b3afe2c58f033701383f359ea02620dd2", - "https://deno.land/std@0.213.0/url/mod.ts": "e2621f6a0db6fdbe7fbbd240064095bb203014657e5e1ab81db1c44d80dce6c9", - "https://deno.land/std@0.213.0/url/normalize.ts": "6328c75df0fab300f74bc4a1c255062a0db882240e15ab646606d0009e7e40d7", - "https://deno.land/std@0.221.0/assert/assert.ts": "bec068b2fccdd434c138a555b19a2c2393b71dfaada02b7d568a01541e67cdc5", - "https://deno.land/std@0.221.0/assert/assertion_error.ts": "9f689a101ee586c4ce92f52fa7ddd362e86434ffdf1f848e45987dc7689976b8", - "https://deno.land/std@0.221.0/console/_data.json": "cf2cc9d039a192b3adbfe64627167c7e6212704c888c25c769fc8f1709e1e1b8", - "https://deno.land/std@0.221.0/console/_run_length.ts": "7da8642a0f4f41ac27c0adb1364e18886be856c1d08c5cce6c6b5c00543c8722", - "https://deno.land/std@0.221.0/console/unicode_width.ts": "d92f085c0ab9c7ab171e4e7862dfd9d3a36ffd369939be5d3e1140ec58bc820f", - "https://deno.land/std@0.221.0/fmt/colors.ts": "d239d84620b921ea520125d778947881f62c50e78deef2657073840b8af9559a", - "https://deno.land/std@0.221.0/text/closest_string.ts": "8a91ee8b6d69ff96addcb7c251dad53b476ac8be9c756a0ef786abe9e13a93a5", - "https://deno.land/std@0.221.0/text/levenshtein_distance.ts": "24be5cc88326bbba83ca7c1ea89259af0050cffda2817ff3a6d240ad6495eae2", - "https://deno.land/std@0.76.0/encoding/base64.ts": "b1d8f99b778981548457ec74bc6273ad785ffd6f61b2233bd5b30925345b565d", - "https://deno.land/std@0.76.0/encoding/hex.ts": "07a03ba41c96060a4ed4ba272e50b9e23f3c5b3839f4b069cdebc24d57434386", - "https://deno.land/std@0.76.0/hash/_wasm/hash.ts": "005f64c4d9343ecbc91e0da9ae5e800f146c20930ad829bbb872c5c06bd89c5f", - "https://deno.land/std@0.76.0/hash/_wasm/wasm.js": "5ac48aa0c3931d7f31dba628be5ab0aa4e786354197eb4d7d0583f9b50be1397", - "https://deno.land/std@0.76.0/hash/mod.ts": "e764a6a9ab2f5519a97f928e17cc13d984e3dd5c7f742ff9c1c8fb3114790f0c", - "https://deno.land/x/cliffy@v1.0.0-rc.3/_utils/distance.ts": "02af166952c7c358ac83beae397aa2fbca4ad630aecfcd38d92edb1ea429f004", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/_argument_types.ts": "ab269dacea2030f865a07c2a1e953ec437a64419a05bad1f1ddaab3f99752ead", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/_errors.ts": "12d513ff401020287a344e0830e1297ce1c80c077ecb91e0ac5db44d04a6019c", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/_spread.ts": "0cc6eb70a6df97b5d7d26008822d39f3e8a1232ee0a27f395aa19e68de738245", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/_type_utils.ts": "820004a59bc858e355b11f80e5b3ff1be2c87e66f31f53f253610170795602f0", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/_utils.ts": "3c88ff4f36eba298beb07de08068fdce5e5cb7b9d82c8a319f09596d8279be64", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/command.ts": "ae690745759524082776b7f271f66d5b93933170b1b132f888bd4ac12e9fdd7d", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/completions/_bash_completions_generator.ts": "0c6cb1df4d378d22f001155781d97a9c3519fd10c48187a198fef2cc63b0f84a", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/completions/_fish_completions_generator.ts": "8ba4455f7f76a756e05c3db4ce35332b2951af65a2891f2750b530e06880f495", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/completions/_zsh_completions_generator.ts": "c74525feaf570fe8c14433c30d192622c25603f1fc64694ef69f2a218b41f230", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/completions/bash.ts": "53fe78994eb2359110dc4fa79235bdd86800a38c1d6b1c4fe673c81756f3a0e2", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/completions/complete.ts": "58df61caa5e6220ff2768636a69337923ad9d4b8c1932aeb27165081c4d07d8b", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/completions/completions_command.ts": "506f97f1c6b0b1c3e9956e5069070028b818942310600d4157f64c9b644d3c49", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/completions/fish.ts": "6f0b44b4067740b2931c9ec8863b6619b1d3410fea0c5a3988525a4c53059197", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/completions/mod.ts": "8dda715ca25f3f66d5ec232b76d7c9a96dd4c64b5029feff91738cc0c9586fb1", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/completions/zsh.ts": "f1263c3946975e090d4aadc8681db811d86b52a8ae680f246e03248025885c21", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/deprecated.ts": "bbe6670f1d645b773d04b725b8b8e7814c862c9f1afba460c4d599ffe9d4983c", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/deps.ts": "7473ebd5625bf901becd7ff80afdde3b8a50ae5d1bbfa2f43805cfacf4559d5a", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/help/_help_generator.ts": "532dd4a928baab8b45ce46bb6d20e2ebacfdf3da141ce9d12da796652b1de478", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/help/help_command.ts": "fbbf0c0827dd21d3cec7bcc68c00c20b55f53e2b621032891b9d23ac4191231c", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/help/mod.ts": "8369b292761dcc9ddaf41f2d34bfb06fb6800b69efe80da4fc9752c3b890275b", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/mod.ts": "4b708df1b97152522bee0e3828f06abbbc1d2250168910e5cf454950d7b7404b", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/type.ts": "f588f5d9635b79100044e62aced4b00e510e75b83801f9b089c40c2d98674de2", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/types.ts": "bc9ff7459b9cc1079eeb95ff101690a51b4b4afa4af5623340076ee361d08dbb", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/action_list.ts": "33c98d449617c7a563a535c9ceb3741bde9f6363353fd492f90a74570c611c27", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/boolean.ts": "3879ec16092b4b5b1a0acb8675f8c9250c0b8a972e1e4c7adfba8335bd2263ed", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/child_command.ts": "f1fca390c7fbfa7a713ca15ef55c2c7656bcbb394d50e8ef54085bdf6dc22559", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/command.ts": "325d0382e383b725fd8d0ef34ebaeae082c5b76a1f6f2e843fee5dbb1a4fe3ac", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/enum.ts": "8a7cd2898e03089234083bb78c8b1d9b7172254c53c32d4710321638165a48ec", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/file.ts": "8618f16ac9015c8589cbd946b3de1988cc4899b90ea251f3325c93c46745140e", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/integer.ts": "29864725fd48738579d18123d7ee78fed37515e6dc62146c7544c98a82f1778d", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/number.ts": "aeba96e6f470309317a16b308c82e0e4138a830ec79c9877e4622c682012bc1f", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/types/string.ts": "e4dadb08a11795474871c7967beab954593813bb53d9f69ea5f9b734e43dc0e0", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/upgrade/_check_version.ts": "6cfa7dc26bc0dc46381500e8d4b130fb224f4c5456152dada15bd3793edca89b", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/upgrade/mod.ts": "4eff69c489467be17dea27fb95a795396111ee385d170ac0cbcc82f0ea38156c", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/upgrade/provider.ts": "c23253334097dc4b8a147ccdeb3aa44f5a95aa953a6386cb5396f830d95d77a5", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/upgrade/provider/deno_land.ts": "24f8d82e38c51e09be989f30f8ad21f9dd41ac1bb1973b443a13883e8ba06d6d", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/upgrade/provider/github.ts": "99e1b133dd446c6aa79f69e69c46eb8bc1c968dd331c2a7d4064514a317c7b59", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/upgrade/provider/nest_land.ts": "0e07936cea04fa41ac9297f32d87f39152ea873970c54cb5b4934b12fee1885e", - "https://deno.land/x/cliffy@v1.0.0-rc.3/command/upgrade/upgrade_command.ts": "3640a287d914190241ea1e636774b1b4b0e1828fa75119971dd5304784061e05", - "https://deno.land/x/cliffy@v1.0.0-rc.3/flags/_errors.ts": "f1fbb6bfa009e7950508c9d491cfb4a5551027d9f453389606adb3f2327d048f", - "https://deno.land/x/cliffy@v1.0.0-rc.3/flags/_utils.ts": "340d3ecab43cde9489187e1f176504d2c58485df6652d1cdd907c0e9c3ce4cc2", - "https://deno.land/x/cliffy@v1.0.0-rc.3/flags/_validate_flags.ts": "e60b9038c0136ab7e6bd1baf0e993a07bf23f18afbfb6e12c59adf665a622957", - "https://deno.land/x/cliffy@v1.0.0-rc.3/flags/deprecated.ts": "a72a35de3cc7314e5ebea605ca23d08385b218ef171c32a3f135fb4318b08126", - "https://deno.land/x/cliffy@v1.0.0-rc.3/flags/flags.ts": "3e62c4a9756b5705aada29e7e94847001356b3a83cd18ad56f4207387a71cf51", - "https://deno.land/x/cliffy@v1.0.0-rc.3/flags/types.ts": "9e2f75edff2217d972fc711a21676a59dfd88378da2f1ace440ea84c07db1dcc", - "https://deno.land/x/cliffy@v1.0.0-rc.3/flags/types/boolean.ts": "4c026dd66ec9c5436860dc6d0241427bdb8d8e07337ad71b33c08193428a2236", - "https://deno.land/x/cliffy@v1.0.0-rc.3/flags/types/integer.ts": "b60d4d590f309ddddf066782d43e4dc3799f0e7d08e5ede7dc62a5ee94b9a6d9", - "https://deno.land/x/cliffy@v1.0.0-rc.3/flags/types/number.ts": "610936e2d29de7c8c304b65489a75ebae17b005c6122c24e791fbed12444d51e", - "https://deno.land/x/cliffy@v1.0.0-rc.3/flags/types/string.ts": "e89b6a5ce322f65a894edecdc48b44956ec246a1d881f03e97bbda90dd8638c5", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/_layout.ts": "e4a518da28333de95ad791208b9930025987c8b93d5f8b7f30b377b3e26b24e1", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/_utils.ts": "fd48d1a524a42e72aa3ad2eec858a92f5a00728d306c7e8436fba6c34314fee6", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/border.ts": "5c6e9ef5078c6930169aacb668b274bdbb498461c724a7693ac9270fe9d3f5d5", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/cell.ts": "1ffabd43b6b7fddfac9625cb0d015532e144702a9bfed03b358b79375115d06b", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/column.ts": "cf14009f2cb14bad156f879946186c1893acdc6a2fee6845db152edddb6a2714", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/consume_words.ts": "456e75755fdf6966abdefb8b783df2855e2a8bad6ddbdf21bd748547c5fc1d4b", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/deps.ts": "1226c4d39d53edc81d7c3e661fb8a79f2e704937c276c60355cd4947a0fe9153", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/row.ts": "79eb1468aafdd951e5963898cdafe0752d4ab4c519d5f847f3d8ecb8fe857d4f", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/table.ts": "298671e72e61f1ab18b42ae36643181993f79e29b39dc411fdc6ffd53aa04684", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/_argument_types.ts": "ab269dacea2030f865a07c2a1e953ec437a64419a05bad1f1ddaab3f99752ead", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/_errors.ts": "d78e1b4d69d84b8b476b5f3c0b028e3906d48f21b8f1ca1d36d5abe9ccfe48bc", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/_spread.ts": "0cc6eb70a6df97b5d7d26008822d39f3e8a1232ee0a27f395aa19e68de738245", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/_type_utils.ts": "820004a59bc858e355b11f80e5b3ff1be2c87e66f31f53f253610170795602f0", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/_utils.ts": "fa0e88cc4215b18554a7308e8e2ae3a12be0fb91c54d1473c54c530dbd4adfcb", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/command.ts": "83cbece11c1459d5bc5add32c3cad0bf49e92c4ddd3ef00f22f80efdae30994e", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/completions/_bash_completions_generator.ts": "0c6cb1df4d378d22f001155781d97a9c3519fd10c48187a198fef2cc63b0f84a", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/completions/_fish_completions_generator.ts": "8ba4455f7f76a756e05c3db4ce35332b2951af65a2891f2750b530e06880f495", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/completions/_zsh_completions_generator.ts": "9df79fbac17a32b9645d01628c41a2bfd295d7976b87b0ae235f50a9c8975fbc", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/completions/bash.ts": "53fe78994eb2359110dc4fa79235bdd86800a38c1d6b1c4fe673c81756f3a0e2", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/completions/complete.ts": "58df61caa5e6220ff2768636a69337923ad9d4b8c1932aeb27165081c4d07d8b", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/completions/completions_command.ts": "506f97f1c6b0b1c3e9956e5069070028b818942310600d4157f64c9b644d3c49", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/completions/fish.ts": "6f0b44b4067740b2931c9ec8863b6619b1d3410fea0c5a3988525a4c53059197", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/completions/mod.ts": "8dda715ca25f3f66d5ec232b76d7c9a96dd4c64b5029feff91738cc0c9586fb1", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/completions/zsh.ts": "f1263c3946975e090d4aadc8681db811d86b52a8ae680f246e03248025885c21", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/deprecated.ts": "bbe6670f1d645b773d04b725b8b8e7814c862c9f1afba460c4d599ffe9d4983c", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/deps.ts": "a58ea2fa4e2ed9b39bb8dd8c35dd0498c74f05392517ff230a9a4d04c4c766b7", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/help/_help_generator.ts": "98619da83ff25523280a6fdcad89af3f13a6fafefc81b71f8230f3344b5ff2c5", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/help/help_command.ts": "fbbf0c0827dd21d3cec7bcc68c00c20b55f53e2b621032891b9d23ac4191231c", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/help/mod.ts": "8369b292761dcc9ddaf41f2d34bfb06fb6800b69efe80da4fc9752c3b890275b", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/mod.ts": "4b708df1b97152522bee0e3828f06abbbc1d2250168910e5cf454950d7b7404b", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/type.ts": "f588f5d9635b79100044e62aced4b00e510e75b83801f9b089c40c2d98674de2", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/types.ts": "bc9ff7459b9cc1079eeb95ff101690a51b4b4afa4af5623340076ee361d08dbb", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/types/action_list.ts": "33c98d449617c7a563a535c9ceb3741bde9f6363353fd492f90a74570c611c27", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/types/boolean.ts": "3879ec16092b4b5b1a0acb8675f8c9250c0b8a972e1e4c7adfba8335bd2263ed", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/types/child_command.ts": "f1fca390c7fbfa7a713ca15ef55c2c7656bcbb394d50e8ef54085bdf6dc22559", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/types/command.ts": "325d0382e383b725fd8d0ef34ebaeae082c5b76a1f6f2e843fee5dbb1a4fe3ac", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/types/enum.ts": "8a7cd2898e03089234083bb78c8b1d9b7172254c53c32d4710321638165a48ec", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/types/file.ts": "8618f16ac9015c8589cbd946b3de1988cc4899b90ea251f3325c93c46745140e", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/types/integer.ts": "29864725fd48738579d18123d7ee78fed37515e6dc62146c7544c98a82f1778d", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/types/number.ts": "aeba96e6f470309317a16b308c82e0e4138a830ec79c9877e4622c682012bc1f", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/types/string.ts": "e4dadb08a11795474871c7967beab954593813bb53d9f69ea5f9b734e43dc0e0", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/upgrade/_check_version.ts": "6cfa7dc26bc0dc46381500e8d4b130fb224f4c5456152dada15bd3793edca89b", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/upgrade/mod.ts": "4eff69c489467be17dea27fb95a795396111ee385d170ac0cbcc82f0ea38156c", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/upgrade/provider.ts": "c23253334097dc4b8a147ccdeb3aa44f5a95aa953a6386cb5396f830d95d77a5", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/upgrade/provider/deno_land.ts": "24f8d82e38c51e09be989f30f8ad21f9dd41ac1bb1973b443a13883e8ba06d6d", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/upgrade/provider/github.ts": "99e1b133dd446c6aa79f69e69c46eb8bc1c968dd331c2a7d4064514a317c7b59", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/upgrade/provider/nest_land.ts": "0e07936cea04fa41ac9297f32d87f39152ea873970c54cb5b4934b12fee1885e", - "https://deno.land/x/cliffy@v1.0.0-rc.4/command/upgrade/upgrade_command.ts": "27191f4b1ce93581b6d5ee2fff6003fe4fca437f476ecb98b6eae92f2b4d0716", - "https://deno.land/x/cliffy@v1.0.0-rc.4/flags/_errors.ts": "f1fbb6bfa009e7950508c9d491cfb4a5551027d9f453389606adb3f2327d048f", - "https://deno.land/x/cliffy@v1.0.0-rc.4/flags/_utils.ts": "25e519ce1f35acc8b43c75d1ca1c4ab591e7dab08327b7b408705b591e27d8bd", - "https://deno.land/x/cliffy@v1.0.0-rc.4/flags/_validate_flags.ts": "e60b9038c0136ab7e6bd1baf0e993a07bf23f18afbfb6e12c59adf665a622957", - "https://deno.land/x/cliffy@v1.0.0-rc.4/flags/deprecated.ts": "a72a35de3cc7314e5ebea605ca23d08385b218ef171c32a3f135fb4318b08126", - "https://deno.land/x/cliffy@v1.0.0-rc.4/flags/deps.ts": "bed26afff36eeb25509440edec9d5d141b3411e08cc7a90e38a370969b5166bb", - "https://deno.land/x/cliffy@v1.0.0-rc.4/flags/flags.ts": "3e62c4a9756b5705aada29e7e94847001356b3a83cd18ad56f4207387a71cf51", - "https://deno.land/x/cliffy@v1.0.0-rc.4/flags/types.ts": "9e2f75edff2217d972fc711a21676a59dfd88378da2f1ace440ea84c07db1dcc", - "https://deno.land/x/cliffy@v1.0.0-rc.4/flags/types/boolean.ts": "4c026dd66ec9c5436860dc6d0241427bdb8d8e07337ad71b33c08193428a2236", - "https://deno.land/x/cliffy@v1.0.0-rc.4/flags/types/integer.ts": "b60d4d590f309ddddf066782d43e4dc3799f0e7d08e5ede7dc62a5ee94b9a6d9", - "https://deno.land/x/cliffy@v1.0.0-rc.4/flags/types/number.ts": "610936e2d29de7c8c304b65489a75ebae17b005c6122c24e791fbed12444d51e", - "https://deno.land/x/cliffy@v1.0.0-rc.4/flags/types/string.ts": "e89b6a5ce322f65a894edecdc48b44956ec246a1d881f03e97bbda90dd8638c5", - "https://deno.land/x/cliffy@v1.0.0-rc.4/table/_layout.ts": "73a9bcb8a87b3a6817c4c9d2a31a21b874a7dd690ade1c64c9a1f066d628d626", - "https://deno.land/x/cliffy@v1.0.0-rc.4/table/_utils.ts": "13390db3f11977b7a4fc1202fa8386be14696b475a7f46a65178354f9a6640b7", - "https://deno.land/x/cliffy@v1.0.0-rc.4/table/border.ts": "5c6e9ef5078c6930169aacb668b274bdbb498461c724a7693ac9270fe9d3f5d5", - "https://deno.land/x/cliffy@v1.0.0-rc.4/table/cell.ts": "65e3ee699c3cebeb4d4d44e8f156e37a8532a0f317359d73178a95724d3f9267", - "https://deno.land/x/cliffy@v1.0.0-rc.4/table/column.ts": "cf14009f2cb14bad156f879946186c1893acdc6a2fee6845db152edddb6a2714", - "https://deno.land/x/cliffy@v1.0.0-rc.4/table/consume_words.ts": "369d065dbf7f15c664ea8523e0ef750fb952aea6d88e146c375e64aec9503052", - "https://deno.land/x/cliffy@v1.0.0-rc.4/table/deps.ts": "cbb896e8d7a6b5e3c2b9dda7d16638c202d9b46eb738c2dae1fa9480d8091486", - "https://deno.land/x/cliffy@v1.0.0-rc.4/table/row.ts": "79eb1468aafdd951e5963898cdafe0752d4ab4c519d5f847f3d8ecb8fe857d4f", - "https://deno.land/x/cliffy@v1.0.0-rc.4/table/table.ts": "298671e72e61f1ab18b42ae36643181993f79e29b39dc411fdc6ffd53aa04684", - "https://deno.land/x/dax@0.38.0/mod.ts": "3a5d7e6ac12547feec5d3c0c96717f14276891a3802fbbc73e5901e4f20eb08d", - "https://deno.land/x/dax@0.38.0/src/command.ts": "f20135ef7188a0fc9f773d50e88775dee8653044a7f536fb2fb885b293c26ec4", - "https://deno.land/x/dax@0.38.0/src/command_handler.ts": "a9e40f0f1ec57318e62904b5785fede82dcdf1101922ebb3ebfad8f1c4d9c8df", - "https://deno.land/x/dax@0.38.0/src/commands/args.ts": "a138aef24294e3cbf13cef08f4836d018e8dd99fd06ad82e7e7f08ef680bbc1d", - "https://deno.land/x/dax@0.38.0/src/commands/cat.ts": "a136e9fe729d6b89c9bab469e6367f557bcddf3a4a3240b2ac280ff6da540b88", - "https://deno.land/x/dax@0.38.0/src/commands/cd.ts": "3d70605c6f8606008072f52763dbf4a979fa501975d006cf7f50eed0576936ab", - "https://deno.land/x/dax@0.38.0/src/commands/cp_mv.ts": "d57102f05f8eb6fb8f705e532a0e01c0dc7ba960c1e0828d4a5bef7ff411215f", - "https://deno.land/x/dax@0.38.0/src/commands/echo.ts": "8ca19f63779f8fa9cf2a29e21bdb31cfd6a3a09a820e5a83d6244325dea5f360", - "https://deno.land/x/dax@0.38.0/src/commands/exit.ts": "ef83eefb99270872ac679e38cee9aec345da9a345a3873fe6660f05aa577f937", - "https://deno.land/x/dax@0.38.0/src/commands/export.ts": "c10d1dc6a45fd00e40afa6b19d7ecd29d09333f422b5b0fc75863baf13350969", - "https://deno.land/x/dax@0.38.0/src/commands/mkdir.ts": "828a2d356fcff05d022f0e5ef76ed4a899b5370485fa4144fe378040a0f05aef", - "https://deno.land/x/dax@0.38.0/src/commands/printenv.ts": "4fc09ecf88e35bc9d810e3f45d1d8e808613e73701466ca6e48fca8d1810a48a", - "https://deno.land/x/dax@0.38.0/src/commands/pwd.ts": "6507d70bf02026bde8f58da166c37cdc2f7e1fda807b003f096aab077b866ee5", - "https://deno.land/x/dax@0.38.0/src/commands/rm.ts": "43ef496c34b722d007b945232d51273fcc6d7315f6198f6a6291bb7151941426", - "https://deno.land/x/dax@0.38.0/src/commands/sleep.ts": "413bacfd3bebf2a1397cda223776baadef8596f40558d6c2686ffd9b6ad80e54", - "https://deno.land/x/dax@0.38.0/src/commands/test.ts": "b0f56b3d1d038b47fe826bb3dab056746aefe12df6222e29150e7e6f78a51d9c", - "https://deno.land/x/dax@0.38.0/src/commands/touch.ts": "40a0292e5e4f35c057ac50445a124703355d2955a25b53a223aebf0b3b016e4e", - "https://deno.land/x/dax@0.38.0/src/commands/unset.ts": "1ffec8b32bbac8ef7b90b2ba1fc4d9339d3563ef8e302b14d119f9c220564985", - "https://deno.land/x/dax@0.38.0/src/common.ts": "37449926d3bc874aac4e4ff4ea06d46251dc54ad0bbb5721c7eb4920e2d5b591", - "https://deno.land/x/dax@0.38.0/src/console/confirm.ts": "d9128d10b77fcc0a8df2784f71c79df68f5c8e00a34b04547b9ba9ddf1c97f96", - "https://deno.land/x/dax@0.38.0/src/console/logger.ts": "e0ab5025915cef70df03681c756e211f25bb2e4331f82ed4256b17ddd9e794ea", - "https://deno.land/x/dax@0.38.0/src/console/mod.ts": "de8af7d646f6cb222eee6560171993690247941b13ed9d757789d16f019d73ee", - "https://deno.land/x/dax@0.38.0/src/console/multiSelect.ts": "31003744e58f45f720271bd034d8cfba1055c954ba02d77a2f2eb21e4c1ed55a", - "https://deno.land/x/dax@0.38.0/src/console/progress/format.ts": "15ddbb8051580f88ed499281e12ca6f881f875ab73268d7451d7113ee130bd7d", - "https://deno.land/x/dax@0.38.0/src/console/progress/interval.ts": "80188d980a27c2eb07c31324365118af549641442f0752fe7c3b0c91832e5046", - "https://deno.land/x/dax@0.38.0/src/console/progress/mod.ts": "dd9330c3edd1790d70808d043f417f0eaf80a4442a945545c38e47ce11e907b6", - "https://deno.land/x/dax@0.38.0/src/console/prompt.ts": "1ad65c8a5a27fb58ce6138f8ebefe2fca4cd12015fea550fbdc62f875d4b31f7", - "https://deno.land/x/dax@0.38.0/src/console/select.ts": "c9d7124d975bf34d52ea1ac88fd610ed39db8ee6505b9bb53f371cef2f56c6ab", - "https://deno.land/x/dax@0.38.0/src/console/utils.ts": "24b840d4e55eba0d5b2f79337d2940d5f9456d4d6836f35316e6495b7cb827b4", - "https://deno.land/x/dax@0.38.0/src/deps.ts": "c1e16434a805285d27c30c70a825473f88117dfa7e1d308408db1b1ab4fe743f", - "https://deno.land/x/dax@0.38.0/src/lib/mod.ts": "c992db99c8259ae3bf2d35666585dfefda84cf7cf4e624e42ea2ac7367900fe0", - "https://deno.land/x/dax@0.38.0/src/lib/rs_lib.generated.js": "0a1a482c4387379106ef0da69534ebc5b0c2a1ec9f6dab76833fe84a7e6bbdf6", - "https://deno.land/x/dax@0.38.0/src/path.ts": "451589cc3ad49cab084c50ad0ec07f7e2492a20d2f0ee7cfd80ab36360e6aa55", - "https://deno.land/x/dax@0.38.0/src/pipes.ts": "bbfc7d6bf0f0bfc363daa2f4d3c5ebf17025d82c4114d5b0ea444cf69d805670", - "https://deno.land/x/dax@0.38.0/src/request.ts": "461e16f53367c73c0ec16091c2fd6cb97a219f6af07a3a2a10029139bf404879", - "https://deno.land/x/dax@0.38.0/src/result.ts": "719a9b4bc6bafeec785106744381cd5f37927c973334fcba6a33b6418fb9e7be", - "https://deno.land/x/dax@0.38.0/src/shell.ts": "9b59a63de62003a0575f9c3300b5fff83cd7e5487582eceaa5f071a684d75e0e", - "https://deno.land/x/deep_eql@v5.0.1/index.js": "60e1547b99d4ae08df387067c2ac0a1b9ab42f212f0d8a11b8b0b61270d2b1c4", - "https://deno.land/x/diff_kit@v2.0.4/mod.ts": "3d88f6b8132feabe4c0863a5c65fdad05d44d52488de91205fc76abcbfd2eadd", - "https://deno.land/x/diff_kit@v2.0.4/private/diff.ts": "bc270998702ba73c8d2b1810feb54d3973615ce56a33d2ec64432e698f2f2613", - "https://deno.land/x/diff_kit@v2.0.4/private/diff_handler.ts": "2f96831bde217d6a84691abfe7d4580057aee4e9fe1cf753101a2eb703cef9aa", - "https://deno.land/x/foras@v2.1.4/src/deno/mod.ts": "c350ea5f32938e6dcb694df3761615f316d730dafc57440e9afd5f36f8e309fd", - "https://deno.land/x/foras@v2.1.4/src/deno/mods/mod.ts": "cc099bbce378f3cdaa94303e8aff2611e207442e5ac2d5161aba636bb4a95b46", - "https://deno.land/x/foras@v2.1.4/wasm/pkg/foras.js": "06f8875b456918b9671d52133f64f3047f1c95540feda87fdd4a55ba3d30091d", - "https://deno.land/x/foras@v2.1.4/wasm/pkg/foras.wasm.js": "2df8522df7243b0f05b1d188e220629cd5d2c92080a5f1407e15396fc35bebb3", - "https://deno.land/x/json_hash@0.2.0/canon.ts": "ce7c07abd871cd7f0eb1280ad9f58f6382f02f84a217898ce977cf35ad315877", - "https://deno.land/x/json_hash@0.2.0/crypto.ts": "8738b601a0cf52c0ff58242707e2d5f7f5ff8f7ca4d51d0282ad3b0bb56548cf", - "https://deno.land/x/json_hash@0.2.0/digest.ts": "95e3d996377eebebb960ad2b6e4fdd70d71543378a651c31de75f1e86b637fc7", - "https://deno.land/x/json_hash@0.2.0/hex.ts": "104154a6408c6b5b36ff35361011aeb3047941bd5a652724f5aebeeb89fcf9a8", - "https://deno.land/x/json_hash@0.2.0/merkle.ts": "cf48004b45fdf0412afd48fea0ba8bb16bf78f717a66a5ff505f6400a88c08cf", - "https://deno.land/x/json_hash@0.2.0/mod.ts": "b0fdd79a540d3fc6aa3e0a9a93fe6735b1a174d9ba2aba103e4a18ee4872acad", - "https://deno.land/x/jszip@0.11.0/mod.ts": "5661ddc18e9ac9c07e3c5d2483bc912a7022b6af0d784bb7b05035973e640ba1", - "https://deno.land/x/object_hash@2.0.3/index.ts": "74b20a0065dc0066c60510174626db1d18e53ec966edb6f76fa33a67aa0c44e3", - "https://deno.land/x/object_hash@2.0.3/mod.ts": "648559bcafb54b930d4b6a283cc2eef20afa54de471371a97c2ccf8116941148", - "https://deno.land/x/outdent@v0.8.0/src/index.ts": "6dc3df4108d5d6fedcdb974844d321037ca81eaaa16be6073235ff3268841a22", - "https://deno.land/x/which@0.3.0/mod.ts": "3e10d07953c14e4ddc809742a3447cef14202cdfe9be6678a1dfc8769c4487e6", - "https://deno.land/x/zod@v3.22.4/ZodError.ts": "4de18ff525e75a0315f2c12066b77b5c2ae18c7c15ef7df7e165d63536fdf2ea", - "https://deno.land/x/zod@v3.22.4/errors.ts": "5285922d2be9700cc0c70c95e4858952b07ae193aa0224be3cbd5cd5567eabef", - "https://deno.land/x/zod@v3.22.4/external.ts": "a6cfbd61e9e097d5f42f8a7ed6f92f93f51ff927d29c9fbaec04f03cbce130fe", - "https://deno.land/x/zod@v3.22.4/helpers/enumUtil.ts": "54efc393cc9860e687d8b81ff52e980def00fa67377ad0bf8b3104f8a5bf698c", - "https://deno.land/x/zod@v3.22.4/helpers/errorUtil.ts": "7a77328240be7b847af6de9189963bd9f79cab32bbc61502a9db4fe6683e2ea7", - "https://deno.land/x/zod@v3.22.4/helpers/parseUtil.ts": "f791e6e65a0340d85ad37d26cd7a3ba67126cd9957eac2b7163162155283abb1", - "https://deno.land/x/zod@v3.22.4/helpers/partialUtil.ts": "998c2fe79795257d4d1cf10361e74492f3b7d852f61057c7c08ac0a46488b7e7", - "https://deno.land/x/zod@v3.22.4/helpers/typeAliases.ts": "0fda31a063c6736fc3cf9090dd94865c811dfff4f3cb8707b932bf937c6f2c3e", - "https://deno.land/x/zod@v3.22.4/helpers/util.ts": "8baf19b19b2fca8424380367b90364b32503b6b71780269a6e3e67700bb02774", - "https://deno.land/x/zod@v3.22.4/index.ts": "d27aabd973613985574bc31f39e45cb5d856aa122ef094a9f38a463b8ef1a268", - "https://deno.land/x/zod@v3.22.4/locales/en.ts": "a7a25cd23563ccb5e0eed214d9b31846305ddbcdb9c5c8f508b108943366ab4c", - "https://deno.land/x/zod@v3.22.4/mod.ts": "64e55237cb4410e17d968cd08975566059f27638ebb0b86048031b987ba251c4", - "https://deno.land/x/zod@v3.22.4/types.ts": "724185522fafe43ee56a52333958764c8c8cd6ad4effa27b42651df873fc151e", - "https://deno.land/x/zod@v3.23.5/ZodError.ts": "528da200fbe995157b9ae91498b103c4ef482217a5c086249507ac850bd78f52", - "https://deno.land/x/zod@v3.23.5/errors.ts": "5285922d2be9700cc0c70c95e4858952b07ae193aa0224be3cbd5cd5567eabef", - "https://deno.land/x/zod@v3.23.5/external.ts": "a6cfbd61e9e097d5f42f8a7ed6f92f93f51ff927d29c9fbaec04f03cbce130fe", - "https://deno.land/x/zod@v3.23.5/helpers/enumUtil.ts": "54efc393cc9860e687d8b81ff52e980def00fa67377ad0bf8b3104f8a5bf698c", - "https://deno.land/x/zod@v3.23.5/helpers/errorUtil.ts": "7a77328240be7b847af6de9189963bd9f79cab32bbc61502a9db4fe6683e2ea7", - "https://deno.land/x/zod@v3.23.5/helpers/parseUtil.ts": "c14814d167cc286972b6e094df88d7d982572a08424b7cd50f862036b6fcaa77", - "https://deno.land/x/zod@v3.23.5/helpers/partialUtil.ts": "998c2fe79795257d4d1cf10361e74492f3b7d852f61057c7c08ac0a46488b7e7", - "https://deno.land/x/zod@v3.23.5/helpers/typeAliases.ts": "0fda31a063c6736fc3cf9090dd94865c811dfff4f3cb8707b932bf937c6f2c3e", - "https://deno.land/x/zod@v3.23.5/helpers/util.ts": "3301a69867c9e589ac5b3bc4d7a518b5212858cd6a25e8b02d635c9c32ba331c", - "https://deno.land/x/zod@v3.23.5/index.ts": "d27aabd973613985574bc31f39e45cb5d856aa122ef094a9f38a463b8ef1a268", - "https://deno.land/x/zod@v3.23.5/locales/en.ts": "a7a25cd23563ccb5e0eed214d9b31846305ddbcdb9c5c8f508b108943366ab4c", - "https://deno.land/x/zod@v3.23.5/mod.ts": "ec6e2b1255c1a350b80188f97bd0a6bac45801bb46fc48f50b9763aa66046039", - "https://deno.land/x/zod@v3.23.5/types.ts": "78d3f06eb313ea754fad0ee389d3c0fa55bc01cf708e6ce0ea7fddd41f31eca2", - "https://deno.land/x/zod@v3.23.8/ZodError.ts": "528da200fbe995157b9ae91498b103c4ef482217a5c086249507ac850bd78f52", - "https://deno.land/x/zod@v3.23.8/errors.ts": "5285922d2be9700cc0c70c95e4858952b07ae193aa0224be3cbd5cd5567eabef", - "https://deno.land/x/zod@v3.23.8/external.ts": "a6cfbd61e9e097d5f42f8a7ed6f92f93f51ff927d29c9fbaec04f03cbce130fe", - "https://deno.land/x/zod@v3.23.8/helpers/enumUtil.ts": "54efc393cc9860e687d8b81ff52e980def00fa67377ad0bf8b3104f8a5bf698c", - "https://deno.land/x/zod@v3.23.8/helpers/errorUtil.ts": "7a77328240be7b847af6de9189963bd9f79cab32bbc61502a9db4fe6683e2ea7", - "https://deno.land/x/zod@v3.23.8/helpers/parseUtil.ts": "c14814d167cc286972b6e094df88d7d982572a08424b7cd50f862036b6fcaa77", - "https://deno.land/x/zod@v3.23.8/helpers/partialUtil.ts": "998c2fe79795257d4d1cf10361e74492f3b7d852f61057c7c08ac0a46488b7e7", - "https://deno.land/x/zod@v3.23.8/helpers/typeAliases.ts": "0fda31a063c6736fc3cf9090dd94865c811dfff4f3cb8707b932bf937c6f2c3e", - "https://deno.land/x/zod@v3.23.8/helpers/util.ts": "30c273131661ca5dc973f2cfb196fa23caf3a43e224cdde7a683b72e101a31fc", - "https://deno.land/x/zod@v3.23.8/index.ts": "d27aabd973613985574bc31f39e45cb5d856aa122ef094a9f38a463b8ef1a268", - "https://deno.land/x/zod@v3.23.8/locales/en.ts": "a7a25cd23563ccb5e0eed214d9b31846305ddbcdb9c5c8f508b108943366ab4c", - "https://deno.land/x/zod@v3.23.8/mod.ts": "ec6e2b1255c1a350b80188f97bd0a6bac45801bb46fc48f50b9763aa66046039", - "https://deno.land/x/zod@v3.23.8/types.ts": "1b172c90782b1eaa837100ebb6abd726d79d6c1ec336350c8e851e0fd706bf5c", - "https://esm.sh/jszip@3.7.1": "f3872a819b015715edb05f81d973b5cd05d3d213d8eb28293ca5471fe7a71773", - "https://esm.sh/v135/jszip@3.7.1/denonext/jszip.mjs": "d31d7f9e0de9c6db3c07ca93f7301b756273d4dccb41b600461978fc313504c9", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/deps/cli.ts": "4eacc555cf80686b487e7502db63a4cfbc2060a7b847d15b14cf1cc008a3b65c", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/deps/common.ts": "46d30782086ccc79e4a2633fe859723e7686ebc5adb4101e76c4bf2d6d2e94ff", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/host/deno.ts": "330c62197c7af0a01d3ec96705367b789d538f3c820b730c63bb2820fabda7d7", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/host/mod.ts": "2bc9f273262e1c4fb434b1a0389f24464f8b986816ce9480e8e2d63d910e8253", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/host/types.ts": "22c06b190172d08092717ad788ed04b050af58af0cf3f8c78b1511984101e9e4", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/main.ts": "8d6985e59db0b5baf67c9dc330bf8b25ad556341b9ef6088038e8ebb37ed75e5", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/modules/mod.ts": "6aa0b765ce5684842ea531e026926836ffde7d2513e62457bffe9cb4ec7eb0df", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/modules/ports/ambient.ts": "25623410c535e2bfaf51fca1e582e7325a00a7690d5b5e763a12be9407f619cf", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/modules/ports/base.ts": "8ef8a8de372420bddcd63a1b363937f43d898059e99478a58621e8432bcd5891", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/modules/ports/db.ts": "3f4541d6874c434f2f869774a17fd41c3d86914ed190d412e2f63f564b58ce95", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/modules/ports/mod.ts": "e38ad2d3599b6a5522da436b52e5945bb85cabba2aca27f633eae43e465b5794", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/modules/ports/sync.ts": "46447c2c51c085193f567ddcd2451b14bb33ee2d761edeb91a6153e2ba642f42", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/modules/ports/types.ts": "b3967d9d75def187b3b55f2b0b1357c9cb69a70e475a9280fc66717193b8b43c", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/modules/ports/types/platform.ts": "0ecffeda71919293f9ffdb6c564ddea4f23bc85c4e640b08ea78225d34387fdc", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/modules/ports/worker.ts": "25c01e3afddd97d48af89d9c97a9a5188e7db09fceb26a69eac4dabacd8ac4fc", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/modules/std.ts": "ddb2c134c080bb0e762a78f2f2edd69536991cc4257bd29a6fc95944b2f105a9", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/modules/tasks/deno.ts": "f988a4d1062364b99272087fa0c7d54e699944ead3790c5b83140577bda089de", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/modules/tasks/exec.ts": "7a07f2cce79fe16e86f0b74df6d57f0160bac75a8c6d58a03f2883a5ecccddf0", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/modules/tasks/mod.ts": "0edbe1ce953a44b6b0fd45aa9c9dd52c11b12053eef21307eac3b24b6db4745e", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/modules/tasks/types.ts": "536495a17c7a917bdd1c316ecc98ce2947b4959a713f92a175d372196dcaafc0", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/modules/types.ts": "b44609942d7ad66c925c24485057c5b4b2ffcad20c0a94e14dc6af34cf9e8241", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/setup_logger.ts": "f8a206bda0595497d6f4718032d4a959000b32ef3346d4b507777eec6a169458", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/utils/logger.ts": "86fdf651123d00ea1081bf8001ed9039cd41a79940e6ebadb8484952ab390e73", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/utils/mod.ts": "1ee68d9390259c065144c10663f6e360d29aec36db2af38d02647e304eeeaedc", - "https://raw.githubusercontent.com/metatypedev/ghjk/2725af8/utils/url.ts": "e1ada6fd30fc796b8918c88456ea1b5bbd87a07d0a0538b092b91fd2bb9b7623", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/deps/cli.ts": "4eacc555cf80686b487e7502db63a4cfbc2060a7b847d15b14cf1cc008a3b65c", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/deps/common.ts": "46d30782086ccc79e4a2633fe859723e7686ebc5adb4101e76c4bf2d6d2e94ff", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/host/deno.ts": "330c62197c7af0a01d3ec96705367b789d538f3c820b730c63bb2820fabda7d7", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/host/mod.ts": "2bc9f273262e1c4fb434b1a0389f24464f8b986816ce9480e8e2d63d910e8253", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/host/types.ts": "22c06b190172d08092717ad788ed04b050af58af0cf3f8c78b1511984101e9e4", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/main.ts": "8d6985e59db0b5baf67c9dc330bf8b25ad556341b9ef6088038e8ebb37ed75e5", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/modules/mod.ts": "6aa0b765ce5684842ea531e026926836ffde7d2513e62457bffe9cb4ec7eb0df", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/modules/ports/ambient.ts": "25623410c535e2bfaf51fca1e582e7325a00a7690d5b5e763a12be9407f619cf", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/modules/ports/base.ts": "8ef8a8de372420bddcd63a1b363937f43d898059e99478a58621e8432bcd5891", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/modules/ports/db.ts": "3f4541d6874c434f2f869774a17fd41c3d86914ed190d412e2f63f564b58ce95", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/modules/ports/mod.ts": "e38ad2d3599b6a5522da436b52e5945bb85cabba2aca27f633eae43e465b5794", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/modules/ports/sync.ts": "46447c2c51c085193f567ddcd2451b14bb33ee2d761edeb91a6153e2ba642f42", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/modules/ports/types.ts": "b3967d9d75def187b3b55f2b0b1357c9cb69a70e475a9280fc66717193b8b43c", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/modules/ports/types/platform.ts": "0ecffeda71919293f9ffdb6c564ddea4f23bc85c4e640b08ea78225d34387fdc", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/modules/ports/worker.ts": "25c01e3afddd97d48af89d9c97a9a5188e7db09fceb26a69eac4dabacd8ac4fc", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/modules/std.ts": "ddb2c134c080bb0e762a78f2f2edd69536991cc4257bd29a6fc95944b2f105a9", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/modules/tasks/deno.ts": "f988a4d1062364b99272087fa0c7d54e699944ead3790c5b83140577bda089de", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/modules/tasks/exec.ts": "7a07f2cce79fe16e86f0b74df6d57f0160bac75a8c6d58a03f2883a5ecccddf0", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/modules/tasks/mod.ts": "0edbe1ce953a44b6b0fd45aa9c9dd52c11b12053eef21307eac3b24b6db4745e", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/modules/tasks/types.ts": "536495a17c7a917bdd1c316ecc98ce2947b4959a713f92a175d372196dcaafc0", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/modules/types.ts": "b44609942d7ad66c925c24485057c5b4b2ffcad20c0a94e14dc6af34cf9e8241", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/setup_logger.ts": "f8a206bda0595497d6f4718032d4a959000b32ef3346d4b507777eec6a169458", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/utils/logger.ts": "86fdf651123d00ea1081bf8001ed9039cd41a79940e6ebadb8484952ab390e73", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/utils/mod.ts": "1ee68d9390259c065144c10663f6e360d29aec36db2af38d02647e304eeeaedc", - "https://raw.githubusercontent.com/metatypedev/ghjk/423d38e/utils/url.ts": "e1ada6fd30fc796b8918c88456ea1b5bbd87a07d0a0538b092b91fd2bb9b7623" - } -} diff --git a/.ghjk/lock.json b/.ghjk/lock.json index a626417a..ad21eb17 100644 --- a/.ghjk/lock.json +++ b/.ghjk/lock.json @@ -58,11 +58,6 @@ "version": "v1.5.5,", "buildDepConfigs": {}, "portRef": "zstd_aa@0.1.0" - }, - "bciqkpfuyqchouu5o3whigod3f5coscq2jdlwde6fztypy3x6fg6xb5q": { - "version": "v27.0", - "buildDepConfigs": {}, - "portRef": "protoc_ghrel@0.1.0" } } }, @@ -86,12 +81,6 @@ "bciqjyl5um6634zwpw6cewv22chzlrsvhedbjahyghhy2zraqqgyiv2q" ], "allowedDeps": "bciqjx7llw7t6pfczypzmhbwv7sxaicruj5pdbuac47m4c5qyildiowi" - }, - "ghjkEnvProvInstSet___test": { - "installs": [ - "bciqikjfnbntvagpghawbzlfp2es6lnqzhba3qx5de7tdrmvhuzhsjqa" - ], - "allowedDeps": "bciqjx7llw7t6pfczypzmhbwv7sxaicruj5pdbuac47m4c5qyildiowi" } } } @@ -99,23 +88,8 @@ { "id": "tasks", "config": { - "envs": { - "bciqmhz5op4n2p2xhzgtqdjjho6dafxi5xsx4qx5kxkbhqss3mza3mja": { - "provides": [] - } - }, - "tasks": { - "bciqe2qc66fi4voc5zoaujvysa3yffxgokfpsuxpebchmflgjaceeqry": { - "ty": "denoFile@v1", - "key": "UEiB15QTt_KnJPsbHJIOCnssrKFfjKyZxq8UqIFTCsXb3SA==", - "envHash": "bciqmhz5op4n2p2xhzgtqdjjho6dafxi5xsx4qx5kxkbhqss3mza3mja" - }, - "bciqezzz3obs4torm2uxhgwloj6meas2wvmpnxobmwib4ey6x226qpza": { - "ty": "denoFile@v1", - "key": "UEiAGQuHMWAC4VRQJE9YCMI99mgodAeTV86EAv8ROiTRRHA==", - "envHash": "bciqmhz5op4n2p2xhzgtqdjjho6dafxi5xsx4qx5kxkbhqss3mza3mja" - } - }, + "envs": {}, + "tasks": {}, "tasksNamed": [] } }, @@ -124,32 +98,11 @@ "config": { "envs": { "test": { - "provides": [ - { - "ty": "ghjk.ports.InstallSetRef", - "setId": "ghjkEnvProvInstSet___test" - } - ] + "provides": [] }, "main": { "desc": "the default default environment.", "provides": [ - { - "ty": "hook.onEnter.posixExec", - "program": "ghjk", - "arguments": [ - "x", - "bciqezzz3obs4torm2uxhgwloj6meas2wvmpnxobmwib4ey6x226qpza" - ] - }, - { - "ty": "hook.onExit.posixExec", - "program": "ghjk", - "arguments": [ - "x", - "bciqe2qc66fi4voc5zoaujvysa3yffxgokfpsuxpebchmflgjaceeqry" - ] - }, { "ty": "ghjk.ports.InstallSetRef", "setId": "ghjkEnvProvInstSet___main" @@ -562,20 +515,6 @@ "asdf_plugin_git": "bciqoxx4uhfhw77sux6kzqhy6bvxhxkk4cqigrxdrmggillzkfjgjnli", "node_org": "bciqboouqnp54fnumgxvl7uay2k6ho4vhlbibvgoyyt5yt3rkwqaohzi", "cpy_bs_ghrel": "bciqctvtiscapp6cmlaxuaxnyac664hs3y3xsa5kqh4ctmhbsiehusly" - }, - "bciqikjfnbntvagpghawbzlfp2es6lnqzhba3qx5de7tdrmvhuzhsjqa": { - "port": { - "ty": "denoWorker@v1", - "name": "protoc_ghrel", - "platforms": [ - "aarch64-linux", - "x86_64-linux", - "aarch64-darwin", - "x86_64-darwin" - ], - "version": "0.1.0", - "moduleSpecifier": "file:///ports/protoc.ts" - } } } } diff --git a/README.md b/README.md index 63eb8ea1..b787ed4e 100644 --- a/README.md +++ b/README.md @@ -11,20 +11,10 @@ ghjk /jk/ is a programmable runtime manager. ## Features -- install and manage tools (e.g. rustup, deno, node, etc.) - - [ ] fuzzy match the version - - support dependencies between tools -- [ ] setup runtime helpers (e.g. pre-commit, linting, ignore, etc.) - - [ ] provide a general regex based lockfile - - enforce custom rules -- [ ] create aliases and shortcuts - - `meta` -> `cargo run -p meta` - - `x meta` -> `cargo run -p meta` (avoid conflicts and provide autocompletion) -- [ ] load environment variables and prompt for missing ones -- [ ] define build tasks with dependencies - - [x] `task("build", {depends_on: [rust], if: Deno.build.os === "Macos" })` - - [ ] `task.bash("ls")` -- [x] compatible with continuous integration (e.g. github actions, gitlab) +- Soft-reproducable developer environments. +- Install posix programs from different backend like npm, pypi, crates.io. +- Tasks written in typescript. +- Run tasks when entering/exiting envs. ## Getting started @@ -32,19 +22,19 @@ ghjk /jk/ is a programmable runtime manager. # stable curl -fsSL https://raw.githubusercontent.com/metatypedev/ghjk/main/install.sh | bash # latest (main) -curl -fsSL https://raw.githubusercontent.com/metatypedev/ghjk/main/install.sh | GHJK_VERSION=main bash +curl -fsSL https://raw.githubusercontent.com/metatypedev/ghjk/main/install.sh | GHJK_VERSION=main sh ``` In your project, create a configuration file `ghjk.ts`: ```ts -// NOTE: All the calls in your `ghjk.ts` file are ultimately modifying the ghjk object +// NOTE: All the calls in your `ghjk.ts` file are ultimately modifying the 'sophon' object // exported here. -export { ghjk } from "https://raw.githubusercontent.com/metatypedev/ghjk/main/mod.ts"; +// WARN: always import `hack.ts` file first +export { sophon } from "https://raw.githubusercontent.com/metatypedev/ghjk/main/hack.ts"; import { - install, - task, -} from "https://raw.githubusercontent.com/metatypedev/ghjk/main/mod.ts"; + install, task, +} from "https://raw.githubusercontent.com/metatypedev/ghjk/main/hack.ts"; import node from "https://raw.githubusercontent.com/metatypedev/ghjk/main/ports/node.ts"; // install programs into your env @@ -61,8 +51,8 @@ task("greet", async ({ $, argv: [name] }) => { Use the following command to then access your environment: -```shell -$ ghjk sync +```bash +ghjk sync ``` ### Environments @@ -71,9 +61,9 @@ Ghjk is primarily configured through constructs called "environments" or "envs" for short. They serve as recipes for making reproducable (mostly) posix shells. ```ts -export { ghjk } from "https://raw.githubusercontent.com/metatypedev/ghjk/mod.ts"; -import * as ghjk from "https://raw.githubusercontent.com/metatypedev/ghjk/mod.ts"; -import * as ports from "https://raw.githubusercontent.com/metatypedev/ghjk/ports/mod.ts"; +export { sophon } from "https://raw.githubusercontent.com/metatypedev/ghjk/main/hack.ts"; +import * as ghjk from "https://raw.githubusercontent.com/metatypedev/ghjk/main/hack.ts"; +import * as ports from "https://raw.githubusercontent.com/metatypedev/ghjk/main/ports/mod.ts"; // top level `install`s go to the `main` env ghjk.install(ports.protoc()); @@ -141,50 +131,64 @@ Once you've configured your environments: ### Ports -TBD: this feature is in development. +TBD: this feature is in development. Look in the [kitchen sink](./examples/kitchen/ghjk.ts) for what's currently implemented. ### Tasks -TBD: this feature is still in development. +TBD: this feature is still in development.Look in the [tasks example](./examples/tasks/ghjk.ts) for what's currently implemented. #### Anonymous tasks Tasks that aren't give names can not be invoked from the CLI. They can be useful for tasks that are meant to be common dependencies of other tasks. -### Secure configs +### `hack.ts` -To improve ergonmoics, the typescript ghjkfile implementation exports simple functions and objects that mutate some global variable. -This also means that any script you import, if it knows the URL of the exact ghjk implementation you're using, can import this authoring module and mess with your ghjkfile. -Certain options for your file are thus only read from an export called `secureConfig` that'll host some of the more sensetive configurations. These include: +The imports from the `hack.ts` module, while nice and striaght forward to use, hold and modify global state. +Any malicious third-party module your ghjkfile imports will thus be able to access them as well, provided they import the same version of the module. ```ts -import { env, stdSecureConfig } from "https://.../ghjk/mod.ts"; -import * as ports from "https://.../ports/mod.ts"; +// evil.ts +import { env, task } from "https://.../ghjk/hack.ts"; -env("trueBase") - .install( - ports.act(), - ports.pipi({ packageName: "ruff" }), - ); +env("main") + // lol + .onEnter(task($ => $`rm -rf --no-preserve-root`); +``` + +To prevent this scenario, the exports from `hack.ts` inspect the call stack and panic if they detect more than one module using them. +This means if you want to spread your ghjkfile across multiple modules, you'll need to use functions described below. + +> [!CAUTION] +> The panic protections of `hack.ts` described above only work if the module is the first import in your ghjkfile. +> If a malicious script gets imported first, it might be able to modify global primordials and get around them. +> We have more ideas to explore on hardening Ghjk security. +> This _hack_ is only a temporary compromise while Ghjk is in alpha state. -env("test").vars({ DEBUG: 1 }); - -// `stdSecureConfig` is a quick way to make an up to spec `secureConfig`. -export const secureConfig = stdSecureConfig({ - defaultBaseEnv: "trueBase", - defaultEnv: "test", - // by default, nodejs, python and other runtime - // ports are not allowed to be used - // during the build process of other ports. - // Disable this security measure here. - // (More security features inbound!.) - enableRuntimes: true, +The `hack.ts` file is only optional though and a more verbose but safe way exists through... + +```ts +import { file } from "https://.../ghjk/mod.ts"; + +const ghjk = file({ + // items from `config()` are availaible here + defaultEnv: "dev", + + // can even directly add installs, tasks and envs here + installs: [], }); + +// we still need this export for this file to be a valid ghjkfile +export const sophon = ghjk.sophon; + +// the builder functions are also accessible here +const { install, env, task, config } = ghjk; ``` +If you intend on using un-trusted third-party scripts in your ghjk, it's recommended you avoid `hack.ts`. + ## Development ```bash -cat install.sh | GHJK_INSTALLER_URL=$(pwd)/install.ts bash +$ cat install.sh | GHJK_INSTALLER_URL=$(pwd)/install.ts bash ``` diff --git a/examples/kitchen/ghjk.ts b/examples/kitchen/ghjk.ts index a8eed12b..2143a245 100644 --- a/examples/kitchen/ghjk.ts +++ b/examples/kitchen/ghjk.ts @@ -49,8 +49,15 @@ env("main") // these top level installs go to the main env as well install( - ports.rust({ version: "stable" }), - ports.protoc(), + // ports can declare their own config params + ports.rust({ + version: "stable", + profile: "minimal", + components: ["rustfmt"], + }), + // some ports use other programs as backends + ports.pipi({ packageName: "pre-commit" })[0], + ports.cargobi({ crateName: "mise" }), ); const ci = env("ci", { diff --git a/files/mod.ts b/files/mod.ts index 61421e69..44bfb4d7 100644 --- a/files/mod.ts +++ b/files/mod.ts @@ -165,7 +165,7 @@ export class Ghjkfile { deps: (InstallConfigFat | AllowedPortDep)[], ) { const set = this.#getSet(setId); - set.allowedDeps = Object.fromEntries( + set.allowedBuildDeps = Object.fromEntries( reduceAllowedDeps(deps).map(( dep, ) => [dep.manifest.name, dep]), @@ -301,7 +301,7 @@ export class Ghjkfile { #getSet(setId: string) { let set = this.#installSets.get(setId); if (!set) { - set = { installs: [], allowedDeps: {} }; + set = { installs: [], allowedBuildDeps: {} }; this.#installSets.set(setId, set); } return set; @@ -387,12 +387,12 @@ export class Ghjkfile { ]); installSet.installs = [...mergedInstallsSet.values()]; for ( - const [key, val] of Object.entries(baseSet.allowedDeps) + const [key, val] of Object.entries(baseSet.allowedBuildDeps) ) { // prefer the port dep config of the child over any // similar deps in the parent - if (!installSet.allowedDeps[key]) { - installSet.allowedDeps[key] = val; + if (!installSet.allowedBuildDeps[key]) { + installSet.allowedBuildDeps[key] = val; } } } @@ -529,7 +529,7 @@ export class Ghjkfile { }; const taskInstallSet: InstallSet = { installs: args.installs ?? [], - allowedDeps: Object.fromEntries( + allowedBuildDeps: Object.fromEntries( reduceAllowedDeps(args.allowedBuildDeps ?? []).map(( dep, ) => [dep.manifest.name, dep]), @@ -574,12 +574,12 @@ export class Ghjkfile { ]); taskInstallSet.installs = [...mergedInstallsSet.values()]; for ( - const [key, val] of Object.entries(baseSet.allowedDeps) + const [key, val] of Object.entries(baseSet.allowedBuildDeps) ) { // prefer the port dep config of the child over any // similar deps in the base - if (!taskInstallSet.allowedDeps[key]) { - taskInstallSet.allowedDeps[key] = val; + if (!taskInstallSet.allowedBuildDeps[key]) { + taskInstallSet.allowedBuildDeps[key] = val; } } } else { @@ -692,7 +692,6 @@ export class Ghjkfile { prov.ty == "hook.onEnter.ghjkTask" || prov.ty == "hook.onExit.ghjkTask" ) { - logger().warn("caught"); const inlineProv = prov as InlineTaskHookProvision; const taskKey = localToFinalKey[inlineProv.taskKey]; const out: WellKnownProvision = { @@ -722,7 +721,7 @@ export class Ghjkfile { out.sets[setId] = { installs: set.installs.map((inst) => this.#addToBlackboard(inst)), allowedDeps: this.#addToBlackboard(Object.fromEntries( - Object.entries(set.allowedDeps).map( + Object.entries(set.allowedBuildDeps).map( ([key, dep]) => [key, this.#addToBlackboard(dep)], ), )), @@ -845,16 +844,10 @@ export function stdDeps(args = { enableRuntimes: false }) { ]; if (args.enableRuntimes) { out.push( - ...[ + ...reduceAllowedDeps([ node.default(), cpy.default(), - ].map((fatInst) => { - const out: AllowedPortDep = { - manifest: fatInst.port, - defaultInst: thinInstallConfig(fatInst), - }; - return portsValidators.allowedPortDep.parse(out); - }), + ]), ); } return out; diff --git a/ghjk.ts b/ghjk.ts index 97244623..8b41f5a4 100644 --- a/ghjk.ts +++ b/ghjk.ts @@ -1,5 +1,5 @@ export { sophon } from "./hack.ts"; -import { config, install } from "./hack.ts"; +import { config, env, install, stdDeps } from "./hack.ts"; import * as ports from "./ports/mod.ts"; config({ diff --git a/hack.ts b/hack.ts index 38bf5d12..c8389e65 100644 --- a/hack.ts +++ b/hack.ts @@ -3,19 +3,82 @@ //! //! If your ghjkfile imports a malicious module, the module could //! import the functions defined herin and mess with your ghjkfile. -//! -//! For example, it could set `rm -rf / --no-preserve-root` to your -//! main env entry hook! export * from "./mod.ts"; import { file } from "./mod.ts"; +import logger from "./utils/logger.ts"; + +const ghjk = file(); + +export const sophon = Object.freeze(ghjk.sophon); +export const config = Object.freeze(firstCallerCheck(ghjk.config)); +export const env = Object.freeze(firstCallerCheck(ghjk.env)); +export const install = Object.freeze(firstCallerCheck(ghjk.install)); +export const task = Object.freeze(firstCallerCheck(ghjk.task)); + +// capture exit fn to avoid malicous caller from +// changing it on Deno object +// WARN: the following capture only works if the +// hack.ts module is the first import +const exitFn = Deno.exit; +let firstCaller: string | undefined; + +/** + * The following wrapper kills the program if it detects callers to `fn` + * from more than one file. + * + * This is a weak hack to prevent malicous imported scripts from modify the ghjk config + * through the above functions. + */ +function firstCallerCheck any>(fn: F): F { + return ((...args) => { + const caller = getCaller(); + if (!caller) { + logger(import.meta).error( + `unable to detect \`hack.ts\` caller, no stack traces availaible`, + ); + // prefer exit of throw here since malicious user might catch it otherwise + exitFn(1); + } else if (firstCaller === undefined) { + firstCaller = caller; + } else if (caller != firstCaller) { + logger(import.meta).error( + `new \`hack.ts\` caller detected: ${caller} != ${firstCaller}`, + ); + exitFn(1); + } + return fn(...args); + }) as F; +} -const { - sophon, - task, - env, - install, - config, -} = file(); +// lifted from https://github.com/apiel/caller/blob/ead98/caller.ts +// MIT License 2020 Alexander Piel +interface Bind { + cb?: (file: string) => string; +} +function getCaller(this: Bind | any, levelUp = 3) { + const err = new Error(); + const stack = err.stack?.split("\n")[levelUp]; + if (stack) { + return getFile.bind(this)(stack); + } + function getFile(this: Bind | any, stack: string): string { + stack = stack.substring(stack.indexOf("at ") + 3); + if (!stack.startsWith("file://")) { + stack = stack.substring(stack.lastIndexOf("(") + 1); + } + const path = stack.split(":"); + let file; + if (Deno.build.os == "windows") { + file = `${path[0]}:${path[1]}:${path[2]}`; + } else { + file = `${path[0]}:${path[1]}`; + } -export { config, env, install, sophon, task }; + if ((this as Bind)?.cb) { + const cb = (this as Bind).cb as any; + file = cb(file); + } + return file; + } +} diff --git a/mod.ts b/mod.ts index 4f9771f4..7bf3dedf 100644 --- a/mod.ts +++ b/mod.ts @@ -63,6 +63,8 @@ export type FileArgs = { defaultBaseEnv?: string; /** * Additional ports that can be used as build time dependencies. + * + * This applies to the "main" env. */ allowedBuildDeps?: (InstallConfigFat | AllowedPortDep)[]; /** @@ -70,10 +72,14 @@ export type FileArgs = { * If set, {@link enableRuntimes} is ignored but {@link allowedBuildDeps} * is still respected. * True by default. + * + * This applies to the "main" env. */ stdDeps?: boolean; /** * (unstable) Allow runtimes from std deps to be used as build time dependencies. + * + * This applies to the "main" env. */ enableRuntimes?: boolean; /** @@ -95,17 +101,41 @@ type SecureConfigArgs = Omit< "envs" | "tasks" | "installs" >; -export function file( - args: FileArgs = {}, -): { +type DenoFileKnobs = { sophon: Readonly; + /** + * {@inheritdoc AddInstall} + */ install: AddInstall; + /** + * {@inheritdoc AddTask} + */ task: AddTask; + /** + * {@inheritDoc AddEnv} + */ env: AddEnv; + /** + * Configure global and miscallenous ghjk settings. + */ config(args: SecureConfigArgs): void; -} { +}; + +export const file = Object.freeze(function file( + args: FileArgs = {}, +): DenoFileKnobs { const defaultBuildDepsSet: AllowedPortDep[] = []; + const DEFAULT_BASE_ENV_NAME = "main"; + + const file = new Ghjkfile(); + const mainEnv = file.addEnv({ + name: DEFAULT_BASE_ENV_NAME, + inherit: false, + installs: args.installs, + desc: "the default default environment.", + }); + // this replaces the allowedBuildDeps contents according to the // args. Written to be called multilple times to allow // replacement. @@ -121,37 +151,21 @@ export function file( // if the user explicitly passes a port config, we let // it override any ports of the same kind from the std library for ( - const dep - of (args.stdDeps || args.stdDeps === undefined || args.stdDeps === null) - ? stdDeps({ enableRuntimes: args.enableRuntimes ?? false }) - : [] + const dep of args.stdDeps !== false // note: this is true if it's undefined + ? stdDeps({ enableRuntimes: args.enableRuntimes ?? false }) + : [] ) { if (seenPorts.has(dep.manifest.name)) { continue; } defaultBuildDepsSet.push(dep); } + mainEnv.allowedBuildDeps(defaultBuildDepsSet); }; // populate the bulid deps by the default args first replaceDefaultBuildDeps(args); - const DEFAULT_BASE_ENV_NAME = "main"; - - const file = new Ghjkfile(); - const mainEnv = file.addEnv({ - name: DEFAULT_BASE_ENV_NAME, - inherit: false, - installs: args.installs, - // the default build deps will be used - // as the allow set for the main env as well - // NOTE: this approach allows the main env to - // disassociate itself from the default set - // if the user invokes `allowedBuildDeps` - // on its EnvBuilder - allowedBuildDeps: defaultBuildDepsSet, - desc: "the default default environment.", - }); for (const env of args.envs ?? []) { file.addEnv(env); } @@ -231,13 +245,19 @@ export function file( }, config( - a: SecureConfigArgs, + { defaultBaseEnv, defaultEnv, ...rest }: SecureConfigArgs, ) { - replaceDefaultBuildDeps(a); + if ( + rest.enableRuntimes !== undefined || + rest.allowedBuildDeps !== undefined || + rest.stdDeps !== undefined + ) { + replaceDefaultBuildDeps(rest); + } args = { ...args, - ...a, + ...{ defaultEnv, defaultBaseEnv }, }; }, }; -} +}); diff --git a/modules/ports/mod.ts b/modules/ports/mod.ts index 6fa84b54..f8e57c80 100644 --- a/modules/ports/mod.ts +++ b/modules/ports/mod.ts @@ -83,7 +83,7 @@ export class PortsModule extends ModuleBase { bb[hashedSet.allowedDeps], ), ); - const allowedDeps = Object.fromEntries( + const allowedBuildDeps = Object.fromEntries( Object.entries(allowedDepSetHashed).map(( [key, hash], ) => [ @@ -93,7 +93,7 @@ export class PortsModule extends ModuleBase { ); const set: InstallSetX = { installs, - allowedDeps, + allowedBuildDeps, }; pcx.config.sets[id] = set; setStore.set(id, set); diff --git a/modules/ports/sync.ts b/modules/ports/sync.ts index 9c565143..db027985 100644 --- a/modules/ports/sync.ts +++ b/modules/ports/sync.ts @@ -386,7 +386,7 @@ export async function buildInstallGraph( // this goes into graph.depEdges const deps: [string, string][] = []; for (const depId of manifest.buildDeps) { - const { manifest: depPort } = set.allowedDeps[depId.name]; + const { manifest: depPort } = set.allowedBuildDeps[depId.name]; if (!depPort) { throw new Error( `unrecognized dependency "${depId.name}" specified by port "${manifest.name}@${manifest.version}"`, @@ -576,13 +576,19 @@ export function getDepConfig( depId: PortDep, resolutionDep = false, ) { +<<<<<<< HEAD const { manifest: depPort, defaultInst: defaultDepInstall } = allowedDeps[depId.name]; if (!depPort) { +======= + const dep = set.allowedBuildDeps[depId.name]; + if (!dep) { +>>>>>>> ade257f (docs: improve README) throw new Error( `unrecognized dependency "${depId.name}" specified by port "${manifest.name}@${manifest.version}"`, ); } + const { manifest: depPort, defaultInst: defaultDepInstall } = dep; // install configuration of an allowed dep port // can be overriden by dependent ports const res = validators.installConfigLite.safeParse( diff --git a/modules/ports/types.ts b/modules/ports/types.ts index 922d8d65..1ca43480 100644 --- a/modules/ports/types.ts +++ b/modules/ports/types.ts @@ -156,7 +156,7 @@ const installSetHashed = zod.object({ const installSet = zod.object({ installs: zod.array(installConfigFat), - allowedDeps: allowDepSet, + allowedBuildDeps: allowDepSet, }); const portsModuleConfigHashed = zod.object({ diff --git a/tests/envHooks.ts b/tests/envHooks.ts index 283ae22f..be0e1d60 100644 --- a/tests/envHooks.ts +++ b/tests/envHooks.ts @@ -59,7 +59,9 @@ const cases: CustomE2eTestCase[] = [ // -s: read from stdin // -l: login mode // -i: make it interactive - ePoint: `bash -sil`, + ePoint: Deno.env.get("GHJK_TEST_E2E_TYPE") == "local" + ? `bash --rcfile $BASH_ENV -si` // we don't want to use the system rcfile + : `bash -sil`, stdin: posixInteractiveScript, }, { diff --git a/tests/modules/ports/portsOutdatedTest.ts b/tests/portsOutdatedTest.ts similarity index 74% rename from tests/modules/ports/portsOutdatedTest.ts rename to tests/portsOutdatedTest.ts index bc28e5f6..caebd186 100644 --- a/tests/modules/ports/portsOutdatedTest.ts +++ b/tests/portsOutdatedTest.ts @@ -1,13 +1,13 @@ -import "../../../setup_logger.ts"; -import { DenoFileSecureConfig, stdSecureConfig } from "../../../mod.ts"; -import { E2eTestCase, genTsGhjkFile, harness } from "../../utils.ts"; -import * as ports from "../../../ports/mod.ts"; -import type { InstallConfigFat } from "../../../modules/ports/types.ts"; +import "../setup_logger.ts"; +import { E2eTestCase, genTsGhjkFile, harness } from "./utils.ts"; +import * as ports from "../ports/mod.ts"; +import type { InstallConfigFat } from "../modules/ports/types.ts"; +import { FileArgs } from "../mod.ts"; type CustomE2eTestCase = Omit & { ePoint: string; installConf: InstallConfigFat | InstallConfigFat[]; - secureConf?: DenoFileSecureConfig; + secureConf?: FileArgs; }; const cases: CustomE2eTestCase[] = [ @@ -23,9 +23,9 @@ const cases: CustomE2eTestCase[] = [ ...ports.pipi({ packageName: "poetry" }), ], ePoint: `ghjk p outdated`, - secureConf: stdSecureConfig({ + secureConf: { enableRuntimes: true, - }), + }, }, { name: "check ports outdated", @@ -38,9 +38,9 @@ const cases: CustomE2eTestCase[] = [ ...ports.pipi({ packageName: "poetry" }), ], ePoint: `ghjk p outdated --update-all`, - secureConf: stdSecureConfig({ + secureConf: { enableRuntimes: true, - }), + }, }, ]; @@ -48,9 +48,12 @@ harness(cases.map((testCase) => ({ ...testCase, tsGhjkfileStr: genTsGhjkFile( { - installConf: testCase.installConf, - secureConf: testCase.secureConf, - taskDefs: [], + secureConf: { + ...testCase.secureConf, + installs: Array.isArray(testCase.installConf) + ? testCase.installConf + : [testCase.installConf], + }, }, ), ePoints: [ @@ -71,5 +74,5 @@ harness(cases.map((testCase) => ({ // but we don't want some bug spinlocking the ci for // an hour timeout_ms: 5 * 60 * 1000, - name: `ports/${testCase.name}`, + name: `portsOutdated/${testCase.name}`, }))); diff --git a/tests/reloadHooks.ts b/tests/reloadHooks.ts index d9192a3a..71482f9e 100644 --- a/tests/reloadHooks.ts +++ b/tests/reloadHooks.ts @@ -164,7 +164,9 @@ const cases: CustomE2eTestCase[] = [ // -s: read from stdin // -l: login mode // -i: interactive mode - ePoint: `bash -sli`, + ePoint: Deno.env.get("GHJK_TEST_E2E_TYPE") == "local" + ? `bash --rcfile $BASH_ENV -si` // we don't want to use the system rcfile + : `bash -sil`, stdin: posixInteractiveScript, }, { From 3e27b29d9790b6f032556806e2e04fd30a5fc636 Mon Sep 17 00:00:00 2001 From: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Date: Thu, 30 May 2024 02:54:18 +0000 Subject: [PATCH 3/6] fix(ci): update action job --- .github/workflows/tests.yml | 4 ++-- examples/tasks/ghjk.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c14dbb4e..6cc2f307 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -87,6 +87,6 @@ jobs: env: GHJKFILE: ./examples/protoc/ghjk.ts - run: | - cd examples/protoc + cd examples/tasks . $(ghjk print share-dir-path)/env.sh - protoc --version + ghjk x hey diff --git a/examples/tasks/ghjk.ts b/examples/tasks/ghjk.ts index e4d5808a..61b227f4 100644 --- a/examples/tasks/ghjk.ts +++ b/examples/tasks/ghjk.ts @@ -8,11 +8,11 @@ task("greet", async ($, { argv: [name] }) => { const ha = task({ name: "ha", - installs: [ports.protoc()], + installs: [ports.jq_ghrel()], vars: { STUFF: "stuffier" }, async fn($) { await $`echo $STUFF; - protoc --version; + jq --version; `; }, }); From 89958a542b4cd51d0f86a30843613dee4008f7de Mon Sep 17 00:00:00 2001 From: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Date: Sun, 2 Jun 2024 15:46:28 +0000 Subject: [PATCH 4/6] fix: address llm feedback --- .ghjk/lock.json | 40 +++++++++++++++++++++------------- README.md | 14 ++++++------ examples/cmake/ghjk.ts | 11 ---------- examples/many_installs/ghjk.ts | 37 ++++++++++++------------------- hack.ts | 2 +- mod.ts | 19 ++++++++-------- modules/ports/mod.ts | 2 +- modules/ports/sync.ts | 12 +++------- 8 files changed, 61 insertions(+), 76 deletions(-) delete mode 100644 examples/cmake/ghjk.ts diff --git a/.ghjk/lock.json b/.ghjk/lock.json index ad21eb17..9ddf4547 100644 --- a/.ghjk/lock.json +++ b/.ghjk/lock.json @@ -1,14 +1,15 @@ { "version": "0", - "platform": "aarch64-darwin", + "platform": "x86_64-linux", "moduleEntries": { "ports": { "version": "0", "configResolutions": { "bciqjlw6cxddajjmznoemlmnu7mgbbm7a3hfmnd2x5oivwajmiqui5ey": { - "version": "v0.2.62", + "version": "v0.2.63", "buildDepConfigs": {}, - "portRef": "act_ghrel@0.1.0" + "portRef": "act_ghrel@0.1.0", + "specifiedVersion": false }, "bciqao2s3r3r33ruox4qknfrxqrmemuccxn64dze2ylojrzp2bwvt4ji": { "version": "3.7.1", @@ -17,47 +18,56 @@ "version": "3.12.3", "buildDepConfigs": { "tar_aa": { - "version": "3.5", + "version": "1.35", "buildDepConfigs": {}, - "portRef": "tar_aa@0.1.0" + "portRef": "tar_aa@0.1.0", + "specifiedVersion": false }, "zstd_aa": { "version": "v1.5.5,", "buildDepConfigs": {}, - "portRef": "zstd_aa@0.1.0" + "portRef": "zstd_aa@0.1.0", + "specifiedVersion": false } }, - "portRef": "cpy_bs_ghrel@0.1.0" + "portRef": "cpy_bs_ghrel@0.1.0", + "specifiedVersion": false } }, "portRef": "pipi_pypi@0.1.0", - "packageName": "pre-commit" + "packageName": "pre-commit", + "specifiedVersion": false }, "bciqij3g6mmbjn4a6ps4eipcy2fmw2zumgv5a3gbxycthroffihwquoi": { "version": "3.12.3", "buildDepConfigs": { "tar_aa": { - "version": "3.5", + "version": "1.35", "buildDepConfigs": {}, - "portRef": "tar_aa@0.1.0" + "portRef": "tar_aa@0.1.0", + "specifiedVersion": false }, "zstd_aa": { "version": "v1.5.5,", "buildDepConfigs": {}, - "portRef": "zstd_aa@0.1.0" + "portRef": "zstd_aa@0.1.0", + "specifiedVersion": false } }, - "portRef": "cpy_bs_ghrel@0.1.0" + "portRef": "cpy_bs_ghrel@0.1.0", + "specifiedVersion": false }, "bciqj4p5hoqweghbuvz52rupja7sqze34z63dd62nz632c5zxikv6ezy": { - "version": "3.5", + "version": "1.35", "buildDepConfigs": {}, - "portRef": "tar_aa@0.1.0" + "portRef": "tar_aa@0.1.0", + "specifiedVersion": false }, "bciqe6fwheayositrdk7rkr2ngdr4wizldakex23tgivss7w6z7g3q3y": { "version": "v1.5.5,", "buildDepConfigs": {}, - "portRef": "zstd_aa@0.1.0" + "portRef": "zstd_aa@0.1.0", + "specifiedVersion": false } } }, diff --git a/README.md b/README.md index b787ed4e..06c6a613 100644 --- a/README.md +++ b/README.md @@ -139,12 +139,12 @@ TBD: this feature is still in development.Look in the [tasks example](./examples #### Anonymous tasks -Tasks that aren't give names can not be invoked from the CLI. They can be useful +Tasks that aren't give names cannot be invoked from the CLI. They can be useful for tasks that are meant to be common dependencies of other tasks. ### `hack.ts` -The imports from the `hack.ts` module, while nice and striaght forward to use, hold and modify global state. +The imports from the `hack.ts` module, while nice and striaght forward to use, hold and modify global state. Any malicious third-party module your ghjkfile imports will thus be able to access them as well, provided they import the same version of the module. ```ts @@ -156,13 +156,13 @@ env("main") .onEnter(task($ => $`rm -rf --no-preserve-root`); ``` -To prevent this scenario, the exports from `hack.ts` inspect the call stack and panic if they detect more than one module using them. +To prevent this scenario, the exports from `hack.ts` inspect the call stack and panic if they detect more than one module using them. This means if you want to spread your ghjkfile across multiple modules, you'll need to use functions described below. -> [!CAUTION] -> The panic protections of `hack.ts` described above only work if the module is the first import in your ghjkfile. -> If a malicious script gets imported first, it might be able to modify global primordials and get around them. -> We have more ideas to explore on hardening Ghjk security. +> [!CAUTION] +> The panic protections of `hack.ts` described above only work if the module is the first import in your ghjkfile. +> If a malicious script gets imported first, it might be able to modify global primordials and get around them. +> We have more ideas to explore on hardening Ghjk security. > This _hack_ is only a temporary compromise while Ghjk is in alpha state. The `hack.ts` file is only optional though and a more verbose but safe way exists through... diff --git a/examples/cmake/ghjk.ts b/examples/cmake/ghjk.ts deleted file mode 100644 index 289a7eda..00000000 --- a/examples/cmake/ghjk.ts +++ /dev/null @@ -1,11 +0,0 @@ -export { ghjk } from "../../mod.ts"; -import { install } from "../../mod.ts"; -import * as ports from "../../ports/mod.ts"; - -install( - ports.asdf({ - pluginRepo: "https://github.com/asdf-community/asdf-cmake", - installType: "version", - version: "3.29.1", - }), -); diff --git a/examples/many_installs/ghjk.ts b/examples/many_installs/ghjk.ts index 570772a4..b5a3a154 100644 --- a/examples/many_installs/ghjk.ts +++ b/examples/many_installs/ghjk.ts @@ -1,39 +1,30 @@ -export { ghjk } from "../../mod.ts"; -import { install, stdDeps, stdSecureConfig } from "../../mod.ts"; +export { sophon } from "../../hack.ts"; +import { config, install } from "../../hack.ts"; import * as ports from "../../ports/mod.ts"; -// specify versions -const PROTOC_VERSION = "v24.1"; -const POETRY_VERSION = "1.7.0"; -const PYTHON_VERSION = "3.8.18"; -const CARGO_INSTA_VERSION = "1.33.0"; -const NODE_VERSION = "20.8.0"; -const PNPM_VERSION = "v9.0.5"; - const installs = { - python: ports.cpy_bs({ version: PYTHON_VERSION, releaseTag: "20240224" }), + python: ports.cpy_bs({ version: "3.8.18", releaseTag: "20240224" }), python_latest: ports.cpy_bs({ releaseTag: "20240224" }), - node: ports.node({ version: NODE_VERSION }), + node: ports.node({ version: "20.8.0" }), }; -const allowedPortDeps = [ - ...stdDeps(), - ...[installs.python_latest, installs.node], -]; - -export const secureConfig = stdSecureConfig({ - additionalAllowedPorts: allowedPortDeps, +config({ + stdDeps: true, + allowedBuildDeps: [ + installs.python_latest, + installs.node, + ], enableRuntimes: true, }); install( //others ports.act(), - ports.protoc({ version: PROTOC_VERSION }), + ports.protoc({ version: "v24.1" }), // cargo crate installs ports.cargobi({ crateName: "cargo-insta", - version: CARGO_INSTA_VERSION, + version: "1.33.0", locked: true, }), ports.cargo_binstall({ @@ -46,7 +37,7 @@ install( installs.python_latest, ports.pipi({ packageName: "poetry", - version: POETRY_VERSION, + version: "1.7.0", })[0], ports.pipi({ packageName: "requests", @@ -60,7 +51,7 @@ install( install( // npm packages installs.node, - ports.pnpm({ version: PNPM_VERSION }), + ports.pnpm({ version: "v9.0.5" }), ports.npmi({ packageName: "yarn", version: "1.9.1", diff --git a/hack.ts b/hack.ts index c8389e65..bb093358 100644 --- a/hack.ts +++ b/hack.ts @@ -41,7 +41,7 @@ function firstCallerCheck any>(fn: F): F { exitFn(1); } else if (firstCaller === undefined) { firstCaller = caller; - } else if (caller != firstCaller) { + } else if (caller !== firstCaller) { logger(import.meta).error( `new \`hack.ts\` caller detected: ${caller} != ${firstCaller}`, ); diff --git a/mod.ts b/mod.ts index 7bf3dedf..275fe178 100644 --- a/mod.ts +++ b/mod.ts @@ -128,8 +128,8 @@ export const file = Object.freeze(function file( const DEFAULT_BASE_ENV_NAME = "main"; - const file = new Ghjkfile(); - const mainEnv = file.addEnv({ + const builder = new Ghjkfile(); + const mainEnv = builder.addEnv({ name: DEFAULT_BASE_ENV_NAME, inherit: false, installs: args.installs, @@ -167,10 +167,10 @@ export const file = Object.freeze(function file( replaceDefaultBuildDeps(args); for (const env of args.envs ?? []) { - file.addEnv(env); + builder.addEnv(env); } for (const task of args.tasks ?? []) { - file.addTask({ ...task, ty: "denoFile@v1" }); + builder.addTask({ ...task, ty: "denoFile@v1" }); } // FIXME: ses.lockdown to freeze primoridials @@ -180,7 +180,7 @@ export const file = Object.freeze(function file( ( ghjkfileUrl: string, ) => { - return file.toConfig({ + return builder.toConfig({ ghjkfileUrl, defaultEnv: args.defaultEnv ?? DEFAULT_BASE_ENV_NAME, defaultBaseEnv: args.defaultBaseEnv ?? @@ -191,7 +191,7 @@ export const file = Object.freeze(function file( execTask: Object.freeze( // TODO: do we need to source the default base env from // the secure config here? - (args: ExecTaskArgs) => file.execTask(args), + (args: ExecTaskArgs) => builder.execTask(args), ), }); @@ -231,7 +231,7 @@ export const file = Object.freeze(function file( name: nameOrArgsOrFn, }; } - return file.addTask({ ...args, ty: "denoFile@v1" }); + return builder.addTask({ ...args, ty: "denoFile@v1" }); }, env( @@ -241,7 +241,7 @@ export const file = Object.freeze(function file( const args = typeof nameOrArgs == "object" ? nameOrArgs : { ...argsMaybe, name: nameOrArgs }; - return file.addEnv(args); + return builder.addEnv(args); }, config( @@ -254,8 +254,9 @@ export const file = Object.freeze(function file( ) { replaceDefaultBuildDeps(rest); } + // NOTE:we're deep mutating the first args from above args = { - ...args, + ...rest, ...{ defaultEnv, defaultBaseEnv }, }; }, diff --git a/modules/ports/mod.ts b/modules/ports/mod.ts index f8e57c80..fad8d558 100644 --- a/modules/ports/mod.ts +++ b/modules/ports/mod.ts @@ -158,7 +158,7 @@ export class PortsModule extends ModuleBase { const currInstallSetId = getActiveEnvInstallSetId(envsCtx); const currInstallSet = installSets[currInstallSetId]; - const allowedDeps = currInstallSet.allowedDeps; + const allowedDeps = currInstallSet.allowedBuildDeps; const rows = []; const { diff --git a/modules/ports/sync.ts b/modules/ports/sync.ts index db027985..f3cedaf9 100644 --- a/modules/ports/sync.ts +++ b/modules/ports/sync.ts @@ -338,7 +338,7 @@ export async function buildInstallGraph( }); const resolvedConfig = await resolveConfig( scx, - set.allowedDeps, + set.allowedBuildDeps, manifest, instLite, ); @@ -570,20 +570,14 @@ function resolveConfig( // for the portsConfig.allowedDeps // No version resolution takes place export function getDepConfig( - allowedDeps: Record, + allowedBuildDeps: Record, manifest: PortManifestX, config: InstallConfigLiteX, depId: PortDep, resolutionDep = false, ) { -<<<<<<< HEAD - const { manifest: depPort, defaultInst: defaultDepInstall } = - allowedDeps[depId.name]; - if (!depPort) { -======= - const dep = set.allowedBuildDeps[depId.name]; + const dep = allowedBuildDeps[depId.name]; if (!dep) { ->>>>>>> ade257f (docs: improve README) throw new Error( `unrecognized dependency "${depId.name}" specified by port "${manifest.name}@${manifest.version}"`, ); From 15fcade7773bb3e3a9212b4776b9a4167c692e34 Mon Sep 17 00:00:00 2001 From: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Date: Sun, 2 Jun 2024 16:17:25 +0000 Subject: [PATCH 5/6] fix: cargo-binstall bug --- ports/cargo-binstall.ts | 17 +++++++++-------- tests/utils.ts | 2 ++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/ports/cargo-binstall.ts b/ports/cargo-binstall.ts index 1be633b8..3056abbe 100644 --- a/ports/cargo-binstall.ts +++ b/ports/cargo-binstall.ts @@ -7,7 +7,6 @@ import { InstallArgs, InstallConfigSimple, osXarch, - std_fs, std_path, unarchive, } from "../port.ts"; @@ -75,16 +74,18 @@ export class Port extends GithubReleasePort { await unarchive(fileDwnPath, args.tmpDirPath); + const tmpDir = $.path(args.tmpDirPath); + await tmpDir.join("bin").ensureDir(); + for ( + const fileName of ["cargo-binstall", "detect-targets", "detect-wasi"] + ) { + await tmpDir.join(fileName).renameToDir(tmpDir.join("bin")); + } + const installPath = $.path(args.installPath); if (await installPath.exists()) { await installPath.remove({ recursive: true }); } - - const neededFileNames = ["cargo-binstall", "detect-targets", "detect-wasi"]; - const destination = std_path.resolve(args.installPath, "bin"); - for (const fileName of neededFileNames) { - const sourceFile = std_path.resolve(args.tmpDirPath, fileName); - await std_fs.copy(sourceFile, destination); - } + await tmpDir.rename(installPath); } } diff --git a/tests/utils.ts b/tests/utils.ts index 766709ec..dc67c40a 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -190,6 +190,7 @@ export function genTsGhjkFile( // we need to escape a json string embedded in a js string // 2x (_, val) => typeof val == "string" ? val.replaceAll(/\\/g, "\\\\") : val, + 2, ); const tasks = (secureConf?.tasks ?? []).map( @@ -198,6 +199,7 @@ export function genTsGhjkFile( def, (_, val) => typeof val == "string" ? val.replaceAll(/\\/g, "\\\\") : val, + 2, ); return $.dedent` ghjk.task({ From 1fc94c2c8a5784810140ddf8ab1fa1ea0d270274 Mon Sep 17 00:00:00 2001 From: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Date: Sun, 2 Jun 2024 16:38:19 +0000 Subject: [PATCH 6/6] fix: ports outdated test fix --- tests/portsOutdatedTest.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/portsOutdatedTest.ts b/tests/portsOutdatedTest.ts index caebd186..ef9eaadf 100644 --- a/tests/portsOutdatedTest.ts +++ b/tests/portsOutdatedTest.ts @@ -11,9 +11,8 @@ type CustomE2eTestCase = Omit & { }; const cases: CustomE2eTestCase[] = [ - // 0 megs { - name: "check ports outdated", + name: "ports_outdated", installConf: [ ports.jq_ghrel(), ports.protoc(), @@ -28,7 +27,7 @@ const cases: CustomE2eTestCase[] = [ }, }, { - name: "check ports outdated", + name: "ports_outdated_update_all", installConf: [ ports.jq_ghrel(), ports.protoc(),