@akta/dao-cli 0.1.1 → 0.1.2

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.
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akta/dao-cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Read-only CLI and TUI for querying Akita DAO state on Algorand",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,7 +8,8 @@
8
8
  },
9
9
  "scripts": {
10
10
  "start": "bun run src/index.ts",
11
- "typecheck": "tsc --noEmit"
11
+ "typecheck": "tsc --noEmit",
12
+ "style-screenshots": "bun run scripts/style-screenshots.ts"
12
13
  },
13
14
  "dependencies": {
14
15
  "@akta/sdk": "0.0.1",
@@ -9,13 +9,32 @@ import {
9
9
  formatBigInt,
10
10
  daoStateLabel,
11
11
  resolveAppName,
12
+ getAppName,
12
13
  colorState,
13
14
  } from "../formatting";
14
15
 
15
16
  export async function stateCommand(dao: AkitaDaoSDK, network: AkitaNetwork, json: boolean): Promise<void> {
16
17
  const state = await dao.getGlobalState();
17
18
 
18
- if (json) return printJson(state);
19
+ if (json) {
20
+ let pluginProposalSettings: { plugin: bigint; pluginName: string; account: string; fee: bigint; power: bigint; duration: bigint; participation: bigint; approval: bigint }[] = [];
21
+ try {
22
+ const pluginsMap = await dao.client.state.box.plugins.getMap();
23
+ pluginProposalSettings = [...pluginsMap.entries()].map(([key, ps]) => ({
24
+ plugin: key.plugin,
25
+ pluginName: (getAppName(key.plugin, network) ?? key.plugin.toString()).replace(/ Plugin$/, ""),
26
+ account: key.escrow || "Main",
27
+ fee: ps.fee,
28
+ power: ps.power,
29
+ duration: ps.duration,
30
+ participation: ps.participation,
31
+ approval: ps.approval,
32
+ }));
33
+ } catch {
34
+ // Box may be empty or inaccessible
35
+ }
36
+ return printJson({ ...state, pluginProposalSettings });
37
+ }
19
38
 
20
39
  header("Core Settings");
21
40
  printKV([
@@ -38,6 +57,7 @@ export async function stateCommand(dao: AkitaDaoSDK, network: AkitaNetwork, json
38
57
  printAppLists(state, network);
39
58
  printFees(state);
40
59
  printProposalSettings(state);
60
+ await printPluginProposalSettings(dao, network);
41
61
  printRevenueSplits(state, network);
42
62
  }
43
63
 
@@ -152,6 +172,31 @@ function printProposalSettings(state: Partial<AkitaDaoGlobalState>): void {
152
172
  printColumns(["Category", "Fee", "Power", "Duration", "Participation", "Approval"], rows);
153
173
  }
154
174
 
175
+ async function printPluginProposalSettings(dao: AkitaDaoSDK, network: AkitaNetwork): Promise<void> {
176
+ let pluginsMap: Map<{ plugin: bigint; escrow: string }, { fee: bigint; power: bigint; duration: bigint; participation: bigint; approval: bigint }>;
177
+ try {
178
+ pluginsMap = await dao.client.state.box.plugins.getMap();
179
+ } catch {
180
+ return;
181
+ }
182
+ if (pluginsMap.size === 0) return;
183
+
184
+ header("Plugin Proposal Settings");
185
+ const rows = [...pluginsMap.entries()].map(([key, ps]) => {
186
+ const name = (getAppName(key.plugin, network) ?? key.plugin.toString()).replace(/ Plugin$/, "");
187
+ return [
188
+ name,
189
+ key.escrow || "Main",
190
+ formatMicroAlgo(ps.fee),
191
+ formatBigInt(ps.power),
192
+ formatDuration(ps.duration),
193
+ formatBasisPoints(ps.participation),
194
+ formatBasisPoints(ps.approval),
195
+ ];
196
+ });
197
+ printColumns(["Plugin", "Account", "Fee", "Power", "Duration", "Participation", "Approval"], rows);
198
+ }
199
+
155
200
  function printRevenueSplits(state: Partial<AkitaDaoGlobalState>, network: AkitaNetwork): void {
156
201
  if (!state.revenueSplits || state.revenueSplits.length === 0) return;
157
202
 
@@ -16,6 +16,9 @@ import {
16
16
  } from "../../formatting";
17
17
  import { renderPanel, renderPanelGrid, splitWidth } from "../panels";
18
18
  import type { LoadResult, View, ViewContext } from "../types";
19
+ import type { AkitaDaoSDK } from "@akta/sdk/dao";
20
+
21
+ type PluginsMap = Awaited<ReturnType<AkitaDaoSDK["client"]["state"]["box"]["plugins"]["getMap"]>>;
19
22
 
20
23
  export const daoView: View = {
21
24
  async load(ctx: ViewContext): Promise<LoadResult> {
@@ -23,6 +26,15 @@ export const daoView: View = {
23
26
  const state = await dao.getGlobalState();
24
27
  const ids = getNetworkAppIds(network);
25
28
 
29
+ // Fetch per-plugin proposal settings from box storage
30
+ let pluginsMap: PluginsMap | null = null;
31
+ try {
32
+ pluginsMap = await dao.client.state.box.plugins.getMap();
33
+ if (pluginsMap.size === 0) pluginsMap = null;
34
+ } catch {
35
+ // Box may be empty or inaccessible
36
+ }
37
+
26
38
  // Fetch supply data for AKTA & BONES
27
39
  let aktaSupply: SupplyInfo | null = null;
28
40
  let bonesSupply: SupplyInfo | null = null;
@@ -54,11 +66,11 @@ export const daoView: View = {
54
66
  }
55
67
 
56
68
  // Build structured data for JSON mode
57
- const data = buildDaoData(state, network, ids, dao.appId, aktaSupply, bonesSupply);
69
+ const data = buildDaoData(state, network, ids, dao.appId, aktaSupply, bonesSupply, pluginsMap);
58
70
 
59
71
  let lines: string[];
60
72
  if (width < 80) {
61
- lines = renderSingleColumn(state, network, ids, width, aktaSupply, bonesSupply);
73
+ lines = renderSingleColumn(state, network, ids, width, aktaSupply, bonesSupply, pluginsMap);
62
74
  } else {
63
75
  const gridRows: string[][][] = [];
64
76
 
@@ -108,11 +120,16 @@ export const daoView: View = {
108
120
  ? renderPanel(appLines, { title: "App IDs", width: appW })
109
121
  : renderPanel([" No app ID data"], { title: "App IDs", width: appW });
110
122
 
111
- // Stack Proposal Settings + Revenue Splits into one right column
123
+ // Stack Proposal Settings + Plugin Proposal Settings + Revenue Splits into one right column
112
124
  const rightPanels: string[] = [];
113
125
  if (proposalLines.length > 0) {
114
126
  rightPanels.push(...renderPanel(proposalLines, { title: "Proposal Settings", width: rightPanelW }));
115
127
  }
128
+ const pluginPsLines = renderPluginProposalSettings(pluginsMap, network);
129
+ if (pluginPsLines.length > 0) {
130
+ if (rightPanels.length > 0) rightPanels.push("");
131
+ rightPanels.push(...renderPanel(pluginPsLines, { title: "Plugin Proposal Settings", width: rightPanelW }));
132
+ }
116
133
  if (revLines.length > 0) {
117
134
  if (rightPanels.length > 0) rightPanels.push("");
118
135
  rightPanels.push(...renderPanel(revLines, { title: "Revenue Splits", width: rightPanelW }));
@@ -140,6 +157,7 @@ function renderSingleColumn(
140
157
  width: number,
141
158
  aktaSupply: SupplyInfo | null,
142
159
  bonesSupply: SupplyInfo | null,
160
+ pluginsMap: PluginsMap | null,
143
161
  ): string[] {
144
162
  const lines: string[] = [""];
145
163
 
@@ -173,6 +191,12 @@ function renderSingleColumn(
173
191
  lines.push(...renderPanel(proposalLines, { title: "Proposal Settings", width }));
174
192
  }
175
193
 
194
+ const pluginPsLines = renderPluginProposalSettings(pluginsMap, network);
195
+ if (pluginPsLines.length > 0) {
196
+ lines.push("");
197
+ lines.push(...renderPanel(pluginPsLines, { title: "Plugin Proposal Settings", width }));
198
+ }
199
+
176
200
  const revLines = renderRevenueSplits(state, network, width - 4);
177
201
  if (revLines.length > 0) {
178
202
  lines.push("");
@@ -191,6 +215,7 @@ function buildDaoData(
191
215
  appId: bigint,
192
216
  aktaSupply: SupplyInfo | null,
193
217
  bonesSupply: SupplyInfo | null,
218
+ pluginsMap: PluginsMap | null,
194
219
  ) {
195
220
  // App ID lists
196
221
  const appSections: [string, Record<string, bigint> | undefined][] = [
@@ -255,6 +280,16 @@ function buildDaoData(
255
280
  tokenSupply,
256
281
  apps,
257
282
  proposalSettings,
283
+ pluginProposalSettings: pluginsMap ? [...pluginsMap.entries()].map(([key, ps]) => ({
284
+ plugin: key.plugin,
285
+ pluginName: (getAppName(key.plugin, network) ?? key.plugin.toString()).replace(/ Plugin$/, ""),
286
+ account: key.escrow || "Main",
287
+ fee: ps.fee,
288
+ power: ps.power,
289
+ duration: ps.duration,
290
+ participation: ps.participation,
291
+ approval: ps.approval,
292
+ })) : [],
258
293
  revenueSplits,
259
294
  };
260
295
  }
@@ -312,6 +347,25 @@ function renderProposalSettings(state: Partial<AkitaDaoGlobalState>): string[] {
312
347
  return renderColumns(["Cat", "Fee", "Pwr", "Dur", "Part", "Appr"], rows);
313
348
  }
314
349
 
350
+ function renderPluginProposalSettings(pluginsMap: PluginsMap | null, network: AkitaNetwork): string[] {
351
+ if (!pluginsMap || pluginsMap.size === 0) return [];
352
+
353
+ const rows = [...pluginsMap.entries()].map(([key, ps]) => {
354
+ const name = (getAppName(key.plugin, network) ?? key.plugin.toString()).replace(/ Plugin$/, "");
355
+ return [
356
+ name,
357
+ key.escrow || "Main",
358
+ formatMicroAlgo(ps.fee),
359
+ formatBigInt(ps.power),
360
+ formatDuration(ps.duration),
361
+ inlineBar(ps.participation),
362
+ inlineBar(ps.approval),
363
+ ];
364
+ });
365
+
366
+ return renderColumns(["Plugin", "Account", "Fee", "Pwr", "Dur", "Part", "Appr"], rows);
367
+ }
368
+
315
369
  const SPLIT_COLORS = theme.splitColors;
316
370
 
317
371
  function renderRevenueSplits(state: Partial<AkitaDaoGlobalState>, network: AkitaNetwork, barWidth: number): string[] {
@@ -376,7 +430,7 @@ function renderRevenueSplits(state: Partial<AkitaDaoGlobalState>, network: Akita
376
430
 
377
431
  // ── Inline bar for basis-point percentages ─────────────────────
378
432
 
379
- const INLINE_BAR_WIDTH = 8;
433
+ const INLINE_BAR_WIDTH = 10;
380
434
 
381
435
  function inlineBar(bp: bigint): string {
382
436
  const pct = Number(bp) / 1000;