diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index e7678228..00000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.decisions/2-Release-Cycle.md b/.decisions/2-Release-Cycle.md new file mode 100644 index 00000000..f741ee25 --- /dev/null +++ b/.decisions/2-Release-Cycle.md @@ -0,0 +1,19 @@ +# â„šī¸ Overview + +The release cycle is largely based on the internal Algorand Foundation's engineering compass. +It has been tailored to work with a cli based tool with binary artifacts + +## ✅ Decisions + +- **SHOULD** use conventional commits for consistency +- **SHOULD** use automated release tools like semantic-release +- **SHOULD** build for arm/amd64 on darwin and linux +- **SHOULD** have checks on code quality and regressions +- **SHOULD** present a manual page and generated reference material +- **SHOULD** provide handcrafted guides and documentation + +## 🔨 Deliverables + +- automated CI/CD release actions +- installer features for consumers +- marketing landing page with documentation site \ No newline at end of file diff --git a/.decisions/3-Node-Management.md b/.decisions/3-Node-Management.md new file mode 100644 index 00000000..7542edc9 --- /dev/null +++ b/.decisions/3-Node-Management.md @@ -0,0 +1,17 @@ +# â„šī¸ Overview + +Node Management has many aspects which this decision makes concrete. + +## ✅ Decisions + +- **SHOULD** include install/upgrade commands +- **SHOULD** include start/stop commands +- **SHOULD** include catchup commands +- **SHOULD** include bootstrap command + +## 🔨 Deliverables + +- Use package managers for installation and upgrades (brew, dnf, apt-get) +- Use native supervisors for algod orchestration (launchd, systemd) +- Bootstrap concept which ties several components together (install, start, fast-catchup, launch TUI) +- Limited amount of configurations for the initial release \ No newline at end of file diff --git a/.decisions/README.md b/.decisions/README.md index f13882e5..173ebd1d 100644 --- a/.decisions/README.md +++ b/.decisions/README.md @@ -1,3 +1,5 @@ # Decisions for this Project -- [1. GoLang/Charm TUI](1-GoLang-Charm.md) \ No newline at end of file +- [1. GoLang/Charm TUI](1-GoLang-Charm.md) +- [2. Release Cycle](2-Release-Cycle.md) +- [3. Node Management](3-Node-Management.md) \ No newline at end of file diff --git a/.gitignore b/.gitignore index a08a225b..ca362f52 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.DS_Store nodekit coverage bin diff --git a/.tapes/README.md b/.tapes/README.md new file mode 100644 index 00000000..c1ff62b9 --- /dev/null +++ b/.tapes/README.md @@ -0,0 +1,37 @@ +# Overview + +Includes various [vhs](https://github.com/charmbracelet/vhs) tapes for the project. +Useful for creating consistent demos and guides when the TUI updates + + +## Get Started + +Install vhs + +```bash +go install github.com/charmbracelet/vhs@latest +``` + +Copy the default `tui.tape` and name it appropriately + +```bash +cp ./tui.tape ./my-demo.tape +``` + +Edit the tape with your favorite editor. +Then you can run the vhs tape + +(Make sure to update the output file) + +```bash +vhs ./my-demo.tape +``` + +### Theme + +Example theme that uses some of the official Algorand Foundation brand guides + +``` +Set Theme { "name": "Whimsy", "black": "#2D2DFI", "red": "#ef6487", "green": "#5eca89", "yellow": "#fdd877", "blue": "#65aef7", "magenta": "#aa7ff0", "cyan": "#43c1be", "white": "#ffffff", "brightBlack": "#535178", "brightRed": "#ef6487", "brightGreen": "#5eca89", "brightYellow": "#fdd877", "brightBlue": "#65aef7", "brightMagenta": "#aa7ff0", "brightCyan": "#43c1be", "brightWhite": "#ffffff", "background": "#001324", "foreground": "#b3b0d6", "selection": "#3d3c58", "cursor": "#b3b0d6" } +``` + diff --git a/.tapes/tui.tape b/.tapes/tui.tape new file mode 100644 index 00000000..9f8f94e2 --- /dev/null +++ b/.tapes/tui.tape @@ -0,0 +1,25 @@ +Output ../assets/tapes/tui.gif + +Require nodekit + +Set Framerate 30 +Set Margin 1 + +Set Theme { "name": "Whimsy", "black": "#2D2DFI", "red": "#ef6487", "green": "#5eca89", "yellow": "#fdd877", "blue": "#65aef7", "magenta": "#aa7ff0", "cyan": "#43c1be", "white": "#ffffff", "brightBlack": "#535178", "brightRed": "#ef6487", "brightGreen": "#5eca89", "brightYellow": "#fdd877", "brightBlue": "#65aef7", "brightMagenta": "#aa7ff0", "brightCyan": "#43c1be", "brightWhite": "#ffffff", "background": "#001324", "foreground": "#b3b0d6", "selection": "#3d3c58", "cursor": "#b3b0d6" } + +Set Shell "bash" +Set FontSize 10 +Set Width 1280 +Set Height 640 + +Type "nodekit" Sleep 500ms Enter + +Sleep 3s Enter + +Sleep 500ms Down Sleep 1s Enter + +Sleep 1s Type "o" + +Sleep 5s + +Ctrl+C diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 577ae06b..c2efa1bb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,28 +22,8 @@ Build the project make build ``` -Optionally, run a sandboxed participation node - - -```bash -docker compose up -``` - -Create a configuration file for the participation node in the root directory of the project (.nodekit.yaml) - -```yaml -algod-endpoint: http://localhost:8080 -algod-token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -``` - -Launch the TUI - - -> [!NOTE] -> If you skipped the docker container or config file, try running `./bin/nodekit` standalone, -> which will detect your algorand data directory from the `ALGORAND_DATA` environment variable that works for `goal`. -> Otherwise, provide the `--algod-endpoint` and `--algod-token` arguments so that it can find your node. -> Note that nodekit requires the admin algod token. +Launch the TUI. +See the [full documentation](https://nodekit.run/guides/getting-started/) for a complete guide ```bash ./bin/nodekit @@ -52,7 +32,7 @@ Launch the TUI # 📂 Folder Structure ```bash -├── api # Generated API Client +├── api # Generated API Client and Hand Crafted HTTPInterface ├── cmd # Command Controller ├── internal # Data Models/Fetch Wrappers └── ui # BubbleTea Interfaces @@ -142,3 +122,8 @@ The full command for reference ```bash oapi-codegen -config generate.yaml https://raw.githubusercontent.com/algorand/go-algorand/v3.26.0-stable/daemon/algod/api/algod.oas3.yml ``` + +# Submitting Changes + +This project follows [GitHub flow](https://githubflow.github.io/). +Create a fork and submit changes directly to the `main` branch. \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..202e36eb --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Algorand Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/assets/tapes/tui.gif b/assets/tapes/tui.gif new file mode 100644 index 00000000..2518ed55 Binary files /dev/null and b/assets/tapes/tui.gif differ diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 00000000..c461f4ec --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,7 @@ +# Overview + +Collection of scripts and utilities used in this project. + +# Documentation + +Documentation generator is based on CobraDoc \ No newline at end of file diff --git a/scripts/wallet.json b/scripts/wallet.json new file mode 100644 index 00000000..fab5f2fb --- /dev/null +++ b/scripts/wallet.json @@ -0,0 +1,5 @@ +{ + "mnemonic": "artefact exist coil life turtle edge edge inside punch glance recycle teach melody diet method pause slam dumb race interest amused side learn able heavy", + "address": "TUIDKH2C7MUHZDD77MAMUREJRKNK25SYXB7OAFA6JFBB24PEL5UX4S4GUU", + "private_key": "Z/CTWhR4dRnJKHVurdhn6U3F9oRxoVj+0GBbF4Qf20+dEDUfQvsofIx/+wDKRImKmq12WLh+4BQeSUIdceRfaQ==" +} \ No newline at end of file diff --git a/scripts/wallet.mjs b/scripts/wallet.mjs deleted file mode 100644 index b26f5384..00000000 --- a/scripts/wallet.mjs +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env node - -import { - Algodv2, - makeKeyRegistrationTxnWithSuggestedParamsFromObject, - mnemonicToSecretKey, - waitForConfirmation -} from 'algosdk' -const key = { - 'mnemonic': 'artefact exist coil life turtle edge edge inside punch glance recycle teach melody diet method pause slam dumb race interest amused side learn able heavy', - 'address': 'TUIDKH2C7MUHZDD77MAMUREJRKNK25SYXB7OAFA6JFBB24PEL5UX4S4GUU', - 'private_key': 'Z/CTWhR4dRnJKHVurdhn6U3F9oRxoVj+0GBbF4Qf20+dEDUfQvsofIx/+wDKRImKmq12WLh+4BQeSUIdceRfaQ==' -} -const account = mnemonicToSecretKey(key.mnemonic) -console.log(account) - - -const keys = await fetch('http://localhost:8081/v2/participation', { - headers: { - "X-Algo-API-Token": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - } -}).then(r => r.json()) - -const partkey = keys.filter((k)=>k.address === key.address)[0] -console.log(partkey) - -const client = new Algodv2( - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "http://localhost", - 8081 -) - -const params = await client.getTransactionParams().do() - - -// sets up keys for 100000 rounds -const numRounds = 1e5; - -// dilution default is sqrt num rounds -const keyDilution = BigInt(Math.floor(numRounds ** 0.5)); - -const txn = makeKeyRegistrationTxnWithSuggestedParamsFromObject({ - sender: key.address, - voteKey: Buffer.from(partkey.key['vote-participation-key'], "base64"), - selectionKey: Buffer.from(partkey.key['selection-participation-key'], "base64"), - stateProofKey: Buffer.from(partkey.key['state-proof-key'], "base64"), - voteFirst: partkey.key['vote-first-valid'], - voteLast: partkey.key['vote-last-valid'], - voteKeyDilution: partkey.key['vote-key-dilution'], - suggestedParams: params, - } -) - -const signtxn = txn.signTxn(account.sk) - -const { txId } = await client.sendRawTransaction(signtxn).do(); -const result = await waitForConfirmation(client, txId, 40); -console.log(txn)