scai 0.1.139 → 0.1.140

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/README.md CHANGED
@@ -92,9 +92,10 @@ scai shell
92
92
 
93
93
  Once in the REPL, you can:
94
94
 
95
- ### Ask questions about your codebase
95
+ ### Ask questions about your codebase. Be specific for better results.
96
96
 
97
97
  ```text
98
+ scai> what does withContext function do in index.ts file?
98
99
  scai> How many functions in config.js are missing tests?
99
100
  scai> Write me comprehensive comments for componentMap.js and typescript.ts files
100
101
  scai> Summarize utils/helpers.ts
@@ -32,12 +32,12 @@ or modifications in the system to achieve the intended task.
32
32
  Intent / task description:
33
33
  ${intentText}
34
34
 
35
- Allowed actions (transformation only):
36
- ${actionsJson}
37
-
38
35
  Task category:
39
36
  ${intentCategory}
40
37
 
38
+ Allowed actions (transformation only):
39
+ ${actionsJson}
40
+
41
41
  Existing relevant files:
42
42
  ${JSON.stringify(context.analysis.focus?.relevantFiles ?? {}, null, 2)}
43
43
 
@@ -49,7 +49,6 @@ Only perform transformations that are safe based on the existing analysis.
49
49
 
50
50
  ⚡ Phase guidance:
51
51
  - Only include transform steps in this phase.
52
- - Include a 'writeFile' step for each 'codeTransform' to persist changes to disk.
53
52
  - Each step must include: "action", "targetFile" (optional), "description", "metadata"
54
53
 
55
54
  ❌ IMPORTANT: Do NOT include "info" steps here.
@@ -6,7 +6,13 @@ import { LOG_PATH, PID_PATH, CONFIG_LOCK_PATH } from '../constants.js';
6
6
  import { Config } from '../config.js';
7
7
  import { getDbPathForRepo } from '../db/client.js';
8
8
  // --- Helpers ---
9
- function isProcessRunning(pid) {
9
+ export function isDaemonRunning() {
10
+ if (!fs.existsSync(PID_PATH))
11
+ return false;
12
+ const pid = parseInt(fs.readFileSync(PID_PATH, 'utf8'), 10);
13
+ return isProcessRunning(pid);
14
+ }
15
+ export function isProcessRunning(pid) {
10
16
  try {
11
17
  process.kill(pid, 0);
12
18
  return true;
@@ -23,7 +29,7 @@ function unlockConfigFile() {
23
29
  fs.unlinkSync(CONFIG_LOCK_PATH);
24
30
  }
25
31
  }
26
- function getLockedRepo() {
32
+ export function getLockedRepo() {
27
33
  return fs.existsSync(CONFIG_LOCK_PATH)
28
34
  ? fs.readFileSync(CONFIG_LOCK_PATH, 'utf8')
29
35
  : null;
@@ -32,39 +32,46 @@ export async function runInteractiveSwitch() {
32
32
  console.log('⚠️ No repositories configured.');
33
33
  return;
34
34
  }
35
- // Auto-switch to the other repo if only 2 are present
36
- if (keys.length === 2) {
37
- const current = config.activeRepo;
38
- const other = keys.find(k => k !== current);
39
- if (other) {
40
- runSwitchCommand(other);
41
- return;
42
- }
43
- }
44
35
  // Otherwise, show interactive selection
45
36
  console.log('\n📁 Available Repositories:\n');
37
+ console.log('\n📁 Available Repositories:\n');
46
38
  keys.forEach((key, i) => {
47
39
  const isActive = config.activeRepo === key ? chalk.green('(active)') : '';
48
40
  const dir = config.repos[key]?.indexDir ?? '';
49
- // Color the number using chalk.blue and make active repo green
50
- const numberedRepo = chalk.blue(`${i + 1})`);
51
- // Highlight the active repo in green and list it
52
- console.log(`${numberedRepo} ${key} ${isActive}`);
53
- // Use light grey for the indexDir
41
+ console.log(`${chalk.blue(`${i + 1})`)} ${key} ${isActive}`);
54
42
  console.log(` ↳ ${chalk.grey(dir)}`);
55
43
  });
44
+ console.log(chalk.yellow(`\n0) Cancel`));
56
45
  const rl = readline.createInterface({
57
46
  input: process.stdin,
58
47
  output: process.stdout,
59
48
  });
60
49
  rl.question('\n👉 Select a repository number to activate: ', (answer) => {
61
50
  rl.close();
62
- const index = parseInt(answer.trim(), 10) - 1;
51
+ const choice = parseInt(answer.trim(), 10);
52
+ if (choice === 0) {
53
+ console.log('ℹ️ Cancelled.');
54
+ return;
55
+ }
56
+ const index = choice - 1;
63
57
  if (isNaN(index) || index < 0 || index >= keys.length) {
64
58
  console.log('❌ Invalid selection.');
65
59
  return;
66
60
  }
67
- const selectedKey = keys[index];
68
- runSwitchCommand(selectedKey);
61
+ runSwitchCommand(keys[index]);
69
62
  });
70
63
  }
64
+ export async function statusIndex() {
65
+ const config = Config.getRaw();
66
+ const activeRepo = config.activeRepo;
67
+ if (!activeRepo) {
68
+ console.log(chalk.red('🔴 No active repository'));
69
+ console.log(' Run `scai index list` to select one');
70
+ return;
71
+ }
72
+ const repo = config.repos?.[activeRepo];
73
+ const dir = repo?.indexDir ?? '(unknown path)';
74
+ console.log(chalk.green('🟢 Active repository'));
75
+ console.log(` ↳ ${activeRepo}`);
76
+ console.log(` ↳ ${dir}`);
77
+ }
@@ -11,7 +11,7 @@ import { promptForToken } from '../github/token.js';
11
11
  import { validateGitHubTokenAgainstRepo } from '../github/githubAuthCheck.js';
12
12
  import { runWorkflowCommand } from './WorkflowCmd.js';
13
13
  import { handleStandaloneChangelogUpdate } from './ChangeLogUpdateCmd.js';
14
- import { runInteractiveSwitch } from './SwitchCmd.js';
14
+ import { runInteractiveSwitch, runSwitchCommand, statusIndex } from './SwitchCmd.js';
15
15
  import { runInteractiveDelete } from './DeleteIndex.js';
16
16
  import { startDaemon, stopDaemon, restartDaemon, statusDaemon, unlockConfig, showLogs } from './DaemonCmd.js';
17
17
  import { Config } from '../config.js';
@@ -24,6 +24,7 @@ import { runBackupCommand } from './BackupCmd.js';
24
24
  import { updateContext } from '../context.js';
25
25
  import { createRequire } from 'module';
26
26
  import { runTasksCommand } from './TasksCmd.js';
27
+ import { getRepoKeyForPath } from '../utils/contentUtils.js';
27
28
  const require = createRequire(import.meta.url);
28
29
  const { version } = require('../../package.json');
29
30
  export async function withContext(action) {
@@ -201,14 +202,36 @@ export function createProgram() {
201
202
  await Config.setIndexDir(dir);
202
203
  Config.show();
203
204
  });
204
- index
205
- .command('list')
206
- .description('List all indexed repositories')
207
- .action(async () => await withContext(async () => { await Config.printAllRepos(); }));
208
205
  index
209
206
  .command('switch')
210
- .description('Switch active repository interactively')
211
- .action(async () => await withContext(runInteractiveSwitch));
207
+ .description('Switch active repo to the one for the current directory')
208
+ .action(async () => {
209
+ const config = Config.getRaw();
210
+ const cwd = process.cwd();
211
+ const repoKey = getRepoKeyForPath(cwd, config);
212
+ if (!repoKey) {
213
+ console.log(`❌ This directory is not an indexed repository.`);
214
+ console.log(``);
215
+ console.log(`• To see indexed repos: scai index list`);
216
+ console.log(`• To index this repo: scai index set`);
217
+ process.exit(1);
218
+ }
219
+ await withContext(async () => {
220
+ runSwitchCommand(repoKey);
221
+ });
222
+ });
223
+ index
224
+ .command('status')
225
+ .description('Show active indexed repository')
226
+ .action(async () => {
227
+ await statusIndex();
228
+ });
229
+ index
230
+ .command('list')
231
+ .description('List indexed repositories and select one')
232
+ .action(async () => withContext(async () => {
233
+ await runInteractiveSwitch();
234
+ }));
212
235
  index
213
236
  .command('delete')
214
237
  .description('Delete repository interactively')
package/dist/index.js CHANGED
@@ -10,6 +10,8 @@ const shellQuote = require('shell-quote');
10
10
  import { createProgram as cmdFactory, withContext } from './commands/factory.js';
11
11
  import { runAskCommand } from './commands/AskCmd.js';
12
12
  import enquirer from 'enquirer';
13
+ import { getLockedRepo, isDaemonRunning, startDaemon, stopDaemon } from './commands/DaemonCmd.js';
14
+ import { Config } from './config.js';
13
15
  const { prompt } = enquirer;
14
16
  const program = cmdFactory();
15
17
  const customCommands = {};
@@ -37,8 +39,29 @@ const testQueries = [
37
39
  function pickRandom(items) {
38
40
  return items[Math.floor(Math.random() * items.length)];
39
41
  }
42
+ // ---------------- Run Query with Context ----------------
43
+ // The withContext function is a utility that wraps async operations with context handling.
44
+ // It ensures that asynchronous operations are executed within a specific execution context,
45
+ // which is crucial for managing state, configuration, or environment settings during CLI operations.
46
+ // This function is used to properly manage the execution context when running queries or commands.
40
47
  async function runQuery(query) {
41
- await withContext(() => runAskCommand(query));
48
+ const cfg = Config.getRaw();
49
+ const activeRepo = cfg.activeRepo;
50
+ const lockedRepo = getLockedRepo();
51
+ const shouldPauseDaemon = isDaemonRunning() &&
52
+ activeRepo &&
53
+ lockedRepo === activeRepo;
54
+ if (shouldPauseDaemon) {
55
+ await stopDaemon();
56
+ }
57
+ try {
58
+ await withContext(() => runAskCommand(query));
59
+ }
60
+ finally {
61
+ if (shouldPauseDaemon) {
62
+ await startDaemon();
63
+ }
64
+ }
42
65
  }
43
66
  // ---------------- Built-in Commands ----------------
44
67
  customCommands.clear = async () => {
@@ -88,6 +111,10 @@ function editInEditorAsync(initialContent = '') {
88
111
  });
89
112
  }
90
113
  // ---------------- REPL / Shell ----------------
114
+ // The startShell function initializes an interactive shell for the CLI.
115
+ // It allows users to input queries directly, use built-in commands with '/',
116
+ // run terminal commands with '!', or edit input in an external editor with '/edit'.
117
+ // It uses withContext to ensure proper execution context for each command or query.
91
118
  async function startShell() {
92
119
  console.log(chalk.yellow("Welcome to SCAI shell!") + "\n" +
93
120
  chalk.blueBright(`- Type your query directly for short commands or questions.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scai",
3
- "version": "0.1.139",
3
+ "version": "0.1.140",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "scai": "./dist/index.js"