@latentforce/shift 1.0.8 → 1.0.9
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 +69 -25
- package/build/cli/commands/init.js +76 -58
- package/build/cli/commands/start.js +32 -69
- package/build/cli/commands/status.js +17 -7
- package/build/cli/commands/update-drg.js +175 -0
- package/build/daemon/tools-executor.js +19 -86
- package/build/index.js +38 -4
- package/build/mcp-server.js +105 -8
- package/build/utils/api-client.js +70 -35
- package/build/utils/auth-resolver.js +184 -0
- package/build/utils/prompts.js +45 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,15 +10,31 @@ npm install -g @latentforce/shift
|
|
|
10
10
|
|
|
11
11
|
## Quick Start
|
|
12
12
|
|
|
13
|
-
###
|
|
13
|
+
### Guest mode (zero-config)
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
cd /path/to/your/project
|
|
17
|
-
shift-cli
|
|
17
|
+
shift-cli init --guest # Auto-creates guest key + project, scans, and indexes
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### With an API key
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# Create a new project and index it (prompts for template selection)
|
|
24
|
+
shift-cli init --api-key YOUR_KEY --project-name "My App"
|
|
25
|
+
|
|
26
|
+
# Fully non-interactive (CI/CD friendly)
|
|
27
|
+
shift-cli init --api-key YOUR_KEY --project-name "My App" --template TEMPLATE_ID
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Interactive (original behavior)
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
shift-cli start # Configure API key and project interactively
|
|
18
34
|
shift-cli init # Index project files
|
|
19
35
|
```
|
|
20
36
|
|
|
21
|
-
###
|
|
37
|
+
### Add to Claude Code
|
|
22
38
|
|
|
23
39
|
```bash
|
|
24
40
|
claude mcp add-json shift '{"type":"stdio","command":"shift-cli","args":["mcp"],"env":{"SHIFT_PROJECT_ID":"YOUR_PROJECT_ID"}}'
|
|
@@ -30,7 +46,7 @@ Or using npx:
|
|
|
30
46
|
claude mcp add-json shift '{"type":"stdio","command":"npx","args":["@latentforce/shift","mcp"],"env":{"SHIFT_PROJECT_ID":"YOUR_PROJECT_ID"}}'
|
|
31
47
|
```
|
|
32
48
|
|
|
33
|
-
###
|
|
49
|
+
### Add to Claude Desktop
|
|
34
50
|
|
|
35
51
|
Add to your config file (`%APPDATA%\Claude\claude_desktop_config.json` on Windows, `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
|
|
36
52
|
|
|
@@ -48,39 +64,67 @@ Add to your config file (`%APPDATA%\Claude\claude_desktop_config.json` on Window
|
|
|
48
64
|
}
|
|
49
65
|
```
|
|
50
66
|
|
|
51
|
-
## MCP Tools
|
|
52
|
-
|
|
53
|
-
| Tool | Description |
|
|
54
|
-
|------|-------------|
|
|
55
|
-
| `blast_radius` | Analyze what would be affected if a file is modified |
|
|
56
|
-
| `dependencies` | Get all dependencies for a file |
|
|
57
|
-
| `file_summary` | Generate a summary of a file |
|
|
58
|
-
|
|
59
67
|
## CLI Commands
|
|
60
68
|
|
|
61
69
|
| Command | Description |
|
|
62
70
|
|---------|-------------|
|
|
63
71
|
| `shift-cli start` | Start daemon and configure project |
|
|
64
|
-
| `shift-cli init` |
|
|
72
|
+
| `shift-cli init` | Scan and index project files |
|
|
73
|
+
| `shift-cli update-drg` | Update the dependency relationship graph |
|
|
65
74
|
| `shift-cli stop` | Stop the daemon |
|
|
66
75
|
| `shift-cli status` | Show current status |
|
|
67
76
|
| `shift-cli config` | Manage configuration |
|
|
68
77
|
|
|
69
|
-
|
|
78
|
+
### CLI Flags
|
|
79
|
+
|
|
80
|
+
#### `shift-cli init`
|
|
81
|
+
|
|
82
|
+
| Flag | Description |
|
|
83
|
+
|------|-------------|
|
|
84
|
+
| `--guest` | Use guest authentication (auto-creates project) |
|
|
85
|
+
| `--api-key <key>` | Provide API key directly |
|
|
86
|
+
| `--project-name <name>` | Create new project or match existing by name |
|
|
87
|
+
| `--project-id <id>` | Use existing project UUID |
|
|
88
|
+
| `--template <id>` | Migration template ID for project creation |
|
|
89
|
+
| `-f, --force` | Force re-indexing even if already indexed |
|
|
70
90
|
|
|
71
|
-
|
|
91
|
+
#### `shift-cli start`
|
|
92
|
+
|
|
93
|
+
| Flag | Description |
|
|
94
|
+
|------|-------------|
|
|
95
|
+
| `--guest` | Use guest authentication (auto-creates project) |
|
|
96
|
+
| `--api-key <key>` | Provide API key directly |
|
|
97
|
+
| `--project-name <name>` | Create new project or match existing by name |
|
|
98
|
+
| `--project-id <id>` | Use existing project UUID |
|
|
99
|
+
| `--template <id>` | Migration template ID for project creation |
|
|
100
|
+
|
|
101
|
+
#### `shift-cli update-drg`
|
|
102
|
+
|
|
103
|
+
| Flag | Description |
|
|
104
|
+
|------|-------------|
|
|
105
|
+
| `-m, --mode <mode>` | `baseline` (all files) or `incremental` (git-changed only, default) |
|
|
106
|
+
|
|
107
|
+
### Update DRG
|
|
108
|
+
|
|
109
|
+
After initializing your project, update the dependency graph to keep code intelligence in sync:
|
|
72
110
|
|
|
73
111
|
```bash
|
|
74
|
-
shift-cli
|
|
75
|
-
shift-cli
|
|
76
|
-
shift-cli config set ws-url wss://your-orch.example.com
|
|
112
|
+
shift-cli update-drg # Incremental (default) — only git-changed files
|
|
113
|
+
shift-cli update-drg --mode baseline # Full re-scan of all JS/TS files
|
|
77
114
|
```
|
|
78
115
|
|
|
79
|
-
|
|
116
|
+
Scans `.js`, `.jsx`, `.ts`, `.tsx`, `.mjs`, `.cjs` files.
|
|
80
117
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
118
|
+
## MCP Tools
|
|
119
|
+
|
|
120
|
+
| Tool | Description |
|
|
121
|
+
|------|-------------|
|
|
122
|
+
| `blast_radius` | Analyze what files would be affected if a file is modified or deleted |
|
|
123
|
+
| `dependencies` | Get all dependencies for a file with relationship summaries |
|
|
124
|
+
| `file_summary` | Get a summary of a file with optional parent directory context |
|
|
125
|
+
|
|
126
|
+
Each tool accepts an optional `project_id` parameter. If not provided, it falls back to the `SHIFT_PROJECT_ID` environment variable.
|
|
127
|
+
|
|
128
|
+
MCP tools return formatted markdown and include:
|
|
129
|
+
- **Path normalization** — backslashes, leading `./` and `/` are handled automatically
|
|
130
|
+
- **Actionable error messages** — missing graph prompts you to run `update-drg`, missing files explain possible causes
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { exec } from 'child_process';
|
|
2
2
|
import { promisify } from 'util';
|
|
3
3
|
import { createInterface } from 'readline';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
4
|
+
import { createRequire } from 'module';
|
|
5
|
+
import { readProjectConfig, writeProjectConfig } from '../../utils/config.js';
|
|
6
|
+
import { fetchProjectStatus, sendInitScan } from '../../utils/api-client.js';
|
|
7
|
+
import { resolveApiKey, resolveProject } from '../../utils/auth-resolver.js';
|
|
8
|
+
import { getDaemonStatus, startDaemon } from '../../daemon/daemon-manager.js';
|
|
8
9
|
import { getProjectTree, extractAllFilePaths, categorizeFiles } from '../../utils/tree-scanner.js';
|
|
9
|
-
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
11
|
+
const { version } = require('../../../package.json');
|
|
10
12
|
const execAsync = promisify(exec);
|
|
11
13
|
/**
|
|
12
14
|
* Prompt user to confirm re-indexing an already indexed project
|
|
@@ -25,64 +27,64 @@ async function promptForReindex() {
|
|
|
25
27
|
}
|
|
26
28
|
export async function initCommand(options = {}) {
|
|
27
29
|
const projectRoot = process.cwd();
|
|
30
|
+
const isAuthInteractive = !options.guest && !options.apiKey;
|
|
31
|
+
const isProjectInteractive = !!(process.stdin.isTTY);
|
|
28
32
|
console.log('╔═══════════════════════════════════════════════╗');
|
|
29
33
|
console.log('║ Initializing Shift Project ║');
|
|
30
34
|
console.log('╚═══════════════════════════════════════════════╝\n');
|
|
31
|
-
// Step 1:
|
|
35
|
+
// Step 1: Resolve API key
|
|
32
36
|
console.log('[Init] Step 1/5: Checking API key...');
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
else {
|
|
42
|
-
console.log('\n[Init] Requesting guest session...');
|
|
43
|
-
try {
|
|
44
|
-
const guestResponse = await requestGuestKey();
|
|
45
|
-
setGuestKey(guestResponse.api_key);
|
|
46
|
-
apiKey = guestResponse.api_key;
|
|
47
|
-
console.log('[Init] ✓ Guest session started\n');
|
|
48
|
-
}
|
|
49
|
-
catch (error) {
|
|
50
|
-
console.error(`\n❌ Failed to get guest key: ${error.message}`);
|
|
51
|
-
process.exit(1);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
else if (isGuestKey()) {
|
|
56
|
-
console.log('[Init] ✓ Guest key found\n');
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
console.log('[Init] ✓ API key found\n');
|
|
60
|
-
}
|
|
61
|
-
// Step 2: Check project config
|
|
37
|
+
const authResult = await resolveApiKey({
|
|
38
|
+
guest: options.guest,
|
|
39
|
+
apiKey: options.apiKey,
|
|
40
|
+
interactive: isAuthInteractive,
|
|
41
|
+
commandLabel: 'Init',
|
|
42
|
+
});
|
|
43
|
+
const apiKey = authResult.apiKey;
|
|
44
|
+
// Step 2: Resolve project
|
|
62
45
|
console.log('[Init] Step 2/5: Checking project configuration...');
|
|
46
|
+
// If guest flow returned a project_id, save it before resolving
|
|
47
|
+
if (authResult.projectId && !readProjectConfig(projectRoot)) {
|
|
48
|
+
const { setProject } = await import('../../utils/config.js');
|
|
49
|
+
setProject(authResult.projectId, options.projectName || 'Guest Project', projectRoot);
|
|
50
|
+
}
|
|
51
|
+
const project = await resolveProject({
|
|
52
|
+
apiKey,
|
|
53
|
+
projectId: options.projectId,
|
|
54
|
+
projectName: options.projectName,
|
|
55
|
+
template: options.template,
|
|
56
|
+
interactive: isProjectInteractive,
|
|
57
|
+
commandLabel: 'Init',
|
|
58
|
+
projectRoot,
|
|
59
|
+
});
|
|
60
|
+
// Re-read project config (may have been written by resolveProject)
|
|
63
61
|
const projectConfig = readProjectConfig(projectRoot);
|
|
64
62
|
if (!projectConfig) {
|
|
65
|
-
console.error('\n❌
|
|
66
|
-
console.log('Run "shift start" first to configure the project.\n');
|
|
63
|
+
console.error('\n❌ Failed to configure project.');
|
|
67
64
|
process.exit(1);
|
|
68
65
|
}
|
|
69
|
-
console.log(`[Init] ✓ Project: ${projectConfig.project_name} (${projectConfig.project_id})\n`);
|
|
70
66
|
// Check if project is already indexed (skip check if --force flag is used)
|
|
71
67
|
if (!options.force) {
|
|
72
68
|
try {
|
|
73
|
-
const projectStatus = await fetchProjectStatus(apiKey,
|
|
69
|
+
const projectStatus = await fetchProjectStatus(apiKey, project.projectId);
|
|
74
70
|
if (projectStatus.indexed) {
|
|
75
71
|
console.log(`[Init] ✓ Project already indexed (${projectStatus.file_count} files)\n`);
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
72
|
+
if (isProjectInteractive) {
|
|
73
|
+
const shouldReindex = await promptForReindex();
|
|
74
|
+
if (!shouldReindex) {
|
|
75
|
+
console.log('\n╔═══════════════════════════════════════════════╗');
|
|
76
|
+
console.log('║ Project Already Initialized ║');
|
|
77
|
+
console.log('╚═══════════════════════════════════════════════╝');
|
|
78
|
+
console.log('\nUse "shift-cli status" to check the current status.');
|
|
79
|
+
console.log('Use "shift-cli init --force" to force re-indexing.\n');
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
console.log('\n[Init] Proceeding with re-indexing...\n');
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
console.log('[Init] Already indexed. Use --force to re-index.\n');
|
|
83
86
|
return;
|
|
84
87
|
}
|
|
85
|
-
console.log('\n[Init] Proceeding with re-indexing...\n');
|
|
86
88
|
}
|
|
87
89
|
}
|
|
88
90
|
catch {
|
|
@@ -93,14 +95,28 @@ export async function initCommand(options = {}) {
|
|
|
93
95
|
else {
|
|
94
96
|
console.log('[Init] Force flag detected, skipping indexing status check...\n');
|
|
95
97
|
}
|
|
96
|
-
// Step 3: Check daemon status
|
|
98
|
+
// Step 3: Check daemon status — start it automatically if not running
|
|
97
99
|
console.log('[Init] Step 3/5: Checking daemon status...');
|
|
98
|
-
const
|
|
99
|
-
if (!
|
|
100
|
-
console.log('[Init]
|
|
100
|
+
const daemonStatus = getDaemonStatus(projectRoot);
|
|
101
|
+
if (!daemonStatus.running) {
|
|
102
|
+
console.log('[Init] Daemon not running. Starting it...');
|
|
103
|
+
try {
|
|
104
|
+
const daemonResult = await startDaemon(projectRoot, project.projectId, apiKey);
|
|
105
|
+
if (daemonResult.success) {
|
|
106
|
+
console.log(`[Init] ✓ Daemon started (PID: ${daemonResult.pid})\n`);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
console.log(`[Init] ⚠️ Could not start daemon: ${daemonResult.error}`);
|
|
110
|
+
console.log('[Init] Continuing without daemon — run "shift-cli start" later.\n');
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
console.log(`[Init] ⚠️ Could not start daemon: ${err.message}`);
|
|
115
|
+
console.log('[Init] Continuing without daemon — run "shift-cli start" later.\n');
|
|
116
|
+
}
|
|
101
117
|
}
|
|
102
118
|
else {
|
|
103
|
-
console.log(`[Init] ✓ Daemon running (PID: ${
|
|
119
|
+
console.log(`[Init] ✓ Daemon running (PID: ${daemonStatus.pid}, Connected: ${daemonStatus.connected})\n`);
|
|
104
120
|
}
|
|
105
121
|
// Step 4: Scan project structure (matching extension's Step 6)
|
|
106
122
|
console.log('[Init] Step 4/5: Scanning project structure...');
|
|
@@ -150,7 +166,7 @@ export async function initCommand(options = {}) {
|
|
|
150
166
|
// Step 5: Send scan to backend (matching extension's Step 9)
|
|
151
167
|
console.log('[Init] Step 5/5: Sending scan to backend...');
|
|
152
168
|
const payload = {
|
|
153
|
-
project_id:
|
|
169
|
+
project_id: project.projectId,
|
|
154
170
|
project_tree: treeData,
|
|
155
171
|
git_info: gitInfo,
|
|
156
172
|
file_manifest: {
|
|
@@ -158,13 +174,13 @@ export async function initCommand(options = {}) {
|
|
|
158
174
|
categorized: categorized,
|
|
159
175
|
},
|
|
160
176
|
metadata: {
|
|
161
|
-
extension_version:
|
|
177
|
+
extension_version: `${version}-cli`,
|
|
162
178
|
scan_timestamp: new Date().toISOString(),
|
|
163
|
-
project_name:
|
|
179
|
+
project_name: project.projectName,
|
|
164
180
|
},
|
|
165
181
|
};
|
|
166
182
|
try {
|
|
167
|
-
const response = await sendInitScan(apiKey,
|
|
183
|
+
const response = await sendInitScan(apiKey, project.projectId, payload);
|
|
168
184
|
console.log('[Init] ✓ Backend initialization completed');
|
|
169
185
|
console.log(`[Init] Files read: ${response.files_read}`);
|
|
170
186
|
console.log(`[Init] Files failed: ${response.files_failed}`);
|
|
@@ -181,15 +197,17 @@ export async function initCommand(options = {}) {
|
|
|
181
197
|
writeProjectConfig(projectConfig, projectRoot);
|
|
182
198
|
console.log(`[Init] ✓ Agent info saved: ${agentInfo.agent_id}`);
|
|
183
199
|
}
|
|
200
|
+
if (response.files_read === 0 && response.files_failed > 0) {
|
|
201
|
+
console.log(`\n[Init] ⚠️ No files were read (${response.files_failed} failed).`);
|
|
202
|
+
}
|
|
184
203
|
console.log('\n╔═══════════════════════════════════════════════╗');
|
|
185
204
|
console.log('║ ✓ Project Initialization Complete ║');
|
|
186
205
|
console.log('╚═══════════════════════════════════════════════╝');
|
|
206
|
+
console.log('\nIndexing is running in the background. Use "shift-cli status" to check progress.');
|
|
187
207
|
if (response.next_steps) {
|
|
188
208
|
console.log('\nNext steps:');
|
|
189
209
|
response.next_steps.forEach((step) => console.log(` - ${step}`));
|
|
190
210
|
}
|
|
191
|
-
console.log('\nFile indexing has been triggered. This may take a few moments.');
|
|
192
|
-
console.log('Use "shift status" to check the daemon connection.\n');
|
|
193
211
|
}
|
|
194
212
|
catch (error) {
|
|
195
213
|
console.error(`\n❌ Failed to initialize project: ${error.message}`);
|
|
@@ -1,75 +1,38 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { promptApiKey, promptProjectId, promptSelectProject, promptKeyChoice } from '../../utils/prompts.js';
|
|
1
|
+
import { readProjectConfig, setProject } from '../../utils/config.js';
|
|
3
2
|
import { startDaemon, getDaemonStatus } from '../../daemon/daemon-manager.js';
|
|
4
|
-
import {
|
|
5
|
-
export async function startCommand() {
|
|
3
|
+
import { resolveApiKey, resolveProject } from '../../utils/auth-resolver.js';
|
|
4
|
+
export async function startCommand(options = {}) {
|
|
6
5
|
const projectRoot = process.cwd();
|
|
6
|
+
const isAuthInteractive = !options.guest && !options.apiKey;
|
|
7
|
+
const isProjectInteractive = !!(process.stdin.isTTY);
|
|
7
8
|
console.log('╔════════════════════════════════════════════╗');
|
|
8
9
|
console.log('║ Starting Shift ║');
|
|
9
10
|
console.log('╚════════════════════════════════════════════╝\n');
|
|
10
|
-
// Step 1:
|
|
11
|
+
// Step 1: Resolve API key
|
|
11
12
|
console.log('[Start] Step 1/4: Checking API key...');
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
else {
|
|
21
|
-
console.log('\n[Start] Requesting guest session...');
|
|
22
|
-
try {
|
|
23
|
-
const guestResponse = await requestGuestKey();
|
|
24
|
-
setGuestKey(guestResponse.api_key);
|
|
25
|
-
apiKey = guestResponse.api_key;
|
|
26
|
-
console.log('[Start] ✓ Guest session started\n');
|
|
27
|
-
}
|
|
28
|
-
catch (error) {
|
|
29
|
-
console.error(`\n❌ Failed to get guest key: ${error.message}`);
|
|
30
|
-
process.exit(1);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
else if (isGuestKey()) {
|
|
35
|
-
console.log('[Start] ✓ Guest key found\n');
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
console.log('[Start] ✓ API key found\n');
|
|
39
|
-
}
|
|
40
|
-
// Step 2: Check/create project config
|
|
13
|
+
const authResult = await resolveApiKey({
|
|
14
|
+
guest: options.guest,
|
|
15
|
+
apiKey: options.apiKey,
|
|
16
|
+
interactive: isAuthInteractive,
|
|
17
|
+
commandLabel: 'Start',
|
|
18
|
+
});
|
|
19
|
+
const apiKey = authResult.apiKey;
|
|
20
|
+
// Step 2: Resolve project
|
|
41
21
|
console.log('[Start] Step 2/4: Checking project configuration...');
|
|
42
|
-
|
|
43
|
-
if (!
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
setProject(selected.project_id, selected.project_name, projectRoot);
|
|
57
|
-
console.log(`[Start] ✓ Project "${selected.project_name}" saved to .shift/config.json\n`);
|
|
58
|
-
projectConfig = readProjectConfig(projectRoot);
|
|
59
|
-
}
|
|
60
|
-
catch (error) {
|
|
61
|
-
// If fetching fails, fall back to manual entry
|
|
62
|
-
console.error(`\n⚠️ Could not fetch projects: ${error.message}`);
|
|
63
|
-
console.log('Falling back to manual project ID entry...\n');
|
|
64
|
-
const projectId = await promptProjectId();
|
|
65
|
-
setProject(projectId, 'Unknown Project', projectRoot);
|
|
66
|
-
console.log(`[Start] ✓ Project ID saved to .shift/config.json\n`);
|
|
67
|
-
projectConfig = readProjectConfig(projectRoot);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
console.log(`[Start] ✓ Project found: ${projectConfig.project_name} (${projectConfig.project_id})\n`);
|
|
72
|
-
}
|
|
22
|
+
// If guest flow returned a project_id, save it before resolving
|
|
23
|
+
if (authResult.projectId && !readProjectConfig(projectRoot)) {
|
|
24
|
+
setProject(authResult.projectId, options.projectName || 'Guest Project', projectRoot);
|
|
25
|
+
}
|
|
26
|
+
const project = await resolveProject({
|
|
27
|
+
apiKey,
|
|
28
|
+
projectId: options.projectId,
|
|
29
|
+
projectName: options.projectName,
|
|
30
|
+
template: options.template,
|
|
31
|
+
interactive: isProjectInteractive,
|
|
32
|
+
commandLabel: 'Start',
|
|
33
|
+
projectRoot,
|
|
34
|
+
});
|
|
35
|
+
const projectConfig = readProjectConfig(projectRoot);
|
|
73
36
|
if (!projectConfig) {
|
|
74
37
|
console.error('❌ Failed to configure project');
|
|
75
38
|
process.exit(1);
|
|
@@ -85,7 +48,7 @@ export async function startCommand() {
|
|
|
85
48
|
console.log('[Start] Daemon not running\n');
|
|
86
49
|
// Step 4: Start daemon
|
|
87
50
|
console.log('[Start] Step 4/4: Starting daemon...');
|
|
88
|
-
const result = await startDaemon(projectRoot,
|
|
51
|
+
const result = await startDaemon(projectRoot, project.projectId, apiKey);
|
|
89
52
|
if (!result.success) {
|
|
90
53
|
console.error(`\n❌ Failed to start daemon: ${result.error}`);
|
|
91
54
|
process.exit(1);
|
|
@@ -94,7 +57,7 @@ export async function startCommand() {
|
|
|
94
57
|
console.log('\n╔════════════════════════════════════════════╗');
|
|
95
58
|
console.log('║ Shift is now running! ║');
|
|
96
59
|
console.log('╚════════════════════════════════════════════╝');
|
|
97
|
-
console.log('\nUse "shift status" to check connection status.');
|
|
98
|
-
console.log('Use "shift init" to scan and index the project.');
|
|
99
|
-
console.log('Use "shift stop" to stop the daemon.\n');
|
|
60
|
+
console.log('\nUse "shift-cli status" to check connection status.');
|
|
61
|
+
console.log('Use "shift-cli init" to scan and index the project.');
|
|
62
|
+
console.log('Use "shift-cli stop" to stop the daemon.\n');
|
|
100
63
|
}
|
|
@@ -10,7 +10,7 @@ export async function statusCommand() {
|
|
|
10
10
|
const apiKey = getApiKey();
|
|
11
11
|
if (!apiKey) {
|
|
12
12
|
console.log('API Key: ❌ Not configured');
|
|
13
|
-
console.log('\nRun "shift start" to configure your API key.\n');
|
|
13
|
+
console.log('\nRun "shift-cli start" to configure your API key.\n');
|
|
14
14
|
return;
|
|
15
15
|
}
|
|
16
16
|
if (isGuestKey()) {
|
|
@@ -23,7 +23,7 @@ export async function statusCommand() {
|
|
|
23
23
|
const projectConfig = readProjectConfig(projectRoot);
|
|
24
24
|
if (!projectConfig) {
|
|
25
25
|
console.log('Project: ❌ Not configured');
|
|
26
|
-
console.log('\nRun "shift start" to configure this project.\n');
|
|
26
|
+
console.log('\nRun "shift-cli start" to configure this project.\n');
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
29
29
|
console.log(`Project: ${projectConfig.project_name}`);
|
|
@@ -35,25 +35,35 @@ export async function statusCommand() {
|
|
|
35
35
|
console.log(` - ${agent.agent_name} (${agent.agent_type})`);
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
|
-
// Check project
|
|
38
|
+
// Check project status from backend
|
|
39
39
|
try {
|
|
40
40
|
const projectStatus = await fetchProjectStatus(apiKey, projectConfig.project_id);
|
|
41
|
+
// Init scan status
|
|
42
|
+
const scanStatus = projectStatus.init_scan_status ?? 'not_started';
|
|
43
|
+
const scanLabel = scanStatus === 'completed' ? '✓ Complete'
|
|
44
|
+
: scanStatus === 'in_progress' ? '⏳ In progress'
|
|
45
|
+
: scanStatus === 'failed' ? '❌ Failed'
|
|
46
|
+
: '❌ Not started';
|
|
47
|
+
console.log(`Init Scan: ${scanLabel}`);
|
|
48
|
+
// Indexed
|
|
41
49
|
if (projectStatus.indexed) {
|
|
42
|
-
console.log(`Indexed: ✓
|
|
50
|
+
console.log(`Indexed: ✓ ${projectStatus.file_count} files`);
|
|
43
51
|
}
|
|
44
52
|
else {
|
|
45
53
|
console.log('Indexed: ❌ Not indexed');
|
|
46
|
-
|
|
54
|
+
if (scanStatus === 'not_started') {
|
|
55
|
+
console.log(' Run "shift-cli init" to scan the project.');
|
|
56
|
+
}
|
|
47
57
|
}
|
|
48
58
|
}
|
|
49
59
|
catch {
|
|
50
|
-
console.log('
|
|
60
|
+
console.log('Status: ⚠️ Unable to check (server unavailable)');
|
|
51
61
|
}
|
|
52
62
|
// Check daemon status
|
|
53
63
|
const status = getDaemonStatus(projectRoot);
|
|
54
64
|
if (!status.running) {
|
|
55
65
|
console.log('Daemon: ❌ Not running');
|
|
56
|
-
console.log('\nRun "shift start" to start the daemon.\n');
|
|
66
|
+
console.log('\nRun "shift-cli start" to start the daemon.\n');
|
|
57
67
|
return;
|
|
58
68
|
}
|
|
59
69
|
console.log(`Daemon: ✓ Running (PID: ${status.pid})`);
|