@akta/dao-cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +137 -0
- package/images/dao_view_styled.png +0 -0
- package/images/fees_view_styled.png +0 -0
- package/images/proposals_view_styled.png +0 -0
- package/images/wallet_view_styled.png +0 -0
- package/install.sh +19 -0
- package/package.json +33 -0
- package/src/commands/info.ts +33 -0
- package/src/commands/proposals.ts +133 -0
- package/src/commands/state.ts +167 -0
- package/src/commands/wallet.ts +356 -0
- package/src/formatting.ts +659 -0
- package/src/index.ts +188 -0
- package/src/output.ts +232 -0
- package/src/sdk.ts +37 -0
- package/src/theme.ts +73 -0
- package/src/tui/app.ts +366 -0
- package/src/tui/input.ts +85 -0
- package/src/tui/panels.ts +133 -0
- package/src/tui/renderer.ts +126 -0
- package/src/tui/terminal.ts +66 -0
- package/src/tui/types.ts +74 -0
- package/src/tui/views/dao.ts +338 -0
- package/src/tui/views/fees.ts +164 -0
- package/src/tui/views/proposal-detail.ts +331 -0
- package/src/tui/views/proposals-list.ts +213 -0
- package/src/tui/views/wallet.ts +560 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import type { AkitaNetwork } from "@akta/sdk";
|
|
4
|
+
import { createDAO } from "./sdk";
|
|
5
|
+
import { infoCommand } from "./commands/info";
|
|
6
|
+
import { stateCommand } from "./commands/state";
|
|
7
|
+
import { listProposals, getProposal } from "./commands/proposals";
|
|
8
|
+
import {
|
|
9
|
+
walletInfo,
|
|
10
|
+
walletPlugins,
|
|
11
|
+
walletNamedPlugins,
|
|
12
|
+
walletEscrows,
|
|
13
|
+
walletAllowances,
|
|
14
|
+
walletExecutions,
|
|
15
|
+
walletBalance,
|
|
16
|
+
} from "./commands/wallet";
|
|
17
|
+
import { startTUI } from "./tui/app";
|
|
18
|
+
|
|
19
|
+
const program = new Command();
|
|
20
|
+
|
|
21
|
+
program
|
|
22
|
+
.name("akita-dao")
|
|
23
|
+
.description("Read-only CLI for querying Akita DAO state on Algorand")
|
|
24
|
+
.version("0.1.0")
|
|
25
|
+
.option("-n, --network <network>", "Network to connect to", "mainnet")
|
|
26
|
+
.option("-j, --json", "Output as JSON", false);
|
|
27
|
+
|
|
28
|
+
function getOpts(): { network: AkitaNetwork; json: boolean } {
|
|
29
|
+
const opts = program.opts();
|
|
30
|
+
const network = opts.network as AkitaNetwork;
|
|
31
|
+
if (!["mainnet", "testnet", "localnet"].includes(network)) {
|
|
32
|
+
console.error(`Invalid network: ${network}. Use mainnet, testnet, or localnet.`);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
return { network, json: opts.json };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// tui
|
|
39
|
+
program
|
|
40
|
+
.command("tui")
|
|
41
|
+
.description("Launch interactive full-screen TUI")
|
|
42
|
+
.action(async () => {
|
|
43
|
+
const { network } = getOpts();
|
|
44
|
+
await startTUI(network);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// info
|
|
48
|
+
program
|
|
49
|
+
.command("info")
|
|
50
|
+
.description("Quick DAO dashboard (app IDs, assets, version)")
|
|
51
|
+
.action(async () => {
|
|
52
|
+
const { network, json } = getOpts();
|
|
53
|
+
const dao = createDAO(network);
|
|
54
|
+
await infoCommand(dao, network, json);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// state
|
|
58
|
+
program
|
|
59
|
+
.command("state")
|
|
60
|
+
.description("Full decoded global state")
|
|
61
|
+
.action(async () => {
|
|
62
|
+
const { network, json } = getOpts();
|
|
63
|
+
const dao = createDAO(network);
|
|
64
|
+
await stateCommand(dao, network, json);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// proposals
|
|
68
|
+
const proposals = program
|
|
69
|
+
.command("proposals")
|
|
70
|
+
.description("Proposal commands");
|
|
71
|
+
|
|
72
|
+
proposals
|
|
73
|
+
.command("list")
|
|
74
|
+
.description("List proposals")
|
|
75
|
+
.option("-s, --status <status>", "Filter by status: all, active, past", "all")
|
|
76
|
+
.option("-l, --limit <limit>", "Max proposals to show", "20")
|
|
77
|
+
.action(async (opts) => {
|
|
78
|
+
const { network, json } = getOpts();
|
|
79
|
+
const dao = createDAO(network);
|
|
80
|
+
await listProposals(dao, json, opts.status, parseInt(opts.limit, 10));
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
proposals
|
|
84
|
+
.command("get <id>")
|
|
85
|
+
.description("Get detailed proposal view")
|
|
86
|
+
.action(async (id: string) => {
|
|
87
|
+
const { network, json } = getOpts();
|
|
88
|
+
const dao = createDAO(network);
|
|
89
|
+
await getProposal(dao, BigInt(id), json);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// wallet
|
|
93
|
+
const walletCmd = program
|
|
94
|
+
.command("wallet")
|
|
95
|
+
.description("Wallet commands");
|
|
96
|
+
|
|
97
|
+
walletCmd
|
|
98
|
+
.command("info")
|
|
99
|
+
.description("Wallet global state")
|
|
100
|
+
.action(async () => {
|
|
101
|
+
const { network, json } = getOpts();
|
|
102
|
+
const dao = createDAO(network);
|
|
103
|
+
await walletInfo(dao, network, json);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
walletCmd
|
|
107
|
+
.command("plugins")
|
|
108
|
+
.description("All installed plugins")
|
|
109
|
+
.action(async () => {
|
|
110
|
+
const { network, json } = getOpts();
|
|
111
|
+
const dao = createDAO(network);
|
|
112
|
+
await walletPlugins(dao, network, json);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
walletCmd
|
|
116
|
+
.command("named-plugins")
|
|
117
|
+
.description("Named plugin aliases")
|
|
118
|
+
.action(async () => {
|
|
119
|
+
const { network, json } = getOpts();
|
|
120
|
+
const dao = createDAO(network);
|
|
121
|
+
await walletNamedPlugins(dao, json);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
walletCmd
|
|
125
|
+
.command("escrows")
|
|
126
|
+
.description("All escrows")
|
|
127
|
+
.action(async () => {
|
|
128
|
+
const { network, json } = getOpts();
|
|
129
|
+
const dao = createDAO(network);
|
|
130
|
+
await walletEscrows(dao, json);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
walletCmd
|
|
134
|
+
.command("allowances")
|
|
135
|
+
.description("All spending allowances")
|
|
136
|
+
.action(async () => {
|
|
137
|
+
const { network, json } = getOpts();
|
|
138
|
+
const dao = createDAO(network);
|
|
139
|
+
await walletAllowances(dao, json);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
walletCmd
|
|
143
|
+
.command("executions")
|
|
144
|
+
.description("All execution keys")
|
|
145
|
+
.action(async () => {
|
|
146
|
+
const { network, json } = getOpts();
|
|
147
|
+
const dao = createDAO(network);
|
|
148
|
+
await walletExecutions(dao, json);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
walletCmd
|
|
152
|
+
.command("balance [assets...]")
|
|
153
|
+
.description("Check balances (default: ALGO, AKTA, BONES)")
|
|
154
|
+
.option("-e, --escrow <name>", "Check escrow balance instead of main wallet")
|
|
155
|
+
.action(async (assets: string[], opts: { escrow?: string }) => {
|
|
156
|
+
const { network, json } = getOpts();
|
|
157
|
+
const dao = createDAO(network);
|
|
158
|
+
await walletBalance(dao, network, json, assets, opts.escrow);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// Hoist global flags (e.g. -n testnet) before the subcommand so Commander parses them
|
|
162
|
+
const GLOBAL_VALUE_FLAGS = new Set(["-n", "--network"]);
|
|
163
|
+
const GLOBAL_BOOL_FLAGS = new Set(["-j", "--json"]);
|
|
164
|
+
|
|
165
|
+
function hoistGlobalFlags(args: string[]): string[] {
|
|
166
|
+
const flags: string[] = [];
|
|
167
|
+
const rest: string[] = [];
|
|
168
|
+
for (let i = 0; i < args.length; i++) {
|
|
169
|
+
if (GLOBAL_VALUE_FLAGS.has(args[i]) && i + 1 < args.length) {
|
|
170
|
+
flags.push(args[i], args[i + 1]);
|
|
171
|
+
i++;
|
|
172
|
+
} else if (GLOBAL_BOOL_FLAGS.has(args[i])) {
|
|
173
|
+
flags.push(args[i]);
|
|
174
|
+
} else {
|
|
175
|
+
rest.push(args[i]);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return [...flags, ...rest];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const userArgs = hoistGlobalFlags(process.argv.slice(2));
|
|
182
|
+
const hasCommand = userArgs.some((arg) => !arg.startsWith("-"));
|
|
183
|
+
|
|
184
|
+
if (!hasCommand && process.stdout.isTTY) {
|
|
185
|
+
program.parse([...process.argv.slice(0, 2), ...userArgs, "tui"]);
|
|
186
|
+
} else {
|
|
187
|
+
program.parse([...process.argv.slice(0, 2), ...userArgs]);
|
|
188
|
+
}
|
package/src/output.ts
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import theme from "./theme";
|
|
2
|
+
|
|
3
|
+
// ── Internal helpers ─────────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
/** Strip ANSI escape codes for accurate visible-length calculation */
|
|
6
|
+
export function visibleLength(str: string): number {
|
|
7
|
+
// eslint-disable-next-line no-control-regex
|
|
8
|
+
return str.replace(/\x1b\[[0-9;]*m/g, "").length;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** padEnd that accounts for invisible ANSI escape codes */
|
|
12
|
+
export function padEndVisible(str: string, len: number): string {
|
|
13
|
+
const diff = len - visibleLength(str);
|
|
14
|
+
return diff > 0 ? str + " ".repeat(diff) : str;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Truncate a string that may contain ANSI codes to a visible width */
|
|
18
|
+
export function truncateAnsi(str: string, maxWidth: number): string {
|
|
19
|
+
let visible = 0;
|
|
20
|
+
let i = 0;
|
|
21
|
+
let result = "";
|
|
22
|
+
|
|
23
|
+
while (i < str.length && visible < maxWidth) {
|
|
24
|
+
// Check for ANSI escape sequence
|
|
25
|
+
if (str[i] === "\x1b" && str[i + 1] === "[") {
|
|
26
|
+
const end = str.indexOf("m", i);
|
|
27
|
+
if (end !== -1) {
|
|
28
|
+
result += str.slice(i, end + 1);
|
|
29
|
+
i = end + 1;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
result += str[i];
|
|
34
|
+
visible++;
|
|
35
|
+
i++;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Reset ANSI at end
|
|
39
|
+
return result + "\x1b[0m";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Terminal width with fallback for piped/non-TTY output */
|
|
43
|
+
function termWidth(): number {
|
|
44
|
+
return process.stdout.columns || 120;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ── JSON output (unchanged) ──────────────────────────────────────
|
|
48
|
+
|
|
49
|
+
export function jsonReplacer(_key: string, value: unknown): unknown {
|
|
50
|
+
if (typeof value === "bigint") return value.toString();
|
|
51
|
+
if (value instanceof Uint8Array) return Buffer.from(value).toString("hex");
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function printJson(data: unknown): void {
|
|
56
|
+
console.log(JSON.stringify(data, jsonReplacer, 2));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ── Section header ───────────────────────────────────────────────
|
|
60
|
+
|
|
61
|
+
export function renderHeader(text: string, width?: number): string[] {
|
|
62
|
+
const w = width ?? termWidth();
|
|
63
|
+
const prefix = "── ";
|
|
64
|
+
const suffix = " ";
|
|
65
|
+
const remaining = w - prefix.length - text.length - suffix.length;
|
|
66
|
+
const rule = remaining > 0 ? "─".repeat(remaining) : "";
|
|
67
|
+
return [
|
|
68
|
+
"",
|
|
69
|
+
`${theme.label(prefix)}${theme.sectionHeader(text)}${theme.label(suffix + rule)}`,
|
|
70
|
+
];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function header(text: string): void {
|
|
74
|
+
for (const line of renderHeader(text)) console.log(line);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ── Key-Value pairs ──────────────────────────────────────────────
|
|
78
|
+
|
|
79
|
+
export function renderKV(pairs: [string, unknown][]): string[] {
|
|
80
|
+
if (pairs.length === 0) return [];
|
|
81
|
+
const maxKeyLen = Math.max(...pairs.map(([k]) => k.length));
|
|
82
|
+
return pairs.map(([key, value]) => {
|
|
83
|
+
const paddedKey = key.padEnd(maxKeyLen);
|
|
84
|
+
return ` ${theme.label(paddedKey)} ${String(value)}`;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function printKV(pairs: [string, unknown][]): void {
|
|
89
|
+
for (const line of renderKV(pairs)) console.log(line);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ── Data table (borderless aligned columns) ──────────────────────
|
|
93
|
+
|
|
94
|
+
export function renderColumns(headers: string[], rows: string[][]): string[] {
|
|
95
|
+
if (rows.length === 0) return [];
|
|
96
|
+
|
|
97
|
+
const colWidths = headers.map((h, i) => {
|
|
98
|
+
const dataMax = rows.reduce((max, row) => Math.max(max, visibleLength(row[i] ?? "")), 0);
|
|
99
|
+
return Math.max(h.length, dataMax);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const gap = 3;
|
|
103
|
+
const lines: string[] = [];
|
|
104
|
+
|
|
105
|
+
const headerLine = headers
|
|
106
|
+
.map((h, i) => padEndVisible(theme.label(h.toUpperCase()), colWidths[i]))
|
|
107
|
+
.join(" ".repeat(gap));
|
|
108
|
+
lines.push(` ${headerLine}`);
|
|
109
|
+
|
|
110
|
+
for (const row of rows) {
|
|
111
|
+
const line = row
|
|
112
|
+
.map((cell, i) => {
|
|
113
|
+
if (i === row.length - 1) return cell;
|
|
114
|
+
return padEndVisible(cell, colWidths[i]);
|
|
115
|
+
})
|
|
116
|
+
.join(" ".repeat(gap));
|
|
117
|
+
lines.push(` ${line}`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return lines;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function printColumns(headers: string[], rows: string[][]): void {
|
|
124
|
+
for (const line of renderColumns(headers, rows)) console.log(line);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ── Multi-column KV (side-by-side fee groups) ────────────────────
|
|
128
|
+
|
|
129
|
+
export interface KVGroup {
|
|
130
|
+
title: string;
|
|
131
|
+
pairs: [string, string][];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function renderMultiColumnKV(groups: KVGroup[], width?: number): string[] {
|
|
135
|
+
if (groups.length === 0) return [];
|
|
136
|
+
|
|
137
|
+
const w = width ?? termWidth();
|
|
138
|
+
const groupGap = 4;
|
|
139
|
+
const indent = 2;
|
|
140
|
+
const lines: string[] = [];
|
|
141
|
+
|
|
142
|
+
let cols: number;
|
|
143
|
+
if (w >= 120) cols = Math.min(3, groups.length);
|
|
144
|
+
else if (w >= 80) cols = Math.min(2, groups.length);
|
|
145
|
+
else cols = 1;
|
|
146
|
+
|
|
147
|
+
for (let i = 0; i < groups.length; i += cols) {
|
|
148
|
+
const chunk = groups.slice(i, i + cols);
|
|
149
|
+
|
|
150
|
+
const groupMetas = chunk.map((g) => {
|
|
151
|
+
const maxKey = Math.max(g.title.length, ...g.pairs.map(([k]) => k.length));
|
|
152
|
+
const maxVal = Math.max(...g.pairs.map(([, v]) => visibleLength(v)), 0);
|
|
153
|
+
return { group: g, keyWidth: maxKey, valWidth: maxVal, totalWidth: maxKey + 2 + maxVal };
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
const titleLine = groupMetas
|
|
157
|
+
.map((m, idx) => {
|
|
158
|
+
const title = theme.label(m.group.title.toUpperCase());
|
|
159
|
+
if (idx === groupMetas.length - 1) return title;
|
|
160
|
+
return padEndVisible(title, m.totalWidth);
|
|
161
|
+
})
|
|
162
|
+
.join(" ".repeat(groupGap));
|
|
163
|
+
lines.push(" ".repeat(indent) + titleLine);
|
|
164
|
+
|
|
165
|
+
const maxRows = Math.max(...groupMetas.map((m) => m.group.pairs.length));
|
|
166
|
+
for (let r = 0; r < maxRows; r++) {
|
|
167
|
+
const parts = groupMetas.map((m, idx) => {
|
|
168
|
+
const pair = m.group.pairs[r];
|
|
169
|
+
if (!pair) {
|
|
170
|
+
if (idx === groupMetas.length - 1) return "";
|
|
171
|
+
return " ".repeat(m.totalWidth);
|
|
172
|
+
}
|
|
173
|
+
const [key, val] = pair;
|
|
174
|
+
const paddedKey = theme.label(key.padEnd(m.keyWidth));
|
|
175
|
+
const paddedVal = padEndVisible(val, m.valWidth);
|
|
176
|
+
if (idx === groupMetas.length - 1) return `${paddedKey} ${val}`;
|
|
177
|
+
return `${paddedKey} ${paddedVal}`;
|
|
178
|
+
});
|
|
179
|
+
const line = parts.join(" ".repeat(groupGap));
|
|
180
|
+
lines.push(" ".repeat(indent) + line);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return lines;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export function printMultiColumnKV(groups: KVGroup[]): void {
|
|
188
|
+
for (const line of renderMultiColumnKV(groups)) console.log(line);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// ── Plugin card (compact inline) ─────────────────────────────────
|
|
192
|
+
|
|
193
|
+
export interface PluginCardOpts {
|
|
194
|
+
name: string;
|
|
195
|
+
pairs: [string, string][];
|
|
196
|
+
methods?: string[];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export function renderPluginCard(opts: PluginCardOpts, width?: number): string[] {
|
|
200
|
+
const w = width ?? termWidth();
|
|
201
|
+
const indentStr = " ";
|
|
202
|
+
const maxLineWidth = w - indentStr.length;
|
|
203
|
+
const sep = " ";
|
|
204
|
+
const lines: string[] = [];
|
|
205
|
+
|
|
206
|
+
lines.push("");
|
|
207
|
+
lines.push(` ${theme.sectionHeader(opts.name)}`);
|
|
208
|
+
|
|
209
|
+
const items = opts.pairs.map(([k, v]) => `${theme.label(k + ":")} ${v}`);
|
|
210
|
+
let current = "";
|
|
211
|
+
|
|
212
|
+
for (const item of items) {
|
|
213
|
+
const candidateLen = current ? visibleLength(current) + sep.length + visibleLength(item) : visibleLength(item);
|
|
214
|
+
if (current && candidateLen > maxLineWidth) {
|
|
215
|
+
lines.push(indentStr + current);
|
|
216
|
+
current = item;
|
|
217
|
+
} else {
|
|
218
|
+
current = current ? current + sep + item : item;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (current) lines.push(indentStr + current);
|
|
222
|
+
|
|
223
|
+
if (opts.methods && opts.methods.length > 0) {
|
|
224
|
+
lines.push(indentStr + theme.label("Methods:") + " " + opts.methods.join(", "));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return lines;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export function printPluginCard(opts: PluginCardOpts): void {
|
|
231
|
+
for (const line of renderPluginCard(opts)) console.log(line);
|
|
232
|
+
}
|
package/src/sdk.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { AlgorandClient } from "@algorandfoundation/algokit-utils/types/algorand-client";
|
|
2
|
+
import { Address, makeEmptyTransactionSigner } from "algosdk";
|
|
3
|
+
import { setCurrentNetwork, type AkitaNetwork, AkitaDaoSDK } from "@akta/sdk";
|
|
4
|
+
|
|
5
|
+
const ALGOD_URLS: Record<AkitaNetwork, string> = {
|
|
6
|
+
mainnet: "https://mainnet-api.algonode.cloud",
|
|
7
|
+
testnet: "https://testnet-api.algonode.cloud",
|
|
8
|
+
localnet: "http://localhost",
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const ALGOD_PORTS: Record<AkitaNetwork, number> = {
|
|
12
|
+
mainnet: 443,
|
|
13
|
+
testnet: 443,
|
|
14
|
+
localnet: 4001,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export function createDAO(network: AkitaNetwork): AkitaDaoSDK {
|
|
18
|
+
setCurrentNetwork(network);
|
|
19
|
+
|
|
20
|
+
const algorand = AlgorandClient.fromConfig({
|
|
21
|
+
algodConfig: {
|
|
22
|
+
server: ALGOD_URLS[network],
|
|
23
|
+
port: ALGOD_PORTS[network],
|
|
24
|
+
token: "",
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const READER = Address.fromString("Y76M3MSY6DKBRHBL7C3NNDXGS5IIMQVQVUAB6MP4XEMMGVF2QWNPL226CA");
|
|
29
|
+
|
|
30
|
+
return new AkitaDaoSDK({
|
|
31
|
+
algorand,
|
|
32
|
+
factoryParams: {
|
|
33
|
+
defaultSender: READER,
|
|
34
|
+
defaultSigner: makeEmptyTransactionSigner(),
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
}
|
package/src/theme.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
|
|
3
|
+
// ── Akita brand palette ──────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
const purple = chalk.hex("#9439e6");
|
|
6
|
+
const pink = chalk.hex("#f35ff2");
|
|
7
|
+
const green = chalk.hex("#44f8bd");
|
|
8
|
+
const gold = chalk.hex("#f5c434");
|
|
9
|
+
const yellow = chalk.hex("#FFEB00");
|
|
10
|
+
const darkBlue = chalk.hex("#0039CB");
|
|
11
|
+
const lightBlue = chalk.hex("#00F0FF");
|
|
12
|
+
|
|
13
|
+
// ── Theme tokens ─────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
const theme = {
|
|
16
|
+
// UI chrome
|
|
17
|
+
border: chalk.dim,
|
|
18
|
+
panelTitle: chalk.bold.hex("#9439e6"),
|
|
19
|
+
appName: chalk.bold.hex("#f35ff2"),
|
|
20
|
+
activeTab: chalk.bgHex("#9439e6").white.bold,
|
|
21
|
+
inactiveTab: chalk.dim,
|
|
22
|
+
tabSeparator: chalk.dim,
|
|
23
|
+
separator: chalk.dim,
|
|
24
|
+
statusBar: chalk.inverse,
|
|
25
|
+
sectionHeader: chalk.bold.hex("#9439e6"),
|
|
26
|
+
|
|
27
|
+
// KV / table labels
|
|
28
|
+
label: chalk.dim,
|
|
29
|
+
|
|
30
|
+
// Selection / navigation
|
|
31
|
+
cursor: pink,
|
|
32
|
+
selected: chalk.bold,
|
|
33
|
+
|
|
34
|
+
// Status colors
|
|
35
|
+
statusApproved: green,
|
|
36
|
+
statusVoting: lightBlue,
|
|
37
|
+
statusDraft: gold,
|
|
38
|
+
statusRejected: chalk.red,
|
|
39
|
+
stateActive: green,
|
|
40
|
+
stateInactive: chalk.red,
|
|
41
|
+
statePaused: gold,
|
|
42
|
+
boolTrue: green,
|
|
43
|
+
boolFalse: chalk.dim,
|
|
44
|
+
|
|
45
|
+
// Proposal action colors
|
|
46
|
+
actionAdd: green,
|
|
47
|
+
actionRemove: chalk.red,
|
|
48
|
+
actionModify: gold,
|
|
49
|
+
|
|
50
|
+
// Escrow status
|
|
51
|
+
locked: chalk.red,
|
|
52
|
+
unlocked: green,
|
|
53
|
+
|
|
54
|
+
// Compact number suffixes
|
|
55
|
+
suffixK: chalk.bold.white,
|
|
56
|
+
suffixM: green,
|
|
57
|
+
suffixB: lightBlue,
|
|
58
|
+
suffixT: purple,
|
|
59
|
+
|
|
60
|
+
// Charts
|
|
61
|
+
barFilled: lightBlue,
|
|
62
|
+
barEmpty: chalk.dim,
|
|
63
|
+
chartLabel: chalk.bold,
|
|
64
|
+
chartDim: chalk.dim,
|
|
65
|
+
|
|
66
|
+
// Revenue split segment palette (cycled)
|
|
67
|
+
splitColors: [purple, pink, green, gold, lightBlue, darkBlue, yellow],
|
|
68
|
+
|
|
69
|
+
// Global caller
|
|
70
|
+
globalCaller: green,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export default theme;
|