@elaraai/e3-cli 0.0.2-beta.8 → 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 (135) hide show
  1. package/LICENSE.md +4 -0
  2. package/README.md +169 -46
  3. package/dist/src/cli.js +197 -73
  4. package/dist/src/cli.js.map +1 -1
  5. package/dist/src/commands/auth.d.ts +23 -0
  6. package/dist/src/commands/auth.d.ts.map +1 -0
  7. package/dist/src/commands/auth.js +200 -0
  8. package/dist/src/commands/auth.js.map +1 -0
  9. package/dist/src/commands/complete.d.ts +14 -0
  10. package/dist/src/commands/complete.d.ts.map +1 -0
  11. package/dist/src/commands/complete.js +166 -0
  12. package/dist/src/commands/complete.js.map +1 -0
  13. package/dist/src/commands/complete.spec.d.ts +6 -0
  14. package/dist/src/commands/complete.spec.d.ts.map +1 -0
  15. package/dist/src/commands/complete.spec.js +63 -0
  16. package/dist/src/commands/complete.spec.js.map +1 -0
  17. package/dist/src/commands/completion-install.d.ts +47 -0
  18. package/dist/src/commands/completion-install.d.ts.map +1 -0
  19. package/dist/src/commands/completion-install.js +141 -0
  20. package/dist/src/commands/completion-install.js.map +1 -0
  21. package/dist/src/commands/completion-install.spec.d.ts +6 -0
  22. package/dist/src/commands/completion-install.spec.d.ts.map +1 -0
  23. package/dist/src/commands/completion-install.spec.js +136 -0
  24. package/dist/src/commands/completion-install.spec.js.map +1 -0
  25. package/dist/src/commands/completion.d.ts +12 -0
  26. package/dist/src/commands/completion.d.ts.map +1 -0
  27. package/dist/src/commands/completion.js +75 -0
  28. package/dist/src/commands/completion.js.map +1 -0
  29. package/dist/src/commands/completion.spec.d.ts +6 -0
  30. package/dist/src/commands/completion.spec.d.ts.map +1 -0
  31. package/dist/src/commands/completion.spec.js +48 -0
  32. package/dist/src/commands/completion.spec.js.map +1 -0
  33. package/dist/src/commands/convert.impl.spec.d.ts +6 -0
  34. package/dist/src/commands/convert.impl.spec.d.ts.map +1 -0
  35. package/dist/src/commands/convert.impl.spec.js +245 -0
  36. package/dist/src/commands/convert.impl.spec.js.map +1 -0
  37. package/dist/src/commands/dataset-status.d.ts +9 -0
  38. package/dist/src/commands/dataset-status.d.ts.map +1 -0
  39. package/dist/src/commands/dataset-status.js +77 -0
  40. package/dist/src/commands/dataset-status.js.map +1 -0
  41. package/dist/src/commands/find.d.ts +17 -0
  42. package/dist/src/commands/find.d.ts.map +1 -0
  43. package/dist/src/commands/find.js +59 -0
  44. package/dist/src/commands/find.js.map +1 -0
  45. package/dist/src/commands/find.spec.d.ts +6 -0
  46. package/dist/src/commands/find.spec.d.ts.map +1 -0
  47. package/dist/src/commands/find.spec.js +43 -0
  48. package/dist/src/commands/find.spec.js.map +1 -0
  49. package/dist/src/commands/get.d.ts +3 -0
  50. package/dist/src/commands/get.d.ts.map +1 -1
  51. package/dist/src/commands/get.js +43 -20
  52. package/dist/src/commands/get.js.map +1 -1
  53. package/dist/src/commands/get.spec.d.ts +6 -0
  54. package/dist/src/commands/get.spec.d.ts.map +1 -0
  55. package/dist/src/commands/get.spec.js +28 -0
  56. package/dist/src/commands/get.spec.js.map +1 -0
  57. package/dist/src/commands/list.d.ts +6 -2
  58. package/dist/src/commands/list.d.ts.map +1 -1
  59. package/dist/src/commands/list.js +189 -30
  60. package/dist/src/commands/list.js.map +1 -1
  61. package/dist/src/commands/logs.d.ts.map +1 -1
  62. package/dist/src/commands/logs.js +96 -70
  63. package/dist/src/commands/logs.js.map +1 -1
  64. package/dist/src/commands/package.d.ts.map +1 -1
  65. package/dist/src/commands/package.js +78 -18
  66. package/dist/src/commands/package.js.map +1 -1
  67. package/dist/src/commands/repo.d.ts +44 -0
  68. package/dist/src/commands/repo.d.ts.map +1 -0
  69. package/dist/src/commands/repo.js +278 -0
  70. package/dist/src/commands/repo.js.map +1 -0
  71. package/dist/src/commands/run.d.ts +12 -0
  72. package/dist/src/commands/run.d.ts.map +1 -1
  73. package/dist/src/commands/run.js +21 -13
  74. package/dist/src/commands/run.js.map +1 -1
  75. package/dist/src/commands/run.spec.d.ts +6 -0
  76. package/dist/src/commands/run.spec.d.ts.map +1 -0
  77. package/dist/src/commands/run.spec.js +39 -0
  78. package/dist/src/commands/run.spec.js.map +1 -0
  79. package/dist/src/commands/set.d.ts +1 -0
  80. package/dist/src/commands/set.d.ts.map +1 -1
  81. package/dist/src/commands/set.js +33 -32
  82. package/dist/src/commands/set.js.map +1 -1
  83. package/dist/src/commands/start.d.ts.map +1 -1
  84. package/dist/src/commands/start.js +270 -52
  85. package/dist/src/commands/start.js.map +1 -1
  86. package/dist/src/commands/watch.d.ts +5 -2
  87. package/dist/src/commands/watch.d.ts.map +1 -1
  88. package/dist/src/commands/watch.js +32 -26
  89. package/dist/src/commands/watch.js.map +1 -1
  90. package/dist/src/commands/workspace.d.ts +12 -1
  91. package/dist/src/commands/workspace.d.ts.map +1 -1
  92. package/dist/src/commands/workspace.js +332 -38
  93. package/dist/src/commands/workspace.js.map +1 -1
  94. package/dist/src/credentials.d.ts +123 -0
  95. package/dist/src/credentials.d.ts.map +1 -0
  96. package/dist/src/credentials.js +213 -0
  97. package/dist/src/credentials.js.map +1 -0
  98. package/dist/src/format.d.ts +18 -0
  99. package/dist/src/format.d.ts.map +1 -0
  100. package/dist/src/format.js +43 -0
  101. package/dist/src/format.js.map +1 -0
  102. package/dist/src/path-resolver.d.ts +86 -0
  103. package/dist/src/path-resolver.d.ts.map +1 -0
  104. package/dist/src/path-resolver.js +241 -0
  105. package/dist/src/path-resolver.js.map +1 -0
  106. package/dist/src/path-resolver.spec.d.ts +6 -0
  107. package/dist/src/path-resolver.spec.d.ts.map +1 -0
  108. package/dist/src/path-resolver.spec.js +247 -0
  109. package/dist/src/path-resolver.spec.js.map +1 -0
  110. package/dist/src/utils.d.ts +76 -1
  111. package/dist/src/utils.d.ts.map +1 -1
  112. package/dist/src/utils.js +104 -1
  113. package/dist/src/utils.js.map +1 -1
  114. package/dist/src/utils.spec.d.ts +6 -0
  115. package/dist/src/utils.spec.d.ts.map +1 -0
  116. package/dist/src/utils.spec.js +199 -0
  117. package/dist/src/utils.spec.js.map +1 -0
  118. package/package.json +22 -18
  119. package/scripts/postinstall.cjs +26 -0
  120. package/dist/src/commands/gc.d.ts +0 -12
  121. package/dist/src/commands/gc.d.ts.map +0 -1
  122. package/dist/src/commands/gc.js +0 -44
  123. package/dist/src/commands/gc.js.map +0 -1
  124. package/dist/src/commands/init.d.ts +0 -9
  125. package/dist/src/commands/init.d.ts.map +0 -1
  126. package/dist/src/commands/init.js +0 -33
  127. package/dist/src/commands/init.js.map +0 -1
  128. package/dist/src/commands/status.d.ts +0 -9
  129. package/dist/src/commands/status.d.ts.map +0 -1
  130. package/dist/src/commands/status.js +0 -157
  131. package/dist/src/commands/status.js.map +0 -1
  132. package/dist/src/commands/tree.d.ts +0 -14
  133. package/dist/src/commands/tree.d.ts.map +0 -1
  134. package/dist/src/commands/tree.js +0 -77
  135. package/dist/src/commands/tree.js.map +0 -1
@@ -0,0 +1,247 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * Tests for the dataset path resolver.
7
+ *
8
+ * The pure functions (`levenshtein`, `suggestSimilar`, `indexFromTree`,
9
+ * `indexFromRemoteEntries`, `resolveDatasetPathFromIndex`) are exercised
10
+ * directly without a real repository.
11
+ */
12
+ import { describe, it } from 'node:test';
13
+ import assert from 'node:assert/strict';
14
+ import { variant } from '@elaraai/east';
15
+ import { levenshtein, suggestSimilar, indexFromTree, indexFromRemoteEntries, resolveDatasetPathFromIndex, } from './path-resolver.js';
16
+ // =============================================================================
17
+ // Tree fixture builders
18
+ // =============================================================================
19
+ function leaf(name) {
20
+ return { name, kind: 'dataset' };
21
+ }
22
+ function branch(name, children) {
23
+ return { name, kind: 'tree', children };
24
+ }
25
+ function inputs(...names) {
26
+ return branch('inputs', names.map(leaf));
27
+ }
28
+ function tasks(...names) {
29
+ return branch('tasks', names.map(leaf));
30
+ }
31
+ // Remote ListEntry builders
32
+ function remoteDataset(path) {
33
+ return variant('dataset', {
34
+ path,
35
+ type: variant('String', null),
36
+ hash: variant('none', null),
37
+ size: variant('none', null),
38
+ });
39
+ }
40
+ function remoteTree(path) {
41
+ return variant('tree', { path, kind: variant('struct', null) });
42
+ }
43
+ // =============================================================================
44
+ // levenshtein
45
+ // =============================================================================
46
+ describe('levenshtein', () => {
47
+ it('returns 0 for identical strings', () => {
48
+ assert.strictEqual(levenshtein('abc', 'abc'), 0);
49
+ assert.strictEqual(levenshtein('', ''), 0);
50
+ });
51
+ it('returns length of the non-empty string when one side is empty', () => {
52
+ assert.strictEqual(levenshtein('', 'abc'), 3);
53
+ assert.strictEqual(levenshtein('xyz', ''), 3);
54
+ });
55
+ it('returns 1 for single insertion', () => {
56
+ assert.strictEqual(levenshtein('abc', 'abcd'), 1);
57
+ });
58
+ it('returns 1 for single deletion', () => {
59
+ assert.strictEqual(levenshtein('abcd', 'abc'), 1);
60
+ });
61
+ it('returns 1 for single substitution', () => {
62
+ assert.strictEqual(levenshtein('abc', 'abd'), 1);
63
+ });
64
+ it('handles the classic kitten/sitting case', () => {
65
+ assert.strictEqual(levenshtein('kitten', 'sitting'), 3);
66
+ });
67
+ it('handles unicode characters as JS code units', () => {
68
+ // résumé vs resume — two characters with accents replaced
69
+ assert.strictEqual(levenshtein('résumé', 'resume'), 2);
70
+ });
71
+ });
72
+ // =============================================================================
73
+ // suggestSimilar
74
+ // =============================================================================
75
+ describe('suggestSimilar', () => {
76
+ it('returns exact match first', () => {
77
+ const result = suggestSimilar('greet', ['greeting', 'greet', 'grit'], 5);
78
+ assert.strictEqual(result[0], 'greet');
79
+ });
80
+ it('returns single-char typos within threshold', () => {
81
+ const result = suggestSimilar('greet', ['greeting', 'gret', 'shout'], 5);
82
+ assert.ok(result.includes('gret'));
83
+ });
84
+ it('filters out candidates beyond the threshold', () => {
85
+ // target length 5 → threshold = max(2, 2) = 2
86
+ const result = suggestSimilar('greet', ['completely-unrelated', 'gret'], 5);
87
+ assert.deepStrictEqual(result, ['gret']);
88
+ });
89
+ it('returns at most `max` candidates', () => {
90
+ const result = suggestSimilar('a', ['a', 'b', 'c', 'd', 'e', 'f'], 3);
91
+ assert.strictEqual(result.length, 3);
92
+ });
93
+ it('returns candidates in distance order', () => {
94
+ const result = suggestSimilar('hello', ['hellp', 'hxllo', 'help'], 5);
95
+ // hellp d=1, hxllo d=1, help d=2 (all within threshold)
96
+ // First two could be in either order (both d=1), but help must come last
97
+ assert.strictEqual(result[result.length - 1], 'help');
98
+ });
99
+ it('returns empty array when candidates is empty', () => {
100
+ assert.deepStrictEqual(suggestSimilar('greet', [], 5), []);
101
+ });
102
+ it('still applies threshold of 2 for very short targets', () => {
103
+ // target 'a' → threshold = max(2, 0) = 2
104
+ const result = suggestSimilar('a', ['ab', 'abc', 'abcd'], 5);
105
+ // ab d=1, abc d=2, abcd d=3 (excluded)
106
+ assert.ok(result.includes('ab'));
107
+ assert.ok(result.includes('abc'));
108
+ assert.ok(!result.includes('abcd'));
109
+ });
110
+ it('handles very long names with appropriate threshold', () => {
111
+ // target length 100 → threshold = 50; far-apart strings still excluded
112
+ const longName = 'a'.repeat(100);
113
+ const result = suggestSimilar(longName, ['b'.repeat(100)], 5);
114
+ // 100 edits — far above threshold of 50
115
+ assert.deepStrictEqual(result, []);
116
+ });
117
+ });
118
+ // =============================================================================
119
+ // indexFromTree
120
+ // =============================================================================
121
+ describe('indexFromTree', () => {
122
+ it('returns [] for empty tree', () => {
123
+ assert.deepStrictEqual(indexFromTree([]), []);
124
+ });
125
+ it('indexes inputs as kind=input with [inputs, name] storage', () => {
126
+ const tree = [inputs('name', 'count')];
127
+ const result = indexFromTree(tree);
128
+ const name = result.find((e) => e.name === 'name');
129
+ assert.strictEqual(name.kind, 'input');
130
+ assert.deepStrictEqual(name.storage.map((s) => s.value), ['inputs', 'name']);
131
+ });
132
+ it('indexes tasks as kind=task-output with [tasks, name, output] storage', () => {
133
+ const tree = [tasks('greet')];
134
+ const result = indexFromTree(tree);
135
+ const greet = result.find((e) => e.name === 'greet');
136
+ assert.strictEqual(greet.kind, 'task-output');
137
+ assert.deepStrictEqual(greet.storage.map((s) => s.value), ['tasks', 'greet', 'output']);
138
+ });
139
+ it('indexes both inputs and tasks in a typical workspace', () => {
140
+ const tree = [inputs('name'), tasks('greet', 'shout')];
141
+ const result = indexFromTree(tree);
142
+ assert.strictEqual(result.length, 3);
143
+ assert.ok(result.some((e) => e.name === 'name' && e.kind === 'input'));
144
+ assert.ok(result.some((e) => e.name === 'greet' && e.kind === 'task-output'));
145
+ assert.ok(result.some((e) => e.name === 'shout' && e.kind === 'task-output'));
146
+ });
147
+ it('treats nested non-input/non-task branches as kind=other with dotted name', () => {
148
+ const tree = [branch('config', [leaf('value')])];
149
+ const result = indexFromTree(tree);
150
+ assert.strictEqual(result.length, 1);
151
+ const e = result[0];
152
+ assert.strictEqual(e.kind, 'other');
153
+ assert.strictEqual(e.name, 'config.value');
154
+ assert.deepStrictEqual(e.storage.map((s) => s.value), ['config', 'value']);
155
+ });
156
+ it('handles a leaf at the root (no prefix)', () => {
157
+ // unusual but well-defined: dataset at root would be kind=other with bare name
158
+ const tree = [leaf('bare')];
159
+ const result = indexFromTree(tree);
160
+ assert.strictEqual(result.length, 1);
161
+ assert.strictEqual(result[0].kind, 'other');
162
+ assert.strictEqual(result[0].name, 'bare');
163
+ });
164
+ });
165
+ // =============================================================================
166
+ // indexFromRemoteEntries
167
+ // =============================================================================
168
+ describe('indexFromRemoteEntries', () => {
169
+ it('returns [] for empty list', () => {
170
+ assert.deepStrictEqual(indexFromRemoteEntries([]), []);
171
+ });
172
+ it('indexes inputs.<name> as kind=input', () => {
173
+ const result = indexFromRemoteEntries([remoteDataset('inputs.name')]);
174
+ assert.strictEqual(result.length, 1);
175
+ assert.strictEqual(result[0].kind, 'input');
176
+ assert.strictEqual(result[0].name, 'name');
177
+ });
178
+ it('indexes tasks.<name> as kind=task-output with output suffix in storage', () => {
179
+ const result = indexFromRemoteEntries([remoteDataset('tasks.greet')]);
180
+ assert.strictEqual(result.length, 1);
181
+ assert.strictEqual(result[0].kind, 'task-output');
182
+ assert.strictEqual(result[0].name, 'greet');
183
+ assert.deepStrictEqual(result[0].storage.map((s) => s.value), ['tasks', 'greet', 'output']);
184
+ });
185
+ it('ignores tree entries (only datasets are indexable leaves)', () => {
186
+ const result = indexFromRemoteEntries([remoteTree('inputs'), remoteDataset('inputs.name')]);
187
+ assert.strictEqual(result.length, 1);
188
+ assert.strictEqual(result[0].name, 'name');
189
+ });
190
+ });
191
+ // =============================================================================
192
+ // resolveDatasetPathFromIndex
193
+ // =============================================================================
194
+ describe('resolveDatasetPathFromIndex', () => {
195
+ const index = indexFromTree([
196
+ inputs('name', 'count'),
197
+ tasks('greet', 'shout'),
198
+ ]);
199
+ it('resolves a known input', () => {
200
+ const result = resolveDatasetPathFromIndex('dev.name', index);
201
+ assert.strictEqual(result.ws, 'dev');
202
+ assert.strictEqual(result.kind, 'input');
203
+ assert.deepStrictEqual(result.path.map((s) => s.value), ['inputs', 'name']);
204
+ });
205
+ it('resolves a known task with the output suffix added', () => {
206
+ const result = resolveDatasetPathFromIndex('dev.greet', index);
207
+ assert.strictEqual(result.kind, 'task-output');
208
+ assert.deepStrictEqual(result.path.map((s) => s.value), ['tasks', 'greet', 'output']);
209
+ });
210
+ it('errors on path with no name segment', () => {
211
+ assert.throws(() => resolveDatasetPathFromIndex('dev', index), /Path must include a name/);
212
+ });
213
+ it('rejects legacy inputs.<name> form with a hint', () => {
214
+ assert.throws(() => resolveDatasetPathFromIndex('dev.inputs.name', index), /Use the short form: 'dev.name'/);
215
+ });
216
+ it('rejects legacy tasks.<name>.output form with a hint', () => {
217
+ assert.throws(() => resolveDatasetPathFromIndex('dev.tasks.greet.output', index), /Use the short form: 'dev.greet'/);
218
+ });
219
+ it('suggests close matches for typos', () => {
220
+ assert.throws(() => resolveDatasetPathFromIndex('dev.gret', index), /Did you mean.*dev\.greet/s);
221
+ });
222
+ it('lists available names when no close match exists', () => {
223
+ assert.throws(() => resolveDatasetPathFromIndex('dev.completelyDifferentName', index), /Available names/);
224
+ });
225
+ it('caps the available list at 10 names with a "... and N more" suffix', () => {
226
+ const many = indexFromTree([
227
+ inputs(...Array.from({ length: 15 }, (_, i) => `in${i}`)),
228
+ ]);
229
+ let err;
230
+ try {
231
+ resolveDatasetPathFromIndex('dev.completelyDifferentName', many);
232
+ }
233
+ catch (e) {
234
+ err = e;
235
+ }
236
+ assert.ok(err, 'expected error');
237
+ assert.match(err.message, /\.\.\. and 5 more/);
238
+ });
239
+ it('reports ambiguity when an input and task share a name', () => {
240
+ const ambig = indexFromTree([inputs('foo'), tasks('foo')]);
241
+ assert.throws(() => resolveDatasetPathFromIndex('dev.foo', ambig), /ambiguous/);
242
+ });
243
+ it('rejects nested field access past the leaf', () => {
244
+ assert.throws(() => resolveDatasetPathFromIndex('dev.greet.field', index), /Nested field access/);
245
+ });
246
+ });
247
+ //# sourceMappingURL=path-resolver.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-resolver.spec.js","sourceRoot":"","sources":["../../src/path-resolver.spec.ts"],"names":[],"mappings":"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"}
@@ -2,8 +2,72 @@
2
2
  * Copyright (c) 2025 Elara AI Pty Ltd
3
3
  * Licensed under BSL 1.1. See LICENSE for details.
4
4
  */
5
+ /** Character width used when truncating object hashes for display. */
6
+ export declare const HASH_DISPLAY_WIDTH = 12;
7
+ /** Truncate a hash to `HASH_DISPLAY_WIDTH` chars with a trailing ellipsis. */
8
+ export declare function shortHash(hash: string): string;
5
9
  import { parseDatasetPath, parsePackageRef } from '@elaraai/e3-types';
10
+ /**
11
+ * Resolve the `<repo>` positional argument with fallback to `E3_REPO` env var
12
+ * then `.` (cwd). Used by every command that accepts a repository argument so
13
+ * users in a current directory can drop the leading `.`.
14
+ */
15
+ export declare function defaultRepoArg(arg: string | undefined): string;
16
+ /**
17
+ * Wrap a command handler whose first parameter is `<repo>` so that the
18
+ * Commander action callback can pass `string | undefined` and the handler
19
+ * still sees a fully-resolved repo string.
20
+ */
21
+ export declare function withDefaultRepo<A extends unknown[]>(handler: (repo: string, ...args: A) => void | Promise<void>): (repo: string | undefined, ...args: A) => void | Promise<void>;
6
22
  export { parseDatasetPath, parsePackageRef };
23
+ /**
24
+ * Repository location - either local filesystem or remote URL.
25
+ */
26
+ export type RepoLocation = {
27
+ type: 'local';
28
+ path: string;
29
+ } | {
30
+ type: 'remote';
31
+ baseUrl: string;
32
+ repo: string;
33
+ token: string;
34
+ };
35
+ /**
36
+ * Parse a repository location argument.
37
+ *
38
+ * Supports:
39
+ * - Local paths: `.`, `./repo`, `/path/to/repo`
40
+ * - Remote URLs: `http://...`, `https://...`
41
+ *
42
+ * For remote URLs, the URL should be the user-facing "shareable" URL,
43
+ * e.g., `https://platform.example.com/repos/my_repo`.
44
+ * The CLI will internally add `/api` when making API calls.
45
+ *
46
+ * For remote locations, this function will load and validate the auth token.
47
+ * If not logged in or token is expired and cannot be refreshed, throws an error.
48
+ *
49
+ * @returns For local: { type: 'local', path: '/absolute/path/to/repo' }
50
+ * For remote: { type: 'remote', baseUrl: 'https://example.com', repo: 'my_repo', token: '...' }
51
+ */
52
+ export declare function parseRepoLocation(arg: string): Promise<RepoLocation>;
53
+ /**
54
+ * Repository location without required token (for sync parsing).
55
+ */
56
+ export type RepoLocationNoToken = {
57
+ type: 'local';
58
+ path: string;
59
+ } | {
60
+ type: 'remote';
61
+ baseUrl: string;
62
+ repo: string;
63
+ };
64
+ /**
65
+ * Parse a repository location (synchronous, no auth).
66
+ *
67
+ * Use this only for operations that don't need authentication (e.g., local repos).
68
+ * For remote repos, use parseRepoLocation() instead.
69
+ */
70
+ export declare function parseRepoLocationSync(arg: string): RepoLocationNoToken;
7
71
  /**
8
72
  * Resolve repository path from CLI argument.
9
73
  * Supports `.` for current directory and relative/absolute paths.
@@ -18,7 +82,18 @@ export declare function parsePackageSpec(spec: string): {
18
82
  version: string;
19
83
  };
20
84
  /**
21
- * Format error for CLI output.
85
+ * Format an error into a human-readable CLI message.
86
+ *
87
+ * Handles three error categories:
88
+ * - {@link ApiError} — humanizes the error code (e.g. `"package_not_found"` → `"Package not found"`)
89
+ * and appends details if present (string details verbatim, objects as JSON).
90
+ * - Standard `Error` — returns `.message`.
91
+ * - Other values — coerces to string via `String()`.
92
+ *
93
+ * The returned string is intended for `exitError()` which prefixes it with `"Error: "`.
94
+ *
95
+ * @param err - The caught error value (may be any type)
96
+ * @returns A single-line, human-readable error description
22
97
  */
23
98
  export declare function formatError(err: unknown): string;
24
99
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGtE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,CAAC;AAE7C;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGnD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAGhF;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAKhD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,CAGhD"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,sEAAsE;AACtE,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC,8EAA8E;AAC9E,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAGD,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAItE;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAG9D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,OAAO,EAAE,EACjD,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAEnD,MAAM,MAAM,GAAG,SAAS,EAAE,GAAG,MAAM,CAAC,0BAC7C;AAGD,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,CAAC;AAE7C;;GAEG;AACH,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAErE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAqB1E;AAED;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAC3B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,mBAAmB,CActE;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGnD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAGhF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAchD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,CAGhD"}
package/dist/src/utils.js CHANGED
@@ -6,10 +6,93 @@
6
6
  * CLI utilities for path parsing and resolution
7
7
  */
8
8
  import { resolve } from 'path';
9
+ /** Character width used when truncating object hashes for display. */
10
+ export const HASH_DISPLAY_WIDTH = 12;
11
+ /** Truncate a hash to `HASH_DISPLAY_WIDTH` chars with a trailing ellipsis. */
12
+ export function shortHash(hash) {
13
+ return `${hash.slice(0, HASH_DISPLAY_WIDTH)}...`;
14
+ }
9
15
  import { repoGet } from '@elaraai/e3-core';
10
16
  import { parseDatasetPath, parsePackageRef } from '@elaraai/e3-types';
17
+ import { ApiError } from '@elaraai/e3-api-client';
18
+ import { getValidToken } from './credentials.js';
19
+ /**
20
+ * Resolve the `<repo>` positional argument with fallback to `E3_REPO` env var
21
+ * then `.` (cwd). Used by every command that accepts a repository argument so
22
+ * users in a current directory can drop the leading `.`.
23
+ */
24
+ export function defaultRepoArg(arg) {
25
+ if (arg && arg.length > 0)
26
+ return arg;
27
+ return process.env.E3_REPO ?? '.';
28
+ }
29
+ /**
30
+ * Wrap a command handler whose first parameter is `<repo>` so that the
31
+ * Commander action callback can pass `string | undefined` and the handler
32
+ * still sees a fully-resolved repo string.
33
+ */
34
+ export function withDefaultRepo(handler) {
35
+ return (repo, ...args) => handler(defaultRepoArg(repo), ...args);
36
+ }
11
37
  // Re-export for convenience
12
38
  export { parseDatasetPath, parsePackageRef };
39
+ /**
40
+ * Parse a repository location argument.
41
+ *
42
+ * Supports:
43
+ * - Local paths: `.`, `./repo`, `/path/to/repo`
44
+ * - Remote URLs: `http://...`, `https://...`
45
+ *
46
+ * For remote URLs, the URL should be the user-facing "shareable" URL,
47
+ * e.g., `https://platform.example.com/repos/my_repo`.
48
+ * The CLI will internally add `/api` when making API calls.
49
+ *
50
+ * For remote locations, this function will load and validate the auth token.
51
+ * If not logged in or token is expired and cannot be refreshed, throws an error.
52
+ *
53
+ * @returns For local: { type: 'local', path: '/absolute/path/to/repo' }
54
+ * For remote: { type: 'remote', baseUrl: 'https://example.com', repo: 'my_repo', token: '...' }
55
+ */
56
+ export async function parseRepoLocation(arg) {
57
+ if (arg.startsWith('https://') || arg.startsWith('http://')) {
58
+ const url = new URL(arg);
59
+ // Extract repo name from path: /repos/{repo}[/...]
60
+ const match = url.pathname.match(/^\/repos\/([^/]+)/);
61
+ if (!match) {
62
+ throw new Error(`Invalid remote URL: expected /repos/{repo} in path, got ${url.pathname}`);
63
+ }
64
+ // Load and validate token
65
+ const token = await getValidToken(url.origin);
66
+ return {
67
+ type: 'remote',
68
+ baseUrl: url.origin,
69
+ repo: match[1],
70
+ token,
71
+ };
72
+ }
73
+ return { type: 'local', path: resolveRepo(arg) };
74
+ }
75
+ /**
76
+ * Parse a repository location (synchronous, no auth).
77
+ *
78
+ * Use this only for operations that don't need authentication (e.g., local repos).
79
+ * For remote repos, use parseRepoLocation() instead.
80
+ */
81
+ export function parseRepoLocationSync(arg) {
82
+ if (arg.startsWith('https://') || arg.startsWith('http://')) {
83
+ const url = new URL(arg);
84
+ const match = url.pathname.match(/^\/repos\/([^/]+)/);
85
+ if (!match) {
86
+ throw new Error(`Invalid remote URL: expected /repos/{repo} in path, got ${url.pathname}`);
87
+ }
88
+ return {
89
+ type: 'remote',
90
+ baseUrl: url.origin,
91
+ repo: match[1],
92
+ };
93
+ }
94
+ return { type: 'local', path: resolveRepo(arg) };
95
+ }
13
96
  /**
14
97
  * Resolve repository path from CLI argument.
15
98
  * Supports `.` for current directory and relative/absolute paths.
@@ -27,9 +110,29 @@ export function parsePackageSpec(spec) {
27
110
  return { name, version: version ?? 'latest' };
28
111
  }
29
112
  /**
30
- * Format error for CLI output.
113
+ * Format an error into a human-readable CLI message.
114
+ *
115
+ * Handles three error categories:
116
+ * - {@link ApiError} — humanizes the error code (e.g. `"package_not_found"` → `"Package not found"`)
117
+ * and appends details if present (string details verbatim, objects as JSON).
118
+ * - Standard `Error` — returns `.message`.
119
+ * - Other values — coerces to string via `String()`.
120
+ *
121
+ * The returned string is intended for `exitError()` which prefixes it with `"Error: "`.
122
+ *
123
+ * @param err - The caught error value (may be any type)
124
+ * @returns A single-line, human-readable error description
31
125
  */
32
126
  export function formatError(err) {
127
+ if (err instanceof ApiError) {
128
+ // Humanize the error code: "execution_not_found" → "Execution not found"
129
+ const message = err.code.replace(/_/g, ' ').replace(/^\w/, c => c.toUpperCase());
130
+ if (err.details != null) {
131
+ const detail = typeof err.details === 'string' ? err.details : JSON.stringify(err.details);
132
+ return `${message}: ${detail}`;
133
+ }
134
+ return message;
135
+ }
33
136
  if (err instanceof Error) {
34
137
  return err.message;
35
138
  }
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEtE,4BAA4B;AAC5B,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,CAAC;AAE7C;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtC,OAAO,OAAO,CAAC,YAAY,CAAC,CAAC;AAC/B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IAChD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,CAAC;AAChD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,GAAY;IACtC,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;QACzB,OAAO,GAAG,CAAC,OAAO,CAAC;IACrB,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,OAAe;IACvC,OAAO,CAAC,KAAK,CAAC,UAAU,OAAO,EAAE,CAAC,CAAC;IACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=utils.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.spec.d.ts","sourceRoot":"","sources":["../../src/utils.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG"}