@lifestreamdynamics/vault-cli 1.0.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.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +759 -0
  3. package/dist/client.d.ts +12 -0
  4. package/dist/client.js +79 -0
  5. package/dist/commands/admin.d.ts +2 -0
  6. package/dist/commands/admin.js +263 -0
  7. package/dist/commands/audit.d.ts +2 -0
  8. package/dist/commands/audit.js +119 -0
  9. package/dist/commands/auth.d.ts +2 -0
  10. package/dist/commands/auth.js +256 -0
  11. package/dist/commands/config.d.ts +2 -0
  12. package/dist/commands/config.js +130 -0
  13. package/dist/commands/connectors.d.ts +2 -0
  14. package/dist/commands/connectors.js +224 -0
  15. package/dist/commands/docs.d.ts +2 -0
  16. package/dist/commands/docs.js +194 -0
  17. package/dist/commands/hooks.d.ts +2 -0
  18. package/dist/commands/hooks.js +159 -0
  19. package/dist/commands/keys.d.ts +2 -0
  20. package/dist/commands/keys.js +165 -0
  21. package/dist/commands/publish.d.ts +2 -0
  22. package/dist/commands/publish.js +138 -0
  23. package/dist/commands/search.d.ts +2 -0
  24. package/dist/commands/search.js +61 -0
  25. package/dist/commands/shares.d.ts +2 -0
  26. package/dist/commands/shares.js +121 -0
  27. package/dist/commands/subscription.d.ts +2 -0
  28. package/dist/commands/subscription.js +166 -0
  29. package/dist/commands/sync.d.ts +2 -0
  30. package/dist/commands/sync.js +565 -0
  31. package/dist/commands/teams.d.ts +2 -0
  32. package/dist/commands/teams.js +322 -0
  33. package/dist/commands/user.d.ts +2 -0
  34. package/dist/commands/user.js +48 -0
  35. package/dist/commands/vaults.d.ts +2 -0
  36. package/dist/commands/vaults.js +157 -0
  37. package/dist/commands/versions.d.ts +2 -0
  38. package/dist/commands/versions.js +219 -0
  39. package/dist/commands/webhooks.d.ts +2 -0
  40. package/dist/commands/webhooks.js +181 -0
  41. package/dist/config.d.ts +24 -0
  42. package/dist/config.js +88 -0
  43. package/dist/index.d.ts +2 -0
  44. package/dist/index.js +63 -0
  45. package/dist/lib/credential-manager.d.ts +48 -0
  46. package/dist/lib/credential-manager.js +101 -0
  47. package/dist/lib/encrypted-config.d.ts +20 -0
  48. package/dist/lib/encrypted-config.js +102 -0
  49. package/dist/lib/keychain.d.ts +8 -0
  50. package/dist/lib/keychain.js +82 -0
  51. package/dist/lib/migration.d.ts +31 -0
  52. package/dist/lib/migration.js +92 -0
  53. package/dist/lib/profiles.d.ts +43 -0
  54. package/dist/lib/profiles.js +104 -0
  55. package/dist/sync/config.d.ts +32 -0
  56. package/dist/sync/config.js +100 -0
  57. package/dist/sync/conflict.d.ts +30 -0
  58. package/dist/sync/conflict.js +60 -0
  59. package/dist/sync/daemon-worker.d.ts +1 -0
  60. package/dist/sync/daemon-worker.js +128 -0
  61. package/dist/sync/daemon.d.ts +44 -0
  62. package/dist/sync/daemon.js +174 -0
  63. package/dist/sync/diff.d.ts +43 -0
  64. package/dist/sync/diff.js +166 -0
  65. package/dist/sync/engine.d.ts +41 -0
  66. package/dist/sync/engine.js +233 -0
  67. package/dist/sync/ignore.d.ts +16 -0
  68. package/dist/sync/ignore.js +72 -0
  69. package/dist/sync/remote-poller.d.ts +23 -0
  70. package/dist/sync/remote-poller.js +145 -0
  71. package/dist/sync/state.d.ts +32 -0
  72. package/dist/sync/state.js +98 -0
  73. package/dist/sync/types.d.ts +68 -0
  74. package/dist/sync/types.js +4 -0
  75. package/dist/sync/watcher.d.ts +23 -0
  76. package/dist/sync/watcher.js +207 -0
  77. package/dist/utils/flags.d.ts +18 -0
  78. package/dist/utils/flags.js +31 -0
  79. package/dist/utils/format.d.ts +2 -0
  80. package/dist/utils/format.js +22 -0
  81. package/dist/utils/output.d.ts +87 -0
  82. package/dist/utils/output.js +229 -0
  83. package/package.json +62 -0
@@ -0,0 +1,87 @@
1
+ import type { GlobalFlags } from './flags.js';
2
+ /**
3
+ * Column definition for table output.
4
+ */
5
+ export interface TableColumn {
6
+ key: string;
7
+ header: string;
8
+ width?: number;
9
+ }
10
+ /**
11
+ * Output helper that centralizes formatting for text, json, and table modes.
12
+ * Status messages go to stderr so stdout stays clean for piping.
13
+ */
14
+ export declare class Output {
15
+ private flags;
16
+ private spinner;
17
+ constructor(flags: GlobalFlags);
18
+ /**
19
+ * Start a spinner (only shown in text mode, non-quiet, TTY).
20
+ */
21
+ startSpinner(message: string): void;
22
+ /**
23
+ * Stop the spinner without a status symbol.
24
+ */
25
+ stopSpinner(): void;
26
+ /**
27
+ * Stop the spinner with a success message.
28
+ */
29
+ succeedSpinner(message: string): void;
30
+ /**
31
+ * Stop the spinner with a failure message.
32
+ */
33
+ failSpinner(message: string): void;
34
+ /**
35
+ * Print a status/info message to stderr (never captured by piping).
36
+ */
37
+ status(message: string): void;
38
+ /**
39
+ * Print a verbose/debug message to stderr.
40
+ */
41
+ debug(message: string): void;
42
+ /**
43
+ * Print an error message to stderr.
44
+ */
45
+ error(message: string): void;
46
+ /**
47
+ * Print a warning message to stderr.
48
+ */
49
+ warn(message: string): void;
50
+ /**
51
+ * Output a single record based on the format.
52
+ * - text: prints key-value lines
53
+ * - json: prints a single JSON object
54
+ * - table: prints a single-row table
55
+ */
56
+ record(data: Record<string, unknown>, columns?: TableColumn[]): void;
57
+ /**
58
+ * Output a list of records based on the format.
59
+ * - text: prints each item using textFn, or key-value pairs
60
+ * - json: prints one JSON object per line (JSON Lines)
61
+ * - table: prints an ASCII table
62
+ */
63
+ list(data: Record<string, unknown>[], options?: {
64
+ columns?: TableColumn[];
65
+ textFn?: (item: Record<string, unknown>) => string;
66
+ emptyMessage?: string;
67
+ }): void;
68
+ /**
69
+ * Output raw content to stdout (for piping document content, etc.).
70
+ */
71
+ raw(content: string): void;
72
+ /**
73
+ * Print a success result (used for create/update/delete confirmations).
74
+ */
75
+ success(message: string, data?: Record<string, unknown>): void;
76
+ private printKeyValue;
77
+ private table;
78
+ }
79
+ /**
80
+ * Create an Output instance from global flags.
81
+ */
82
+ export declare function createOutput(flags: GlobalFlags): Output;
83
+ /**
84
+ * Standard error handler for commands.
85
+ * Prints error to stderr and sets exit code.
86
+ */
87
+ export declare function handleError(out: Output, err: unknown, spinnerMessage?: string): void;
@@ -0,0 +1,229 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ /**
4
+ * Output helper that centralizes formatting for text, json, and table modes.
5
+ * Status messages go to stderr so stdout stays clean for piping.
6
+ */
7
+ export class Output {
8
+ flags;
9
+ spinner = null;
10
+ constructor(flags) {
11
+ this.flags = flags;
12
+ }
13
+ /**
14
+ * Start a spinner (only shown in text mode, non-quiet, TTY).
15
+ */
16
+ startSpinner(message) {
17
+ if (this.flags.output === 'text' && !this.flags.quiet && process.stderr.isTTY) {
18
+ this.spinner = ora({ text: message, stream: process.stderr }).start();
19
+ }
20
+ }
21
+ /**
22
+ * Stop the spinner without a status symbol.
23
+ */
24
+ stopSpinner() {
25
+ this.spinner?.stop();
26
+ this.spinner = null;
27
+ }
28
+ /**
29
+ * Stop the spinner with a success message.
30
+ */
31
+ succeedSpinner(message) {
32
+ if (this.spinner) {
33
+ this.spinner.succeed(message);
34
+ this.spinner = null;
35
+ }
36
+ else if (this.flags.output === 'text' && !this.flags.quiet) {
37
+ process.stderr.write(chalk.green('✓') + ' ' + message + '\n');
38
+ }
39
+ }
40
+ /**
41
+ * Stop the spinner with a failure message.
42
+ */
43
+ failSpinner(message) {
44
+ if (this.spinner) {
45
+ this.spinner.fail(message);
46
+ this.spinner = null;
47
+ }
48
+ else {
49
+ process.stderr.write(chalk.red('✖') + ' ' + message + '\n');
50
+ }
51
+ }
52
+ /**
53
+ * Print a status/info message to stderr (never captured by piping).
54
+ */
55
+ status(message) {
56
+ if (!this.flags.quiet) {
57
+ process.stderr.write(message + '\n');
58
+ }
59
+ }
60
+ /**
61
+ * Print a verbose/debug message to stderr.
62
+ */
63
+ debug(message) {
64
+ if (this.flags.verbose) {
65
+ process.stderr.write(chalk.dim('[debug] ' + message) + '\n');
66
+ }
67
+ }
68
+ /**
69
+ * Print an error message to stderr.
70
+ */
71
+ error(message) {
72
+ process.stderr.write(chalk.red(message) + '\n');
73
+ }
74
+ /**
75
+ * Print a warning message to stderr.
76
+ */
77
+ warn(message) {
78
+ if (!this.flags.quiet) {
79
+ process.stderr.write(chalk.yellow(message) + '\n');
80
+ }
81
+ }
82
+ /**
83
+ * Output a single record based on the format.
84
+ * - text: prints key-value lines
85
+ * - json: prints a single JSON object
86
+ * - table: prints a single-row table
87
+ */
88
+ record(data, columns) {
89
+ switch (this.flags.output) {
90
+ case 'json':
91
+ process.stdout.write(JSON.stringify(data) + '\n');
92
+ break;
93
+ case 'table':
94
+ this.table([data], columns);
95
+ break;
96
+ case 'text':
97
+ default:
98
+ this.printKeyValue(data);
99
+ break;
100
+ }
101
+ }
102
+ /**
103
+ * Output a list of records based on the format.
104
+ * - text: prints each item using textFn, or key-value pairs
105
+ * - json: prints one JSON object per line (JSON Lines)
106
+ * - table: prints an ASCII table
107
+ */
108
+ list(data, options) {
109
+ if (data.length === 0) {
110
+ if (this.flags.output === 'json') {
111
+ // empty json array: no output
112
+ return;
113
+ }
114
+ if (options?.emptyMessage && !this.flags.quiet) {
115
+ this.status(options.emptyMessage);
116
+ }
117
+ return;
118
+ }
119
+ switch (this.flags.output) {
120
+ case 'json':
121
+ for (const item of data) {
122
+ process.stdout.write(JSON.stringify(item) + '\n');
123
+ }
124
+ break;
125
+ case 'table':
126
+ this.table(data, options?.columns);
127
+ break;
128
+ case 'text':
129
+ default:
130
+ if (options?.textFn) {
131
+ for (const item of data) {
132
+ process.stdout.write(options.textFn(item) + '\n');
133
+ }
134
+ }
135
+ else {
136
+ for (const item of data) {
137
+ this.printKeyValue(item);
138
+ process.stdout.write('\n');
139
+ }
140
+ }
141
+ break;
142
+ }
143
+ }
144
+ /**
145
+ * Output raw content to stdout (for piping document content, etc.).
146
+ */
147
+ raw(content) {
148
+ process.stdout.write(content);
149
+ }
150
+ /**
151
+ * Print a success result (used for create/update/delete confirmations).
152
+ */
153
+ success(message, data) {
154
+ if (this.flags.output === 'json' && data) {
155
+ process.stdout.write(JSON.stringify(data) + '\n');
156
+ }
157
+ else if (!this.flags.quiet) {
158
+ this.succeedSpinner(message);
159
+ if (data && this.flags.output === 'text') {
160
+ this.printKeyValue(data);
161
+ }
162
+ }
163
+ }
164
+ printKeyValue(data) {
165
+ const maxKeyLen = Math.max(...Object.keys(data).map(k => k.length));
166
+ for (const [key, value] of Object.entries(data)) {
167
+ const label = key.charAt(0).toUpperCase() + key.slice(1);
168
+ const padding = ' '.repeat(Math.max(0, maxKeyLen - key.length + 1));
169
+ const displayValue = value === null || value === undefined
170
+ ? chalk.dim('none')
171
+ : String(value);
172
+ process.stdout.write(`${label}:${padding}${displayValue}\n`);
173
+ }
174
+ }
175
+ table(data, columns) {
176
+ if (data.length === 0)
177
+ return;
178
+ const cols = columns ?? Object.keys(data[0]).map(key => ({
179
+ key,
180
+ header: key.charAt(0).toUpperCase() + key.slice(1),
181
+ }));
182
+ // Calculate column widths
183
+ const widths = cols.map(col => {
184
+ const headerLen = col.header.length;
185
+ const maxDataLen = Math.max(...data.map(row => String(row[col.key] ?? '').length), 0);
186
+ return col.width ?? Math.max(headerLen, maxDataLen);
187
+ });
188
+ const separator = '─';
189
+ const corner = {
190
+ tl: '┌', tr: '┐', bl: '└', br: '┘',
191
+ ml: '├', mr: '┤', t: '┬', b: '┴', m: '┼',
192
+ };
193
+ // Top border
194
+ const topBorder = corner.tl + widths.map(w => separator.repeat(w + 2)).join(corner.t) + corner.tr;
195
+ process.stdout.write(topBorder + '\n');
196
+ // Header row
197
+ const headerRow = '│' + cols.map((col, i) => ' ' + col.header.padEnd(widths[i]) + ' ').join('│') + '│';
198
+ process.stdout.write(headerRow + '\n');
199
+ // Header separator
200
+ const headerSep = corner.ml + widths.map(w => separator.repeat(w + 2)).join(corner.m) + corner.mr;
201
+ process.stdout.write(headerSep + '\n');
202
+ // Data rows
203
+ for (const row of data) {
204
+ const dataRow = '│' + cols.map((col, i) => ' ' + String(row[col.key] ?? '').padEnd(widths[i]) + ' ').join('│') + '│';
205
+ process.stdout.write(dataRow + '\n');
206
+ }
207
+ // Bottom border
208
+ const bottomBorder = corner.bl + widths.map(w => separator.repeat(w + 2)).join(corner.b) + corner.br;
209
+ process.stdout.write(bottomBorder + '\n');
210
+ }
211
+ }
212
+ /**
213
+ * Create an Output instance from global flags.
214
+ */
215
+ export function createOutput(flags) {
216
+ return new Output(flags);
217
+ }
218
+ /**
219
+ * Standard error handler for commands.
220
+ * Prints error to stderr and sets exit code.
221
+ */
222
+ export function handleError(out, err, spinnerMessage) {
223
+ if (spinnerMessage) {
224
+ out.failSpinner(spinnerMessage);
225
+ }
226
+ const message = err instanceof Error ? err.message : String(err);
227
+ out.error(message);
228
+ process.exitCode = 1;
229
+ }
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@lifestreamdynamics/vault-cli",
3
+ "version": "1.0.0",
4
+ "description": "Command-line interface for Lifestream Vault",
5
+ "type": "module",
6
+ "bin": {
7
+ "lsvault": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "!dist/**/*.test.*",
12
+ "!dist/**/__tests__",
13
+ "README.md"
14
+ ],
15
+ "keywords": [
16
+ "lifestream",
17
+ "vault",
18
+ "cli",
19
+ "markdown",
20
+ "webdav",
21
+ "sync",
22
+ "command-line"
23
+ ],
24
+ "author": "Lifestream Dynamics <eric@lifestreamdynamics.com>",
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/lifestreamdynamics/lifestream-vault-cli.git"
29
+ },
30
+ "bugs": {
31
+ "url": "https://github.com/lifestreamdynamics/lifestream-vault-cli/issues"
32
+ },
33
+ "homepage": "https://github.com/lifestreamdynamics/lifestream-vault-cli#readme",
34
+ "scripts": {
35
+ "build": "tsc",
36
+ "dev": "tsx src/index.ts",
37
+ "test": "vitest run",
38
+ "test:watch": "vitest",
39
+ "test:coverage": "vitest run --coverage",
40
+ "test:ui": "vitest --ui",
41
+ "prepublishOnly": "npm run build && npm test"
42
+ },
43
+ "dependencies": {
44
+ "@lifestreamdynamics/vault-sdk": "^1.0.0",
45
+ "chalk": "^5.4.0",
46
+ "chokidar": "^4.0.3",
47
+ "commander": "^13.0.0",
48
+ "minimatch": "^10.2.0",
49
+ "ora": "^8.0.0"
50
+ },
51
+ "optionalDependencies": {
52
+ "keytar": "^7.9.0"
53
+ },
54
+ "devDependencies": {
55
+ "@types/node": "^22.0.0",
56
+ "@vitest/coverage-v8": "^2.0.0",
57
+ "@vitest/ui": "^2.0.0",
58
+ "tsx": "^4.19.0",
59
+ "typescript": "^5.7.0",
60
+ "vitest": "^2.0.0"
61
+ }
62
+ }