repowise 0.1.5 → 0.1.7
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/dist/bin/repowise.js +24 -6
- package/dist/src/commands/create.d.ts +1 -1
- package/dist/src/commands/create.d.ts.map +1 -1
- package/dist/src/commands/create.js +237 -2
- package/dist/src/commands/create.js.map +1 -1
- package/dist/src/commands/listen.d.ts +3 -2
- package/dist/src/commands/listen.d.ts.map +1 -1
- package/dist/src/commands/listen.js +45 -3
- package/dist/src/commands/listen.js.map +1 -1
- package/dist/src/commands/login.d.ts +4 -1
- package/dist/src/commands/login.d.ts.map +1 -1
- package/dist/src/commands/login.js +56 -2
- package/dist/src/commands/login.js.map +1 -1
- package/dist/src/commands/logout.d.ts +1 -1
- package/dist/src/commands/logout.d.ts.map +1 -1
- package/dist/src/commands/logout.js +10 -2
- package/dist/src/commands/logout.js.map +1 -1
- package/dist/src/commands/start.d.ts +2 -0
- package/dist/src/commands/start.d.ts.map +1 -0
- package/dist/src/commands/start.js +17 -0
- package/dist/src/commands/start.js.map +1 -0
- package/dist/src/commands/status.d.ts +1 -1
- package/dist/src/commands/status.d.ts.map +1 -1
- package/dist/src/commands/status.js +61 -2
- package/dist/src/commands/status.js.map +1 -1
- package/dist/src/commands/stop.d.ts +2 -0
- package/dist/src/commands/stop.d.ts.map +1 -0
- package/dist/src/commands/stop.js +17 -0
- package/dist/src/commands/stop.js.map +1 -0
- package/dist/src/lib/ai-tools.d.ts +23 -0
- package/dist/src/lib/ai-tools.d.ts.map +1 -0
- package/dist/src/lib/ai-tools.js +193 -0
- package/dist/src/lib/ai-tools.js.map +1 -0
- package/dist/src/lib/api.d.ts.map +1 -1
- package/dist/src/lib/api.js +25 -4
- package/dist/src/lib/api.js.map +1 -1
- package/dist/src/lib/auth.d.ts +18 -0
- package/dist/src/lib/auth.d.ts.map +1 -1
- package/dist/src/lib/auth.js +251 -7
- package/dist/src/lib/auth.js.map +1 -1
- package/dist/src/lib/config.d.ts +2 -0
- package/dist/src/lib/config.d.ts.map +1 -1
- package/dist/src/lib/config.js.map +1 -1
- package/dist/src/lib/env.d.ts +10 -0
- package/dist/src/lib/env.d.ts.map +1 -0
- package/dist/src/lib/env.js +26 -0
- package/dist/src/lib/env.js.map +1 -0
- package/dist/src/lib/interview-handler.d.ts +2 -0
- package/dist/src/lib/interview-handler.d.ts.map +1 -0
- package/dist/src/lib/interview-handler.js +96 -0
- package/dist/src/lib/interview-handler.js.map +1 -0
- package/dist/src/lib/progress-renderer.d.ts +69 -0
- package/dist/src/lib/progress-renderer.d.ts.map +1 -0
- package/dist/src/lib/progress-renderer.js +186 -0
- package/dist/src/lib/progress-renderer.js.map +1 -0
- package/dist/src/lib/prompts.d.ts +6 -1
- package/dist/src/lib/prompts.d.ts.map +1 -1
- package/dist/src/lib/prompts.js +21 -3
- package/dist/src/lib/prompts.js.map +1 -1
- package/dist/src/types/index.d.ts +1 -0
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/tsup.config.d.ts +3 -0
- package/dist/tsup.config.d.ts.map +1 -0
- package/dist/tsup.config.js +18 -0
- package/dist/tsup.config.js.map +1 -0
- package/package.json +1 -1
package/dist/bin/repowise.js
CHANGED
|
@@ -592,16 +592,33 @@ var init_config = __esm({
|
|
|
592
592
|
// src/lib/interview-handler.ts
|
|
593
593
|
import chalk2 from "chalk";
|
|
594
594
|
import { input } from "@inquirer/prompts";
|
|
595
|
-
async function handleInterview(syncId, questionId, questionText, questionContext) {
|
|
595
|
+
async function handleInterview(syncId, questionId, questionText, questionContext, estimatedQuestions) {
|
|
596
596
|
questionCounter++;
|
|
597
|
+
if (questionCounter === 1) {
|
|
598
|
+
console.log("");
|
|
599
|
+
console.log(chalk2.cyan.bold(" \u2500\u2500 Interview \u2500\u2500"));
|
|
600
|
+
console.log(chalk2.dim(" Help us understand your project better. Answer a few short"));
|
|
601
|
+
console.log(chalk2.dim(" questions so we can generate more relevant context files."));
|
|
602
|
+
if (estimatedQuestions) {
|
|
603
|
+
console.log(
|
|
604
|
+
chalk2.dim(
|
|
605
|
+
` The AI estimates ${chalk2.white(`~${estimatedQuestions}`)} questions based on your codebase.`
|
|
606
|
+
)
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
console.log(chalk2.dim(' Type "skip" to skip a question, "done" to finish early.'));
|
|
610
|
+
}
|
|
597
611
|
console.log("");
|
|
598
|
-
console.log(
|
|
612
|
+
console.log(
|
|
613
|
+
chalk2.cyan.bold(
|
|
614
|
+
` Question ${questionCounter}${estimatedQuestions ? `/${estimatedQuestions}` : ""}`
|
|
615
|
+
)
|
|
616
|
+
);
|
|
599
617
|
if (questionContext) {
|
|
600
618
|
console.log(chalk2.dim(` ${questionContext}`));
|
|
601
619
|
}
|
|
602
620
|
console.log(` ${questionText}`);
|
|
603
|
-
console.log(chalk2.dim(' Type "skip" to skip, "done" to finish
|
|
604
|
-
console.log(chalk2.dim(" (Auto-skips after 5 minutes of inactivity)"));
|
|
621
|
+
console.log(chalk2.dim(' (Type "skip" to skip, "done" to finish early)'));
|
|
605
622
|
let answer;
|
|
606
623
|
try {
|
|
607
624
|
answer = await Promise.race([
|
|
@@ -1330,13 +1347,15 @@ async function create() {
|
|
|
1330
1347
|
}
|
|
1331
1348
|
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
1332
1349
|
const syncResult = await apiRequest(`/v1/sync/${syncId}/status`);
|
|
1350
|
+
progressRenderer.update(syncResult, spinner);
|
|
1333
1351
|
if (syncResult.status === "awaiting_input" && syncResult.questionId && syncResult.questionText) {
|
|
1334
1352
|
spinner.stop();
|
|
1335
1353
|
await handleInterview(
|
|
1336
1354
|
syncId,
|
|
1337
1355
|
syncResult.questionId,
|
|
1338
1356
|
syncResult.questionText,
|
|
1339
|
-
syncResult.questionContext ?? void 0
|
|
1357
|
+
syncResult.questionContext ?? void 0,
|
|
1358
|
+
syncResult.discoveryResult?.estimatedInterviewQuestions
|
|
1340
1359
|
);
|
|
1341
1360
|
spinner.start("Resuming pipeline...");
|
|
1342
1361
|
continue;
|
|
@@ -1350,7 +1369,6 @@ async function create() {
|
|
|
1350
1369
|
process.exitCode = 1;
|
|
1351
1370
|
return;
|
|
1352
1371
|
}
|
|
1353
|
-
progressRenderer.update(syncResult, spinner);
|
|
1354
1372
|
}
|
|
1355
1373
|
if (repoRoot) {
|
|
1356
1374
|
spinner.start("Pulling latest changes...");
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function create(): void
|
|
1
|
+
export declare function create(): Promise<void>;
|
|
2
2
|
//# sourceMappingURL=create.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/create.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/create.ts"],"names":[],"mappings":"AAyGA,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAkQ5C"}
|
|
@@ -1,4 +1,239 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import { getValidCredentials, performLogin, decodeIdToken } from '../lib/auth.js';
|
|
5
|
+
import { apiRequest } from '../lib/api.js';
|
|
6
|
+
import { selectAiTools } from '../lib/prompts.js';
|
|
7
|
+
import { updateToolConfig, scanLocalContextFiles, AI_TOOL_CONFIG } from '../lib/ai-tools.js';
|
|
8
|
+
import { getConfig, saveConfig } from '../lib/config.js';
|
|
9
|
+
import { handleInterview } from '../lib/interview-handler.js';
|
|
10
|
+
import { ProgressRenderer } from '../lib/progress-renderer.js';
|
|
11
|
+
function detectRepoRoot() {
|
|
12
|
+
return execSync('git rev-parse --show-toplevel', { encoding: 'utf-8' }).trim();
|
|
13
|
+
}
|
|
14
|
+
function detectRepoName(repoRoot) {
|
|
15
|
+
try {
|
|
16
|
+
const remoteUrl = execSync('git remote get-url origin', {
|
|
17
|
+
encoding: 'utf-8',
|
|
18
|
+
cwd: repoRoot,
|
|
19
|
+
}).trim();
|
|
20
|
+
// Extract repo name from URL (handles both HTTPS and SSH)
|
|
21
|
+
const match = remoteUrl.match(/\/([^/]+?)(?:\.git)?$/);
|
|
22
|
+
if (match?.[1])
|
|
23
|
+
return match[1];
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// No remote configured — fall back to directory name
|
|
27
|
+
}
|
|
28
|
+
return repoRoot.split('/').pop() ?? 'unknown';
|
|
29
|
+
}
|
|
30
|
+
function formatElapsed(ms) {
|
|
31
|
+
const totalSeconds = Math.round(ms / 1000);
|
|
32
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
33
|
+
const seconds = totalSeconds % 60;
|
|
34
|
+
if (minutes === 0)
|
|
35
|
+
return `${seconds}s`;
|
|
36
|
+
return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
|
|
37
|
+
}
|
|
38
|
+
const POLL_INTERVAL_MS = 3000;
|
|
39
|
+
const MAX_POLL_ATTEMPTS = 200; // ~10 minutes at 3s interval
|
|
40
|
+
const DEFAULT_CONTEXT_FOLDER = 'repowise-context';
|
|
41
|
+
export async function create() {
|
|
42
|
+
const startTime = Date.now();
|
|
43
|
+
const spinner = ora('Checking authentication...').start();
|
|
44
|
+
try {
|
|
45
|
+
// Step 1: Auth check — auto-login if not authenticated (Story 2.1)
|
|
46
|
+
let credentials = await getValidCredentials();
|
|
47
|
+
if (!credentials) {
|
|
48
|
+
spinner.info(chalk.yellow('Not logged in. Opening browser to authenticate...'));
|
|
49
|
+
credentials = await performLogin();
|
|
50
|
+
const { email } = decodeIdToken(credentials.idToken);
|
|
51
|
+
spinner.succeed(chalk.green(`Authenticated as ${chalk.bold(email)}`));
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
spinner.succeed('Authenticated');
|
|
55
|
+
}
|
|
56
|
+
// Step 2: Check for pending onboarding repo from dashboard (Story 2.2)
|
|
57
|
+
let repoId;
|
|
58
|
+
let repoName;
|
|
59
|
+
let repoRoot;
|
|
60
|
+
spinner.start('Checking for pending repository...');
|
|
61
|
+
try {
|
|
62
|
+
const pending = await apiRequest('/v1/onboarding/pending');
|
|
63
|
+
if (pending?.repoId) {
|
|
64
|
+
repoId = pending.repoId;
|
|
65
|
+
repoName = pending.repoName;
|
|
66
|
+
spinner.succeed(`Found pending repository: ${chalk.bold(repoName)}`);
|
|
67
|
+
// Clear pending onboarding after pickup
|
|
68
|
+
apiRequest('/v1/onboarding/pending', { method: 'DELETE' }).catch(() => { });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// No pending onboarding API available or failed — fall through to local detection
|
|
73
|
+
}
|
|
74
|
+
// Fall back to local git detection if no pending repo
|
|
75
|
+
if (!repoId) {
|
|
76
|
+
spinner.text = 'Detecting repository...';
|
|
77
|
+
try {
|
|
78
|
+
repoRoot = detectRepoRoot();
|
|
79
|
+
repoName = detectRepoName(repoRoot);
|
|
80
|
+
spinner.succeed(`Repository: ${chalk.bold(repoName)}`);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
spinner.fail(chalk.red('Not in a git repository. Run this command from your repo directory, or select a repo on the dashboard first.'));
|
|
84
|
+
process.exitCode = 1;
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// Resolve repoId from API
|
|
88
|
+
try {
|
|
89
|
+
const repos = await apiRequest('/v1/repos');
|
|
90
|
+
const match = repos.find((r) => r.name === repoName || r.fullName.endsWith(`/${repoName}`));
|
|
91
|
+
if (match) {
|
|
92
|
+
repoId = match.repoId;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// Could not resolve — will fail at sync trigger
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
// Try to detect local repo root even with pending repo (for git pull later)
|
|
101
|
+
try {
|
|
102
|
+
repoRoot = detectRepoRoot();
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Not in a git repo directory — that's ok with pending repo
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (!repoId) {
|
|
109
|
+
spinner.fail(chalk.red('Could not find this repository in your RepoWise account. Connect it on the dashboard first.'));
|
|
110
|
+
process.exitCode = 1;
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
// Step 3: AI tool selection
|
|
114
|
+
const { tools, hasOther } = await selectAiTools();
|
|
115
|
+
if (hasOther) {
|
|
116
|
+
console.log(chalk.cyan('\nFor AI tools not listed, context files still work with any tool that reads the filesystem.\nRequest support for your tool at: https://dashboard.repowise.ai/support/ai-tools'));
|
|
117
|
+
}
|
|
118
|
+
if (tools.length === 0 && !hasOther) {
|
|
119
|
+
console.log(chalk.yellow('\nNo AI tools selected. You can configure them later with `repowise config`.'));
|
|
120
|
+
}
|
|
121
|
+
// Step 4: Trigger pipeline (or resume an existing active sync)
|
|
122
|
+
spinner.start('Starting context generation pipeline...');
|
|
123
|
+
let syncId;
|
|
124
|
+
try {
|
|
125
|
+
const triggerResult = await apiRequest(`/v1/repos/${repoId}/sync`, {
|
|
126
|
+
method: 'POST',
|
|
127
|
+
body: JSON.stringify({ scanType: 'full' }),
|
|
128
|
+
});
|
|
129
|
+
syncId = triggerResult.syncId;
|
|
130
|
+
}
|
|
131
|
+
catch (triggerErr) {
|
|
132
|
+
const msg = triggerErr instanceof Error ? triggerErr.message : '';
|
|
133
|
+
if (!msg.toLowerCase().includes('already running')) {
|
|
134
|
+
throw triggerErr;
|
|
135
|
+
}
|
|
136
|
+
// A sync is already in progress — find it and resume polling
|
|
137
|
+
spinner.text = 'Resuming existing pipeline...';
|
|
138
|
+
const syncs = await apiRequest(`/v1/repos/${repoId}/syncs?limit=1`);
|
|
139
|
+
const active = syncs.items.find((s) => s.status === 'in_progress' || s.status === 'awaiting_input');
|
|
140
|
+
if (!active) {
|
|
141
|
+
throw new Error('Could not find active sync to resume. Please try again.');
|
|
142
|
+
}
|
|
143
|
+
syncId = active.syncId;
|
|
144
|
+
spinner.info(chalk.cyan('Resuming existing pipeline...'));
|
|
145
|
+
spinner.start();
|
|
146
|
+
}
|
|
147
|
+
// Step 5: Poll for completion with enriched progress display
|
|
148
|
+
let pollAttempts = 0;
|
|
149
|
+
const progressRenderer = new ProgressRenderer();
|
|
150
|
+
while (true) {
|
|
151
|
+
if (++pollAttempts > MAX_POLL_ATTEMPTS) {
|
|
152
|
+
spinner.fail(chalk.red('Pipeline timed out. Check dashboard for status.'));
|
|
153
|
+
process.exitCode = 1;
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
157
|
+
const syncResult = await apiRequest(`/v1/sync/${syncId}/status`);
|
|
158
|
+
// Update progress display first so discovery/scan sections render
|
|
159
|
+
// even if the status already jumped to awaiting_input or completed
|
|
160
|
+
progressRenderer.update(syncResult, spinner);
|
|
161
|
+
// Handle interview questions (Story 3.2)
|
|
162
|
+
if (syncResult.status === 'awaiting_input' &&
|
|
163
|
+
syncResult.questionId &&
|
|
164
|
+
syncResult.questionText) {
|
|
165
|
+
spinner.stop();
|
|
166
|
+
await handleInterview(syncId, syncResult.questionId, syncResult.questionText, syncResult.questionContext ?? undefined, syncResult.discoveryResult?.estimatedInterviewQuestions);
|
|
167
|
+
spinner.start('Resuming pipeline...');
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (syncResult.status === 'completed') {
|
|
171
|
+
spinner.succeed('Context generation complete');
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
if (syncResult.status === 'failed') {
|
|
175
|
+
spinner.fail(chalk.red(`Pipeline failed: ${syncResult.error ?? 'Unknown error'}`));
|
|
176
|
+
process.exitCode = 1;
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// Step 6: Git pull to get context files
|
|
181
|
+
if (repoRoot) {
|
|
182
|
+
spinner.start('Pulling latest changes...');
|
|
183
|
+
try {
|
|
184
|
+
execSync('git pull', { cwd: repoRoot, encoding: 'utf-8', stdio: 'pipe' });
|
|
185
|
+
spinner.succeed('Pulled latest changes');
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
spinner.warn(chalk.yellow('Could not pull latest changes. You may need to run `git pull` manually.'));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Step 7: Collect context files
|
|
192
|
+
const contextFolder = DEFAULT_CONTEXT_FOLDER;
|
|
193
|
+
let contextFiles = [];
|
|
194
|
+
if (repoRoot) {
|
|
195
|
+
contextFiles = await scanLocalContextFiles(repoRoot, contextFolder);
|
|
196
|
+
}
|
|
197
|
+
// Step 8: Configure AI tools
|
|
198
|
+
if (tools.length > 0 && repoRoot) {
|
|
199
|
+
spinner.start('Configuring AI tools...');
|
|
200
|
+
const results = [];
|
|
201
|
+
for (const tool of tools) {
|
|
202
|
+
const { created: wasCreated } = await updateToolConfig(repoRoot, tool, repoName, contextFolder, contextFiles);
|
|
203
|
+
const config = AI_TOOL_CONFIG[tool];
|
|
204
|
+
const action = wasCreated ? 'Created' : 'Updated';
|
|
205
|
+
results.push(` ${action} ${config.filePath}`);
|
|
206
|
+
}
|
|
207
|
+
spinner.succeed('AI tools configured');
|
|
208
|
+
console.log(chalk.dim(results.join('\n')));
|
|
209
|
+
}
|
|
210
|
+
// Step 9: Save config
|
|
211
|
+
const existingConfig = await getConfig();
|
|
212
|
+
await saveConfig({
|
|
213
|
+
...existingConfig,
|
|
214
|
+
aiTools: tools,
|
|
215
|
+
contextFolder,
|
|
216
|
+
});
|
|
217
|
+
// Step 10: Auto-start listener
|
|
218
|
+
try {
|
|
219
|
+
const { install } = await import('@repowise/listener/service-installer');
|
|
220
|
+
const { startBackground } = await import('@repowise/listener/process-manager');
|
|
221
|
+
await install();
|
|
222
|
+
await startBackground();
|
|
223
|
+
console.log(chalk.green('Listener started — your context will stay in sync automatically.'));
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
console.log(chalk.yellow('Warning: Could not start listener automatically. Run `repowise listen --install` to enable auto-start.'));
|
|
227
|
+
}
|
|
228
|
+
// Step 11: Completion summary with elapsed time (Story 2.3)
|
|
229
|
+
const elapsed = formatElapsed(Date.now() - startTime);
|
|
230
|
+
console.log(chalk.green(`\n${chalk.bold('Setup complete!')} Your AI tools now have access to project context for ${chalk.bold(repoName)}.`));
|
|
231
|
+
console.log(chalk.dim(`Total time: ${elapsed}`));
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
const message = err instanceof Error ? err.message : 'Create failed';
|
|
235
|
+
spinner.fail(chalk.red(message));
|
|
236
|
+
process.exitCode = 1;
|
|
237
|
+
}
|
|
3
238
|
}
|
|
4
239
|
//# sourceMappingURL=create.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../../src/commands/create.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,MAAM;
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../../src/commands/create.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"listen.d.ts","sourceRoot":"","sources":["../../../src/commands/listen.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"listen.d.ts","sourceRoot":"","sources":["../../../src/commands/listen.ts"],"names":[],"mappings":"AAEA,wBAAsB,MAAM,CAAC,OAAO,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA6C/F"}
|
|
@@ -1,5 +1,47 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { getValidCredentials } from '../lib/auth.js';
|
|
2
|
+
export async function listen(options) {
|
|
3
|
+
if (options.install) {
|
|
4
|
+
try {
|
|
5
|
+
const { install } = await import('@repowise/listener/service-installer');
|
|
6
|
+
await install();
|
|
7
|
+
console.log('Auto-start service installed. The listener will start on boot.');
|
|
8
|
+
}
|
|
9
|
+
catch (err) {
|
|
10
|
+
const message = err instanceof Error ? err.message : 'Unknown error';
|
|
11
|
+
console.error(`Failed to install auto-start service: ${message}`);
|
|
12
|
+
console.error('You can still run the listener manually with `repowise listen`.');
|
|
13
|
+
process.exitCode = 1;
|
|
14
|
+
}
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (options.uninstall) {
|
|
18
|
+
try {
|
|
19
|
+
const { uninstall } = await import('@repowise/listener/service-installer');
|
|
20
|
+
await uninstall();
|
|
21
|
+
console.log('Auto-start service removed.');
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
const message = err instanceof Error ? err.message : 'Unknown error';
|
|
25
|
+
console.error(`Failed to uninstall auto-start service: ${message}`);
|
|
26
|
+
process.exitCode = 1;
|
|
27
|
+
}
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const credentials = await getValidCredentials();
|
|
31
|
+
if (!credentials) {
|
|
32
|
+
console.error('Not logged in. Run `repowise login` first.');
|
|
33
|
+
process.exitCode = 1;
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
console.log('Starting RepoWise listener...');
|
|
37
|
+
// Dynamic import to avoid hard dependency on listener package
|
|
38
|
+
try {
|
|
39
|
+
const { startListener } = await import('@repowise/listener/main');
|
|
40
|
+
await startListener();
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
console.error('Failed to start listener. Ensure @repowise/listener is installed.');
|
|
44
|
+
process.exitCode = 1;
|
|
45
|
+
}
|
|
4
46
|
}
|
|
5
47
|
//# sourceMappingURL=listen.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"listen.js","sourceRoot":"","sources":["../../../src/commands/listen.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"listen.js","sourceRoot":"","sources":["../../../src/commands/listen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,OAAmD;IAC9E,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,sCAAsC,CAAC,CAAC;YACzE,MAAM,OAAO,EAAE,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAC;QAChF,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACrE,OAAO,CAAC,KAAK,CAAC,yCAAyC,OAAO,EAAE,CAAC,CAAC;YAClE,OAAO,CAAC,KAAK,CAAC,iEAAiE,CAAC,CAAC;YACjF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;QACD,OAAO;IACT,CAAC;IAED,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACtB,IAAI,CAAC;YACH,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,sCAAsC,CAAC,CAAC;YAC3E,MAAM,SAAS,EAAE,CAAC;YAClB,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QAC7C,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACrE,OAAO,CAAC,KAAK,CAAC,2CAA2C,OAAO,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;QACD,OAAO;IACT,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,mBAAmB,EAAE,CAAC;IAChD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAC5D,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;IAE7C,8DAA8D;IAC9D,IAAI,CAAC;QACH,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAC;QAClE,MAAM,aAAa,EAAE,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,KAAK,CAAC,mEAAmE,CAAC,CAAC;QACnF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../../src/commands/login.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../../src/commands/login.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAsB,KAAK,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6DrE"}
|
|
@@ -1,4 +1,58 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import { generateCodeVerifier, generateCodeChallenge, generateState, getAuthorizeUrl, startCallbackServer, exchangeCodeForTokens, storeCredentials, decodeIdToken, } from '../lib/auth.js';
|
|
4
|
+
export async function login(options = {}) {
|
|
5
|
+
const spinner = ora('Preparing login...').start();
|
|
6
|
+
try {
|
|
7
|
+
// Generate PKCE and state
|
|
8
|
+
const codeVerifier = generateCodeVerifier();
|
|
9
|
+
const codeChallenge = generateCodeChallenge(codeVerifier);
|
|
10
|
+
const state = generateState();
|
|
11
|
+
// Build authorize URL
|
|
12
|
+
const authorizeUrl = getAuthorizeUrl(codeChallenge, state);
|
|
13
|
+
// Start callback server first
|
|
14
|
+
const callbackPromise = startCallbackServer();
|
|
15
|
+
// Open browser or print URL
|
|
16
|
+
if (options.browser === false) {
|
|
17
|
+
spinner.stop();
|
|
18
|
+
console.log(`\nOpen this URL in your browser to authenticate:\n`);
|
|
19
|
+
console.log(chalk.cyan(authorizeUrl));
|
|
20
|
+
console.log(`\nWaiting for authentication...`);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
spinner.text = 'Opening browser for authentication...';
|
|
24
|
+
try {
|
|
25
|
+
const open = (await import('open')).default;
|
|
26
|
+
await open(authorizeUrl);
|
|
27
|
+
spinner.text = 'Waiting for authentication in browser...';
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Fall back to printing URL if open fails
|
|
31
|
+
spinner.stop();
|
|
32
|
+
console.log(`\nCould not open browser automatically. Open this URL:\n`);
|
|
33
|
+
console.log(chalk.cyan(authorizeUrl));
|
|
34
|
+
console.log(`\nWaiting for authentication...`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// Wait for callback
|
|
38
|
+
const { code, state: returnedState } = await callbackPromise;
|
|
39
|
+
// Validate state
|
|
40
|
+
if (returnedState !== state) {
|
|
41
|
+
throw new Error('State mismatch — possible CSRF attack. Please try again.');
|
|
42
|
+
}
|
|
43
|
+
spinner.start('Exchanging authorization code...');
|
|
44
|
+
// Exchange code for tokens
|
|
45
|
+
const credentials = await exchangeCodeForTokens(code, codeVerifier);
|
|
46
|
+
// Store credentials
|
|
47
|
+
await storeCredentials(credentials);
|
|
48
|
+
// Decode ID token for display
|
|
49
|
+
const { email } = decodeIdToken(credentials.idToken);
|
|
50
|
+
spinner.succeed(chalk.green(`Logged in as ${chalk.bold(email)}`));
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
const message = err instanceof Error ? err.message : 'Login failed';
|
|
54
|
+
spinner.fail(chalk.red(message));
|
|
55
|
+
process.exitCode = 1;
|
|
56
|
+
}
|
|
3
57
|
}
|
|
4
58
|
//# sourceMappingURL=login.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../../src/commands/login.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,KAAK;
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../../src/commands/login.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function logout(): void
|
|
1
|
+
export declare function logout(): Promise<void>;
|
|
2
2
|
//# sourceMappingURL=logout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../../src/commands/logout.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../../src/commands/logout.ts"],"names":[],"mappings":"AAGA,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAU5C"}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { clearCredentials, getStoredCredentials } from '../lib/auth.js';
|
|
3
|
+
export async function logout() {
|
|
4
|
+
const creds = await getStoredCredentials();
|
|
5
|
+
if (!creds) {
|
|
6
|
+
console.log(chalk.yellow('Not logged in.'));
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
await clearCredentials();
|
|
10
|
+
console.log(chalk.green('Logged out successfully.'));
|
|
3
11
|
}
|
|
4
12
|
//# sourceMappingURL=logout.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,MAAM;
|
|
1
|
+
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAExE,MAAM,CAAC,KAAK,UAAU,MAAM;IAC1B,MAAM,KAAK,GAAG,MAAM,oBAAoB,EAAE,CAAC;IAE3C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC;QAC5C,OAAO;IACT,CAAC;IAED,MAAM,gBAAgB,EAAE,CAAC;IACzB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/commands/start.ts"],"names":[],"mappings":"AAAA,wBAAsB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAgB3C"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export async function start() {
|
|
2
|
+
try {
|
|
3
|
+
const { isRunning, startBackground } = await import('@repowise/listener/process-manager');
|
|
4
|
+
if (await isRunning()) {
|
|
5
|
+
console.log('Listener is already running.');
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const pid = await startBackground();
|
|
9
|
+
console.log(`Listener started (PID: ${pid}).`);
|
|
10
|
+
}
|
|
11
|
+
catch (err) {
|
|
12
|
+
const message = err instanceof Error ? err.message : 'Unknown error';
|
|
13
|
+
console.error(`Failed to start listener: ${message}`);
|
|
14
|
+
process.exitCode = 1;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=start.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.js","sourceRoot":"","sources":["../../../src/commands/start.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,KAAK,UAAU,KAAK;IACzB,IAAI,CAAC;QACH,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,oCAAoC,CAAC,CAAC;QAE1F,IAAI,MAAM,SAAS,EAAE,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;YAC5C,OAAO;QACT,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,eAAe,EAAE,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,0BAA0B,GAAG,IAAI,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACrE,OAAO,CAAC,KAAK,CAAC,6BAA6B,OAAO,EAAE,CAAC,CAAC;QACtD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC;AACH,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function status(): void
|
|
1
|
+
export declare function status(): Promise<void>;
|
|
2
2
|
//# sourceMappingURL=status.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/commands/status.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/commands/status.ts"],"names":[],"mappings":"AAUA,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CA8D5C"}
|
|
@@ -1,4 +1,63 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
const STATE_PATH = join(homedir(), '.repowise', 'listener-state.json');
|
|
5
|
+
export async function status() {
|
|
6
|
+
let state = null;
|
|
7
|
+
try {
|
|
8
|
+
const data = await readFile(STATE_PATH, 'utf-8');
|
|
9
|
+
state = JSON.parse(data);
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
// No state file — listener hasn't run yet
|
|
13
|
+
}
|
|
14
|
+
// Check process status
|
|
15
|
+
let processRunning = false;
|
|
16
|
+
let pid = null;
|
|
17
|
+
try {
|
|
18
|
+
const { getStatus } = await import('@repowise/listener/process-manager');
|
|
19
|
+
const processStatus = await getStatus();
|
|
20
|
+
processRunning = processStatus.running;
|
|
21
|
+
pid = processStatus.pid;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// process-manager not available
|
|
25
|
+
}
|
|
26
|
+
// Check service registration
|
|
27
|
+
let serviceInstalled = false;
|
|
28
|
+
try {
|
|
29
|
+
const { isInstalled } = await import('@repowise/listener/service-installer');
|
|
30
|
+
serviceInstalled = await isInstalled();
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// service-installer not available
|
|
34
|
+
}
|
|
35
|
+
console.log('RepoWise Status');
|
|
36
|
+
console.log('===============');
|
|
37
|
+
if (processRunning) {
|
|
38
|
+
console.log(`Listener: running (PID: ${pid})`);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
console.log('Listener: stopped');
|
|
42
|
+
}
|
|
43
|
+
if (serviceInstalled) {
|
|
44
|
+
console.log('Auto-start: enabled');
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
console.log('Auto-start: disabled');
|
|
48
|
+
}
|
|
49
|
+
console.log('');
|
|
50
|
+
if (!state || Object.keys(state.repos).length === 0) {
|
|
51
|
+
console.log('No sync history. Run `repowise listen` to start syncing.');
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
console.log('Watched Repos:');
|
|
55
|
+
for (const [repoId, repoState] of Object.entries(state.repos)) {
|
|
56
|
+
const syncTime = repoState.lastSyncTimestamp
|
|
57
|
+
? new Date(repoState.lastSyncTimestamp).toLocaleString()
|
|
58
|
+
: 'never';
|
|
59
|
+
const commit = repoState.lastSyncCommitSha ? repoState.lastSyncCommitSha.slice(0, 7) : 'none';
|
|
60
|
+
console.log(` ${repoId}: last sync ${syncTime} (commit: ${commit})`);
|
|
61
|
+
}
|
|
3
62
|
}
|
|
4
63
|
//# sourceMappingURL=status.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/commands/status.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,MAAM;
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/commands/status.ts"],"names":[],"mappings":"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"}
|