codeant-cli 0.3.9 → 0.4.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeant-cli",
3
- "version": "0.3.9",
3
+ "version": "0.4.1",
4
4
  "description": "Code review CLI tool",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,30 @@
1
+ import React, { useEffect } from 'react';
2
+ import { Text, Box, useApp } from 'ink';
3
+ import { getConfigValue } from '../utils/config.js';
4
+
5
+ export default function GetApiKey() {
6
+ const { exit } = useApp();
7
+
8
+ const apiKey = getConfigValue('apiKeyV2');
9
+
10
+ useEffect(() => {
11
+ exit();
12
+ }, []);
13
+
14
+ if (!apiKey) {
15
+ return React.createElement(
16
+ Box,
17
+ { flexDirection: 'column', padding: 1 },
18
+ React.createElement(Text, { color: 'yellow' }, 'No CodeAnt API key configured.'),
19
+ React.createElement(Text, { color: 'gray' }, 'Set one with: codeant set-codeant-api-key <key>')
20
+ );
21
+ }
22
+
23
+ const masked = apiKey.slice(0, 4) + '…' + apiKey.slice(-4);
24
+
25
+ return React.createElement(
26
+ Box,
27
+ { flexDirection: 'column', padding: 1 },
28
+ React.createElement(Text, { bold: true }, 'CodeAnt API Key: ', masked)
29
+ );
30
+ }
@@ -0,0 +1,37 @@
1
+ import React, { useEffect } from 'react';
2
+ import { Text, Box, useApp } from 'ink';
3
+ import { setConfigValue, CONFIG_FILE } from '../utils/config.js';
4
+
5
+ export default function SetApiKey({ apiKey }) {
6
+ const { exit } = useApp();
7
+
8
+ useEffect(() => {
9
+ if (!apiKey) {
10
+ exit(new Error('API key is required'));
11
+ return;
12
+ }
13
+
14
+ try {
15
+ setConfigValue('apiKeyV2', apiKey);
16
+ exit();
17
+ } catch (err) {
18
+ exit(err);
19
+ }
20
+ }, []);
21
+
22
+ if (!apiKey) {
23
+ return React.createElement(
24
+ Box,
25
+ { flexDirection: 'column', padding: 1 },
26
+ React.createElement(Text, { color: 'red' }, '✗ Error: API key is required'),
27
+ React.createElement(Text, { color: 'gray' }, 'Usage: codeant set-codeant-api-key <key>')
28
+ );
29
+ }
30
+
31
+ return React.createElement(
32
+ Box,
33
+ { flexDirection: 'column', padding: 1 },
34
+ React.createElement(Text, { color: 'green' }, '✓ CodeAnt API key saved.'),
35
+ React.createElement(Text, { color: 'gray' }, 'Saved to: ', CONFIG_FILE)
36
+ );
37
+ }
package/src/index.js CHANGED
@@ -7,6 +7,8 @@ import { createRequire } from 'module';
7
7
  import Secrets from './commands/secrets.js';
8
8
  import SetBaseUrl from './commands/setBaseUrl.js';
9
9
  import GetBaseUrl from './commands/getBaseUrl.js';
10
+ import SetApiKey from './commands/setApiKey.js';
11
+ import GetApiKey from './commands/getApiKey.js';
10
12
  import Login from './commands/login.js';
11
13
  import Logout from './commands/logout.js';
12
14
  import Review from './commands/review.js';
@@ -183,6 +185,20 @@ program
183
185
  render(React.createElement(GetBaseUrl));
184
186
  });
185
187
 
188
+ program
189
+ .command('set-codeant-api-key <key>')
190
+ .description('Set the CodeAnt API key')
191
+ .action((key) => {
192
+ render(React.createElement(SetApiKey, { apiKey: key }));
193
+ });
194
+
195
+ program
196
+ .command('get-codeant-api-key')
197
+ .description('Show the current CodeAnt API key')
198
+ .action(() => {
199
+ render(React.createElement(GetApiKey));
200
+ });
201
+
186
202
  program
187
203
  .command('login')
188
204
  .description('Login to CodeAnt')
@@ -8,16 +8,31 @@ const HOOK_MARKER_END = '# end-codeant-push-protection';
8
8
  /**
9
9
  * Build the full pre-push hook script (with shebang).
10
10
  */
11
- function buildHookScript() {
11
+ function buildHookScript(cliPath) {
12
12
  return `#!/bin/sh
13
- ${buildHookBlock()}
13
+ ${buildHookBlock(cliPath)}
14
14
  `;
15
15
  }
16
16
 
17
17
  /**
18
18
  * Build just the CodeAnt block (no shebang), used when appending to an existing hook.
19
+ * If cliPath is provided, uses the absolute path to the extension-bundled CLI via node.
20
+ * Otherwise falls back to the global `codeant` command.
19
21
  */
20
- function buildHookBlock() {
22
+ function buildHookBlock(cliPath) {
23
+ if (cliPath) {
24
+ return `${HOOK_MARKER}
25
+ # Auto-installed by CodeAnt AI — blocks pushes containing secrets.
26
+ # To disable: delete this hook or run "codeant push-protection disable"
27
+ # Uses the CLI bundled with the VS Code extension.
28
+ if [ -f "${cliPath}" ]; then
29
+ node "${cliPath}" secrets --committed --hook
30
+ else
31
+ command -v codeant >/dev/null 2>&1 || exit 0
32
+ codeant secrets --committed --hook
33
+ fi
34
+ ${HOOK_MARKER_END}`;
35
+ }
21
36
  return `${HOOK_MARKER}
22
37
  # Auto-installed by CodeAnt AI — blocks pushes containing secrets.
23
38
  # To disable: delete this hook or run "codeant push-protection disable"
@@ -81,9 +96,10 @@ function getHooksDir(gitRoot) {
81
96
  * Install a pre-push hook that runs secret scanning before push.
82
97
  *
83
98
  * @param {string} workspacePath - Path to the git repository
99
+ * @param {string} [cliPath] - Absolute path to the codeant CLI entry point (from extension node_modules)
84
100
  * @returns {{ installed: boolean, hookPath: string|null, message: string }}
85
101
  */
86
- export function installPushProtectionHook(workspacePath) {
102
+ export function installPushProtectionHook(workspacePath, cliPath) {
87
103
  const gitRoot = findGitRoot(workspacePath);
88
104
  if (!gitRoot) {
89
105
  return { installed: false, hookPath: null, message: 'Not a git repository' };
@@ -100,7 +116,7 @@ export function installPushProtectionHook(workspacePath) {
100
116
  const existing = readFileSync(hookPath, 'utf-8');
101
117
  if (existing.includes(HOOK_MARKER)) {
102
118
  // Replace only our block, preserve everything else
103
- const updated = replaceCodeAntBlock(existing, buildHookBlock());
119
+ const updated = replaceCodeAntBlock(existing, buildHookBlock(cliPath));
104
120
  writeFileSync(hookPath, updated, 'utf-8');
105
121
  chmodSync(hookPath, 0o755);
106
122
  return { installed: true, hookPath, message: 'Hook updated' };
@@ -111,13 +127,13 @@ export function installPushProtectionHook(workspacePath) {
111
127
  if (!isShellHook) {
112
128
  return { installed: false, hookPath, message: 'Existing pre-push hook is non-shell; cannot append CodeAnt block safely' };
113
129
  }
114
- const appended = existing.trimEnd() + '\n\n' + buildHookBlock() + '\n';
130
+ const appended = existing.trimEnd() + '\n\n' + buildHookBlock(cliPath) + '\n';
115
131
  writeFileSync(hookPath, appended, 'utf-8');
116
132
  chmodSync(hookPath, 0o755);
117
133
  return { installed: true, hookPath, message: 'Hook appended to existing pre-push' };
118
134
  }
119
135
 
120
- writeFileSync(hookPath, buildHookScript(), 'utf-8');
136
+ writeFileSync(hookPath, buildHookScript(cliPath), 'utf-8');
121
137
  chmodSync(hookPath, 0o755);
122
138
  return { installed: true, hookPath, message: 'Hook installed' };
123
139
  }