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 +2 -1
- package/dist/agents/transformPlanGenStep.js +3 -4
- package/dist/commands/DaemonCmd.js +8 -2
- package/dist/commands/SwitchCmd.js +24 -17
- package/dist/commands/factory.js +30 -7
- package/dist/index.js +28 -1
- package/package.json +1 -1
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
+
}
|
package/dist/commands/factory.js
CHANGED
|
@@ -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
|
|
211
|
-
.action(async () =>
|
|
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
|
-
|
|
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.
|