@elaraai/e3-cli 0.0.2-beta.9 → 1.0.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.
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,14 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ export declare function completeCommand(cwordStr: string, words?: string[]): Promise<void>;
6
+ /**
7
+ * Pure(-ish) helper that produces the candidate list for given inputs.
8
+ *
9
+ * Static branches never touch the network or filesystem. Dynamic branches
10
+ * (workspace / dataset path completion) may call out to local storage or
11
+ * the API client — wrapped in try/catch so completion never errors.
12
+ */
13
+ export declare function completionCandidates(cwordStr: string, words: string[]): Promise<string[]>;
14
+ //# sourceMappingURL=complete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"complete.d.ts","sourceRoot":"","sources":["../../../src/commands/complete.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAoDH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAI3F;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAuB/F"}
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * Hidden `e3 __complete <cword> <words...>` handler.
7
+ *
8
+ * Called by the shell completion scripts. Given the position of the cursor
9
+ * and the words on the command line (excluding the leading `e3`), prints
10
+ * newline-separated candidates that the shell uses to populate completion.
11
+ *
12
+ * Static candidates (subcommand names, flag names, enum values) are returned
13
+ * immediately. Dynamic candidates (workspace names, dataset paths) query the
14
+ * relevant list functions; errors are swallowed silently so the shell never
15
+ * sees noise from a missing repo or unreachable server.
16
+ */
17
+ import { workspaceList, LocalStorage } from '@elaraai/e3-core';
18
+ import { workspaceList as workspaceListRemote } from '@elaraai/e3-api-client';
19
+ import { parseRepoLocation, defaultRepoArg } from '../utils.js';
20
+ import { buildWorkspaceIndex } from '../path-resolver.js';
21
+ // =============================================================================
22
+ // Static tables
23
+ // =============================================================================
24
+ /** Top-level subcommand names. */
25
+ const TOP_LEVEL = [
26
+ 'repo', 'package', 'workspace', 'dataset', 'task', 'dataflow', 'auth',
27
+ 'run', 'watch', 'convert', 'completion',
28
+ ];
29
+ /** Subcommand names per noun group. */
30
+ const SUBCOMMANDS = {
31
+ repo: ['create', 'remove', 'status', 'gc', 'list'],
32
+ package: ['import', 'export', 'list', 'remove'],
33
+ workspace: ['create', 'remove', 'list', 'status', 'deploy', 'export'],
34
+ dataset: ['get', 'set', 'list', 'status', 'find'],
35
+ task: ['logs', 'list'],
36
+ dataflow: ['run'],
37
+ auth: ['login', 'logout', 'status', 'token', 'whoami'],
38
+ completion: ['bash', 'zsh', 'fish'],
39
+ };
40
+ /** Enum values for known options. */
41
+ const FORMAT_VALUES = ['east', 'json', 'beast2'];
42
+ /** Number of dynamic candidates to emit at most. */
43
+ const MAX_DYNAMIC_CANDIDATES = 100;
44
+ // =============================================================================
45
+ // Entry point (commander action wrapper)
46
+ // =============================================================================
47
+ export async function completeCommand(cwordStr, words = []) {
48
+ for (const c of await completionCandidates(cwordStr, words)) {
49
+ console.log(c);
50
+ }
51
+ }
52
+ /**
53
+ * Pure(-ish) helper that produces the candidate list for given inputs.
54
+ *
55
+ * Static branches never touch the network or filesystem. Dynamic branches
56
+ * (workspace / dataset path completion) may call out to local storage or
57
+ * the API client — wrapped in try/catch so completion never errors.
58
+ */
59
+ export async function completionCandidates(cwordStr, words) {
60
+ const cword = Number.parseInt(cwordStr, 10);
61
+ if (!Number.isInteger(cword) || cword < 0)
62
+ return [];
63
+ const current = words[cword] ?? '';
64
+ const prev = cword > 0 ? words[cword - 1] : '';
65
+ if (prev === '--format' || prev === '-f') {
66
+ return filterByPrefix(FORMAT_VALUES, current);
67
+ }
68
+ if (cword === 0) {
69
+ return filterByPrefix(TOP_LEVEL, current);
70
+ }
71
+ const cmd = words[0];
72
+ if (cword === 1 && SUBCOMMANDS[cmd]) {
73
+ return filterByPrefix(SUBCOMMANDS[cmd], current);
74
+ }
75
+ const sub = words[1] ?? '';
76
+ return dispatchPositional(cmd, sub, cword, words, current);
77
+ }
78
+ // =============================================================================
79
+ // Positional dispatcher
80
+ // =============================================================================
81
+ async function dispatchPositional(cmd, sub, cword, words, current) {
82
+ // For all noun groups, `<cmd> <sub> <repo> [more...]` puts the repo at index 2.
83
+ const repoIndex = 2;
84
+ if (cword === repoIndex) {
85
+ return filterByPrefix(['.', 'http://', 'https://'], current);
86
+ }
87
+ // dataset.{get,set,status}: third positional is the dotted dataset path.
88
+ if (cmd === 'dataset' && (sub === 'get' || sub === 'set' || sub === 'status') && cword === repoIndex + 1) {
89
+ return completeDatasetPath(words[repoIndex], current);
90
+ }
91
+ // dataset.{list,find}: third positional is the workspace name.
92
+ if (cmd === 'dataset' && (sub === 'list' || sub === 'find') && cword === repoIndex + 1) {
93
+ return completeWorkspaceName(words[repoIndex], current);
94
+ }
95
+ // task.list / dataflow.run: third positional is the workspace name.
96
+ if ((cmd === 'task' && sub === 'list') ||
97
+ (cmd === 'dataflow' && sub === 'run')) {
98
+ if (cword === repoIndex + 1) {
99
+ return completeWorkspaceName(words[repoIndex], current);
100
+ }
101
+ }
102
+ // task.logs: third positional is the dotted task path.
103
+ if (cmd === 'task' && sub === 'logs' && cword === repoIndex + 1) {
104
+ return completeDatasetPath(words[repoIndex], current);
105
+ }
106
+ // workspace.{remove,status,export,deploy}: third positional is the ws name.
107
+ if (cmd === 'workspace' &&
108
+ (sub === 'remove' || sub === 'status' || sub === 'export' || sub === 'deploy') &&
109
+ cword === repoIndex + 1) {
110
+ return completeWorkspaceName(words[repoIndex], current);
111
+ }
112
+ return [];
113
+ }
114
+ // =============================================================================
115
+ // Dynamic candidates
116
+ // =============================================================================
117
+ async function completeWorkspaceName(repoArg, current) {
118
+ try {
119
+ const location = await parseRepoLocation(defaultRepoArg(repoArg));
120
+ const names = location.type === 'local'
121
+ ? await workspaceList(new LocalStorage(), location.path)
122
+ : (await workspaceListRemote(location.baseUrl, location.repo, { token: location.token }))
123
+ .map((w) => w.name);
124
+ return filterByPrefix(names, current);
125
+ }
126
+ catch {
127
+ return [];
128
+ }
129
+ }
130
+ async function completeDatasetPath(repoArg, current) {
131
+ // The current word looks like `<ws>` or `<ws>.<prefix>`. With no dot, suggest
132
+ // workspace names with a trailing dot to invite drill-down; with a dot,
133
+ // suggest dataset names under that workspace.
134
+ try {
135
+ const location = await parseRepoLocation(defaultRepoArg(repoArg));
136
+ const dotIdx = current.indexOf('.');
137
+ if (dotIdx === -1) {
138
+ const wsNames = location.type === 'local'
139
+ ? await workspaceList(new LocalStorage(), location.path)
140
+ : (await workspaceListRemote(location.baseUrl, location.repo, { token: location.token }))
141
+ .map((w) => w.name);
142
+ return filterByPrefix(wsNames.map((w) => `${w}.`), current);
143
+ }
144
+ const ws = current.slice(0, dotIdx);
145
+ const index = await buildWorkspaceIndex(location, ws);
146
+ return filterByPrefix(index.map((e) => `${ws}.${e.name}`), current);
147
+ }
148
+ catch {
149
+ return [];
150
+ }
151
+ }
152
+ // =============================================================================
153
+ // Filter
154
+ // =============================================================================
155
+ function filterByPrefix(candidates, current) {
156
+ const out = [];
157
+ for (const c of candidates) {
158
+ if (!c.startsWith(current))
159
+ continue;
160
+ out.push(c);
161
+ if (out.length >= MAX_DYNAMIC_CANDIDATES)
162
+ break;
163
+ }
164
+ return out;
165
+ }
166
+ //# sourceMappingURL=complete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"complete.js","sourceRoot":"","sources":["../../../src/commands/complete.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=complete.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"complete.spec.d.ts","sourceRoot":"","sources":["../../../src/commands/complete.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ import { describe, it } from 'node:test';
6
+ import assert from 'node:assert/strict';
7
+ import { completionCandidates } from './complete.js';
8
+ /**
9
+ * The static branches of `completionCandidates` are exercised here.
10
+ * Dynamic branches (workspace/dataset path lookups) hit storage or the API,
11
+ * which is covered by integration tests.
12
+ */
13
+ describe('completionCandidates — static', () => {
14
+ it('returns top-level commands when cword=0', async () => {
15
+ const c = await completionCandidates('0', ['']);
16
+ assert.ok(c.includes('dataset'));
17
+ assert.ok(c.includes('workspace'));
18
+ assert.ok(c.includes('completion'));
19
+ });
20
+ it('filters top-level commands by prefix', async () => {
21
+ const c = await completionCandidates('0', ['dat']);
22
+ assert.deepStrictEqual(c, ['dataset', 'dataflow']);
23
+ });
24
+ it('returns nothing for unknown numeric cword string', async () => {
25
+ assert.deepStrictEqual(await completionCandidates('xyz', []), []);
26
+ assert.deepStrictEqual(await completionCandidates('-1', []), []);
27
+ });
28
+ it('returns subcommands for a known noun at cword=1', async () => {
29
+ const c = await completionCandidates('1', ['dataset', '']);
30
+ assert.deepStrictEqual(c.sort(), ['find', 'get', 'list', 'set', 'status']);
31
+ });
32
+ it('filters subcommands by prefix', async () => {
33
+ const c = await completionCandidates('1', ['dataset', 'g']);
34
+ assert.deepStrictEqual(c, ['get']);
35
+ });
36
+ it('returns empty for unknown noun at cword=1', async () => {
37
+ assert.deepStrictEqual(await completionCandidates('1', ['nosuch', '']), []);
38
+ });
39
+ it('suggests format enum after --format', async () => {
40
+ const c = await completionCandidates('5', ['dataset', 'get', '.', 'dev.greet', '--format', '']);
41
+ assert.deepStrictEqual(c, ['east', 'json', 'beast2']);
42
+ });
43
+ it('filters format enum by prefix', async () => {
44
+ const c = await completionCandidates('5', ['dataset', 'get', '.', 'dev.greet', '--format', 'j']);
45
+ assert.deepStrictEqual(c, ['json']);
46
+ });
47
+ it('suggests repo seeds at the repo slot', async () => {
48
+ const c = await completionCandidates('2', ['dataset', 'get', '']);
49
+ assert.ok(c.includes('.'));
50
+ assert.ok(c.includes('http://'));
51
+ assert.ok(c.includes('https://'));
52
+ });
53
+ it('filters repo seeds by prefix', async () => {
54
+ const c = await completionCandidates('2', ['dataset', 'get', 'http']);
55
+ assert.deepStrictEqual(c.sort(), ['http://', 'https://']);
56
+ });
57
+ it('returns empty when no rule matches a position', async () => {
58
+ // cword beyond known shape and no special rule
59
+ const c = await completionCandidates('5', ['convert', 'file.east', '--from', 'east', '--to', '']);
60
+ assert.deepStrictEqual(c, []);
61
+ });
62
+ });
63
+ //# sourceMappingURL=complete.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"complete.spec.js","sourceRoot":"","sources":["../../../src/commands/complete.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ export type SupportedShell = 'bash' | 'zsh' | 'fish';
6
+ interface InstallOptions {
7
+ shell?: string;
8
+ quiet?: boolean;
9
+ }
10
+ interface UninstallOptions {
11
+ shell?: string;
12
+ }
13
+ /**
14
+ * Detect the user's interactive shell from $SHELL.
15
+ *
16
+ * Returns `null` when $SHELL is unset or unrecognised.
17
+ */
18
+ export declare function detectShell(env?: NodeJS.ProcessEnv): SupportedShell | null;
19
+ /**
20
+ * Resolve the file to edit for a given shell.
21
+ *
22
+ * bash → ~/.bashrc, zsh → ~/.zshrc (honouring $ZDOTDIR),
23
+ * fish → ~/.config/fish/completions/e3.fish (a file, not appended to rc).
24
+ */
25
+ export declare function rcPath(shell: SupportedShell, env?: NodeJS.ProcessEnv, home?: string): string;
26
+ /**
27
+ * Install completion for the chosen (or detected) shell.
28
+ *
29
+ * Behaviour matrix:
30
+ * - fish : writes ~/.config/fish/completions/e3.fish (overwrites)
31
+ * - bash : appends `eval "$(e3 completion bash)" {MARKER}` to ~/.bashrc
32
+ * - zsh : same as bash but for ~/.zshrc
33
+ *
34
+ * Both bash and zsh paths short-circuit if the marker is already present, so
35
+ * re-running this command is a no-op.
36
+ */
37
+ export declare function installCommand(options?: InstallOptions): void;
38
+ /** Pure helper for install — exposed for tests via a real filesystem path. */
39
+ export declare function installToFile(shell: SupportedShell, target: string): string;
40
+ /**
41
+ * Uninstall completion for the chosen (or detected) shell.
42
+ */
43
+ export declare function uninstallCommand(options?: UninstallOptions): void;
44
+ /** Pure helper for uninstall — exposed for tests. */
45
+ export declare function uninstallFromFile(shell: SupportedShell, target: string): string;
46
+ export {};
47
+ //# sourceMappingURL=completion-install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion-install.d.ts","sourceRoot":"","sources":["../../../src/commands/completion-install.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAwBH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;AAKrD,UAAU,cAAc;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,UAAU,gBAAgB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,cAAc,GAAG,IAAI,CAQvF;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,EAAE,IAAI,GAAE,MAAkB,GAAG,MAAM,CASpH;AAgBD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,cAAmB,GAAG,IAAI,CAWjE;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAiB3E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,gBAAqB,GAAG,IAAI,CAQrE;AAED,qDAAqD;AACrD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAqB/E"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * `e3 completion install` / `e3 completion uninstall`.
7
+ *
8
+ * Edits the user's shell rc file (bash, zsh) or writes a completion file (fish).
9
+ * Idempotent: re-running `install` doesn't duplicate the eval line; `uninstall`
10
+ * removes only the marker line we control.
11
+ *
12
+ * Used by the `postinstall` hook on `npm install -g` and by `make link`.
13
+ */
14
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync, } from 'node:fs';
15
+ import { homedir } from 'node:os';
16
+ import { dirname, join } from 'node:path';
17
+ import { COMPLETION_SCRIPTS } from './completion.js';
18
+ import { exitError, formatError } from '../utils.js';
19
+ const MARKER = '# e3 completion';
20
+ const SHELLS = ['bash', 'zsh', 'fish'];
21
+ /**
22
+ * Detect the user's interactive shell from $SHELL.
23
+ *
24
+ * Returns `null` when $SHELL is unset or unrecognised.
25
+ */
26
+ export function detectShell(env = process.env) {
27
+ const shell = env.SHELL;
28
+ if (!shell)
29
+ return null;
30
+ const basename = shell.split('/').pop() ?? '';
31
+ if (basename === 'bash')
32
+ return 'bash';
33
+ if (basename === 'zsh')
34
+ return 'zsh';
35
+ if (basename === 'fish')
36
+ return 'fish';
37
+ return null;
38
+ }
39
+ /**
40
+ * Resolve the file to edit for a given shell.
41
+ *
42
+ * bash → ~/.bashrc, zsh → ~/.zshrc (honouring $ZDOTDIR),
43
+ * fish → ~/.config/fish/completions/e3.fish (a file, not appended to rc).
44
+ */
45
+ export function rcPath(shell, env = process.env, home = homedir()) {
46
+ switch (shell) {
47
+ case 'bash':
48
+ return join(home, '.bashrc');
49
+ case 'zsh':
50
+ return env.ZDOTDIR ? join(env.ZDOTDIR, '.zshrc') : join(home, '.zshrc');
51
+ case 'fish':
52
+ return join(home, '.config', 'fish', 'completions', 'e3.fish');
53
+ }
54
+ }
55
+ function resolveShell(shell) {
56
+ if (shell !== undefined) {
57
+ if (!SHELLS.includes(shell)) {
58
+ exitError(`Unknown shell: '${shell}'. Use one of: ${SHELLS.join(', ')}`);
59
+ }
60
+ return shell;
61
+ }
62
+ const detected = detectShell();
63
+ if (detected)
64
+ return detected;
65
+ exitError(`Could not detect shell from $SHELL. Specify explicitly with --shell ${SHELLS.join('|')}`);
66
+ }
67
+ /**
68
+ * Install completion for the chosen (or detected) shell.
69
+ *
70
+ * Behaviour matrix:
71
+ * - fish : writes ~/.config/fish/completions/e3.fish (overwrites)
72
+ * - bash : appends `eval "$(e3 completion bash)" {MARKER}` to ~/.bashrc
73
+ * - zsh : same as bash but for ~/.zshrc
74
+ *
75
+ * Both bash and zsh paths short-circuit if the marker is already present, so
76
+ * re-running this command is a no-op.
77
+ */
78
+ export function installCommand(options = {}) {
79
+ try {
80
+ const shell = resolveShell(options.shell);
81
+ const target = rcPath(shell);
82
+ const result = installToFile(shell, target);
83
+ if (!options.quiet) {
84
+ console.log(result);
85
+ }
86
+ }
87
+ catch (err) {
88
+ exitError(formatError(err));
89
+ }
90
+ }
91
+ /** Pure helper for install — exposed for tests via a real filesystem path. */
92
+ export function installToFile(shell, target) {
93
+ if (shell === 'fish') {
94
+ mkdirSync(dirname(target), { recursive: true });
95
+ writeFileSync(target, COMPLETION_SCRIPTS.fish);
96
+ return `Installed fish completion: ${target}`;
97
+ }
98
+ const evalLine = `eval "$(e3 completion ${shell})" ${MARKER}`;
99
+ const content = existsSync(target) ? readFileSync(target, 'utf-8') : '';
100
+ if (content.includes(MARKER)) {
101
+ return `e3 completion already installed in ${target}`;
102
+ }
103
+ const sep = content.length === 0 || content.endsWith('\n') ? '' : '\n';
104
+ writeFileSync(target, `${content}${sep}${evalLine}\n`);
105
+ return `Installed ${shell} completion in ${target}\nRestart your shell, or run: source ${target}`;
106
+ }
107
+ /**
108
+ * Uninstall completion for the chosen (or detected) shell.
109
+ */
110
+ export function uninstallCommand(options = {}) {
111
+ try {
112
+ const shell = resolveShell(options.shell);
113
+ const target = rcPath(shell);
114
+ console.log(uninstallFromFile(shell, target));
115
+ }
116
+ catch (err) {
117
+ exitError(formatError(err));
118
+ }
119
+ }
120
+ /** Pure helper for uninstall — exposed for tests. */
121
+ export function uninstallFromFile(shell, target) {
122
+ if (shell === 'fish') {
123
+ if (!existsSync(target)) {
124
+ return `No completion file at ${target}`;
125
+ }
126
+ unlinkSync(target);
127
+ return `Removed ${target}`;
128
+ }
129
+ if (!existsSync(target)) {
130
+ return `No rc file at ${target}`;
131
+ }
132
+ const content = readFileSync(target, 'utf-8');
133
+ const lines = content.split('\n');
134
+ const filtered = lines.filter((l) => !l.includes(MARKER));
135
+ if (filtered.length === lines.length) {
136
+ return `e3 completion not present in ${target}`;
137
+ }
138
+ writeFileSync(target, filtered.join('\n'));
139
+ return `Removed e3 completion from ${target}`;
140
+ }
141
+ //# sourceMappingURL=completion-install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion-install.js","sourceRoot":"","sources":["../../../src/commands/completion-install.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=completion-install.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion-install.spec.d.ts","sourceRoot":"","sources":["../../../src/commands/completion-install.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ import { describe, it, before, after } from 'node:test';
6
+ import assert from 'node:assert/strict';
7
+ import { mkdtempSync, rmSync, writeFileSync, readFileSync, existsSync } from 'node:fs';
8
+ import { tmpdir } from 'node:os';
9
+ import { join } from 'node:path';
10
+ import { detectShell, rcPath, installToFile, uninstallFromFile } from './completion-install.js';
11
+ let tmp;
12
+ before(() => {
13
+ tmp = mkdtempSync(join(tmpdir(), 'e3-completion-test-'));
14
+ });
15
+ after(() => {
16
+ rmSync(tmp, { recursive: true, force: true });
17
+ });
18
+ describe('detectShell', () => {
19
+ it('detects bash from /bin/bash', () => {
20
+ assert.strictEqual(detectShell({ SHELL: '/bin/bash' }), 'bash');
21
+ });
22
+ it('detects zsh from /usr/bin/zsh', () => {
23
+ assert.strictEqual(detectShell({ SHELL: '/usr/bin/zsh' }), 'zsh');
24
+ });
25
+ it('detects fish from /usr/local/bin/fish', () => {
26
+ assert.strictEqual(detectShell({ SHELL: '/usr/local/bin/fish' }), 'fish');
27
+ });
28
+ it('returns null for unknown shells', () => {
29
+ assert.strictEqual(detectShell({ SHELL: '/bin/dash' }), null);
30
+ });
31
+ it('returns null when SHELL is unset', () => {
32
+ assert.strictEqual(detectShell({}), null);
33
+ });
34
+ });
35
+ describe('rcPath', () => {
36
+ it('uses ~/.bashrc for bash', () => {
37
+ assert.strictEqual(rcPath('bash', {}, '/home/u'), '/home/u/.bashrc');
38
+ });
39
+ it('uses ~/.zshrc for zsh by default', () => {
40
+ assert.strictEqual(rcPath('zsh', {}, '/home/u'), '/home/u/.zshrc');
41
+ });
42
+ it('honours $ZDOTDIR for zsh', () => {
43
+ assert.strictEqual(rcPath('zsh', { ZDOTDIR: '/etc/zsh' }, '/home/u'), '/etc/zsh/.zshrc');
44
+ });
45
+ it('uses ~/.config/fish/completions/e3.fish for fish', () => {
46
+ assert.strictEqual(rcPath('fish', {}, '/home/u'), '/home/u/.config/fish/completions/e3.fish');
47
+ });
48
+ });
49
+ describe('installToFile — bash/zsh', () => {
50
+ it('appends the eval line when the file is missing', () => {
51
+ const target = join(tmp, 'fresh.bashrc');
52
+ const out = installToFile('bash', target);
53
+ assert.match(out, /Installed bash completion/);
54
+ const content = readFileSync(target, 'utf-8');
55
+ assert.match(content, /eval "\$\(e3 completion bash\)"/);
56
+ assert.match(content, /# e3 completion/);
57
+ });
58
+ it('appends to a non-empty file, preserving prior content', () => {
59
+ const target = join(tmp, 'existing.bashrc');
60
+ writeFileSync(target, '# my stuff\nalias ls="ls -lh"\n');
61
+ installToFile('bash', target);
62
+ const content = readFileSync(target, 'utf-8');
63
+ assert.ok(content.startsWith('# my stuff\nalias ls="ls -lh"\n'));
64
+ assert.match(content, /eval "\$\(e3 completion bash\)"/);
65
+ });
66
+ it('is idempotent — re-running does not duplicate the eval line', () => {
67
+ const target = join(tmp, 'idem.bashrc');
68
+ installToFile('bash', target);
69
+ installToFile('bash', target);
70
+ const content = readFileSync(target, 'utf-8');
71
+ const evalLines = content.split('\n').filter((l) => l.startsWith('eval "$(e3 completion'));
72
+ assert.strictEqual(evalLines.length, 1);
73
+ });
74
+ it('handles files missing a trailing newline', () => {
75
+ const target = join(tmp, 'no-newline.bashrc');
76
+ writeFileSync(target, 'export FOO=1');
77
+ installToFile('bash', target);
78
+ const content = readFileSync(target, 'utf-8');
79
+ assert.match(content, /export FOO=1\neval/);
80
+ });
81
+ });
82
+ describe('installToFile — fish', () => {
83
+ it('writes the completion file', () => {
84
+ const target = join(tmp, 'fish', 'completions', 'e3.fish');
85
+ const out = installToFile('fish', target);
86
+ assert.match(out, /Installed fish completion/);
87
+ assert.ok(existsSync(target));
88
+ const content = readFileSync(target, 'utf-8');
89
+ assert.match(content, /e3 fish completion/);
90
+ });
91
+ it('overwrites an existing file (no idempotency drama)', () => {
92
+ const target = join(tmp, 'fish2', 'completions', 'e3.fish');
93
+ installToFile('fish', target);
94
+ const first = readFileSync(target, 'utf-8');
95
+ installToFile('fish', target);
96
+ const second = readFileSync(target, 'utf-8');
97
+ assert.strictEqual(first, second);
98
+ });
99
+ });
100
+ describe('uninstallFromFile — bash/zsh', () => {
101
+ it('removes the marker line, leaving other content', () => {
102
+ const target = join(tmp, 'uninst.bashrc');
103
+ writeFileSync(target, '# my stuff\n');
104
+ installToFile('bash', target);
105
+ uninstallFromFile('bash', target);
106
+ const content = readFileSync(target, 'utf-8');
107
+ assert.match(content, /# my stuff/);
108
+ assert.doesNotMatch(content, /e3 completion/);
109
+ });
110
+ it('returns a "not present" message when marker missing', () => {
111
+ const target = join(tmp, 'clean.bashrc');
112
+ writeFileSync(target, '# nothing here\n');
113
+ const out = uninstallFromFile('bash', target);
114
+ assert.match(out, /not present/);
115
+ });
116
+ it('returns a "no rc file" message when file is missing', () => {
117
+ const target = join(tmp, 'does-not-exist');
118
+ const out = uninstallFromFile('bash', target);
119
+ assert.match(out, /No rc file/);
120
+ });
121
+ });
122
+ describe('uninstallFromFile — fish', () => {
123
+ it('removes the completion file when it exists', () => {
124
+ const target = join(tmp, 'fish3', 'completions', 'e3.fish');
125
+ installToFile('fish', target);
126
+ const out = uninstallFromFile('fish', target);
127
+ assert.match(out, /Removed/);
128
+ assert.ok(!existsSync(target));
129
+ });
130
+ it('returns a "no file" message when nothing to remove', () => {
131
+ const target = join(tmp, 'fish4', 'completions', 'e3.fish');
132
+ const out = uninstallFromFile('fish', target);
133
+ assert.match(out, /No completion file/);
134
+ });
135
+ });
136
+ //# sourceMappingURL=completion-install.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion-install.spec.js","sourceRoot":"","sources":["../../../src/commands/completion-install.spec.ts"],"names":[],"mappings":"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"}