Full Code of moghtech/komodo for AI

main 34a9f8eb9ef3 cached
673 files
4.3 MB
1.2M tokens
5064 symbols
1 requests
Download .txt
Showing preview only (4,659K chars total). Download the full file or copy to clipboard to get everything.
Repository: moghtech/komodo
Branch: main
Commit: 34a9f8eb9ef3
Files: 673
Total size: 4.3 MB

Directory structure:
gitextract_7y0a1oom/

├── .cargo/
│   └── config.toml
├── .devcontainer/
│   ├── dev.compose.yaml
│   ├── devcontainer.json
│   └── postCreate.sh
├── .github/
│   └── FUNDING.yml
├── .gitignore
├── .kminclude
├── .vscode/
│   ├── extensions.json
│   ├── resolver.code-snippets
│   └── tasks.json
├── Cargo.toml
├── LICENSE
├── bin/
│   ├── binaries.Dockerfile
│   ├── chef.binaries.Dockerfile
│   ├── cli/
│   │   ├── Cargo.toml
│   │   ├── README.md
│   │   ├── aio.Dockerfile
│   │   ├── docs/
│   │   │   └── copy-database.md
│   │   ├── multi-arch.Dockerfile
│   │   ├── runfile.toml
│   │   ├── single-arch.Dockerfile
│   │   └── src/
│   │       ├── command/
│   │       │   ├── container.rs
│   │       │   ├── database.rs
│   │       │   ├── execute.rs
│   │       │   ├── list.rs
│   │       │   ├── mod.rs
│   │       │   └── update/
│   │       │       ├── mod.rs
│   │       │       ├── resource.rs
│   │       │       ├── user.rs
│   │       │       └── variable.rs
│   │       ├── config.rs
│   │       └── main.rs
│   ├── core/
│   │   ├── Cargo.toml
│   │   ├── aio.Dockerfile
│   │   ├── debian-deps.sh
│   │   ├── multi-arch.Dockerfile
│   │   ├── single-arch.Dockerfile
│   │   ├── src/
│   │   │   ├── alert/
│   │   │   │   ├── discord.rs
│   │   │   │   ├── mod.rs
│   │   │   │   ├── ntfy.rs
│   │   │   │   ├── pushover.rs
│   │   │   │   └── slack.rs
│   │   │   ├── api/
│   │   │   │   ├── auth.rs
│   │   │   │   ├── execute/
│   │   │   │   │   ├── action.rs
│   │   │   │   │   ├── alerter.rs
│   │   │   │   │   ├── build.rs
│   │   │   │   │   ├── deployment.rs
│   │   │   │   │   ├── maintenance.rs
│   │   │   │   │   ├── mod.rs
│   │   │   │   │   ├── procedure.rs
│   │   │   │   │   ├── repo.rs
│   │   │   │   │   ├── server.rs
│   │   │   │   │   ├── stack.rs
│   │   │   │   │   └── sync.rs
│   │   │   │   ├── mod.rs
│   │   │   │   ├── read/
│   │   │   │   │   ├── action.rs
│   │   │   │   │   ├── alert.rs
│   │   │   │   │   ├── alerter.rs
│   │   │   │   │   ├── build.rs
│   │   │   │   │   ├── builder.rs
│   │   │   │   │   ├── deployment.rs
│   │   │   │   │   ├── mod.rs
│   │   │   │   │   ├── permission.rs
│   │   │   │   │   ├── procedure.rs
│   │   │   │   │   ├── provider.rs
│   │   │   │   │   ├── repo.rs
│   │   │   │   │   ├── schedule.rs
│   │   │   │   │   ├── server.rs
│   │   │   │   │   ├── stack.rs
│   │   │   │   │   ├── sync.rs
│   │   │   │   │   ├── tag.rs
│   │   │   │   │   ├── toml.rs
│   │   │   │   │   ├── update.rs
│   │   │   │   │   ├── user.rs
│   │   │   │   │   ├── user_group.rs
│   │   │   │   │   └── variable.rs
│   │   │   │   ├── terminal.rs
│   │   │   │   ├── user.rs
│   │   │   │   └── write/
│   │   │   │       ├── action.rs
│   │   │   │       ├── alerter.rs
│   │   │   │       ├── build.rs
│   │   │   │       ├── builder.rs
│   │   │   │       ├── deployment.rs
│   │   │   │       ├── mod.rs
│   │   │   │       ├── permissions.rs
│   │   │   │       ├── procedure.rs
│   │   │   │       ├── provider.rs
│   │   │   │       ├── repo.rs
│   │   │   │       ├── resource.rs
│   │   │   │       ├── server.rs
│   │   │   │       ├── service_user.rs
│   │   │   │       ├── stack.rs
│   │   │   │       ├── sync.rs
│   │   │   │       ├── tag.rs
│   │   │   │       ├── user.rs
│   │   │   │       ├── user_group.rs
│   │   │   │       └── variable.rs
│   │   │   ├── auth/
│   │   │   │   ├── github/
│   │   │   │   │   ├── client.rs
│   │   │   │   │   └── mod.rs
│   │   │   │   ├── google/
│   │   │   │   │   ├── client.rs
│   │   │   │   │   └── mod.rs
│   │   │   │   ├── jwt.rs
│   │   │   │   ├── local.rs
│   │   │   │   ├── mod.rs
│   │   │   │   └── oidc/
│   │   │   │       ├── client.rs
│   │   │   │       └── mod.rs
│   │   │   ├── cloud/
│   │   │   │   ├── aws/
│   │   │   │   │   ├── ec2.rs
│   │   │   │   │   └── mod.rs
│   │   │   │   └── mod.rs
│   │   │   ├── config.rs
│   │   │   ├── helpers/
│   │   │   │   ├── action_state.rs
│   │   │   │   ├── all_resources.rs
│   │   │   │   ├── builder.rs
│   │   │   │   ├── cache.rs
│   │   │   │   ├── channel.rs
│   │   │   │   ├── maintenance.rs
│   │   │   │   ├── matcher.rs
│   │   │   │   ├── mod.rs
│   │   │   │   ├── procedure.rs
│   │   │   │   ├── prune.rs
│   │   │   │   ├── query.rs
│   │   │   │   └── update.rs
│   │   │   ├── listener/
│   │   │   │   ├── integrations/
│   │   │   │   │   ├── github.rs
│   │   │   │   │   ├── gitlab.rs
│   │   │   │   │   └── mod.rs
│   │   │   │   ├── mod.rs
│   │   │   │   ├── resources.rs
│   │   │   │   └── router.rs
│   │   │   ├── main.rs
│   │   │   ├── monitor/
│   │   │   │   ├── alert/
│   │   │   │   │   ├── deployment.rs
│   │   │   │   │   ├── mod.rs
│   │   │   │   │   ├── server.rs
│   │   │   │   │   └── stack.rs
│   │   │   │   ├── helpers.rs
│   │   │   │   ├── lists.rs
│   │   │   │   ├── mod.rs
│   │   │   │   ├── record.rs
│   │   │   │   └── resources.rs
│   │   │   ├── network.rs
│   │   │   ├── permission.rs
│   │   │   ├── resource/
│   │   │   │   ├── action.rs
│   │   │   │   ├── alerter.rs
│   │   │   │   ├── build.rs
│   │   │   │   ├── builder.rs
│   │   │   │   ├── deployment.rs
│   │   │   │   ├── mod.rs
│   │   │   │   ├── procedure.rs
│   │   │   │   ├── refresh.rs
│   │   │   │   ├── repo.rs
│   │   │   │   ├── server.rs
│   │   │   │   ├── stack.rs
│   │   │   │   └── sync.rs
│   │   │   ├── schedule.rs
│   │   │   ├── stack/
│   │   │   │   ├── execute.rs
│   │   │   │   ├── mod.rs
│   │   │   │   ├── remote.rs
│   │   │   │   └── services.rs
│   │   │   ├── startup.rs
│   │   │   ├── state.rs
│   │   │   ├── sync/
│   │   │   │   ├── deploy.rs
│   │   │   │   ├── execute.rs
│   │   │   │   ├── file.rs
│   │   │   │   ├── mod.rs
│   │   │   │   ├── remote.rs
│   │   │   │   ├── resources.rs
│   │   │   │   ├── toml.rs
│   │   │   │   ├── user_groups.rs
│   │   │   │   ├── variables.rs
│   │   │   │   └── view.rs
│   │   │   ├── ts_client.rs
│   │   │   └── ws/
│   │   │       ├── container.rs
│   │   │       ├── deployment.rs
│   │   │       ├── mod.rs
│   │   │       ├── stack.rs
│   │   │       ├── terminal.rs
│   │   │       └── update.rs
│   │   └── starship.toml
│   └── periphery/
│       ├── Cargo.toml
│       ├── aio.Dockerfile
│       ├── debian-deps.sh
│       ├── multi-arch.Dockerfile
│       ├── single-arch.Dockerfile
│       ├── src/
│       │   ├── api/
│       │   │   ├── build.rs
│       │   │   ├── compose.rs
│       │   │   ├── container.rs
│       │   │   ├── deploy.rs
│       │   │   ├── git.rs
│       │   │   ├── image.rs
│       │   │   ├── mod.rs
│       │   │   ├── network.rs
│       │   │   ├── router.rs
│       │   │   ├── stats.rs
│       │   │   ├── terminal.rs
│       │   │   └── volume.rs
│       │   ├── build.rs
│       │   ├── compose/
│       │   │   ├── mod.rs
│       │   │   ├── up.rs
│       │   │   └── write.rs
│       │   ├── config.rs
│       │   ├── docker/
│       │   │   ├── containers.rs
│       │   │   ├── images.rs
│       │   │   ├── mod.rs
│       │   │   ├── networks.rs
│       │   │   ├── stats.rs
│       │   │   └── volumes.rs
│       │   ├── git.rs
│       │   ├── helpers.rs
│       │   ├── main.rs
│       │   ├── ssl.rs
│       │   ├── stats.rs
│       │   └── terminal.rs
│       └── starship.toml
├── client/
│   ├── core/
│   │   ├── rs/
│   │   │   ├── Cargo.toml
│   │   │   ├── README.md
│   │   │   └── src/
│   │   │       ├── api/
│   │   │       │   ├── auth.rs
│   │   │       │   ├── execute/
│   │   │       │   │   ├── action.rs
│   │   │       │   │   ├── alerter.rs
│   │   │       │   │   ├── build.rs
│   │   │       │   │   ├── deployment.rs
│   │   │       │   │   ├── maintenance.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   ├── procedure.rs
│   │   │       │   │   ├── repo.rs
│   │   │       │   │   ├── server.rs
│   │   │       │   │   ├── stack.rs
│   │   │       │   │   └── sync.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── read/
│   │   │       │   │   ├── action.rs
│   │   │       │   │   ├── alert.rs
│   │   │       │   │   ├── alerter.rs
│   │   │       │   │   ├── build.rs
│   │   │       │   │   ├── builder.rs
│   │   │       │   │   ├── deployment.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   ├── permission.rs
│   │   │       │   │   ├── procedure.rs
│   │   │       │   │   ├── provider.rs
│   │   │       │   │   ├── repo.rs
│   │   │       │   │   ├── schedule.rs
│   │   │       │   │   ├── server.rs
│   │   │       │   │   ├── stack.rs
│   │   │       │   │   ├── sync.rs
│   │   │       │   │   ├── tag.rs
│   │   │       │   │   ├── toml.rs
│   │   │       │   │   ├── update.rs
│   │   │       │   │   ├── user.rs
│   │   │       │   │   ├── user_group.rs
│   │   │       │   │   └── variable.rs
│   │   │       │   ├── terminal.rs
│   │   │       │   ├── user.rs
│   │   │       │   └── write/
│   │   │       │       ├── action.rs
│   │   │       │       ├── alerter.rs
│   │   │       │       ├── api_key.rs
│   │   │       │       ├── build.rs
│   │   │       │       ├── builder.rs
│   │   │       │       ├── deployment.rs
│   │   │       │       ├── mod.rs
│   │   │       │       ├── permissions.rs
│   │   │       │       ├── procedure.rs
│   │   │       │       ├── provider.rs
│   │   │       │       ├── repo.rs
│   │   │       │       ├── resource.rs
│   │   │       │       ├── server.rs
│   │   │       │       ├── stack.rs
│   │   │       │       ├── sync.rs
│   │   │       │       ├── tags.rs
│   │   │       │       ├── user.rs
│   │   │       │       ├── user_group.rs
│   │   │       │       └── variable.rs
│   │   │       ├── busy.rs
│   │   │       ├── deserializers/
│   │   │       │   ├── conversion.rs
│   │   │       │   ├── environment.rs
│   │   │       │   ├── file_contents.rs
│   │   │       │   ├── forgiving_vec.rs
│   │   │       │   ├── item_or_vec.rs
│   │   │       │   ├── labels.rs
│   │   │       │   ├── maybe_string_i64.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── permission.rs
│   │   │       │   ├── string_list.rs
│   │   │       │   └── term_signal_labels.rs
│   │   │       ├── entities/
│   │   │       │   ├── action.rs
│   │   │       │   ├── alert.rs
│   │   │       │   ├── alerter.rs
│   │   │       │   ├── api_key.rs
│   │   │       │   ├── build.rs
│   │   │       │   ├── builder.rs
│   │   │       │   ├── config/
│   │   │       │   │   ├── cli/
│   │   │       │   │   │   ├── args/
│   │   │       │   │   │   │   ├── container.rs
│   │   │       │   │   │   │   ├── database.rs
│   │   │       │   │   │   │   ├── list.rs
│   │   │       │   │   │   │   ├── mod.rs
│   │   │       │   │   │   │   └── update.rs
│   │   │       │   │   │   └── mod.rs
│   │   │       │   │   ├── core.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   └── periphery.rs
│   │   │       │   ├── deployment.rs
│   │   │       │   ├── docker/
│   │   │       │   │   ├── container.rs
│   │   │       │   │   ├── image.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   ├── network.rs
│   │   │       │   │   ├── stats.rs
│   │   │       │   │   └── volume.rs
│   │   │       │   ├── logger.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── permission.rs
│   │   │       │   ├── procedure.rs
│   │   │       │   ├── provider.rs
│   │   │       │   ├── repo.rs
│   │   │       │   ├── resource.rs
│   │   │       │   ├── schedule.rs
│   │   │       │   ├── server.rs
│   │   │       │   ├── stack.rs
│   │   │       │   ├── stats.rs
│   │   │       │   ├── sync.rs
│   │   │       │   ├── tag.rs
│   │   │       │   ├── toml.rs
│   │   │       │   ├── update.rs
│   │   │       │   ├── user.rs
│   │   │       │   ├── user_group.rs
│   │   │       │   └── variable.rs
│   │   │       ├── lib.rs
│   │   │       ├── parsers.rs
│   │   │       ├── request.rs
│   │   │       ├── terminal.rs
│   │   │       └── ws.rs
│   │   └── ts/
│   │       ├── README.md
│   │       ├── generate_types.mjs
│   │       ├── package.json
│   │       ├── runfile.toml
│   │       ├── src/
│   │       │   ├── lib.ts
│   │       │   ├── responses.ts
│   │       │   ├── terminal.ts
│   │       │   └── types.ts
│   │       └── tsconfig.json
│   └── periphery/
│       └── rs/
│           ├── Cargo.toml
│           └── src/
│               ├── api/
│               │   ├── build.rs
│               │   ├── compose.rs
│               │   ├── container.rs
│               │   ├── git.rs
│               │   ├── image.rs
│               │   ├── mod.rs
│               │   ├── network.rs
│               │   ├── stats.rs
│               │   ├── terminal.rs
│               │   └── volume.rs
│               ├── lib.rs
│               └── terminal.rs
├── compose/
│   ├── compose.env
│   ├── ferretdb.compose.yaml
│   ├── mongo.compose.yaml
│   └── periphery.compose.yaml
├── config/
│   ├── core.config.toml
│   ├── komodo.cli.toml
│   └── periphery.config.toml
├── deploy/
│   ├── deno.json
│   └── komodo.ts
├── dev.compose.yaml
├── docsite/
│   ├── .gitignore
│   ├── README.md
│   ├── babel.config.js
│   ├── docs/
│   │   ├── ecosystem/
│   │   │   ├── api.md
│   │   │   ├── cli.mdx
│   │   │   ├── community.md
│   │   │   ├── development.md
│   │   │   └── index.mdx
│   │   ├── intro.md
│   │   ├── resources/
│   │   │   ├── auto-update.md
│   │   │   ├── build-images/
│   │   │   │   ├── builders.md
│   │   │   │   ├── configuration.md
│   │   │   │   ├── index.mdx
│   │   │   │   ├── pre-build.md
│   │   │   │   └── versioning.md
│   │   │   ├── deploy-containers/
│   │   │   │   ├── configuration.md
│   │   │   │   ├── index.mdx
│   │   │   │   └── lifetime-management.md
│   │   │   ├── docker-compose.md
│   │   │   ├── index.md
│   │   │   ├── permissioning.md
│   │   │   ├── procedures.md
│   │   │   ├── sync-resources.md
│   │   │   ├── variables.md
│   │   │   └── webhooks.md
│   │   └── setup/
│   │       ├── advanced.mdx
│   │       ├── backup.md
│   │       ├── connect-servers.mdx
│   │       ├── ferretdb.mdx
│   │       ├── index.mdx
│   │       ├── mongo.mdx
│   │       └── version-upgrades.md
│   ├── docusaurus.config.ts
│   ├── package.json
│   ├── runfile.toml
│   ├── sidebars.ts
│   ├── src/
│   │   ├── components/
│   │   │   ├── ComposeAndEnv.tsx
│   │   │   ├── Divider.tsx
│   │   │   ├── HomepageFeatures/
│   │   │   │   ├── index.tsx
│   │   │   │   └── styles.module.css
│   │   │   ├── KomodoLogo.tsx
│   │   │   ├── RemoteCodeFile.tsx
│   │   │   └── SummaryImg.tsx
│   │   ├── css/
│   │   │   └── custom.css
│   │   └── pages/
│   │       ├── index.module.css
│   │       └── index.tsx
│   ├── static/
│   │   └── .nojekyll
│   └── tsconfig.json
├── example/
│   ├── alerter/
│   │   ├── Cargo.toml
│   │   ├── Dockerfile
│   │   ├── README.md
│   │   └── src/
│   │       └── main.rs
│   └── update_logger/
│       ├── Cargo.toml
│       ├── Dockerfile
│       └── src/
│           └── main.rs
├── expose.compose.yaml
├── frontend/
│   ├── .eslintrc.cjs
│   ├── .gitignore
│   ├── Dockerfile
│   ├── README.md
│   ├── components.json
│   ├── index.html
│   ├── package.json
│   ├── postcss.config.js
│   ├── public/
│   │   ├── client/
│   │   │   ├── lib.d.ts
│   │   │   ├── lib.js
│   │   │   ├── responses.d.ts
│   │   │   ├── responses.js
│   │   │   ├── terminal.d.ts
│   │   │   ├── terminal.js
│   │   │   ├── types.d.ts
│   │   │   └── types.js
│   │   ├── deno.d.ts
│   │   ├── index.d.ts
│   │   ├── manifest.json
│   │   ├── robots.txt
│   │   └── schema/
│   │       └── compose-spec.json
│   ├── runfile.toml
│   ├── src/
│   │   ├── components/
│   │   │   ├── alert/
│   │   │   │   ├── details.tsx
│   │   │   │   ├── index.tsx
│   │   │   │   └── table.tsx
│   │   │   ├── config/
│   │   │   │   ├── env_vars.tsx
│   │   │   │   ├── index.tsx
│   │   │   │   ├── linked_repo.tsx
│   │   │   │   ├── maintenance.tsx
│   │   │   │   └── util.tsx
│   │   │   ├── export.tsx
│   │   │   ├── group-actions.tsx
│   │   │   ├── inspect.tsx
│   │   │   ├── keys/
│   │   │   │   └── table.tsx
│   │   │   ├── layouts.tsx
│   │   │   ├── log.tsx
│   │   │   ├── monaco.tsx
│   │   │   ├── omnibar.tsx
│   │   │   ├── resources/
│   │   │   │   ├── action/
│   │   │   │   │   ├── config.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   ├── info.tsx
│   │   │   │   │   └── table.tsx
│   │   │   │   ├── alerter/
│   │   │   │   │   ├── config/
│   │   │   │   │   │   ├── alert_types.tsx
│   │   │   │   │   │   ├── endpoint.tsx
│   │   │   │   │   │   ├── index.tsx
│   │   │   │   │   │   └── resources.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── table.tsx
│   │   │   │   ├── build/
│   │   │   │   │   ├── actions.tsx
│   │   │   │   │   ├── chart.tsx
│   │   │   │   │   ├── config.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   ├── info.tsx
│   │   │   │   │   └── table.tsx
│   │   │   │   ├── builder/
│   │   │   │   │   ├── config.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── table.tsx
│   │   │   │   ├── common.tsx
│   │   │   │   ├── deployment/
│   │   │   │   │   ├── actions.tsx
│   │   │   │   │   ├── config/
│   │   │   │   │   │   ├── components/
│   │   │   │   │   │   │   ├── image.tsx
│   │   │   │   │   │   │   ├── network.tsx
│   │   │   │   │   │   │   ├── restart.tsx
│   │   │   │   │   │   │   └── term-signal.tsx
│   │   │   │   │   │   └── index.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   ├── inspect.tsx
│   │   │   │   │   ├── log.tsx
│   │   │   │   │   └── table.tsx
│   │   │   │   ├── index.tsx
│   │   │   │   ├── procedure/
│   │   │   │   │   ├── config.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── table.tsx
│   │   │   │   ├── repo/
│   │   │   │   │   ├── actions.tsx
│   │   │   │   │   ├── config.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── table.tsx
│   │   │   │   ├── resource-sync/
│   │   │   │   │   ├── actions.tsx
│   │   │   │   │   ├── config.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   ├── info.tsx
│   │   │   │   │   ├── pending.tsx
│   │   │   │   │   └── table.tsx
│   │   │   │   ├── server/
│   │   │   │   │   ├── actions.tsx
│   │   │   │   │   ├── config.tsx
│   │   │   │   │   ├── hooks.ts
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   ├── info/
│   │   │   │   │   │   ├── containers.tsx
│   │   │   │   │   │   ├── images.tsx
│   │   │   │   │   │   ├── index.tsx
│   │   │   │   │   │   ├── networks.tsx
│   │   │   │   │   │   └── volumes.tsx
│   │   │   │   │   ├── monitoring-table.tsx
│   │   │   │   │   ├── stat-chart.tsx
│   │   │   │   │   ├── stats-mini.tsx
│   │   │   │   │   ├── stats.tsx
│   │   │   │   │   └── table.tsx
│   │   │   │   └── stack/
│   │   │   │       ├── actions.tsx
│   │   │   │       ├── config.tsx
│   │   │   │       ├── index.tsx
│   │   │   │       ├── info.tsx
│   │   │   │       ├── log.tsx
│   │   │   │       ├── services.tsx
│   │   │   │       └── table.tsx
│   │   │   ├── sidebar.tsx
│   │   │   ├── tags/
│   │   │   │   └── index.tsx
│   │   │   ├── terminal/
│   │   │   │   ├── container.tsx
│   │   │   │   ├── index.tsx
│   │   │   │   └── server.tsx
│   │   │   ├── topbar/
│   │   │   │   ├── components.tsx
│   │   │   │   └── index.tsx
│   │   │   ├── updates/
│   │   │   │   ├── details.tsx
│   │   │   │   ├── resource.tsx
│   │   │   │   └── table.tsx
│   │   │   ├── users/
│   │   │   │   ├── delete-user-group.tsx
│   │   │   │   ├── hooks.ts
│   │   │   │   ├── new.tsx
│   │   │   │   ├── permissions-selector.tsx
│   │   │   │   ├── permissions-table.tsx
│   │   │   │   ├── service-api-key.tsx
│   │   │   │   └── table.tsx
│   │   │   └── util.tsx
│   │   ├── globals.css
│   │   ├── lib/
│   │   │   ├── color.ts
│   │   │   ├── dashboard-preferences.ts
│   │   │   ├── formatting.ts
│   │   │   ├── hooks.ts
│   │   │   ├── socket.tsx
│   │   │   └── utils.ts
│   │   ├── main.tsx
│   │   ├── monaco/
│   │   │   ├── fancy_toml.ts
│   │   │   ├── index.ts
│   │   │   ├── init.ts
│   │   │   ├── key_value.ts
│   │   │   ├── shell.ts
│   │   │   ├── string_list.ts
│   │   │   ├── theme.ts
│   │   │   ├── toml.ts
│   │   │   └── yaml.ts
│   │   ├── pages/
│   │   │   ├── alerts.tsx
│   │   │   ├── containers.tsx
│   │   │   ├── home/
│   │   │   │   ├── all_resources.tsx
│   │   │   │   ├── dashboard.tsx
│   │   │   │   ├── index.tsx
│   │   │   │   └── tree.tsx
│   │   │   ├── login.tsx
│   │   │   ├── resource-notifications.tsx
│   │   │   ├── resource.tsx
│   │   │   ├── resources.tsx
│   │   │   ├── schedules.tsx
│   │   │   ├── server-info/
│   │   │   │   ├── container/
│   │   │   │   │   ├── actions.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   ├── inspect.tsx
│   │   │   │   │   └── log.tsx
│   │   │   │   ├── image.tsx
│   │   │   │   ├── network.tsx
│   │   │   │   └── volume.tsx
│   │   │   ├── settings/
│   │   │   │   ├── index.tsx
│   │   │   │   ├── profile.tsx
│   │   │   │   ├── providers.tsx
│   │   │   │   ├── tags.tsx
│   │   │   │   ├── users.tsx
│   │   │   │   └── variables.tsx
│   │   │   ├── stack-service/
│   │   │   │   ├── index.tsx
│   │   │   │   ├── inspect.tsx
│   │   │   │   └── log.tsx
│   │   │   ├── update.tsx
│   │   │   ├── updates.tsx
│   │   │   ├── user-group.tsx
│   │   │   ├── user.tsx
│   │   │   └── user_disabled.tsx
│   │   ├── router.tsx
│   │   ├── types.d.ts
│   │   ├── ui/
│   │   │   ├── badge.tsx
│   │   │   ├── button.tsx
│   │   │   ├── card.tsx
│   │   │   ├── checkbox.tsx
│   │   │   ├── command.tsx
│   │   │   ├── data-table.tsx
│   │   │   ├── dialog.tsx
│   │   │   ├── dropdown-menu.tsx
│   │   │   ├── hover-card.tsx
│   │   │   ├── input.tsx
│   │   │   ├── json.tsx
│   │   │   ├── label.tsx
│   │   │   ├── multi-select.tsx
│   │   │   ├── pagination.tsx
│   │   │   ├── popover.tsx
│   │   │   ├── progress.tsx
│   │   │   ├── select.tsx
│   │   │   ├── separator.tsx
│   │   │   ├── sheet.tsx
│   │   │   ├── skeleton.tsx
│   │   │   ├── switch.tsx
│   │   │   ├── table.tsx
│   │   │   ├── tabs.tsx
│   │   │   ├── textarea.tsx
│   │   │   ├── theme.tsx
│   │   │   ├── toast.tsx
│   │   │   ├── toaster.tsx
│   │   │   ├── toggle-group.tsx
│   │   │   ├── toggle.tsx
│   │   │   ├── tooltip.tsx
│   │   │   └── use-toast.ts
│   │   └── vite-env.d.ts
│   ├── tailwind.config.js
│   ├── tsconfig.json
│   ├── tsconfig.node.json
│   └── vite.config.ts
├── komodo.code-workspace
├── lib/
│   ├── cache/
│   │   ├── Cargo.toml
│   │   ├── README.md
│   │   └── src/
│   │       └── lib.rs
│   ├── command/
│   │   ├── Cargo.toml
│   │   ├── README.md
│   │   └── src/
│   │       └── lib.rs
│   ├── config/
│   │   ├── Cargo.toml
│   │   └── src/
│   │       ├── error.rs
│   │       ├── includes.rs
│   │       ├── lib.rs
│   │       ├── load.rs
│   │       └── merge.rs
│   ├── database/
│   │   ├── Cargo.toml
│   │   └── src/
│   │       ├── lib.rs
│   │       └── utils/
│   │           ├── backup.rs
│   │           ├── copy.rs
│   │           ├── mod.rs
│   │           └── restore.rs
│   ├── environment/
│   │   ├── Cargo.toml
│   │   └── src/
│   │       └── lib.rs
│   ├── environment_file/
│   │   ├── Cargo.toml
│   │   ├── README.md
│   │   └── src/
│   │       └── lib.rs
│   ├── formatting/
│   │   ├── Cargo.toml
│   │   ├── README.md
│   │   └── src/
│   │       └── lib.rs
│   ├── git/
│   │   ├── Cargo.toml
│   │   ├── README.md
│   │   └── src/
│   │       ├── clone.rs
│   │       ├── commit.rs
│   │       ├── init.rs
│   │       ├── lib.rs
│   │       ├── pull.rs
│   │       └── pull_or_clone.rs
│   ├── interpolate/
│   │   ├── Cargo.toml
│   │   └── src/
│   │       └── lib.rs
│   ├── logger/
│   │   ├── Cargo.toml
│   │   ├── README.md
│   │   └── src/
│   │       ├── lib.rs
│   │       └── otel.rs
│   └── response/
│       ├── Cargo.toml
│       └── src/
│           └── lib.rs
├── readme.md
├── roadmap.md
├── runfile.toml
├── rustfmt.toml
├── scripts/
│   ├── install-cli.py
│   ├── readme.md
│   └── setup-periphery.py
└── typeshare.toml

================================================
FILE CONTENTS
================================================

================================================
FILE: .cargo/config.toml
================================================
[build]
rustflags = ["-Wunused-crate-dependencies"]

================================================
FILE: .devcontainer/dev.compose.yaml
================================================
services:
  dev:
    image: mcr.microsoft.com/devcontainers/rust:1-1-bullseye
    volumes:
      # Mount the root folder that contains .git
      - ../:/workspace:cached
      - /var/run/docker.sock:/var/run/docker.sock
      - /proc:/proc
      - repos:/etc/komodo/repos
      - stacks:/etc/komodo/stacks
    command: sleep infinity
    ports:
      - "9121:9121"
    environment:
      KOMODO_FIRST_SERVER: http://localhost:8120
      KOMODO_DATABASE_ADDRESS: db
      KOMODO_ENABLE_NEW_USERS: true
      KOMODO_LOCAL_AUTH: true
      KOMODO_JWT_SECRET: a_random_secret
    links:
      - db
    # ...

  db:
    extends:
      file: ../dev.compose.yaml
      service: ferretdb

volumes:
  data:
  repo-cache:
  repos:
  stacks:

================================================
FILE: .devcontainer/devcontainer.json
================================================
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/rust
{
	"name": "Komodo",
	// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
	//"image": "mcr.microsoft.com/devcontainers/rust:1-1-bullseye",
	"dockerComposeFile": ["dev.compose.yaml"],
	"workspaceFolder": "/workspace",
  	"service": "dev",
	// Features to add to the dev container. More info: https://containers.dev/features.
	"features": {
		"ghcr.io/devcontainers/features/node:1": {
			"version": "20.12.2"
		},
		"ghcr.io/devcontainers-community/features/deno:1": {

		}
	},

	// Use 'mounts' to make the cargo cache persistent in a Docker Volume.
	"mounts": [
		{
			"source": "devcontainer-cargo-cache-${devcontainerId}",
			"target": "/usr/local/cargo",
			"type": "volume"
		}
	],

	// Use 'forwardPorts' to make a list of ports inside the container available locally.
	"forwardPorts": [
		9121
	],

	// Use 'postCreateCommand' to run commands after the container is created.
	"postCreateCommand": "./.devcontainer/postCreate.sh",

	"runServices": [
		"db"
	]

	// Configure tool-specific properties.
	// "customizations": {},

	// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
	// "remoteUser": "root"
}


================================================
FILE: .devcontainer/postCreate.sh
================================================
#!/bin/sh

cargo install typeshare-cli

================================================
FILE: .github/FUNDING.yml
================================================
# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/displaying-a-sponsor-button-in-your-repository
open_collective: komodo


================================================
FILE: .gitignore
================================================
target
node_modules
dist
deno.lock
.env
.env.development
.DS_Store
.idea

/frontend/build
/lib/ts_client/build

.dev


================================================
FILE: .kminclude
================================================
.dev

================================================
FILE: .vscode/extensions.json
================================================
{
    "recommendations": [
        "rust-lang.rust-analyzer",
        "tamasfe.even-better-toml",
        "vadimcn.vscode-lldb",
        "denoland.vscode-deno"
    ]
}

================================================
FILE: .vscode/resolver.code-snippets
================================================
{
	"resolve": {
		"scope": "rust",
		"prefix": "resolve",
		"body": [
			"impl Resolve<${1}, User> for State {",
			"\tasync fn resolve(&self, ${1} { ${0} }: ${1}, _: User) -> anyhow::Result<${2}> {",
			"\t\ttodo!()",
			"\t}",
			"}"
		]
	},
	"static": {
		"scope": "rust",
		"prefix": "static",
		"body": [
			"fn ${1}() -> &'static ${2} {",
			"\tstatic ${3}: OnceLock<${2}> = OnceLock::new();",
			"\t${3}.get_or_init(|| {",
			"\t\t${0}",
			"\t})",
			"}"
		]
	}
}

================================================
FILE: .vscode/tasks.json
================================================
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Run Core",
            "command": "cargo",
            "args": [
                "run",
                "-p",
                "komodo_core",
                "--release"
            ],
            "options": {
                "cwd": "${workspaceFolder}",
                "env": {
                    "KOMODO_CONFIG_PATH": "test.core.config.toml"
                }
            },
            "problemMatcher": [
                "$rustc"
            ]
        },
        {
            "label": "Build Core",
            "command": "cargo",
            "args": [
                "build",
                "-p",
                "komodo_core",
                "--release"
            ],
            "options": {
                "cwd": "${workspaceFolder}",
                "env": {
                    "KOMODO_CONFIG_PATH": "test.core.config.toml"
                }
            },
            "problemMatcher": [
                "$rustc"
            ]
        },
        {
            "label": "Run Periphery",
            "command": "cargo",
            "args": [
                "run",
                "-p",
                "komodo_periphery",
                "--release"
            ],
            "options": {
                "cwd": "${workspaceFolder}",
                "env": {
                    "KOMODO_CONFIG_PATH": "test.periphery.config.toml"
                }
            },
            "problemMatcher": [
                "$rustc"
            ]
        },
        {
            "label": "Build Periphery",
            "command": "cargo",
            "args": [
                "build",
                "-p",
                "komodo_periphery",
                "--release"
            ],
            "options": {
                "cwd": "${workspaceFolder}",
                "env": {
                    "KOMODO_CONFIG_PATH": "test.periphery.config.toml"
                }
            },
            "problemMatcher": [
                "$rustc"
            ]
        },
        {
            "label": "Run Backend",
            "dependsOn": [
                "Run Core",
                "Run Periphery"
            ],
            "problemMatcher": [
                "$rustc"
            ]
        },
        {
            "label": "Build TS Client Types",
            "type": "process",
            "command": "node",
            "args": [
                "./client/core/ts/generate_types.mjs"
            ],
            "problemMatcher": []
        },
        {
            "label": "Init TS Client",
            "type": "shell",
            "command": "yarn && yarn build && yarn link",
            "options": {
                "cwd": "${workspaceFolder}/client/core/ts",
            },
            "problemMatcher": []
        },
        {
            "label": "Init Frontend Client",
            "type": "shell",
            "command": "yarn link komodo_client && yarn install",
            "options": {
                "cwd": "${workspaceFolder}/frontend",
            },
            "problemMatcher": []
        },
        {
            "label": "Init Frontend",
            "dependsOn": [
                "Build TS Client Types",
                "Init TS Client",
                "Init Frontend Client"
            ],
            "dependsOrder": "sequence",
            "problemMatcher": []
        },
        {
            "label": "Build Frontend",
            "type": "shell",
            "command": "yarn build",
            "options": {
                "cwd": "${workspaceFolder}/frontend",
            },
            "problemMatcher": []
        },
        {
            "label": "Prepare Frontend For Run",
            "type": "shell",
            "command": "cp -r ./client/core/ts/dist/. frontend/public/client/.",
            "options": {
                "cwd": "${workspaceFolder}",
            },
            "dependsOn": [
                "Build TS Client Types",
                "Build Frontend"
            ],
            "dependsOrder": "sequence",
            "problemMatcher": []
        },
        {
            "label": "Run Frontend",
            "type": "shell",
            "command": "yarn dev",
            "options": {
                "cwd": "${workspaceFolder}/frontend",
            },
            "dependsOn": ["Prepare Frontend For Run"],
            "problemMatcher": []
        },
        {
            "label": "Init",
            "dependsOn": [
                "Build Backend",
                "Init Frontend"
            ],
            "dependsOrder": "sequence",
            "problemMatcher": []
        },
        {
            "label": "Run Komodo",
            "dependsOn": [
                "Run Core",
                "Run Periphery",
                "Run Frontend"
            ],
            "problemMatcher": []
        },
    ]
  }

================================================
FILE: Cargo.toml
================================================
[workspace]
resolver = "2"
members = [
	"bin/*",
	"lib/*",
	"client/core/rs",
	"client/periphery/rs",
]

[workspace.package]
version = "1.19.5"
edition = "2024"
authors = ["mbecker20 <becker.maxh@gmail.com>"]
license = "GPL-3.0-or-later"
repository = "https://github.com/moghtech/komodo"
homepage = "https://komo.do"

[profile.release]
strip = "debuginfo"

[workspace.dependencies]
# LOCAL
komodo_client = { path = "client/core/rs" }
periphery_client = { path = "client/periphery/rs" }
environment_file = { path = "lib/environment_file" }
environment = { path = "lib/environment" }
interpolate = { path = "lib/interpolate" }
formatting = { path = "lib/formatting" }
database = { path = "lib/database" }
response = { path = "lib/response" }
command = { path = "lib/command" }
config = { path = "lib/config" }
logger = { path = "lib/logger" }
cache = { path = "lib/cache" }
git = { path = "lib/git" }

# MOGH
run_command = { version = "0.0.6", features = ["async_tokio"] }
serror = { version = "0.5.1", default-features = false }
slack = { version = "0.4.0", package = "slack_client_rs", default-features = false, features = ["rustls"] }
derive_default_builder = "0.1.8"
derive_empty_traits = "0.1.0"
async_timing_util = "1.0.0"
partial_derive2 = "0.4.3"
derive_variants = "1.0.0"
mongo_indexed = "2.0.2"
resolver_api = "3.0.0"
toml_pretty = "1.2.0"
mungos = "3.2.2"
svi = "1.2.0"

# ASYNC
reqwest = { version = "0.12.23", default-features = false, features = ["json", "stream", "rustls-tls-native-roots"] }
tokio = { version = "1.47.1", features = ["full"] }
tokio-util = { version = "0.7.16", features = ["io", "codec"] }
tokio-stream = { version = "0.1.17", features = ["sync"] }
pin-project-lite = "0.2.16"
futures = "0.3.31"
futures-util = "0.3.31"
arc-swap = "1.7.1"

# SERVER
tokio-tungstenite = { version = "0.27.0", features = ["rustls-tls-native-roots"] }
axum-extra = { version = "0.10.1", features = ["typed-header"] }
tower-http = { version = "0.6.6", features = ["fs", "cors"] }
axum-server = { version = "0.7.2", features = ["tls-rustls"] }
axum = { version = "0.8.4", features = ["ws", "json", "macros"] }

# SER/DE
ipnetwork = { version = "0.21.1", features = ["serde"] }
indexmap = { version = "2.11.1", features = ["serde"] }
serde = { version = "1.0.219", features = ["derive"] }
strum = { version = "0.27.2", features = ["derive"] }
bson = { version = "2.15.0" } # must keep in sync with mongodb version
serde_yaml_ng = "0.10.0"
serde_json = "1.0.145"
serde_qs = "0.15.0"
toml = "0.9.5"

# ERROR
anyhow = "1.0.99"
thiserror = "2.0.16"

# LOGGING
opentelemetry-otlp = { version = "0.30.0", features = ["tls-roots", "reqwest-rustls"] }
opentelemetry_sdk = { version = "0.30.0", features = ["rt-tokio"] }
tracing-subscriber = { version = "0.3.20", features = ["json"] }
opentelemetry-semantic-conventions = "0.30.0"
tracing-opentelemetry = "0.31.0"
opentelemetry = "0.30.0"
tracing = "0.1.41"

# CONFIG
clap = { version = "4.5.47", features = ["derive"] }
dotenvy = "0.15.7"
envy = "0.4.2"

# CRYPTO / AUTH
uuid = { version = "1.18.1", features = ["v4", "fast-rng", "serde"] }
jsonwebtoken = { version = "9.3.1", default-features = false }
openidconnect = "4.0.1"
urlencoding = "2.1.3"
nom_pem = "4.0.0"
bcrypt = "0.17.1"
base64 = "0.22.1"
rustls = "0.23.31"
hmac = "0.12.1"
sha2 = "0.10.9"
rand = "0.9.2"
hex = "0.4.3"

# SYSTEM
portable-pty = "0.9.0"
bollard = "0.19.2"
sysinfo = "0.37.0"

# CLOUD
aws-config = "1.8.6"
aws-sdk-ec2 = "1.167.0"
aws-credential-types = "1.2.6"

## CRON
english-to-cron = "0.1.6"
chrono-tz = "0.10.4"
chrono = "0.4.42"
croner = "3.0.0"

# MISC
async-compression = { version = "0.4.30", features = ["tokio", "gzip"] }
derive_builder = "0.20.2"
comfy-table = "7.2.1"
typeshare = "1.0.4"
octorust = "0.10.0"
dashmap = "6.1.0"
wildcard = "0.3.0"
colored = "3.0.0"
regex = "1.11.2"
bytes = "1.10.1"
shell-escape = "0.1.5"

================================================
FILE: LICENSE
================================================
                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Use with the GNU Affero General Public License.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

    <program>  Copyright (C) <year>  <name of author>
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.

  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.


================================================
FILE: bin/binaries.Dockerfile
================================================
## Builds the Komodo Core, Periphery, and Util binaries
## for a specific architecture.

FROM rust:1.89.0-bullseye AS builder
RUN cargo install cargo-strip

WORKDIR /builder
COPY Cargo.toml Cargo.lock ./
COPY ./lib ./lib
COPY ./client/core/rs ./client/core/rs
COPY ./client/periphery ./client/periphery
COPY ./bin/core ./bin/core
COPY ./bin/periphery ./bin/periphery
COPY ./bin/cli ./bin/cli

# Compile bin
RUN \
  cargo build -p komodo_core --release && \
  cargo build -p komodo_periphery --release && \
  cargo build -p komodo_cli --release && \
  cargo strip

# Copy just the binaries to scratch image
FROM scratch

COPY --from=builder /builder/target/release/core /core
COPY --from=builder /builder/target/release/periphery /periphery
COPY --from=builder /builder/target/release/km /km

LABEL org.opencontainers.image.source=https://github.com/moghtech/komodo
LABEL org.opencontainers.image.description="Komodo Binaries"
LABEL org.opencontainers.image.licenses=GPL-3.0

================================================
FILE: bin/chef.binaries.Dockerfile
================================================
## Builds the Komodo Core, Periphery, and Util binaries
## for a specific architecture.

## Uses chef for dependency caching to help speed up back-to-back builds.

FROM lukemathwalker/cargo-chef:latest-rust-1.89.0-bullseye AS chef
WORKDIR /builder

# Plan just the RECIPE to see if things have changed
FROM chef AS planner
COPY . .
RUN cargo chef prepare --recipe-path recipe.json

FROM chef AS builder
RUN cargo install cargo-strip
COPY --from=planner /builder/recipe.json recipe.json
# Build JUST dependencies - cached layer
RUN cargo chef cook --release --recipe-path recipe.json
# NOW copy again (this time into builder) and build app
COPY . .
RUN \
  cargo build --release --bin core && \
  cargo build --release --bin periphery && \
  cargo build --release --bin km && \
  cargo strip

# Copy just the binaries to scratch image
FROM scratch

COPY --from=builder /builder/target/release/core /core
COPY --from=builder /builder/target/release/periphery /periphery
COPY --from=builder /builder/target/release/km /km

LABEL org.opencontainers.image.source=https://github.com/moghtech/komodo
LABEL org.opencontainers.image.description="Komodo Binaries"
LABEL org.opencontainers.image.licenses=GPL-3.0

================================================
FILE: bin/cli/Cargo.toml
================================================
[package]
name = "komodo_cli"
description = "Command line tool for Komodo"
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
repository.workspace = true
homepage.workspace = true

[[bin]]
name = "km"
path = "src/main.rs"

[dependencies]
# local
environment_file.workspace = true
komodo_client.workspace = true
database.workspace = true
config.workspace = true
logger.workspace = true
# external
futures-util.workspace = true
comfy-table.workspace = true
serde_json.workspace = true
serde_qs.workspace = true
wildcard.workspace = true
tracing.workspace = true
colored.workspace = true
dotenvy.workspace = true
anyhow.workspace = true
chrono.workspace = true
tokio.workspace = true
serde.workspace = true
clap.workspace = true
envy.workspace = true

================================================
FILE: bin/cli/README.md
================================================
# Komodo CLI

Komodo CLI is a tool to execute actions on your Komodo instance from shell scripts.

## Install

```sh
cargo install komodo_cli
```

Note: On Ubuntu, also requires `apt install build-essential pkg-config libssl-dev`.

## Usage

### Credentials

Configure a file `~/.config/komodo/creds.toml` file with contents:
```toml
url = "https://your.komodo.address"
key = "YOUR-API-KEY"
secret = "YOUR-API-SECRET"
```

Note. You can specify a different creds file by using `--creds ./other/path.toml`.
You can also bypass using any file and pass the information using `--url`, `--key`, `--secret`:

```sh
komodo --url "https://your.komodo.address" --key "YOUR-API-KEY" --secret "YOUR-API-SECRET" ...
```

### Run Executions

```sh
# Triggers an example build
komodo execute run-build test_build
```

#### Manual
`komodo --help`
```md
Command line tool to execute Komodo actions

Usage: komodo [OPTIONS] <COMMAND>

Commands:
  execute  Runs an execution
  help     Print this message or the help of the given subcommand(s)

Options:
      --creds <CREDS>    The path to a creds file [default: /Users/max/.config/komodo/creds.toml]
      --url <URL>        Pass url in args instead of creds file
      --key <KEY>        Pass api key in args instead of creds file
      --secret <SECRET>  Pass api secret in args instead of creds file
  -y, --yes              Always continue on user confirmation prompts
  -h, --help             Print help (see more with '--help')
  -V, --version          Print version
```

`komodo execute --help`
```md
Runs an execution

Usage: komodo execute <COMMAND>

Commands:
  none                    The "null" execution. Does nothing
  run-procedure           Runs the target procedure. Response: [Update]
  run-build               Runs the target build. Response: [Update]
  cancel-build            Cancels the target build. Only does anything if the build is `building` when called. Response: [Update]
  deploy                  Deploys the container for the target deployment. Response: [Update]
  start-deployment        Starts the container for the target deployment. Response: [Update]
  restart-deployment      Restarts the container for the target deployment. Response: [Update]
  pause-deployment        Pauses the container for the target deployment. Response: [Update]
  unpause-deployment      Unpauses the container for the target deployment. Response: [Update]
  stop-deployment         Stops the container for the target deployment. Response: [Update]
  destroy-deployment      Stops and destroys the container for the target deployment. Reponse: [Update]
  clone-repo              Clones the target repo. Response: [Update]
  pull-repo               Pulls the target repo. Response: [Update]
  build-repo              Builds the target repo, using the attached builder. Response: [Update]
  cancel-repo-build       Cancels the target repo build. Only does anything if the repo build is `building` when called. Response: [Update]
  start-container         Starts the container on the target server. Response: [Update]
  restart-container       Restarts the container on the target server. Response: [Update]
  pause-container         Pauses the container on the target server. Response: [Update]
  unpause-container       Unpauses the container on the target server. Response: [Update]
  stop-container          Stops the container on the target server. Response: [Update]
  destroy-container       Stops and destroys the container on the target server. Reponse: [Update]
  start-all-containers    Starts all containers on the target server. Response: [Update]
  restart-all-containers  Restarts all containers on the target server. Response: [Update]
  pause-all-containers    Pauses all containers on the target server. Response: [Update]
  unpause-all-containers  Unpauses all containers on the target server. Response: [Update]
  stop-all-containers     Stops all containers on the target server. Response: [Update]
  prune-containers        Prunes the docker containers on the target server. Response: [Update]
  delete-network          Delete a docker network. Response: [Update]
  prune-networks          Prunes the docker networks on the target server. Response: [Update]
  delete-image            Delete a docker image. Response: [Update]
  prune-images            Prunes the docker images on the target server. Response: [Update]
  delete-volume           Delete a docker volume. Response: [Update]
  prune-volumes           Prunes the docker volumes on the target server. Response: [Update]
  prune-system            Prunes the docker system on the target server, including volumes. Response: [Update]
  run-sync                Runs the target resource sync. Response: [Update]
  deploy-stack            Deploys the target stack. `docker compose up`. Response: [Update]
  start-stack             Starts the target stack. `docker compose start`. Response: [Update]
  restart-stack           Restarts the target stack. `docker compose restart`. Response: [Update]
  pause-stack             Pauses the target stack. `docker compose pause`. Response: [Update]
  unpause-stack           Unpauses the target stack. `docker compose unpause`. Response: [Update]
  stop-stack              Starts the target stack. `docker compose stop`. Response: [Update]
  destroy-stack           Destoys the target stack. `docker compose down`. Response: [Update]
  sleep                   
  help                    Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help
```

### --yes

You can use `--yes` to avoid any human prompt to continue, for use in automated environments.



================================================
FILE: bin/cli/aio.Dockerfile
================================================
FROM rust:1.89.0-bullseye AS builder
RUN cargo install cargo-strip

WORKDIR /builder
COPY Cargo.toml Cargo.lock ./
COPY ./lib ./lib
COPY ./client/core/rs ./client/core/rs
COPY ./client/periphery ./client/periphery
COPY ./bin/cli ./bin/cli

# Compile bin
RUN cargo build -p komodo_cli --release && cargo strip

# Copy binaries to distroless base
FROM gcr.io/distroless/cc

COPY --from=builder /builder/target/release/km /usr/local/bin/km

ENV KOMODO_CLI_CONFIG_PATHS="/config"

CMD [ "km" ]

LABEL org.opencontainers.image.source=https://github.com/moghtech/komodo
LABEL org.opencontainers.image.description="Komodo CLI"
LABEL org.opencontainers.image.licenses=GPL-3.0

================================================
FILE: bin/cli/docs/copy-database.md
================================================
# Copy Database Utility

Copy the Komodo database contents between running, mongo-compatible databases.
Can be used to move between MongoDB / FerretDB, or upgrade from FerretDB v1 to v2.

```yaml
services:

  copy_database:
    image: ghcr.io/moghtech/komodo-cli
    command: km database copy -y
    environment:
      KOMODO_DATABASE_URI: mongodb://${KOMODO_DB_USERNAME}:${KOMODO_DB_PASSWORD}@source:27017
      KOMODO_DATABASE_DB_NAME: ${KOMODO_DATABASE_DB_NAME:-komodo}
      KOMODO_CLI_DATABASE_TARGET_URI: mongodb://${KOMODO_DB_USERNAME}:${KOMODO_DB_PASSWORD}@target:27017
      KOMODO_CLI_DATABASE_TARGET_DB_NAME: ${KOMODO_DATABASE_DB_NAME:-komodo}

```

## FerretDB v2 Update Guide

Up to Komodo 1.17.5, users who wanted to use Postgres / Sqlite were instructed to deploy FerretDB v1.
Now that v2 is out however, v1 will go largely unsupported. Users are recommended to migrate to v2 for
the best performance and ongoing support / updates, however the internal data structures
have changed and this cannot be done in-place. 

Also note that FerretDB v2 no longer supports Sqlite, and only supports 
a [customized Postgres distribution](https://docs.ferretdb.io/installation/documentdb/docker/).
Nonetheless, it remains a solid option for hosts which [do not support mongo](https://github.com/moghtech/komodo/issues/59).

Also note, the same basic process outlined below can also be used to move between MongoDB and FerretDB, just replace FerretDB v2
with the database you wish to move to.

### **Step 1**: *Add* the new database to the top of your existing Komodo compose file.

**Don't forget to also add the new volumes.**

```yaml
## In Komodo compose.yaml
services:
  postgres2:
    # Recommended: Pin to a specific version
    # https://github.com/FerretDB/documentdb/pkgs/container/postgres-documentdb
    image: ghcr.io/ferretdb/postgres-documentdb
    labels:
      komodo.skip: # Prevent Komodo from stopping with StopAllContainers
    restart: unless-stopped
    # ports:
    #   - 5432:5432
    volumes:
      - postgres-data:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: ${KOMODO_DB_USERNAME}
      POSTGRES_PASSWORD: ${KOMODO_DB_PASSWORD}
      POSTGRES_DB: postgres # Do not change

  ferretdb2:
    # Recommended: Pin to a specific version
    # https://github.com/FerretDB/FerretDB/pkgs/container/ferretdb
    image: ghcr.io/ferretdb/ferretdb
    labels:
      komodo.skip: # Prevent Komodo from stopping with StopAllContainers
    restart: unless-stopped
    depends_on:
      - postgres2
    # ports:
    #   - 27017:27017
    volumes:
      - ferretdb-state:/state
    environment:
      FERRETDB_POSTGRESQL_URL: postgres://${KOMODO_DB_USERNAME}:${KOMODO_DB_PASSWORD}@postgres2:5432/postgres

  ...(unchanged)

volumes:
  ...(unchanged)
  postgres-data:
  ferretdb-state:
```

### **Step 2**: *Add* the database copy utility to Komodo compose file.

The SOURCE_URI points to the existing database, ie the old FerretDB v1, and it depends
on whether it was deployed using Postgres or Sqlite. The example below uses the Postgres one,
but if you use Sqlite it should just be something like `mongodb://ferretdb:27017`.

```yaml
## In Komodo compose.yaml
services:
  ...(new database)

  copy_database:
    image: ghcr.io/moghtech/komodo-cli
    command: km database copy -y
    environment:
      KOMODO_DATABASE_URI: mongodb://${KOMODO_DB_USERNAME}:${KOMODO_DB_PASSWORD}@ferretdb:27017/${KOMODO_DATABASE_DB_NAME:-komodo}?authMechanism=PLAIN
      KOMODO_DATABASE_DB_NAME: ${KOMODO_DATABASE_DB_NAME:-komodo}
      KOMODO_CLI_DATABASE_TARGET_URI: mongodb://${KOMODO_DB_USERNAME}:${KOMODO_DB_PASSWORD}@ferretdb2:27017
      KOMODO_CLI_DATABASE_TARGET_DB_NAME: ${KOMODO_DATABASE_DB_NAME:-komodo}

  ...(unchanged)
```

### **Step 3**: *Compose Up* the new additions

Run `docker compose -p komodo --env-file compose.env -f xxxxx.compose.yaml up -d`, filling in the name of your compose.yaml.
This will start up both the old and new database, and copy the data to the new one.

Wait a few moments for the `copy_database` service to finish. When it exits,
confirm the logs show the data was moved successfully, and move on to the next step.

### **Step 4**: Point Komodo Core to the new database

In your Komodo compose.yaml, first *comment out* the `copy_database` service and old ferretdb v1 service/s.
Then update the `core` service environment to point to `ferretdb2`.

```yaml
services:
  ...

  core:
    ...(unchanged)
    environment:
      KOMODO_DATABASE_ADDRESS: ferretdb2:27017
      KOMODO_DATABASE_USERNAME: ${KOMODO_DB_USERNAME}
      KOMODO_DATABASE_PASSWORD: ${KOMODO_DB_PASSWORD}
```

### **Step 5**: Final *Compose Up*

Repeat the same `docker compose` command as before to apply the changes, and then try navigating to your Komodo web page.
If it works, congrats, **you are done**. You can clean up the compose file if you would like, removing the old volumes etc.

If it does not work, check the logs for any obvious issues, and if necessary you can undo the previous steps
to go back to using the previous database.


================================================
FILE: bin/cli/multi-arch.Dockerfile
================================================
## Assumes the latest binaries for x86_64 and aarch64 are already built (by binaries.Dockerfile).
## Since theres no heavy build here, QEMU multi-arch builds are fine for this image.

ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:latest
ARG X86_64_BINARIES=${BINARIES_IMAGE}-x86_64
ARG AARCH64_BINARIES=${BINARIES_IMAGE}-aarch64

# This is required to work with COPY --from
FROM ${X86_64_BINARIES} AS x86_64
FROM ${AARCH64_BINARIES} AS aarch64

FROM debian:bullseye-slim

WORKDIR /app

## Copy both binaries initially, but only keep appropriate one for the TARGETPLATFORM.
COPY --from=x86_64 /km /app/arch/linux/amd64
COPY --from=aarch64 /km /app/arch/linux/arm64

ARG TARGETPLATFORM
RUN mv /app/arch/${TARGETPLATFORM} /usr/local/bin/km && rm -r /app/arch

ENV KOMODO_CLI_CONFIG_PATHS="/config"

CMD [ "km" ]

LABEL org.opencontainers.image.source=https://github.com/moghtech/komodo
LABEL org.opencontainers.image.description="Komodo CLI"
LABEL org.opencontainers.image.licenses=GPL-3.0

================================================
FILE: bin/cli/runfile.toml
================================================
[install-cli]
alias = "ic"
description = "installs the komodo-cli, available on the command line as 'km'"
cmd = "cargo install --path ."

================================================
FILE: bin/cli/single-arch.Dockerfile
================================================
## Assumes the latest binaries for the required arch are already built (by binaries.Dockerfile).

ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:latest

# This is required to work with COPY --from
FROM ${BINARIES_IMAGE} AS binaries

FROM gcr.io/distroless/cc

COPY --from=binaries /km /usr/local/bin/km

ENV KOMODO_CLI_CONFIG_PATHS="/config"

CMD [ "km" ]

LABEL org.opencontainers.image.source=https://github.com/moghtech/komodo
LABEL org.opencontainers.image.description="Komodo CLI"
LABEL org.opencontainers.image.licenses=GPL-3.0


================================================
FILE: bin/cli/src/command/container.rs
================================================
use std::collections::{HashMap, HashSet};

use anyhow::Context;
use colored::Colorize;
use comfy_table::{Attribute, Cell, Color};
use futures_util::{
  FutureExt, TryStreamExt, stream::FuturesUnordered,
};
use komodo_client::{
  api::read::{
    InspectDockerContainer, ListAllDockerContainers, ListServers,
  },
  entities::{
    config::cli::args::container::{
      Container, ContainerCommand, InspectContainer,
    },
    docker::{
      self,
      container::{ContainerListItem, ContainerStateStatusEnum},
    },
  },
};

use crate::{
  command::{
    PrintTable, clamp_sha, matches_wildcards, parse_wildcards,
    print_items,
  },
  config::cli_config,
};

pub async fn handle(container: &Container) -> anyhow::Result<()> {
  match &container.command {
    None => list_containers(container).await,
    Some(ContainerCommand::Inspect(inspect)) => {
      inspect_container(inspect).await
    }
  }
}

async fn list_containers(
  Container {
    all,
    down,
    links,
    reverse,
    containers: names,
    images,
    networks,
    servers,
    format,
    command: _,
  }: &Container,
) -> anyhow::Result<()> {
  let client = super::komodo_client().await?;
  let (server_map, containers) = tokio::try_join!(
    client
      .read(ListServers::default())
      .map(|res| res.map(|res| res
        .into_iter()
        .map(|s| (s.id.clone(), s))
        .collect::<HashMap<_, _>>())),
    client.read(ListAllDockerContainers {
      servers: Default::default()
    }),
  )?;

  // (Option<Server Name>, Container)
  let containers = containers.into_iter().map(|c| {
    let server = if let Some(server_id) = c.server_id.as_ref()
      && let Some(server) = server_map.get(server_id)
    {
      server
    } else {
      return (None, c);
    };
    (Some(server.name.as_str()), c)
  });

  let names = parse_wildcards(names);
  let servers = parse_wildcards(servers);
  let images = parse_wildcards(images);
  let networks = parse_wildcards(networks);

  let mut containers = containers
    .into_iter()
    .filter(|(server_name, c)| {
      let state_check = if *all {
        true
      } else if *down {
        !matches!(c.state, ContainerStateStatusEnum::Running)
      } else {
        matches!(c.state, ContainerStateStatusEnum::Running)
      };
      let network_check = matches_wildcards(
        &networks,
        &c.network_mode
          .as_deref()
          .map(|n| vec![n])
          .unwrap_or_default(),
      ) || matches_wildcards(
        &networks,
        &c.networks.iter().map(String::as_str).collect::<Vec<_>>(),
      );
      state_check
        && network_check
        && matches_wildcards(&names, &[c.name.as_str()])
        && matches_wildcards(
          &servers,
          &server_name
            .as_deref()
            .map(|i| vec![i])
            .unwrap_or_default(),
        )
        && matches_wildcards(
          &images,
          &c.image.as_deref().map(|i| vec![i]).unwrap_or_default(),
        )
    })
    .collect::<Vec<_>>();
  containers.sort_by(|(a_s, a), (b_s, b)| {
    a.state
      .cmp(&b.state)
      .then(a.name.cmp(&b.name))
      .then(a_s.cmp(b_s))
      .then(a.network_mode.cmp(&b.network_mode))
      .then(a.image.cmp(&b.image))
  });
  if *reverse {
    containers.reverse();
  }
  print_items(containers, *format, *links)?;
  Ok(())
}

pub async fn inspect_container(
  inspect: &InspectContainer,
) -> anyhow::Result<()> {
  let client = super::komodo_client().await?;
  let (server_map, mut containers) = tokio::try_join!(
    client
      .read(ListServers::default())
      .map(|res| res.map(|res| res
        .into_iter()
        .map(|s| (s.id.clone(), s))
        .collect::<HashMap<_, _>>())),
    client.read(ListAllDockerContainers {
      servers: Default::default()
    }),
  )?;

  containers.iter_mut().for_each(|c| {
    let Some(server_id) = c.server_id.as_ref() else {
      return;
    };
    let Some(server) = server_map.get(server_id) else {
      c.server_id = Some(String::from("Unknown"));
      return;
    };
    c.server_id = Some(server.name.clone());
  });

  let names = [inspect.container.to_string()];
  let names = parse_wildcards(&names);
  let servers = parse_wildcards(&inspect.servers);

  let mut containers = containers
    .into_iter()
    .filter(|c| {
      matches_wildcards(&names, &[c.name.as_str()])
        && matches_wildcards(
          &servers,
          &c.server_id
            .as_deref()
            .map(|i| vec![i])
            .unwrap_or_default(),
        )
    })
    .map(|c| async move {
      client
        .read(InspectDockerContainer {
          container: c.name,
          server: c.server_id.context("No server...")?,
        })
        .await
    })
    .collect::<FuturesUnordered<_>>()
    .try_collect::<Vec<_>>()
    .await?;

  containers.sort_by(|a, b| a.name.cmp(&b.name));

  match containers.len() {
    0 => {
      println!(
        "{}: Did not find any containers matching '{}'",
        "INFO".green(),
        inspect.container.bold()
      );
    }
    1 => {
      println!("{}", serialize_container(inspect, &containers[0])?);
    }
    _ => {
      let containers = containers
        .iter()
        .map(|c| serialize_container(inspect, c))
        .collect::<anyhow::Result<Vec<_>>>()?
        .join("\n");
      println!("{containers}");
    }
  }

  Ok(())
}

fn serialize_container(
  inspect: &InspectContainer,
  container: &docker::container::Container,
) -> anyhow::Result<String> {
  let res = if inspect.state {
    serde_json::to_string_pretty(&container.state)
  } else if inspect.mounts {
    serde_json::to_string_pretty(&container.mounts)
  } else if inspect.host_config {
    serde_json::to_string_pretty(&container.host_config)
  } else if inspect.config {
    serde_json::to_string_pretty(&container.config)
  } else if inspect.network_settings {
    serde_json::to_string_pretty(&container.network_settings)
  } else {
    serde_json::to_string_pretty(container)
  }
  .context("Failed to serialize items to JSON")?;
  Ok(res)
}

// (Option<Server Name>, Container)
impl PrintTable for (Option<&'_ str>, ContainerListItem) {
  fn header(links: bool) -> &'static [&'static str] {
    if links {
      &[
        "Container",
        "State",
        "Server",
        "Ports",
        "Networks",
        "Image",
        "Link",
      ]
    } else {
      &["Container", "State", "Server", "Ports", "Networks", "Image"]
    }
  }
  fn row(self, links: bool) -> Vec<Cell> {
    let color = match self.1.state {
      ContainerStateStatusEnum::Running => Color::Green,
      ContainerStateStatusEnum::Paused => Color::DarkYellow,
      ContainerStateStatusEnum::Empty => Color::Grey,
      _ => Color::Red,
    };
    let mut networks = HashSet::new();
    if let Some(network) = self.1.network_mode {
      networks.insert(network);
    }
    for network in self.1.networks {
      networks.insert(network);
    }
    let mut networks = networks.into_iter().collect::<Vec<_>>();
    networks.sort();
    let mut ports = self
      .1
      .ports
      .into_iter()
      .flat_map(|p| p.public_port.map(|p| p.to_string()))
      .collect::<HashSet<_>>()
      .into_iter()
      .collect::<Vec<_>>();
    ports.sort();
    let ports = if ports.is_empty() {
      Cell::new("")
    } else {
      Cell::new(format!(":{}", ports.join(", :")))
    };

    let image = self.1.image.as_deref().unwrap_or("Unknown");
    let mut res = vec![
      Cell::new(self.1.name.clone()).add_attribute(Attribute::Bold),
      Cell::new(self.1.state.to_string())
        .fg(color)
        .add_attribute(Attribute::Bold),
      Cell::new(self.0.unwrap_or("Unknown")),
      ports,
      Cell::new(networks.join(", ")),
      Cell::new(clamp_sha(image)),
    ];
    if !links {
      return res;
    }
    let link = if let Some(server_id) = self.1.server_id {
      format!(
        "{}/servers/{server_id}/container/{}",
        cli_config().host,
        self.1.name
      )
    } else {
      String::new()
    };
    res.push(Cell::new(link));
    res
  }
}


================================================
FILE: bin/cli/src/command/database.rs
================================================
use std::path::Path;

use anyhow::Context;
use colored::Colorize;
use komodo_client::entities::{
  config::cli::args::database::DatabaseCommand, optional_string,
};

use crate::{command::sanitize_uri, config::cli_config};

pub async fn handle(command: &DatabaseCommand) -> anyhow::Result<()> {
  match command {
    DatabaseCommand::Backup { yes, .. } => backup(*yes).await,
    DatabaseCommand::Restore {
      restore_folder,
      index,
      yes,
      ..
    } => restore(restore_folder.as_deref(), *index, *yes).await,
    DatabaseCommand::Prune { yes, .. } => prune(*yes).await,
    DatabaseCommand::Copy { yes, index, .. } => {
      copy(*index, *yes).await
    }
  }
}

async fn backup(yes: bool) -> anyhow::Result<()> {
  let config = cli_config();

  println!(
    "\n🦎  {} Database {} Utility  🦎",
    "Komodo".bold(),
    "Backup".green().bold()
  );
  println!(
    "\n{}\n",
    " - Backup all database contents to gzip compressed files."
      .dimmed()
  );
  if let Some(uri) = optional_string(&config.database.uri) {
    println!("{}: {}", " - Source URI".dimmed(), sanitize_uri(&uri));
  }
  if let Some(address) = optional_string(&config.database.address) {
    println!("{}: {address}", " - Source Address".dimmed());
  }
  if let Some(username) = optional_string(&config.database.username) {
    println!("{}: {username}", " - Source Username".dimmed());
  }
  println!(
    "{}: {}\n",
    " - Source Db Name".dimmed(),
    config.database.db_name,
  );
  println!(
    "{}: {:?}",
    " - Backups Folder".dimmed(),
    config.backups_folder
  );
  if config.max_backups == 0 {
    println!(
      "{}{}",
      " - Backup pruning".dimmed(),
      "disabled".red().dimmed()
    );
  } else {
    println!("{}: {}", " - Max Backups".dimmed(), config.max_backups);
  }

  crate::command::wait_for_enter("start backup", yes)?;

  let db = database::init(&config.database).await?;

  database::utils::backup(&db, &config.backups_folder).await?;

  // Early return if backup pruning disabled
  if config.max_backups == 0 {
    return Ok(());
  }

  // Know that new backup was taken successfully at this point,
  // safe to prune old backup folders

  prune_inner().await
}

async fn restore(
  restore_folder: Option<&Path>,
  index: bool,
  yes: bool,
) -> anyhow::Result<()> {
  let config = cli_config();

  println!(
    "\n🦎  {} Database {} Utility  🦎",
    "Komodo".bold(),
    "Restore".purple().bold()
  );
  println!(
    "\n{}\n",
    " - Restores database contents from gzip compressed files."
      .dimmed()
  );
  if let Some(uri) = optional_string(&config.database_target.uri) {
    println!("{}: {}", " - Target URI".dimmed(), sanitize_uri(&uri));
  }
  if let Some(address) =
    optional_string(&config.database_target.address)
  {
    println!("{}: {address}", " - Target Address".dimmed());
  }
  if let Some(username) =
    optional_string(&config.database_target.username)
  {
    println!("{}: {username}", " - Target Username".dimmed());
  }
  println!(
    "{}: {}",
    " - Target Db Name".dimmed(),
    config.database_target.db_name,
  );
  if !index {
    println!(
      "{}: {}",
      " - Target Db Indexing".dimmed(),
      "DISABLED".red(),
    );
  }
  println!(
    "\n{}: {:?}",
    " - Backups Folder".dimmed(),
    config.backups_folder
  );
  if let Some(restore_folder) = restore_folder {
    println!("{}: {restore_folder:?}", " - Restore Folder".dimmed());
  }

  crate::command::wait_for_enter("start restore", yes)?;

  let db = if index {
    database::Client::new(&config.database_target).await?.db
  } else {
    database::init(&config.database_target).await?
  };

  database::utils::restore(
    &db,
    &config.backups_folder,
    restore_folder,
  )
  .await
}

async fn prune(yes: bool) -> anyhow::Result<()> {
  let config = cli_config();

  println!(
    "\n🦎  {} Database {} Utility  🦎",
    "Komodo".bold(),
    "Backup Prune".cyan().bold()
  );
  println!(
    "\n{}\n",
    " - Prunes database backup folders when greater than the configured amount."
      .dimmed()
  );
  println!(
    "{}: {:?}",
    " - Backups Folder".dimmed(),
    config.backups_folder
  );
  if config.max_backups == 0 {
    println!(
      "{}{}",
      " - Backup pruning".dimmed(),
      "disabled".red().dimmed()
    );
  } else {
    println!("{}: {}", " - Max Backups".dimmed(), config.max_backups);
  }

  // Early return if backup pruning disabled
  if config.max_backups == 0 {
    info!(
      "Backup pruning is disabled, enabled using 'max_backups' (KOMODO_CLI_MAX_BACKUPS)"
    );
    return Ok(());
  }

  crate::command::wait_for_enter("start backup prune", yes)?;

  prune_inner().await
}

async fn prune_inner() -> anyhow::Result<()> {
  let config = cli_config();

  let mut backups_dir =
    match tokio::fs::read_dir(&config.backups_folder)
      .await
      .context("Failed to read backups folder for prune")
    {
      Ok(backups_dir) => backups_dir,
      Err(e) => {
        warn!("{e:#}");
        return Ok(());
      }
    };

  let mut backup_folders = Vec::new();
  loop {
    match backups_dir.next_entry().await {
      Ok(Some(entry)) => {
        let Ok(metadata) = entry.metadata().await else {
          continue;
        };
        if metadata.is_dir() {
          backup_folders.push(entry.path());
        }
      }
      Ok(None) => break,
      Err(_) => {
        continue;
      }
    }
  }
  // Ordered from oldest -> newest
  backup_folders.sort();

  let max_backups = config.max_backups as usize;
  let backup_folders_len = backup_folders.len();

  // Early return if under the backup count threshold
  if backup_folders_len <= max_backups {
    info!("No backups to prune");
    return Ok(());
  }

  let to_delete =
    &backup_folders[..(backup_folders_len - max_backups)];

  info!("Pruning old backups: {to_delete:?}");

  for path in to_delete {
    if let Err(e) =
      tokio::fs::remove_dir_all(path).await.with_context(|| {
        format!("Failed to delete backup folder at {path:?}")
      })
    {
      warn!("{e:#}");
    }
  }

  Ok(())
}

async fn copy(index: bool, yes: bool) -> anyhow::Result<()> {
  let config = cli_config();

  println!(
    "\n🦎  {} Database {} Utility  🦎",
    "Komodo".bold(),
    "Copy".blue().bold()
  );
  println!(
    "\n{}\n",
    " - Copies database contents to another database.".dimmed()
  );

  if let Some(uri) = optional_string(&config.database.uri) {
    println!("{}: {}", " - Source URI".dimmed(), sanitize_uri(&uri));
  }
  if let Some(address) = optional_string(&config.database.address) {
    println!("{}: {address}", " - Source Address".dimmed());
  }
  if let Some(username) = optional_string(&config.database.username) {
    println!("{}: {username}", " - Source Username".dimmed());
  }
  println!(
    "{}: {}\n",
    " - Source Db Name".dimmed(),
    config.database.db_name,
  );

  if let Some(uri) = optional_string(&config.database_target.uri) {
    println!("{}: {}", " - Target URI".dimmed(), sanitize_uri(&uri));
  }
  if let Some(address) =
    optional_string(&config.database_target.address)
  {
    println!("{}: {address}", " - Target Address".dimmed());
  }
  if let Some(username) =
    optional_string(&config.database_target.username)
  {
    println!("{}: {username}", " - Target Username".dimmed());
  }
  println!(
    "{}: {}",
    " - Target Db Name".dimmed(),
    config.database_target.db_name,
  );
  if !index {
    println!(
      "{}: {}",
      " - Target Db Indexing".dimmed(),
      "DISABLED".red(),
    );
  }

  crate::command::wait_for_enter("start copy", yes)?;

  let source_db = database::init(&config.database).await?;
  let target_db = if index {
    database::Client::new(&config.database_target).await?.db
  } else {
    database::init(&config.database_target).await?
  };

  database::utils::copy(&source_db, &target_db).await
}


================================================
FILE: bin/cli/src/command/execute.rs
================================================
use std::time::Duration;

use colored::Colorize;
use futures_util::{StreamExt, stream::FuturesUnordered};
use komodo_client::{
  api::execute::{
    BatchExecutionResponse, BatchExecutionResponseItem, Execution,
  },
  entities::{resource_link, update::Update},
};

use crate::config::cli_config;

enum ExecutionResult {
  Single(Box<Update>),
  Batch(BatchExecutionResponse),
}

pub async fn handle(
  execution: &Execution,
  yes: bool,
) -> anyhow::Result<()> {
  if matches!(execution, Execution::None(_)) {
    println!("Got 'none' execution. Doing nothing...");
    tokio::time::sleep(Duration::from_secs(3)).await;
    println!("Finished doing nothing. Exiting...");
    std::process::exit(0);
  }

  println!("\n{}: Execution", "Mode".dimmed());
  match execution {
    Execution::None(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::RunAction(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::BatchRunAction(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::RunProcedure(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::BatchRunProcedure(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::RunBuild(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::BatchRunBuild(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::CancelBuild(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::Deploy(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::BatchDeploy(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::PullDeployment(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::StartDeployment(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::RestartDeployment(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::PauseDeployment(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::UnpauseDeployment(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::StopDeployment(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::DestroyDeployment(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::BatchDestroyDeployment(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::CloneRepo(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::BatchCloneRepo(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::PullRepo(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::BatchPullRepo(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::BuildRepo(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::BatchBuildRepo(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::CancelRepoBuild(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::StartContainer(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::RestartContainer(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::PauseContainer(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::UnpauseContainer(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::StopContainer(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::DestroyContainer(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::StartAllContainers(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::RestartAllContainers(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::PauseAllContainers(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::UnpauseAllContainers(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::StopAllContainers(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::PruneContainers(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::DeleteNetwork(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::PruneNetworks(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::DeleteImage(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::PruneImages(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::DeleteVolume(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::PruneVolumes(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::PruneDockerBuilders(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::PruneBuildx(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::PruneSystem(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::RunSync(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::CommitSync(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::DeployStack(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::BatchDeployStack(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::DeployStackIfChanged(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::BatchDeployStackIfChanged(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::PullStack(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::BatchPullStack(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::StartStack(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::RestartStack(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::PauseStack(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::UnpauseStack(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::StopStack(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::DestroyStack(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::BatchDestroyStack(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::RunStackService(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::TestAlerter(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::SendAlert(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::ClearRepoCache(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::BackupCoreDatabase(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::GlobalAutoUpdate(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
    Execution::Sleep(data) => {
      println!("{}: {data:?}", "Data".dimmed())
    }
  }

  super::wait_for_enter("run execution", yes)?;

  info!("Running Execution...");

  let client = super::komodo_client().await?;

  let res = match execution.clone() {
    Execution::RunAction(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::BatchRunAction(request) => {
      client.execute(request).await.map(ExecutionResult::Batch)
    }
    Execution::RunProcedure(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::BatchRunProcedure(request) => {
      client.execute(request).await.map(ExecutionResult::Batch)
    }
    Execution::RunBuild(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::BatchRunBuild(request) => {
      client.execute(request).await.map(ExecutionResult::Batch)
    }
    Execution::CancelBuild(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::Deploy(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::BatchDeploy(request) => {
      client.execute(request).await.map(ExecutionResult::Batch)
    }
    Execution::PullDeployment(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::StartDeployment(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::RestartDeployment(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::PauseDeployment(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::UnpauseDeployment(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::StopDeployment(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::DestroyDeployment(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::BatchDestroyDeployment(request) => {
      client.execute(request).await.map(ExecutionResult::Batch)
    }
    Execution::CloneRepo(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::BatchCloneRepo(request) => {
      client.execute(request).await.map(ExecutionResult::Batch)
    }
    Execution::PullRepo(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::BatchPullRepo(request) => {
      client.execute(request).await.map(ExecutionResult::Batch)
    }
    Execution::BuildRepo(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::BatchBuildRepo(request) => {
      client.execute(request).await.map(ExecutionResult::Batch)
    }
    Execution::CancelRepoBuild(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::StartContainer(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::RestartContainer(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::PauseContainer(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::UnpauseContainer(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::StopContainer(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::DestroyContainer(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::StartAllContainers(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::RestartAllContainers(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::PauseAllContainers(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::UnpauseAllContainers(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::StopAllContainers(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::PruneContainers(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::DeleteNetwork(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::PruneNetworks(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::DeleteImage(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::PruneImages(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::DeleteVolume(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::PruneVolumes(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::PruneDockerBuilders(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::PruneBuildx(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::PruneSystem(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::RunSync(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::CommitSync(request) => client
      .write(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::DeployStack(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::BatchDeployStack(request) => {
      client.execute(request).await.map(ExecutionResult::Batch)
    }
    Execution::DeployStackIfChanged(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::BatchDeployStackIfChanged(request) => {
      client.execute(request).await.map(ExecutionResult::Batch)
    }
    Execution::PullStack(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::BatchPullStack(request) => {
      client.execute(request).await.map(ExecutionResult::Batch)
    }
    Execution::StartStack(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::RestartStack(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::PauseStack(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::UnpauseStack(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::StopStack(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::DestroyStack(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::BatchDestroyStack(request) => {
      client.execute(request).await.map(ExecutionResult::Batch)
    }
    Execution::RunStackService(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::TestAlerter(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::SendAlert(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::ClearRepoCache(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::BackupCoreDatabase(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::GlobalAutoUpdate(request) => client
      .execute(request)
      .await
      .map(|u| ExecutionResult::Single(u.into())),
    Execution::Sleep(request) => {
      let duration =
        Duration::from_millis(request.duration_ms as u64);
      tokio::time::sleep(duration).await;
      println!("Finished sleeping!");
      std::process::exit(0)
    }
    Execution::None(_) => unreachable!(),
  };

  match res {
    Ok(ExecutionResult::Single(update)) => {
      poll_update_until_complete(&update).await
    }
    Ok(ExecutionResult::Batch(updates)) => {
      let mut handles = updates
        .iter()
        .map(|update| async move {
          match update {
            BatchExecutionResponseItem::Ok(update) => {
              poll_update_until_complete(update).await
            }
            BatchExecutionResponseItem::Err(e) => {
              error!("{e:#?}");
              Ok(())
            }
          }
        })
        .collect::<FuturesUnordered<_>>();
      while let Some(res) = handles.next().await {
        match res {
          Ok(()) => {}
          Err(e) => {
            error!("{e:#?}");
          }
        }
      }
      Ok(())
    }
    Err(e) => {
      error!("{e:#?}");
      Ok(())
    }
  }
}

async fn poll_update_until_complete(
  update: &Update,
) -> anyhow::Result<()> {
  let link = if update.id.is_empty() {
    let (resource_type, id) = update.target.extract_variant_id();
    resource_link(&cli_config().host, resource_type, id)
  } else {
    format!("{}/updates/{}", cli_config().host, update.id)
  };
  println!("Link: '{}'", link.bold());

  let client = super::komodo_client().await?;

  let timer = tokio::time::Instant::now();
  let update = client.poll_update_until_complete(&update.id).await?;
  if update.success {
    println!(
      "FINISHED in {}: {}",
      format!("{:.1?}", timer.elapsed()).bold(),
      "EXECUTION SUCCESSFUL".green(),
    );
  } else {
    eprintln!(
      "FINISHED in {}: {}",
      format!("{:.1?}", timer.elapsed()).bold(),
      "EXECUTION FAILED".red(),
    );
  }
  Ok(())
}


================================================
FILE: bin/cli/src/command/list.rs
================================================
use std::{cmp::Ordering, collections::HashMap};

use comfy_table::{Attribute, Cell, Color};
use futures_util::{FutureExt, try_join};
use komodo_client::{
  KomodoClient,
  api::read::{
    ListActions, ListAlerters, ListBuilders, ListBuilds,
    ListDeployments, ListProcedures, ListRepos, ListResourceSyncs,
    ListSchedules, ListServers, ListStacks, ListTags,
  },
  entities::{
    ResourceTargetVariant,
    action::{ActionListItem, ActionListItemInfo, ActionState},
    alerter::{AlerterListItem, AlerterListItemInfo},
    build::{BuildListItem, BuildListItemInfo, BuildState},
    builder::{BuilderListItem, BuilderListItemInfo},
    config::cli::args::{
      self,
      list::{ListCommand, ResourceFilters},
    },
    deployment::{
      DeploymentListItem, DeploymentListItemInfo, DeploymentState,
    },
    procedure::{
      ProcedureListItem, ProcedureListItemInfo, ProcedureState,
    },
    repo::{RepoListItem, RepoListItemInfo, RepoState},
    resource::{ResourceListItem, ResourceQuery},
    resource_link,
    schedule::Schedule,
    server::{ServerListItem, ServerListItemInfo, ServerState},
    stack::{StackListItem, StackListItemInfo, StackState},
    sync::{
      ResourceSyncListItem, ResourceSyncListItemInfo,
      ResourceSyncState,
    },
  },
};
use serde::Serialize;

use crate::{
  command::{
    PrintTable, format_timetamp, matches_wildcards, parse_wildcards,
    print_items,
  },
  config::cli_config,
};

pub async fn handle(list: &args::list::List) -> anyhow::Result<()> {
  match &list.command {
    None => list_all(list).await,
    Some(ListCommand::Servers(filters)) => {
      list_resources::<ServerListItem>(filters, false).await
    }
    Some(ListCommand::Stacks(filters)) => {
      list_resources::<StackListItem>(filters, false).await
    }
    Some(ListCommand::Deployments(filters)) => {
      list_resources::<DeploymentListItem>(filters, false).await
    }
    Some(ListCommand::Builds(filters)) => {
      list_resources::<BuildListItem>(filters, false).await
    }
    Some(ListCommand::Repos(filters)) => {
      list_resources::<RepoListItem>(filters, false).await
    }
    Some(ListCommand::Procedures(filters)) => {
      list_resources::<ProcedureListItem>(filters, false).await
    }
    Some(ListCommand::Actions(filters)) => {
      list_resources::<ActionListItem>(filters, false).await
    }
    Some(ListCommand::Syncs(filters)) => {
      list_resources::<ResourceSyncListItem>(filters, false).await
    }
    Some(ListCommand::Builders(filters)) => {
      list_resources::<BuilderListItem>(filters, false).await
    }
    Some(ListCommand::Alerters(filters)) => {
      list_resources::<AlerterListItem>(filters, false).await
    }
    Some(ListCommand::Schedules(filters)) => {
      list_schedules(filters).await
    }
  }
}

/// Includes all resources besides builds and alerters.
async fn list_all(list: &args::list::List) -> anyhow::Result<()> {
  let filters: ResourceFilters = list.clone().into();
  let client = super::komodo_client().await?;
  let (
    tags,
    mut servers,
    mut stacks,
    mut deployments,
    mut builds,
    mut repos,
    mut procedures,
    mut actions,
    mut syncs,
  ) = try_join!(
    client.read(ListTags::default()).map(|res| res.map(|res| res
      .into_iter()
      .map(|t| (t.id, t.name))
      .collect::<HashMap<_, _>>())),
    ServerListItem::list(client, &filters, true),
    StackListItem::list(client, &filters, true),
    DeploymentListItem::list(client, &filters, true),
    BuildListItem::list(client, &filters, true),
    RepoListItem::list(client, &filters, true),
    ProcedureListItem::list(client, &filters, true),
    ActionListItem::list(client, &filters, true),
    ResourceSyncListItem::list(client, &filters, true),
  )?;

  if !servers.is_empty() {
    fix_tags(&mut servers, &tags);
    print_items(servers, filters.format, list.links)?;
    println!();
  }

  if !stacks.is_empty() {
    fix_tags(&mut stacks, &tags);
    print_items(stacks, filters.format, list.links)?;
    println!();
  }

  if !deployments.is_empty() {
    fix_tags(&mut deployments, &tags);
    print_items(deployments, filters.format, list.links)?;
    println!();
  }

  if !builds.is_empty() {
    fix_tags(&mut builds, &tags);
    print_items(builds, filters.format, list.links)?;
    println!();
  }

  if !repos.is_empty() {
    fix_tags(&mut repos, &tags);
    print_items(repos, filters.format, list.links)?;
    println!();
  }

  if !procedures.is_empty() {
    fix_tags(&mut procedures, &tags);
    print_items(procedures, filters.format, list.links)?;
    println!();
  }

  if !actions.is_empty() {
    fix_tags(&mut actions, &tags);
    print_items(actions, filters.format, list.links)?;
    println!();
  }

  if !syncs.is_empty() {
    fix_tags(&mut syncs, &tags);
    print_items(syncs, filters.format, list.links)?;
    println!();
  }

  Ok(())
}

async fn list_resources<T>(
  filters: &ResourceFilters,
  minimal: bool,
) -> anyhow::Result<()>
where
  T: ListResources,
  ResourceListItem<T::Info>: PrintTable + Serialize,
{
  let client = crate::command::komodo_client().await?;
  let (mut resources, tags) = tokio::try_join!(
    T::list(client, filters, minimal),
    client.read(ListTags::default()).map(|res| res.map(|res| res
      .into_iter()
      .map(|t| (t.id, t.name))
      .collect::<HashMap<_, _>>()))
  )?;
  fix_tags(&mut resources, &tags);
  if !resources.is_empty() {
    print_items(resources, filters.format, filters.links)?;
  }
  Ok(())
}

async fn list_schedules(
  filters: &ResourceFilters,
) -> anyhow::Result<()> {
  let client = crate::command::komodo_client().await?;
  let (mut schedules, tags) = tokio::try_join!(
    client
      .read(ListSchedules {
        tags: filters.tags.clone(),
        tag_behavior: Default::default(),
      })
      .map(|res| res.map(|res| res
        .into_iter()
        .filter(|s| s.next_scheduled_run.is_some())
        .collect::<Vec<_>>())),
    client.read(ListTags::default()).map(|res| res.map(|res| res
      .into_iter()
      .map(|t| (t.id, t.name))
      .collect::<HashMap<_, _>>()))
  )?;
  schedules.iter_mut().for_each(|resource| {
    resource.tags.iter_mut().for_each(|id| {
      let Some(name) = tags.get(id) else {
        *id = String::new();
        return;
      };
      id.clone_from(name);
    });
  });
  schedules.sort_by(|a, b| {
    match (a.next_scheduled_run, b.next_scheduled_run) {
      (Some(_), None) => return Ordering::Less,
      (None, Some(_)) => return Ordering::Greater,
      (Some(a), Some(b)) => return a.cmp(&b),
      (None, None) => {}
    }
    a.name.cmp(&b.name).then(a.enabled.cmp(&b.enabled))
  });
  if !schedules.is_empty() {
    print_items(schedules, filters.format, filters.links)?;
  }
  Ok(())
}

fn fix_tags<T>(
  resources: &mut [ResourceListItem<T>],
  tags: &HashMap<String, String>,
) {
  resources.iter_mut().for_each(|resource| {
    resource.tags.iter_mut().for_each(|id| {
      let Some(name) = tags.get(id) else {
        *id = String::new();
        return;
      };
      id.clone_from(name);
    });
  });
}

trait ListResources: Sized
where
  ResourceListItem<Self::Info>: PrintTable,
{
  type Info;
  async fn list(
    client: &KomodoClient,
    filters: &ResourceFilters,
    // For use with root `km ls`
    minimal: bool,
  ) -> anyhow::Result<Vec<ResourceListItem<Self::Info>>>;
}

// LIST

impl ListResources for ServerListItem {
  type Info = ServerListItemInfo;
  async fn list(
    client: &KomodoClient,
    filters: &ResourceFilters,
    _minimal: bool,
  ) -> anyhow::Result<Vec<Self>> {
    let servers = client
      .read(ListServers {
        query: ResourceQuery::builder()
          .tags(filters.tags.clone())
          // .tag_behavior(TagQueryBehavior::Any)
          .templates(filters.templates)
          .build(),
      })
      .await?;
    let names = parse_wildcards(&filters.names);
    let server_wildcards = parse_wildcards(&filters.servers);
    let mut servers = servers
      .into_iter()
      .filter(|server| {
        let state_check = if filters.all {
          true
        } else if filters.down {
          !matches!(server.info.state, ServerState::Ok)
        } else if filters.in_progress {
          false
        } else {
          matches!(server.info.state, ServerState::Ok)
        };
        let name_items = &[server.name.as_str()];
        state_check
          && matches_wildcards(&names, name_items)
          && matches_wildcards(&server_wildcards, name_items)
      })
      .collect::<Vec<_>>();
    servers.sort_by(|a, b| {
      a.info.state.cmp(&b.info.state).then(a.name.cmp(&b.name))
    });
    Ok(servers)
  }
}

impl ListResources for StackListItem {
  type Info = StackListItemInfo;
  async fn list(
    client: &KomodoClient,
    filters: &ResourceFilters,
    _minimal: bool,
  ) -> anyhow::Result<Vec<Self>> {
    let (servers, mut stacks) = tokio::try_join!(
      client
        .read(ListServers {
          query: ResourceQuery::builder().build(),
        })
        .map(|res| res.map(|res| res
          .into_iter()
          .map(|s| (s.id.clone(), s))
          .collect::<HashMap<_, _>>())),
      client.read(ListStacks {
        query: ResourceQuery::builder()
          .tags(filters.tags.clone())
          // .tag_behavior(TagQueryBehavior::Any)
          .templates(filters.templates)
          .build(),
      })
    )?;
    stacks.iter_mut().for_each(|stack| {
      if stack.info.server_id.is_empty() {
        return;
      }
      let Some(server) = servers.get(&stack.info.server_id) else {
        return;
      };
      stack.info.server_id.clone_from(&server.name);
    });
    let names = parse_wildcards(&filters.names);
    let servers = parse_wildcards(&filters.servers);
    let mut stacks = stacks
      .into_iter()
      .filter(|stack| {
        let state_check = if filters.all {
          true
        } else if filters.down {
          !matches!(
            stack.info.state,
            StackState::Running | StackState::Deploying
          )
        } else if filters.in_progress {
          matches!(stack.info.state, StackState::Deploying)
        } else {
          matches!(
            stack.info.state,
            StackState::Running | StackState::Deploying
          )
        };
        state_check
          && matches_wildcards(&names, &[stack.name.as_str()])
          && matches_wildcards(
            &servers,
            &[stack.info.server_id.as_str()],
          )
      })
      .collect::<Vec<_>>();
    stacks.sort_by(|a, b| {
      a.info
        .state
        .cmp(&b.info.state)
        .then(a.name.cmp(&b.name))
        .then(a.info.server_id.cmp(&b.info.server_id))
    });
    Ok(stacks)
  }
}

impl ListResources for DeploymentListItem {
  type Info = DeploymentListItemInfo;
  async fn list(
    client: &KomodoClient,
    filters: &ResourceFilters,
    _minimal: bool,
  ) -> anyhow::Result<Vec<Self>> {
    let (servers, mut deployments) = tokio::try_join!(
      client
        .read(ListServers {
          query: ResourceQuery::builder().build(),
        })
        .map(|res| res.map(|res| res
          .into_iter()
          .map(|s| (s.id.clone(), s))
          .collect::<HashMap<_, _>>())),
      client.read(ListDeployments {
        query: ResourceQuery::builder()
          .tags(filters.tags.clone())
          // .tag_behavior(TagQueryBehavior::Any)
          .templates(filters.templates)
          .build(),
      })
    )?;
    deployments.iter_mut().for_each(|deployment| {
      if deployment.info.server_id.is_empty() {
        return;
      }
      let Some(server) = servers.get(&deployment.info.server_id)
      else {
        return;
      };
      deployment.info.server_id.clone_from(&server.name);
    });
    let names = parse_wildcards(&filters.names);
    let servers = parse_wildcards(&filters.servers);
    let mut deployments = deployments
      .into_iter()
      .filter(|deployment| {
        let state_check = if filters.all {
          true
        } else if filters.down {
          !matches!(
            deployment.info.state,
            DeploymentState::Running | DeploymentState::Deploying
          )
        } else if filters.in_progress {
          matches!(deployment.info.state, DeploymentState::Deploying)
        } else {
          matches!(
            deployment.info.state,
            DeploymentState::Running | DeploymentState::Deploying
          )
        };
        state_check
          && matches_wildcards(&names, &[deployment.name.as_str()])
          && matches_wildcards(
            &servers,
            &[deployment.info.server_id.as_str()],
          )
      })
      .collect::<Vec<_>>();
    deployments.sort_by(|a, b| {
      a.info
        .state
        .cmp(&b.info.state)
        .then(a.name.cmp(&b.name))
        .then(a.info.server_id.cmp(&b.info.server_id))
    });
    Ok(deployments)
  }
}

impl ListResources for BuildListItem {
  type Info = BuildListItemInfo;
  async fn list(
    client: &KomodoClient,
    filters: &ResourceFilters,
    minimal: bool,
  ) -> anyhow::Result<Vec<Self>> {
    let (builders, mut builds) = tokio::try_join!(
      client
        .read(ListBuilders {
          query: ResourceQuery::builder().build(),
        })
        .map(|res| res.map(|res| res
          .into_iter()
          .map(|s| (s.id.clone(), s))
          .collect::<HashMap<_, _>>())),
      client.read(ListBuilds {
        query: ResourceQuery::builder()
          .tags(filters.tags.clone())
          // .tag_behavior(TagQueryBehavior::Any)
          .templates(filters.templates)
          .build(),
      })
    )?;
    builds.iter_mut().for_each(|build| {
      if build.info.builder_id.is_empty() {
        return;
      }
      let Some(builder) = builders.get(&build.info.builder_id) else {
        return;
      };
      build.info.builder_id.clone_from(&builder.name);
    });
    let names = parse_wildcards(&filters.names);
    let builders = parse_wildcards(&filters.builders);
    let mut builds = builds
      .into_iter()
      .filter(|build| {
        let state_check = if filters.all {
          true
        } else if filters.down {
          matches!(
            build.info.state,
            BuildState::Failed | BuildState::Unknown
          )
        } else if minimal || filters.in_progress {
          matches!(build.info.state, BuildState::Building)
        } else {
          true
        };
        state_check
          && matches_wildcards(&names, &[build.name.as_str()])
          && matches_wildcards(
            &builders,
            &[build.info.builder_id.as_str()],
          )
      })
      .collect::<Vec<_>>();
    builds.sort_by(|a, b| {
      a.name
        .cmp(&b.name)
        .then(a.info.builder_id.cmp(&b.info.builder_id))
        .then(a.info.state.cmp(&b.info.state))
    });
    Ok(builds)
  }
}

impl ListResources for RepoListItem {
  type Info = RepoListItemInfo;
  async fn list(
    client: &KomodoClient,
    filters: &ResourceFilters,
    minimal: bool,
  ) -> anyhow::Result<Vec<Self>> {
    let names = parse_wildcards(&filters.names);
    let mut repos = client
      .read(ListRepos {
        query: ResourceQuery::builder()
          .tags(filters.tags.clone())
          // .tag_behavior(TagQueryBehavior::Any)
          .templates(filters.templates)
          .build(),
      })
      .await?
      .into_iter()
      .filter(|repo| {
        let state_check = if filters.all {
          true
        } else if filters.down {
          matches!(
            repo.info.state,
            RepoState::Failed | RepoState::Unknown
          )
        } else if minimal || filters.in_progress {
          matches!(
            repo.info.state,
            RepoState::Building | RepoState::Cloning
          )
        } else {
          true
        };
        state_check
          && matches_wildcards(&names, &[repo.name.as_str()])
      })
      .collect::<Vec<_>>();
    repos.sort_by(|a, b| {
      a.name
        .cmp(&b.name)
        .then(a.info.server_id.cmp(&b.info.server_id))
        .then(a.info.builder_id.cmp(&b.info.builder_id))
    });
    Ok(repos)
  }
}

impl ListResources for ProcedureListItem {
  type Info = ProcedureListItemInfo;
  async fn list(
    client: &KomodoClient,
    filters: &ResourceFilters,
    minimal: bool,
  ) -> anyhow::Result<Vec<Self>> {
    let names = parse_wildcards(&filters.names);
    let mut procedures = client
      .read(ListProcedures {
        query: ResourceQuery::builder()
          .tags(filters.tags.clone())
          // .tag_behavior(TagQueryBehavior::Any)
          .templates(filters.templates)
          .build(),
      })
      .await?
      .into_iter()
      .filter(|procedure| {
        let state_check = if filters.all {
          true
        } else if filters.down {
          matches!(
            procedure.info.state,
            ProcedureState::Failed | ProcedureState::Unknown
          )
        } else if minimal || filters.in_progress {
          matches!(procedure.info.state, ProcedureState::Running)
        } else {
          true
        };
        state_check
          && matches_wildcards(&names, &[procedure.name.as_str()])
      })
      .collect::<Vec<_>>();
    procedures.sort_by(|a, b| {
      match (a.info.next_scheduled_run, b.info.next_scheduled_run) {
        (Some(_), None) => return Ordering::Less,
        (None, Some(_)) => return Ordering::Greater,
        (Some(a), Some(b)) => return a.cmp(&b),
        (None, None) => {}
      }
      a.name.cmp(&b.name).then(a.info.state.cmp(&b.info.state))
    });
    Ok(procedures)
  }
}

impl ListResources for ActionListItem {
  type Info = ActionListItemInfo;
  async fn list(
    client: &KomodoClient,
    filters: &ResourceFilters,
    minimal: bool,
  ) -> anyhow::Result<Vec<Self>> {
    let names = parse_wildcards(&filters.names);
    let mut actions = client
      .read(ListActions {
        query: ResourceQuery::builder()
          .tags(filters.tags.clone())
          // .tag_behavior(TagQueryBehavior::Any)
          .templates(filters.templates)
          .build(),
      })
      .await?
      .into_iter()
      .filter(|action| {
        let state_check = if filters.all {
          true
        } else if filters.down {
          matches!(
            action.info.state,
            ActionState::Failed | ActionState::Unknown
          )
        } else if minimal || filters.in_progress {
          matches!(action.info.state, ActionState::Running)
        } else {
          true
        };
        state_check
          && matches_wildcards(&names, &[action.name.as_str()])
      })
      .collect::<Vec<_>>();
    actions.sort_by(|a, b| {
      match (a.info.next_scheduled_run, b.info.next_scheduled_run) {
        (Some(_), None) => return Ordering::Less,
        (None, Some(_)) => return Ordering::Greater,
        (Some(a), Some(b)) => return a.cmp(&b),
        (None, None) => {}
      }
      a.name.cmp(&b.name).then(a.info.state.cmp(&b.info.state))
    });
    Ok(actions)
  }
}

impl ListResources for ResourceSyncListItem {
  type Info = ResourceSyncListItemInfo;
  async fn list(
    client: &KomodoClient,
    filters: &ResourceFilters,
    minimal: bool,
  ) -> anyhow::Result<Vec<Self>> {
    let names = parse_wildcards(&filters.names);
    let mut syncs = client
      .read(ListResourceSyncs {
        query: ResourceQuery::builder()
          .tags(filters.tags.clone())
          // .tag_behavior(TagQueryBehavior::Any)
          .templates(filters.templates)
          .build(),
      })
      .await?
      .into_iter()
      .filter(|sync| {
        let state_check = if filters.all {
          true
        } else if filters.down {
          matches!(
            sync.info.state,
            ResourceSyncState::Failed | ResourceSyncState::Unknown
          )
        } else if minimal || filters.in_progress {
          matches!(
            sync.info.state,
            ResourceSyncState::Syncing | ResourceSyncState::Pending
          )
        } else {
          true
        };
        state_check
          && matches_wildcards(&names, &[sync.name.as_str()])
      })
      .collect::<Vec<_>>();
    syncs.sort_by(|a, b| {
      a.name.cmp(&b.name).then(a.info.state.cmp(&b.info.state))
    });
    Ok(syncs)
  }
}

impl ListResources for BuilderListItem {
  type Info = BuilderListItemInfo;
  async fn list(
    client: &KomodoClient,
    filters: &ResourceFilters,
    minimal: bool,
  ) -> anyhow::Result<Vec<Self>> {
    let names = parse_wildcards(&filters.names);
    let mut builders = client
      .read(ListBuilders {
        query: ResourceQuery::builder()
          .tags(filters.tags.clone())
          // .tag_behavior(TagQueryBehavior::Any)
          .templates(filters.templates)
          .build(),
      })
      .await?
      .into_iter()
      .filter(|builder| {
        (!minimal || filters.all)
          && matches_wildcards(&names, &[builder.name.as_str()])
      })
      .collect::<Vec<_>>();
    builders.sort_by(|a, b| {
      a.name
        .cmp(&b.name)
        .then(a.info.builder_type.cmp(&b.info.builder_type))
    });
    Ok(builders)
  }
}

impl ListResources for AlerterListItem {
  type Info = AlerterListItemInfo;
  async fn list(
    client: &KomodoClient,
    filters: &ResourceFilters,
    minimal: bool,
  ) -> anyhow::Result<Vec<Self>> {
    let names = parse_wildcards(&filters.names);
    let mut syncs = client
      .read(ListAlerters {
        query: ResourceQuery::builder()
          .tags(filters.tags.clone())
          // .tag_behavior(TagQueryBehavior::Any)
          .templates(filters.templates)
          .build(),
      })
      .await?
      .into_iter()
      .filter(|sync| {
        (!minimal || filters.all)
          && matches_wildcards(&names, &[sync.name.as_str()])
      })
      .collect::<Vec<_>>();
    syncs.sort_by(|a, b| {
      a.info
        .enabled
        .cmp(&b.info.enabled)
        .then(a.name.cmp(&b.name))
        .then(a.info.endpoint_type.cmp(&b.info.endpoint_type))
    });
    Ok(syncs)
  }
}

// TABLE

impl PrintTable for ResourceListItem<ServerListItemInfo> {
  fn header(links: bool) -> &'static [&'static str] {
    if links {
      &["Server", "State", "Address", "Tags", "Link"]
    } else {
      &["Server", "State", "Address", "Tags"]
    }
  }
  fn row(self, links: bool) -> Vec<Cell> {
    let color = match self.info.state {
      ServerState::Ok => Color::Green,
      ServerState::NotOk => Color::Red,
      ServerState::Disabled => Color::Blue,
    };
    let mut res = vec![
      Cell::new(self.name).add_attribute(Attribute::Bold),
      Cell::new(self.info.state.to_string())
        .fg(color)
        .add_attribute(Attribute::Bold),
      Cell::new(self.info.address),
      Cell::new(self.tags.join(", ")),
    ];
    if links {
      res.push(Cell::new(resource_link(
        &cli_config().host,
        ResourceTargetVariant::Server,
        &self.id,
      )))
    }
    res
  }
}

impl PrintTable for ResourceListItem<StackListItemInfo> {
  fn header(links: bool) -> &'static [&'static str] {
    if links {
      &["Stack", "State", "Server", "Tags", "Link"]
    } else {
      &["Stack", "State", "Server", "Tags"]
    }
  }
  fn row(self, links: bool) -> Vec<comfy_table::Cell> {
    let color = match self.info.state {
      StackState::Down => Color::Blue,
      StackState::Running => Color::Green,
      StackState::Deploying => Color::DarkYellow,
      StackState::Paused => Color::DarkYellow,
      StackState::Unknown => Color::Magenta,
      _ => Color::Red,
    };
    // let source = if self.info.files_on_host {
    //   "On Host"
    // } else if !self.info.repo.is_empty() {
    //   self.info.repo_link.as_str()
    // } else {
    //   "UI Defined"
    // };
    let mut res = vec![
      Cell::new(self.name).add_attribute(Attribute::Bold),
      Cell::new(self.info.state.to_string())
        .fg(color)
        .add_attribute(Attribute::Bold),
      Cell::new(self.info.server_id),
      // Cell::new(source),
      Cell::new(self.tags.join(", ")),
    ];
    if links {
      res.push(Cell::new(resource_link(
        &cli_config().host,
        ResourceTargetVariant::Stack,
        &self.id,
      )))
    }
    res
  }
}

impl PrintTable for ResourceListItem<DeploymentListItemInfo> {
  fn header(links: bool) -> &'static [&'static str] {
    if links {
      &["Deployment", "State", "Server", "Tags", "Link"]
    } else {
      &["Deployment", "State", "Server", "Tags"]
    }
  }
  fn row(self, links: bool) -> Vec<comfy_table::Cell> {
    let color = match self.info.state {
      DeploymentState::NotDeployed => Color::Blue,
      DeploymentState::Running => Color::Green,
      DeploymentState::Deploying => Color::DarkYellow,
      DeploymentState::Paused => Color::DarkYellow,
      DeploymentState::Unknown => Color::Magenta,
      _ => Color::Red,
    };
    let mut res = vec![
      Cell::new(self.name).add_attribute(Attribute::Bold),
      Cell::new(self.info.state.to_string())
        .fg(color)
        .add_attribute(Attribute::Bold),
      Cell::new(self.info.server_id),
      Cell::new(self.tags.join(", ")),
    ];
    if links {
      res.push(Cell::new(resource_link(
        &cli_config().host,
        ResourceTargetVariant::Deployment,
        &self.id,
      )))
    }
    res
  }
}

impl PrintTable for ResourceListItem<BuildListItemInfo> {
  fn header(links: bool) -> &'static [&'static str] {
    if links {
      &["Build", "State", "Builder", "Tags", "Link"]
    } else {
      &["Build", "State", "Builder", "Tags"]
    }
  }
  fn row(self, links: bool) -> Vec<comfy_table::Cell> {
    let color = match self.info.state {
      BuildState::Ok => Color::Green,
      BuildState::Building => Color::DarkYellow,
      BuildState::Unknown => Color::Magenta,
      BuildState::Failed => Color::Red,
    };
    let mut res = vec![
      Cell::new(self.name).add_attribute(Attribute::Bold),
      Cell::new(self.info.state.to_string())
        .fg(color)
        .add_attribute(Attribute::Bold),
      Cell::new(self.info.builder_id),
      Cell::new(self.tags.join(", ")),
    ];
    if links {
      res.push(Cell::new(resource_link(
        &cli_config().host,
        ResourceTargetVariant::Build,
        &self.id,
      )));
    }
    res
  }
}

impl PrintTable for ResourceListItem<RepoListItemInfo> {
  fn header(links: bool) -> &'static [&'static str] {
    if links {
      &["Repo", "State", "Link", "Tags", "Link"]
    } else {
      &["Repo", "State", "Link", "Tags"]
    }
  }
  fn row(self, links: bool) -> Vec<comfy_table::Cell> {
    let color = match self.info.state {
      RepoState::Ok => Color::Green,
      RepoState::Building
      | RepoState::Cloning
      | RepoState::Pulling => Color::DarkYellow,
      RepoState::Unknown => Color::Magenta,
      RepoState::Failed => Color::Red,
    };
    let mut res = vec![
      Cell::new(self.name).add_attribute(Attribute::Bold),
      Cell::new(self.info.state.to_string())
        .fg(color)
        .add_attribute(Attribute::Bold),
      Cell::new(self.info.repo_link),
      Cell::new(self.tags.join(", ")),
    ];
    if links {
      res.push(Cell::new(resource_link(
        &cli_config().host,
        ResourceTargetVariant::Repo,
        &self.id,
      )))
    }
    res
  }
}

impl PrintTable for ResourceListItem<ProcedureListItemInfo> {
  fn header(links: bool) -> &'static [&'static str] {
    if links {
      &["Procedure", "State", "Next Run", "Tags", "Link"]
    } else {
      &["Procedure", "State", "Next Run", "Tags"]
    }
  }
  fn row(self, links: bool) -> Vec<comfy_table::Cell> {
    let color = match self.info.state {
      ProcedureState::Ok => Color::Green,
      ProcedureState::Running => Color::DarkYellow,
      ProcedureState::Unknown => Color::Magenta,
      ProcedureState::Failed => Color::Red,
    };
    let next_run = if let Some(ts) = self.info.next_scheduled_run {
      Cell::new(
        format_timetamp(ts)
          .unwrap_or(String::from("Invalid next ts")),
      )
      .add_attribute(Attribute::Bold)
    } else {
      Cell::new(String::from("None"))
    };
    let mut res = vec![
      Cell::new(self.name).add_attribute(Attribute::Bold),
      Cell::new(self.info.state.to_string())
        .fg(color)
        .add_attribute(Attribute::Bold),
      next_run,
      Cell::new(self.tags.join(", ")),
    ];
    if links {
      res.push(Cell::new(resource_link(
        &cli_config().host,
        ResourceTargetVariant::Procedure,
        &self.id,
      )))
    }
    res
  }
}

impl PrintTable for ResourceListItem<ActionListItemInfo> {
  fn header(links: bool) -> &'static [&'static str] {
    if links {
      &["Action", "State", "Next Run", "Tags", "Link"]
    } else {
      &["Action", "State", "Next Run", "Tags"]
    }
  }
  fn row(self, links: bool) -> Vec<comfy_table::Cell> {
    let color = match self.info.state {
      ActionState::Ok => Color::Green,
      ActionState::Running => Color::DarkYellow,
      ActionState::Unknown => Color::Magenta,
      ActionState::Failed => Color::Red,
    };
    let next_run = if let Some(ts) = self.info.next_scheduled_run {
      Cell::new(
        format_timetamp(ts)
          .unwrap_or(String::from("Invalid next ts")),
      )
      .add_attribute(Attribute::Bold)
    } else {
      Cell::new(String::from("None"))
    };
    let mut res = vec![
      Cell::new(self.name).add_attribute(Attribute::Bold),
      Cell::new(self.info.state.to_string())
        .fg(color)
        .add_attribute(Attribute::Bold),
      next_run,
      Cell::new(self.tags.join(", ")),
    ];
    if links {
      res.push(Cell::new(resource_link(
        &cli_config().host,
        ResourceTargetVariant::Action,
        &self.id,
      )));
    }
    res
  }
}

impl PrintTable for ResourceListItem<ResourceSyncListItemInfo> {
  fn header(links: bool) -> &'static [&'static str] {
    if links {
      &["Sync", "State", "Tags", "Link"]
    } else {
      &["Sync", "State", "Tags"]
    }
  }
  fn row(self, links: bool) -> Vec<comfy_table::Cell> {
    let color = match self.info.state {
      ResourceSyncState::Ok => Color::Green,
      ResourceSyncState::Pending | ResourceSyncState::Syncing => {
        Color::DarkYellow
      }
      ResourceSyncState::Unknown => Color::Magenta,
      ResourceSyncState::Failed => Color::Red,
    };
    let mut res = vec![
      Cell::new(self.name).add_attribute(Attribute::Bold),
      Cell::new(self.info.state.to_string())
        .fg(color)
        .add_attribute(Attribute::Bold),
      Cell::new(self.tags.join(", ")),
    ];
    if links {
      res.push(Cell::new(resource_link(
        &cli_config().host,
        ResourceTargetVariant::ResourceSync,
        &self.id,
      )))
    }
    res
  }
}

impl PrintTable for ResourceListItem<BuilderListItemInfo> {
  fn header(links: bool) -> &'static [&'static str] {
    if links {
      &["Builder", "Type", "Tags", "Link"]
    } else {
      &["Builder", "Type", "Tags"]
    }
  }
  fn row(self, links: bool) -> Vec<comfy_table::Cell> {
    let mut res = vec![
      Cell::new(self.name).add_attribute(Attribute::Bold),
      Cell::new(self.info.builder_type),
      Cell::new(self.tags.join(", ")),
    ];
    if links {
      res.push(Cell::new(resource_link(
        &cli_config().host,
        ResourceTargetVariant::Builder,
        &self.id,
      )));
    }
    res
  }
}

impl PrintTable for ResourceListItem<AlerterListItemInfo> {
  fn header(links: bool) -> &'static [&'static str] {
    if links {
      &["Alerter", "Type", "Enabled", "Tags", "Link"]
    } else {
      &["Alerter", "Type", "Enabled", "Tags"]
    }
  }
  fn row(self, links: bool) -> Vec<comfy_table::Cell> {
    let mut row = vec![
      Cell::new(self.name).add_attribute(Attribute::Bold),
      Cell::new(self.info.endpoint_type),
      if self.info.enabled {
        Cell::new(self.info.enabled.to_string()).fg(Color::Green)
      } else {
        Cell::new(self.info.enabled.to_string()).fg(Color::Red)
      },
      Cell::new(self.tags.join(", ")),
    ];
    if links {
      row.push(Cell::new(resource_link(
        &cli_config().host,
        ResourceTargetVariant::Alerter,
        &self.id,
      )));
    }
    row
  }
}

impl PrintTable for Schedule {
  fn header(links: bool) -> &'static [&'static str] {
    if links {
      &["Name", "Type", "Next Run", "Tags", "Link"]
    } else {
      &["Name", "Type", "Next Run", "Tags"]
    }
  }
  fn row(self, links: bool) -> Vec<comfy_table::Cell> {
    let next_run = if let Some(ts) = self.next_scheduled_run {
      Cell::new(
        format_timetamp(ts)
          .unwrap_or(String::from("Invalid next ts")),
      )
      .add_attribute(Attribute::Bold)
    } else {
      Cell::new(String::from("None"))
    };
    let (resource_type, id) = self.target.extract_variant_id();
    let mut res = vec![
      Cell::new(self.name).add_attribute(Attribute::Bold),
      Cell::new(self.target.extract_variant_id().0),
      next_run,
      Cell::new(self.tags.join(", ")),
    ];
    if links {
      res.push(Cell::new(resource_link(
        &cli_config().host,
        resource_type,
        id,
      )));
    }
    res
  }
}


================================================
FILE: bin/cli/src/command/mod.rs
================================================
use std::io::Read;

use anyhow::{Context, anyhow};
use chrono::TimeZone;
use colored::Colorize;
use comfy_table::{Attribute, Cell, Table};
use komodo_client::{
  KomodoClient,
  entities::config::cli::{CliTableBorders, args::CliFormat},
};
use serde::Serialize;
use tokio::sync::OnceCell;
use wildcard::Wildcard;

use crate::config::cli_config;

pub mod container;
pub mod database;
pub mod execute;
pub mod list;
pub mod update;

async fn komodo_client() -> anyhow::Result<&'static KomodoClient> {
  static KOMODO_CLIENT: OnceCell<KomodoClient> =
    OnceCell::const_new();
  KOMODO_CLIENT
    .get_or_try_init(|| async {
      let config = cli_config();
      let (Some(key), Some(secret)) =
        (&config.cli_key, &config.cli_secret)
      else {
        return Err(anyhow!(
          "Must provide both cli_key and cli_secret"
        ));
      };
      KomodoClient::new(&config.host, key, secret)
        .with_healthcheck()
        .await
    })
    .await
}

fn wait_for_enter(
  press_enter_to: &str,
  skip: bool,
) -> anyhow::Result<()> {
  if skip {
    println!();
    return Ok(());
  }
  println!(
    "\nPress {} to {}\n",
    "ENTER".green(),
    press_enter_to.bold()
  );
  let buffer = &mut [0u8];
  std::io::stdin()
    .read_exact(buffer)
    .context("failed to read ENTER")?;
  Ok(())
}

/// Sanitizes uris of the form:
/// `protocol://username:password@address`
fn sanitize_uri(uri: &str) -> String {
  // protocol: `mongodb`
  // credentials_address: `username:password@address`
  let Some((protocol, credentials_address)) = uri.split_once("://")
  else {
    // If no protocol, return as-is
    return uri.to_string();
  };

  // credentials: `username:password`
  let Some((credentials, address)) =
    credentials_address.split_once('@')
  else {
    // If no credentials, return as-is
    return uri.to_string();
  };

  match credentials.split_once(':') {
    Some((username, _)) => {
      format!("{protocol}://{username}:*****@{address}")
    }
    None => {
      format!("{protocol}://*****@{address}")
    }
  }
}

fn print_items<T: PrintTable + Serialize>(
  items: Vec<T>,
  format: CliFormat,
  links: bool,
) -> anyhow::Result<()> {
  match format {
    CliFormat::Table => {
      let mut table = Table::new();
      let preset = {
        use comfy_table::presets::*;
        match cli_config().table_borders {
          None | Some(CliTableBorders::Horizontal) => {
            UTF8_HORIZONTAL_ONLY
          }
          Some(CliTableBorders::Vertical) => UTF8_FULL_CONDENSED,
          Some(CliTableBorders::Inside) => UTF8_NO_BORDERS,
          Some(CliTableBorders::Outside) => UTF8_BORDERS_ONLY,
          Some(CliTableBorders::All) => UTF8_FULL,
        }
      };
      table.load_preset(preset).set_header(
        T::header(links)
          .iter()
          .map(|h| Cell::new(h).add_attribute(Attribute::Bold)),
      );
      for item in items {
        table.add_row(item.row(links));
      }
      println!("{table}");
    }
    CliFormat::Json => {
      println!(
        "{}",
        serde_json::to_string_pretty(&items)
          .context("Failed to serialize items to JSON")?
      );
    }
  }
  Ok(())
}

trait PrintTable {
  fn header(links: bool) -> &'static [&'static str];
  fn row(self, links: bool) -> Vec<Cell>;
}

fn parse_wildcards(items: &[String]) -> Vec<Wildcard<'_>> {
  items
    .iter()
    .flat_map(|i| {
      Wildcard::new(i.as_bytes()).inspect_err(|e| {
        warn!("Failed to parse wildcard: {i} | {e:?}")
      })
    })
    .collect::<Vec<_>>()
}

fn matches_wildcards(
  wildcards: &[Wildcard<'_>],
  items: &[&str],
) -> bool {
  if wildcards.is_empty() {
    return true;
  }
  items.iter().any(|item| {
    wildcards.iter().any(|wc| wc.is_match(item.as_bytes()))
  })
}

fn format_timetamp(ts: i64) -> anyhow::Result<String> {
  let ts = chrono::Local
    .timestamp_millis_opt(ts)
    .single()
    .context("Invalid ts")?
    .format("%m/%d %H:%M:%S")
    .to_string();
  Ok(ts)
}

fn clamp_sha(maybe_sha: &str) -> String {
  if maybe_sha.starts_with("sha256:") {
    maybe_sha[0..20].to_string() + "..."
  } else {
    maybe_sha.to_string()
  }
}

// fn text_link(link: &str, text: &str) -> String {
//   format!("\x1b]8;;{link}\x07{text}\x1b]8;;\x07")
// }


================================================
FILE: bin/cli/src/command/update/mod.rs
================================================
use komodo_client::entities::{
  build::PartialBuildConfig,
  config::cli::args::update::UpdateCommand,
  deployment::PartialDeploymentConfig, repo::PartialRepoConfig,
  server::PartialServerConfig, stack::PartialStackConfig,
  sync::PartialResourceSyncConfig,
};

mod resource;
mod user;
mod variable;

pub async fn handle(command: &UpdateCommand) -> anyhow::Result<()> {
  match command {
    UpdateCommand::Build(update) => {
      resource::update::<PartialBuildConfig>(update).await
    }
    UpdateCommand::Deployment(update) => {
      resource::update::<PartialDeploymentConfig>(update).await
    }
    UpdateCommand::Repo(update) => {
      resource::update::<PartialRepoConfig>(update).await
    }
    UpdateCommand::Server(update) => {
      resource::update::<PartialServerConfig>(update).await
    }
    UpdateCommand::Stack(update) => {
      resource::update::<PartialStackConfig>(update).await
    }
    UpdateCommand::Sync(update) => {
      resource::update::<PartialResourceSyncConfig>(update).await
    }
    UpdateCommand::Variable {
      name,
      value,
      secret,
      yes,
    } => variable::update(name, value, *secret, *yes).await,
    UpdateCommand::User { username, command } => {
      user::update(username, command).await
    }
  }
}


================================================
FILE: bin/cli/src/command/update/resource.rs
================================================
use anyhow::Context;
use colored::Colorize;
use komodo_client::{
  api::write::{
    UpdateBuild, UpdateDeployment, UpdateRepo, UpdateResourceSync,
    UpdateServer, UpdateStack,
  },
  entities::{
    build::PartialBuildConfig,
    config::cli::args::update::UpdateResource,
    deployment::PartialDeploymentConfig, repo::PartialRepoConfig,
    server::PartialServerConfig, stack::PartialStackConfig,
    sync::PartialResourceSyncConfig,
  },
};
use serde::{Serialize, de::DeserializeOwned};

pub async fn update<
  T: std::fmt::Debug + Serialize + DeserializeOwned + ResourceUpdate,
>(
  UpdateResource {
    resource,
    update,
    yes,
  }: &UpdateResource,
) -> anyhow::Result<()> {
  println!("\n{}: Update {}\n", "Mode".dimmed(), T::resource_type());
  println!(" - {}: {resource}", "Name".dimmed());

  let config = serde_qs::from_str::<T>(update)
    .context("Failed to deserialize config")?;

  match serde_json::to_string_pretty(&config) {
    Ok(config) => {
      println!(" - {}: {config}", "Update".dimmed());
    }
    Err(_) => {
      println!(" - {}: {config:#?}", "Update".dimmed());
    }
  }

  crate::command::wait_for_enter("update resource", *yes)?;

  config.apply(resource).await
}

pub trait ResourceUpdate {
  fn resource_type() -> &'static str;
  async fn apply(self, resource: &str) -> anyhow::Result<()>;
}

impl ResourceUpdate for PartialBuildConfig {
  fn resource_type() -> &'static str {
    "Build"
  }
  async fn apply(self, resource: &str) -> anyhow::Result<()> {
    let client = crate::command::komodo_client().await?;
    client
      .write(UpdateBuild {
        id: resource.to_string(),
        config: self,
      })
      .await
      .context("Failed to update build config")?;
    Ok(())
  }
}

impl ResourceUpdate for PartialDeploymentConfig {
  fn resource_type() -> &'static str {
    "Deployment"
  }
  async fn apply(self, resource: &str) -> anyhow::Result<()> {
    let client = crate::command::komodo_client().await?;
    client
      .write(UpdateDeployment {
        id: resource.to_string(),
        config: self,
      })
      .await
      .context("Failed to update deployment config")?;
    Ok(())
  }
}

impl ResourceUpdate for PartialRepoConfig {
  fn resource_type() -> &'static str {
    "Repo"
  }
  async fn apply(self, resource: &str) -> anyhow::Result<()> {
    let client = crate::command::komodo_client().await?;
    client
      .write(UpdateRepo {
        id: resource.to_string(),
        config: self,
      })
      .await
      .context("Failed to update repo config")?;
    Ok(())
  }
}

impl ResourceUpdate for PartialServerConfig {
  fn resource_type() -> &'static str {
    "Server"
  }
  async fn apply(self, resource: &str) -> anyhow::Result<()> {
    let client = crate::command::komodo_client().await?;
    client
      .write(UpdateServer {
        id: resource.to_string(),
        config: self,
      })
      .await
      .context("Failed to update server config")?;
    Ok(())
  }
}

impl ResourceUpdate for PartialStackConfig {
  fn resource_type() -> &'static str {
    "Stack"
  }
  async fn apply(self, resource: &str) -> anyhow::Result<()> {
    let client = crate::command::komodo_client().await?;
    client
      .write(UpdateStack {
        id: resource.to_string(),
        config: self,
      })
      .await
      .context("Failed to update stack config")?;
    Ok(())
  }
}

impl ResourceUpdate for PartialResourceSyncConfig {
  fn resource_type() -> &'static str {
    "Sync"
  }
  async fn apply(self, resource: &str) -> anyhow::Result<()> {
    let client = crate::command::komodo_client().await?;
    client
      .write(UpdateResourceSync {
        id: resource.to_string(),
        config: self,
      })
      .await
      .context("Failed to update sync config")?;
    Ok(())
  }
}


================================================
FILE: bin/cli/src/command/update/user.rs
================================================
use anyhow::Context;
use colored::Colorize;
use database::mungos::mongodb::bson::doc;
use komodo_client::entities::{
  config::{
    cli::args::{CliEnabled, update::UpdateUserCommand},
    empty_or_redacted,
  },
  optional_string,
};

use crate::{command::sanitize_uri, config::cli_config};

pub async fn update(
  username: &str,
  command: &UpdateUserCommand,
) -> anyhow::Result<()> {
  match command {
    UpdateUserCommand::Password {
      password,
      unsanitized,
      yes,
    } => {
      update_password(username, password, *unsanitized, *yes).await
    }
    UpdateUserCommand::SuperAdmin { enabled, yes } => {
      update_super_admin(username, *enabled, *yes).await
    }
  }
}

async fn update_password(
  username: &str,
  password: &str,
  unsanitized: bool,
  yes: bool,
) -> anyhow::Result<()> {
  println!("\n{}: Update Password\n", "Mode".dimmed());
  println!(" - {}: {username}", "Username".dimmed());
  if unsanitized {
    println!(" - {}: {password}", "Password".dimmed());
  } else {
    println!(
      " - {}: {}",
      "Password".dimmed(),
      empty_or_redacted(password)
    );
  }

  crate::command::wait_for_enter("update password", yes)?;

  info!("Updating password...");

  let db = database::Client::new(&cli_config().database).await?;

  let user = db
    .users
    .find_one(doc! { "username": username })
    .await
    .context("Failed to query database for user")?
    .context("No user found with given username")?;

  db.set_user_password(&user, password).await?;

  info!("Password updated ✅");

  Ok(())
}

async fn update_super_admin(
  username: &str,
  super_admin: CliEnabled,
  yes: bool,
) -> anyhow::Result<()> {
  let config = cli_config();

  println!("\n{}: Update Super Admin\n", "Mode".dimmed());
  println!(" - {}: {username}", "Username".dimmed());
  println!(" - {}: {super_admin}\n", "Super Admin".dimmed());

  if let Some(uri) = optional_string(&config.database.uri) {
    println!("{}: {}", " - Source URI".dimmed(), sanitize_uri(&uri));
  }
  if let Some(address) = optional_string(&config.database.address) {
    println!("{}: {address}", " - Source Address".dimmed());
  }
  if let Some(username) = optional_string(&config.database.username) {
    println!("{}: {username}", " - Source Username".dimmed());
  }
  println!(
    "{}: {}",
    " - Source Db Name".dimmed(),
    config.database.db_name,
  );

  crate::command::wait_for_enter("update super admin", yes)?;

  info!("Updating super admin...");

  let db = database::Client::new(&config.database).await?;

  // Make sure the user exists first before saying it is successful.
  let user = db
    .users
    .find_one(doc! { "username": username })
    .await
    .context("Failed to query database for user")?
    .context("No user found with given username")?;

  let super_admin: bool = super_admin.into();
  db.users
    .update_one(
      doc! { "username": user.username },
      doc! { "$set": { "super_admin": super_admin } },
    )
    .await
    .context("Failed to update user super admin on db")?;

  info!("Super admin updated ✅");

  Ok(())
}


================================================
FILE: bin/cli/src/command/update/variable.rs
================================================
use anyhow::Context;
use colored::Colorize;
use komodo_client::api::{
  read::GetVariable,
  write::{
    CreateVariable, UpdateVariableIsSecret, UpdateVariableValue,
  },
};

pub async fn update(
  name: &str,
  value: &str,
  secret: Option<bool>,
  yes: bool,
) -> anyhow::Result<()> {
  println!("\n{}: Update Variable\n", "Mode".dimmed());
  println!(" - {}:  {name}", "Name".dimmed());
  println!(" - {}: {value}", "Value".dimmed());
  if let Some(secret) = secret {
    println!(" - {}: {secret}", "Is Secret".dimmed());
  }

  crate::command::wait_for_enter("update variable", yes)?;

  let client = crate::command::komodo_client().await?;

  let Ok(existing) = client
    .read(GetVariable {
      name: name.to_string(),
    })
    .await
  else {
    // Create the variable
    client
      .write(CreateVariable {
        name: name.to_string(),
        value: value.to_string(),
        is_secret: secret.unwrap_or_default(),
        description: Default::default(),
      })
      .await
      .context("Failed to create variable")?;
    info!("Variable created ✅");
    return Ok(());
  };

  client
    .write(UpdateVariableValue {
      name: name.to_string(),
      value: value.to_string(),
    })
    .await
    .context("Failed to update variable 'value'")?;
  info!("Variable 'value' updated ✅");

  let Some(secret) = secret else { return Ok(()) };

  if secret != existing.is_secret {
    client
      .write(UpdateVariableIsSecret {
        name: name.to_string(),
        is_secret: secret,
      })
      .await
      .context("Failed to update variable 'is_secret'")?;
    info!("Variable 'is_secret' updated to {secret} ✅");
  }

  Ok(())
}


================================================
FILE: bin/cli/src/config.rs
================================================
use std::{path::PathBuf, sync::OnceLock};

use anyhow::Context;
use clap::Parser;
use colored::Colorize;
use environment_file::maybe_read_item_from_file;
use komodo_client::entities::{
  config::{
    DatabaseConfig,
    cli::{
      CliConfig, Env,
      args::{CliArgs, Command, Execute, database::DatabaseCommand},
    },
  },
  logger::LogConfig,
};

pub fn cli_args() -> &'static CliArgs {
  static CLI_ARGS: OnceLock<CliArgs> = OnceLock::new();
  CLI_ARGS.get_or_init(CliArgs::parse)
}

pub fn cli_env() -> &'static Env {
  static CLI_ARGS: OnceLock<Env> = OnceLock::new();
  CLI_ARGS.get_or_init(|| {
    match envy::from_env()
      .context("Failed to parse Komodo CLI environment")
    {
      Ok(env) => env,
      Err(e) => {
        panic!("{e:?}");
      }
    }
  })
}

pub fn cli_config() -> &'static CliConfig {
  static CLI_CONFIG: OnceLock<CliConfig> = OnceLock::new();
  CLI_CONFIG.get_or_init(|| {
    let args = cli_args();
    let env = cli_env().clone();
    let config_paths = args
      .config_path
      .clone()
      .unwrap_or(env.komodo_cli_config_paths);
    let debug_startup =
      args.debug_startup.unwrap_or(env.komodo_cli_debug_startup);

    if debug_startup {
      println!(
        "{}: Komodo CLI version: {}",
        "DEBUG".cyan(),
        env!("CARGO_PKG_VERSION").blue().bold()
      );
      println!(
        "{}: {}: {config_paths:?}",
        "DEBUG".cyan(),
        "Config Paths".dimmed(),
      );
    }

    let config_keywords = args
      .config_keyword
      .clone()
      .unwrap_or(env.komodo_cli_config_keywords);
    let config_keywords = config_keywords
      .iter()
      .map(String::as_str)
      .collect::<Vec<_>>();
    if debug_startup {
      println!(
        "{}: {}: {config_keywords:?}",
        "DEBUG".cyan(),
        "Config File Keywords".dimmed(),
      );
    }
    let mut unparsed_config = (config::ConfigLoader {
      paths: &config_paths
        .iter()
        .map(PathBuf::as_path)
        .collect::<Vec<_>>(),
      match_wildcards: &config_keywords,
      include_file_name: ".kminclude",
      merge_nested: env.komodo_cli_merge_nested_config,
      extend_array: env.komodo_cli_extend_config_arrays,
      debug_print: debug_startup,
    })
    .load::<serde_json::Map<String, serde_json::Value>>()
    .expect("failed at parsing config from paths");
    let init_parsed_config = serde_json::from_value::<CliConfig>(
      serde_json::Value::Object(unparsed_config.clone()),
    )
    .context("Failed to parse config")
    .unwrap();

    let (host, key, secret) = match &args.command {
      Command::Execute(Execute {
        host, key, secret, ..
      }) => (host.clone(), key.clone(), secret.clone()),
      _ => (None, None, None),
    };

    let backups_folder = match &args.command {
      Command::Database {
        command: DatabaseCommand::Backup { backups_folder, .. },
      } => backups_folder.clone(),
      Command::Database {
        command: DatabaseCommand::Restore { backups_folder, .. },
      } => backups_folder.clone(),
      _ => None,
    };
    let (uri, address, username, password, db_name) =
      match &args.command {
        Command::Database {
          command:
            DatabaseCommand::Copy {
              uri,
              address,
              username,
              password,
              db_name,
              ..
            },
        } => (
          uri.clone(),
          address.clone(),
          username.clone(),
          password.clone(),
          db_name.clone(),
        ),
        _ => (None, None, None, None, None),
      };

    let profile = args
      .profile
      .as_ref()
      .or(init_parsed_config.default_profile.as_ref());

    let unparsed_config = if let Some(profile) = profile
      && !profile.is_empty()
    {
      // Find the profile config,
      // then merge it with the Default config.
      let serde_json::Value::Array(profiles) = unparsed_config
        .remove("profile")
        .context("Config has no profiles, but a profile is required")
        .unwrap()
      else {
        panic!("`config.profile` is not array");
      };
      let Some(profile_config) = profiles.into_iter().find(|p| {
        let Ok(parsed) =
          serde_json::from_value::<CliConfig>(p.clone())
        else {
          return false;
        };
        &parsed.config_profile == profile
          || parsed
            .config_aliases
            .iter()
            .any(|alias| alias == profile)
      }) else {
        panic!("No profile matching '{profile}' was found.");
      };
      let serde_json::Value::Object(profile_config) = profile_config
      else {
        panic!("Profile config is not Object type.");
      };
      config::merge_config(
        unparsed_config,
        profile_config.clone(),
        env.komodo_cli_merge_nested_config,
        env.komodo_cli_extend_config_arrays,
      )
      .unwrap_or(profile_config)
    } else {
      unparsed_config
    };
    let config = serde_json::from_value::<CliConfig>(
      serde_json::Value::Object(unparsed_config),
    )
    .context("Failed to parse final config")
    .unwrap();
    let config_profile = if config.config_profile.is_empty() {
      String::from("None")
    } else {
      config.config_profile
    };

    CliConfig {
      config_profile,
      config_aliases: config.config_aliases,
      default_profile: config.default_profile,
      table_borders: env
        .komodo_cli_table_borders
        .or(config.table_borders),
      host: host
        .or(env.komodo_cli_host)
        .or(env.komodo_host)
        .unwrap_or(config.host),
      cli_key: key.or(env.komodo_cli_key).or(config.cli_key),
      cli_secret: secret
        .or(env.komodo_cli_secret)
        .or(config.cli_secret),
      backups_folder: backups_folder
        .or(env.komodo_cli_backups_folder)
        .unwrap_or(config.backups_folder),
      max_backups: env
        .komodo_cli_max_backups
        .unwrap_or(config.max_backups),
      database_target: DatabaseConfig {
        uri: uri
          .or(env.komodo_cli_database_target_uri)
          .unwrap_or(config.database_target.uri),
        address: address
          .or(env.komodo_cli_database_target_address)
          .unwrap_or(config.database_target.address),
        username: username
          .or(env.komodo_cli_database_target_username)
          .unwrap_or(config.database_target.username),
        password: password
          .or(env.komodo_cli_database_target_password)
          .unwrap_or(config.database_target.password),
        db_name: db_name
          .or(env.komodo_cli_database_target_db_name)
          .unwrap_or(config.database_target.db_name),
        app_name: config.database_target.app_name,
      },
      database: DatabaseConfig {
        uri: maybe_read_item_from_file(
          env.komodo_database_uri_file,
          env.komodo_database_uri,
        )
        .unwrap_or(config.database.uri),
        address: env
          .komodo_database_address
          .unwrap_or(config.database.address),
        username: maybe_read_item_from_file(
          env.komodo_database_username_file,
          env.komodo_database_username,
        )
        .unwrap_or(config.database.username),
        password: maybe_read_item_from_file(
          env.komodo_database_password_file,
          env.komodo_database_password,
        )
        .unwrap_or(config.database.password),
        db_name: env
          .komodo_database_db_name
          .unwrap_or(config.database.db_name),
        app_name: config.database.app_name,
      },
      cli_logging: LogConfig {
        level: env
          .komodo_cli_logging_level
          .unwrap_or(config.cli_logging.level),
        stdio: env
          .komodo_cli_logging_stdio
          .unwrap_or(config.cli_logging.stdio),
        pretty: env
          .komodo_cli_logging_pretty
          .unwrap_or(config.cli_logging.pretty),
        location: false,
        otlp_endpoint: env
          .komodo_cli_logging_otlp_endpoint
          .unwrap_or(config.cli_logging.otlp_endpoint),
        opentelemetry_service_name: env
          .komodo_cli_logging_opentelemetry_service_name
          .unwrap_or(config.cli_logging.opentelemetry_service_name),
      },
      profile: config.profile,
    }
  })
}


================================================
FILE: bin/cli/src/main.rs
================================================
#[macro_use]
extern crate tracing;

use anyhow::Context;
use komodo_client::entities::config::cli::args;

use crate::config::cli_config;

mod command;
mod config;

async fn app() -> anyhow::Result<()> {
  dotenvy::dotenv().ok();
  logger::init(&config::cli_config().cli_logging)?;
  let args = config::cli_args();
  let env = config::cli_env();
  let debug_load =
    args.debug_startup.unwrap_or(env.komodo_cli_debug_startup);

  match &args.command {
    args::Command::Config {
      all_profiles,
      unsanitized,
    } => {
      let mut config = if *unsanitized {
        cli_config().clone()
      } else {
        cli_config().sanitized()
      };
      if !*all_profiles {
        config.profile = Default::default();
      }
      if debug_load {
        println!("\n{config:#?}");
      } else {
        println!(
          "\nCLI Config {}",
          serde_json::to_string_pretty(&config)
            .context("Failed to serialize config for pretty print")?
        );
      }
      Ok(())
    }
    args::Command::Container(container) => {
      command::container::handle(container).await
    }
    args::Command::Inspect(inspect) => {
      command::container::inspect_container(inspect).await
    }
    args::Command::List(list) => command::list::handle(list).await,
    args::Command::Execute(args) => {
      command::execute::handle(&args.execution, args.yes).await
    }
    args::Command::Update { command } => {
      command::update::handle(command).await
    }
    args::Command::Database { command } => {
      command::database::handle(command).await
    }
  }
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
  let mut term_signal = tokio::signal::unix::signal(
    tokio::signal::unix::SignalKind::terminate(),
  )?;
  tokio::select! {
    res = tokio::spawn(app()) => res?,
    _ = term_signal.recv() => Ok(()),
  }
}


================================================
FILE: bin/core/Cargo.toml
================================================
[package]
name = "komodo_core"
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true

[[bin]]
name = "core"
path = "src/main.rs"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
# local
komodo_client = { workspace = true, features = ["mongo"] }
periphery_client.workspace = true
environment_file.workspace = true
interpolate.workspace = true
formatting.workspace = true
database.workspace = true
response.workspace = true
command.workspace = true
config.workspace = true
logger.workspace = true
cache.workspace = true
git.workspace = true
# mogh
serror = { workspace = true, features = ["axum"] }
async_timing_util.workspace = true
partial_derive2.workspace = true
derive_variants.workspace = true
resolver_api.workspace = true
toml_pretty.workspace = true
slack.workspace = true
svi.workspace = true
# external
aws-credential-types.workspace = true
tokio-tungstenite.workspace = true
english-to-cron.workspace = true
openidconnect.workspace = true
jsonwebtoken.workspace = true
axum-server.workspace = true
urlencoding.workspace = true
aws-sdk-ec2.workspace = true
aws-config.workspace = true
tokio-util.workspace = true
axum-extra.workspace = true
tower-http.workspace = true
serde_json.workspace = true
serde_yaml_ng.workspace = true
typeshare.workspace = true
chrono-tz.workspace = true
indexmap.workspace = true
octorust.workspace = true
wildcard.workspace = true
arc-swap.workspace = true
colored.workspace = true
dashmap.workspace = true
tracing.workspace = true
reqwest.workspace = true
futures.workspace = true
nom_pem.workspace = true
dotenvy.workspace = true
anyhow.workspace = true
croner.workspace = true
chrono.workspace = true
bcrypt.workspace = true
base64.workspace = true
rustls.workspace = true
tokio.workspace = true
serde.workspace = true
regex.workspace = true
axum.workspace = true
toml.workspace = true
uuid.workspace = true
envy.workspace = true
rand.workspace = true
hmac.workspace = true
sha2.workspace = true
hex.workspace = true


================================================
FILE: bin/core/aio.Dockerfile
================================================
## All in one, multi stage compile + runtime Docker build for your architecture.

# Build Core
FROM rust:1.89.0-bullseye AS core-builder
RUN cargo install cargo-strip

WORKDIR /builder
COPY Cargo.toml Cargo.lock ./
COPY ./lib ./lib
COPY ./client/core/rs ./client/core/rs
COPY ./client/periphery ./client/periphery
COPY ./bin/core ./bin/core
COPY ./bin/cli ./bin/cli

# Compile app
RUN cargo build -p komodo_core --release && \
  cargo build -p komodo_cli --release && \
  cargo strip

# Build Frontend
FROM node:20.12-alpine AS frontend-builder
WORKDIR /builder
COPY ./frontend ./frontend
COPY ./client/core/ts ./client
RUN cd client && yarn && yarn build && yarn link
RUN cd frontend && yarn link komodo_client && yarn && yarn build

# Final Image
FROM debian:bullseye-slim

COPY ./bin/core/starship.toml /starship.toml
COPY ./bin/core/debian-deps.sh .
RUN sh ./debian-deps.sh && rm ./debian-deps.sh

# Setup an application directory
WORKDIR /app

# Copy
COPY ./config/core.config.toml /config/.default.config.toml
COPY --from=frontend-builder /builder/frontend/dist /app/frontend
COPY --from=core-builder /builder/target/release/core /usr/local/bin/core
COPY --from=core-builder /builder/target/release/km /usr/local/bin/km
COPY --from=denoland/deno:bin /deno /usr/local/bin/deno

# Set $DENO_DIR and preload external Deno deps
ENV DENO_DIR=/action-cache/deno
RUN mkdir /action-cache && \
  cd /action-cache && \
  deno install jsr:@std/yaml jsr:@std/toml

# Hint at the port
EXPOSE 9120

ENV KOMODO_CLI_CONFIG_PATHS="/config"
# This ensures any `komodo.cli.*` takes precedence over the Core `/config/*config.*`
ENV KOMODO_CLI_CONFIG_KEYWORDS="*config.*,*komodo.cli*.*"

CMD [ "core" ]

# Label for Ghcr
LABEL org.opencontainers.image.source=https://github.com/moghtech/komodo
LABEL org.opencontainers.image.description="Komodo Core"
LABEL org.opencontainers.image.licenses=GPL-3.0


================================================
FILE: bin/core/debian-deps.sh
================================================
#!/bin/bash

## Core deps installer

apt-get update
apt-get install -y git curl ca-certificates iproute2

rm -rf /var/lib/apt/lists/*

# Starship prompt
curl -sS https://starship.rs/install.sh | sh -s -- --yes --bin-dir /usr/local/bin
echo 'export STARSHIP_CONFIG=/starship.toml' >> /root/.bashrc
echo 'eval "$(starship init bash)"' >> /root/.bashrc



================================================
FILE: bin/core/multi-arch.Dockerfile
================================================
## Assumes the latest binaries for x86_64 and aarch64 are already built (by binaries.Dockerfile).
## Sets up the necessary runtime container dependencies for Komodo Core.
## Since theres no heavy build here, QEMU multi-arch builds are fine for this image.

ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:latest
ARG FRONTEND_IMAGE=ghcr.io/moghtech/komodo-frontend:latest
ARG X86_64_BINARIES=${BINARIES_IMAGE}-x86_64
ARG AARCH64_BINARIES=${BINARIES_IMAGE}-aarch64

# This is required to work with COPY --from
FROM ${X86_64_BINARIES} AS x86_64
FROM ${AARCH64_BINARIES} AS aarch64
FROM ${FRONTEND_IMAGE} AS frontend

# Final Image
FROM debian:bullseye-slim

COPY ./bin/core/starship.toml /starship.toml
COPY ./bin/core/debian-deps.sh .
RUN sh ./debian-deps.sh && rm ./debian-deps.sh

WORKDIR /app

ARG TARGETPLATFORM

# Copy both binaries initially, but only keep appropriate one for the TARGETPLATFORM.
COPY --from=x86_64 /core /app/core/linux/amd64
COPY --from=aarch64 /core /app/core/linux/arm64
RUN mv /app/core/${TARGETPLATFORM} /usr/local/bin/core && rm -r /app/core

# Same for util
COPY --from=x86_64 /km /app/km/linux/amd64
COPY --from=aarch64 /km /app/km/linux/arm64
RUN mv /app/km/${TARGETPLATFORM} /usr/local/bin/km && rm -r /app/km

# Copy default config / static frontend / deno binary
COPY ./config/core.config.toml /config/.default.config.toml
COPY --from=frontend /frontend /app/frontend
COPY --from=denoland/deno:bin /deno /usr/local/bin/deno

# Set $DENO_DIR and preload external Deno deps
ENV DENO_DIR=/action-cache/deno
RUN mkdir /action-cache && \
  cd /action-cache && \
  deno install jsr:@std/yaml jsr:@std/toml

# Hint at the port
EXPOSE 9120

ENV KOMODO_CLI_CONFIG_PATHS="/config"
# This ensures any `komodo.cli.*` takes precedence over the Core `/config/*config.*`
ENV KOMODO_CLI_CONFIG_KEYWORDS="*config.*,*komodo.cli*.*"

CMD [ "core" ]

# Label for Ghcr
LABEL org.opencontainers.image.source=https://github.com/moghtech/komodo
LABEL org.opencontainers.image.description="Komodo Core"
LABEL org.opencontainers.image.licenses=GPL-3.0


================================================
FILE: bin/core/single-arch.Dockerfile
================================================
## Assumes the latest binaries for the required arch are already built (by binaries.Dockerfile).
## Sets up the necessary runtime container dependencies for Komodo Core.

ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:latest

# This is required to work with COPY --from
FROM ${BINARIES_IMAGE} AS binaries

# Build Frontend
FROM node:20.12-alpine AS frontend-builder
WORKDIR /builder
COPY ./frontend ./frontend
COPY ./client/core/ts ./client
RUN cd client && yarn && yarn build && yarn link
RUN cd frontend && yarn link komodo_client && yarn && yarn build

FROM debian:bullseye-slim

COPY ./bin/core/starship.toml /starship.toml
COPY ./bin/core/debian-deps.sh .
RUN sh ./debian-deps.sh && rm ./debian-deps.sh
	
# Copy
COPY ./config/core.config.toml /config/.default.config.toml
COPY --from=frontend-builder /builder/frontend/dist /app/frontend
COPY --from=binaries /core /usr/local/bin/core
COPY --from=binaries /km /usr/local/bin/km
COPY --from=denoland/deno:bin /deno /usr/local/bin/deno

# Set $DENO_DIR and preload external Deno deps
ENV DENO_DIR=/action-cache/deno
RUN mkdir /action-cache && \
	cd /action-cache && \
	deno install jsr:@std/yaml jsr:@std/toml

# Hint at the port
EXPOSE 9120

ENV KOMODO_CLI_CONFIG_PATHS="/config"
# This ensures any `komodo.cli.*` takes precedence over the Core `/config/*config.*`
ENV KOMODO_CLI_CONFIG_KEYWORDS="*config.*,*komodo.cli*.*"

CMD [ "core" ]

# Label for Ghcr
LABEL org.opencontainers.image.source=https://github.com/moghtech/komodo
LABEL org.opencontainers.image.description="Komodo Core"
LABEL org.opencontainers.image.licenses=GPL-3.0


================================================
FILE: bin/core/src/alert/discord.rs
================================================
use std::sync::OnceLock;

use serde::Serialize;

use super::*;

#[instrument(level = "debug")]
pub async fn send_alert(
  url: &str,
  alert: &Alert,
) -> anyhow::Result<()> {
  let level = fmt_level(alert.level);
  let content = match &alert.data {
    AlertData::Test { id, name } => {
      let link = resource_link(ResourceTargetVariant::Alerter, id);
      format!(
        "{level} | If you see this message, then Alerter **{name}** is **working**\n{link}"
      )
    }
    AlertData::ServerVersionMismatch {
      id,
      name,
      region,
      server_version,
      core_version,
    } => {
      let region = fmt_region(region);
      let link = resource_link(ResourceTargetVariant::Server, id);
      match alert.level {
        SeverityLevel::Ok => {
          format!(
            "{level} | **{name}**{region} | Periphery version now matches Core version ✅\n{link}"
          )
        }
        _ => {
          format!(
            "{level} | **{name}**{region} | Version mismatch detected ⚠️\nPeriphery: **{server_version}** | Core: **{core_version}**\n{link}"
          )
        }
      }
    }
    AlertData::ServerUnreachable {
      id,
      name,
      region,
      err,
    } => {
      let region = fmt_region(region);
      let link = resource_link(ResourceTargetVariant::Server, id);
      match alert.level {
        SeverityLevel::Ok => {
          format!(
            "{level} | **{name}**{region} is now **reachable**\n{link}"
          )
        }
        SeverityLevel::Critical => {
          let err = err
            .as_ref()
            .map(|e| format!("\n**error**: {e:#?}"))
            .unwrap_or_default();
          format!(
            "{level} | **{name}**{region} is **unreachable** ❌\n{link}{err}"
          )
        }
        _ => unreachable!(),
      }
    }
    AlertData::ServerCpu {
      id,
      name,
      region,
      percentage,
    } => {
      let region = fmt_region(region);
      let link = resource_link(ResourceTargetVariant::Server, id);
      format!(
        "{level} | **{name}**{region} cpu usage at **{percentage:.1}%**\n{link}"
      )
    }
    AlertData::ServerMem {
      id,
      name,
      region,
      used_gb,
      total_gb,
    } => {
      let region = fmt_region(region);
      let link = resource_link(ResourceTargetVariant::Server, id);
      let percentage = 100.0 * used_gb / total_gb;
      format!(
        "{level} | **{name}**{region} memory usage at **{percentage:.1}%** 💾\n\nUsing **{used_gb:.1} GiB** / **{total_gb:.1} GiB**\n{link}"
      )
    }
    AlertData::ServerDisk {
      id,
      name,
      region,
      path,
      used_gb,
      total_gb,
    } => {
      let region = fmt_region(region);
      let link = resource_link(ResourceTargetVariant::Server, id);
      let percentage = 100.0 * used_gb / total_gb;
      format!(
        "{level} | **{name}**{region} disk usage at **{percentage:.1}%** 💿\nmount point: `{path:?}`\nusing **{used_gb:.1} GiB** / **{total_gb:.1} GiB**\n{link}"
      )
    }
    AlertData::ContainerStateChange {
      id,
      name,
      server_id: _server_id,
      server_name,
      from,
      to,
    } => {
      let link = resource_link(ResourceTargetVariant::Deployment, id);
      let to = fmt_docker_container_state(to);
      format!(
        "📦 Deployment **{name}** is now **{to}**\nserver: **{server_name}**\nprevious: **{from}**\n{link}"
      )
    }
    AlertData::DeploymentImageUpdateAvailable {
      id,
      name,
      server_id: _server_id,
      server_name,
      image,
    } => {
      let link = resource_link(ResourceTargetVariant::Deployment, id);
      format!(
        "⬆ Deployment **{name}** has an update available\nserver: **{server_name}**\nimage: **{image}**\n{link}"
      )
    }
    AlertData::DeploymentAutoUpdated {
      id,
      name,
      server_id: _server_id,
      server_name,
      image,
    } => {
      let link = resource_link(ResourceTargetVariant::Deployment, id);
      format!(
        "⬆ Deployment **{name}** was updated automatically ⏫\nserver: **{server_name}**\nimage: **{image}**\n{link}"
      )
    }
    AlertData::StackStateChange {
      id,
      name,
      server_id: _server_id,
      server_name,
      from,
      to,
    } => {
      let link = resource_link(ResourceTargetVariant::Stack, id);
      let to = fmt_stack_state(to);
      format!(
        "🥞 Stack **{name}** is now {to}\nserver: **{server_name}**\nprevious: **{from}**\n{link}"
      )
    }
    AlertData::StackImageUpdateAvailable {
      id,
      name,
      server_id: _server_id,
      server_name,
      service,
      image,
    } => {
      let link = resource_link(ResourceTargetVariant::Stack, id);
      format!(
        "⬆ Stack **{name}** has an update available\nserver: **{server_name}**\nservice: **{service}**\nimage: **{image}**\n{link}"
      )
    }
    AlertData::StackAutoUpdated {
      id,
      name,
      server_id: _server_id,
      server_name,
      images,
    } => {
      let link = resource_link(ResourceTargetVariant::Stack, id);
      let images_label =
        if images.len() > 1 { "images" } else { "image" };
      let images = images.join(", ");
      format!(
        "⬆ Stack **{name}** was updated automatically ⏫\nserver: **{server_name}**\n{images_label}: **{images}**\n{link}"
      )
    }
    AlertData::AwsBuilderTerminationFailed {
      instance_id,
      message,
    } => {
      format!(
        "{level} | Failed to terminated AWS builder instance\ninstance id: **{instance_id}**\n{message}"
      )
    }
    AlertData::ResourceSyncPendingUpdates { id, name } => {
      let link =
        resource_link(ResourceTargetVariant::ResourceSync, id);
      format!(
        "{level} | Pending resource sync updates on **{name}**\n{link}"
      )
    }
    AlertData::BuildFailed { id, name, version } => {
      let link = resource_link(ResourceTargetVariant::Build, id);
      format!(
        "{level} | Build **{name}** failed\nversion: **v{version}**\n{link}"
      )
    }
    AlertData::RepoBuildFailed { id, name } => {
      let link = resource_link(ResourceTargetVariant::Repo, id);
      format!("{level} | Repo build for **{name}** failed\n{link}")
    }
    AlertData::ProcedureFailed { id, name } => {
      let link = resource_link(ResourceTargetVariant::Procedure, id);
      format!("{level} | Procedure **{name}** failed\n{link}")
    }
    AlertData::ActionFailed { id, name } => {
      let link = resource_link(ResourceTargetVariant::Action, id);
      format!("{level} | Action **{name}** failed\n{link}")
    }
    AlertData::ScheduleRun {
      resource_type,
      id,
      name,
    } => {
      let link = resource_link(*resource_type, id);
      format!(
        "{level} | **{name}** ({resource_type}) | Scheduled run started 🕝\n{link}"
      )
    }
    AlertData::Custom { message, details } => {
      format!(
        "{level} | {message}{}",
        if details.is_empty() {
          format_args!("")
        } else {
          format_args!("\n{details}")
        }
      )
    }
    AlertData::None {} => Default::default(),
  };
  if !content.is_empty() {
    let VariablesAndSecrets { variables, secrets } =
      get_variables_and_secrets().await?;
    let mut url_interpolated = url.to_string();

    let mut interpolator =
      Interpolator::new(Some(&variables), &secrets);

    interpolator.interpolate_string(&mut url_interpolated)?;

    send_message(&url_interpolated, &content)
      .await
      .map_err(|e| {
        let replacers = interpolator
          .secret_replacers
          .into_iter()
          .collect::<Vec<_>>();
        let sanitized_error =
          svi::replace_in_string(&format!("{e:?}"), &replacers);
        anyhow::Error::msg(format!(
          "Error with slack request: {sanitized_error}"
        ))
      })?;
  }
  Ok(())
}

async fn send_message(
  url: &str,
  content: &str,
) -> anyhow::Result<()> {
  let body = DiscordMessageBody { content };

  let response = http_client()
    .post(url)
    .json(&body)
    .send()
    .await
    .context("Failed to send message")?;

  let status = response.status();

  if status.is_success() {
    Ok(())
  } else {
    let text = response.text().await.with_context(|| {
      format!("Failed to send message to Discord | {status} | failed to get response text")
    })?;
    Err(anyhow::anyhow!(
      "Failed to send message to Discord | {status} | {text}"
    ))
  }
}

fn http_client() -> &'static reqwest::Client {
  static CLIENT: OnceLock<reqwest::Client> = OnceLock::new();
  CLIENT.get_or_init(reqwest::Client::new)
}

#[derive(Serialize)]
struct DiscordMessageBody<'a> {
  content: &'a str,
}


================================================
FILE: bin/core/src/alert/mod.rs
================================================
use ::slack::types::Block;
use anyhow::{Context, anyhow};
use database::mungos::{find::find_collect, mongodb::bson::doc};
use derive_variants::ExtractVariant;
use futures::future::join_all;
use interpolate::Interpolator;
use komodo_client::entities::{
  ResourceTargetVariant,
  alert::{Alert, AlertData, AlertDataVariant, SeverityLevel},
  alerter::*,
  deployment::DeploymentState,
  komodo_timestamp,
  stack::StackState,
};
use tracing::Instrument;

use crate::helpers::query::get_variables_and_secrets;
use crate::helpers::{
  maintenance::is_in_maintenance, query::VariablesAndSecrets,
};
use crate::{config::core_config, state::db_client};

mod discord;
mod ntfy;
mod pushover;
mod slack;

#[instrument(level = "debug")]
pub async fn send_alerts(alerts: &[Alert]) {
  if alerts.is_empty() {
    return;
  }

  let span =
    info_span!("send_alerts", alerts = format!("{alerts:?}"));
  async {
    let Ok(alerters) = find_collect(
      &db_client().alerters,
      doc! { "config.enabled": true },
      None,
    )
    .await
    .inspect_err(|e| {
      error!(
      "ERROR sending alerts | failed to get alerters from db | {e:#}"
    )
    }) else {
      return;
    };

    let handles = alerts
      .iter()
      .map(|alert| send_alert_to_alerters(&alerters, alert));

    join_all(handles).await;
  }
  .instrument(span)
  .await
}

#[instrument(level = "debug")]
async fn send_alert_to_alerters(alerters: &[Alerter], alert: &Alert) {
  if alerters.is_empty() {
    return;
  }

  let handles = alerters
    .iter()
    .map(|alerter| send_alert_to_alerter(alerter, alert));

  join_all(handles)
    .await
    .into_iter()
    .filter_map(|res| res.err())
    .for_each(|e| error!("{e:#}"));
}

pub async fn send_alert_to_alerter(
  alerter: &Alerter,
  alert: &Alert,
) -> anyhow::Result<()> {
  // Don't send if not enabled
  if !alerter.config.enabled {
    return Ok(());
  }

  if is_in_maintenance(
    &alerter.config.maintenance_windows,
    komodo_timestamp(),
  ) {
    return Ok(());
  }

  let alert_type = alert.data.extract_variant();

  // In the test case, we don't want the filters inside this
  // block to stop the test from being sent to the alerting endpoint.
  if alert_type != AlertDataVariant::Test {
    // Don't send if alert type not configured on the alerter
    if !alerter.config.alert_types.is_empty()
      && !alerter.config.alert_types.contains(&alert_type)
    {
      return Ok(());
    }

    // Don't send if resource is in the blacklist
    if alerter.config.except_resources.contains(&alert.target) {
      return Ok(());
    }

    // Don't send if whitelist configured and target is not included
    if !alerter.config.resources.is_empty()
      && !alerter.config.resources.contains(&alert.target)
    {
      return Ok(());
    }
  }

  match &alerter.config.endpoint {
    AlerterEndpoint::Custom(CustomAlerterEndpoint { url }) => {
      send_custom_alert(url, alert).await.with_context(|| {
        format!(
          "Failed to send alert to Custom Alerter {}",
          alerter.name
        )
      })
    }
    AlerterEndpoint::Slack(SlackAlerterEndpoint { url }) => {
      slack::send_alert(url, alert).await.with_context(|| {
        format!(
          "Failed to send alert to Slack Alerter {}",
          alerter.name
        )
      })
    }
    AlerterEndpoint::Discord(DiscordAlerterEndpoint { url }) => {
      discord::send_alert(url, alert).await.with_context(|| {
        format!(
          "Failed to send alert to Discord Alerter {}",
          alerter.name
        )
      })
    }
    AlerterEndpoint::Ntfy(NtfyAlerterEndpoint { url, email }) => {
      ntfy::send_alert(url, email.as_deref(), alert)
        .await
        .with_context(|| {
          format!(
            "Failed to send alert to ntfy Alerter {}",
            alerter.name
          )
        })
    }
    AlerterEndpoint::Pushover(PushoverAlerterEndpoint { url }) => {
      pushover::send_alert(url, alert).await.with_context(|| {
        format!(
          "Failed to send alert to Pushover Alerter {}",
          alerter.name
        )
      })
    }
  }
}

#[instrument(level = "debug")]
async fn send_custom_alert(
  url: &str,
  alert: &Alert,
) -> anyhow::Result<()> {
  let VariablesAndSecrets { variables, secrets } =
    get_variables_and_secrets().await?;
  let mut url_interpolated = url.to_string();

  let mut interpolator =
    Interpolator::new(Some(&variables), &secrets);

  interpolator.interpolate_string(&mut url_interpolated)?;

  let res = reqwest::Client::new()
    .post(url_interpolated)
    .json(alert)
    .send()
    .await
    .map_err(|e| {
      let replacers = interpolator
        .secret_replacers
        .into_iter()
        .collect::<Vec<_>>();
      let sanitized_error =
        svi::replace_in_string(&format!("{e:?}"), &replacers);
      anyhow::Error::msg(format!(
        "Error with request: {sanitized_error}"
      ))
    })
    .context("failed at post request to alerter")?;
  let status = res.status();
  if !status.is_success() {
    let text = res
      .text()
      .await
      .context("failed to get response text on alerter response")?;
    return Err(anyhow!(
      "post to alerter failed | {status} | {text}"
    ));
  }
  Ok(())
}

fn fmt_region(region: &Option<String>) -> String {
  match region {
    Some(region) => format!(" ({region})"),
    None => String::new(),
  }
}

fn fmt_docker_container_state(state: &DeploymentState) -> String {
  match state {
    DeploymentState::Running => String::from("Running ▶️"),
    DeploymentState::Exited => String::from("Exited 🛑"),
    DeploymentState::Restarting => String::from("Restarting 🔄"),
    DeploymentState::NotDeployed => String::from("Not Deployed"),
    _ => state.to_string(),
  }
}

fn fmt_stack_state(state: &StackState) -> String {
  match state {
    StackState::Running => String::from("Running ▶️"),
    StackState::Stopped => String::from("Stopped 🛑"),
    StackState::Restarting => String::from("Restarting 🔄"),
    StackState::Down => String::from("Down ⬇️"),
    _ => state.to_string(),
  }
}

fn fmt_level(level: SeverityLevel) -> &'static str {
  match level {
    SeverityLevel::Critical => "CRITICAL 🚨",
    SeverityLevel::Warning => "WARNING ‼️",
    SeverityLevel::Ok => "OK ✅",
  }
}

fn resource_link(
  resource_type: ResourceTargetVariant,
  id: &str,
) -> String {
  komodo_client::entities::resource_link(
    &core_config().host,
    resource_type,
    id,
  )
}

/// Standard message content format
/// used by Ntfy, Pushover.
fn standard_alert_content(alert: &Alert) -> String {
  let level = fmt_level(alert.level);
  match &alert.data {
    AlertData::Test { id, name } => {
      let link = resource_link(ResourceTargetVariant::Alerter, id);
      format!(
        "{level} | If you see this message, then Alerter {name} is working\n{link}",
      )
    }
    AlertData::ServerVersionMismatch {
      id,
      name,
      region,
      server_version,
      core_version,
    } => {
      let region = fmt_region(region);
      let link = resource_link(ResourceTargetVariant::Server, id);
      match alert.level {
        SeverityLevel::Ok => {
          format!(
            "{level} | {name}{region} | Periphery version now matches Core version ✅\n{link}"
          )
        }
        _ => {
          format!(
            "{level} | {name}{region} | Version mismatch detected ⚠️\nPeriphery: {server_version} | Core: {core_version}\n{link}"
          )
        }
      }
    }
    AlertData::ServerUnreachable {
      id,
      name,
      region,
      err,
    } => {
      let region = fmt_region(region);
      let link = resource_link(ResourceTargetVariant::Server, id);
      match alert.level {
        SeverityLevel::Ok => {
          format!("{level} | {name}{region} is now reachable\n{link}")
        }
        SeverityLevel::Critical => {
          let err = err
            .as_ref()
            .map(|e| format!("\nerror: {e:#?}"))
            .unwrap_or_default();
          format!(
            "{level} | {name}{region} is unreachable ❌\n{link}{err}"
          )
        }
        _ => unreachable!(),
      }
    }
    AlertData::ServerCpu {
      id,
      name,
      region,
      percentage,
    } => {
      let region = fmt_region(region);
      let link = resource_link(ResourceTargetVariant::Server, id);
      format!(
        "{level} | {name}{region} cpu usage at {percentage:.1}%\n{link}",
      )
    }
    AlertData::ServerMem {
      id,
      name,
      region,
      used_gb,
      total_gb,
    } => {
      let region = fmt_region(region);
      let link = resource_link(ResourceTargetVariant::Server, id);
      let percentage = 100.0 * used_gb / total_gb;
      format!(
        "{level} | {name}{region} memory usage at {percentage:.1}%💾\n\nUsing {used_gb:.1} GiB / {total_gb:.1} GiB\n{link}",
      )
    }
    AlertData::ServerDisk {
      id,
      name,
      region,
      path,
      used_gb,
      total_gb,
    } => {
      let region = fmt_region(region);
      let link = resource_link(ResourceTargetVariant::Server, id);
      let percentage = 100.0 * used_gb / total_gb;
      format!(
        "{level} | {name}{region} disk usage at {percentage:.1}%💿\nmount point: {path:?}\nusing {used_gb:.1} GiB / {total_gb:.1} GiB\n{link}",
      )
    }
    AlertData::ContainerStateChange {
      id,
      name,
      server_id: _server_id,
      server_name,
      from,
      to,
    } => {
      let link = resource_link(ResourceTargetVariant::Deployment, id);
      let to_state = fmt_docker_container_state(to);
      format!(
        "📦Deployment {name} is now {to_state}\nserver: {server_name}\nprevious: {from}\n{link}",
      )
    }
    AlertData::DeploymentImageUpdateAvailable {
      id,
      name,
      server_id: _server_id,
      server_name,
      image,
    } => {
      let link = resource_link(ResourceTargetVariant::Deployment, id);
      format!(
        "⬆ Deployment {name} has an update available\nserver: {server_name}\nimage: {image}\n{link}",
      )
    }
    AlertData::DeploymentAutoUpdated {
      id,
      name,
      server_id: _server_id,
      server_name,
      image,
    } => {
      let link = resource_link(ResourceTargetVariant::Deployment, id);
      format!(
        "⬆ Deployment {name} was updated automatically\nserver: {server_name}\nimage: {image}\n{link}",
      )
    }
    AlertData::StackStateChange {
      id,
      name,
      server_id: _server_id,
      server_name,
      from,
      to,
    } => {
      let link = resource_link(ResourceTargetVariant::Stack, id);
      let to_state = fmt_stack_state(to);
      format!(
        "🥞 Stack {name} is now {to_state}\nserver: {server_name}\nprevious: {from}\n{link}",
      )
    }
    AlertData::StackImageUpdateAvailable {
      id,
      name,
      server_id: _server_id,
      server_name,
      service,
      image,
    } => {
      let link = resource_link(ResourceTargetVariant::Stack, id);
      format!(
        "⬆ Stack {name} has an update available\nserver: {server_name}\nservice: {service}\nimage: {image}\n{link}",
      )
    }
    AlertData::StackAutoUpdated {
      id,
      name,
      server_id: _server_id,
      server_name,
      images,
    } => {
      let link = resource_link(ResourceTargetVariant::Stack, id);
      let images_label =
        if images.len() > 1 { "images" } else { "image" };
      let images_str = images.join(", ");
      format!(
        "⬆ Stack {name} was updated automatically ⏫\nserver: {server_name}\n{images_label}: {images_str}\n{link}",
      )
    }
    AlertData::AwsBuilderTerminationFailed {
      instance_id,
      message,
    } => {
      format!(
        "{level} | Failed to terminate AWS builder instance\ninstance id: {instance_id}\n{message}",
      )
    }
    AlertData::ResourceSyncPendingUpdates { id, name } => {
      let link =
        resource_link(ResourceTargetVariant::ResourceSync, id);
      format!(
        "{level} | Pending resource sync updates on {name}\n{link}",
      )
    }
    AlertData::BuildFailed { id, name, version } => {
      let link = resource_link(ResourceTargetVariant::Build, id);
      format!(
        "{level} | Build {name} failed\nversion: v{version}\n{link}",
      )
    }
    AlertData::RepoBuildFailed { id, name } => {
      let link = resource_link(ResourceTargetVariant::Repo, id);
      format!("{level} | Repo build for {name} failed\n{link}",)
    }
    AlertData::ProcedureFailed { id, name } => {
      let link = resource_link(ResourceTargetVariant::Procedure, id);
      format!("{level} | Procedure {name} failed\n{link}")
    }
    AlertData::ActionFailed { id, name } => {
      let link = resource_link(ResourceTargetVariant::Action, id);
      format!("{level} | Action {name} failed\n{link}")
    }
    AlertData::ScheduleRun {
      resource_type,
      id,
      name,
    } => {
      let link = resource_link(*resource_type, id);
      format!(
        "{level} | {name} ({resource_type}) | Scheduled run started 🕝\n{link}"
      )
    }
    AlertData::Custom { message, details } => {
      format!(
        "{level} | {message}{}",
        if details.is_empty() {
          format_args!("")
        } else {
          format_args!("\n{details}")
        }
      )
    }
    AlertData::None {} => Default::default(),
  }
}


================================================
FILE: bin/core/src/alert/ntfy.rs
================================================
use std::sync::OnceLock;

use super::*;

#[instrument(level = "debug")]
pub async fn send_alert(
  url: &str,
  email: Option<&str>,
  alert: &Alert,
) -> anyhow::Result<()> {
  let content = standard_alert_content(alert);
  if !content.is_empty() {
    send_message(url, email, content).await?;
  }
  Ok(())
}

async fn send_message(
  url: &str,
  email: Option<&str>,
  content: String,
) -> anyhow::Result<()> {
  let mut request = http_client()
    .post(url)
    .header("Title", "ntfy Alert")
    .body(content);

  if let Some(email) = email {
    request = request.header("X-Email", email);
  }

  let response =
    request.send().await.context("Failed to send message")?;

  let status = response.status();
  if status.is_success() {
    debug!("ntfy alert sent successfully: {}", status);
    Ok(())
  } else {
    let text = response.text().await.with_context(|| {
      format!(
        "Failed to send message to ntfy | {status} | failed to get response text"
      )
    })?;
    Err(anyhow!(
      "Failed to send message to ntfy | {} | {}",
      status,
      text
    ))
  }
}

fn http_client() -> &'static reqwest::Client {
  static CLIENT: OnceLock<reqwest::Client> = OnceLock::new();
  CLIENT.get_or_init(reqwest::Client::new)
}


================================================
FILE: bin/core/src/alert/pushover.rs
================================================
use std::sync::OnceLock;

use super::*;

#[instrument(level = "debug")]
pub async fn send_alert(
  url: &str,
  alert: &Alert,
) -> anyhow::Result<()> {
  let content = standard_alert_content(alert);
  if !content.is_empty() {
    send_message(url, content).await?;
  }
  Ok(())
}

async fn send_message(
  url: &str,
  content: String,
) -> anyhow::Result<()> {
  // pushover needs all information to be encoded in the URL. At minimum they need
  // the user key, the application token, and the message (url encoded).
  // other optional params here: https://pushover.net/api (just add them to the
  // webhook url along with the application token and the user key).
  let content = [("message", content)];

  let response = http_client()
    .post(url)
    .form(&content)
    .send()
    .await
    .context("Failed to send message")?;

  let status = response.status();
  if status.is_success() {
    debug!("pushover alert sent successfully: {}", status);
    Ok(())
  } else {
    let text = response.text().await.with_context(|| {
      format!(
        "Failed to send message to pushover | {status} | failed to get response text"
      )
    })?;
    Err(anyhow!(
      "Failed to send message to pushover | {} | {}",
      status,
      text
    ))
  }
}

fn http_client() -> &'static reqwest::Client {
  static CLIENT: OnceLock<reqwest::Client> = OnceLock::new();
  CLIENT.get_or_init(reqwest::Client::new)
}


================================================
FILE: bin/core/src/alert/slack.rs
================================================
use super::*;

#[instrument(level = "debug")]
pub async fn send_alert(
  url: &str,
  alert: &Alert,
) -> anyhow::Result<()> {
  let level = fmt_level(alert.level);
  let (text, blocks): (_, Option<_>) = match &alert.data {
    AlertData::Test { id, name } => {
      let text = format!(
        "{level} | If you see this message, then Alerter *{name}* is *working*"
      );
      let blocks = vec![
        Block::header(level),
        Block::section(format!(
          "If you see this message, then Alerter *{name}* is *working*"
        )),
        Block::section(resource_link(
          ResourceTargetVariant::Alerter,
          id,
        )),
      ];
      (text, blocks.into())
    }
    AlertData::ServerVersionMismatch {
      id,
      name,
      region,
      server_version,
      core_version,
    } => {
      let region = fmt_region(region);
      let text = match alert.level {
        SeverityLevel::Ok => {
          format!(
            "{level} | *{name}*{region} | Periphery version now matches Core version ✅"
          )
        }
        _ => {
          format!(
            "{level} | *{name}*{region} | Version mismatch detected ⚠️\nPeriphery: {server_version} | Core: {core_version}"
          )
        }
      };
      let blocks = vec![
        Block::header(text.clone()),
        Block::section(resource_link(
          ResourceTargetVariant::Server,
          id,
        )),
      ];
      (text, blocks.into())
    }
    AlertData::ServerUnreachable {
      id,
      name,
      region,
      err,
    } => {
      let region = fmt_region(region);
      match alert.level {
        SeverityLevel::Ok => {
          let text =
            format!("{level} | *{name}*{region} is now *reachable*");
          let blocks = vec![
            Block::header(level),
            Block::section(format!(
              "*{name}*{region} is now *reachable*"
            )),
          ];
          (text, blocks.into())
        }
        SeverityLevel::Critical => {
          let text =
            format!("{level} | *{name}*{region} is *unreachable* ❌");
          let err = err
            .as_ref()
            .map(|e| format!("\nerror: {e:#?}"))
            .unwrap_or_default();
          let blocks = vec![
            Block::header(level),
            Block::section(format!(
              "*{name}*{region} is *unreachable* ❌{err}"
            )),
            Block::section(resource_link(
              ResourceTargetVariant::Server,
              id,
            )),
          ];
          (text, blocks.into())
        }
        _ => unreachable!(),
      }
    }
    AlertData::ServerCpu {
      id,
      name,
      region,
      percentage,
    } => {
      let region = fmt_region(region);
      match alert.level {
        SeverityLevel::Ok => {
          let text = format!(
            "{level} | *{name}*{region} cpu usage at *{percentage:.1}%*"
          );
          let blocks = vec![
            Block::header(level),
            Block::section(format!(
              "*{name}*{region} cpu usage at *{percentage:.1}%*"
            )),
            Block::section(resource_link(
              ResourceTargetVariant::Server,
              id,
            )),
          ];
          (text, blocks.into())
        }
        _ => {
          let text = format!(
            "{level} | *{name}*{region} cpu usage at *{percentage:.1}%* 📈"
          );
          let blocks = vec![
            Block::header(level),
            Block::section(format!(
              "*{name}*{region} cpu usage at *{percentage:.1}%* 📈"
            )),
            Block::section(resource_link(
              ResourceTargetVariant::Server,
              id,
            )),
          ];
          (text, blocks.into())
        }
      }
    }
    AlertData::ServerMem {
      id,
      name,
      region,
      used_gb,
      total_gb,
    } => {
      let region = fmt_region(region);
      let percentage = 100.0 * used_gb / total_gb;
      match alert.level {
        SeverityLevel::Ok => {
          let text = format!(
            "{level} | *{name}*{region} memory usage at *{percentage:.1}%* 💾"
          );
          let blocks = vec![
            Block::header(level),
            Block::section(format!(
              "*{name}*{region} memory usage at *{percentage:.1}%* 💾"
            )),
            Block::section(format!(
              "using *{used_gb:.1} GiB* / *{total_gb:.1} GiB*"
            )),
            Block::section(resource_link(
              ResourceTargetVariant::Server,
              id,
            )),
          ];
          (text, blocks.into())
        }
        _ => {
          let text = format!(
            "{level} | *{name}*{region} memory usage at *{percentage:.1}%* 💾"
          );
          let blocks = vec![
            Block::header(level),
            Block::section(format!(
              "*{name}*{region} memory usage at *{percentage:.1}%* 💾"
            )),
            Block::section(format!(
              "using *{used_gb:.1} GiB* / *{total_gb:.1} GiB*"
            )),
            Block::section(resource_link(
              ResourceTargetVariant::Server,
              id,
            )),
          ];
          (text, blocks.into())
        }
      }
    }
    AlertData::ServerDisk {
      id,
      name,
      region,
      path,
      used_gb,
      total_gb,
    } => {
      let region = fmt_region(region);
      let percentage = 100.0 * used_gb / total_gb;
      match alert.level {
        SeverityLevel::Ok => {
          let text = format!(
            "{level} | *{name}*{region} disk usage at *{percentage:.1}%* | mount point: *{path:?}* 💿"
          );
          let blocks = vec![
            Block::header(level),
            Block::section(format!(
              "*{name}*{region} disk usage at *{percentage:.1}%* 💿"
            )),
            Block::section(format!(
              "mount point: {path:?} | using *{used_gb:.1} GiB* / *{total_gb:.1} GiB*"
            )),
            Block::section(resource_link(
              ResourceTargetVariant::Server,
              id,
            )),
          ];
          (text, blocks.into())
        }
        _ => {
          let text = format!(
            "{level} | *{name}*{region} disk usage at *{percentage:.1}%* | mount point: *{path:?}* 💿"
          );
          let blocks = vec![
            Block::header(level),
            Block::section(format!(
              "*{name}*{region} disk usage at *{percentage:.1}%* 💿"
            )),
            Block::section(format!(
              "mount point: {path:?} | using *{used_gb:.1} GiB* / *{total_gb:.1} GiB*"
            )),
            Block::section(resource_link(
              ResourceTargetVariant::Server,
              id,
            )),
          ];
          (text, blocks.into())
        }
      }
    }
    AlertData::ContainerStateChange {
      name,
      server_name,
      from,
      to,
      id,
      ..
    } => {
      let to = fmt_docker_container_state(to);
      let text = format!("📦 Container *{name}* is now *{to}*");
      let blocks = vec![
        Block::header(text.clone()),
        Block::section(format!(
          "server: {server_name}\nprevious: {from}",
        )),
        Block::section(resource_link(
          ResourceTargetVariant::Deployment,
          id,
        )),
      ];
      (text, blocks.into())
    }
Download .txt
gitextract_7y0a1oom/

├── .cargo/
│   └── config.toml
├── .devcontainer/
│   ├── dev.compose.yaml
│   ├── devcontainer.json
│   └── postCreate.sh
├── .github/
│   └── FUNDING.yml
├── .gitignore
├── .kminclude
├── .vscode/
│   ├── extensions.json
│   ├── resolver.code-snippets
│   └── tasks.json
├── Cargo.toml
├── LICENSE
├── bin/
│   ├── binaries.Dockerfile
│   ├── chef.binaries.Dockerfile
│   ├── cli/
│   │   ├── Cargo.toml
│   │   ├── README.md
│   │   ├── aio.Dockerfile
│   │   ├── docs/
│   │   │   └── copy-database.md
│   │   ├── multi-arch.Dockerfile
│   │   ├── runfile.toml
│   │   ├── single-arch.Dockerfile
│   │   └── src/
│   │       ├── command/
│   │       │   ├── container.rs
│   │       │   ├── database.rs
│   │       │   ├── execute.rs
│   │       │   ├── list.rs
│   │       │   ├── mod.rs
│   │       │   └── update/
│   │       │       ├── mod.rs
│   │       │       ├── resource.rs
│   │       │       ├── user.rs
│   │       │       └── variable.rs
│   │       ├── config.rs
│   │       └── main.rs
│   ├── core/
│   │   ├── Cargo.toml
│   │   ├── aio.Dockerfile
│   │   ├── debian-deps.sh
│   │   ├── multi-arch.Dockerfile
│   │   ├── single-arch.Dockerfile
│   │   ├── src/
│   │   │   ├── alert/
│   │   │   │   ├── discord.rs
│   │   │   │   ├── mod.rs
│   │   │   │   ├── ntfy.rs
│   │   │   │   ├── pushover.rs
│   │   │   │   └── slack.rs
│   │   │   ├── api/
│   │   │   │   ├── auth.rs
│   │   │   │   ├── execute/
│   │   │   │   │   ├── action.rs
│   │   │   │   │   ├── alerter.rs
│   │   │   │   │   ├── build.rs
│   │   │   │   │   ├── deployment.rs
│   │   │   │   │   ├── maintenance.rs
│   │   │   │   │   ├── mod.rs
│   │   │   │   │   ├── procedure.rs
│   │   │   │   │   ├── repo.rs
│   │   │   │   │   ├── server.rs
│   │   │   │   │   ├── stack.rs
│   │   │   │   │   └── sync.rs
│   │   │   │   ├── mod.rs
│   │   │   │   ├── read/
│   │   │   │   │   ├── action.rs
│   │   │   │   │   ├── alert.rs
│   │   │   │   │   ├── alerter.rs
│   │   │   │   │   ├── build.rs
│   │   │   │   │   ├── builder.rs
│   │   │   │   │   ├── deployment.rs
│   │   │   │   │   ├── mod.rs
│   │   │   │   │   ├── permission.rs
│   │   │   │   │   ├── procedure.rs
│   │   │   │   │   ├── provider.rs
│   │   │   │   │   ├── repo.rs
│   │   │   │   │   ├── schedule.rs
│   │   │   │   │   ├── server.rs
│   │   │   │   │   ├── stack.rs
│   │   │   │   │   ├── sync.rs
│   │   │   │   │   ├── tag.rs
│   │   │   │   │   ├── toml.rs
│   │   │   │   │   ├── update.rs
│   │   │   │   │   ├── user.rs
│   │   │   │   │   ├── user_group.rs
│   │   │   │   │   └── variable.rs
│   │   │   │   ├── terminal.rs
│   │   │   │   ├── user.rs
│   │   │   │   └── write/
│   │   │   │       ├── action.rs
│   │   │   │       ├── alerter.rs
│   │   │   │       ├── build.rs
│   │   │   │       ├── builder.rs
│   │   │   │       ├── deployment.rs
│   │   │   │       ├── mod.rs
│   │   │   │       ├── permissions.rs
│   │   │   │       ├── procedure.rs
│   │   │   │       ├── provider.rs
│   │   │   │       ├── repo.rs
│   │   │   │       ├── resource.rs
│   │   │   │       ├── server.rs
│   │   │   │       ├── service_user.rs
│   │   │   │       ├── stack.rs
│   │   │   │       ├── sync.rs
│   │   │   │       ├── tag.rs
│   │   │   │       ├── user.rs
│   │   │   │       ├── user_group.rs
│   │   │   │       └── variable.rs
│   │   │   ├── auth/
│   │   │   │   ├── github/
│   │   │   │   │   ├── client.rs
│   │   │   │   │   └── mod.rs
│   │   │   │   ├── google/
│   │   │   │   │   ├── client.rs
│   │   │   │   │   └── mod.rs
│   │   │   │   ├── jwt.rs
│   │   │   │   ├── local.rs
│   │   │   │   ├── mod.rs
│   │   │   │   └── oidc/
│   │   │   │       ├── client.rs
│   │   │   │       └── mod.rs
│   │   │   ├── cloud/
│   │   │   │   ├── aws/
│   │   │   │   │   ├── ec2.rs
│   │   │   │   │   └── mod.rs
│   │   │   │   └── mod.rs
│   │   │   ├── config.rs
│   │   │   ├── helpers/
│   │   │   │   ├── action_state.rs
│   │   │   │   ├── all_resources.rs
│   │   │   │   ├── builder.rs
│   │   │   │   ├── cache.rs
│   │   │   │   ├── channel.rs
│   │   │   │   ├── maintenance.rs
│   │   │   │   ├── matcher.rs
│   │   │   │   ├── mod.rs
│   │   │   │   ├── procedure.rs
│   │   │   │   ├── prune.rs
│   │   │   │   ├── query.rs
│   │   │   │   └── update.rs
│   │   │   ├── listener/
│   │   │   │   ├── integrations/
│   │   │   │   │   ├── github.rs
│   │   │   │   │   ├── gitlab.rs
│   │   │   │   │   └── mod.rs
│   │   │   │   ├── mod.rs
│   │   │   │   ├── resources.rs
│   │   │   │   └── router.rs
│   │   │   ├── main.rs
│   │   │   ├── monitor/
│   │   │   │   ├── alert/
│   │   │   │   │   ├── deployment.rs
│   │   │   │   │   ├── mod.rs
│   │   │   │   │   ├── server.rs
│   │   │   │   │   └── stack.rs
│   │   │   │   ├── helpers.rs
│   │   │   │   ├── lists.rs
│   │   │   │   ├── mod.rs
│   │   │   │   ├── record.rs
│   │   │   │   └── resources.rs
│   │   │   ├── network.rs
│   │   │   ├── permission.rs
│   │   │   ├── resource/
│   │   │   │   ├── action.rs
│   │   │   │   ├── alerter.rs
│   │   │   │   ├── build.rs
│   │   │   │   ├── builder.rs
│   │   │   │   ├── deployment.rs
│   │   │   │   ├── mod.rs
│   │   │   │   ├── procedure.rs
│   │   │   │   ├── refresh.rs
│   │   │   │   ├── repo.rs
│   │   │   │   ├── server.rs
│   │   │   │   ├── stack.rs
│   │   │   │   └── sync.rs
│   │   │   ├── schedule.rs
│   │   │   ├── stack/
│   │   │   │   ├── execute.rs
│   │   │   │   ├── mod.rs
│   │   │   │   ├── remote.rs
│   │   │   │   └── services.rs
│   │   │   ├── startup.rs
│   │   │   ├── state.rs
│   │   │   ├── sync/
│   │   │   │   ├── deploy.rs
│   │   │   │   ├── execute.rs
│   │   │   │   ├── file.rs
│   │   │   │   ├── mod.rs
│   │   │   │   ├── remote.rs
│   │   │   │   ├── resources.rs
│   │   │   │   ├── toml.rs
│   │   │   │   ├── user_groups.rs
│   │   │   │   ├── variables.rs
│   │   │   │   └── view.rs
│   │   │   ├── ts_client.rs
│   │   │   └── ws/
│   │   │       ├── container.rs
│   │   │       ├── deployment.rs
│   │   │       ├── mod.rs
│   │   │       ├── stack.rs
│   │   │       ├── terminal.rs
│   │   │       └── update.rs
│   │   └── starship.toml
│   └── periphery/
│       ├── Cargo.toml
│       ├── aio.Dockerfile
│       ├── debian-deps.sh
│       ├── multi-arch.Dockerfile
│       ├── single-arch.Dockerfile
│       ├── src/
│       │   ├── api/
│       │   │   ├── build.rs
│       │   │   ├── compose.rs
│       │   │   ├── container.rs
│       │   │   ├── deploy.rs
│       │   │   ├── git.rs
│       │   │   ├── image.rs
│       │   │   ├── mod.rs
│       │   │   ├── network.rs
│       │   │   ├── router.rs
│       │   │   ├── stats.rs
│       │   │   ├── terminal.rs
│       │   │   └── volume.rs
│       │   ├── build.rs
│       │   ├── compose/
│       │   │   ├── mod.rs
│       │   │   ├── up.rs
│       │   │   └── write.rs
│       │   ├── config.rs
│       │   ├── docker/
│       │   │   ├── containers.rs
│       │   │   ├── images.rs
│       │   │   ├── mod.rs
│       │   │   ├── networks.rs
│       │   │   ├── stats.rs
│       │   │   └── volumes.rs
│       │   ├── git.rs
│       │   ├── helpers.rs
│       │   ├── main.rs
│       │   ├── ssl.rs
│       │   ├── stats.rs
│       │   └── terminal.rs
│       └── starship.toml
├── client/
│   ├── core/
│   │   ├── rs/
│   │   │   ├── Cargo.toml
│   │   │   ├── README.md
│   │   │   └── src/
│   │   │       ├── api/
│   │   │       │   ├── auth.rs
│   │   │       │   ├── execute/
│   │   │       │   │   ├── action.rs
│   │   │       │   │   ├── alerter.rs
│   │   │       │   │   ├── build.rs
│   │   │       │   │   ├── deployment.rs
│   │   │       │   │   ├── maintenance.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   ├── procedure.rs
│   │   │       │   │   ├── repo.rs
│   │   │       │   │   ├── server.rs
│   │   │       │   │   ├── stack.rs
│   │   │       │   │   └── sync.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── read/
│   │   │       │   │   ├── action.rs
│   │   │       │   │   ├── alert.rs
│   │   │       │   │   ├── alerter.rs
│   │   │       │   │   ├── build.rs
│   │   │       │   │   ├── builder.rs
│   │   │       │   │   ├── deployment.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   ├── permission.rs
│   │   │       │   │   ├── procedure.rs
│   │   │       │   │   ├── provider.rs
│   │   │       │   │   ├── repo.rs
│   │   │       │   │   ├── schedule.rs
│   │   │       │   │   ├── server.rs
│   │   │       │   │   ├── stack.rs
│   │   │       │   │   ├── sync.rs
│   │   │       │   │   ├── tag.rs
│   │   │       │   │   ├── toml.rs
│   │   │       │   │   ├── update.rs
│   │   │       │   │   ├── user.rs
│   │   │       │   │   ├── user_group.rs
│   │   │       │   │   └── variable.rs
│   │   │       │   ├── terminal.rs
│   │   │       │   ├── user.rs
│   │   │       │   └── write/
│   │   │       │       ├── action.rs
│   │   │       │       ├── alerter.rs
│   │   │       │       ├── api_key.rs
│   │   │       │       ├── build.rs
│   │   │       │       ├── builder.rs
│   │   │       │       ├── deployment.rs
│   │   │       │       ├── mod.rs
│   │   │       │       ├── permissions.rs
│   │   │       │       ├── procedure.rs
│   │   │       │       ├── provider.rs
│   │   │       │       ├── repo.rs
│   │   │       │       ├── resource.rs
│   │   │       │       ├── server.rs
│   │   │       │       ├── stack.rs
│   │   │       │       ├── sync.rs
│   │   │       │       ├── tags.rs
│   │   │       │       ├── user.rs
│   │   │       │       ├── user_group.rs
│   │   │       │       └── variable.rs
│   │   │       ├── busy.rs
│   │   │       ├── deserializers/
│   │   │       │   ├── conversion.rs
│   │   │       │   ├── environment.rs
│   │   │       │   ├── file_contents.rs
│   │   │       │   ├── forgiving_vec.rs
│   │   │       │   ├── item_or_vec.rs
│   │   │       │   ├── labels.rs
│   │   │       │   ├── maybe_string_i64.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── permission.rs
│   │   │       │   ├── string_list.rs
│   │   │       │   └── term_signal_labels.rs
│   │   │       ├── entities/
│   │   │       │   ├── action.rs
│   │   │       │   ├── alert.rs
│   │   │       │   ├── alerter.rs
│   │   │       │   ├── api_key.rs
│   │   │       │   ├── build.rs
│   │   │       │   ├── builder.rs
│   │   │       │   ├── config/
│   │   │       │   │   ├── cli/
│   │   │       │   │   │   ├── args/
│   │   │       │   │   │   │   ├── container.rs
│   │   │       │   │   │   │   ├── database.rs
│   │   │       │   │   │   │   ├── list.rs
│   │   │       │   │   │   │   ├── mod.rs
│   │   │       │   │   │   │   └── update.rs
│   │   │       │   │   │   └── mod.rs
│   │   │       │   │   ├── core.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   └── periphery.rs
│   │   │       │   ├── deployment.rs
│   │   │       │   ├── docker/
│   │   │       │   │   ├── container.rs
│   │   │       │   │   ├── image.rs
│   │   │       │   │   ├── mod.rs
│   │   │       │   │   ├── network.rs
│   │   │       │   │   ├── stats.rs
│   │   │       │   │   └── volume.rs
│   │   │       │   ├── logger.rs
│   │   │       │   ├── mod.rs
│   │   │       │   ├── permission.rs
│   │   │       │   ├── procedure.rs
│   │   │       │   ├── provider.rs
│   │   │       │   ├── repo.rs
│   │   │       │   ├── resource.rs
│   │   │       │   ├── schedule.rs
│   │   │       │   ├── server.rs
│   │   │       │   ├── stack.rs
│   │   │       │   ├── stats.rs
│   │   │       │   ├── sync.rs
│   │   │       │   ├── tag.rs
│   │   │       │   ├── toml.rs
│   │   │       │   ├── update.rs
│   │   │       │   ├── user.rs
│   │   │       │   ├── user_group.rs
│   │   │       │   └── variable.rs
│   │   │       ├── lib.rs
│   │   │       ├── parsers.rs
│   │   │       ├── request.rs
│   │   │       ├── terminal.rs
│   │   │       └── ws.rs
│   │   └── ts/
│   │       ├── README.md
│   │       ├── generate_types.mjs
│   │       ├── package.json
│   │       ├── runfile.toml
│   │       ├── src/
│   │       │   ├── lib.ts
│   │       │   ├── responses.ts
│   │       │   ├── terminal.ts
│   │       │   └── types.ts
│   │       └── tsconfig.json
│   └── periphery/
│       └── rs/
│           ├── Cargo.toml
│           └── src/
│               ├── api/
│               │   ├── build.rs
│               │   ├── compose.rs
│               │   ├── container.rs
│               │   ├── git.rs
│               │   ├── image.rs
│               │   ├── mod.rs
│               │   ├── network.rs
│               │   ├── stats.rs
│               │   ├── terminal.rs
│               │   └── volume.rs
│               ├── lib.rs
│               └── terminal.rs
├── compose/
│   ├── compose.env
│   ├── ferretdb.compose.yaml
│   ├── mongo.compose.yaml
│   └── periphery.compose.yaml
├── config/
│   ├── core.config.toml
│   ├── komodo.cli.toml
│   └── periphery.config.toml
├── deploy/
│   ├── deno.json
│   └── komodo.ts
├── dev.compose.yaml
├── docsite/
│   ├── .gitignore
│   ├── README.md
│   ├── babel.config.js
│   ├── docs/
│   │   ├── ecosystem/
│   │   │   ├── api.md
│   │   │   ├── cli.mdx
│   │   │   ├── community.md
│   │   │   ├── development.md
│   │   │   └── index.mdx
│   │   ├── intro.md
│   │   ├── resources/
│   │   │   ├── auto-update.md
│   │   │   ├── build-images/
│   │   │   │   ├── builders.md
│   │   │   │   ├── configuration.md
│   │   │   │   ├── index.mdx
│   │   │   │   ├── pre-build.md
│   │   │   │   └── versioning.md
│   │   │   ├── deploy-containers/
│   │   │   │   ├── configuration.md
│   │   │   │   ├── index.mdx
│   │   │   │   └── lifetime-management.md
│   │   │   ├── docker-compose.md
│   │   │   ├── index.md
│   │   │   ├── permissioning.md
│   │   │   ├── procedures.md
│   │   │   ├── sync-resources.md
│   │   │   ├── variables.md
│   │   │   └── webhooks.md
│   │   └── setup/
│   │       ├── advanced.mdx
│   │       ├── backup.md
│   │       ├── connect-servers.mdx
│   │       ├── ferretdb.mdx
│   │       ├── index.mdx
│   │       ├── mongo.mdx
│   │       └── version-upgrades.md
│   ├── docusaurus.config.ts
│   ├── package.json
│   ├── runfile.toml
│   ├── sidebars.ts
│   ├── src/
│   │   ├── components/
│   │   │   ├── ComposeAndEnv.tsx
│   │   │   ├── Divider.tsx
│   │   │   ├── HomepageFeatures/
│   │   │   │   ├── index.tsx
│   │   │   │   └── styles.module.css
│   │   │   ├── KomodoLogo.tsx
│   │   │   ├── RemoteCodeFile.tsx
│   │   │   └── SummaryImg.tsx
│   │   ├── css/
│   │   │   └── custom.css
│   │   └── pages/
│   │       ├── index.module.css
│   │       └── index.tsx
│   ├── static/
│   │   └── .nojekyll
│   └── tsconfig.json
├── example/
│   ├── alerter/
│   │   ├── Cargo.toml
│   │   ├── Dockerfile
│   │   ├── README.md
│   │   └── src/
│   │       └── main.rs
│   └── update_logger/
│       ├── Cargo.toml
│       ├── Dockerfile
│       └── src/
│           └── main.rs
├── expose.compose.yaml
├── frontend/
│   ├── .eslintrc.cjs
│   ├── .gitignore
│   ├── Dockerfile
│   ├── README.md
│   ├── components.json
│   ├── index.html
│   ├── package.json
│   ├── postcss.config.js
│   ├── public/
│   │   ├── client/
│   │   │   ├── lib.d.ts
│   │   │   ├── lib.js
│   │   │   ├── responses.d.ts
│   │   │   ├── responses.js
│   │   │   ├── terminal.d.ts
│   │   │   ├── terminal.js
│   │   │   ├── types.d.ts
│   │   │   └── types.js
│   │   ├── deno.d.ts
│   │   ├── index.d.ts
│   │   ├── manifest.json
│   │   ├── robots.txt
│   │   └── schema/
│   │       └── compose-spec.json
│   ├── runfile.toml
│   ├── src/
│   │   ├── components/
│   │   │   ├── alert/
│   │   │   │   ├── details.tsx
│   │   │   │   ├── index.tsx
│   │   │   │   └── table.tsx
│   │   │   ├── config/
│   │   │   │   ├── env_vars.tsx
│   │   │   │   ├── index.tsx
│   │   │   │   ├── linked_repo.tsx
│   │   │   │   ├── maintenance.tsx
│   │   │   │   └── util.tsx
│   │   │   ├── export.tsx
│   │   │   ├── group-actions.tsx
│   │   │   ├── inspect.tsx
│   │   │   ├── keys/
│   │   │   │   └── table.tsx
│   │   │   ├── layouts.tsx
│   │   │   ├── log.tsx
│   │   │   ├── monaco.tsx
│   │   │   ├── omnibar.tsx
│   │   │   ├── resources/
│   │   │   │   ├── action/
│   │   │   │   │   ├── config.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   ├── info.tsx
│   │   │   │   │   └── table.tsx
│   │   │   │   ├── alerter/
│   │   │   │   │   ├── config/
│   │   │   │   │   │   ├── alert_types.tsx
│   │   │   │   │   │   ├── endpoint.tsx
│   │   │   │   │   │   ├── index.tsx
│   │   │   │   │   │   └── resources.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── table.tsx
│   │   │   │   ├── build/
│   │   │   │   │   ├── actions.tsx
│   │   │   │   │   ├── chart.tsx
│   │   │   │   │   ├── config.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   ├── info.tsx
│   │   │   │   │   └── table.tsx
│   │   │   │   ├── builder/
│   │   │   │   │   ├── config.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── table.tsx
│   │   │   │   ├── common.tsx
│   │   │   │   ├── deployment/
│   │   │   │   │   ├── actions.tsx
│   │   │   │   │   ├── config/
│   │   │   │   │   │   ├── components/
│   │   │   │   │   │   │   ├── image.tsx
│   │   │   │   │   │   │   ├── network.tsx
│   │   │   │   │   │   │   ├── restart.tsx
│   │   │   │   │   │   │   └── term-signal.tsx
│   │   │   │   │   │   └── index.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   ├── inspect.tsx
│   │   │   │   │   ├── log.tsx
│   │   │   │   │   └── table.tsx
│   │   │   │   ├── index.tsx
│   │   │   │   ├── procedure/
│   │   │   │   │   ├── config.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── table.tsx
│   │   │   │   ├── repo/
│   │   │   │   │   ├── actions.tsx
│   │   │   │   │   ├── config.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── table.tsx
│   │   │   │   ├── resource-sync/
│   │   │   │   │   ├── actions.tsx
│   │   │   │   │   ├── config.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   ├── info.tsx
│   │   │   │   │   ├── pending.tsx
│   │   │   │   │   └── table.tsx
│   │   │   │   ├── server/
│   │   │   │   │   ├── actions.tsx
│   │   │   │   │   ├── config.tsx
│   │   │   │   │   ├── hooks.ts
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   ├── info/
│   │   │   │   │   │   ├── containers.tsx
│   │   │   │   │   │   ├── images.tsx
│   │   │   │   │   │   ├── index.tsx
│   │   │   │   │   │   ├── networks.tsx
│   │   │   │   │   │   └── volumes.tsx
│   │   │   │   │   ├── monitoring-table.tsx
│   │   │   │   │   ├── stat-chart.tsx
│   │   │   │   │   ├── stats-mini.tsx
│   │   │   │   │   ├── stats.tsx
│   │   │   │   │   └── table.tsx
│   │   │   │   └── stack/
│   │   │   │       ├── actions.tsx
│   │   │   │       ├── config.tsx
│   │   │   │       ├── index.tsx
│   │   │   │       ├── info.tsx
│   │   │   │       ├── log.tsx
│   │   │   │       ├── services.tsx
│   │   │   │       └── table.tsx
│   │   │   ├── sidebar.tsx
│   │   │   ├── tags/
│   │   │   │   └── index.tsx
│   │   │   ├── terminal/
│   │   │   │   ├── container.tsx
│   │   │   │   ├── index.tsx
│   │   │   │   └── server.tsx
│   │   │   ├── topbar/
│   │   │   │   ├── components.tsx
│   │   │   │   └── index.tsx
│   │   │   ├── updates/
│   │   │   │   ├── details.tsx
│   │   │   │   ├── resource.tsx
│   │   │   │   └── table.tsx
│   │   │   ├── users/
│   │   │   │   ├── delete-user-group.tsx
│   │   │   │   ├── hooks.ts
│   │   │   │   ├── new.tsx
│   │   │   │   ├── permissions-selector.tsx
│   │   │   │   ├── permissions-table.tsx
│   │   │   │   ├── service-api-key.tsx
│   │   │   │   └── table.tsx
│   │   │   └── util.tsx
│   │   ├── globals.css
│   │   ├── lib/
│   │   │   ├── color.ts
│   │   │   ├── dashboard-preferences.ts
│   │   │   ├── formatting.ts
│   │   │   ├── hooks.ts
│   │   │   ├── socket.tsx
│   │   │   └── utils.ts
│   │   ├── main.tsx
│   │   ├── monaco/
│   │   │   ├── fancy_toml.ts
│   │   │   ├── index.ts
│   │   │   ├── init.ts
│   │   │   ├── key_value.ts
│   │   │   ├── shell.ts
│   │   │   ├── string_list.ts
│   │   │   ├── theme.ts
│   │   │   ├── toml.ts
│   │   │   └── yaml.ts
│   │   ├── pages/
│   │   │   ├── alerts.tsx
│   │   │   ├── containers.tsx
│   │   │   ├── home/
│   │   │   │   ├── all_resources.tsx
│   │   │   │   ├── dashboard.tsx
│   │   │   │   ├── index.tsx
│   │   │   │   └── tree.tsx
│   │   │   ├── login.tsx
│   │   │   ├── resource-notifications.tsx
│   │   │   ├── resource.tsx
│   │   │   ├── resources.tsx
│   │   │   ├── schedules.tsx
│   │   │   ├── server-info/
│   │   │   │   ├── container/
│   │   │   │   │   ├── actions.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   ├── inspect.tsx
│   │   │   │   │   └── log.tsx
│   │   │   │   ├── image.tsx
│   │   │   │   ├── network.tsx
│   │   │   │   └── volume.tsx
│   │   │   ├── settings/
│   │   │   │   ├── index.tsx
│   │   │   │   ├── profile.tsx
│   │   │   │   ├── providers.tsx
│   │   │   │   ├── tags.tsx
│   │   │   │   ├── users.tsx
│   │   │   │   └── variables.tsx
│   │   │   ├── stack-service/
│   │   │   │   ├── index.tsx
│   │   │   │   ├── inspect.tsx
│   │   │   │   └── log.tsx
│   │   │   ├── update.tsx
│   │   │   ├── updates.tsx
│   │   │   ├── user-group.tsx
│   │   │   ├── user.tsx
│   │   │   └── user_disabled.tsx
│   │   ├── router.tsx
│   │   ├── types.d.ts
│   │   ├── ui/
│   │   │   ├── badge.tsx
│   │   │   ├── button.tsx
│   │   │   ├── card.tsx
│   │   │   ├── checkbox.tsx
│   │   │   ├── command.tsx
│   │   │   ├── data-table.tsx
│   │   │   ├── dialog.tsx
│   │   │   ├── dropdown-menu.tsx
│   │   │   ├── hover-card.tsx
│   │   │   ├── input.tsx
│   │   │   ├── json.tsx
│   │   │   ├── label.tsx
│   │   │   ├── multi-select.tsx
│   │   │   ├── pagination.tsx
│   │   │   ├── popover.tsx
│   │   │   ├── progress.tsx
│   │   │   ├── select.tsx
│   │   │   ├── separator.tsx
│   │   │   ├── sheet.tsx
│   │   │   ├── skeleton.tsx
│   │   │   ├── switch.tsx
│   │   │   ├── table.tsx
│   │   │   ├── tabs.tsx
│   │   │   ├── textarea.tsx
│   │   │   ├── theme.tsx
│   │   │   ├── toast.tsx
│   │   │   ├── toaster.tsx
│   │   │   ├── toggle-group.tsx
│   │   │   ├── toggle.tsx
│   │   │   ├── tooltip.tsx
│   │   │   └── use-toast.ts
│   │   └── vite-env.d.ts
│   ├── tailwind.config.js
│   ├── tsconfig.json
│   ├── tsconfig.node.json
│   └── vite.config.ts
├── komodo.code-workspace
├── lib/
│   ├── cache/
│   │   ├── Cargo.toml
│   │   ├── README.md
│   │   └── src/
│   │       └── lib.rs
│   ├── command/
│   │   ├── Cargo.toml
│   │   ├── README.md
│   │   └── src/
│   │       └── lib.rs
│   ├── config/
│   │   ├── Cargo.toml
│   │   └── src/
│   │       ├── error.rs
│   │       ├── includes.rs
│   │       ├── lib.rs
│   │       ├── load.rs
│   │       └── merge.rs
│   ├── database/
│   │   ├── Cargo.toml
│   │   └── src/
│   │       ├── lib.rs
│   │       └── utils/
│   │           ├── backup.rs
│   │           ├── copy.rs
│   │           ├── mod.rs
│   │           └── restore.rs
│   ├── environment/
│   │   ├── Cargo.toml
│   │   └── src/
│   │       └── lib.rs
│   ├── environment_file/
│   │   ├── Cargo.toml
│   │   ├── README.md
│   │   └── src/
│   │       └── lib.rs
│   ├── formatting/
│   │   ├── Cargo.toml
│   │   ├── README.md
│   │   └── src/
│   │       └── lib.rs
│   ├── git/
│   │   ├── Cargo.toml
│   │   ├── README.md
│   │   └── src/
│   │       ├── clone.rs
│   │       ├── commit.rs
│   │       ├── init.rs
│   │       ├── lib.rs
│   │       ├── pull.rs
│   │       └── pull_or_clone.rs
│   ├── interpolate/
│   │   ├── Cargo.toml
│   │   └── src/
│   │       └── lib.rs
│   ├── logger/
│   │   ├── Cargo.toml
│   │   ├── README.md
│   │   └── src/
│   │       ├── lib.rs
│   │       └── otel.rs
│   └── response/
│       ├── Cargo.toml
│       └── src/
│           └── lib.rs
├── readme.md
├── roadmap.md
├── runfile.toml
├── rustfmt.toml
├── scripts/
│   ├── install-cli.py
│   ├── readme.md
│   └── setup-periphery.py
└── typeshare.toml
Download .txt
Showing preview only (386K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (5064 symbols across 423 files)

FILE: bin/cli/src/command/container.rs
  function handle (line 32) | pub async fn handle(container: &Container) -> anyhow::Result<()> {
  function list_containers (line 41) | async fn list_containers(
  function inspect_container (line 136) | pub async fn inspect_container(
  function serialize_container (line 217) | fn serialize_container(
  method header (line 240) | fn header(links: bool) -> &'static [&'static str] {
  method row (line 255) | fn row(self, links: bool) -> Vec<Cell> {

FILE: bin/cli/src/command/database.rs
  function handle (line 11) | pub async fn handle(command: &DatabaseCommand) -> anyhow::Result<()> {
  function backup (line 27) | async fn backup(yes: bool) -> anyhow::Result<()> {
  function restore (line 86) | async fn restore(
  function prune (line 153) | async fn prune(yes: bool) -> anyhow::Result<()> {
  function prune_inner (line 194) | async fn prune_inner() -> anyhow::Result<()> {
  function copy (line 256) | async fn copy(index: bool, yes: bool) -> anyhow::Result<()> {

FILE: bin/cli/src/command/execute.rs
  type ExecutionResult (line 14) | enum ExecutionResult {
  function handle (line 19) | pub async fn handle(
  function poll_update_until_complete (line 543) | async fn poll_update_until_complete(

FILE: bin/cli/src/command/list.rs
  function handle (line 50) | pub async fn handle(list: &args::list::List) -> anyhow::Result<()> {
  function list_all (line 90) | async fn list_all(list: &args::list::List) -> anyhow::Result<()> {
  function list_resources (line 169) | async fn list_resources<T>(
  function list_schedules (line 192) | async fn list_schedules(
  function fix_tags (line 235) | fn fix_tags<T>(
  type ListResources (line 250) | trait ListResources: Sized
    method list (line 255) | async fn list(
    type Info (line 266) | type Info = ServerListItemInfo;
    method list (line 267) | async fn list(
    type Info (line 309) | type Info = StackListItemInfo;
    method list (line 310) | async fn list(
    type Info (line 381) | type Info = DeploymentListItemInfo;
    method list (line 382) | async fn list(
    type Info (line 454) | type Info = BuildListItemInfo;
    method list (line 455) | async fn list(
    type Info (line 522) | type Info = RepoListItemInfo;
    method list (line 523) | async fn list(
    type Info (line 570) | type Info = ProcedureListItemInfo;
    method list (line 571) | async fn list(
    type Info (line 618) | type Info = ActionListItemInfo;
    method list (line 619) | async fn list(
    type Info (line 666) | type Info = ResourceSyncListItemInfo;
    method list (line 667) | async fn list(
    type Info (line 711) | type Info = BuilderListItemInfo;
    method list (line 712) | async fn list(
    type Info (line 743) | type Info = AlerterListItemInfo;
    method list (line 744) | async fn list(
  method header (line 779) | fn header(links: bool) -> &'static [&'static str] {
  method row (line 786) | fn row(self, links: bool) -> Vec<Cell> {
  method header (line 812) | fn header(links: bool) -> &'static [&'static str] {
  method row (line 819) | fn row(self, links: bool) -> Vec<comfy_table::Cell> {
  method header (line 856) | fn header(links: bool) -> &'static [&'static str] {
  method row (line 863) | fn row(self, links: bool) -> Vec<comfy_table::Cell> {
  method header (line 892) | fn header(links: bool) -> &'static [&'static str] {
  method row (line 899) | fn row(self, links: bool) -> Vec<comfy_table::Cell> {
  method header (line 926) | fn header(links: bool) -> &'static [&'static str] {
  method row (line 933) | fn row(self, links: bool) -> Vec<comfy_table::Cell> {
  method header (line 962) | fn header(links: bool) -> &'static [&'static str] {
  method row (line 969) | fn row(self, links: bool) -> Vec<comfy_table::Cell> {
  method header (line 1005) | fn header(links: bool) -> &'static [&'static str] {
  method row (line 1012) | fn row(self, links: bool) -> Vec<comfy_table::Cell> {
  method header (line 1048) | fn header(links: bool) -> &'static [&'static str] {
  method row (line 1055) | fn row(self, links: bool) -> Vec<comfy_table::Cell> {
  method header (line 1083) | fn header(links: bool) -> &'static [&'static str] {
  method row (line 1090) | fn row(self, links: bool) -> Vec<comfy_table::Cell> {
  method header (line 1108) | fn header(links: bool) -> &'static [&'static str] {
  method row (line 1115) | fn row(self, links: bool) -> Vec<comfy_table::Cell> {
  method header (line 1138) | fn header(links: bool) -> &'static [&'static str] {
  method row (line 1145) | fn row(self, links: bool) -> Vec<comfy_table::Cell> {

FILE: bin/cli/src/command/mod.rs
  function komodo_client (line 23) | async fn komodo_client() -> anyhow::Result<&'static KomodoClient> {
  function wait_for_enter (line 43) | fn wait_for_enter(
  function sanitize_uri (line 65) | fn sanitize_uri(uri: &str) -> String {
  function print_items (line 92) | fn print_items<T: PrintTable + Serialize>(
  type PrintTable (line 133) | trait PrintTable {
    method header (line 134) | fn header(links: bool) -> &'static [&'static str];
    method row (line 135) | fn row(self, links: bool) -> Vec<Cell>;
  function parse_wildcards (line 138) | fn parse_wildcards(items: &[String]) -> Vec<Wildcard<'_>> {
  function matches_wildcards (line 149) | fn matches_wildcards(
  function format_timetamp (line 161) | fn format_timetamp(ts: i64) -> anyhow::Result<String> {
  function clamp_sha (line 171) | fn clamp_sha(maybe_sha: &str) -> String {

FILE: bin/cli/src/command/update/mod.rs
  function handle (line 13) | pub async fn handle(command: &UpdateCommand) -> anyhow::Result<()> {

FILE: bin/cli/src/command/update/resource.rs
  function update (line 18) | pub async fn update<
  type ResourceUpdate (line 47) | pub trait ResourceUpdate {
    method resource_type (line 48) | fn resource_type() -> &'static str;
    method apply (line 49) | async fn apply(self, resource: &str) -> anyhow::Result<()>;
    method resource_type (line 53) | fn resource_type() -> &'static str {
    method apply (line 56) | async fn apply(self, resource: &str) -> anyhow::Result<()> {
    method resource_type (line 70) | fn resource_type() -> &'static str {
    method apply (line 73) | async fn apply(self, resource: &str) -> anyhow::Result<()> {
    method resource_type (line 87) | fn resource_type() -> &'static str {
    method apply (line 90) | async fn apply(self, resource: &str) -> anyhow::Result<()> {
    method resource_type (line 104) | fn resource_type() -> &'static str {
    method apply (line 107) | async fn apply(self, resource: &str) -> anyhow::Result<()> {
    method resource_type (line 121) | fn resource_type() -> &'static str {
    method apply (line 124) | async fn apply(self, resource: &str) -> anyhow::Result<()> {
    method resource_type (line 138) | fn resource_type() -> &'static str {
    method apply (line 141) | async fn apply(self, resource: &str) -> anyhow::Result<()> {

FILE: bin/cli/src/command/update/user.rs
  function update (line 14) | pub async fn update(
  function update_password (line 32) | async fn update_password(
  function update_super_admin (line 70) | async fn update_super_admin(

FILE: bin/cli/src/command/update/variable.rs
  function update (line 10) | pub async fn update(

FILE: bin/cli/src/config.rs
  function cli_args (line 18) | pub fn cli_args() -> &'static CliArgs {
  function cli_env (line 23) | pub fn cli_env() -> &'static Env {
  function cli_config (line 37) | pub fn cli_config() -> &'static CliConfig {

FILE: bin/cli/src/main.rs
  function app (line 12) | async fn app() -> anyhow::Result<()> {
  function main (line 64) | async fn main() -> anyhow::Result<()> {

FILE: bin/core/src/alert/discord.rs
  function send_alert (line 8) | pub async fn send_alert(
  function send_message (line 271) | async fn send_message(
  function http_client (line 298) | fn http_client() -> &'static reqwest::Client {
  type DiscordMessageBody (line 304) | struct DiscordMessageBody<'a> {

FILE: bin/core/src/alert/mod.rs
  function send_alerts (line 29) | pub async fn send_alerts(alerts: &[Alert]) {
  function send_alert_to_alerters (line 62) | async fn send_alert_to_alerters(alerters: &[Alerter], alert: &Alert) {
  function send_alert_to_alerter (line 78) | pub async fn send_alert_to_alerter(
  function send_custom_alert (line 166) | async fn send_custom_alert(
  function fmt_region (line 209) | fn fmt_region(region: &Option<String>) -> String {
  function fmt_docker_container_state (line 216) | fn fmt_docker_container_state(state: &DeploymentState) -> String {
  function fmt_stack_state (line 226) | fn fmt_stack_state(state: &StackState) -> String {
  function fmt_level (line 236) | fn fmt_level(level: SeverityLevel) -> &'static str {
  function resource_link (line 244) | fn resource_link(
  function standard_alert_content (line 257) | fn standard_alert_content(alert: &Alert) -> String {

FILE: bin/core/src/alert/ntfy.rs
  function send_alert (line 6) | pub async fn send_alert(
  function send_message (line 18) | async fn send_message(
  function http_client (line 53) | fn http_client() -> &'static reqwest::Client {

FILE: bin/core/src/alert/pushover.rs
  function send_alert (line 6) | pub async fn send_alert(
  function send_message (line 17) | async fn send_message(
  function http_client (line 52) | fn http_client() -> &'static reqwest::Client {

FILE: bin/core/src/alert/slack.rs
  function send_alert (line 4) | pub async fn send_alert(

FILE: bin/core/src/api/auth.rs
  type AuthArgs (line 30) | pub struct AuthArgs {
  type AuthRequest (line 44) | pub enum AuthRequest {
  function router (line 52) | pub fn router() -> Router {
  function variant_handler (line 79) | async fn variant_handler(
  function handler (line 92) | async fn handler(
  function login_options_reponse (line 111) | fn login_options_reponse() -> &'static GetLoginOptionsResponse {
  method resolve (line 129) | async fn resolve(
  method resolve (line 139) | async fn resolve(
  method resolve (line 152) | async fn resolve(

FILE: bin/core/src/api/execute/action.rs
  type Resource (line 52) | type Resource = Action;
  method single_request (line 53) | fn single_request(action: String) -> ExecuteRequest {
  method resolve (line 63) | async fn resolve(
  method resolve (line 76) | async fn resolve(
  function interpolate (line 243) | async fn interpolate(
  function full_contents (line 267) | fn full_contents(
  function cleanup_run (line 328) | async fn cleanup_run(file: String, path: &Path) {
  function deno_dir (line 342) | fn deno_dir() -> Option<&'static Path> {
  function delete_file (line 356) | fn delete_file(
  function parse_action_arguments (line 406) | fn parse_action_arguments(

FILE: bin/core/src/api/execute/alerter.rs
  method resolve (line 26) | async fn resolve(
  method resolve (line 83) | async fn resolve(

FILE: bin/core/src/api/execute/build.rs
  type Resource (line 62) | type Resource = Build;
  method single_request (line 63) | fn single_request(build: String) -> ExecuteRequest {
  method resolve (line 70) | async fn resolve(
  method resolve (line 83) | async fn resolve(
  function handle_early_return (line 398) | async fn handle_early_return(
  function validate_cancel_build (line 444) | pub async fn validate_cancel_build(
  method resolve (line 492) | async fn resolve(
  function handle_post_build_redeploy (line 552) | async fn handle_post_build_redeploy(build_id: &str) {
  function validate_account_extract_registry_tokens (line 613) | async fn validate_account_extract_registry_tokens(

FILE: bin/core/src/api/execute/deployment.rs
  type Resource (line 41) | type Resource = Deployment;
  method single_request (line 42) | fn single_request(deployment: String) -> ExecuteRequest {
  method resolve (line 53) | async fn resolve(
  function setup_deployment_execution (line 64) | async fn setup_deployment_execution(
  method resolve (line 91) | async fn resolve(
  constant PULL_TIMEOUT (line 235) | const PULL_TIMEOUT: i64 = 5_000;
  type ServerId (line 236) | type ServerId = String;
  type Image (line 237) | type Image = String;
  type PullCache (line 238) | type PullCache = TimeoutCache<(ServerId, Image), Log>;
  function pull_cache (line 240) | fn pull_cache() -> &'static PullCache {
  function pull_deployment_inner (line 245) | pub async fn pull_deployment_inner(
  method resolve (line 360) | async fn resolve(
  method resolve (line 394) | async fn resolve(
  method resolve (line 441) | async fn resolve(
  method resolve (line 490) | async fn resolve(
  method resolve (line 537) | async fn resolve(
  method resolve (line 586) | async fn resolve(
  type Resource (line 640) | type Resource = Deployment;
  method single_request (line 641) | fn single_request(deployment: String) -> ExecuteRequest {
  method resolve (line 652) | async fn resolve(
  method resolve (line 668) | async fn resolve(

FILE: bin/core/src/api/execute/maintenance.rs
  function clear_repo_cache_lock (line 34) | fn clear_repo_cache_lock() -> &'static Mutex<()> {
  method resolve (line 45) | async fn resolve(
  function backup_database_lock (line 109) | fn backup_database_lock() -> &'static Mutex<()> {
  method resolve (line 120) | async fn resolve(
  function global_update_lock (line 158) | fn global_update_lock() -> &'static Mutex<()> {
  method resolve (line 169) | async fn resolve(

FILE: bin/core/src/api/execute/mod.rs
  type ExecuteArgs (line 53) | pub struct ExecuteArgs {
  type ExecuteRequest (line 67) | pub enum ExecuteRequest {
  function router (line 154) | pub fn router() -> Router {
  function variant_handler (line 161) | async fn variant_handler(
  function handler (line 173) | async fn handler(
  type BoxUpdate (line 186) | type BoxUpdate = Box<Update>;
  type ExecutionResult (line 188) | pub enum ExecutionResult {
  function inner_handler (line 194) | pub fn inner_handler(
  function task (line 283) | async fn task(
  type BatchExecute (line 311) | trait BatchExecute {
    method single_request (line 313) | fn single_request(name: String) -> ExecuteRequest;
  function batch_execute (line 316) | async fn batch_execute<E: BatchExecute>(

FILE: bin/core/src/api/execute/procedure.rs
  type Resource (line 34) | type Resource = Procedure;
  method single_request (line 35) | fn single_request(procedure: String) -> ExecuteRequest {
  method resolve (line 42) | async fn resolve(
  method resolve (line 55) | async fn resolve(
  function resolve_inner (line 66) | fn resolve_inner(

FILE: bin/core/src/api/execute/repo.rs
  type Resource (line 47) | type Resource = Repo;
  method single_request (line 48) | fn single_request(repo: String) -> ExecuteRequest {
  method resolve (line 55) | async fn resolve(
  method resolve (line 68) | async fn resolve(
  type Resource (line 161) | type Resource = Repo;
  method single_request (line 162) | fn single_request(repo: String) -> ExecuteRequest {
  method resolve (line 169) | async fn resolve(
  method resolve (line 182) | async fn resolve(
  function handle_repo_update_return (line 279) | async fn handle_repo_update_return(
  function update_last_pulled_time (line 301) | async fn update_last_pulled_time(repo_name: &str) {
  type Resource (line 317) | type Resource = Repo;
  method single_request (line 318) | fn single_request(repo: String) -> ExecuteRequest {
  method resolve (line 325) | async fn resolve(
  method resolve (line 338) | async fn resolve(
  function handle_builder_early_return (line 557) | async fn handle_builder_early_return(
  function validate_cancel_repo_build (line 602) | pub async fn validate_cancel_repo_build(
  method resolve (line 652) | async fn resolve(
  function interpolate (line 711) | async fn interpolate(

FILE: bin/core/src/api/execute/server.rs
  method resolve (line 26) | async fn resolve(
  method resolve (line 80) | async fn resolve(
  method resolve (line 136) | async fn resolve(
  method resolve (line 190) | async fn resolve(
  method resolve (line 246) | async fn resolve(
  method resolve (line 302) | async fn resolve(
  method resolve (line 364) | async fn resolve(
  method resolve (line 414) | async fn resolve(
  method resolve (line 466) | async fn resolve(
  method resolve (line 516) | async fn resolve(
  method resolve (line 568) | async fn resolve(
  method resolve (line 618) | async fn resolve(
  method resolve (line 674) | async fn resolve(
  method resolve (line 725) | async fn resolve(
  method resolve (line 779) | async fn resolve(
  method resolve (line 827) | async fn resolve(
  method resolve (line 879) | async fn resolve(
  method resolve (line 930) | async fn resolve(
  method resolve (line 982) | async fn resolve(
  method resolve (line 1034) | async fn resolve(
  method resolve (line 1086) | async fn resolve(

FILE: bin/core/src/api/execute/stack.rs
  type Resource (line 46) | type Resource = Stack;
  method single_request (line 47) | fn single_request(stack: String) -> ExecuteRequest {
  method resolve (line 58) | async fn resolve(
  method resolve (line 71) | async fn resolve(
  type Resource (line 273) | type Resource = Stack;
  method single_request (line 274) | fn single_request(stack: String) -> ExecuteRequest {
  method resolve (line 284) | async fn resolve(
  method resolve (line 300) | async fn resolve(
  function deploy_services (line 469) | async fn deploy_services(
  function restart_services (line 494) | async fn restart_services(
  function update_deployed_contents_with_latest (line 528) | async fn update_deployed_contents_with_latest(
  type DeployIfChangedAction (line 569) | enum DeployIfChangedAction {
  function resolve_deploy_if_changed_action (line 588) | fn resolve_deploy_if_changed_action(
  type Resource (line 655) | type Resource = Stack;
  method single_request (line 656) | fn single_request(stack: String) -> ExecuteRequest {
  method resolve (line 666) | async fn resolve(
  function maybe_pull_stack (line 677) | async fn maybe_pull_stack(
  function pull_stack_inner (line 702) | pub async fn pull_stack_inner(
  method resolve (line 771) | async fn resolve(
  method resolve (line 824) | async fn resolve(
  method resolve (line 843) | async fn resolve(
  method resolve (line 864) | async fn resolve(
  method resolve (line 883) | async fn resolve(
  method resolve (line 902) | async fn resolve(
  type Resource (line 920) | type Resource = Stack;
  method single_request (line 921) | fn single_request(stack: String) -> ExecuteRequest {
  method resolve (line 933) | async fn resolve(
  method resolve (line 945) | async fn resolve(
  method resolve (line 964) | async fn resolve(

FILE: bin/core/src/api/execute/sync.rs
  method resolve (line 53) | async fn resolve(
  function maybe_extend (line 536) | fn maybe_extend(logs: &mut Vec<Log>, log: Option<Log>) {

FILE: bin/core/src/api/mod.rs
  type Variant (line 9) | struct Variant {

FILE: bin/core/src/api/read/action.rs
  method resolve (line 23) | async fn resolve(
  method resolve (line 39) | async fn resolve(
  method resolve (line 61) | async fn resolve(
  method resolve (line 83) | async fn resolve(
  method resolve (line 104) | async fn resolve(

FILE: bin/core/src/api/read/alert.rs
  constant NUM_ALERTS_PER_PAGE (line 25) | const NUM_ALERTS_PER_PAGE: u64 = 100;
  method resolve (line 28) | async fn resolve(
  method resolve (line 77) | async fn resolve(

FILE: bin/core/src/api/read/alerter.rs
  method resolve (line 21) | async fn resolve(
  method resolve (line 37) | async fn resolve(
  method resolve (line 59) | async fn resolve(
  method resolve (line 81) | async fn resolve(

FILE: bin/core/src/api/read/build.rs
  method resolve (line 35) | async fn resolve(
  method resolve (line 51) | async fn resolve(
  method resolve (line 73) | async fn resolve(
  method resolve (line 95) | async fn resolve(
  method resolve (line 116) | async fn resolve(
  constant ONE_DAY_MS (line 161) | const ONE_DAY_MS: i64 = 86400000;
  method resolve (line 164) | async fn resolve(
  constant MS_TO_HOUR_DIVISOR (line 214) | const MS_TO_HOUR_DIVISOR: f64 = 1000.0 * 60.0 * 60.0;
  function ms_to_hour (line 215) | fn ms_to_hour(duration: i64) -> f64 {
  method resolve (line 220) | async fn resolve(
  method resolve (line 277) | async fn resolve(
  method resolve (line 311) | async fn resolve(

FILE: bin/core/src/api/read/builder.rs
  method resolve (line 21) | async fn resolve(
  method resolve (line 37) | async fn resolve(
  method resolve (line 59) | async fn resolve(
  method resolve (line 81) | async fn resolve(

FILE: bin/core/src/api/read/deployment.rs
  method resolve (line 32) | async fn resolve(
  method resolve (line 48) | async fn resolve(
  method resolve (line 78) | async fn resolve(
  method resolve (line 100) | async fn resolve(
  constant MAX_LOG_LENGTH (line 122) | const MAX_LOG_LENGTH: u64 = 5000;
  method resolve (line 125) | async fn resolve(
  method resolve (line 161) | async fn resolve(
  method resolve (line 201) | async fn resolve(
  method resolve (line 245) | async fn resolve(
  method resolve (line 274) | async fn resolve(
  method resolve (line 295) | async fn resolve(
  method resolve (line 336) | async fn resolve(

FILE: bin/core/src/api/read/mod.rs
  type ReadArgs (line 57) | pub struct ReadArgs {
  type ReadRequest (line 67) | enum ReadRequest {
  function router (line 229) | pub fn router() -> Router {
  function variant_handler (line 236) | async fn variant_handler(
  function handler (line 249) | async fn handler(
  method resolve (line 266) | async fn resolve(
  function core_info (line 276) | fn core_info() -> &'static GetCoreInfoResponse {
  method resolve (line 306) | async fn resolve(
  method resolve (line 315) | async fn resolve(
  method resolve (line 367) | async fn resolve(
  method resolve (line 469) | async fn resolve(
  function merge_git_providers_for_server (line 513) | async fn merge_git_providers_for_server(
  function merge_git_providers (line 531) | fn merge_git_providers(
  function merge_docker_registries_for_server (line 551) | async fn merge_docker_registries_for_server(
  function merge_docker_registries (line 569) | fn merge_docker_registries(

FILE: bin/core/src/api/read/permission.rs
  method resolve (line 20) | async fn resolve(
  method resolve (line 39) | async fn resolve(
  method resolve (line 51) | async fn resolve(

FILE: bin/core/src/api/read/procedure.rs
  method resolve (line 21) | async fn resolve(
  method resolve (line 37) | async fn resolve(
  method resolve (line 59) | async fn resolve(
  method resolve (line 81) | async fn resolve(
  method resolve (line 127) | async fn resolve(

FILE: bin/core/src/api/read/provider.rs
  method resolve (line 15) | async fn resolve(
  method resolve (line 35) | async fn resolve(
  method resolve (line 65) | async fn resolve(
  method resolve (line 87) | async fn resolve(

FILE: bin/core/src/api/read/repo.rs
  method resolve (line 23) | async fn resolve(
  method resolve (line 39) | async fn resolve(
  method resolve (line 61) | async fn resolve(
  method resolve (line 83) | async fn resolve(
  method resolve (line 104) | async fn resolve(
  method resolve (line 160) | async fn resolve(

FILE: bin/core/src/api/read/schedule.rs
  method resolve (line 24) | async fn resolve(

FILE: bin/core/src/api/read/server.rs
  method resolve (line 63) | async fn resolve(
  method resolve (line 106) | async fn resolve(
  method resolve (line 126) | async fn resolve(
  method resolve (line 142) | async fn resolve(
  method resolve (line 164) | async fn resolve(
  method resolve (line 186) | async fn resolve(
  method resolve (line 208) | async fn resolve(
  method resolve (line 229) | async fn resolve(
  method resolve (line 244) | async fn resolve(
  constant PROCESSES_EXPIRY (line 267) | const PROCESSES_EXPIRY: u128 = FIFTEEN_SECONDS_MS;
  type ProcessesCache (line 268) | type ProcessesCache =
  function processes_cache (line 270) | fn processes_cache() -> &'static ProcessesCache {
  method resolve (line 276) | async fn resolve(
  constant STATS_PER_PAGE (line 307) | const STATS_PER_PAGE: i64 = 200;
  method resolve (line 310) | async fn resolve(
  method resolve (line 363) | async fn resolve(
  method resolve (line 385) | async fn resolve(
  method resolve (line 419) | async fn resolve(
  method resolve (line 459) | async fn resolve(
  constant MAX_LOG_LENGTH (line 490) | const MAX_LOG_LENGTH: u64 = 5000;
  method resolve (line 493) | async fn resolve(
  method resolve (line 522) | async fn resolve(
  method resolve (line 555) | async fn resolve(
  method resolve (line 616) | async fn resolve(
  method resolve (line 638) | async fn resolve(
  method resolve (line 668) | async fn resolve(
  method resolve (line 690) | async fn resolve(
  method resolve (line 717) | async fn resolve(
  method resolve (line 747) | async fn resolve(
  method resolve (line 769) | async fn resolve(
  method resolve (line 796) | async fn resolve(
  type TerminalCacheItem (line 818) | struct TerminalCacheItem {
  constant TERMINAL_CACHE_TIMEOUT (line 823) | const TERMINAL_CACHE_TIMEOUT: i64 = 30_000;
  type TerminalCache (line 826) | struct TerminalCache(
    method get_or_insert (line 833) | fn get_or_insert(
  function terminals_cache (line 849) | fn terminals_cache() -> &'static TerminalCache {
  method resolve (line 855) | async fn resolve(

FILE: bin/core/src/api/read/stack.rs
  method resolve (line 35) | async fn resolve(
  method resolve (line 51) | async fn resolve(
  method resolve (line 75) | async fn resolve(
  method resolve (line 106) | async fn resolve(
  method resolve (line 141) | async fn resolve(
  method resolve (line 195) | async fn resolve(
  method resolve (line 229) | async fn resolve(
  method resolve (line 263) | async fn resolve(
  method resolve (line 299) | async fn resolve(
  method resolve (line 321) | async fn resolve(
  method resolve (line 342) | async fn resolve(
  method resolve (line 376) | async fn resolve(

FILE: bin/core/src/api/read/sync.rs
  method resolve (line 25) | async fn resolve(
  method resolve (line 41) | async fn resolve(
  method resolve (line 63) | async fn resolve(
  method resolve (line 85) | async fn resolve(
  method resolve (line 106) | async fn resolve(
  method resolve (line 159) | async fn resolve(

FILE: bin/core/src/api/read/tag.rs
  method resolve (line 17) | async fn resolve(self, _: &ReadArgs) -> serror::Result<Tag> {
  method resolve (line 23) | async fn resolve(self, _: &ReadArgs) -> serror::Result<Vec<Tag>> {

FILE: bin/core/src/api/read/toml.rs
  function get_all_targets (line 35) | async fn get_all_targets(
  method resolve (line 160) | async fn resolve(
  method resolve (line 196) | async fn resolve(
  function add_user_groups (line 396) | async fn add_user_groups(
  function serialize_resources_toml (line 416) | fn serialize_resources_toml(

FILE: bin/core/src/api/read/update.rs
  constant UPDATES_PER_PAGE (line 38) | const UPDATES_PER_PAGE: i64 = 100;
  method resolve (line 41) | async fn resolve(
  method resolve (line 214) | async fn resolve(

FILE: bin/core/src/api/read/user.rs
  method resolve (line 23) | async fn resolve(
  method resolve (line 53) | async fn resolve(
  method resolve (line 65) | async fn resolve(
  method resolve (line 87) | async fn resolve(
  method resolve (line 109) | async fn resolve(

FILE: bin/core/src/api/read/user_group.rs
  method resolve (line 19) | async fn resolve(
  method resolve (line 43) | async fn resolve(

FILE: bin/core/src/api/read/variable.rs
  method resolve (line 14) | async fn resolve(
  method resolve (line 28) | async fn resolve(

FILE: bin/core/src/api/terminal.rs
  function router (line 19) | pub fn router() -> Router {
  function execute_terminal (line 32) | async fn execute_terminal(
  function execute_terminal_inner (line 46) | async fn execute_terminal_inner(
  function execute_container_exec (line 91) | async fn execute_container_exec(
  function execute_container_exec_inner (line 105) | async fn execute_container_exec_inner(
  function execute_deployment_exec (line 158) | async fn execute_deployment_exec(
  function execute_deployment_exec_inner (line 172) | async fn execute_deployment_exec_inner(
  function execute_stack_exec (line 226) | async fn execute_stack_exec(
  function execute_stack_exec_inner (line 240) | async fn execute_stack_exec_inner(

FILE: bin/core/src/api/user.rs
  type UserArgs (line 31) | pub struct UserArgs {
  type UserRequest (line 43) | enum UserRequest {
  function router (line 50) | pub fn router() -> Router {
  function variant_handler (line 57) | async fn variant_handler(
  function handler (line 70) | async fn handler(
  constant RECENTLY_VIEWED_MAX (line 89) | const RECENTLY_VIEWED_MAX: usize = 10;
  method resolve (line 97) | async fn resolve(
  method resolve (line 139) | async fn resolve(
  constant SECRET_LENGTH (line 157) | const SECRET_LENGTH: usize = 40;
  constant BCRYPT_COST (line 158) | const BCRYPT_COST: u32 = 10;
  method resolve (line 162) | async fn resolve(
  method resolve (line 192) | async fn resolve(

FILE: bin/core/src/api/write/action.rs
  method resolve (line 15) | async fn resolve(
  method resolve (line 25) | async fn resolve(
  method resolve (line 41) | async fn resolve(
  method resolve (line 51) | async fn resolve(
  method resolve (line 61) | async fn resolve(self, args: &WriteArgs) -> serror::Result<Action> {

FILE: bin/core/src/api/write/alerter.rs
  method resolve (line 15) | async fn resolve(
  method resolve (line 25) | async fn resolve(
  method resolve (line 41) | async fn resolve(
  method resolve (line 51) | async fn resolve(
  method resolve (line 64) | async fn resolve(

FILE: bin/core/src/api/write/build.rs
  method resolve (line 49) | async fn resolve(
  method resolve (line 59) | async fn resolve(
  method resolve (line 77) | async fn resolve(self, args: &WriteArgs) -> serror::Result<Build> {
  method resolve (line 84) | async fn resolve(
  method resolve (line 94) | async fn resolve(
  method resolve (line 104) | async fn resolve(self, args: &WriteArgs) -> serror::Result<Update> {
  function write_dockerfile_contents_git (line 175) | async fn write_dockerfile_contents_git(
  method resolve (line 325) | async fn resolve(
  function get_on_host_periphery (line 415) | async fn get_on_host_periphery(
  function get_on_host_dockerfile (line 459) | async fn get_on_host_dockerfile(
  function get_git_remote (line 472) | async fn get_git_remote(
  method resolve (line 535) | async fn resolve(
  method resolve (line 650) | async fn resolve(

FILE: bin/core/src/api/write/builder.rs
  method resolve (line 15) | async fn resolve(
  method resolve (line 25) | async fn resolve(
  method resolve (line 41) | async fn resolve(
  method resolve (line 51) | async fn resolve(
  method resolve (line 64) | async fn resolve(

FILE: bin/core/src/api/write/deployment.rs
  method resolve (line 37) | async fn resolve(
  method resolve (line 48) | async fn resolve(
  method resolve (line 66) | async fn resolve(
  method resolve (line 158) | async fn resolve(
  method resolve (line 168) | async fn resolve(
  method resolve (line 181) | async fn resolve(

FILE: bin/core/src/api/write/mod.rs
  type WriteArgs (line 40) | pub struct WriteArgs {
  type WriteRequest (line 53) | pub enum WriteRequest {
  function router (line 197) | pub fn router() -> Router {
  function variant_handler (line 204) | async fn variant_handler(
  function handler (line 216) | async fn handler(
  function task (line 237) | async fn task(

FILE: bin/core/src/api/write/permissions.rs
  method resolve (line 26) | async fn resolve(
  method resolve (line 64) | async fn resolve(
  method resolve (line 121) | async fn resolve(
  method resolve (line 189) | async fn resolve(
  function extract_user_target_with_validation (line 259) | async fn extract_user_target_with_validation(
  function extract_resource_target_with_validation (line 295) | async fn extract_resource_target_with_validation(

FILE: bin/core/src/api/write/procedure.rs
  method resolve (line 15) | async fn resolve(
  method resolve (line 25) | async fn resolve(
  method resolve (line 43) | async fn resolve(
  method resolve (line 56) | async fn resolve(
  method resolve (line 69) | async fn resolve(

FILE: bin/core/src/api/write/provider.rs
  method resolve (line 23) | async fn resolve(
  method resolve (line 82) | async fn resolve(
  method resolve (line 162) | async fn resolve(
  method resolve (line 212) | async fn resolve(
  method resolve (line 275) | async fn resolve(
  method resolve (line 362) | async fn resolve(

FILE: bin/core/src/api/write/repo.rs
  method resolve (line 41) | async fn resolve(
  method resolve (line 51) | async fn resolve(
  method resolve (line 67) | async fn resolve(self, args: &WriteArgs) -> serror::Result<Repo> {
  method resolve (line 74) | async fn resolve(
  method resolve (line 84) | async fn resolve(
  method resolve (line 164) | async fn resolve(
  method resolve (line 238) | async fn resolve(
  method resolve (line 361) | async fn resolve(

FILE: bin/core/src/api/write/resource.rs
  method resolve (line 18) | async fn resolve(

FILE: bin/core/src/api/write/server.rs
  method resolve (line 29) | async fn resolve(
  method resolve (line 39) | async fn resolve(
  method resolve (line 56) | async fn resolve(self, args: &WriteArgs) -> serror::Result<Server> {
  method resolve (line 63) | async fn resolve(
  method resolve (line 73) | async fn resolve(
  method resolve (line 83) | async fn resolve(
  method resolve (line 124) | async fn resolve(
  method resolve (line 152) | async fn resolve(
  method resolve (line 178) | async fn resolve(

FILE: bin/core/src/api/write/service_user.rs
  method resolve (line 23) | async fn resolve(
  method resolve (line 67) | async fn resolve(
  method resolve (line 103) | async fn resolve(
  method resolve (line 129) | async fn resolve(

FILE: bin/core/src/api/write/stack.rs
  method resolve (line 50) | async fn resolve(
  method resolve (line 60) | async fn resolve(
  method resolve (line 77) | async fn resolve(self, args: &WriteArgs) -> serror::Result<Stack> {
  method resolve (line 84) | async fn resolve(
  method resolve (line 94) | async fn resolve(
  method resolve (line 104) | async fn resolve(
  function write_stack_file_contents_on_host (line 152) | async fn write_stack_file_contents_on_host(
  function write_stack_file_contents_git (line 223) | async fn write_stack_file_contents_git(
  method resolve (line 369) | async fn resolve(
  method resolve (line 569) | async fn resolve(
  method resolve (line 691) | async fn resolve(

FILE: bin/core/src/api/write/sync.rs
  method resolve (line 67) | async fn resolve(
  method resolve (line 78) | async fn resolve(
  method resolve (line 96) | async fn resolve(
  method resolve (line 106) | async fn resolve(
  method resolve (line 119) | async fn resolve(
  method resolve (line 132) | async fn resolve(self, args: &WriteArgs) -> serror::Result<Update> {
  function write_sync_file_contents_on_host (line 176) | async fn write_sync_file_contents_on_host(
  function write_sync_file_contents_git (line 246) | async fn write_sync_file_contents_git(
  method resolve (line 398) | async fn resolve(self, args: &WriteArgs) -> serror::Result<Update> {
  function commit_git_sync (line 582) | async fn commit_git_sync(
  method resolve (line 631) | async fn resolve(
  method resolve (line 978) | async fn resolve(
  method resolve (line 1099) | async fn resolve(

FILE: bin/core/src/api/write/tag.rs
  method resolve (line 31) | async fn resolve(
  method resolve (line 72) | async fn resolve(
  method resolve (line 97) | async fn resolve(
  method resolve (line 118) | async fn resolve(

FILE: bin/core/src/api/write/user.rs
  method resolve (line 28) | async fn resolve(
  method resolve (line 105) | async fn resolve(
  method resolve (line 156) | async fn resolve(
  method resolve (line 179) | async fn resolve(

FILE: bin/core/src/api/write/user_group.rs
  method resolve (line 23) | async fn resolve(
  method resolve (line 61) | async fn resolve(
  method resolve (line 90) | async fn resolve(
  method resolve (line 126) | async fn resolve(
  method resolve (line 173) | async fn resolve(
  method resolve (line 220) | async fn resolve(
  method resolve (line 270) | async fn resolve(

FILE: bin/core/src/api/write/variable.rs
  method resolve (line 23) | async fn resolve(
  method resolve (line 72) | async fn resolve(
  method resolve (line 129) | async fn resolve(
  method resolve (line 153) | async fn resolve(
  method resolve (line 176) | async fn resolve(

FILE: bin/core/src/auth/github/client.rs
  function github_oauth_client (line 16) | pub fn github_oauth_client() -> &'static Option<GithubOauthClient> {
  type GithubOauthClient (line 23) | pub struct GithubOauthClient {
    method new (line 34) | pub fn new(
    method get_login_redirect_url (line 80) | pub async fn get_login_redirect_url(
    method check_state (line 99) | pub async fn check_state(&self, state: &str) -> bool {
    method get_access_token (line 113) | pub async fn get_access_token(
    method get_github_user (line 134) | pub async fn get_github_user(
    method get (line 145) | async fn get<R: DeserializeOwned>(
    method post (line 180) | async fn post<B: Serialize, R: DeserializeOwned>(
  type AccessTokenResponse (line 223) | pub struct AccessTokenResponse {
  type GithubUserResponse (line 230) | pub struct GithubUserResponse {

FILE: bin/core/src/auth/github/mod.rs
  function router (line 27) | pub fn router() -> Router {
  type CallbackQuery (line 51) | struct CallbackQuery {
  function callback (line 57) | async fn callback(

FILE: bin/core/src/auth/google/client.rs
  function google_oauth_client (line 17) | pub fn google_oauth_client() -> &'static Option<GoogleOauthClient> {
  type GoogleOauthClient (line 24) | pub struct GoogleOauthClient {
    method new (line 35) | pub fn new(
    method get_login_redirect_url (line 89) | pub async fn get_login_redirect_url(
    method check_state (line 108) | pub async fn check_state(&self, state: &str) -> bool {
    method get_access_token (line 122) | pub async fn get_access_token(
    method get_google_user (line 143) | pub fn get_google_user(
    method post (line 160) | async fn post<R: DeserializeOwned>(
  type AccessTokenResponse (line 198) | pub struct AccessTokenResponse {
  type GoogleUser (line 206) | pub struct GoogleUser {

FILE: bin/core/src/auth/google/mod.rs
  function router (line 25) | pub fn router() -> Router {
  type CallbackQuery (line 49) | struct CallbackQuery {
  function callback (line 56) | async fn callback(

FILE: bin/core/src/auth/jwt.rs
  type ExchangeTokenMap (line 19) | type ExchangeTokenMap = Mutex<HashMap<String, (JwtResponse, u128)>>;
  type JwtClaims (line 22) | pub struct JwtClaims {
  type JwtClient (line 28) | pub struct JwtClient {
    method new (line 38) | pub fn new(config: &CoreConfig) -> anyhow::Result<JwtClient> {
    method encode (line 56) | pub fn encode(
    method decode (line 72) | pub fn decode(&self, jwt: &str) -> anyhow::Result<JwtClaims> {
    method create_exchange_token (line 79) | pub async fn create_exchange_token(
    method redeem_exchange_token (line 95) | pub async fn redeem_exchange_token(

FILE: bin/core/src/auth/local.rs
  method resolve (line 26) | async fn resolve(
  method resolve (line 108) | async fn resolve(

FILE: bin/core/src/auth/mod.rs
  constant STATE_PREFIX_LENGTH (line 27) | const STATE_PREFIX_LENGTH: usize = 20;
  type RedirectQuery (line 30) | struct RedirectQuery {
  function auth_request (line 35) | pub async fn auth_request(
  function get_user_id_from_headers (line 48) | pub async fn get_user_id_from_headers(
  function authenticate_check_enabled (line 81) | pub async fn authenticate_check_enabled(
  function auth_jwt_get_user_id (line 94) | pub async fn auth_jwt_get_user_id(
  function auth_jwt_check_enabled (line 106) | pub async fn auth_jwt_check_enabled(
  function auth_api_key_get_user_id (line 114) | pub async fn auth_api_key_get_user_id(
  function auth_api_key_check_enabled (line 139) | pub async fn auth_api_key_check_enabled(
  function check_enabled (line 148) | async fn check_enabled(user_id: String) -> anyhow::Result<User> {

FILE: bin/core/src/auth/oidc/client.rs
  type OidcClient (line 13) | type OidcClient = Client<
  function oidc_client (line 33) | pub fn oidc_client() -> &'static ArcSwapOption<OidcClient> {
  function spawn_oidc_client_management (line 43) | pub async fn spawn_oidc_client_management() {
  function reset_oidc_client (line 64) | async fn reset_oidc_client() -> anyhow::Result<()> {

FILE: bin/core/src/auth/oidc/mod.rs
  function reqwest_client (line 37) | fn reqwest_client() -> &'static reqwest::Client {
  constant CSRF_VALID_FOR_MS (line 50) | const CSRF_VALID_FOR_MS: i64 = 120_000;
  type RedirectUrl (line 52) | type RedirectUrl = Option<String>;
  type VerifierMap (line 55) | type VerifierMap =
  function verifier_tokens (line 57) | fn verifier_tokens() -> &'static VerifierMap {
  function router (line 62) | pub fn router() -> Router {
  function login (line 79) | async fn login(
  type CallbackQuery (line 135) | struct CallbackQuery {
  function callback (line 142) | async fn callback(

FILE: bin/core/src/cloud/aws/ec2.rs
  constant POLL_RATE_SECS (line 24) | const POLL_RATE_SECS: u64 = 2;
  constant MAX_POLL_TRIES (line 25) | const MAX_POLL_TRIES: usize = 30;
  type Ec2Instance (line 27) | pub struct Ec2Instance {
  type CredentialsFromConfig (line 34) | struct CredentialsFromConfig;
    method provide_credentials (line 39) | fn provide_credentials<'a>(
  function create_ec2_client (line 61) | async fn create_ec2_client(region: String) -> Client {
  function launch_ec2_instance (line 72) | pub async fn launch_ec2_instance(
  constant MAX_TERMINATION_TRIES (line 168) | const MAX_TERMINATION_TRIES: usize = 5;
  constant TERMINATION_WAIT_SECS (line 169) | const TERMINATION_WAIT_SECS: u64 = 15;
  function terminate_ec2_instance_with_retry (line 172) | pub async fn terminate_ec2_instance_with_retry(
  function terminate_ec2_instance_inner (line 212) | async fn terminate_ec2_instance_inner(
  function get_ec2_instance_status (line 231) | async fn get_ec2_instance_status(
  function get_ec2_instance_state_name (line 263) | async fn get_ec2_instance_state_name(
  function get_ec2_instance_public_ip (line 283) | async fn get_ec2_instance_public_ip(
  function handle_unknown_instance_type (line 320) | fn handle_unknown_instance_type(

FILE: bin/core/src/cloud/mod.rs
  type BuildCleanupData (line 4) | pub enum BuildCleanupData {

FILE: bin/core/src/config.rs
  function core_config (line 20) | pub fn core_config() -> &'static CoreConfig {

FILE: bin/core/src/helpers/action_state.rs
  type ActionStates (line 18) | pub struct ActionStates {
  type ActionState (line 33) | pub struct ActionState<States: Default + Send + 'static>(
  function get (line 40) | pub fn get(&self) -> anyhow::Result<States> {
  function busy (line 49) | pub fn busy(&self) -> anyhow::Result<bool> {
  function update (line 62) | pub fn update(
  function update_custom (line 76) | pub fn update_custom(
  type UpdateGuard (line 98) | pub struct UpdateGuard<'a, States: Default + Send + 'static>(
  method drop (line 106) | fn drop(&mut self) {

FILE: bin/core/src/helpers/all_resources.rs
  type AllResourcesById (line 10) | pub struct AllResourcesById {
    method load (line 25) | pub async fn load() -> anyhow::Result<Self> {

FILE: bin/core/src/helpers/builder.rs
  constant BUILDER_POLL_RATE_SECS (line 32) | const BUILDER_POLL_RATE_SECS: u64 = 2;
  constant BUILDER_POLL_MAX_TRIES (line 33) | const BUILDER_POLL_MAX_TRIES: usize = 60;
  function get_builder_periphery (line 36) | pub async fn get_builder_periphery(
  function get_aws_builder (line 80) | async fn get_aws_builder(
  function cleanup_builder_instance (line 168) | pub async fn cleanup_builder_instance(
  function start_aws_builder_log (line 194) | pub fn start_aws_builder_log(

FILE: bin/core/src/helpers/cache.rs
  type Cache (line 6) | pub struct Cache<K: PartialEq + Eq + Hash, T: Clone + Default> {
  function get (line 16) | pub async fn get(&self, key: &K) -> Option<T> {
  function get_or_insert_default (line 21) | pub async fn get_or_insert_default(&self, key: &K) -> T {
  function get_list (line 34) | pub async fn get_list(&self) -> Vec<T> {
  function insert (line 40) | pub async fn insert<Key>(&self, key: Key, val: T)
  function remove (line 66) | pub async fn remove(&self, key: &K) {

FILE: bin/core/src/helpers/channel.rs
  function build_cancel_channel (line 7) | pub fn build_cancel_channel()
  function repo_cancel_channel (line 16) | pub fn repo_cancel_channel()
  function update_channel (line 24) | pub fn update_channel() -> &'static BroadcastChannel<UpdateListItem> {
  type BroadcastChannel (line 30) | pub struct BroadcastChannel<T> {
  function new (line 36) | pub fn new(capacity: usize) -> BroadcastChannel<T> {

FILE: bin/core/src/helpers/maintenance.rs
  function is_in_maintenance (line 12) | pub fn is_in_maintenance(
  function is_maintenance_window_active (line 22) | pub fn is_maintenance_window_active(
  function is_time_in_window (line 82) | fn is_time_in_window(
  function convert_day_of_week (line 104) | fn convert_day_of_week(value: chrono::Weekday) -> DayOfWeek {

FILE: bin/core/src/helpers/matcher.rs
  type Matcher (line 3) | pub enum Matcher<'a> {
  function new (line 9) | pub fn new(pattern: &'a str) -> anyhow::Result<Self> {
  function is_match (line 24) | pub fn is_match(&self, source: &str) -> bool {

FILE: bin/core/src/helpers/mod.rs
  function empty_or_only_spaces (line 37) | pub fn empty_or_only_spaces(word: &str) -> bool {
  function random_string (line 49) | pub fn random_string(length: usize) -> String {
  function git_token (line 60) | pub async fn git_token(
  function stack_git_token (line 93) | pub async fn stack_git_token(
  function build_git_token (line 125) | pub async fn build_git_token(
  function registry_token (line 159) | pub async fn registry_token(
  function periphery_client (line 188) | pub fn periphery_client(
  function create_permission (line 209) | pub async fn create_permission<T>(
  function flatten_document (line 241) | pub fn flatten_document(doc: Document) -> Document {
  function repo_link (line 257) | pub fn repo_link(

FILE: bin/core/src/helpers/procedure.rs
  function execute_procedure (line 36) | pub async fn execute_procedure(
  function execute_stage (line 91) | async fn execute_stage(
  function execute_execution (line 221) | async fn execute_execution(
  function handle_resolve_result (line 1234) | async fn handle_resolve_result(
  function add_line_to_update (line 1258) | async fn add_line_to_update(update: &Mutex<Update>, line: &str) {
  function extend_batch_exection (line 1270) | async fn extend_batch_exection<E: ExtendBatch>(
  type ExtendBatch (line 1288) | trait ExtendBatch {
    method single_execution (line 1290) | fn single_execution(name: String) -> Execution;
    type Resource (line 1294) | type Resource = Procedure;
    method single_execution (line 1295) | fn single_execution(procedure: String) -> Execution {
    type Resource (line 1301) | type Resource = Action;
    method single_execution (line 1302) | fn single_execution(action: String) -> Execution {
    type Resource (line 1311) | type Resource = Build;
    method single_execution (line 1312) | fn single_execution(build: String) -> Execution {
    type Resource (line 1318) | type Resource = Repo;
    method single_execution (line 1319) | fn single_execution(repo: String) -> Execution {
    type Resource (line 1325) | type Resource = Repo;
    method single_execution (line 1326) | fn single_execution(repo: String) -> Execution {
    type Resource (line 1332) | type Resource = Repo;
    method single_execution (line 1333) | fn single_execution(repo: String) -> Execution {
    type Resource (line 1339) | type Resource = Deployment;
    method single_execution (line 1340) | fn single_execution(deployment: String) -> Execution {
    type Resource (line 1350) | type Resource = Deployment;
    method single_execution (line 1351) | fn single_execution(deployment: String) -> Execution {
    type Resource (line 1361) | type Resource = Stack;
    method single_execution (line 1362) | fn single_execution(stack: String) -> Execution {
    type Resource (line 1372) | type Resource = Stack;
    method single_execution (line 1373) | fn single_execution(stack: String) -> Execution {
    type Resource (line 1382) | type Resource = Stack;
    method single_execution (line 1383) | fn single_execution(stack: String) -> Execution {
    type Resource (line 1392) | type Resource = Stack;
    method single_execution (line 1393) | fn single_execution(stack: String) -> Execution {

FILE: bin/core/src/helpers/prune.rs
  function spawn_prune_loop (line 13) | pub fn spawn_prune_loop() {
  function prune_images (line 32) | async fn prune_images() -> anyhow::Result<()> {
  function prune_stats (line 64) | async fn prune_stats() -> anyhow::Result<()> {
  function prune_alerts (line 83) | async fn prune_alerts() -> anyhow::Result<()> {

FILE: bin/core/src/helpers/query.rs
  function get_user (line 61) | pub async fn get_user(user: &str) -> anyhow::Result<User> {
  function get_server_with_state (line 74) | pub async fn get_server_with_state(
  function get_server_state (line 83) | pub async fn get_server_state(server: &Server) -> ServerState {
  function get_deployment_state (line 99) | pub async fn get_deployment_state(
  function get_stack_state_from_containers (line 124) | pub fn get_stack_state_from_containers(
  function get_stack_state (line 195) | pub async fn get_stack_state(
  function get_tag (line 211) | pub async fn get_tag(id_or_name: &str) -> anyhow::Result<Tag> {
  function get_tag_check_owner (line 225) | pub async fn get_tag_check_owner(
  function get_all_tags (line 236) | pub async fn get_all_tags(
  function get_id_to_tags (line 244) | pub async fn get_id_to_tags(
  function get_user_user_groups (line 257) | pub async fn get_user_user_groups(
  function get_user_user_group_ids (line 275) | pub async fn get_user_user_group_ids(
  function user_target_query (line 286) | pub fn user_target_query(
  function get_user_permission_on_target (line 302) | pub async fn get_user_permission_on_target(
  function id_or_name_filter (line 341) | pub fn id_or_name_filter(id_or_name: &str) -> Document {
  function id_or_username_filter (line 348) | pub fn id_or_username_filter(id_or_username: &str) -> Document {
  function get_variable (line 355) | pub async fn get_variable(name: &str) -> anyhow::Result<Variable> {
  function get_latest_update (line 366) | pub async fn get_latest_update(
  type VariablesAndSecrets (line 387) | pub struct VariablesAndSecrets {
  function get_variables_and_secrets (line 392) | pub async fn get_variables_and_secrets()
  constant SYSTEM_INFO_EXPIRY (line 417) | const SYSTEM_INFO_EXPIRY: u128 = ONE_MIN_MS;
  type SystemInfoCache (line 418) | type SystemInfoCache =
  function system_info_cache (line 420) | fn system_info_cache() -> &'static SystemInfoCache {
  function get_system_info (line 426) | pub async fn get_system_info(
  function get_last_run_at (line 451) | pub async fn get_last_run_at<R: KomodoResource>(
  function get_action_state (line 470) | pub async fn get_action_state(id: &String) -> ActionState {
  function get_procedure_state (line 486) | pub async fn get_procedure_state(id: &String) -> ProcedureState {

FILE: bin/core/src/helpers/update.rs
  function make_update (line 28) | pub fn make_update(
  function add_update (line 44) | pub async fn add_update(
  function add_update_without_send (line 63) | pub async fn add_update_without_send(
  function update_update (line 79) | pub async fn update_update(update: Update) -> anyhow::Result<()> {
  function update_list_item (line 89) | async fn update_list_item(
  function send_update (line 119) | async fn send_update(update: UpdateListItem) -> anyhow::Result<()> {
  function init_execution_update (line 124) | pub async fn init_execution_update(

FILE: bin/core/src/listener/integrations/github.rs
  type HmacSha256 (line 13) | type HmacSha256 = Hmac<Sha256>;
  type Github (line 16) | pub struct Github;
  method verify_secret (line 20) | fn verify_secret(
  type GithubWebhookBody (line 51) | struct GithubWebhookBody {
  method extract_branch (line 57) | fn extract_branch(body: &str) -> anyhow::Result<String> {

FILE: bin/core/src/listener/integrations/gitlab.rs
  type Gitlab (line 10) | pub struct Gitlab;
  method verify_secret (line 14) | fn verify_secret(
  type GitlabWebhookBody (line 38) | struct GitlabWebhookBody {
  method extract_branch (line 44) | fn extract_branch(body: &str) -> anyhow::Result<String> {

FILE: bin/core/src/listener/mod.rs
  function router (line 16) | pub fn router() -> Router {
  type ListenerLockCache (line 22) | type ListenerLockCache = Cache<String, Arc<Mutex<()>>>;
  type CustomSecret (line 25) | trait CustomSecret: KomodoResource {
    method custom_secret (line 26) | fn custom_secret(
  type VerifySecret (line 32) | trait VerifySecret {
    method verify_secret (line 33) | fn verify_secret(
  type ExtractBranch (line 41) | trait ExtractBranch {
    method extract_branch (line 42) | fn extract_branch(body: &str) -> anyhow::Result<String>;
    method verify_branch (line 43) | fn verify_branch(body: &str, expected: &str) -> anyhow::Result<()> {
  constant ANY_BRANCH (line 56) | const ANY_BRANCH: &str = "__ANY__";

FILE: bin/core/src/listener/resources.rs
  method custom_secret (line 33) | fn custom_secret(resource: &Self) -> &str {
  function build_locks (line 38) | fn build_locks() -> &'static ListenerLockCache {
  function handle_build_webhook (line 43) | pub async fn handle_build_webhook<B: super::ExtractBranch>(
  method custom_secret (line 77) | fn custom_secret(resource: &Self) -> &str {
  function repo_locks (line 82) | fn repo_locks() -> &'static ListenerLockCache {
  type RepoExecution (line 87) | pub trait RepoExecution {
    method resolve (line 88) | async fn resolve(repo: Repo) -> anyhow::Result<()>;
    method resolve (line 92) | async fn resolve(repo: Repo) -> anyhow::Result<()> {
    method resolve (line 112) | async fn resolve(repo: Repo) -> anyhow::Result<()> {
    method resolve (line 132) | async fn resolve(repo: Repo) -> anyhow::Result<()> {
  type RepoWebhookOption (line 153) | pub enum RepoWebhookOption {
  function handle_repo_webhook (line 159) | pub async fn handle_repo_webhook<B: super::ExtractBranch>(
  function handle_repo_webhook_inner (line 177) | async fn handle_repo_webhook_inner<
  method custom_secret (line 204) | fn custom_secret(resource: &Self) -> &str {
  function stack_locks (line 209) | fn stack_locks() -> &'static ListenerLockCache {
  type StackExecution (line 214) | pub trait StackExecution {
    method resolve (line 215) | async fn resolve(stack: Stack) -> serror::Result<()>;
    method resolve (line 219) | async fn resolve(stack: Stack) -> serror::Result<()> {
    method resolve (line 230) | async fn resolve(stack: Stack) -> serror::Result<()> {
  type StackWebhookOption (line 268) | pub enum StackWebhookOption {
  function handle_stack_webhook (line 273) | pub async fn handle_stack_webhook<B: super::ExtractBranch>(
  function handle_stack_webhook_inner (line 289) | pub async fn handle_stack_webhook_inner<
  method custom_secret (line 316) | fn custom_secret(resource: &Self) -> &str {
  function sync_locks (line 321) | fn sync_locks() -> &'static ListenerLockCache {
  type SyncExecution (line 326) | pub trait SyncExecution {
    method resolve (line 327) | async fn resolve(sync: ResourceSync) -> anyhow::Result<()>;
    method resolve (line 331) | async fn resolve(sync: ResourceSync) -> anyhow::Result<()> {
    method resolve (line 343) | async fn resolve(sync: ResourceSync) -> anyhow::Result<()> {
  type SyncWebhookOption (line 364) | pub enum SyncWebhookOption {
  function handle_sync_webhook (line 369) | pub async fn handle_sync_webhook<B: super::ExtractBranch>(
  function handle_sync_webhook_inner (line 387) | async fn handle_sync_webhook_inner<
  method custom_secret (line 414) | fn custom_secret(resource: &Self) -> &str {
  function procedure_locks (line 419) | fn procedure_locks() -> &'static ListenerLockCache {
  function handle_procedure_webhook (line 425) | pub async fn handle_procedure_webhook<B: super::ExtractBranch>(
  method custom_secret (line 465) | fn custom_secret(resource: &Self) -> &str {
  function action_locks (line 470) | fn action_locks() -> &'static ListenerLockCache {
  function handle_action_webhook (line 475) | pub async fn handle_action_webhook<B: super::ExtractBranch>(

FILE: bin/core/src/listener/router.rs
  type Id (line 24) | struct Id {
  type IdAndOption (line 29) | struct IdAndOption<T> {
  type IdAndBranch (line 35) | struct IdAndBranch {
  function default_branch (line 41) | fn default_branch() -> String {
  function router (line 45) | pub fn router<P: VerifySecret + ExtractBranch>() -> Router {
  function auth_webhook (line 205) | async fn auth_webhook<P, R>(

FILE: bin/core/src/main.rs
  function app (line 35) | async fn app() -> anyhow::Result<()> {
  function main (line 152) | async fn main() -> anyhow::Result<()> {

FILE: bin/core/src/monitor/alert/deployment.rs
  function alert_deployments (line 17) | pub async fn alert_deployments(

FILE: bin/core/src/monitor/alert/mod.rs
  function check_alerts (line 17) | pub async fn check_alerts(ts: i64) {
  function get_all_servers_map (line 34) | async fn get_all_servers_map()

FILE: bin/core/src/monitor/alert/server.rs
  type SendAlerts (line 29) | type SendAlerts = bool;
  type OpenAlertMap (line 30) | type OpenAlertMap<T = AlertDataVariant> =
  type OpenDiskAlertMap (line 32) | type OpenDiskAlertMap = OpenAlertMap<PathBuf>;
  type AlertBuffer (line 35) | struct AlertBuffer {
    method new (line 40) | fn new() -> Self {
    method ready_to_open (line 47) | fn ready_to_open(
    method reset (line 64) | fn reset(&self, server_id: String, variant: AlertDataVariant) {
  function alert_buffer (line 71) | fn alert_buffer() -> &'static AlertBuffer {
  function alert_servers (line 77) | pub async fn alert_servers(
  function open_new_alerts (line 551) | async fn open_new_alerts(alerts: &[(Alert, SendAlerts)]) {
  function update_alerts (line 599) | async fn update_alerts(alerts: &[(Alert, SendAlerts)]) {
  function resolve_alerts (line 647) | async fn resolve_alerts(alerts: &[(Alert, SendAlerts)]) {
  function get_open_alerts (line 704) | async fn get_open_alerts()

FILE: bin/core/src/monitor/alert/stack.rs
  function alert_stacks (line 16) | pub async fn alert_stacks(

FILE: bin/core/src/monitor/helpers.rs
  function insert_deployments_status_unknown (line 29) | pub async fn insert_deployments_status_unknown(
  function insert_repos_status_unknown (line 55) | pub async fn insert_repos_status_unknown(repos: Vec<Repo>) {
  function insert_stacks_status_unknown (line 72) | pub async fn insert_stacks_status_unknown(stacks: Vec<Stack>) {
  type DockerLists (line 94) | type DockerLists = (
  function insert_server_status (line 103) | pub async fn insert_server_status(
  constant ALERT_PERCENTAGE_THRESHOLD (line 133) | const ALERT_PERCENTAGE_THRESHOLD: f32 = 5.0;
  function get_server_health (line 135) | fn get_server_health(

FILE: bin/core/src/monitor/lists.rs
  function get_docker_lists (line 13) | pub async fn get_docker_lists(

FILE: bin/core/src/monitor/mod.rs
  type History (line 41) | pub struct History<Curr: Default, Prev> {
  type CachedServerStatus (line 47) | pub struct CachedServerStatus {
  type CachedDeploymentStatus (line 63) | pub struct CachedDeploymentStatus {
  type CachedRepoStatus (line 72) | pub struct CachedRepoStatus {
  type CachedStackStatus (line 78) | pub struct CachedStackStatus {
  constant ADDITIONAL_MS (line 87) | const ADDITIONAL_MS: u128 = 500;
  function spawn_monitor_loop (line 89) | pub fn spawn_monitor_loop() {
  function refresh_server_cache (line 104) | async fn refresh_server_cache(ts: i64) {
  function update_cache_for_server_controller (line 124) | fn update_cache_for_server_controller()
  function update_cache_for_server (line 136) | pub async fn update_cache_for_server(server: &Server, force: bool) {
  function filter_volumes (line 323) | fn filter_volumes(

FILE: bin/core/src/monitor/record.rs
  function record_server_stats (line 8) | pub async fn record_server_stats(ts: i64) {

FILE: bin/core/src/monitor/resources.rs
  function deployment_alert_sent_cache (line 40) | fn deployment_alert_sent_cache() -> &'static Mutex<HashSet<String>> {
  function update_deployment_cache (line 45) | pub async fn update_deployment_cache(
  function stack_alert_sent_cache (line 228) | fn stack_alert_sent_cache()
  function update_stack_cache (line 235) | pub async fn update_stack_cache(

FILE: bin/core/src/network.rs
  constant DOCKER_GATEWAY_CANDIDATES (line 20) | const DOCKER_GATEWAY_CANDIDATES: &[&str] = &[".1", ".254"];
  constant DOCKERENV_FILE (line 23) | const DOCKERENV_FILE: &str = "/.dockerenv";
  constant CGROUP_FILE (line 24) | const CGROUP_FILE: &str = "/proc/1/cgroup";
  function is_container_environment (line 27) | fn is_container_environment() -> bool {
  function configure_internet_gateway (line 49) | pub async fn configure_internet_gateway() {
  function configure_manual_interface (line 75) | async fn configure_manual_interface(
  function find_gateway (line 115) | async fn find_gateway(
  function set_default_gateway (line 239) | async fn set_default_gateway(
  function check_network_privileges (line 303) | async fn check_network_privileges() -> bool {

FILE: bin/core/src/permission.rs
  function get_check_permissions (line 26) | pub async fn get_check_permissions<T: KomodoResource>(
  function get_user_permission_on_resource (line 72) | pub fn get_user_permission_on_resource<'a, T: KomodoResource>(
  function get_resource_ids_for_user (line 168) | pub async fn get_resource_ids_for_user<T: KomodoResource>(

FILE: bin/core/src/resource/action.rs
  type Config (line 29) | type Config = ActionConfig;
  type PartialConfig (line 30) | type PartialConfig = PartialActionConfig;
  type ConfigDiff (line 31) | type ConfigDiff = ActionConfigDiff;
  type Info (line 32) | type Info = NoData;
  type ListItem (line 33) | type ListItem = ActionListItem;
  type QuerySpecifics (line 34) | type QuerySpecifics = ActionQuerySpecifics;
  method resource_type (line 36) | fn resource_type() -> ResourceTargetVariant {
  method resource_target (line 40) | fn resource_target(id: impl Into<String>) -> ResourceTarget {
  method coll (line 44) | fn coll() -> &'static Collection<Resource<Self::Config, Self::Info>>
  method to_list_item (line 49) | async fn to_list_item(
  method busy (line 74) | async fn busy(id: &String) -> anyhow::Result<bool> {
  method create_operation (line 85) | fn create_operation() -> Operation {
  method user_can_create (line 89) | fn user_can_create(user: &User) -> bool {
  method validate_create_config (line 93) | async fn validate_create_config(
  method post_create (line 104) | async fn post_create(
  method update_operation (line 115) | fn update_operation() -> Operation {
  method validate_update_config (line 119) | async fn validate_update_config(
  method post_update (line 127) | async fn post_update(
  method rename_operation (line 136) | fn rename_operation() -> Operation {
  method delete_operation (line 142) | fn delete_operation() -> Operation {
  method pre_delete (line 146) | async fn pre_delete(
  method post_delete (line 153) | async fn post_delete(
  function spawn_action_state_refresh_loop (line 163) | pub fn spawn_action_state_refresh_loop() {
  function refresh_action_state_cache (line 172) | pub async fn refresh_action_state_cache() {
  function get_action_state_from_db (line 190) | async fn get_action_state_from_db(id: &str) -> ActionState {
  constant DEFAULT_ACTION_FILE_CONTENTS (line 222) | const DEFAULT_ACTION_FILE_CONTENTS: &str =

FILE: bin/core/src/resource/alerter.rs
  type Config (line 17) | type Config = AlerterConfig;
  type PartialConfig (line 18) | type PartialConfig = PartialAlerterConfig;
  type ConfigDiff (line 19) | type ConfigDiff = AlerterConfigDiff;
  type Info (line 20) | type Info = ();
  type ListItem (line 21) | type ListItem = AlerterListItem;
  type QuerySpecifics (line 22) | type QuerySpecifics = AlerterQuerySpecifics;
  method resource_type (line 24) | fn resource_type() -> ResourceTargetVariant {
  method resource_target (line 28) | fn resource_target(id: impl Into<String>) -> ResourceTarget {
  method coll (line 32) | fn coll() -> &'static Collection<Resource<Self::Config, Self::Info>>
  method to_list_item (line 37) | async fn to_list_item(
  method busy (line 53) | async fn busy(_id: &String) -> anyhow::Result<bool> {
  method create_operation (line 59) | fn create_operation() -> Operation {
  method user_can_create (line 63) | fn user_can_create(user: &User) -> bool {
  method validate_create_config (line 67) | async fn validate_create_config(
  method post_create (line 74) | async fn post_create(
  method update_operation (line 83) | fn update_operation() -> Operation {
  method validate_update_config (line 87) | async fn validate_update_config(
  method post_update (line 95) | async fn post_update(
  method rename_operation (line 104) | fn rename_operation() -> Operation {
  method delete_operation (line 110) | fn delete_operation() -> Operation {
  method pre_delete (line 114) | async fn pre_delete(
  method post_delete (line 121) | async fn post_delete(

FILE: bin/core/src/resource/build.rs
  type Config (line 43) | type Config = BuildConfig;
  type PartialConfig (line 44) | type PartialConfig = PartialBuildConfig;
  type ConfigDiff (line 45) | type ConfigDiff = BuildConfigDiff;
  type Info (line 46) | type Info = BuildInfo;
  type ListItem (line 47) | type ListItem = BuildListItem;
  type QuerySpecifics (line 48) | type QuerySpecifics = BuildQuerySpecifics;
  method resource_type (line 50) | fn resource_type() -> ResourceTargetVariant {
  method resource_target (line 54) | fn resource_target(id: impl Into<String>) -> ResourceTarget {
  method validated_name (line 58) | fn validated_name(name: &str) -> String {
  method coll (line 62) | fn coll() -> &'static Collection<Resource<Self::Config, Self::Info>>
  method to_list_item (line 67) | async fn to_list_item(
  method busy (line 131) | async fn busy(id: &String) -> anyhow::Result<bool> {
  method create_operation (line 142) | fn create_operation() -> Operation {
  method user_can_create (line 146) | fn user_can_create(user: &User) -> bool {
  method validate_create_config (line 152) | async fn validate_create_config(
  method post_create (line 159) | async fn post_create(
  method update_operation (line 182) | fn update_operation() -> Operation {
  method validate_update_config (line 186) | async fn validate_update_config(
  method post_update (line 194) | async fn post_update(
  method rename_operation (line 203) | fn rename_operation() -> Operation {
  method delete_operation (line 209) | fn delete_operation() -> Operation {
  method pre_delete (line 213) | async fn pre_delete(
  method post_delete (line 220) | async fn post_delete(
  function spawn_build_state_refresh_loop (line 229) | pub fn spawn_build_state_refresh_loop() {
  function refresh_build_state_cache (line 238) | pub async fn refresh_build_state_cache() {
  function validate_config (line 257) | async fn validate_config(
  function get_build_state (line 300) | async fn get_build_state(id: &String) -> BuildState {
  function get_build_state_from_db (line 316) | async fn get_build_state_from_db(id: &str) -> BuildState {
  function latest_2_build_updates (line 361) | async fn latest_2_build_updates(

FILE: bin/core/src/resource/builder.rs
  type Config (line 24) | type Config = BuilderConfig;
  type PartialConfig (line 25) | type PartialConfig = PartialBuilderConfig;
  type ConfigDiff (line 26) | type ConfigDiff = BuilderConfigDiff;
  type Info (line 27) | type Info = ();
  type ListItem (line 28) | type ListItem = BuilderListItem;
  type QuerySpecifics (line 29) | type QuerySpecifics = BuilderQuerySpecifics;
  method resource_type (line 31) | fn resource_type() -> ResourceTargetVariant {
  method resource_target (line 35) | fn resource_target(id: impl Into<String>) -> ResourceTarget {
  method creator_specific_permissions (line 39) | fn creator_specific_permissions() -> IndexSet<SpecificPermission> {
  method coll (line 43) | fn coll() -> &'static Collection<Resource<Self::Config, Self::Info>>
  method to_list_item (line 48) | async fn to_list_item(
  method busy (line 77) | async fn busy(_id: &String) -> anyhow::Result<bool> {
  method create_operation (line 83) | fn create_operation() -> Operation {
  method user_can_create (line 87) | fn user_can_create(user: &User) -> bool {
  method validate_create_config (line 91) | async fn validate_create_config(
  method post_create (line 98) | async fn post_create(
  method update_operation (line 107) | fn update_operation() -> Operation {
  method validate_update_config (line 111) | async fn validate_update_config(
  method update_document (line 119) | fn update_document(
  method post_update (line 128) | async fn post_update(
  method rename_operation (line 137) | fn rename_operation() -> Operation {
  method delete_operation (line 143) | fn delete_operation() -> Operation {
  method pre_delete (line 147) | async fn pre_delete(
  method post_delete (line 174) | async fn post_delete(
  function validate_config (line 183) | async fn validate_config(

FILE: bin/core/src/resource/deployment.rs
  type Config (line 37) | type Config = DeploymentConfig;
  type PartialConfig (line 38) | type PartialConfig = PartialDeploymentConfig;
  type ConfigDiff (line 39) | type ConfigDiff = DeploymentConfigDiff;
  type Info (line 40) | type Info = ();
  type ListItem (line 41) | type ListItem = DeploymentListItem;
  type QuerySpecifics (line 42) | type QuerySpecifics = DeploymentQuerySpecifics;
  method resource_type (line 44) | fn resource_type() -> ResourceTargetVariant {
  method resource_target (line 48) | fn resource_target(id: impl Into<String>) -> ResourceTarget {
  method validated_name (line 52) | fn validated_name(name: &str) -> String {
  method creator_specific_permissions (line 56) | fn creator_specific_permissions() -> IndexSet<SpecificPermission> {
  method inherit_specific_permissions_from (line 66) | fn inherit_specific_permissions_from(
  method coll (line 72) | fn coll() -> &'static Collection<Resource<Self::Config, Self::Info>>
  method to_list_item (line 77) | async fn to_list_item(
  method busy (line 147) | async fn busy(id: &String) -> anyhow::Result<bool> {
  method create_operation (line 158) | fn create_operation() -> Operation {
  method user_can_create (line 162) | fn user_can_create(user: &User) -> bool {
  method validate_create_config (line 166) | async fn validate_create_config(
  method post_create (line 173) | async fn post_create(
  method update_operation (line 197) | fn update_operation() -> Operation {
  method validate_update_config (line 201) | async fn validate_update_config(
  method post_update (line 209) | async fn post_update(
  method rename_operation (line 218) | fn rename_operation() -> Operation {
  method delete_operation (line 224) | fn delete_operation() -> Operation {
  method pre_delete (line 228) | async fn pre_delete(
  method post_delete (line 303) | async fn post_delete(
  function validate_config (line 313) | async fn validate_config(

FILE: bin/core/src/resource/mod.rs
  type KomodoResource (line 84) | pub trait KomodoResource {
    method resource_type (line 115) | fn resource_type() -> ResourceTargetVariant;
    method resource_target (line 116) | fn resource_target(id: impl Into<String>) -> ResourceTarget;
    method coll (line 118) | fn coll() -> &'static Collection<Resource<Self::Config, Self::Info>>;
    method to_list_item (line 120) | async fn to_list_item(
    method busy (line 125) | async fn busy(id: &String) -> anyhow::Result<bool>;
    method validated_name (line 130) | fn validated_name(name: &str) -> String {
    method creator_specific_permissions (line 136) | fn creator_specific_permissions() -> IndexSet<SpecificPermission> {
    method inherit_specific_permissions_from (line 143) | fn inherit_specific_permissions_from(
    method create_operation (line 153) | fn create_operation() -> Operation;
    method user_can_create (line 155) | fn user_can_create(user: &User) -> bool;
    method validate_create_config (line 157) | async fn validate_create_config(
    method default_info (line 162) | async fn default_info() -> anyhow::Result<Self::Info> {
    method post_create (line 166) | async fn post_create(
    method update_operation (line 175) | fn update_operation() -> Operation;
    method validate_update_config (line 177) | async fn validate_update_config(
    method update_document (line 184) | fn update_document(
    method post_update (line 194) | async fn post_update(
    method rename_operation (line 203) | fn rename_operation() -> Operation;
    method delete_operation (line 209) | fn delete_operation() -> Operation;
    method pre_delete (line 212) | async fn pre_delete(
    method post_delete (line 219) | async fn post_delete(
  function get (line 231) | pub async fn get<T: KomodoResource>(
  function get_resource_object_ids_for_user (line 258) | pub async fn get_resource_object_ids_for_user<T: KomodoResource>(
  function list_for_user (line 272) | pub async fn list_for_user<T: KomodoResource>(
  function list_for_user_using_document (line 306) | pub async fn list_for_user_using_document<T: KomodoResource>(
  function list_full_for_user_using_pattern (line 327) | pub async fn list_full_for_user_using_pattern<T: KomodoResource>(
  function list_full_for_user (line 370) | pub async fn list_full_for_user<T: KomodoResource>(
  function list_full_for_user_using_document (line 383) | pub async fn list_full_for_user_using_document<T: KomodoResource>(
  type IdResourceMap (line 403) | pub type IdResourceMap<T> = HashMap<
  function get_id_to_resource_map (line 412) | pub async fn get_id_to_resource_map<T: KomodoResource>(
  function create (line 459) | pub async fn create<T: KomodoResource>(
  function update (line 578) | pub async fn update<T: KomodoResource>(
  function resource_target (line 671) | fn resource_target<T: KomodoResource>(id: String) -> ResourceTarget {
  type ResourceMetaUpdate (line 691) | pub struct ResourceMetaUpdate {
    method is_none (line 698) | pub fn is_none(&self) -> bool {
  function update_meta (line 705) | pub async fn update_meta<T: KomodoResource>(
  function remove_tag_from_all (line 751) | pub async fn remove_tag_from_all<T: KomodoResource>(
  function rename (line 765) | pub async fn rename<T: KomodoResource>(
  function delete (line 823) | pub async fn delete<T: KomodoResource>(
  function delete_from_alerters (line 888) | async fn delete_from_alerters<T: KomodoResource>(id: &str) {
  function validate_resource_query_tags (line 911) | pub fn validate_resource_query_tags<T: Default + std::fmt::Debug>(
  function delete_all_permissions_on_resource (line 932) | pub async fn delete_all_permissions_on_resource<T>(target: T)
  function remove_from_recently_viewed (line 953) | pub async fn remove_from_recently_viewed<T>(resource: T)

FILE: bin/core/src/resource/procedure.rs
  type Config (line 43) | type Config = ProcedureConfig;
  type PartialConfig (line 44) | type PartialConfig = PartialProcedureConfig;
  type ConfigDiff (line 45) | type ConfigDiff = ProcedureConfigDiff;
  type Info (line 46) | type Info = ();
  type ListItem (line 47) | type ListItem = ProcedureListItem;
  type QuerySpecifics (line 48) | type QuerySpecifics = ProcedureQuerySpecifics;
  method resource_type (line 50) | fn resource_type() -> ResourceTargetVariant {
  method resource_target (line 54) | fn resource_target(id: impl Into<String>) -> ResourceTarget {
  method coll (line 58) | fn coll() -> &'static Collection<Resource<Self::Config, Self::Info>>
  method to_list_item (line 63) | async fn to_list_item(
  method busy (line 89) | async fn busy(id: &String) -> anyhow::Result<bool> {
  method create_operation (line 100) | fn create_operation() -> Operation {
  method user_can_create (line 104) | fn user_can_create(user: &User) -> bool {
  method validate_create_config (line 108) | async fn validate_create_config(
  method post_create (line 115) | async fn post_create(
  method update_operation (line 126) | fn update_operation() -> Operation {
  method validate_update_config (line 130) | async fn validate_update_config(
  method post_update (line 138) | async fn post_update(
  method rename_operation (line 147) | fn rename_operation() -> Operation {
  method delete_operation (line 153) | fn delete_operation() -> Operation {
  method pre_delete (line 157) | async fn pre_delete(
  method post_delete (line 164) | async fn post_delete(
  function validate_config (line 175) | async fn validate_config(
  function spawn_procedure_state_refresh_loop (line 785) | pub fn spawn_procedure_state_refresh_loop() {
  function refresh_procedure_state_cache (line 794) | pub async fn refresh_procedure_state_cache() {
  function get_procedure_state_from_db (line 813) | async fn get_procedure_state_from_db(id: &str) -> ProcedureState {

FILE: bin/core/src/resource/refresh.rs
  function spawn_all_resources_cache_refresh_loop (line 21) | pub fn spawn_all_resources_cache_refresh_loop() {
  function refresh_all_resources_cache (line 31) | pub async fn refresh_all_resources_cache() {
  function spawn_resource_refresh_loop (line 42) | pub fn spawn_resource_refresh_loop() {
  function refresh_all (line 58) | async fn refresh_all() {
  function refresh_stacks (line 65) | async fn refresh_stacks() {
  function refresh_builds (line 89) | async fn refresh_builds() {
  function refresh_repos (line 113) | async fn refresh_repos() {
  function refresh_syncs (line 137) | async fn refresh_syncs() {

FILE: bin/core/src/resource/repo.rs
  type Config (line 36) | type Config = RepoConfig;
  type PartialConfig (line 37) | type PartialConfig = PartialRepoConfig;
  type ConfigDiff (line 38) | type ConfigDiff = RepoConfigDiff;
  type Info (line 39) | type Info = RepoInfo;
  type ListItem (line 40) | type ListItem = RepoListItem;
  type QuerySpecifics (line 41) | type QuerySpecifics = RepoQuerySpecifics;
  method resource_type (line 43) | fn resource_type() -> ResourceTargetVariant {
  method resource_target (line 47) | fn resource_target(id: impl Into<String>) -> ResourceTarget {
  method validated_name (line 51) | fn validated_name(name: &str) -> String {
  method coll (line 55) | fn coll() -> &'static Collection<Resource<Self::Config, Self::Info>>
  method to_list_item (line 60) | async fn to_list_item(
  method busy (line 95) | async fn busy(id: &String) -> anyhow::Result<bool> {
  method create_operation (line 106) | fn create_operation() -> Operation {
  method user_can_create (line 110) | fn user_can_create(user: &User) -> bool {
  method validate_create_config (line 114) | async fn validate_create_config(
  method post_create (line 121) | async fn post_create(
  method update_operation (line 131) | fn update_operation() -> Operation {
  method validate_update_config (line 135) | async fn validate_update_config(
  method post_update (line 143) | async fn post_update(
  method rename_operation (line 153) | fn rename_operation() -> Operation {
  method delete_operation (line 159) | fn delete_operation() -> Operation {
  method pre_delete (line 163) | async fn pre_delete(
  method post_delete (line 197) | async fn post_delete(
  function spawn_repo_state_refresh_loop (line 207) | pub fn spawn_repo_state_refresh_loop() {
  function refresh_repo_state_cache (line 216) | pub async fn refresh_repo_state_cache() {
  function validate_config (line 235) | async fn validate_config(
  function get_repo_state (line 266) | async fn get_repo_state(id: &String) -> RepoState {
  function get_repo_state_from_db (line 293) | async fn get_repo_state_from_db(id: &str) -> RepoState {

FILE: bin/core/src/resource/server.rs
  type Config (line 24) | type Config = ServerConfig;
  type PartialConfig (line 25) | type PartialConfig = PartialServerConfig;
  type ConfigDiff (line 26) | type ConfigDiff = ServerConfigDiff;
  type Info (line 27) | type Info = ();
  type ListItem (line 28) | type ListItem = ServerListItem;
  type QuerySpecifics (line 29) | type QuerySpecifics = ServerQuerySpecifics;
  method resource_type (line 31) | fn resource_type() -> ResourceTargetVariant {
  method resource_target (line 35) | fn resource_target(id: impl Into<String>) -> ResourceTarget {
  method creator_specific_permissions (line 39) | fn creator_specific_permissions() -> IndexSet<SpecificPermission> {
  method coll (line 51) | fn coll() -> &'static Collection<Resource<Self::Config, Self::Info>>
  method to_list_item (line 56) | async fn to_list_item(
  method busy (line 94) | async fn busy(id: &String) -> anyhow::Result<bool> {
  method create_operation (line 105) | fn create_operation() -> Operation {
  method user_can_create (line 109) | fn user_can_create(user: &User) -> bool {
  method validate_create_config (line 115) | async fn validate_create_config(
  method post_create (line 122) | async fn post_create(
  method update_operation (line 132) | fn update_operation() -> Operation {
  method validate_update_config (line 136) | async fn validate_update_config(
  method post_update (line 144) | async fn post_update(
  method rename_operation (line 154) | fn rename_operation() -> Operation {
  method delete_operation (line 160) | fn delete_operation() -> Operation {
  method pre_delete (line 164) | async fn pre_delete(
  method post_delete (line 218) | async fn post_delete(

FILE: bin/core/src/resource/stack.rs
  type Config (line 40) | type Config = StackConfig;
  type PartialConfig (line 41) | type PartialConfig = PartialStackConfig;
  type ConfigDiff (line 42) | type ConfigDiff = StackConfigDiff;
  type Info (line 43) | type Info = StackInfo;
  type ListItem (line 44) | type ListItem = StackListItem;
  type QuerySpecifics (line 45) | type QuerySpecifics = StackQuerySpecifics;
  method resource_type (line 47) | fn resource_type() -> ResourceTargetVariant {
  method resource_target (line 51) | fn resource_target(id: impl Into<String>) -> ResourceTarget {
  method validated_name (line 55) | fn validated_name(name: &str) -> String {
  method creator_specific_permissions (line 59) | fn creator_specific_permissions() -> IndexSet<SpecificPermission> {
  method inherit_specific_permissions_from (line 69) | fn inherit_specific_permissions_from(
  method coll (line 75) | fn coll() -> &'static Collection<Resource<Self::Config, Self::Info>>
  method to_list_item (line 80) | async fn to_list_item(
  method busy (line 198) | async fn busy(id: &String) -> anyhow::Result<bool> {
  method create_operation (line 209) | fn create_operation() -> Operation {
  method user_can_create (line 213) | fn user_can_create(user: &User) -> bool {
  method validate_create_config (line 217) | async fn validate_create_config(
  method post_create (line 224) | async fn post_create(
  method update_operation (line 261) | fn update_operation() -> Operation {
  method validate_update_config (line 265) | async fn validate_update_config(
  method post_update (line 273) | async fn post_update(
  method rename_operation (line 282) | fn rename_operation() -> Operation {
  method delete_operation (line 288) | fn delete_operation() -> Operation {
  method pre_delete (line 292) | async fn pre_delete(
  method post_delete (line 367) | async fn post_delete(
  function validate_config (line 377) | async fn validate_config(

FILE: bin/core/src/resource/sync.rs
  type Config (line 33) | type Config = ResourceSyncConfig;
  type PartialConfig (line 34) | type PartialConfig = PartialResourceSyncConfig;
  type ConfigDiff (line 35) | type ConfigDiff = ResourceSyncConfigDiff;
  type Info (line 36) | type Info = ResourceSyncInfo;
  type ListItem (line 37) | type ListItem = ResourceSyncListItem;
  type QuerySpecifics (line 38) | type QuerySpecifics = ResourceSyncQuerySpecifics;
  method resource_type (line 40) | fn resource_type() -> ResourceTargetVariant {
  method resource_target (line 44) | fn resource_target(id: impl Into<String>) -> ResourceTarget {
  method coll (line 48) | fn coll() -> &'static Collection<Resource<Self::Config, Self::Info>>
  method to_list_item (line 53) | async fn to_list_item(
  method busy (line 114) | async fn busy(id: &String) -> anyhow::Result<bool> {
  method create_operation (line 125) | fn create_operation() -> Operation {
  method user_can_create (line 129) | fn user_can_create(user: &User) -> bool {
  method validate_create_config (line 133) | async fn validate_create_config(
  method post_create (line 140) | async fn post_create(
  method update_operation (line 162) | fn update_operation() -> Operation {
  method validate_update_config (line 166) | async fn validate_update_config(
  method post_update (line 174) | async fn post_update(
  method rename_operation (line 183) | fn rename_operation() -> Operation {
  method delete_operation (line 189) | fn delete_operation() -> Operation {
  method pre_delete (line 193) | async fn pre_delete(
  method post_delete (line 211) | async fn post_delete(
  function validate_config (line 220) | async fn validate_config(
  function get_resource_sync_state (line 240) | async fn get_resource_sync_state(

FILE: bin/core/src/schedule.rs
  function spawn_schedule_executor (line 33) | pub fn spawn_schedule_executor() {
  type UnixTimestampMs (line 196) | type UnixTimestampMs = i64;
  type Schedules (line 197) | type Schedules =
  function schedules (line 200) | fn schedules() -> &'static RwLock<Schedules> {
  function get_schedule_item_info (line 205) | pub fn get_schedule_item_info(
  function cancel_schedule (line 215) | pub fn cancel_schedule(target: &ResourceTarget) {
  function update_schedules (line 219) | pub async fn update_schedules() {
  function update_schedule (line 263) | pub fn update_schedule(schedule: impl HasSchedule) {
  function cron_parser (line 278) | fn cron_parser() -> &'static CronParser {
  function find_next_occurrence (line 289) | fn find_next_occurrence(
  type HasSchedule (line 334) | pub trait HasSchedule {
    method target (line 335) | fn target(&self) -> ResourceTarget;
    method enabled (line 336) | fn enabled(&self) -> bool;
    method format (line 337) | fn format(&self) -> ScheduleFormat;
    method schedule (line 338) | fn schedule(&self) -> &str;
    method timezone (line 339) | fn timezone(&self) -> &str;
    method target (line 343) | fn target(&self) -> ResourceTarget {
    method enabled (line 346) | fn enabled(&self) -> bool {
    method format (line 349) | fn format(&self) -> ScheduleFormat {
    method schedule (line 352) | fn schedule(&self) -> &str {
    method timezone (line 355) | fn timezone(&self) -> &str {
    method target (line 361) | fn target(&self) -> ResourceTarget {
    method enabled (line 364) | fn enabled(&self) -> bool {
    method format (line 367) | fn format(&self) -> ScheduleFormat {
    method schedule (line 370) | fn schedule(&self) -> &str {
    method timezone (line 373) | fn timezone(&self) -> &str {

FILE: bin/core/src/stack/execute.rs
  type ExecuteCompose (line 20) | pub trait ExecuteCompose {
    method execute (line 23) | async fn execute(
    type Extras (line 92) | type Extras = ();
    method execute (line 93) | async fn execute(
    type Extras (line 110) | type Extras = ();
    method execute (line 111) | async fn execute(
    type Extras (line 128) | type Extras = ();
    method execute (line 129) | async fn execute(
    type Extras (line 146) | type Extras = ();
    method execute (line 147) | async fn execute(
    type Extras (line 164) | type Extras = Option<i32>;
    method execute (line 165) | async fn execute(
    type Extras (line 183) | type Extras = (Option<i32>, bool);
    method execute (line 184) | async fn execute(
  function execute_compose (line 31) | pub async fn execute_compose<T: ExecuteCompose>(
  function service_args (line 83) | fn service_args(services: &[String]) -> String {
  function maybe_timeout (line 208) | pub fn maybe_timeout(timeout: Option<i32>) -> String {

FILE: bin/core/src/stack/mod.rs
  function get_stack_and_server (line 19) | pub async fn get_stack_and_server(
  function compose_container_match_regex (line 43) | pub fn compose_container_match_regex(

FILE: bin/core/src/stack/remote.rs
  type RemoteComposeContents (line 14) | pub struct RemoteComposeContents {
  function get_repo_compose_contents (line 23) | pub async fn get_repo_compose_contents(
  function ensure_remote_repo (line 77) | pub async fn ensure_remote_repo(

FILE: bin/core/src/stack/services.rs
  function extract_services_from_stack (line 7) | pub fn extract_services_from_stack(
  function extract_services_into_res (line 27) | pub fn extract_services_into_res(

FILE: bin/core/src/startup.rs
  function run_startup_actions (line 47) | pub async fn run_startup_actions() {
  function on_startup (line 102) | pub async fn on_startup() {
  function in_progress_update_cleanup (line 115) | async fn in_progress_update_cleanup() {
  function open_alert_cleanup (line 145) | async fn open_alert_cleanup() {
  function ensure_first_server_and_builder (line 199) | async fn ensure_first_server_and_builder() {
  function ensure_init_user_and_resources (line 264) | async fn ensure_init_user_and_resources() {
  function clean_up_server_templates (line 421) | async fn clean_up_server_templates() {

FILE: bin/core/src/state.rs
  function db_client (line 37) | pub fn db_client() -> &'static Client {
  function init_db_client (line 44) | pub async fn init_db_client() {
  function jwt_client (line 52) | pub fn jwt_client() -> &'static JwtClient {
  function github_client (line 63) | pub fn github_client()
  function action_states (line 133) | pub fn action_states() -> &'static ActionStates {
  type DeploymentStatusCache (line 139) | pub type DeploymentStatusCache = Cache<
  function deployment_status_cache (line 145) | pub fn deployment_status_cache() -> &'static DeploymentStatusCache {
  type StackStatusCache (line 151) | pub type StackStatusCache =
  function stack_status_cache (line 154) | pub fn stack_status_cache() -> &'static StackStatusCache {
  type ServerStatusCache (line 160) | pub type ServerStatusCache = Cache<String, Arc<CachedServerStatus>>;
  function server_status_cache (line 162) | pub fn server_status_cache() -> &'static ServerStatusCache {
  type RepoStatusCache (line 168) | pub type RepoStatusCache = Cache<String, Arc<CachedRepoStatus>>;
  function repo_status_cache (line 170) | pub fn repo_status_cache() -> &'static RepoStatusCache {
  type BuildStateCache (line 176) | pub type BuildStateCache = Cache<String, BuildState>;
  function build_state_cache (line 178) | pub fn build_state_cache() -> &'static BuildStateCache {
  type RepoStateCache (line 184) | pub type RepoStateCache = Cache<String, RepoState>;
  function repo_state_cache (line 186) | pub fn repo_state_cache() -> &'static RepoStateCache {
  type ProcedureStateCache (line 191) | pub type ProcedureStateCache = Cache<String, ProcedureState>;
  function procedure_state_cache (line 193) | pub fn procedure_state_cache() -> &'static ProcedureStateCache {
  type ActionStateCache (line 199) | pub type ActionStateCache = Cache<String, ActionState>;
  function action_state_cache (line 201) | pub fn action_state_cache() -> &'static ActionStateCache {
  function all_resources_cache (line 207) | pub fn all_resources_cache() -> &'static ArcSwap<AllResourcesById> {

FILE: bin/core/src/sync/deploy.rs
  type ToDeployCache (line 43) | pub type ToDeployCache =
  type SyncDeployParams (line 47) | pub struct SyncDeployParams<'a> {
  function deploy_from_cache (line 56) | pub async fn deploy_from_cache(
  function get_updates_for_view (line 193) | pub async fn get_updates_for_view(
  type ToDeployCacheInner (line 243) | type ToDeployCacheInner =
  type BuildVersionCache (line 247) | type BuildVersionCache = HashMap<String, String>;
  function build_deploy_cache (line 249) | pub async fn build_deploy_cache(
  type BuildRes (line 299) | type BuildRes<'a> = std::pin::Pin<
  function build_cache_for_deployment (line 305) | fn build_cache_for_deployment<'a>(
  function build_cache_for_stack (line 495) | fn build_cache_for_stack<'a>(
  function insert_target_using_after_list (line 660) | async fn insert_target_using_after_list<'a>(
  function get_after_as_resource_targets (line 796) | fn get_after_as_resource_targets(

FILE: bin/core/src/sync/execute.rs
  function get_updates_for_execution (line 17) | pub async fn get_updates_for_execution<
  type ExecuteResourceSync (line 123) | pub trait ExecuteResourceSync: ResourceSyncTrait {
    method execute_sync_updates (line 124) | async fn execute_sync_updates(
  function run_update_meta (line 276) | pub async fn run_update_meta<Resource: ResourceSyncTrait>(

FILE: bin/core/src/sync/file.rs
  function read_resources (line 14) | pub fn read_resources(
  function read_resource_file (line 113) | fn read_resource_file(
  function read_resources_directory (line 169) | fn read_resources_directory(
  function extend_resources (line 241) | pub fn extend_resources(
  function filter_by_tag (line 280) | fn filter_by_tag<T: Default>(

FILE: bin/core/src/sync/mod.rs
  type SyncDeltas (line 25) | pub struct SyncDeltas<T: Default> {
  function no_changes (line 32) | pub fn no_changes(&self) -> bool {
  type ToUpdateItem (line 39) | pub struct ToUpdateItem<T: Default> {
  type ResourceSyncTrait (line 47) | pub trait ResourceSyncTrait: ToToml + Sized {
    method include_resource (line 49) | fn include_resource(
    method include_resource_partial (line 70) | fn include_resource_partial(
    method validate_partial_config (line 92) | fn validate_partial_config(_config: &mut Self::PartialConfig) {}
    method get_diff (line 96) | fn get_diff(
    method validate_diff (line 103) | fn validate_diff(_diff: &mut Self::ConfigDiff) {}
  function include_resource_by_tags (line 106) | pub fn include_resource_by_tags(
  function include_resource_by_resource_type_and_name (line 123) | pub fn include_resource_by_resource_type_and_name<
  function deserialize_resources_toml (line 148) | fn deserialize_resources_toml(
  function escape_between_triple_string (line 158) | fn escape_between_triple_string(toml_str: &str) -> String {

FILE: bin/core/src/sync/remote.rs
  type RemoteResources (line 15) | pub struct RemoteResources {
  function get_remote_resources (line 25) | pub async fn get_remote_resources(
  function get_files_on_host (line 40) | async fn get_files_on_host(
  function get_repo (line 66) | async fn get_repo(
  function get_ui_defined (line 126) | async fn get_ui_defined(

FILE: bin/core/src/sync/resources.rs
  method get_diff (line 39) | fn get_diff(
  method get_diff (line 50) | fn get_diff(
  method get_diff (line 83) | fn get_diff(
  method get_diff (line 108) | fn get_diff(
  method validate_diff (line 127) | fn validate_diff(diff: &mut Self::ConfigDiff) {
  method get_diff (line 142) | fn get_diff(
  method get_diff (line 168) | fn get_diff(
  method get_diff (line 179) | fn get_diff(
  method get_diff (line 200) | fn get_diff(
  method include_resource (line 211) | fn include_resource(
  method include_resource_partial (line 246) | fn include_resource_partial(
  method get_diff (line 290) | fn get_diff(
  method get_diff (line 308) | fn get_diff(
  method execute_sync_updates (line 704) | async fn execute_sync_updates(

FILE: bin/core/src/sync/toml.rs
  constant TOML_PRETTY_OPTIONS (line 27) | pub const TOML_PRETTY_OPTIONS: toml_pretty::Options =
  type ToToml (line 37) | pub trait ToToml: KomodoResource {
    method replace_ids (line 39) | fn replace_ids(_resource: &mut Resource<Self::Config, Self::Info>) {
    method edit_config_object (line 42) | fn edit_config_object(
    method push_additional (line 49) | fn push_additional(
    method push_to_toml_string (line 55) | fn push_to_toml_string(
    method replace_ids (line 165) | fn replace_ids(resource: &mut Resource<Self::Config, Self::Info>) {
    method replace_ids (line 178) | fn replace_ids(resource: &mut Resource<Self::Config, Self::Info>) {
    method edit_config_object (line 196) | fn edit_config_object(
    method replace_ids (line 215) | fn replace_ids(resource: &mut Resource<Self::Config, Self::Info>) {
    method edit_config_object (line 237) | fn edit_config_object(
    method replace_ids (line 277) | fn replace_ids(resource: &mut Resource<Self::Config, Self::Info>) {
    method edit_config_object (line 295) | fn edit_config_object(
    method replace_ids (line 327) | fn replace_ids(resource: &mut Resource<Self::Config, Self::Info>) {
    method edit_config_object (line 345) | fn edit_config_object(
    method replace_ids (line 366) | fn replace_ids(resource: &mut Resource<Self::Config, Self::Info>) {
    method push_additional (line 379) | fn push_additional(
    method replace_ids (line 397) | fn replace_ids(resource: &mut Resource<Self::Config, Self::Info>) {
    method push_to_toml_string (line 819) | fn push_to_toml_string(
  function resource_toml_to_toml_string (line 93) | pub fn resource_toml_to_toml_string<R: ToToml>(
  function resource_push_to_toml (line 103) | pub fn resource_push_to_toml<R: ToToml>(
  function resource_to_toml (line 123) | pub fn resource_to_toml<R: ToToml>(
  function convert_resource (line 136) | pub fn convert_resource<R: KomodoResource>(

FILE: bin/core/src/sync/user_groups.rs
  type BasicUserGroupToml (line 44) | struct BasicUserGroupToml {
  function is_false (line 52) | fn is_false(b: &bool) -> bool {
  type Permissions (line 58) | struct Permissions {
  function user_group_to_toml (line 62) | pub fn user_group_to_toml(
  type UpdateItem (line 128) | pub struct UpdateItem {
  type DeleteItem (line 136) | pub struct DeleteItem {
  function get_updates_for_view (line 141) | pub async fn get_updates_for_view(
  function get_updates_for_execution (line 225) | pub async fn get_updates_for_execution(
  function sort_permissions (line 472) | fn sort_permissions(
  function run_updates (line 487) | pub async fn run_updates(
  function set_users (line 638) | async fn set_users(
  function set_everyone (line 670) | async fn set_everyone(
  function run_update_all (line 702) | async fn run_update_all(
  function run_update_permissions (line 740) | async fn run_update_permissions(
  function expand_user_group_permissions (line 785) | async fn expand_user_group_permissions(
  type AllDiff (line 928) | type AllDiff = IndexMap<
  function default_permission (line 933) | fn default_permission() -> &'static PermissionLevelAndSpecifics {
  function diff_group_all (line 940) | fn diff_group_all(
  function specific_equal (line 991) | fn specific_equal(
  function convert_user_groups (line 1008) | pub async fn convert_user_groups(

FILE: bin/core/src/sync/variables.rs
  function variable_to_toml (line 18) | pub fn variable_to_toml(
  type ToUpdateItem (line 26) | pub struct ToUpdateItem {
  function get_updates_for_view (line 33) | pub async fn get_updates_for_view(
  function get_updates_for_execution (line 81) | pub async fn get_updates_for_execution(
  function run_updates (line 130) | pub async fn run_updates(

FILE: bin/core/src/sync/view.rs
  function push_updates_for_view (line 16) | pub async fn push_updates_for_view<Resource: ResourceSyncTrait>(

FILE: bin/core/src/ts_client.rs
  function router (line 15) | pub fn router() -> Router {
  constant ALLOWED_FILES (line 19) | const ALLOWED_FILES: &[&str] = &[
  type FilePath (line 31) | struct FilePath {
  function serve_client_file (line 36) | async fn serve_client_file(

FILE: bin/core/src/ws/container.rs
  function terminal (line 14) | pub async fn terminal(

FILE: bin/core/src/ws/deployment.rs
  function terminal (line 17) | pub async fn terminal(

FILE: bin/core/src/ws/mod.rs
  function router (line 28) | pub fn router() -> Router {
  function ws_login (line 38) | async fn ws_login(
  type LoginMessage (line 112) | enum LoginMessage {
  function check_user_valid (line 120) | async fn check_user_valid(user_id: &str) -> anyhow::Result<User> {
  function handle_container_terminal (line 128) | async fn handle_container_terminal(
  function core_periphery_forward_ws (line 170) | async fn core_periphery_forward_ws(
  function axum_to_tungstenite (line 252) | fn axum_to_tungstenite(msg: Message) -> tungstenite::Message {
  function tungstenite_to_axum (line 272) | fn tungstenite_to_axum(msg: tungstenite::Message) -> Message {

FILE: bin/core/src/ws/stack.rs
  function terminal (line 19) | pub async fn terminal(

FILE: bin/core/src/ws/terminal.rs
  function handler (line 17) | pub async fn handler(

FILE: bin/core/src/ws/update.rs
  function handler (line 20) | pub async fn handler(ws: WebSocketUpgrade) -> impl IntoResponse {
  function user_can_see_update (line 86) | async fn user_can_see_update(

FILE: bin/periphery/src/api/build.rs
  method resolve (line 36) | async fn resolve(
  method resolve (line 85) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  function resolve (line 119) | async fn resolve(
  method resolve (line 320) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  method resolve (line 330) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {

FILE: bin/periphery/src/api/compose.rs
  method resolve (line 36) | async fn resolve(
  type DockerComposeLsItem (line 84) | pub struct DockerComposeLsItem {
  method resolve (line 98) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  method resolve (line 121) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  method resolve (line 149) | async fn resolve(
  method resolve (line 217) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  method resolve (line 261) | async fn resolve(
  method resolve (line 313) | async fn resolve(
  method resolve (line 427) | async fn resolve(
  method resolve (line 687) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  method resolve (line 704) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {

FILE: bin/periphery/src/api/container.rs
  method resolve (line 29) | async fn resolve(
  method resolve (line 41) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  method resolve (line 62) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  method resolve (line 90) | async fn resolve(
  method resolve (line 105) | async fn resolve(
  method resolve (line 120) | async fn resolve(
  method resolve (line 134) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  method resolve (line 150) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  method resolve (line 166) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  method resolve (line 180) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  method resolve (line 196) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  method resolve (line 223) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  method resolve (line 257) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  method resolve (line 271) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  method resolve (line 281) | async fn resolve(
  method resolve (line 308) | async fn resolve(
  method resolve (line 335) | async fn resolve(
  method resolve (line 362) | async fn resolve(
  method resolve (line 389) | async fn resolve(

FILE: bin/periphery/src/api/deploy.rs
  method resolve (line 36) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  function docker_run_command (line 115) | fn docker_run_command(
  function parse_conversions (line 159) | fn parse_conversions(
  function parse_environment (line 170) | fn parse_environment(environment: &[EnvironmentVar]) -> String {
  function parse_network (line 187) | fn parse_network(network: &str) -> String {
  function parse_restart (line 191) | fn parse_restart(restart: &RestartMode) -> String {
  function parse_command (line 199) | fn parse_command(command: &str) -> String {

FILE: bin/periphery/src/api/git.rs
  method resolve (line 23) | async fn resolve(
  method resolve (line 48) | async fn resolve(
  method resolve (line 93) | async fn resolve(
  method resolve (line 137) | async fn resolve(
  method resolve (line 176) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  method resolve (line 197) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  function default_folder (line 223) | fn default_folder(

FILE: bin/periphery/src/api/image.rs
  method resolve (line 20) | async fn resolve(self, _: &super::Args) -> serror::Result<Image> {
  method resolve (line 29) | async fn resolve(
  constant PULL_TIMEOUT (line 40) | const PULL_TIMEOUT: i64 = 5_000;
  function pull_cache (line 42) | fn pull_cache() -> &'static TimeoutCache<String, Log> {
  method resolve (line 50) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  method resolve (line 99) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  method resolve (line 109) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {

FILE: bin/periphery/src/api/mod.rs
  type Args (line 34) | pub struct Args;
  type PeripheryRequest (line 45) | pub enum PeripheryRequest {
  method resolve (line 156) | async fn resolve(
  method resolve (line 168) | async fn resolve(
  method resolve (line 182) | async fn resolve(
  method resolve (line 196) | async fn resolve(
  method resolve (line 208) | async fn resolve(self, _: &Args) -> serror::Result<Vec<String>> {
  method resolve (line 221) | async fn resolve(
  method resolve (line 253) | async fn resolve(self, _: &Args) -> serror::Result<Log> {
  method resolve (line 273) | async fn resolve(self, _: &Args) -> serror::Result<Log> {

FILE: bin/periphery/src/api/network.rs
  method resolve (line 14) | async fn resolve(self, _: &super::Args) -> serror::Result<Network> {
  method resolve (line 23) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  method resolve (line 38) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  method resolve (line 48) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {

FILE: bin/periphery/src/api/router.rs
  function router (line 19) | pub fn router() -> Router {
  function handler (line 48) | async fn handler(
  function task (line 64) | async fn task(
  function guard_request_by_passkey (line 82) | async fn guard_request_by_passkey(
  function guard_request_by_ip (line 113) | async fn guard_request_by_ip(

FILE: bin/periphery/src/api/stats.rs
  method resolve (line 17) | async fn resolve(
  method resolve (line 29) | async fn resolve(
  method resolve (line 41) | async fn resolve(

FILE: bin/periphery/src/api/terminal.rs
  method resolve (line 25) | async fn resolve(
  method resolve (line 36) | async fn resolve(self, _: &super::Args) -> serror::Result<NoData> {
  method resolve (line 52) | async fn resolve(self, _: &super::Args) -> serror::Result<NoData> {
  method resolve (line 60) | async fn resolve(self, _: &super::Args) -> serror::Result<NoData> {
  method resolve (line 68) | async fn resolve(
  function connect_terminal (line 78) | pub async fn connect_terminal(
  function connect_container_exec (line 91) | pub async fn connect_container_exec(
  function handle_terminal_websocket (line 132) | async fn handle_terminal_websocket(
  function execute_terminal (line 283) | pub async fn execute_terminal(
  function execute_container_exec (line 298) | pub async fn execute_container_exec(
  function execute_command_on_terminal (line 331) | async fn execute_command_on_terminal(

FILE: bin/periphery/src/api/volume.rs
  method resolve (line 12) | async fn resolve(self, _: &super::Args) -> serror::Result<Volume> {
  method resolve (line 21) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {
  method resolve (line 31) | async fn resolve(self, _: &super::Args) -> serror::Result<Log> {

FILE: bin/periphery/src/build.rs
  function write_dockerfile (line 13) | pub async fn write_dockerfile(
  function parse_build_args (line 55) | pub fn parse_build_args(build_args: &[EnvironmentVar]) -> String {
  function parse_secret_args (line 73) | pub async fn parse_secret_args(

FILE: bin/periphery/src/compose/mod.rs
  function docker_compose (line 19) | pub fn docker_compose() -> &'static str {
  function env_file_args (line 27) | pub fn env_file_args(
  function down (line 56) | pub async fn down(
  function pull_or_clone_stack (line 88) | pub async fn pull_or_clone_stack(

FILE: bin/periphery/src/compose/up.rs
  function validate_files (line 15) | pub async fn validate_files(
  function maybe_login_registry (line 84) | pub async fn maybe_login_registry(

FILE: bin/periphery/src/compose/write.rs
  type WriteStackRes (line 20) | pub trait WriteStackRes {
    method logs (line 21) | fn logs(&mut self) -> &mut Vec<Log>;
    method add_remote_error (line 22) | fn add_remote_error(&mut self, _contents: FileContents) {}
    method set_commit_hash (line 23) | fn set_commit_hash(&mut self, _hash: Option<String>) {}
    method set_commit_message (line 24) | fn set_commit_message(&mut self, _message: Option<String>) {}
    method logs (line 28) | fn logs(&mut self) -> &mut Vec<Log> {
    method add_remote_error (line 31) | fn add_remote_error(&mut self, contents: FileContents) {
    method set_commit_hash (line 34) | fn set_commit_hash(&mut self, hash: Option<String>) {
    method set_commit_message (line 37) | fn set_commit_message(&mut self, message: Option<String>) {
    method logs (line 43) | fn logs(&mut self) -> &mut Vec<Log> {
    method logs (line 49) | fn logs(&mut self) -> &mut Vec<Log> {
  function write_stack (line 57) | pub async fn write_stack<'a>(
  function write_stack_files_on_host (line 81) | async fn write_stack_files_on_host(
  function write_stack_linked_repo (line 117) | async fn write_stack_linked_repo<'a>(
  function write_stack_inline_repo (line 216) | async fn write_stack_inline_repo(
  function write_stack_ui_defined (line 301) | async fn write_stack_ui_defined(
  function stack_git_token (line 366) | fn stack_git_token<R: WriteStackRes>(

FILE: bin/periphery/src/config.rs
  function periphery_config (line 12) | pub fn periphery_config() -> &'static PeripheryConfig {

FILE: bin/periphery/src/docker/containers.rs
  method list_containers (line 15) | pub async fn list_containers(
  method inspect_container (line 104) | pub async fn inspect_container(
  function convert_summary_container_state (line 524) | fn convert_summary_container_state(
  function convert_container_state_status (line 555) | fn convert_container_state_status(
  function convert_port_type (line 586) | fn convert_port_type(
  function convert_port (line 596) | fn convert_port(port: bollard::secret::Port) -> Port {
  function convert_health_status (line 605) | fn convert_health_status(
  function convert_health_check_result (line 625) | fn convert_health_check_result(
  function convert_restart_policy (line 636) | fn convert_restart_policy(
  function convert_mount_type (line 658) | fn convert_mount_type(
  function convert_mount_point_type (line 672) | fn convert_mount_point_type(
  function convert_mount_propogation (line 698) | fn convert_mount_propogation(
  function convert_cgroupns_mode (line 726) | fn convert_cgroupns_mode(
  function convert_isolation_mode (line 742) | fn convert_isolation_mode(

FILE: bin/periphery/src/docker/images.rs
  method list_images (line 10) | pub async fn list_images(
  method inspect_image (line 44) | pub async fn inspect_image(
  method image_history (line 123) | pub async fn image_history(

FILE: bin/periphery/src/docker/mod.rs
  function docker_client (line 16) | pub fn docker_client() -> &'static DockerClient {
  type DockerClient (line 21) | pub struct DockerClient {
  method default (line 26) | fn default() -> DockerClient {
  function docker_login (line 36) | pub async fn docker_login(
  function pull_image (line 72) | pub async fn pull_image(image: &str) -> Log {
  function stop_container_command (line 77) | pub fn stop_container_command(

FILE: bin/periphery/src/docker/networks.rs
  method list_networks (line 11) | pub async fn list_networks(
  method inspect_network (line 61) | pub async fn inspect_network(

FILE: bin/periphery/src/docker/stats.rs
  type ContainerStatsMap (line 24) | pub type ContainerStatsMap = HashMap<String, ContainerStats>;
  function container_stats (line 26) | pub fn container_stats() -> &'static ArcSwap<ContainerStatsMap> {
  function spawn_polling_thread (line 32) | pub fn spawn_polling_thread() {
  function update_container_stats (line 47) | async fn update_container_stats() {
  function get_container_stats (line 60) | pub async fn get_container_stats(
  method full_container_stats (line 96) | pub async fn full_container_stats(
  function convert_pids_stats (line 126) | fn convert_pids_stats(
  function convert_blkio_stats (line 135) | fn convert_blkio_stats(
  function convert_blkio_stat_entries (line 166) | fn convert_blkio_stat_entries(
  function convert_storage_stats (line 180) | fn convert_storage_stats(
  function convert_cpu_stats (line 191) | fn convert_cpu_stats(
  function convert_cpu_usage (line 204) | fn convert_cpu_usage(
  function convert_cpu_throttling_data (line 215) | fn convert_cpu_throttling_data(
  function convert_memory_stats (line 225) | fn convert_memory_stats(
  function convert_network_stats (line 240) | fn convert_network_stats(

FILE: bin/periphery/src/docker/volumes.rs
  method list_volumes (line 9) | pub async fn list_volumes(
  method inspect_volume (line 52) | pub async fn inspect_volume(

FILE: bin/periphery/src/git.rs
  function handle_post_repo_execution (line 14) | pub async fn handle_post_repo_execution(

FILE: bin/periphery/src/helpers.rs
  function git_token_simple (line 9) | pub fn git_token_simple(
  function git_token (line 23) | pub fn git_token(
  function registry_token (line 37) | pub fn registry_token(
  function parse_extra_args (line 51) | pub fn parse_extra_args(extra_args: &[String]) -> String {
  function parse_labels (line 60) | pub fn parse_labels(labels: &[EnvironmentVar]) -> String {
  function log_grep (line 77) | pub fn log_grep(

FILE: bin/periphery/src/main.rs
  function app (line 22) | async fn app() -> anyhow::Result<()> {
  function main (line 76) | async fn main() -> anyhow::Result<()> {

FILE: bin/periphery/src/ssl.rs
  function ensure_certs (line 3) | pub async fn ensure_certs() {
  function generate_self_signed_ssl_certs (line 13) | async fn generate_self_signed_ssl_certs() {

FILE: bin/periphery/src/stats.rs
  function stats_client (line 13) | pub fn stats_client() -> &'static RwLock<StatsClient> {
  function spawn_polling_thread (line 21) | pub fn spawn_polling_thread() {
  type StatsClient (line 39) | pub struct StatsClient {
    method refresh (line 75) | fn refresh(&mut self) {
    method get_system_stats (line 87) | pub fn get_system_stats(&self) -> SystemStats {
    method get_disks (line 120) | fn get_disks(&self) -> Vec<SingleDiskUsage> {
    method get_processes (line 161) | pub fn get_processes(&self) -> Vec<SystemProcess> {
  constant BYTES_PER_GB (line 51) | const BYTES_PER_GB: f64 = 1073741824.0;
  constant BYTES_PER_MB (line 52) | const BYTES_PER_MB: f64 = 1048576.0;
  constant BYTES_PER_KB (line 53) | const BYTES_PER_KB: f64 = 1024.0;
  method default (line 56) | fn default() -> Self {
  function get_system_information (line 201) | fn get_system_information(

FILE: bin/periphery/src/terminal.rs
  type PtyName (line 24) | type PtyName = String;
  type PtyMap (line 25) | type PtyMap = tokio::sync::RwLock<HashMap<PtyName, Arc<Terminal>>>;
  type StdinSender (line 26) | type StdinSender = mpsc::Sender<StdinMsg>;
  type StdoutReceiver (line 27) | type StdoutReceiver = broadcast::Receiver<Bytes>;
  function create_terminal (line 29) | pub async fn create_terminal(
  function delete_terminal (line 63) | pub async fn delete_terminal(name: &str) {
  function list_terminals (line 69) | pub async fn list_terminals() -> Vec<TerminalInfo> {
  function get_terminal (line 84) | pub async fn get_terminal(
  function clean_up_terminals (line 95) | pub async fn clean_up_terminals() {
  function delete_all_terminals (line 102) | pub async fn delete_all_terminals() {
  function terminals (line 113) | fn terminals() -> &'static PtyMap {
  type ResizeDimensions (line 119) | pub struct ResizeDimensions {
  type StdinMsg (line 125) | pub enum StdinMsg {
  type Terminal (line 130) | pub struct Terminal {
    method new (line 143) | async fn new(command: String) -> anyhow::Result<Terminal> {
    method cancel (line 312) | pub fn cancel(&self) {
  constant MAX_BYTES (line 319) | const MAX_BYTES: usize = 1024 * 1024;
  type History (line 321) | pub struct History {
    method push (line 335) | fn push(&self, bytes: &[u8]) {
    method bytes_parts (line 345) | pub fn bytes_parts(&self) -> (Bytes, Bytes) {
    method size_kb (line 351) | pub fn size_kb(&self) -> f64 {
  method default (line 326) | fn default() -> Self {
  constant START_OF_OUTPUT (line 357) | pub const START_OF_OUTPUT: &str = "__KOMODO_START_OF_OUTPUT__";
  constant END_OF_OUTPUT (line 358) | pub const END_OF_OUTPUT: &str = "__KOMODO_END_OF_OUTPUT__";
  type Item (line 370) | type Item = Result<String, String>;
  method poll_next (line 372) | fn poll_next(
  constant TOKEN_VALID_FOR_MS (line 401) | const TOKEN_VALID_FOR_MS: i64 = 3_000;
  function auth_tokens (line 403) | pub fn auth_tokens() -> &'static AuthTokens {
  type AuthTokens (line 409) | pub struct AuthTokens {
    method create_auth_token (line 414) | pub fn create_auth_token(&self) -> String {
    method check_token (line 428) | pub fn check_token(&self, token: String) -> serror::Result<()> {

FILE: client/core/rs/src/api/auth.rs
  type KomodoAuthRequest (line 8) | pub trait KomodoAuthRequest: HasResponse {}
  type JwtResponse (line 13) | pub struct JwtResponse {
  type GetLoginOptions (line 32) | pub struct GetLoginOptions {}
  type GetLoginOptionsResponse (line 37) | pub struct GetLoginOptionsResponse {
  type SignUpLocalUser (line 65) | pub struct SignUpLocalUser {
  type SignUpLocalUserResponse (line 75) | pub type SignUpLocalUserResponse = JwtResponse;
  type LoginLocalUser (line 90) | pub struct LoginLocalUser {
  type LoginLocalUserResponse (line 99) | pub type LoginLocalUserResponse = JwtResponse;
  type ExchangeForJwt (line 113) | pub struct ExchangeForJwt {
  type ExchangeForJwtResponse (line 120) | pub type ExchangeForJwtResponse = JwtResponse;
  type GetUser (line 133) | pub struct GetUser {}
  type GetUserResponse (line 136) | pub type GetUserResponse = User;

FILE: client/core/rs/src/api/execute/action.rs
  type RunAction (line 27) | pub struct RunAction {
  function args_parser (line 39) | fn args_parser(args: &str) -> anyhow::Result<JsonObject> {
  type BatchRunAction (line 58) | pub struct BatchRunAction {

FILE: client/core/rs/src/api/execute/alerter.rs
  type TestAlerter (line 26) | pub struct TestAlerter {
  type SendAlert (line 48) | pub struct SendAlert {

FILE: client/core/rs/src/api/execute/build.rs
  type RunBuild (line 40) | pub struct RunBuild {
  type BatchRunBuild (line 62) | pub struct BatchRunBuild {
  type CancelBuild (line 95) | pub struct CancelBuild {

FILE: client/core/rs/src/api/execute/deployment.rs
  type Deploy (line 32) | pub struct Deploy {
  type BatchDeploy (line 60) | pub struct BatchDeploy {
  type PullDeployment (line 91) | pub struct PullDeployment {
  type StartDeployment (line 115) | pub struct StartDeployment {
  type RestartDeployment (line 139) | pub struct RestartDeployment {
  type PauseDeployment (line 163) | pub struct PauseDeployment {
  type UnpauseDeployment (line 189) | pub struct UnpauseDeployment {
  type StopDeployment (line 213) | pub struct StopDeployment {
  type DestroyDeployment (line 242) | pub struct DestroyDeployment {
  type BatchDestroyDeployment (line 268) | pub struct BatchDestroyDeployment {

FILE: client/core/rs/src/api/execute/maintenance.rs
  type ClearRepoCache (line 27) | pub struct ClearRepoCache {}
  type BackupCoreDatabase (line 51) | pub struct BackupCoreDatabase {}
  type GlobalAutoUpdate (line 73) | pub struct GlobalAutoUpdate {}

FILE: client/core/rs/src/api/execute/mod.rs
  type KomodoExecuteRequest (line 35) | pub trait KomodoExecuteRequest: HasResponse {}
  type Execution (line 58) | pub enum Execution {
  type Sleep (line 174) | pub struct Sleep {
  type BatchExecutionResponse (line 180) | pub type BatchExecutionResponse = Vec<BatchExecutionResponseItem>;
  type BatchExecutionResponseItem (line 185) | pub enum BatchExecutionResponseItem {
    method from (line 193) | fn from(
  type BatchExecutionResponseItemErr (line 205) | pub struct BatchExecutionResponseItemErr {

FILE: client/core/rs/src/api/execute/procedure.rs
  type RunProcedure (line 26) | pub struct RunProcedure {
  type BatchRunProcedure (line 46) | pub struct BatchRunProcedure {

FILE: client/core/rs/src/api/execute/repo.rs
  type CloneRepo (line 36) | pub struct CloneRepo {
  type BatchCloneRepo (line 58) | pub struct BatchCloneRepo {
  type PullRepo (line 94) | pub struct PullRepo {
  type BatchPullRepo (line 116) | pub struct BatchPullRepo {
  type BuildRepo (line 156) | pub struct BuildRepo {
  type BatchBuildRepo (line 178) | pub struct BatchBuildRepo {
  type CancelRepoBuild (line 211) | pub struct CancelRepoBuild {

FILE: client/core/rs/src/api/execute/server.rs
  type StartContainer (line 32) | pub struct StartContainer {
  type RestartContainer (line 58) | pub struct RestartContainer {
  type PauseContainer (line 84) | pub struct PauseContainer {
  type UnpauseContainer (line 112) | pub struct UnpauseContainer {
  type StopContainer (line 138) | pub struct StopContainer {
  type DestroyContainer (line 169) | pub struct DestroyContainer {
  type StartAllContainers (line 197) | pub struct StartAllContainers {
  type RestartAllContainers (line 219) | pub struct RestartAllContainers {
  type PauseAllContainers (line 241) | pub struct PauseAllContainers {
  type UnpauseAllContainers (line 263) | pub struct UnpauseAllContainers {
  type StopAllContainers (line 285) | pub struct StopAllContainers {
  type PruneContainers (line 309) | pub struct PruneContainers {
  type DeleteNetwork (line 334) | pub struct DeleteNetwork {
  type PruneNetworks (line 360) | pub struct PruneNetworks {
  type DeleteImage (line 383) | pub struct DeleteImage {
  type PruneImages (line 409) | pub struct PruneImages {
  type DeleteVolume (line 432) | pub struct DeleteVolume {
  type PruneVolumes (line 458) | pub struct PruneVolumes {
  type PruneDockerBuilders (line 482) | pub struct PruneDockerBuilders {
  type PruneBuildx (line 506) | pub struct PruneBuildx {
  type PruneSystem (line 530) | pub struct PruneSystem {

FILE: client/core/rs/src/api/execute/stack.rs
  type DeployStack (line 28) | pub struct DeployStack {
  type BatchDeployStack (line 57) | pub struct BatchDeployStack {
  type DeployStackIfChanged (line 90) | pub struct DeployStackIfChanged {
  type BatchDeployStackIfChanged (line 115) | pub struct BatchDeployStackIfChanged {
  type PullStack (line 146) | pub struct PullStack {
  type BatchPullStack (line 172) | pub struct BatchPullStack {
  type StartStack (line 203) | pub struct StartStack {
  type RestartStack (line 229) | pub struct RestartStack {
  type PauseStack (line 255) | pub struct PauseStack {
  type UnpauseStack (line 283) | pub struct UnpauseStack {
  type StopStack (line 309) | pub struct StopStack {
  type DestroyStack (line 337) | pub struct DestroyStack {
  type RunStackService (line 368) | pub struct RunStackService {
  function env_parser (line 405) | fn env_parser(args: &str) -> anyhow::Result<HashMap<String, String>> {
  type BatchDestroyStack (line 426) | pub struct BatchDestroyStack {

FILE: client/core/rs/src/api/execute/sync.rs
  type RunSync (line 26) | pub struct RunSync {

FILE: client/core/rs/src/api/read/action.rs
  type GetAction (line 22) | pub struct GetAction {
  type GetActionResponse (line 29) | pub type GetActionResponse = Action;
  type ListActions (line 41) | pub struct ListActions {
  type ListActionsResponse (line 48) | pub type ListActionsResponse = Vec<ActionListItem>;
  type ListFullActions (line 60) | pub struct ListFullActions {
  type ListFullActionsResponse (line 67) | pub type ListFullActionsResponse = Vec<Action>;
  type GetActionActionState (line 79) | pub struct GetActionActionState {
  type GetActionActionStateResponse (line 86) | pub type GetActionActionStateResponse = ActionActionState;
  type GetActionsSummary (line 99) | pub struct GetActionsSummary {}
  type GetActionsSummaryResponse (line 104) | pub struct GetActionsSummaryResponse {

FILE: client/core/rs/src/api/read/alert.rs
  type ListAlerts (line 19) | pub struct ListAlerts {
  type ListAlertsResponse (line 54) | pub struct ListAlertsResponse {
  type GetAlert (line 71) | pub struct GetAlert {
  type GetAlertResponse (line 76) | pub type GetAlertResponse = Alert;

FILE: client/core/rs/src/api/read/alerter.rs
  type GetAlerter (line 22) | pub struct GetAlerter {
  type GetAlerterResponse (line 29) | pub type GetAlerterResponse = Alerter;
  type ListAlerters (line 41) | pub struct ListAlerters {
  type ListAlertersResponse (line 48) | pub type ListAlertersResponse = Vec<AlerterListItem>;
  type ListFullAlerters (line 58) | pub struct ListFullAlerters {
  type ListFullAlertersResponse (line 65) | pub type ListFullAlertersResponse = Vec<Alerter>;
  type GetAlertersSummary (line 78) | pub struct GetAlertersSummary {}
  type GetAlertersSummaryResponse (line 83) | pub struct GetAlertersSummaryResponse {

FILE: client/core/rs/src/api/read/build.rs
  type GetBuild (line 25) | pub struct GetBuild {
  type GetBuildResponse (line 32) | pub type GetBuildResponse = Build;
  type ListBuilds (line 44) | pub struct ListBuilds {
  type ListBuildsResponse (line 51) | pub type ListBuildsResponse = Vec<BuildListItem>;
  type ListFullBuilds (line 63) | pub struct ListFullBuilds {
  type ListFullBuildsResponse (line 70) | pub type ListFullBuildsResponse = Vec<Build>;
  type GetBuildActionState (line 82) | pub struct GetBuildActionState {
  type GetBuildActionStateResponse (line 89) | pub type GetBuildActionStateResponse = BuildActionState;
  type GetBuildsSummary (line 102) | pub struct GetBuildsSummary {}
  type GetBuildsSummaryResponse (line 107) | pub struct GetBuildsSummaryResponse {
  type GetBuildMonthlyStats (line 134) | pub struct GetBuildMonthlyStats {
  type GetBuildMonthlyStatsResponse (line 144) | pub struct GetBuildMonthlyStatsResponse {
    method new (line 160) | pub fn new(
  type BuildStatsDay (line 153) | pub struct BuildStatsDay {
  type ListBuildVersions (line 196) | pub struct ListBuildVersions {
  type ListBuildVersionsResponse (line 211) | pub type ListBuildVersionsResponse = Vec<BuildVersionResponseItem>;
  type BuildVersionResponseItem (line 215) | pub struct BuildVersionResponseItem {
  type ListCommonBuildExtraArgs (line 231) | pub struct ListCommonBuildExtraArgs {
  type ListCommonBuildExtraArgsResponse (line 238) | pub type ListCommonBuildExtraArgsResponse = Vec<String>;
  type GetBuildWebhookEnabled (line 250) | pub struct GetBuildWebhookEnabled {
  type GetBuildWebhookEnabledResponse (line 259) | pub struct GetBuildWebhookEnabledResponse {

FILE: client/core/rs/src/api/read/builder.rs
  type GetBuilder (line 22) | pub struct GetBuilder {
  type GetBuilderResponse (line 29) | pub type GetBuilderResponse = Builder;
  type ListBuilders (line 41) | pub struct ListBuilders {
  type ListBuildersResponse (line 47) | pub type ListBuildersResponse = Vec<BuilderListItem>;
  type ListFullBuilders (line 59) | pub struct ListFullBuilders {
  type ListFullBuildersResponse (line 65) | pub type ListFullBuildersResponse = Vec<Builder>;
  type GetBuildersSummary (line 78) | pub struct GetBuildersSummary {}
  type GetBuildersSummaryResponse (line 83) | pub struct GetBuildersSummaryResponse {

FILE: client/core/rs/src/api/read/deployment.rs
  type GetDeployment (line 28) | pub struct GetDeployment {
  type GetDeploymentResponse (line 35) | pub type GetDeploymentResponse = Deployment;
  type ListDeployments (line 48) | pub struct ListDeployments {
  type ListDeploymentsResponse (line 55) | pub type ListDeploymentsResponse = Vec<DeploymentListItem>;
  type ListFullDeployments (line 68) | pub struct ListFullDeployments {
  type ListFullDeploymentsResponse (line 75) | pub type ListFullDeploymentsResponse = Vec<Deployment>;
  type GetDeploymentContainer (line 92) | pub struct GetDeploymentContainer {
  type GetDeploymentContainerResponse (line 101) | pub struct GetDeploymentContainerResponse {
  type InspectDeploymentContainer (line 117) | pub struct InspectDeploymentContainer {
  type InspectDeploymentContainerResponse (line 124) | pub type InspectDeploymentContainerResponse = Container;
  type GetDeploymentLog (line 139) | pub struct GetDeploymentLog {
  function default_tail (line 153) | fn default_tail() -> u64 {
  type GetDeploymentLogResponse (line 158) | pub type GetDeploymentLogResponse = Log;
  type SearchDeploymentLog (line 173) | pub struct SearchDeploymentLog {
  type SearchDeploymentLogResponse (line 194) | pub type SearchDeploymentLogResponse = Log;
  type GetDeploymentStats (line 209) | pub struct GetDeploymentStats {
  type GetDeploymentStatsResponse (line 216) | pub type GetDeploymentStatsResponse = ContainerStats;
  type GetDeploymentActionState (line 229) | pub struct GetDeploymentActionState {
  type GetDeploymentActionStateResponse (line 236) | pub type GetDeploymentActionStateResponse = DeploymentActionState;
  type GetDeploymentsSummary (line 249) | pub struct GetDeploymentsSummary {}
  type GetDeploymentsSummaryResponse (line 254) | pub struct GetDeploymentsSummaryResponse {
  type ListCommonDeploymentExtraArgs (line 280) | pub struct ListCommonDeploymentExtraArgs {
  type ListCommonDeploymentExtraArgsResponse (line 287) | pub type ListCommonDeploymentExtraArgsResponse = Vec<String>;

FILE: client/core/rs/src/api/read/mod.rs
  type KomodoReadRequest (line 53) | pub trait KomodoReadRequest: HasResponse {}
  type GetVersion (line 66) | pub struct GetVersion {}
  type GetVersionResponse (line 71) | pub struct GetVersionResponse {
  type GetCoreInfo (line 87) | pub struct GetCoreInfo {}
  type GetCoreInfoResponse (line 92) | pub struct GetCoreInfoResponse {
  type ListGitProvidersFromConfig (line 133) | pub struct ListGitProvidersFromConfig {
  type ListGitProvidersFromConfigResponse (line 140) | pub type ListGitProvidersFromConfigResponse = Vec<GitProvider>;
  type ListDockerRegistriesFromConfig (line 158) | pub struct ListDockerRegistriesFromConfig {
  type ListDockerRegistriesFromConfigResponse (line 165) | pub type ListDockerRegistriesFromConfigResponse = Vec<DockerRegistry>;
  type ListSecrets (line 178) | pub struct ListSecrets {
  type ListSecretsResponse (line 185) | pub type ListSecretsResponse = Vec<String>;

FILE: client/core/rs/src/api/read/permission.rs
  type ListPermissions (line 23) | pub struct ListPermissions {}
  type ListPermissionsResponse (line 26) | pub type ListPermissionsResponse = Vec<Permission>;
  type GetPermission (line 40) | pub struct GetPermission {
  type GetPermissionResponse (line 46) | pub type GetPermissionResponse = PermissionLevelAndSpecifics;
  type ListUserTargetPermissions (line 59) | pub struct ListUserTargetPermissions {
  type ListUserTargetPermissionsResponse (line 65) | pub type ListUserTargetPermissionsResponse = Vec<Permission>;

FILE: client/core/rs/src/api/read/procedure.rs
  type GetProcedure (line 22) | pub struct GetProcedure {
  type GetProcedureResponse (line 29) | pub type GetProcedureResponse = Procedure;
  type ListProcedures (line 41) | pub struct ListProcedures {
  type ListProceduresResponse (line 48) | pub type ListProceduresResponse = Vec<ProcedureListItem>;
  type ListFullProcedures (line 60) | pub struct ListFullProcedures {
  type ListFullProceduresResponse (line 67) | pub type ListFullProceduresResponse = Vec<Procedure>;
  type GetProcedureActionState (line 79) | pub struct GetProcedureActionState {
  type GetProcedureActionStateResponse (line 86) | pub type GetProcedureActionStateResponse = ProcedureActionState;
  type GetProceduresSummary (line 99) | pub struct GetProceduresSummary {}
  type GetProceduresSummaryResponse (line 104) | pub struct GetProceduresSummaryResponse {

FILE: client/core/rs/src/api/read/provider.rs
  type GetGitProviderAccount (line 21) | pub struct GetGitProviderAccount {
  type GetGitProviderAccountResponse (line 26) | pub type GetGitProviderAccountResponse = GitProviderAccount;
  type ListGitProviderAccounts (line 39) | pub struct ListGitProviderAccounts {
  type ListGitProviderAccountsResponse (line 47) | pub type ListGitProviderAccountsResponse = Vec<GitProviderAccount>;
  type GetDockerRegistryAccount (line 60) | pub struct GetDockerRegistryAccount {
  type GetDockerRegistryAccountResponse (line 65) | pub type GetDockerRegistryAccountResponse = DockerRegistryAccount;
  type ListDockerRegistryAccounts (line 78) | pub struct ListDockerRegistryAccounts {
  type ListDockerRegistryAccountsResponse (line 86) | pub type ListDockerRegistryAccountsResponse =

FILE: client/core/rs/src/api/read/repo.rs
  type GetRepo (line 22) | pub struct GetRepo {
  type GetRepoResponse (line 29) | pub type GetRepoResponse = Repo;
  type ListRepos (line 41) | pub struct ListRepos {
  type ListReposResponse (line 48) | pub type ListReposResponse = Vec<RepoListItem>;
  type ListFullRepos (line 60) | pub struct ListFullRepos {
  type ListFullReposResponse (line 67) | pub type ListFullReposResponse = Vec<Repo>;
  type GetRepoActionState (line 79) | pub struct GetRepoActionState {
  type GetRepoActionStateResponse (line 86) | pub type GetRepoActionStateResponse = RepoActionState;
  type GetReposSummary (line 99) | pub struct GetReposSummary {}
  type GetReposSummaryResponse (line 104) | pub struct GetReposSummaryResponse {
  type GetRepoWebhooksEnabled (line 131) | pub struct GetRepoWebhooksEnabled {
  type GetRepoWebhooksEnabledResponse (line 140) | pub struct GetRepoWebhooksEnabledResponse {

FILE: client/core/rs/src/api/read/schedule.rs
  type ListSchedules (line 22) | pub struct ListSchedules {
  type ListSchedulesResponse (line 32) | pub type ListSchedulesResponse = Vec<Schedule>;

FILE: client/core/rs/src/api/read/server.rs
  type GetServer (line 37) | pub struct GetServer {
  type GetServerResponse (line 44) | pub type GetServerResponse = Server;
  type ListServers (line 56) | pub struct ListServers {
  type ListServersResponse (line 63) | pub type ListServersResponse = Vec<ServerListItem>;
  type ListFullServers (line 75) | pub struct ListFullServers {
  type ListFullServersResponse (line 82) | pub type ListFullServersResponse = Vec<Server>;
  type GetServerState (line 94) | pub struct GetServerState {
  type GetServerStateResponse (line 103) | pub struct GetServerStateResponse {
  type GetServerActionState (line 118) | pub struct GetServerActionState {
  type GetServerActionStateResponse (line 125) | pub type GetServerActionStateResponse = ServerActionState;
  type GetPeripheryVersion (line 138) | pub struct GetPeripheryVersion {
  type GetPeripheryVersionResponse (line 147) | pub struct GetPeripheryVersionResponse {
  type ListDockerNetworks (line 162) | pub struct ListDockerNetworks {
  type ListDockerNetworksResponse (line 169) | pub type ListDockerNetworksResponse = Vec<NetworkListItem>;
  type InspectDockerNetwork (line 181) | pub struct InspectDockerNetwork {
  type InspectDockerNetworkResponse (line 190) | pub type InspectDockerNetworkResponse = Network;
  type ListDockerImages (line 203) | pub struct ListDockerImages {
  type ListDockerImagesResponse (line 210) | pub type ListDockerImagesResponse = Vec<ImageListItem>;
  type InspectDockerImage (line 222) | pub struct InspectDockerImage {
  type InspectDockerImageResponse (line 231) | pub type InspectDockerImageResponse = Image;
  type ListDockerImageHistory (line 243) | pub struct ListDockerImageHistory {
  type ListDockerImageHistoryResponse (line 252) | pub type ListDockerImageHistoryResponse =
  type ListDockerContainers (line 266) | pub struct ListDockerContainers {
  type ListDockerContainersResponse (line 273) | pub type ListDockerContainersResponse = Vec<ContainerListItem>;
  type ListAllDockerContainers (line 286) | pub struct ListAllDockerContainers {
  type ListAllDockerContainersResponse (line 293) | pub type ListAllDockerContainersResponse = Vec<ContainerListItem>;
  type GetDockerContainersSummary (line 306) | pub struct GetDockerContainersSummary {}
  type GetDockerContainersSummaryResponse (line 311) | pub struct GetDockerContainersSummaryResponse {
  type InspectDockerContainer (line 334) | pub struct InspectDockerContainer {
  type InspectDockerContainerResponse (line 343) | pub type InspectDockerContainerResponse = Container;
  type GetContainerLog (line 358) | pub struct GetContainerLog {
  function default_tail (line 374) | fn default_tail() -> u64 {
  type GetContainerLogResponse (line 379) | pub type GetContainerLogResponse = Log;
  type SearchContainerLog (line 394) | pub struct SearchContainerLog {
  type SearchContainerLogResponse (line 417) | pub type SearchContainerLogResponse = Log;
  type GetResourceMatchingContainer (line 429) | pub struct GetResourceMatchingContainer {
  type GetResourceMatchingContainerResponse (line 440) | pub struct GetResourceMatchingContainerResponse {
  type ListDockerVolumes (line 455) | pub struct ListDockerVolumes {
  type ListDockerVolumesResponse (line 462) | pub type ListDockerVolumesResponse = Vec<VolumeListItem>;
  type InspectDockerVolume (line 474) | pub struct InspectDockerVolume {
  type InspectDockerVolumeResponse (line 483) | pub type InspectDockerVolumeResponse = Volume;
  type ListComposeProjects (line 496) | pub struct ListComposeProjects {
  type ListComposeProjectsResponse (line 503) | pub type ListComposeProjectsResponse = Vec<ComposeProject>;
  type GetSystemInformation (line 516) | pub struct GetSystemInformation {
  type GetSystemInformationResponse (line 523) | pub type GetSystemInformationResponse = SystemInformation;
  type GetSystemStats (line 539) | pub struct GetSystemStats {
  type GetSystemStatsResponse (line 546) | pub type GetSystemStatsResponse = SystemStats;
  type ListSystemProcesses (line 563) | pub struct ListSystemProcesses {
  type ListSystemProcessesResponse (line 570) | pub type ListSystemProcessesResponse = Vec<SystemProcess>;
  type GetHistoricalServerStats (line 583) | pub struct GetHistoricalServerStats {
  type GetHistoricalServerStatsResponse (line 598) | pub struct GetHistoricalServerStatsResponse {
  type GetServersSummary (line 616) | pub struct GetServersSummary {}
  type GetServersSummaryResponse (line 621) | pub struct GetServersSummaryResponse {
  type ListTerminals (line 645) | pub struct ListTerminals {
  type ListTerminalsResponse (line 656) | pub type ListTerminalsResponse = Vec<TerminalInfo>;

FILE: client/core/rs/src/api/read/stack.rs
  type GetStack (line 27) | pub struct GetStack {
  type GetStackResponse (line 34) | pub type GetStackResponse = Stack;
  type ListStackServices (line 46) | pub struct ListStackServices {
  type ListStackServicesResponse (line 53) | pub type ListStackServicesResponse = Vec<StackService>;
  type InspectStackContainer (line 66) | pub struct InspectStackContainer {
  type InspectStackContainerResponse (line 75) | pub type InspectStackContainerResponse = Container;
  type GetStackLog (line 89) | pub struct GetStackLog {
  function default_tail (line 106) | fn default_tail() -> u64 {
  type GetStackLogResponse (line 111) | pub type GetStackLogResponse = Log;
  type SearchStackLog (line 126) | pub struct SearchStackLog {
  type SearchStackLogResponse (line 150) | pub type SearchStackLogResponse = Log;
  type ListCommonStackExtraArgs (line 163) | pub struct ListCommonStackExtraArgs {
  type ListCommonStackExtraArgsResponse (line 170) | pub type ListCommonStackExtraArgsResponse = Vec<String>;
  type ListCommonStackBuildExtraArgs (line 183) | pub struct ListCommonStackBuildExtraArgs {
  type ListCommonStackBuildExtraArgsResponse (line 190) | pub type ListCommonStackBuildExtraArgsResponse = Vec<String>;
  type ListStacks (line 202) | pub struct ListStacks {
  type ListStacksResponse (line 209) | pub type ListStacksResponse = Vec<StackListItem>;
  type ListFullStacks (line 221) | pub struct ListFullStacks {
  type ListFullStacksResponse (line 228) | pub type ListFullStacksResponse = Vec<Stack>;
  type GetStackActionState (line 240) | pub struct GetStackActionState {
  type GetStackActionStateResponse (line 247) | pub type GetStackActionStateResponse = StackActionState;
  type GetStacksSummary (line 260) | pub struct GetStacksSummary {}
  type GetStacksSummaryResponse (line 265) | pub struct GetStacksSummaryResponse {
  type GetStackWebhooksEnabled (line 290) | pub struct GetStackWebhooksEnabled {
  type GetStackWebhooksEnabledResponse (line 299) | pub struct GetStackWebhooksEnabledResponse {

FILE: client/core/rs/src/api/read/sync.rs
  type GetResourceSync (line 23) | pub struct GetResourceSync {
  type GetResourceSyncResponse (line 30) | pub type GetResourceSyncResponse = ResourceSync;
  type ListResourceSyncs (line 42) | pub struct ListResourceSyncs {
  type ListResourceSyncsResponse (line 49) | pub type ListResourceSyncsResponse = Vec<ResourceSyncListItem>;
  type ListFullResourceSyncs (line 61) | pub struct ListFullResourceSyncs {
  type ListFullResourceSyncsResponse (line 68) | pub type ListFullResourceSyncsResponse = Vec<ResourceSync>;
  type GetResourceSyncActionState (line 80) | pub struct GetResourceSyncActionState {
  type GetResourceSyncActionStateResponse (line 87) | pub type GetResourceSyncActionStateResponse = ResourceSyncActionState;
  type GetResourceSyncsSummary (line 100) | pub struct GetResourceSyncsSummary {}
  type GetResourceSyncsSummaryResponse (line 105) | pub struct GetResourceSyncsSummaryResponse {
  type GetSyncWebhooksEnabled (line 130) | pub struct GetSyncWebhooksEnabled {
  type GetSyncWebhooksEnabledResponse (line 139) | pub struct GetSyncWebhooksEnabledResponse {

FILE: client/core/rs/src/api/read/tag.rs
  type GetTag (line 20) | pub struct GetTag {
  type GetTagResponse (line 27) | pub type GetTagResponse = Tag;
  type ListTags (line 40) | pub struct ListTags {
  type ListTagsResponse (line 45) | pub type ListTagsResponse = Vec<Tag>;

FILE: client/core/rs/src/api/read/toml.rs
  type TomlResponse (line 13) | pub struct TomlResponse {
  type ExportAllResourcesToToml (line 29) | pub struct ExportAllResourcesToToml {
  function default_include_resources (line 49) | fn default_include_resources() -> bool {
  type ExportAllResourcesToTomlResponse (line 54) | pub type ExportAllResourcesToTomlResponse = TomlResponse;
  type ExportResourcesToToml (line 67) | pub struct ExportResourcesToToml {
  type ExportResourcesToTomlResponse (line 80) | pub type ExportResourcesToTomlResponse = TomlResponse;

FILE: client/core/rs/src/api/read/update.rs
  type GetUpdate (line 22) | pub struct GetUpdate {
  type GetUpdateResponse (line 28) | pub type GetUpdateResponse = Update;
  type ListUpdates (line 41) | pub struct ListUpdates {
  type ListUpdatesResponse (line 53) | pub struct ListUpdatesResponse {

FILE: client/core/rs/src/api/read/user.rs
  type ListApiKeys (line 19) | pub struct ListApiKeys {}
  type ListApiKeysResponse (line 22) | pub type ListApiKeysResponse = Vec<ApiKey>;
  type ListApiKeysForServiceUser (line 37) | pub struct ListApiKeysForServiceUser {
  type ListApiKeysForServiceUserResponse (line 44) | pub type ListApiKeysForServiceUserResponse = Vec<ApiKey>;
  type FindUser (line 58) | pub struct FindUser {
  type FindUserResponse (line 65) | pub type FindUserResponse = User;
  type ListUsers (line 79) | pub struct ListUsers {}
  type ListUsersResponse (line 82) | pub type ListUsersResponse = Vec<User>;
  type GetUsername (line 95) | pub struct GetUsername {
  type GetUsernameResponse (line 103) | pub struct GetUsernameResponse {

FILE: client/core/rs/src/api/read/user_group.rs
  type GetUserGroup (line 19) | pub struct GetUserGroup {
  type GetUserGroupResponse (line 25) | pub type GetUserGroupResponse = UserGroup;
  type ListUserGroups (line 40) | pub struct ListUserGroups {}
  type ListUserGroupsResponse (line 43) | pub type ListUserGroupsResponse = Vec<UserGroup>;

FILE: client/core/rs/src/api/read/variable.rs
  type GetVariable (line 22) | pub struct GetVariable {
  type GetVariableResponse (line 28) | pub type GetVariableResponse = Variable;
  type ListVariables (line 44) | pub struct ListVariables {}
  type ListVariablesResponse (line 47) | pub type ListVariablesResponse = Vec<Variable>;

FILE: client/core/rs/src/api/terminal.rs
  type ConnectTerminalQuery (line 8) | pub struct ConnectTerminalQuery {
  type ExecuteTerminalBody (line 22) | pub struct ExecuteTerminalBody {
  type ConnectContainerExecQuery (line 38) | pub struct ConnectContainerExecQuery {
  type ExecuteContainerExecBody (line 51) | pub struct ExecuteContainerExecBody {
  type ConnectDeploymentExecQuery (line 67) | pub struct ConnectDeploymentExecQuery {
  type ExecuteDeploymentExecBody (line 78) | pub struct ExecuteDeploymentExecBody {
  type ConnectStackExecQuery (line 92) | pub struct ConnectStackExecQuery {
  type ExecuteStackExecBody (line 105) | pub struct ExecuteStackExecBody {

FILE: client/core/rs/src/api/user.rs
  type KomodoUserRequest (line 8) | pub trait KomodoUserRequest: HasResponse {}
  type PushRecentlyViewed (line 21) | pub struct PushRecentlyViewed {
  type PushRecentlyViewedResponse (line 27) | pub type PushRecentlyViewedResponse = NoData;
  type SetLastSeenUpdate (line 41) | pub struct SetLastSeenUpdate {}
  type SetLastSeenUpdateResponse (line 44) | pub type SetLastSeenUpdateResponse = NoData;
  type CreateApiKey (line 60) | pub struct CreateApiKey {
  type CreateApiKeyResponse (line 73) | pub struct CreateApiKeyResponse {
  type DeleteApiKey (line 95) | pub struct DeleteApiKey {
  type DeleteApiKeyResponse (line 101) | pub type DeleteApiKeyResponse = NoData;

FILE: client/core/rs/src/api/write/action.rs
  type CreateAction (line 24) | pub struct CreateAction {
  type CopyAction (line 43) | pub struct CopyAction {
  type DeleteAction (line 61) | pub struct DeleteAction {
  type UpdateAction (line 83) | pub struct UpdateAction {
  type RenameAction (line 101) | pub struct RenameAction {
  type CreateActionWebhook (line 117) | pub struct CreateActionWebhook {
  type CreateActionWebhookResponse (line 124) | pub type CreateActionWebhookResponse = NoData;
  type DeleteActionWebhook (line 137) | pub struct DeleteActionWebhook {
  type DeleteActionWebhookResponse (line 144) | pub type DeleteActionWebhookResponse = NoData;

FILE: client/core/rs/src/api/write/alerter.rs
  type CreateAlerter (line 23) | pub struct CreateAlerter {
  type CopyAlerter (line 42) | pub struct CopyAlerter {
  type DeleteAlerter (line 60) | pub struct DeleteAlerter {
  type UpdateAlerter (line 80) | pub struct UpdateAlerter {
  type RenameAlerter (line 98) | pub struct RenameAlerter {

FILE: client/core/rs/src/api/write/api_key.rs
  type CreateApiKeyForServiceUser (line 24) | pub struct CreateApiKeyForServiceUser {
  type CreateApiKeyForServiceUserResponse (line 36) | pub type CreateApiKeyForServiceUserResponse = CreateApiKeyResponse;
  type DeleteApiKeyForServiceUser (line 49) | pub struct DeleteApiKeyForServiceUser {
  type DeleteApiKeyForServiceUserResponse (line 54) | pub type DeleteApiKeyForServiceUserResponse = NoData;

FILE: client/core/rs/src/api/write/build.rs
  type CreateBuild (line 24) | pub struct CreateBuild {
  type CopyBuild (line 43) | pub struct CopyBuild {
  type DeleteBuild (line 61) | pub struct DeleteBuild {
  type UpdateBuild (line 83) | pub struct UpdateBuild {
  type RenameBuild (line 101) | pub struct RenameBuild {
  type WriteBuildFileContents (line 118) | pub struct WriteBuildFileContents {
  type RefreshBuildCache (line 136) | pub struct RefreshBuildCache {
  type CreateBuildWebhook (line 153) | pub struct CreateBuildWebhook {
  type CreateBuildWebhookResponse (line 160) | pub type CreateBuildWebhookResponse = NoData;
  type DeleteBuildWebhook (line 173) | pub struct DeleteBuildWebhook {
  type DeleteBuildWebhookResponse (line 180) | pub type DeleteBuildWebhookResponse = NoData;

FILE: client/core/rs/src/api/write/builder.rs
  type CreateBuilder (line 23) | pub struct CreateBuilder {
  type CopyBuilder (line 42) | pub struct CopyBuilder {
  type DeleteBuilder (line 60) | pub struct DeleteBuilder {
  type UpdateBuilder (line 82) | pub struct UpdateBuilder {
  type RenameBuilder (line 100) | pub struct RenameBuilder {

FILE: client/core/rs/src/api/write/deployment.rs
  type CreateDeployment (line 23) | pub struct CreateDeployment {
  type CopyDeployment (line 42) | pub struct CopyDeployment {
  type CreateDeploymentFromContainer (line 59) | pub struct CreateDeploymentFromContainer {
  type DeleteDeployment (line 80) | pub struct DeleteDeployment {
  type UpdateDeployment (line 105) | pub struct UpdateDeployment {
  type RenameDeployment (line 125) | pub struct RenameDeployment {

FILE: client/core/rs/src/api/write/mod.rs
  type KomodoWriteRequest (line 39) | pub trait KomodoWriteRequest: resolver_api::HasResponse {}

FILE: client/core/rs/src/api/write/permissions.rs
  type UpdatePermissionOnTarget (line 22) | pub struct UpdatePermissionOnTarget {
  type UpdatePermissionOnTargetResponse (line 32) | pub type UpdatePermissionOnTargetResponse = NoData;
  type UpdatePermissionOnResourceType (line 45) | pub struct UpdatePermissionOnResourceType {
  type UpdatePermissionOnResourceTypeResponse (line 55) | pub type UpdatePermissionOnResourceTypeResponse = NoData;
  type UpdateUserBasePermissions (line 68) | pub struct UpdateUserBasePermissions {
  type UpdateUserBasePermissionsResponse (line 80) | pub type UpdateUserBasePermissionsResponse = NoData;
  type UpdateUserAdmin (line 91) | pub struct UpdateUserAdmin {
  type UpdateUserAdminResponse (line 99) | pub type UpdateUserAdminResponse = NoData;

FILE: client/core/rs/src/api/write/procedure.rs
  type CreateProcedure (line 23) | pub struct CreateProcedure {
  type CreateProcedureResponse (line 32) | pub type CreateProcedureResponse = Procedure;
  type CopyProcedure (line 45) | pub struct CopyProcedure {
  type CopyProcedureResponse (line 53) | pub type CopyProcedureResponse = Procedure;
  type DeleteProcedure (line 66) | pub struct DeleteProcedure {
  type DeleteProcedureResponse (line 72) | pub type DeleteProcedureResponse = Procedure;
  type UpdateProcedure (line 91) | pub struct UpdateProcedure {
  type UpdateProcedureResponse (line 99) | pub type UpdateProcedureResponse = Procedure;
  type RenameProcedure (line 112) | pub struct RenameProcedure {

FILE: client/core/rs/src/api/write/provider.rs
  type CreateGitProviderAccount (line 19) | pub struct CreateGitProviderAccount {
  type CreateGitProviderAccountResponse (line 26) | pub type CreateGitProviderAccountResponse = GitProviderAccount;
  type UpdateGitProviderAccount (line 39) | pub struct UpdateGitProviderAccount {
  type UpdateGitProviderAccountResponse (line 47) | pub type UpdateGitProviderAccountResponse = GitProviderAccount;
  type DeleteGitProviderAccount (line 60) | pub struct DeleteGitProviderAccount {
  type DeleteGitProviderAccountResponse (line 66) | pub type DeleteGitProviderAccountResponse = GitProviderAccount;
  type CreateDockerRegistryAccount (line 79) | pub struct CreateDockerRegistryAccount {
  type CreateDockerRegistryAccountResponse (line 84) | pub type CreateDockerRegistryAccountResponse = DockerRegistryAccount;
  type UpdateDockerRegistryAccount (line 97) | pub struct UpdateDockerRegistryAccount {
  type UpdateDockerRegistryAccountResponse (line 105) | pub type UpdateDockerRegistryAccountResponse = DockerRegistryAccount;
  type DeleteDockerRegistryAccount (line 118) | pub struct DeleteDockerRegistryAccount {
  type DeleteDockerRegistryAccountResponse (line 124) | pub type DeleteDockerRegistryAccountResponse = DockerRegistryAccount;

FILE: client/core/rs/src/api/write/repo.rs
  type CreateRepo (line 24) | pub struct CreateRepo {
  type CopyRepo (line 43) | pub struct CopyRepo {
  type DeleteRepo (line 61) | pub struct DeleteRepo {
  type UpdateRepo (line 86) | pub struct UpdateRepo {
  type RenameRepo (line 104) | pub struct RenameRepo {
  type RefreshRepoCache (line 121) | pub struct RefreshRepoCache {
  type RepoWebhookAction (line 131) | pub enum RepoWebhookAction {
  type CreateRepoWebhook (line 146) | pub struct CreateRepoWebhook {
  type CreateRepoWebhookResponse (line 155) | pub type CreateRepoWebhookResponse = NoData;
  type DeleteRepoWebhook (line 168) | pub struct DeleteRepoWebhook {
  type DeleteRepoWebhookResponse (line 177) | pub type DeleteRepoWebhookResponse = NoData;

FILE: client/core/rs/src/api/write/resource.rs
  type UpdateResourceMeta (line 22) | pub struct UpdateResourceMeta {
  type UpdateResourceMetaResponse (line 37) | pub type UpdateResourceMetaResponse = NoData;

FILE: client/core/rs/src/api/write/server.rs
  type CreateServer (line 24) | pub struct CreateServer {
  type CopyServer (line 43) | pub struct CopyServer {
  type DeleteServer (line 61) | pub struct DeleteServer {
  type UpdateServer (line 83) | pub struct UpdateServer {
  type RenameServer (line 101) | pub struct RenameServer {
  type CreateNetwork (line 121) | pub struct CreateNetwork {
  type TerminalRecreateMode (line 134) | pub enum TerminalRecreateMode {
  type CreateTerminal (line 154) | pub struct CreateTerminal {
  function default_command (line 172) | fn default_command() -> String {
  type DeleteTerminal (line 187) | pub struct DeleteTerminal {
  type DeleteAllTerminals (line 203) | pub struct DeleteAllTerminals {

FILE: client/core/rs/src/api/write/stack.rs
  type CreateStack (line 24) | pub struct CreateStack {
  type CopyStack (line 43) | pub struct CopyStack {
  type DeleteStack (line 61) | pub struct DeleteStack {
  type UpdateStack (line 86) | pub struct UpdateStack {
  type RenameStack (line 103) | pub struct RenameStack {
  type WriteStackFileContents (line 120) | pub struct WriteStackFileContents {
  type RefreshStackCache (line 144) | pub struct RefreshStackCache {
  type StackWebhookAction (line 154) | pub enum StackWebhookAction {
  type CreateStackWebhook (line 168) | pub struct CreateStackWebhook {
  type CreateStackWebhookResponse (line 177) | pub type CreateStackWebhookResponse = NoData;
  type DeleteStackWebhook (line 190) | pub struct DeleteStackWebhook {
  type DeleteStackWebhookResponse (line 199) | pub type DeleteStackWebhookResponse = NoData;

FILE: client/core/rs/src/api/write/sync.rs
  type CreateResourceSync (line 25) | pub struct CreateResourceSync {
  type CopyResourceSync (line 44) | pub struct CopyResourceSync {
  type DeleteResourceSync (line 62) | pub struct DeleteResourceSync {
  type UpdateResourceSync (line 84) | pub struct UpdateResourceSync {
  type RenameResourceSync (line 102) | pub struct RenameResourceSync {
  type RefreshResourceSyncPending (line 119) | pub struct RefreshResourceSyncPending {
  type WriteSyncFileContents (line 135) | pub struct WriteSyncFileContents {
  type CommitSync (line 167) | pub struct CommitSync {
  type SyncWebhookAction (line 177) | pub enum SyncWebhookAction {
  type CreateSyncWebhook (line 191) | pub struct CreateSyncWebhook {
  type CreateSyncWebhookResponse (line 200) | pub type CreateSyncWebhookResponse = NoData;
  type DeleteSyncWebhook (line 213) | pub struct DeleteSyncWebhook {
  type DeleteSyncWebhookResponse (line 222) | pub type DeleteSyncWebhookResponse = NoData;

FILE: client/core/rs/src/api/write/tags.rs
  type CreateTag (line 20) | pub struct CreateTag {
  type DeleteTag (line 39) | pub struct DeleteTag {
  type RenameTag (line 54) | pub struct RenameTag {
  type UpdateTagColor (line 69) | pub struct UpdateTagColor {

FILE: client/core/rs/src/api/write/user.rs
  type UpdateUserUsername (line 21) | pub struct UpdateUserUsername {
  type UpdateUserUsernameResponse (line 26) | pub type UpdateUserUsernameResponse = NoData;
  type UpdateUserPassword (line 39) | pub struct UpdateUserPassword {
  type UpdateUserPasswordResponse (line 44) | pub type UpdateUserPasswordResponse = NoData;
  type DeleteUser (line 61) | pub struct DeleteUser {
  type DeleteUserResponse (line 68) | pub type DeleteUserResponse = User;
  type CreateLocalUser (line 85) | pub struct CreateLocalUser {
  type CreateLocalUserResponse (line 93) | pub type CreateLocalUserResponse = User;
  type CreateServiceUser (line 106) | pub struct CreateServiceUser {
  type CreateServiceUserResponse (line 114) | pub type CreateServiceUserResponse = User;
  type UpdateServiceUserDescription (line 127) | pub struct UpdateServiceUserDescription {
  type UpdateServiceUserDescriptionResponse (line 135) | pub type UpdateServiceUserDescriptionResponse = User;

FILE: client/core/rs/src/api/write/user_group.rs
  type CreateUserGroup (line 18) | pub struct CreateUserGroup {
  type RenameUserGroup (line 33) | pub struct RenameUserGroup {
  type DeleteUserGroup (line 50) | pub struct DeleteUserGroup {
  type AddUserToUserGroup (line 65) | pub struct AddUserToUserGroup {
  type RemoveUserFromUserGroup (line 82) | pub struct RemoveUserFromUserGroup {
  type SetUsersInUserGroup (line 100) | pub struct SetUsersInUserGroup {
  type SetEveryoneUserGroup (line 118) | pub struct SetEveryoneUserGroup {

FILE: client/core/rs/src/api/write/variable.rs
  type CreateVariable (line 18) | pub struct CreateVariable {
  type CreateVariableResponse (line 33) | pub type CreateVariableResponse = Variable;
  type UpdateVariableValue (line 45) | pub struct UpdateVariableValue {
  type UpdateVariableValueResponse (line 53) | pub type UpdateVariableValueResponse = Variable;
  type UpdateVariableDescription (line 65) | pub struct UpdateVariableDescription {
  type UpdateVariableDescriptionResponse (line 73) | pub type UpdateVariableDescriptionResponse = Variable;
  type UpdateVariableIsSecret (line 85) | pub struct UpdateVariableIsSecret {
  type UpdateVariableIsSecretResponse (line 93) | pub type UpdateVariableIsSecretResponse = Variable;
  type DeleteVariable (line 105) | pub struct DeleteVariable {
  type DeleteVariableResponse (line 110) | pub type DeleteVariableResponse = Variable;

FILE: client/core/rs/src/busy.rs
  type Busy (line 8) | pub trait Busy {
    method busy (line 9) | fn busy(&self) -> bool;
    method busy (line 13) | fn busy(&self) -> bool {
    method busy (line 27) | fn busy(&self) -> bool {
    method busy (line 40) | fn busy(&self) -> bool {
    method busy (line 52) | fn busy(&self) -> bool {
    method busy (line 58) | fn busy(&self) -> bool {
    method busy (line 64) | fn busy(&self) -> bool {
    method busy (line 70) | fn busy(&self) -> bool {
    method busy (line 76) | fn busy(&self) -> bool {

FILE: client/core/rs/src/deserializers/conversion.rs
  function conversions_deserializer (line 8) | pub fn conversions_deserializer<'de, D>(
  function option_conversions_deserializer (line 17) | pub fn option_conversions_deserializer<'de, D>(
  type ConversionVisitor (line 26) | struct ConversionVisitor;
    type Value (line 29) | type Value = String;
    method expecting (line 31) | fn expecting(
    method visit_string (line 38) | fn visit_string<E>(self, out: String) -> Result<Self::Value, E>
    method visit_str (line 49) | fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    method visit_seq (line 56) | fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
  type OptionConversionVisitor (line 75) | struct OptionConversionVisitor;
    type Value (line 78) | type Value = Option<String>;
    method expecting (line 80) | fn expecting(
    method visit_string (line 87) | fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
    method visit_str (line 94) | fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    method visit_seq (line 101) | fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
    method visit_none (line 108) | fn visit_none<E>(self) -> Result<Self::Value, E>
    method visit_unit (line 115) | fn visit_unit<E>(self) -> Result<Self::Value, E>

FILE: client/core/rs/src/deserializers/environment.rs
  function env_vars_deserializer (line 8) | pub fn env_vars_deserializer<'de, D>(
  function option_env_vars_deserializer (line 17) | pub fn option_env_vars_deserializer<'de, D>(
  type EnvironmentVarVisitor (line 26) | struct EnvironmentVarVisitor;
    type Value (line 29) | type Value = String;
    method expecting (line 31) | fn expecting(
    method visit_str (line 38) | fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    method visit_seq (line 50) | fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
  type OptionEnvVarVisitor (line 69) | struct OptionEnvVarVisitor;
    type Value (line 72) | type Value = Option<String>;
    method expecting (line 74) | fn expecting(
    method visit_str (line 81) | fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    method visit_seq (line 88) | fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
    method visit_none (line 95) | fn visit_none<E>(self) -> Result<Self::Value, E>
    method visit_unit (line 102) | fn visit_unit<E>(self) -> Result<Self::Value, E>

FILE: client/core/rs/src/deserializers/file_contents.rs
  function file_contents_deserializer (line 4) | pub fn file_contents_deserializer<'de, D>(
  function option_file_contents_deserializer (line 14) | pub fn option_file_contents_deserializer<'de, D>(
  type FileContentsVisitor (line 23) | struct FileContentsVisitor;
    type Value (line 26) | type Value = String;
    method expecting (line 28) | fn expecting(
    method visit_str (line 35) | fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
  type OptionFileContentsVisitor (line 48) | struct OptionFileContentsVisitor;
    type Value (line 51) | type Value = Option<String>;
    method expecting (line 53) | fn expecting(
    method visit_str (line 60) | fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    method visit_none (line 67) | fn visit_none<E>(self) -> Result<Self::Value, E>
    method visit_unit (line 74) | fn visit_unit<E>(self) -> Result<Self::Value, E>

FILE: client/core/rs/src/deserializers/forgiving_vec.rs
  type ForgivingVec (line 7) | pub struct ForgivingVec<T>(pub Vec<T>);
  function iter (line 10) | pub fn iter(&self) -> std::slice::Iter<'_, T> {
  function is_empty (line 14) | pub fn is_empty(&self) -> bool {
  method default (line 20) | fn default() -> Self {
  type Item (line 26) | type Item = T;
  type IntoIter (line 27) | type IntoIter = <Vec<T> as IntoIterator>::IntoIter;
  method into_iter (line 28) | fn into_iter(self) -> Self::IntoIter {
  function from_iter (line 34) | fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
  function deserialize (line 40) | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
  type ForgivingVecVisitor (line 50) | struct ForgivingVecVisitor<T>(std::marker::PhantomData<T>);
  type Value (line 55) | type Value = ForgivingVec<T>;
  function expecting (line 57) | fn expecting(
  function visit_seq (line 64) | fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>

FILE: client/core/rs/src/deserializers/item_or_vec.rs
  function item_or_vec_deserializer (line 14) | pub fn item_or_vec_deserializer<'de, D, T>(
  function option_item_or_vec_deserializer (line 25) | pub fn option_item_or_vec_deserializer<'de, D, T>(
  type ItemOrVecVisitor (line 37) | struct ItemOrVecVisitor<T>(std::marker::PhantomData<T>);
  type Value (line 43) | type Value = Vec<T>;
  function expecting (line 45) | fn expecting(
  function visit_map (line 52) | fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
  function visit_seq (line 62) | fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
  type OptionItemOrVecVisitor (line 72) | struct OptionItemOrVecVisitor<T>(std::marker::PhantomData<T>);
  type Value (line 78) | type Value = Option<Vec<T>>;
  function expecting (line 80) | fn expecting(
  function visit_map (line 87) | fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
  function visit_seq (line 96) | fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>

FILE: client/core/rs/src/deserializers/labels.rs
  function labels_deserializer (line 8) | pub fn labels_deserializer<'de, D>(
  function option_labels_deserializer (line 17) | pub fn option_labels_deserializer<'de, D>(
  type LabelVisitor (line 26) | struct LabelVisitor;
    type Value (line 29) | type Value = String;
    method expecting (line 31) | fn expecting(
    method visit_str (line 38) | fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    method visit_seq (line 50) | fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
  type OptionLabelVisitor (line 69) | struct OptionLabelVisitor;
    type Value (line 72) | type Value = Option<String>;
    method expecting (line 74) | fn expecting(
    method visit_str (line 81) | fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    method visit_seq (line 88) | fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
    method visit_none (line 95) | fn visit_none<E>(self) -> Result<Self::Value, E>
    method visit_unit (line 102) | fn visit_unit<E>(self) -> Result<Self::Value, E>

FILE: client/core/rs/src/deserializers/maybe_string_i64.rs
  function maybe_string_i64_deserializer (line 3) | pub fn maybe_string_i64_deserializer<'de, D>(
  function option_maybe_string_i64_deserializer (line 12) | pub fn option_maybe_string_i64_deserializer<'de, D>(
  type MaybeStringI64Visitor (line 21) | struct MaybeStringI64Visitor;
    type Value (line 24) | type Value = i64;
    method expecting (line 26) | fn expecting(
    method visit_str (line 33) | fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    method visit_f32 (line 40) | fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E>
    method visit_f64 (line 47) | fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
    method visit_i8 (line 54) | fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E>
    method visit_i16 (line 61) | fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E>
    method visit_i32 (line 68) | fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
    method visit_i64 (line 75) | fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
    method visit_u8 (line 82) | fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
    method visit_u16 (line 89) | fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E>
    method visit_u32 (line 96) | fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
    method visit_u64 (line 103) | fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
  type OptionMaybeStringI64Visitor (line 111) | struct OptionMaybeStringI64Visitor;
    type Value (line 114) | type Value = Option<i64>;
    method expecting (line 116) | fn expecting(
    method visit_str (line 123) | fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    method visit_f32 (line 130) | fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E>
    method visit_f64 (line 137) | fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
    method visit_i8 (line 144) | fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E>
    method visit_i16 (line 151) | fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E>
    method visit_i32 (line 158) | fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
    method visit_i64 (line 165) | fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
    method visit_u8 (line 172) | fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
    method visit_u16 (line 179) | fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E>
    method visit_u32 (line 186) | fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
    method visit_u64 (line 193) | fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
    method visit_none (line 200) | fn visit_none<E>(self) -> Result<Self::Value, E>
    method visit_unit (line 207) | fn visit_unit<E>(self) -> Result<Self::Value, E>

FILE: client/core/rs/src/deserializers/permission.rs
  type _PermissionLevelAndSpecifics (line 22) | struct _PermissionLevelAndSpecifics {
  method serialize (line 30) | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
  method deserialize (line 48) | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
  type PermissionLevelAndSpecificsVisitor (line 56) | struct PermissionLevelAndSpecificsVisitor;
    type Value (line 59) | type Value = PermissionLevelAndSpecifics;
    method expecting (line 61) | fn expecting(
    method visit_str (line 71) | fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    method visit_map (line 82) | fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
    method visit_unit (line 95) | fn visit_unit<E>(self) -> Result<Self::Value, E>
    method visit_none (line 105) | fn visit_none<E>(self) -> Result<Self::Value, E>

FILE: client/core/rs/src/deserializers/string_list.rs
  function string_list_deserializer (line 8) | pub fn string_list_deserializer<'de, D>(
  function option_string_list_deserializer (line 17) | pub fn option_string_list_deserializer<'de, D>(
  type StringListVisitor (line 26) | struct StringListVisitor;
    type Value (line 29) | type Value = Vec<String>;
    method expecting (line 31) | fn expecting(
    method visit_str (line 38) | fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    method visit_seq (line 45) | fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
  type OptionStringListVisitor (line 53) | struct OptionStringListVisitor;
    type Value (line 56) | type Value = Option<Vec<String>>;
    method expecting (line 58) | fn expecting(
    method visit_str (line 65) | fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    method visit_seq (line 72) | fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
    method visit_none (line 79) | fn visit_none<E>(self) -> Result<Self::Value, E>
    method visit_unit (line 86) | fn visit_unit<E>(self) -> Result<Self::Value, E>

FILE: client/core/rs/src/deserializers/term_signal_labels.rs
  function term_labels_deserializer (line 8) | pub fn term_labels_deserializer<'de, D>(
  function option_term_labels_deserializer (line 17) | pub fn option_term_labels_deserializer<'de, D>(
  type TermSignalLabelVisitor (line 26) | struct TermSignalLabelVisitor;
    type Value (line 29) | type Value = String;
    method expecting (line 31) | fn expecting(
    method visit_str (line 38) | fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    method visit_seq (line 50) | fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
  type OptionTermSignalLabelVisitor (line 68) | struct OptionTermSignalLabelVisitor;
    type Value (line 71) | type Value = Option<String>;
    method expecting (line 73) | fn expecting(
    method visit_str (line 80) | fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    method visit_seq (line 87) | fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
    method visit_none (line 94) | fn visit_none<E>(self) -> Result<Self::Value, E>
    method visit_unit (line 101) | fn visit_unit<E>(self) -> Result<Self::Value, E>

FILE: client/core/rs/src/entities/action.rs
  type ActionListItem (line 22) | pub type ActionListItem = ResourceListItem<ActionListItemInfo>;
  type ActionListItemInfo (line 26) | pub struct ActionListItemInfo {
  type ActionState (line 53) | pub enum ActionState {
  type Action (line 66) | pub type Action = Resource<ActionConfig, NoData>;
  type _PartialActionConfig (line 69) | pub type _PartialActionConfig = PartialActionConfig;
  type ActionConfig (line 75) | pub struct ActionConfig {
    method builder (line 197) | pub fn builder() -> ActionConfigBuilder {
  function default_schedule_enabled (line 176) | fn default_schedule_enabled() -> bool {
  function default_schedule_alert (line 180) | fn default_schedule_alert() -> bool {
  function default_failure_alert (line 184) | fn default_failure_alert() -> bool {
  function default_run_at_startup (line 188) | fn default_run_at_startup() -> bool {
  function default_webhook_enabled (line 192) | fn default_webhook_enabled() -> bool {
  method default (line 203) | fn default() -> Self {
  type ActionActionState (line 224) | pub struct ActionActionState {
  type ActionQuery (line 230) | pub type ActionQuery = ResourceQuery<ActionQuerySpecifics>;
  type ActionQuerySpecifics (line 236) | pub struct ActionQuerySpecifics {}
    method add_filters (line 239) | fn add_filters(&self, _filters: &mut Document) {}

FILE: client/core/rs/src/entities/alert.rs
  type Alert (line 25) | pub struct Alert {
  type AlertData (line 73) | pub enum AlertData {
  method default (line 316) | fn default() -> Self {
  method default (line 323) | fn default() -> Self {
  type SeverityLevel (line 345) | pub enum SeverityLevel {

FILE: client/core/rs/src/entities/alerter.rs
  type Alerter (line 19) | pub type Alerter = Resource<AlerterConfig, ()>;
  type AlerterListItem (line 22) | pub type AlerterListItem = ResourceListItem<AlerterListItemInfo>;
  type AlerterListItemInfo (line 26) | pub struct AlerterListItemInfo {
  type _PartialAlerterConfig (line 34) | pub type _PartialAlerterConfig = PartialAlerterConfig;
  type AlerterConfig (line 40) | pub struct AlerterConfig {
    method builder (line 77) | pub fn builder() -> AlerterConfigBuilder {
  method default (line 84) | fn default() -> Self {
  type AlerterEndpoint (line 117) | pub enum AlerterEndpoint {
  method default (line 135) | fn default() -> Self {
  type CustomAlerterEndpoint (line 145) | pub struct CustomAlerterEndpoint {
  method default (line 153) | fn default() -> Self {
  function default_custom_url (line 160) | fn default_custom_url() -> String {
  type SlackAlerterEndpoint (line 169) | pub struct SlackAlerterEndpoint {
  method default (line 177) | fn default() -> Self {
  function default_slack_url (line 184) | fn default_slack_url() -> String {
  type DiscordAlerterEndpoint (line 195) | pub struct DiscordAlerterEndpoint {
  method default (line 203) | fn default() -> Self {
  function default_discord_url (line 210) | fn default_discord_url() -> String {
  type NtfyAlerterEndpoint (line 221) | pub struct NtfyAlerterEndpoint {
  method default (line 233) | fn default() -> Self {
  function default_ntfy_url (line 241) | fn default_ntfy_url() -> String {
  type PushoverAlerterEndpoint (line 250) | pub struct PushoverAlerterEndpoint {
  method default (line 258) | fn default() -> Self {
  function default_pushover_url (line 265) | fn default_pushover_url() -> String {
  type AlerterQuery (line 273) | pub type AlerterQuery = ResourceQuery<AlerterQuerySpecifics>;
  type AlerterQuerySpecifics (line 279) | pub struct AlerterQuerySpecifics {
    method add_filters (line 292) | fn add_filters(&self, filters: &mut Document) {

FILE: client/core/rs/src/entities/api_key.rs
  type ApiKey (line 13) | pub struct ApiKey {
    method sanitize (line 36) | pub fn sanitize(&mut self) {

FILE: client/core/rs/src/entities/build.rs
  type Build (line 27) | pub type Build = Resource<BuildConfig, BuildInfo>;
    method get_image_names (line 30) | pub fn get_image_names(&self) -> Vec<String> {
    method get_image_tags (line 79) | pub fn get_image_tags(
    method get_image_tags_as_arg (line 133) | pub fn get_image_tags_as_arg(
  type BuildListItem (line 151) | pub type BuildListItem = ResourceListItem<BuildListItemInfo>;
  type BuildListItemInfo (line 155) | pub struct BuildListItemInfo {
  type BuildState (line 204) | pub enum BuildState {
  type BuildInfo (line 218) | pub struct BuildInfo {
  type _PartialBuildConfig (line 246) | pub type _PartialBuildConfig = PartialBuildConfig;
  type BuildConfig (line 253) | pub struct BuildConfig {
    method builder (line 477) | pub fn builder() -> BuildConfigBuilder {
  function default_auto_increment_version (line 482) | fn default_auto_increment_version() -> bool {
  function default_include_tag (line 486) | fn default_include_tag() -> bool {
  function default_git_provider (line 490) | fn default_git_provider() -> String {
  function default_git_https (line 494) | fn default_git_https() -> bool {
  function default_branch (line 498) | fn default_branch() -> String {
  function default_build_path (line 502) | fn default_build_path() -> String {
  function default_dockerfile_path (line 506) | fn default_dockerfile_path() -> String {
  function default_webhook_enabled (line 510) | fn default_webhook_enabled() -> bool {
  method default (line 515) | fn default() -> Self {
  type ImageRegistryConfig (line 556) | pub struct ImageRegistryConfig {
    method static_default (line 573) | pub fn static_default() -> &'static ImageRegistryConfig {
  type BuildActionState (line 581) | pub struct BuildActionState {
  type BuildQuery (line 586) | pub type BuildQuery = ResourceQuery<BuildQuerySpecifics>;
  type BuildQuerySpecifics (line 592) | pub struct BuildQuerySpecifics {
    method add_filters (line 606) | fn add_filters(&self, filters: &mut Document) {

FILE: client/core/rs/src/entities/builder.rs
  type Builder (line 19) | pub type Builder = Resource<BuilderConfig, ()>;
  type BuilderListItem (line 22) | pub type BuilderListItem = ResourceListItem<BuilderListItemInfo>;
  type _PartialBuilderConfig (line 25) | pub type _PartialBuilderConfig = PartialBuilderConfig;
  type BuilderListItemInfo (line 29) | pub struct BuilderListItemInfo {
  type BuilderConfig (line 51) | pub enum BuilderConfig {
    method partial_diff (line 149) | fn partial_diff(
    method from (line 208) | fn from(value: PartialBuilderConfig) -> BuilderConfig {
  method default (line 63) | fn default() -> Self {
  type PartialBuilderConfig (line 82) | pub enum PartialBuilderConfig {
    method from (line 113) | fn from(value: BuilderConfigDiff) -> Self {
    method from (line 224) | fn from(value: BuilderConfig) -> Self {
  method default (line 89) | fn default() -> Self {
  method is_none (line 95) | fn is_none(&self) -> bool {
  type BuilderConfigDiff (line 106) | pub enum BuilderConfigDiff {
  method iter_field_diffs (line 129) | fn iter_field_diffs(
  method is_none (line 198) | fn is_none(&self) -> bool {
  type Partial (line 240) | type Partial = PartialBuilderConfig;
  method merge_partial (line 241) | fn merge_partial(
  type _PartialUrlBuilderConfig (line 307) | pub type _PartialUrlBuilderConfig = PartialUrlBuilderConfig;
  type UrlBuilderConfig (line 314) | pub struct UrlBuilderConfig {
    method builder (line 337) | pub fn builder() -> UrlBuilderConfigBuilder {
  function default_address (line 323) | fn default_address() -> String {
  method default (line 328) | fn default() -> Self {
  type _PartialServerBuilderConfig (line 343) | pub type _PartialServerBuilderConfig = PartialServerBuilderConfig;
  type ServerBuilderConfig (line 352) | pub struct ServerBuilderConfig {
    method builder (line 360) | pub fn builder() -> ServerBuilderConfigBuilder {
  type _PartialAwsBuilderConfig (line 366) | pub type _PartialAwsBuilderConfig = PartialAwsBuilderConfig;
  type AwsBuilderConfig (line 373) | pub struct AwsBuilderConfig {
    method builder (line 483) | pub fn builder() -> AwsBuilderConfigBuilder {
  method default (line 461) | fn default() -> Self {
  function aws_default_region (line 488) | fn aws_default_region() -> String {
  function aws_default_instance_type (line 492) | fn aws_default_instance_type() -> String {
  function aws_default_volume_gb (line 496) | fn aws_default_volume_gb() -> i32 {
  function default_port (line 500) | fn default_port() -> i32 {
  function default_use_https (line 504) | fn default_use_https() -> bool {
  type BuilderQuery (line 509) | pub type BuilderQuery = ResourceQuery<BuilderQuerySpecifics>;
  type BuilderQuerySpecifics (line 513) | pub struct BuilderQuerySpecifics {}

FILE: client/core/rs/src/entities/config/cli/args/container.rs
  type Container (line 2) | pub struct Container {
  type ContainerCommand (line 43) | pub enum ContainerCommand {
  type InspectContainer (line 50) | pub struct InspectContainer {

FILE: client/core/rs/src/entities/config/cli/args/database.rs
  type DatabaseCommand (line 4) | pub enum DatabaseCommand {

FILE: client/core/rs/src/entities/config/cli/args/list.rs
  type List (line 4) | pub struct List {
  type ListCommand (line 76) | pub enum ListCommand {
  type ResourceFilters (line 113) | pub struct ResourceFilters {
    method from (line 58) | fn from(value: List) -> Self {

FILE: client/core/rs/src/entities/config/cli/args/mod.rs
  type CliArgs (line 14) | pub struct CliArgs {
  type Command (line 40) | pub enum Command {
  type Execute (line 92) | pub struct Execute {
  type CliFormat (line 115) | pub enum CliFormat {
  type CliEnabled (line 129) | pub enum CliEnabled {
  function from (line 138) | fn from(value: CliEnabled) -> Self {

FILE: client/core/rs/src/entities/config/cli/args/update.rs
  type UpdateCommand (line 2) | pub enum UpdateCommand {
  type UpdateResource (line 44) | pub struct UpdateResource {
  type UpdateUserCommand (line 63) | pub enum UpdateUserCommand {

FILE: client/core/rs/src/entities/config/cli/mod.rs
  type Env (line 19) | pub struct Env {
  function default_config_paths (line 137) | fn default_config_paths() -> Vec<PathBuf> {
  function default_config_keywords (line 148) | fn default_config_keywords() -> Vec<String> {
  type CliConfig (line 153) | pub struct CliConfig {
    method sanitized (line 292) | pub fn sanitized(&self) -> CliConfig {
  function default_backups_folder (line 240) | fn default_backups_folder() -> PathBuf {
  function default_max_backups (line 245) | fn default_max_backups() -> u16 {
  function default_database_config (line 249) | fn default_database_config() -> DatabaseConfig {
  function database_config_is_default (line 256) | fn database_config_is_default(db_config: &DatabaseConfig) -> bool {
  function default_log_config (line 260) | fn default_log_config() -> LogConfig {
  function log_config_is_default (line 267) | fn log_config_is_default(log_config: &LogConfig) -> bool {
  method default (line 272) | fn default() -> Self {
  type CliTableBorders (line 322) | pub enum CliTableBorders {

FILE: client/core/rs/src/entities/config/core.rs
  type Env (line 36) | pub struct Env {
  function default_core_config_paths (line 273) | fn default_core_config_paths() -> Vec<PathBuf> {
  type CoreConfig (line 291) | pub struct CoreConfig {
    method sanitized (line 760) | pub fn sanitized(&self) -> CoreConfig {
  function default_title (line 626) | fn default_title() -> String {
  function default_host (line 630) | fn default_host() -> String {
  function default_core_port (line 634) | fn default_core_port() -> u16 {
  function default_core_bind_ip (line 638) | fn default_core_bind_ip() -> String {
  function default_passkey (line 642) | fn default_passkey() -> String {
  function default_frontend_path (line 646) | fn default_frontend_path() -> String {
  function default_first_server_name (line 650) | fn default_first_server_name() -> String {
  function default_jwt_ttl (line 654) | fn default_jwt_ttl() -> Timelength {
  function default_init_admin_password (line 658) | fn default_init_admin_password() -> String {
  function default_sync_directory (line 662) | fn default_sync_directory() -> PathBuf {
  function default_repo_directory (line 667) | fn default_repo_directory() -> PathBuf {
  function default_action_directory (line 672) | fn default_action_directory() -> PathBuf {
  function default_prune_days (line 677) | fn default_prune_days() -> u64 {
  function default_poll_interval (line 681) | fn default_poll_interval() -> Timelength {
  function default_monitoring_interval (line 685) | fn default_monitoring_interval() -> Timelength {
  function default_ssl_key_file (line 689) | fn default_ssl_key_file() -> PathBuf {
  function default_ssl_cert_file (line 693) | fn default_ssl_cert_file() -> PathBuf {
  method default (line 698) | fn default() -> Self {
  type OauthCredentials (line 871) | pub struct OauthCredentials {
  type AwsCredentials (line 885) | pub struct AwsCredentials {
  type GithubWebhookAppConfig (line 894) | pub struct GithubWebhookAppConfig {
  function default_private_key_path (line 904) | fn default_private_key_path() -> String {
  method default (line 909) | fn default() -> Self {
  type GithubWebhookAppInstallationConfig (line 920) | pub struct GithubWebhookAppInstallationConfig {

FILE: client/core/rs/src/entities/config/mod.rs
  function default_config_keywords (line 10) | fn default_config_keywords() -> Vec<String> {
  function default_merge_nested_config (line 14) | fn default_merge_nested_config() -> bool {
  function default_extend_config_arrays (line 18) | fn default_extend_config_arrays() -> bool {
  type DatabaseConfig (line 30) | pub struct DatabaseConfig {
    method sanitized (line 87) | pub fn sanitized(&self) -> DatabaseConfig {
    method is_default (line 98) | pub fn is_default(&self) -> bool {
  function default_database_address (line 55) | fn default_database_address() -> String {
  function default_database_app_name (line 59) | fn default_database_app_name() -> String {
  function default_database_db_name (line 63) | fn default_database_db_name() -> String {
  method default (line 68) | fn default() -> Self {
  function default_database_config (line 80) | fn default_database_config() -> &'static DatabaseConfig {
  type GitProvider (line 115) | pub struct GitProvider {
  function default_git_provider (line 127) | fn default_git_provider() -> String {
  function default_git_https (line 131) | fn default_git_https() -> bool {
  type DockerRegistry (line 147) | pub struct DockerRegistry {
  function default_docker_provider (line 160) | fn default_docker_provider() -> String {
  type ProviderAccount (line 176) | pub struct ProviderAccount {
  function empty_or_redacted (line 185) | pub fn empty_or_redacted(src: &str) -> String {

FILE: client/core/rs/src/entities/config/periphery.rs
  type CliArgs (line 51) | pub struct CliArgs {
  type Env (line 88) | pub struct Env {
  type PeripheryConfig (line 185) | pub struct PeripheryConfig {
    method sanitized (line 370) | pub fn sanitized(&self) -> PeripheryConfig {
    method repo_dir (line 438) | pub fn repo_dir(&self) -> PathBuf {
    method stack_dir (line 446) | pub fn stack_dir(&self) -> PathBuf {
    method build_dir (line 454) | pub fn build_dir(&self) -> PathBuf {
    method ssl_key_file (line 462) | pub fn ssl_key_file(&self) -> PathBuf {
    method ssl_cert_file (line 470) | pub fn ssl_cert_file(&self) -> PathBuf {
  function default_periphery_port (line 314) | fn default_periphery_port() -> u16 {
  function default_periphery_bind_ip (line 318) | fn default_periphery_bind_ip() -> String {
  function default_root_directory (line 322) | fn default_root_directory() -> PathBuf {
  function default_stats_polling_rate (line 326) | fn default_stats_polling_rate() -> Timelength {
  function default_container_stats_polling_rate (line 330) | fn default_container_stats_polling_rate() -> Timelength {
  function default_ssl_enabled (line 334) | fn default_ssl_enabled() -> bool {
  method default (line 339) | fn default() -> Self {

FILE: client/core/rs/src/entities/deployment.rs
  type Deployment (line 30) | pub type Deployment = Resource<DeploymentConfig, ()>;
  type DeploymentListItem (line 33) | pub type DeploymentListItem =
  type DeploymentListItemInfo (line 38) | pub struct DeploymentListItemInfo {
  type _PartialDeploymentConfig (line 54) | pub type _PartialDeploymentConfig = PartialDeploymentConfig;
  type DeploymentConfig (line 60) | pub struct DeploymentConfig {
    method builder (line 209) | pub fn builder() -> DeploymentConfigBuilder {
    method env_vars (line 213) | pub fn env_vars(&self) -> anyhow::Result<Vec<EnvironmentVar>> {
  function default_send_alerts (line 219) | fn default_send_alerts() -> bool {
  function default_termination_timeout (line 223) | fn default_termination_timeout() -> i32 {
  function default_network (line 227) | fn default_network() -> String {
  method default (line 232) | fn default() -> Self {
  type DeploymentImage (line 274) | pub enum DeploymentImage {
  method default (line 295) | fn default() -> Self {
  type Conversion (line 306) | pub struct Conversion {
  function conversions_from_str (line 313) | pub fn conversions_from_str(
  type DeploymentState (line 348) | pub enum DeploymentState {
    method from (line 373) | fn from(value: ContainerStateStatusEnum) -> Self {
  type RestartMode (line 403) | pub enum RestartMode {
  type TerminationSignalLabel (line 430) | pub struct TerminationSignalLabel {
  function term_signal_labels_from_str (line 437) | pub fn term_signal_labels_from_str(
  type DeploymentActionState (line 455) | pub struct DeploymentActionState {
  type DeploymentQuery (line 468) | pub type DeploymentQuery = ResourceQuery<DeploymentQuerySpecifics>;
  type DeploymentQuerySpecifics (line 474) | pub struct DeploymentQuerySpecifics {
    method add_filters (line 493) | fn add_filters(&self, filters: &mut Document) {
  function extract_registry_domain (line 508) | pub fn extract_registry_domain(

FILE: client/core/rs/src/entities/docker/container.rs
  type ContainerListItem (line 17) | pub struct ContainerListItem {
  type NameAndId (line 72) | pub struct NameAndId {
  type Port (line 82) | pub struct Port {
  type PortTypeEnum (line 112) | pub enum PortTypeEnum {
  type Container (line 128) | pub struct Container {
  type ContainerState (line 218) | pub struct ContainerState {
  type ContainerStateStatusEnum (line 281) | pub enum ContainerStateStatusEnum {
    type Err (line 296) | type Err = anyhow::Error;
    method from_str (line 297) | fn from_str(s: &str) -> Result<Self, Self::Err> {
  type ContainerHealth (line 317) | pub struct ContainerHealth {
  type HealthStatusEnum (line 344) | pub enum HealthStatusEnum {
  type HealthcheckResult (line 363) | pub struct HealthcheckResult {
  type HostConfig (line 386) | pub struct HostConfig {
  type ResourcesBlkioWeightDevice (line 669) | pub struct ResourcesBlkioWeightDevice {
  type ThrottleDevice (line 681) | pub struct ThrottleDevice {
  type DeviceMapping (line 696) | pub struct DeviceMapping {
  type DeviceRequest (line 712) | pub struct DeviceRequest {
  type ResourcesUlimits (line 735) | pub struct ResourcesUlimits {
  type HostConfigIsolationEnum (line 762) | pub enum HostConfigIsolationEnum {
  type HostConfigLogConfig (line 779) | pub struct HostConfigLogConfig {
  type RestartPolicy (line 792) | pub struct RestartPolicy {
  type RestartPolicyNameEnum (line 815) | pub enum RestartPolicyNameEnum {
  type ContainerMount (line 833) | pub struct ContainerMount {
  type MountTypeEnum (line 877) | pub enum MountTypeEnum {
  type MountBindOptions (line 900) | pub struct MountBindOptions {
  type MountBindOptionsPropagationEnum (line 935) | pub enum MountBindOptionsPropagationEnum {
  type MountVolumeOptions (line 958) | pub struct MountVolumeOptions {
  type MountVolumeOptionsDriverConfig (line 980) | pub struct MountVolumeOptionsDriverConfig {
  type MountTmpfsOptions (line 995) | pub struct MountTmpfsOptions {
  type HostConfigCgroupnsModeEnum (line 1018) | pub enum HostConfigCgroupnsModeEnum {
  type MountPoint (line 1033) | pub struct MountPoint {
  type NetworkSettings (line 1072) | pub struct NetworkSettings {
  type EndpointSettings (line 1098) | pub struct EndpointSettings {
  type EndpointIpamConfig (line 1158) | pub struct EndpointIpamConfig {
  type ContainerStats (line 1171) | pub struct ContainerStats {

FILE: client/core/rs/src/entities/docker/image.rs
  type ImageListItem (line 12) | pub struct ImageListItem {
  type Image (line 32) | pub struct Image {
  type ImageInspectRootFs (line 105) | pub struct ImageInspectRootFs {
  type ImageInspectMetadata (line 118) | pub struct ImageInspectMetadata {
  type ImageHistoryResponseItem (line 129) | pub struct ImageHistoryResponseItem {

FILE: client/core/rs/src/entities/docker/mod.rs
  type PortBinding (line 19) | pub struct PortBinding {
  type GraphDriverData (line 34) | pub struct GraphDriverData {
  type ContainerConfig (line 48) | pub struct ContainerConfig {
  type HealthConfig (line 154) | pub struct HealthConfig {

FILE: client/core/rs/src/entities/docker/network.rs
  type NetworkListItem (line 8) | pub struct NetworkListItem {
  type Network (line 29) | pub struct Network {
  type Ipam (line 73) | pub struct Ipam {
  type IpamConfig (line 87) | pub struct IpamConfig {
  type NetworkContainer (line 100) | pub struct NetworkContainer {

FILE: client/core/rs/src/entities/docker/stats.rs
  type FullContainerStats (line 13) | pub struct FullContainerStats {
  type ContainerPidsStats (line 72) | pub struct ContainerPidsStats {
  type ContainerBlkioStats (line 88) | pub struct ContainerBlkioStats {
  type ContainerBlkioStatEntry (line 142) | pub struct ContainerBlkioStatEntry {
  type ContainerStorageStats (line 155) | pub struct ContainerStorageStats {
  type ContainerCpuStats (line 167) | pub struct ContainerCpuStats {
  type ContainerCpuUsage (line 189) | pub struct ContainerCpuUsage {
  type ContainerThrottlingData (line 215) | pub struct ContainerThrottlingData {
  type ContainerMemoryStats (line 232) | pub struct ContainerMemoryStats {
  type ContainerNetworkStats (line 270) | pub struct ContainerNetworkStats {

FILE: client/core/rs/src/entities/docker/volume.rs
  type VolumeListItem (line 14) | pub struct VolumeListItem {
  type Volume (line 31) | pub struct Volume {
  type VolumeScopeEnum (line 84) | pub enum VolumeScopeEnum {
  type ClusterVolume (line 99) | pub struct ClusterVolume {
  type ClusterVolumeInfo (line 129) | pub struct ClusterVolumeInfo {
  type ClusterVolumePublishStatus (line 151) | pub struct ClusterVolumePublishStatus {
  type ClusterVolumePublishStatusStateEnum (line 178) | pub enum ClusterVolumePublishStatusStateEnum {
  type ObjectVersion (line 197) | pub struct ObjectVersion {
  type ClusterVolumeSpec (line 207) | pub struct ClusterVolumeSpec {
  type ClusterVolumeSpecAccessMode (line 221) | pub struct ClusterVolumeSpecAccessMode {
  type ClusterVolumeSpecAccessModeScopeEnum (line 260) | pub enum ClusterVolumeSpecAccessModeScopeEnum {
  type ClusterVolumeSpecAccessModeSharingEnum (line 283) | pub enum ClusterVolumeSpecAccessModeSharingEnum {
  type ClusterVolumeSpecAccessModeSecrets (line 302) | pub struct ClusterVolumeSpecAccessModeSecrets {
  type ClusterVolumeSpecAccessModeAccessibilityRequirements (line 317) | pub struct ClusterVolumeSpecAccessModeAccessibilityRequirements {
  type Topology (line 328) | pub type Topology = HashMap<String, Vec<PortBinding>>;
  type ClusterVolumeSpecAccessModeCapacityRange (line 335) | pub struct ClusterVolumeSpecAccessModeCapacityRange {
  type ClusterVolumeSpecAccessModeAvailabilityEnum (line 358) | pub enum ClusterVolumeSpecAccessModeAvailabilityEnum {
  type VolumeUsageData (line 375) | pub struct VolumeUsageData {

FILE: client/core/rs/src/entities/logger.rs
  type LogConfig (line 6) | pub struct LogConfig {
    method is_default (line 60) | pub fn is_default(&self) -> bool {
  function default_opentelemetry_service_name (line 32) | fn default_opentelemetry_service_name() -> String {
  function default_location (line 36) | fn default_location() -> bool {
  method default (line 41) | fn default() -> Self {
  function default_log_config (line 54) | fn default_log_config() -> &'static LogConfig {
  type LogLevel (line 77) | pub enum LogLevel {
    method from (line 99) | fn from(value: tracing::Level) -> Self {
  function from (line 87) | fn from(value: LogLevel) -> Self {
  type StdioLogMode (line 123) | pub enum StdioLogMode {

FILE: client/core/rs/src/entities/mod.rs
  type I64 (line 78) | pub type I64 = i64;
  type U64 (line 80) | pub type U64 = u64;
  type Usize (line 82) | pub type Usize = usize;
  type MongoDocument (line 84) | pub type MongoDocument = bson::Document;
  type JsonValue (line 86) | pub type JsonValue = serde_json::Value;
  type JsonObject (line 88) | pub type JsonObject = serde_json::Map<String, serde_json::Value>;
  type MongoId (line 90) | pub type MongoId = String;
  type _Serror (line 92) | pub type _Serror = Serror;
  type NoData (line 106) | pub struct NoData {}
  type MergePartial (line 108) | pub trait MergePartial: Sized {
    method merge_partial (line 110) | fn merge_partial(self, partial: Self::Partial) -> Self;
  function all_logs_success (line 113) | pub fn all_logs_success(logs: &[update::Log]) -> bool {
  function optional_string (line 122) | pub fn optional_string(string: impl Into<String>) -> Option<String> {
  function to_general_name (line 131) | pub fn to_general_name(name: &str) -> String {
  function to_path_compatible_name (line 135) | pub fn to_path_compatible_name(name: &str) -> String {
  function to_container_compatible_name (line 141) | pub fn to_container_compatible_name(name: &str) -> String {
  function to_docker_compatible_name (line 151) | pub fn to_docker_compatible_name(name: &str) -> String {
  function komodo_timestamp (line 160) | pub fn komodo_timestamp() -> i64 {
  type MongoIdObj (line 166) | pub struct MongoIdObj {
  type __Serror (line 173) | pub struct __Serror {
  type SystemCommand (line 182) | pub struct SystemCommand {
    method command (line 190) | pub fn command(&self) -> Option<String> {
    method into_option (line 198) | pub fn into_option(self) -> Option<SystemCommand> {
    method is_none (line 202) | pub fn is_none(&self) -> bool {
  type Version (line 209) | pub struct Version {
    method deserialize (line 216) | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    method fmt (line 281) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    type Error (line 290) | type Error = anyhow::Error;
    method try_from (line 292) | fn try_from(value: &str) -> Result<Self, Self::Error> {
    method increment (line 320) | pub fn increment(&mut self) {
    method is_none (line 324) | pub fn is_none(&self) -> bool {
  type EnvironmentVar (line 333) | pub struct EnvironmentVar {
  function environment_vars_from_str (line 338) | pub fn environment_vars_from_str(
  type LatestCommit (line 351) | pub struct LatestCommit {
  type FileContents (line 358) | pub struct FileContents {
  type MaintenanceWindow (line 368) | pub struct MaintenanceWindow {
  function default_enabled (line 403) | fn default_enabled() -> bool {
  type DefaultRepoFolder (line 411) | pub enum DefaultRepoFolder {
  type RepoExecutionArgs (line 426) | pub struct RepoExecutionArgs {
    method path (line 450) | pub fn path(&self, root_repo_dir: &Path) -> PathBuf {
    method remote_url (line 461) | pub fn remote_url(
    method unique_path (line 489) | pub fn unique_path(
    method from (line 509) | fn from(stack: &self::stack::Stack) -> Self {
    method from (line 527) | fn from(build: &self::build::Build) -> RepoExecutionArgs {
    method from (line 545) | fn from(repo: &self::repo::Repo) -> RepoExecutionArgs {
    method from (line 563) | fn from(sync: &self::sync::ResourceSync) -> Self {
  type RepoExecutionResponse (line 582) | pub struct RepoExecutionResponse {
  type Timelength (line 609) | pub enum Timelength {
    type Error (line 698) | type Error = anyhow::Error;
    method try_into (line 699) | fn try_into(
  type DayOfWeek (line 720)
Condensed preview — 673 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (4,794K chars).
[
  {
    "path": ".cargo/config.toml",
    "chars": 51,
    "preview": "[build]\nrustflags = [\"-Wunused-crate-dependencies\"]"
  },
  {
    "path": ".devcontainer/dev.compose.yaml",
    "chars": 730,
    "preview": "services:\n  dev:\n    image: mcr.microsoft.com/devcontainers/rust:1-1-bullseye\n    volumes:\n      # Mount the root folder"
  },
  {
    "path": ".devcontainer/devcontainer.json",
    "chars": 1365,
    "preview": "// For format details, see https://aka.ms/devcontainer.json. For config options, see the\n// README at: https://github.co"
  },
  {
    "path": ".devcontainer/postCreate.sh",
    "chars": 38,
    "preview": "#!/bin/sh\n\ncargo install typeshare-cli"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 189,
    "preview": "# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/di"
  },
  {
    "path": ".gitignore",
    "chars": 117,
    "preview": "target\nnode_modules\ndist\ndeno.lock\n.env\n.env.development\n.DS_Store\n.idea\n\n/frontend/build\n/lib/ts_client/build\n\n.dev\n"
  },
  {
    "path": ".kminclude",
    "chars": 4,
    "preview": ".dev"
  },
  {
    "path": ".vscode/extensions.json",
    "chars": 167,
    "preview": "{\n    \"recommendations\": [\n        \"rust-lang.rust-analyzer\",\n        \"tamasfe.even-better-toml\",\n        \"vadimcn.vscod"
  },
  {
    "path": ".vscode/resolver.code-snippets",
    "chars": 471,
    "preview": "{\n\t\"resolve\": {\n\t\t\"scope\": \"rust\",\n\t\t\"prefix\": \"resolve\",\n\t\t\"body\": [\n\t\t\t\"impl Resolve<${1}, User> for State {\",\n\t\t\t\"\\ta"
  },
  {
    "path": ".vscode/tasks.json",
    "chars": 4859,
    "preview": "{\n    \"version\": \"2.0.0\",\n    \"tasks\": [\n        {\n            \"label\": \"Run Core\",\n            \"command\": \"cargo\",\n    "
  },
  {
    "path": "Cargo.toml",
    "chars": 3863,
    "preview": "[workspace]\nresolver = \"2\"\nmembers = [\n\t\"bin/*\",\n\t\"lib/*\",\n\t\"client/core/rs\",\n\t\"client/periphery/rs\",\n]\n\n[workspace.pack"
  },
  {
    "path": "LICENSE",
    "chars": 35149,
    "preview": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
  },
  {
    "path": "bin/binaries.Dockerfile",
    "chars": 973,
    "preview": "## Builds the Komodo Core, Periphery, and Util binaries\n## for a specific architecture.\n\nFROM rust:1.89.0-bullseye AS bu"
  },
  {
    "path": "bin/chef.binaries.Dockerfile",
    "chars": 1201,
    "preview": "## Builds the Komodo Core, Periphery, and Util binaries\n## for a specific architecture.\n\n## Uses chef for dependency cac"
  },
  {
    "path": "bin/cli/Cargo.toml",
    "chars": 796,
    "preview": "[package]\nname = \"komodo_cli\"\ndescription = \"Command line tool for Komodo\"\nversion.workspace = true\nedition.workspace = "
  },
  {
    "path": "bin/cli/README.md",
    "chars": 5654,
    "preview": "# Komodo CLI\n\nKomodo CLI is a tool to execute actions on your Komodo instance from shell scripts.\n\n## Install\n\n```sh\ncar"
  },
  {
    "path": "bin/cli/aio.Dockerfile",
    "chars": 667,
    "preview": "FROM rust:1.89.0-bullseye AS builder\nRUN cargo install cargo-strip\n\nWORKDIR /builder\nCOPY Cargo.toml Cargo.lock ./\nCOPY "
  },
  {
    "path": "bin/cli/docs/copy-database.md",
    "chars": 5071,
    "preview": "# Copy Database Utility\n\nCopy the Komodo database contents between running, mongo-compatible databases.\nCan be used to m"
  },
  {
    "path": "bin/cli/multi-arch.Dockerfile",
    "chars": 992,
    "preview": "## Assumes the latest binaries for x86_64 and aarch64 are already built (by binaries.Dockerfile).\n## Since theres no hea"
  },
  {
    "path": "bin/cli/runfile.toml",
    "chars": 136,
    "preview": "[install-cli]\nalias = \"ic\"\ndescription = \"installs the komodo-cli, available on the command line as 'km'\"\ncmd = \"cargo i"
  },
  {
    "path": "bin/cli/single-arch.Dockerfile",
    "chars": 539,
    "preview": "## Assumes the latest binaries for the required arch are already built (by binaries.Dockerfile).\n\nARG BINARIES_IMAGE=ghc"
  },
  {
    "path": "bin/cli/src/command/container.rs",
    "chars": 8049,
    "preview": "use std::collections::{HashMap, HashSet};\n\nuse anyhow::Context;\nuse colored::Colorize;\nuse comfy_table::{Attribute, Cell"
  },
  {
    "path": "bin/cli/src/command/database.rs",
    "chars": 7844,
    "preview": "use std::path::Path;\n\nuse anyhow::Context;\nuse colored::Colorize;\nuse komodo_client::entities::{\n  config::cli::args::da"
  },
  {
    "path": "bin/cli/src/command/execute.rs",
    "chars": 18053,
    "preview": "use std::time::Duration;\n\nuse colored::Colorize;\nuse futures_util::{StreamExt, stream::FuturesUnordered};\nuse komodo_cli"
  },
  {
    "path": "bin/cli/src/command/list.rs",
    "chars": 33187,
    "preview": "use std::{cmp::Ordering, collections::HashMap};\n\nuse comfy_table::{Attribute, Cell, Color};\nuse futures_util::{FutureExt"
  },
  {
    "path": "bin/cli/src/command/mod.rs",
    "chars": 4258,
    "preview": "use std::io::Read;\n\nuse anyhow::{Context, anyhow};\nuse chrono::TimeZone;\nuse colored::Colorize;\nuse comfy_table::{Attrib"
  },
  {
    "path": "bin/cli/src/command/update/mod.rs",
    "chars": 1273,
    "preview": "use komodo_client::entities::{\n  build::PartialBuildConfig,\n  config::cli::args::update::UpdateCommand,\n  deployment::Pa"
  },
  {
    "path": "bin/cli/src/command/update/resource.rs",
    "chars": 3798,
    "preview": "use anyhow::Context;\nuse colored::Colorize;\nuse komodo_client::{\n  api::write::{\n    UpdateBuild, UpdateDeployment, Upda"
  },
  {
    "path": "bin/cli/src/command/update/user.rs",
    "chars": 3092,
    "preview": "use anyhow::Context;\nuse colored::Colorize;\nuse database::mungos::mongodb::bson::doc;\nuse komodo_client::entities::{\n  c"
  },
  {
    "path": "bin/cli/src/command/update/variable.rs",
    "chars": 1670,
    "preview": "use anyhow::Context;\nuse colored::Colorize;\nuse komodo_client::api::{\n  read::GetVariable,\n  write::{\n    CreateVariable"
  },
  {
    "path": "bin/cli/src/config.rs",
    "chars": 8286,
    "preview": "use std::{path::PathBuf, sync::OnceLock};\n\nuse anyhow::Context;\nuse clap::Parser;\nuse colored::Colorize;\nuse environment"
  },
  {
    "path": "bin/cli/src/main.rs",
    "chars": 1859,
    "preview": "#[macro_use]\nextern crate tracing;\n\nuse anyhow::Context;\nuse komodo_client::entities::config::cli::args;\n\nuse crate::con"
  },
  {
    "path": "bin/core/Cargo.toml",
    "chars": 2123,
    "preview": "[package]\nname = \"komodo_core\"\nversion.workspace = true\nedition.workspace = true\nauthors.workspace = true\nlicense.worksp"
  },
  {
    "path": "bin/core/aio.Dockerfile",
    "chars": 1884,
    "preview": "## All in one, multi stage compile + runtime Docker build for your architecture.\n\n# Build Core\nFROM rust:1.89.0-bullseye"
  },
  {
    "path": "bin/core/debian-deps.sh",
    "chars": 351,
    "preview": "#!/bin/bash\n\n## Core deps installer\n\napt-get update\napt-get install -y git curl ca-certificates iproute2\n\nrm -rf /var/li"
  },
  {
    "path": "bin/core/multi-arch.Dockerfile",
    "chars": 2064,
    "preview": "## Assumes the latest binaries for x86_64 and aarch64 are already built (by binaries.Dockerfile).\n## Sets up the necessa"
  },
  {
    "path": "bin/core/single-arch.Dockerfile",
    "chars": 1594,
    "preview": "## Assumes the latest binaries for the required arch are already built (by binaries.Dockerfile).\n## Sets up the necessar"
  },
  {
    "path": "bin/core/src/alert/discord.rs",
    "chars": 8678,
    "preview": "use std::sync::OnceLock;\n\nuse serde::Serialize;\n\nuse super::*;\n\n#[instrument(level = \"debug\")]\npub async fn send_alert(\n"
  },
  {
    "path": "bin/core/src/alert/mod.rs",
    "chars": 13328,
    "preview": "use ::slack::types::Block;\nuse anyhow::{Context, anyhow};\nuse database::mungos::{find::find_collect, mongodb::bson::doc}"
  },
  {
    "path": "bin/core/src/alert/ntfy.rs",
    "chars": 1252,
    "preview": "use std::sync::OnceLock;\n\nuse super::*;\n\n#[instrument(level = \"debug\")]\npub async fn send_alert(\n  url: &str,\n  email: O"
  },
  {
    "path": "bin/core/src/alert/pushover.rs",
    "chars": 1420,
    "preview": "use std::sync::OnceLock;\n\nuse super::*;\n\n#[instrument(level = \"debug\")]\npub async fn send_alert(\n  url: &str,\n  alert: &"
  },
  {
    "path": "bin/core/src/alert/slack.rs",
    "chars": 13781,
    "preview": "use super::*;\n\n#[instrument(level = \"debug\")]\npub async fn send_alert(\n  url: &str,\n  alert: &Alert,\n) -> anyhow::Result"
  },
  {
    "path": "bin/core/src/api/auth.rs",
    "chars": 4313,
    "preview": "use std::{sync::OnceLock, time::Instant};\n\nuse axum::{Router, extract::Path, http::HeaderMap, routing::post};\nuse derive"
  },
  {
    "path": "bin/core/src/api/execute/action.rs",
    "chars": 11306,
    "preview": "use std::{\n  collections::HashSet,\n  path::{Path, PathBuf},\n  str::FromStr,\n  sync::OnceLock,\n};\n\nuse anyhow::Context;\nu"
  },
  {
    "path": "bin/core/src/api/execute/alerter.rs",
    "chars": 3927,
    "preview": "use anyhow::{Context, anyhow};\nuse formatting::format_serror;\nuse futures::{TryStreamExt, stream::FuturesUnordered};\nuse"
  },
  {
    "path": "bin/core/src/api/execute/build.rs",
    "chars": 18391,
    "preview": "use std::{\n  collections::{HashMap, HashSet},\n  future::IntoFuture,\n  time::Duration,\n};\n\nuse anyhow::{Context, anyhow};"
  },
  {
    "path": "bin/core/src/api/execute/deployment.rs",
    "chars": 21820,
    "preview": "use std::sync::OnceLock;\n\nuse anyhow::{Context, anyhow};\nuse cache::TimeoutCache;\nuse formatting::format_serror;\nuse int"
  },
  {
    "path": "bin/core/src/api/execute/maintenance.rs",
    "chars": 8511,
    "preview": "use std::sync::OnceLock;\n\nuse anyhow::{Context, anyhow};\nuse command::run_komodo_command;\nuse database::mungos::{find::f"
  },
  {
    "path": "bin/core/src/api/execute/mod.rs",
    "chars": 9267,
    "preview": "use std::{pin::Pin, time::Instant};\n\nuse anyhow::Context;\nuse axum::{\n  Extension, Router, extract::Path, middleware, ro"
  },
  {
    "path": "bin/core/src/api/execute/procedure.rs",
    "chars": 4511,
    "preview": "use std::pin::Pin;\n\nuse database::mungos::{\n  by_id::update_one_by_id, mongodb::bson::to_document,\n};\nuse formatting::{C"
  },
  {
    "path": "bin/core/src/api/execute/repo.rs",
    "chars": 21001,
    "preview": "use std::{collections::HashSet, future::IntoFuture, time::Duration};\n\nuse anyhow::{Context, anyhow};\nuse database::mungo"
  },
  {
    "path": "bin/core/src/api/execute/server.rs",
    "chars": 31080,
    "preview": "use anyhow::Context;\nuse formatting::format_serror;\nuse komodo_client::{\n  api::execute::*,\n  entities::{\n    all_logs_s"
  },
  {
    "path": "bin/core/src/api/execute/stack.rs",
    "chars": 29338,
    "preview": "use std::{collections::HashSet, str::FromStr};\n\nuse anyhow::Context;\nuse database::mungos::mongodb::bson::{\n  doc, oid::"
  },
  {
    "path": "bin/core/src/api/execute/sync.rs",
    "chars": 14423,
    "preview": "use std::{collections::HashMap, str::FromStr};\n\nuse anyhow::{Context, anyhow};\nuse database::mungos::{\n  by_id::update_o"
  },
  {
    "path": "bin/core/src/api/mod.rs",
    "chars": 161,
    "preview": "pub mod auth;\npub mod execute;\npub mod read;\npub mod terminal;\npub mod user;\npub mod write;\n\n#[derive(serde::Deserialize"
  },
  {
    "path": "bin/core/src/api/read/action.rs",
    "chars": 3263,
    "preview": "use anyhow::Context;\nuse komodo_client::{\n  api::read::*,\n  entities::{\n    action::{\n      Action, ActionActionState, A"
  },
  {
    "path": "bin/core/src/api/read/alert.rs",
    "chars": 2346,
    "preview": "use anyhow::Context;\nuse database::mungos::{\n  by_id::find_one_by_id,\n  find::find_collect,\n  mongodb::{bson::doc, optio"
  },
  {
    "path": "bin/core/src/api/read/alerter.rs",
    "chars": 2218,
    "preview": "use anyhow::Context;\nuse database::mongo_indexed::Document;\nuse database::mungos::mongodb::bson::doc;\nuse komodo_client:"
  },
  {
    "path": "bin/core/src/api/read/build.rs",
    "chars": 9008,
    "preview": "use std::collections::{HashMap, HashSet};\n\nuse anyhow::Context;\nuse async_timing_util::unix_timestamp_ms;\nuse database::"
  },
  {
    "path": "bin/core/src/api/read/builder.rs",
    "chars": 2218,
    "preview": "use anyhow::Context;\nuse database::mongo_indexed::Document;\nuse database::mungos::mongodb::bson::doc;\nuse komodo_client:"
  },
  {
    "path": "bin/core/src/api/read/deployment.rs",
    "chars": 8839,
    "preview": "use std::{cmp, collections::HashSet};\n\nuse anyhow::{Context, anyhow};\nuse komodo_client::{\n  api::read::*,\n  entities::{"
  },
  {
    "path": "bin/core/src/api/read/mod.rs",
    "chars": 16169,
    "preview": "use std::{collections::HashSet, sync::OnceLock, time::Instant};\n\nuse anyhow::{Context, anyhow};\nuse axum::{\n  Extension,"
  },
  {
    "path": "bin/core/src/api/read/permission.rs",
    "chars": 1767,
    "preview": "use anyhow::{Context, anyhow};\nuse database::mungos::{find::find_collect, mongodb::bson::doc};\nuse komodo_client::{\n  ap"
  },
  {
    "path": "bin/core/src/api/read/procedure.rs",
    "chars": 3324,
    "preview": "use anyhow::Context;\nuse komodo_client::{\n  api::read::*,\n  entities::{\n    permission::PermissionLevel,\n    procedure::"
  },
  {
    "path": "bin/core/src/api/read/provider.rs",
    "chars": 3031,
    "preview": "use anyhow::{Context, anyhow};\nuse database::mongo_indexed::{Document, doc};\nuse database::mungos::{\n  by_id::find_one_b"
  },
  {
    "path": "bin/core/src/api/read/repo.rs",
    "chars": 5939,
    "preview": "use anyhow::Context;\nuse komodo_client::{\n  api::read::*,\n  entities::{\n    config::core::CoreConfig,\n    permission::Pe"
  },
  {
    "path": "bin/core/src/api/read/schedule.rs",
    "chars": 3152,
    "preview": "use futures::future::join_all;\nuse komodo_client::{\n  api::read::*,\n  entities::{\n    ResourceTarget,\n    action::Action"
  },
  {
    "path": "bin/core/src/api/read/server.rs",
    "chars": 21260,
    "preview": "use std::{\n  cmp,\n  collections::HashMap,\n  sync::{Arc, OnceLock},\n};\n\nuse anyhow::{Context, anyhow};\nuse async_timing_u"
  },
  {
    "path": "bin/core/src/api/read/stack.rs",
    "chars": 10681,
    "preview": "use std::collections::HashSet;\n\nuse anyhow::{Context, anyhow};\nuse komodo_client::{\n  api::read::*,\n  entities::{\n    co"
  },
  {
    "path": "bin/core/src/api/read/sync.rs",
    "chars": 5590,
    "preview": "use anyhow::Context;\nuse komodo_client::{\n  api::read::*,\n  entities::{\n    config::core::CoreConfig,\n    permission::Pe"
  },
  {
    "path": "bin/core/src/api/read/tag.rs",
    "chars": 783,
    "preview": "use anyhow::Context;\nuse database::mongo_indexed::doc;\nuse database::mungos::{\n  find::find_collect, mongodb::options::F"
  },
  {
    "path": "bin/core/src/api/read/toml.rs",
    "chars": 13548,
    "preview": "use anyhow::Context;\nuse database::mungos::find::find_collect;\nuse komodo_client::{\n  api::read::{\n    ExportAllResource"
  },
  {
    "path": "bin/core/src/api/read/update.rs",
    "chars": 8029,
    "preview": "use std::collections::HashMap;\n\nuse anyhow::{Context, anyhow};\nuse database::mungos::{\n  by_id::find_one_by_id,\n  find::"
  },
  {
    "path": "bin/core/src/api/read/user.rs",
    "chars": 3400,
    "preview": "use anyhow::{Context, anyhow};\nuse database::mungos::{\n  by_id::find_one_by_id,\n  find::find_collect,\n  mongodb::{bson::"
  },
  {
    "path": "bin/core/src/api/read/user_group.rs",
    "chars": 1512,
    "preview": "use std::str::FromStr;\n\nuse anyhow::Context;\nuse database::mungos::{\n  find::find_collect,\n  mongodb::{\n    bson::{Docum"
  },
  {
    "path": "bin/core/src/api/read/variable.rs",
    "chars": 1304,
    "preview": "use anyhow::Context;\nuse database::mongo_indexed::doc;\nuse database::mungos::{\n  find::find_collect, mongodb::options::F"
  },
  {
    "path": "bin/core/src/api/terminal.rs",
    "chars": 6676,
    "preview": "use anyhow::Context;\nuse axum::{Extension, Router, middleware, routing::post};\nuse komodo_client::{\n  api::terminal::*,\n"
  },
  {
    "path": "bin/core/src/api/user.rs",
    "chars": 5551,
    "preview": "use std::{collections::VecDeque, time::Instant};\n\nuse anyhow::{Context, anyhow};\nuse axum::{\n  Extension, Json, Router, "
  },
  {
    "path": "bin/core/src/api/write/action.rs",
    "chars": 1684,
    "preview": "use komodo_client::{\n  api::write::*,\n  entities::{\n    action::Action, permission::PermissionLevel, update::Update,\n  }"
  },
  {
    "path": "bin/core/src/api/write/alerter.rs",
    "chars": 1742,
    "preview": "use komodo_client::{\n  api::write::*,\n  entities::{\n    alerter::Alerter, permission::PermissionLevel, update::Update,\n "
  },
  {
    "path": "bin/core/src/api/write/build.rs",
    "chars": 18595,
    "preview": "use std::{path::PathBuf, str::FromStr, time::Duration};\n\nuse anyhow::{Context, anyhow};\nuse database::mongo_indexed::doc"
  },
  {
    "path": "bin/core/src/api/write/builder.rs",
    "chars": 1742,
    "preview": "use komodo_client::{\n  api::write::*,\n  entities::{\n    builder::Builder, permission::PermissionLevel, update::Update,\n "
  },
  {
    "path": "bin/core/src/api/write/deployment.rs",
    "chars": 7060,
    "preview": "use anyhow::{Context, anyhow};\nuse database::mungos::{by_id::update_one_by_id, mongodb::bson::doc};\nuse komodo_client::{"
  },
  {
    "path": "bin/core/src/api/write/mod.rs",
    "chars": 6871,
    "preview": "use std::time::Instant;\n\nuse anyhow::Context;\nuse axum::{\n  Extension, Router, extract::Path, middleware, routing::post,"
  },
  {
    "path": "bin/core/src/api/write/permissions.rs",
    "chars": 12816,
    "preview": "use std::str::FromStr;\n\nuse anyhow::{Context, anyhow};\nuse database::mungos::{\n  by_id::{find_one_by_id, update_one_by_i"
  },
  {
    "path": "bin/core/src/api/write/procedure.rs",
    "chars": 1887,
    "preview": "use komodo_client::{\n  api::write::*,\n  entities::{\n    permission::PermissionLevel, procedure::Procedure, update::Updat"
  },
  {
    "path": "bin/core/src/api/write/provider.rs",
    "chars": 9736,
    "preview": "use anyhow::{Context, anyhow};\nuse database::mungos::{\n  by_id::{delete_one_by_id, find_one_by_id, update_one_by_id},\n  "
  },
  {
    "path": "bin/core/src/api/write/repo.rs",
    "chars": 11637,
    "preview": "use anyhow::{Context, anyhow};\nuse database::mongo_indexed::doc;\nuse database::mungos::{\n  by_id::update_one_by_id, mong"
  },
  {
    "path": "bin/core/src/api/write/resource.rs",
    "chars": 2154,
    "preview": "use anyhow::anyhow;\nuse komodo_client::{\n  api::write::{UpdateResourceMeta, UpdateResourceMetaResponse},\n  entities::{\n "
  },
  {
    "path": "bin/core/src/api/write/server.rs",
    "chars": 4751,
    "preview": "use anyhow::Context;\nuse formatting::format_serror;\nuse komodo_client::{\n  api::write::*,\n  entities::{\n    NoData, Oper"
  },
  {
    "path": "bin/core/src/api/write/service_user.rs",
    "chars": 4519,
    "preview": "use std::str::FromStr;\n\nuse anyhow::{Context, anyhow};\nuse database::mungos::{\n  by_id::find_one_by_id,\n  mongodb::bson:"
  },
  {
    "path": "bin/core/src/api/write/stack.rs",
    "chars": 19923,
    "preview": "use std::path::PathBuf;\n\nuse anyhow::{Context, anyhow};\nuse database::mungos::mongodb::bson::{doc, to_document};\nuse for"
  },
  {
    "path": "bin/core/src/api/write/sync.rs",
    "chars": 30536,
    "preview": "use std::{\n  collections::HashMap,\n  path::{Path, PathBuf},\n};\n\nuse anyhow::{Context, anyhow};\nuse database::mungos::{\n "
  },
  {
    "path": "bin/core/src/api/write/tag.rs",
    "chars": 3665,
    "preview": "use std::str::FromStr;\n\nuse anyhow::{Context, anyhow};\nuse database::mungos::{\n  by_id::{delete_one_by_id, update_one_by"
  },
  {
    "path": "bin/core/src/api/write/user.rs",
    "chars": 5915,
    "preview": "use std::str::FromStr;\n\nuse anyhow::{Context, anyhow};\nuse async_timing_util::unix_timestamp_ms;\nuse database::{\n  hash_"
  },
  {
    "path": "bin/core/src/api/write/user_group.rs",
    "chars": 8199,
    "preview": "use std::{collections::HashMap, str::FromStr};\n\nuse anyhow::{Context, anyhow};\nuse database::mungos::{\n  by_id::{delete_"
  },
  {
    "path": "bin/core/src/api/write/variable.rs",
    "chars": 5345,
    "preview": "use anyhow::{Context, anyhow};\nuse database::mungos::mongodb::bson::doc;\nuse komodo_client::{\n  api::write::*,\n  entitie"
  },
  {
    "path": "bin/core/src/auth/github/client.rs",
    "chars": 5905,
    "preview": "use std::sync::OnceLock;\n\nuse anyhow::{Context, anyhow};\nuse komodo_client::entities::config::core::{\n  CoreConfig, Oaut"
  },
  {
    "path": "bin/core/src/auth/github/mod.rs",
    "chars": 3963,
    "preview": "use anyhow::{Context, anyhow};\nuse axum::{\n  Router, extract::Query, response::Redirect, routing::get,\n};\nuse database::"
  },
  {
    "path": "bin/core/src/auth/google/client.rs",
    "chars": 5386,
    "preview": "use std::sync::OnceLock;\n\nuse anyhow::{Context, anyhow};\nuse jsonwebtoken::{DecodingKey, Validation, decode};\nuse komodo"
  },
  {
    "path": "bin/core/src/auth/google/mod.rs",
    "chars": 4421,
    "preview": "use anyhow::{Context, anyhow};\nuse async_timing_util::unix_timestamp_ms;\nuse axum::{\n  Router, extract::Query, response:"
  },
  {
    "path": "bin/core/src/auth/jwt.rs",
    "chars": 2875,
    "preview": "use std::collections::HashMap;\n\nuse anyhow::{Context, anyhow};\nuse async_timing_util::{\n  Timelength, get_timelength_in_"
  },
  {
    "path": "bin/core/src/auth/local.rs",
    "chars": 3780,
    "preview": "use std::str::FromStr;\n\nuse anyhow::{Context, anyhow};\nuse async_timing_util::unix_timestamp_ms;\nuse database::{\n  hash_"
  },
  {
    "path": "bin/core/src/auth/mod.rs",
    "chars": 3716,
    "preview": "use anyhow::{Context, anyhow};\nuse async_timing_util::unix_timestamp_ms;\nuse axum::{\n  extract::Request, http::HeaderMap"
  },
  {
    "path": "bin/core/src/auth/oidc/client.rs",
    "chars": 2598,
    "preview": "use std::{sync::OnceLock, time::Duration};\n\nuse anyhow::Context;\nuse arc_swap::ArcSwapOption;\nuse openidconnect::{\n  Cli"
  },
  {
    "path": "bin/core/src/auth/oidc/mod.rs",
    "chars": 9635,
    "preview": "use std::sync::OnceLock;\n\nuse anyhow::{Context, anyhow};\nuse axum::{\n  Router, extract::Query, response::Redirect, routi"
  },
  {
    "path": "bin/core/src/cloud/aws/ec2.rs",
    "chars": 35356,
    "preview": "use std::time::Duration;\n\nuse anyhow::{Context, anyhow};\nuse aws_config::{BehaviorVersion, Region};\nuse aws_sdk_ec2::{\n "
  },
  {
    "path": "bin/core/src/cloud/aws/mod.rs",
    "chars": 13,
    "preview": "pub mod ec2;\n"
  },
  {
    "path": "bin/core/src/cloud/mod.rs",
    "chars": 172,
    "preview": "pub mod aws;\n\n#[derive(Debug)]\npub enum BuildCleanupData {\n  /// Nothing to clean up\n  Server,\n  /// Clean up AWS instan"
  },
  {
    "path": "bin/core/src/config.rs",
    "chars": 11247,
    "preview": "use std::{path::PathBuf, sync::OnceLock};\n\nuse anyhow::Context;\nuse colored::Colorize;\nuse config::ConfigLoader;\nuse env"
  },
  {
    "path": "bin/core/src/helpers/action_state.rs",
    "chars": 3343,
    "preview": "use std::sync::{Arc, Mutex};\n\nuse anyhow::anyhow;\nuse komodo_client::{\n  busy::Busy,\n  entities::{\n    action::ActionAct"
  },
  {
    "path": "bin/core/src/helpers/all_resources.rs",
    "chars": 2191,
    "preview": "use std::collections::HashMap;\n\nuse komodo_client::entities::{\n  action::Action, alerter::Alerter, build::Build, builder"
  },
  {
    "path": "bin/core/src/helpers/builder.rs",
    "chars": 6185,
    "preview": "use std::time::Duration;\n\nuse anyhow::{Context, anyhow};\nuse formatting::muted;\nuse komodo_client::entities::{\n  Version"
  },
  {
    "path": "bin/core/src/helpers/cache.rs",
    "chars": 2109,
    "preview": "use std::{collections::HashMap, hash::Hash};\n\nuse tokio::sync::RwLock;\n\n#[derive(Default)]\npub struct Cache<K: PartialEq"
  },
  {
    "path": "bin/core/src/helpers/channel.rs",
    "chars": 1290,
    "preview": "use std::sync::OnceLock;\n\nuse komodo_client::entities::update::{Update, UpdateListItem};\nuse tokio::sync::{Mutex, broadc"
  },
  {
    "path": "bin/core/src/helpers/maintenance.rs",
    "chars": 3298,
    "preview": "use std::str::FromStr;\n\nuse anyhow::Context;\nuse chrono::{Datelike, Local};\nuse komodo_client::entities::{\n  DayOfWeek, "
  },
  {
    "path": "bin/core/src/helpers/matcher.rs",
    "chars": 883,
    "preview": "use anyhow::Context;\n\npub enum Matcher<'a> {\n  Wildcard(wildcard::Wildcard<'a>),\n  Regex(regex::Regex),\n}\n\nimpl<'a> Matc"
  },
  {
    "path": "bin/core/src/helpers/mod.rs",
    "chars": 6569,
    "preview": "use std::{fmt::Write, time::Duration};\n\nuse anyhow::{Context, anyhow};\nuse database::mongo_indexed::Document;\nuse databa"
  },
  {
    "path": "bin/core/src/helpers/procedure.rs",
    "chars": 40532,
    "preview": "use std::time::{Duration, Instant};\n\nuse anyhow::{Context, anyhow};\nuse database::mungos::by_id::find_one_by_id;\nuse for"
  },
  {
    "path": "bin/core/src/helpers/prune.rs",
    "chars": 2497,
    "preview": "use anyhow::Context;\nuse async_timing_util::{\n  ONE_DAY_MS, Timelength, unix_timestamp_ms, wait_until_timelength,\n};\nuse"
  },
  {
    "path": "bin/core/src/helpers/query.rs",
    "chars": 13055,
    "preview": "use std::{\n  collections::HashMap,\n  str::FromStr,\n  sync::{Arc, OnceLock},\n};\n\nuse anyhow::{Context, anyhow};\nuse async"
  },
  {
    "path": "bin/core/src/helpers/update.rs",
    "chars": 14930,
    "preview": "use anyhow::Context;\nuse database::mungos::{\n  by_id::{find_one_by_id, update_one_by_id},\n  mongodb::bson::to_document,\n"
  },
  {
    "path": "bin/core/src/listener/integrations/github.rs",
    "chars": 1708,
    "preview": "use anyhow::{Context, anyhow};\nuse axum::http::HeaderMap;\nuse hex::ToHex;\nuse hmac::{Hmac, Mac};\nuse serde::Deserialize;"
  },
  {
    "path": "bin/core/src/listener/integrations/gitlab.rs",
    "chars": 1229,
    "preview": "use anyhow::{Context, anyhow};\nuse serde::Deserialize;\n\nuse crate::{\n  config::core_config,\n  listener::{ExtractBranch, "
  },
  {
    "path": "bin/core/src/listener/integrations/mod.rs",
    "chars": 32,
    "preview": "pub mod github;\npub mod gitlab;\n"
  },
  {
    "path": "bin/core/src/listener/mod.rs",
    "chars": 1479,
    "preview": "use std::sync::Arc;\n\nuse anyhow::anyhow;\nuse axum::{Router, http::HeaderMap};\nuse komodo_client::entities::resource::Res"
  },
  {
    "path": "bin/core/src/listener/resources.rs",
    "chars": 13004,
    "preview": "use std::{str::FromStr, sync::OnceLock};\n\nuse anyhow::{Context, anyhow};\nuse komodo_client::{\n  api::{\n    execute::*,\n "
  },
  {
    "path": "bin/core/src/listener/router.rs",
    "chars": 5882,
    "preview": "use axum::{Router, extract::Path, http::HeaderMap, routing::post};\nuse komodo_client::entities::{\n  action::Action, buil"
  },
  {
    "path": "bin/core/src/main.rs",
    "chars": 4449,
    "preview": "#[macro_use]\nextern crate tracing;\n\nuse std::{net::SocketAddr, str::FromStr};\n\nuse anyhow::Context;\nuse axum::Router;\nus"
  },
  {
    "path": "bin/core/src/monitor/alert/deployment.rs",
    "chars": 2436,
    "preview": "use std::collections::HashMap;\n\nuse komodo_client::entities::{\n  ResourceTarget,\n  alert::{Alert, AlertData, SeverityLev"
  },
  {
    "path": "bin/core/src/monitor/alert/mod.rs",
    "chars": 1343,
    "preview": "use std::collections::HashMap;\n\nuse anyhow::Context;\nuse komodo_client::entities::{\n  permission::PermissionLevel, resou"
  },
  {
    "path": "bin/core/src/monitor/alert/server.rs",
    "chars": 21939,
    "preview": "use std::{\n  collections::HashMap,\n  path::PathBuf,\n  str::FromStr,\n  sync::{Mutex, OnceLock},\n};\n\nuse anyhow::Context;\n"
  },
  {
    "path": "bin/core/src/monitor/alert/stack.rs",
    "chars": 2304,
    "preview": "use std::collections::HashMap;\n\nuse komodo_client::entities::{\n  ResourceTarget,\n  alert::{Alert, AlertData, SeverityLev"
  },
  {
    "path": "bin/core/src/monitor/helpers.rs",
    "chars": 4649,
    "preview": "use komodo_client::entities::{\n  alert::SeverityLevel,\n  deployment::{Deployment, DeploymentState},\n  docker::{\n    cont"
  },
  {
    "path": "bin/core/src/monitor/lists.rs",
    "chars": 1247,
    "preview": "use komodo_client::entities::{\n  docker::{\n    container::ContainerListItem, image::ImageListItem,\n    network::NetworkL"
  },
  {
    "path": "bin/core/src/monitor/mod.rs",
    "chars": 9403,
    "preview": "use std::sync::{Arc, OnceLock};\n\nuse async_timing_util::wait_until_timelength;\nuse database::mungos::{find::find_collect"
  },
  {
    "path": "bin/core/src/monitor/record.rs",
    "chars": 1182,
    "preview": "use komodo_client::entities::stats::{\n  SystemStatsRecord, TotalDiskUsage, sum_disk_usage,\n};\n\nuse crate::state::{db_cli"
  },
  {
    "path": "bin/core/src/monitor/resources.rs",
    "chars": 13256,
    "preview": "use std::{\n  collections::HashSet,\n  sync::{Mutex, OnceLock},\n};\n\nuse anyhow::Context;\nuse komodo_client::{\n  api::execu"
  },
  {
    "path": "bin/core/src/network.rs",
    "chars": 9028,
    "preview": "//! # Network Configuration Module\n//!\n//! This module provides manual network interface configuration for multi-NIC Doc"
  },
  {
    "path": "bin/core/src/permission.rs",
    "chars": 6903,
    "preview": "use std::collections::HashSet;\n\nuse anyhow::{Context, anyhow};\nuse database::mongo_indexed::doc;\nuse database::mungos::f"
  },
  {
    "path": "bin/core/src/resource/action.rs",
    "chars": 5384,
    "preview": "use std::time::Duration;\n\nuse anyhow::Context;\nuse database::mungos::{\n  find::find_collect,\n  mongodb::{Collection, bso"
  },
  {
    "path": "bin/core/src/resource/alerter.rs",
    "chars": 2726,
    "preview": "use database::mungos::mongodb::Collection;\nuse derive_variants::ExtractVariant;\nuse komodo_client::entities::{\n  Operati"
  },
  {
    "path": "bin/core/src/resource/build.rs",
    "chars": 9121,
    "preview": "use std::time::Duration;\n\nuse anyhow::Context;\nuse database::mungos::{\n  find::find_collect,\n  mongodb::{Collection, bso"
  },
  {
    "path": "bin/core/src/resource/builder.rs",
    "chars": 4799,
    "preview": "use anyhow::Context;\nuse database::mungos::mongodb::{\n  Collection,\n  bson::{Document, doc, to_document},\n};\nuse indexma"
  },
  {
    "path": "bin/core/src/resource/deployment.rs",
    "chars": 9341,
    "preview": "use anyhow::Context;\nuse database::mungos::mongodb::Collection;\nuse formatting::format_serror;\nuse indexmap::IndexSet;\nu"
  },
  {
    "path": "bin/core/src/resource/mod.rs",
    "chars": 25061,
    "preview": "use std::{\n  collections::{HashMap, HashSet},\n  str::FromStr,\n};\n\nuse anyhow::{Context, anyhow};\nuse database::mungos::{"
  },
  {
    "path": "bin/core/src/resource/procedure.rs",
    "chars": 24190,
    "preview": "use std::time::Duration;\n\nuse anyhow::{Context, anyhow};\nuse database::mungos::{\n  find::find_collect,\n  mongodb::{Colle"
  },
  {
    "path": "bin/core/src/resource/refresh.rs",
    "chars": 3804,
    "preview": "use std::time::Duration;\n\nuse async_timing_util::{Timelength, get_timelength_in_ms};\nuse database::mungos::find::find_co"
  },
  {
    "path": "bin/core/src/resource/repo.rs",
    "chars": 7609,
    "preview": "use std::time::Duration;\n\nuse anyhow::Context;\nuse database::mungos::{\n  find::find_collect,\n  mongodb::{Collection, bso"
  },
  {
    "path": "bin/core/src/resource/server.rs",
    "chars": 5628,
    "preview": "use anyhow::Context;\nuse database::mungos::mongodb::{Collection, bson::doc};\nuse indexmap::IndexSet;\nuse komodo_client::"
  },
  {
    "path": "bin/core/src/resource/stack.rs",
    "chars": 10329,
    "preview": "use anyhow::Context;\nuse database::mungos::mongodb::Collection;\nuse formatting::format_serror;\nuse indexmap::IndexSet;\nu"
  },
  {
    "path": "bin/core/src/resource/sync.rs",
    "chars": 6813,
    "preview": "use anyhow::Context;\nuse database::mongo_indexed::doc;\nuse database::mungos::mongodb::Collection;\nuse formatting::format"
  },
  {
    "path": "bin/core/src/schedule.rs",
    "chars": 11529,
    "preview": "use std::{\n  collections::HashMap,\n  sync::{OnceLock, RwLock},\n};\n\nuse anyhow::{Context, anyhow};\nuse async_timing_util:"
  },
  {
    "path": "bin/core/src/stack/execute.rs",
    "chars": 5142,
    "preview": "use komodo_client::{\n  api::execute::*,\n  entities::{\n    permission::PermissionLevel,\n    stack::{Stack, StackActionSta"
  },
  {
    "path": "bin/core/src/stack/mod.rs",
    "chars": 1236,
    "preview": "use anyhow::{Context, anyhow};\nuse komodo_client::entities::{\n  permission::PermissionLevelAndSpecifics,\n  server::{Serv"
  },
  {
    "path": "bin/core/src/stack/remote.rs",
    "chars": 3104,
    "preview": "use std::{fs, path::PathBuf};\n\nuse anyhow::Context;\nuse formatting::format_serror;\nuse komodo_client::entities::{\n  File"
  },
  {
    "path": "bin/core/src/stack/services.rs",
    "chars": 1921,
    "preview": "use anyhow::Context;\nuse komodo_client::entities::stack::{\n  ComposeFile, ComposeService, ComposeServiceDeploy, Stack,\n "
  },
  {
    "path": "bin/core/src/startup.rs",
    "chars": 12215,
    "preview": "use std::str::FromStr;\n\nuse colored::Colorize;\nuse database::mungos::{\n  find::find_collect,\n  mongodb::bson::{Document,"
  },
  {
    "path": "bin/core/src/state.rs",
    "chars": 6108,
    "preview": "use std::{\n  collections::HashMap,\n  sync::{Arc, OnceLock},\n};\n\nuse anyhow::Context;\nuse arc_swap::ArcSwap;\nuse database"
  },
  {
    "path": "bin/core/src/sync/deploy.rs",
    "chars": 24131,
    "preview": "use std::{collections::HashMap, time::Duration};\n\nuse anyhow::{Context, anyhow};\nuse formatting::{Color, bold, colored, "
  },
  {
    "path": "bin/core/src/sync/execute.rs",
    "chars": 7852,
    "preview": "use std::collections::HashMap;\n\nuse anyhow::Context;\nuse database::mungos::find::find_collect;\nuse formatting::{Color, b"
  },
  {
    "path": "bin/core/src/sync/file.rs",
    "chars": 8027,
    "preview": "use std::{\n  fs,\n  path::{Path, PathBuf},\n};\n\nuse anyhow::{Context, anyhow};\nuse formatting::{Color, bold, colored, form"
  },
  {
    "path": "bin/core/src/sync/mod.rs",
    "chars": 4479,
    "preview": "use std::{collections::HashMap, str::FromStr};\n\nuse anyhow::anyhow;\nuse database::mungos::mongodb::bson::oid::ObjectId;\n"
  },
  {
    "path": "bin/core/src/sync/remote.rs",
    "chars": 3837,
    "preview": "use anyhow::Context;\nuse komodo_client::entities::{\n  RepoExecutionArgs, RepoExecutionResponse,\n  repo::Repo,\n  sync::{R"
  },
  {
    "path": "bin/core/src/sync/resources.rs",
    "chars": 25881,
    "preview": "use std::collections::HashMap;\n\nuse formatting::{Color, bold, colored, muted};\nuse komodo_client::{\n  api::execute::Exec"
  },
  {
    "path": "bin/core/src/sync/toml.rs",
    "chars": 25494,
    "preview": "use std::collections::HashMap;\n\nuse anyhow::Context;\nuse indexmap::IndexMap;\nuse komodo_client::{\n  api::execute::Execut"
  },
  {
    "path": "bin/core/src/sync/user_groups.rs",
    "chars": 29836,
    "preview": "use std::{\n  cmp::Ordering, collections::HashMap, fmt::Write, sync::OnceLock,\n};\n\nuse anyhow::Context;\nuse database::mun"
  },
  {
    "path": "bin/core/src/sync/variables.rs",
    "chars": 7224,
    "preview": "use std::collections::HashMap;\n\nuse anyhow::Context;\nuse database::mungos::find::find_collect;\nuse formatting::{Color, b"
  },
  {
    "path": "bin/core/src/sync/view.rs",
    "chars": 4165,
    "preview": "use std::collections::HashMap;\n\nuse anyhow::Context;\nuse database::mungos::find::find_collect;\nuse komodo_client::entiti"
  },
  {
    "path": "bin/core/src/ts_client.rs",
    "chars": 1349,
    "preview": "use anyhow::{Context, anyhow};\nuse axum::{\n  Router,\n  extract::Path,\n  http::{HeaderMap, HeaderValue},\n  routing::get,\n"
  },
  {
    "path": "bin/core/src/ws/container.rs",
    "chars": 1229,
    "preview": "use axum::{\n  extract::{Query, WebSocketUpgrade, ws::Message},\n  response::IntoResponse,\n};\nuse futures::SinkExt;\nuse ko"
  },
  {
    "path": "bin/core/src/ws/deployment.rs",
    "chars": 1680,
    "preview": "use axum::{\n  extract::{Query, WebSocketUpgrade, ws::Message},\n  response::IntoResponse,\n};\nuse futures::SinkExt;\nuse ko"
  },
  {
    "path": "bin/core/src/ws/mod.rs",
    "chars": 7780,
    "preview": "use crate::{\n  auth::{auth_api_key_check_enabled, auth_jwt_check_enabled},\n  helpers::query::get_user,\n};\nuse anyhow::an"
  },
  {
    "path": "bin/core/src/ws/stack.rs",
    "chars": 2676,
    "preview": "use axum::{\n  extract::{Query, WebSocketUpgrade, ws::Message},\n  response::IntoResponse,\n};\nuse futures::SinkExt;\nuse ko"
  },
  {
    "path": "bin/core/src/ws/terminal.rs",
    "chars": 2050,
    "preview": "use axum::{\n  extract::{Query, WebSocketUpgrade, ws::Message},\n  response::IntoResponse,\n};\nuse futures::SinkExt;\nuse ko"
  },
  {
    "path": "bin/core/src/ws/update.rs",
    "chars": 2851,
    "preview": "use anyhow::anyhow;\nuse axum::{\n  extract::{WebSocketUpgrade, ws::Message},\n  response::IntoResponse,\n};\nuse futures::{S"
  },
  {
    "path": "bin/core/starship.toml",
    "chars": 1285,
    "preview": "## This is used to customize the shell prompt in Periphery container for Terminals\n\n\"$schema\" = 'https://starship.rs/con"
  },
  {
    "path": "bin/periphery/Cargo.toml",
    "chars": 1527,
    "preview": "[package]\nname = \"komodo_periphery\"\nversion.workspace = true\nedition.workspace = true\nauthors.workspace = true\nlicense.w"
  },
  {
    "path": "bin/periphery/aio.Dockerfile",
    "chars": 884,
    "preview": "## All in one, multi stage compile + runtime Docker build for your architecture.\n\nFROM rust:1.89.0-bullseye AS builder\nR"
  },
  {
    "path": "bin/periphery/debian-deps.sh",
    "chars": 962,
    "preview": "#!/bin/bash\n\n## Periphery deps installer\n\napt-get update\napt-get install -y git curl wget ca-certificates\n\ninstall -m 07"
  },
  {
    "path": "bin/periphery/multi-arch.Dockerfile",
    "chars": 1215,
    "preview": "## Assumes the latest binaries for x86_64 and aarch64 are already built (by binaries.Dockerfile).\n## Sets up the necessa"
  },
  {
    "path": "bin/periphery/single-arch.Dockerfile",
    "chars": 754,
    "preview": "## Assumes the latest binaries for the required arch are already built (by binaries.Dockerfile).\n## Sets up the necessar"
  },
  {
    "path": "bin/periphery/src/api/build.rs",
    "chars": 8767,
    "preview": "use std::{\n  collections::{HashMap, HashSet},\n  path::PathBuf,\n};\n\nuse anyhow::{Context, anyhow};\nuse command::{\n  run_k"
  },
  {
    "path": "bin/periphery/src/api/compose.rs",
    "chars": 21848,
    "preview": "use anyhow::{Context, anyhow};\nuse command::{\n  run_komodo_command, run_komodo_command_with_sanitization,\n};\nuse formatt"
  },
  {
    "path": "bin/periphery/src/api/container.rs",
    "chars": 10407,
    "preview": "use anyhow::Context;\nuse command::run_komodo_command;\nuse futures::future::join_all;\nuse komodo_client::entities::{\n  do"
  },
  {
    "path": "bin/periphery/src/api/deploy.rs",
    "chars": 4968,
    "preview": "use anyhow::Context;\nuse command::run_komodo_command_with_sanitization;\nuse formatting::format_serror;\nuse interpolate::"
  },
  {
    "path": "bin/periphery/src/api/git.rs",
    "chars": 5791,
    "preview": "use anyhow::{Context, anyhow};\nuse axum::http::StatusCode;\nuse formatting::format_serror;\nuse komodo_client::entities::{"
  },
  {
    "path": "bin/periphery/src/api/image.rs",
    "chars": 3021,
    "preview": "use std::sync::OnceLock;\n\nuse cache::TimeoutCache;\nuse command::run_komodo_command;\nuse komodo_client::entities::{\n  dep"
  },
  {
    "path": "bin/periphery/src/api/mod.rs",
    "chars": 6988,
    "preview": "use anyhow::Context;\nuse command::run_komodo_command;\nuse derive_variants::EnumVariants;\nuse futures::TryFutureExt;\nuse "
  },
  {
    "path": "bin/periphery/src/api/network.rs",
    "chars": 1531,
    "preview": "use command::run_komodo_command;\nuse komodo_client::entities::{\n  docker::network::Network, update::Log,\n};\nuse peripher"
  },
  {
    "path": "bin/periphery/src/api/router.rs",
    "chars": 3537,
    "preview": "use anyhow::{Context, anyhow};\nuse axum::{\n  Router,\n  body::Body,\n  extract::ConnectInfo,\n  http::{Request, StatusCode}"
  },
  {
    "path": "bin/periphery/src/api/stats.rs",
    "chars": 1077,
    "preview": "use komodo_client::entities::stats::{\n  SystemInformation, SystemProcess, SystemStats,\n};\nuse periphery_client::api::sta"
  },
  {
    "path": "bin/periphery/src/api/terminal.rs",
    "chars": 10858,
    "preview": "use anyhow::{Context, anyhow};\nuse axum::{\n  extract::{\n    Query, WebSocketUpgrade,\n    ws::{Message, Utf8Bytes},\n  },\n"
  },
  {
    "path": "bin/periphery/src/api/volume.rs",
    "chars": 1019,
    "preview": "use command::run_komodo_command;\nuse komodo_client::entities::{docker::volume::Volume, update::Log};\nuse periphery_clien"
  },
  {
    "path": "bin/periphery/src/build.rs",
    "chars": 2833,
    "preview": "use std::{\n  fmt::Write,\n  path::{Path, PathBuf},\n};\n\nuse anyhow::{Context, anyhow};\nuse formatting::format_serror;\nuse "
  },
  {
    "path": "bin/periphery/src/compose/mod.rs",
    "chars": 3639,
    "preview": "use std::{fmt::Write, path::PathBuf};\n\nuse anyhow::{Context, anyhow};\nuse command::run_komodo_command;\nuse komodo_client"
  },
  {
    "path": "bin/periphery/src/compose/up.rs",
    "chars": 2796,
    "preview": "use std::path::{Path, PathBuf};\n\nuse anyhow::{Context, anyhow};\nuse formatting::format_serror;\nuse komodo_client::entiti"
  },
  {
    "path": "bin/periphery/src/compose/write.rs",
    "chars": 9630,
    "preview": "use std::path::PathBuf;\n\nuse anyhow::{Context, anyhow};\nuse formatting::format_serror;\nuse komodo_client::entities::{\n  "
  },
  {
    "path": "bin/periphery/src/config.rs",
    "chars": 4608,
    "preview": "use std::{path::PathBuf, sync::OnceLock};\n\nuse clap::Parser;\nuse colored::Colorize;\nuse config::ConfigLoader;\nuse enviro"
  },
  {
    "path": "bin/periphery/src/docker/containers.rs",
    "chars": 24948,
    "preview": "use std::collections::HashMap;\n\nuse anyhow::Context;\nuse bollard::query_parameters::{\n  InspectContainerOptions, ListCon"
  }
]

// ... and 473 more files (download for full content)

About this extraction

This page contains the full source code of the moghtech/komodo GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 673 files (4.3 MB), approximately 1.2M tokens, and a symbol index with 5064 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!