@aiaiai-pt/manda-cli 0.0.0-stage → 0.1.1

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.
@@ -0,0 +1,16 @@
1
+ export interface Config {
2
+ url: string;
3
+ token: string;
4
+ }
5
+ export interface ResolvedConfig extends Config {
6
+ source: "env" | "flags" | "file";
7
+ }
8
+ export declare function loadConfigFile(): {
9
+ url?: string;
10
+ token?: string;
11
+ } | null;
12
+ export declare function saveConfigFile(url: string, token: string): void;
13
+ export declare function resolveConfig(flags: {
14
+ url?: string;
15
+ token?: string;
16
+ }): ResolvedConfig | null;
package/dist/config.js ADDED
@@ -0,0 +1,64 @@
1
+ import { readFileSync, writeFileSync, mkdirSync, chmodSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { homedir } from "node:os";
4
+ const DEFAULT_URL = "https://manda.aiaiai.pt";
5
+ function configDir() {
6
+ const xdg = process.env["XDG_CONFIG_HOME"];
7
+ return join(xdg || join(homedir(), ".config"), "manda");
8
+ }
9
+ function configPath() {
10
+ return join(configDir(), "config.json");
11
+ }
12
+ export function loadConfigFile() {
13
+ try {
14
+ const raw = readFileSync(configPath(), "utf8");
15
+ return JSON.parse(raw);
16
+ }
17
+ catch {
18
+ return null;
19
+ }
20
+ }
21
+ export function saveConfigFile(url, token) {
22
+ const dir = configDir();
23
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
24
+ const path = configPath();
25
+ writeFileSync(path, JSON.stringify({ url, token }, null, 2) + "\n", {
26
+ mode: 0o600,
27
+ });
28
+ // Ensure mode even if file existed
29
+ chmodSync(path, 0o600);
30
+ }
31
+ export function resolveConfig(flags) {
32
+ // Flags win over everything
33
+ if (flags.url && flags.token) {
34
+ return { url: flags.url, token: flags.token, source: "flags" };
35
+ }
36
+ // Env wins over file
37
+ const envToken = process.env["MANDA_TOKEN"];
38
+ const envUrl = process.env["MANDA_URL"];
39
+ if (envToken) {
40
+ return {
41
+ url: flags.url || envUrl || DEFAULT_URL,
42
+ token: flags.token || envToken,
43
+ source: flags.url || flags.token ? "flags" : "env",
44
+ };
45
+ }
46
+ // File
47
+ const file = loadConfigFile();
48
+ if (file?.token) {
49
+ return {
50
+ url: flags.url || file.url || DEFAULT_URL,
51
+ token: flags.token || file.token,
52
+ source: flags.url || flags.token ? "flags" : "file",
53
+ };
54
+ }
55
+ // Flag-only partial: token from flags, url from anywhere
56
+ if (flags.token) {
57
+ return {
58
+ url: flags.url || envUrl || DEFAULT_URL,
59
+ token: flags.token,
60
+ source: "flags",
61
+ };
62
+ }
63
+ return null;
64
+ }
@@ -0,0 +1,12 @@
1
+ export declare function isJsonMode(flags: {
2
+ json?: boolean;
3
+ }): boolean;
4
+ export declare function printJson(data: unknown): void;
5
+ export declare function printError(status: number, message: string, exit: number, current?: unknown): void;
6
+ export declare function printTable(rows: Record<string, unknown>[], columns: {
7
+ key: string;
8
+ label: string;
9
+ width?: number;
10
+ }[]): void;
11
+ export declare function printKeyValue(pairs: [string, unknown][]): void;
12
+ export declare function readStdin(): Promise<string>;
package/dist/output.js ADDED
@@ -0,0 +1,48 @@
1
+ import { styleText } from "node:util";
2
+ export function isJsonMode(flags) {
3
+ return flags.json === true || !process.stdout.isTTY;
4
+ }
5
+ export function printJson(data) {
6
+ process.stdout.write(JSON.stringify(data, null, 2) + "\n");
7
+ }
8
+ export function printError(status, message, exit, current) {
9
+ const obj = { error: { status, message, exit } };
10
+ if (current !== undefined) {
11
+ obj.error.current = current;
12
+ }
13
+ process.stderr.write(JSON.stringify(obj) + "\n");
14
+ }
15
+ export function printTable(rows, columns) {
16
+ if (rows.length === 0) {
17
+ process.stdout.write("(none)\n");
18
+ return;
19
+ }
20
+ const widths = columns.map((col) => {
21
+ const values = rows.map((r) => String(r[col.key] ?? ""));
22
+ return (col.width ?? Math.max(col.label.length, ...values.map((v) => v.length)));
23
+ });
24
+ const header = columns
25
+ .map((col, i) => col.label.padEnd(widths[i]))
26
+ .join(" ");
27
+ process.stdout.write(styleText("bold", header) + "\n");
28
+ for (const row of rows) {
29
+ const line = columns
30
+ .map((col, i) => String(row[col.key] ?? "").padEnd(widths[i]))
31
+ .join(" ");
32
+ process.stdout.write(line + "\n");
33
+ }
34
+ }
35
+ export function printKeyValue(pairs) {
36
+ const maxKey = Math.max(...pairs.map(([k]) => k.length));
37
+ for (const [key, value] of pairs) {
38
+ process.stdout.write(`${styleText("bold", key.padEnd(maxKey))} ${value}\n`);
39
+ }
40
+ }
41
+ export function readStdin() {
42
+ return new Promise((resolve, reject) => {
43
+ const chunks = [];
44
+ process.stdin.on("data", (chunk) => chunks.push(chunk));
45
+ process.stdin.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
46
+ process.stdin.on("error", reject);
47
+ });
48
+ }
package/package.json CHANGED
@@ -1,6 +1,34 @@
1
1
  {
2
2
  "name": "@aiaiai-pt/manda-cli",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.1",
4
+ "description": "CLI for the Manda feedback service",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/aiaiai-pt/manda.git",
10
+ "directory": "packages/cli"
11
+ },
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "engines": {
16
+ "node": ">=22"
17
+ },
18
+ "bin": {
19
+ "manda": "dist/bin.js"
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "README.md"
24
+ ],
25
+ "scripts": {
26
+ "build": "tsc",
27
+ "test": "vitest run"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^22.0.0",
31
+ "typescript": "^5.7.0",
32
+ "vitest": "^2.1.0"
33
+ }
34
+ }