mirror of
https://github.com/profullstack/logicsrc.git
synced 2026-10-02 04:43:58 +00:00
Every secret now has a category derived from its name (db, social, server,
api, cloud, finance, crypto, ai, email, messaging, storage, dns, analytics,
devtools, auth, config, other). One rule table in @logicsrc/opencreds serves
both vaults; services win over generic words, so STRIPE_WEBHOOK_SECRET is
finance, not auth. Checked against the 1,208 distinct key names in the
profullstack team: 74 fall to "other".
Team vaults (where the shared .env secrets live):
- teams categories [team] the filter words, with per-category counts
- teams secrets <team> [project] [env] --category/-c --search/-s
names + categories, never decrypts; --format csv
- teams export <team> [project] [env] --category -o file.csv [--yes]
decrypts into team,project,env,category,key,
value,updated_at (0600); skips vaults without a
grant and names them
Personal vault (OpenCreds):
- vault list --category, and the category column in list output
- vault export --format csv: one flat row per item, keeps key/account
secrets that a Bitwarden CSV drops; --category on every export format
DX:
- examples in `logicsrc vault help` / -h / --help that start by saying which
of the two vaults you want, plus examples on teams and each subcommand
- password prompts go to stderr, so eval "$(logicsrc vault unlock)" works
- hints name the command you actually ran (logicsrc vault init, not
opencreds init)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
37 lines
1.3 KiB
TypeScript
37 lines
1.3 KiB
TypeScript
export type OutputFormat = "json" | "table" | "markdown";
|
|
|
|
export function print(data: unknown, format: OutputFormat) {
|
|
if (format === "json") {
|
|
console.log(JSON.stringify(data, null, 2));
|
|
return;
|
|
}
|
|
|
|
if (format === "markdown") {
|
|
if (Array.isArray(data)) {
|
|
for (const item of data) {
|
|
console.log(`- ${Object.entries(item as Record<string, unknown>).map(([key, value]) => `**${key}:** ${String(value)}`).join(", ")}`);
|
|
}
|
|
return;
|
|
}
|
|
|
|
console.log(Object.entries(data as Record<string, unknown>).map(([key, value]) => `**${key}:** ${String(value)}`).join("\n"));
|
|
return;
|
|
}
|
|
|
|
console.table(data);
|
|
}
|
|
|
|
/**
|
|
* A plain, aligned table: no index column, no quotes, no colour. Easier to read
|
|
* than console.table and pipes cleanly into grep, sort and awk.
|
|
*/
|
|
export function printColumns(rows: Array<Record<string, unknown>>): void {
|
|
if (rows.length === 0) return;
|
|
const headers = Object.keys(rows[0]!);
|
|
const cells = rows.map((row) => headers.map((h) => String(row[h] ?? "")));
|
|
const widths = headers.map((h, i) => Math.max(h.length, ...cells.map((c) => c[i]!.length)));
|
|
const line = (values: string[]) =>
|
|
values.map((v, i) => (i === values.length - 1 ? v : v.padEnd(widths[i]!))).join(" ").trimEnd();
|
|
console.log(line(headers.map((h) => h.toUpperCase())));
|
|
for (const c of cells) console.log(line(c));
|
|
}
|