edsger 0.31.0 โ 0.31.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/dist/auth/auth-store.d.ts +13 -0
- package/dist/auth/auth-store.js +38 -1
- package/dist/phases/code-refine/context.js +5 -4
- package/dist/phases/code-review/context.js +5 -4
- package/dist/phases/functional-testing/analyzer.js +3 -2
- package/dist/phases/functional-testing/http-fallback.js +5 -4
- package/dist/phases/functional-testing/test-report-creator.js +7 -6
- package/dist/services/feedbacks.js +5 -4
- package/dist/utils/validation.js +5 -4
- package/dist/utils/workflow-utils.js +3 -2
- package/package.json +1 -1
|
@@ -50,3 +50,16 @@ export declare function getEdsgerBaseUrl(): string;
|
|
|
50
50
|
* Get the auth file path (for display purposes)
|
|
51
51
|
*/
|
|
52
52
|
export declare function getAuthFilePath(): string;
|
|
53
|
+
/**
|
|
54
|
+
* Watch the auth file for external changes (e.g., from Edsger Desktop app).
|
|
55
|
+
* When the file changes, the in-memory cache is invalidated so the CLI
|
|
56
|
+
* picks up new auth credentials automatically.
|
|
57
|
+
*
|
|
58
|
+
* @param onChange - Optional callback invoked when auth config changes
|
|
59
|
+
* @returns A function to stop watching
|
|
60
|
+
*/
|
|
61
|
+
export declare function watchAuthFile(onChange?: (config: AuthConfig | null) => void): () => void;
|
|
62
|
+
/**
|
|
63
|
+
* Stop watching the auth file
|
|
64
|
+
*/
|
|
65
|
+
export declare function stopWatchingAuthFile(): void;
|
package/dist/auth/auth-store.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Stores auth credentials in ~/.edsger/auth.json
|
|
5
5
|
* Provides read/write/clear operations for auth tokens
|
|
6
6
|
*/
|
|
7
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync, chmodSync } from 'fs';
|
|
7
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync, chmodSync, watch } from 'fs';
|
|
8
8
|
import { join } from 'path';
|
|
9
9
|
import { homedir } from 'os';
|
|
10
10
|
const EDSGER_DIR = join(homedir(), '.edsger');
|
|
@@ -115,3 +115,40 @@ export function getEdsgerBaseUrl() {
|
|
|
115
115
|
export function getAuthFilePath() {
|
|
116
116
|
return AUTH_FILE;
|
|
117
117
|
}
|
|
118
|
+
/** Active file watcher for auth file changes */
|
|
119
|
+
let _authWatcher = null;
|
|
120
|
+
/**
|
|
121
|
+
* Watch the auth file for external changes (e.g., from Edsger Desktop app).
|
|
122
|
+
* When the file changes, the in-memory cache is invalidated so the CLI
|
|
123
|
+
* picks up new auth credentials automatically.
|
|
124
|
+
*
|
|
125
|
+
* @param onChange - Optional callback invoked when auth config changes
|
|
126
|
+
* @returns A function to stop watching
|
|
127
|
+
*/
|
|
128
|
+
export function watchAuthFile(onChange) {
|
|
129
|
+
// Stop any existing watcher
|
|
130
|
+
stopWatchingAuthFile();
|
|
131
|
+
ensureEdsgerDir();
|
|
132
|
+
_authWatcher = watch(EDSGER_DIR, (eventType, filename) => {
|
|
133
|
+
if (filename !== 'auth.json')
|
|
134
|
+
return;
|
|
135
|
+
// Invalidate cache so next loadAuth() reads from disk
|
|
136
|
+
_authCache = undefined;
|
|
137
|
+
const config = loadAuth();
|
|
138
|
+
if (onChange) {
|
|
139
|
+
onChange(config);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
// Don't keep the process alive just for the watcher
|
|
143
|
+
_authWatcher.unref();
|
|
144
|
+
return () => stopWatchingAuthFile();
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Stop watching the auth file
|
|
148
|
+
*/
|
|
149
|
+
export function stopWatchingAuthFile() {
|
|
150
|
+
if (_authWatcher) {
|
|
151
|
+
_authWatcher.close();
|
|
152
|
+
_authWatcher = null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { Octokit } from '@octokit/rest';
|
|
6
6
|
import { getFeature } from '../../api/features/get-feature.js';
|
|
7
7
|
import { downloadImagesForClaudeCode } from '../../utils/image-downloader.js';
|
|
8
|
+
import { getMcpServerUrl, getMcpToken } from '../../auth/auth-store.js';
|
|
8
9
|
/**
|
|
9
10
|
* Extract owner, repo, and PR number from GitHub PR URL
|
|
10
11
|
*/
|
|
@@ -183,8 +184,8 @@ export async function fetchUserStories(featureId, verbose) {
|
|
|
183
184
|
if (verbose) {
|
|
184
185
|
console.log(`๐ Fetching user stories for ${featureId}...`);
|
|
185
186
|
}
|
|
186
|
-
const mcpServerUrl =
|
|
187
|
-
const mcpToken =
|
|
187
|
+
const mcpServerUrl = getMcpServerUrl();
|
|
188
|
+
const mcpToken = getMcpToken();
|
|
188
189
|
const response = await fetch(`${mcpServerUrl}/mcp`, {
|
|
189
190
|
method: 'POST',
|
|
190
191
|
headers: {
|
|
@@ -230,8 +231,8 @@ export async function fetchTestCases(featureId, verbose) {
|
|
|
230
231
|
if (verbose) {
|
|
231
232
|
console.log(`๐งช Fetching test cases for ${featureId}...`);
|
|
232
233
|
}
|
|
233
|
-
const mcpServerUrl =
|
|
234
|
-
const mcpToken =
|
|
234
|
+
const mcpServerUrl = getMcpServerUrl();
|
|
235
|
+
const mcpToken = getMcpToken();
|
|
235
236
|
const response = await fetch(`${mcpServerUrl}/mcp`, {
|
|
236
237
|
method: 'POST',
|
|
237
238
|
headers: {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { Octokit } from '@octokit/rest';
|
|
6
6
|
import { getFeature } from '../../api/features/get-feature.js';
|
|
7
|
+
import { getMcpServerUrl, getMcpToken } from '../../auth/auth-store.js';
|
|
7
8
|
/**
|
|
8
9
|
* Extract owner, repo, and PR number from GitHub PR URL
|
|
9
10
|
*/
|
|
@@ -79,8 +80,8 @@ export async function fetchUserStories(featureId, verbose) {
|
|
|
79
80
|
if (verbose) {
|
|
80
81
|
console.log(`๐ Fetching user stories for ${featureId}...`);
|
|
81
82
|
}
|
|
82
|
-
const mcpServerUrl =
|
|
83
|
-
const mcpToken =
|
|
83
|
+
const mcpServerUrl = getMcpServerUrl();
|
|
84
|
+
const mcpToken = getMcpToken();
|
|
84
85
|
const response = await fetch(`${mcpServerUrl}/mcp`, {
|
|
85
86
|
method: 'POST',
|
|
86
87
|
headers: {
|
|
@@ -126,8 +127,8 @@ export async function fetchTestCases(featureId, verbose) {
|
|
|
126
127
|
if (verbose) {
|
|
127
128
|
console.log(`๐งช Fetching test cases for ${featureId}...`);
|
|
128
129
|
}
|
|
129
|
-
const mcpServerUrl =
|
|
130
|
-
const mcpToken =
|
|
130
|
+
const mcpServerUrl = getMcpServerUrl();
|
|
131
|
+
const mcpToken = getMcpToken();
|
|
131
132
|
const response = await fetch(`${mcpServerUrl}/mcp`, {
|
|
132
133
|
method: 'POST',
|
|
133
134
|
headers: {
|
|
@@ -8,6 +8,7 @@ import { fetchFunctionalTestingContext, formatContextForPrompt, } from './contex
|
|
|
8
8
|
import { updateFeatureStatus } from '../../api/features/index.js';
|
|
9
9
|
import { createTestReport, } from './test-report-creator.js';
|
|
10
10
|
import { preparePhaseGitEnvironment, prepareCustomBranchGitEnvironment, } from '../../utils/git-branch-manager.js';
|
|
11
|
+
import { getMcpServerUrl, getMcpToken } from '../../auth/auth-store.js';
|
|
11
12
|
import { getReadyForReviewBranch, } from '../../services/branches.js';
|
|
12
13
|
function userMessage(content) {
|
|
13
14
|
return {
|
|
@@ -299,8 +300,8 @@ export const runFunctionalTesting = async (options, config, checklistContext) =>
|
|
|
299
300
|
structuredTestResult.test_cases.length > 0) {
|
|
300
301
|
// Fetch test cases for this feature to get proper test_case_ids
|
|
301
302
|
try {
|
|
302
|
-
const mcpServerUrl =
|
|
303
|
-
const mcpToken =
|
|
303
|
+
const mcpServerUrl = getMcpServerUrl();
|
|
304
|
+
const mcpToken = getMcpToken();
|
|
304
305
|
const testCasesResponse = await fetch(`${mcpServerUrl}/mcp`, {
|
|
305
306
|
method: 'POST',
|
|
306
307
|
headers: {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { logInfo, logError } from '../../utils/logger.js';
|
|
2
|
+
import { getMcpServerUrl, getMcpToken } from '../../auth/auth-store.js';
|
|
2
3
|
export async function saveFunctionalTestResultsViaHttp(options) {
|
|
3
4
|
const { featureId, testStatus, testResults: _testResults, verbose } = options;
|
|
4
5
|
try {
|
|
5
6
|
if (verbose) {
|
|
6
7
|
logInfo('๐ Attempting to save functional test results via HTTP fallback...');
|
|
7
8
|
}
|
|
8
|
-
const mcpServerUrl =
|
|
9
|
-
const mcpToken =
|
|
9
|
+
const mcpServerUrl = getMcpServerUrl();
|
|
10
|
+
const mcpToken = getMcpToken();
|
|
10
11
|
const response = await fetch(`${mcpServerUrl}/mcp`, {
|
|
11
12
|
method: 'POST',
|
|
12
13
|
headers: {
|
|
@@ -47,8 +48,8 @@ export async function verifyTestStatusSaved(featureId, verbose, expectedStatus)
|
|
|
47
48
|
if (verbose) {
|
|
48
49
|
logInfo('๐ Verifying test status was saved...');
|
|
49
50
|
}
|
|
50
|
-
const mcpServerUrl =
|
|
51
|
-
const mcpToken =
|
|
51
|
+
const mcpServerUrl = getMcpServerUrl();
|
|
52
|
+
const mcpToken = getMcpToken();
|
|
52
53
|
const response = await fetch(`${mcpServerUrl}/mcp`, {
|
|
53
54
|
method: 'POST',
|
|
54
55
|
headers: {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { logInfo, logError } from '../../utils/logger.js';
|
|
2
|
+
import { getMcpServerUrl, getMcpToken } from '../../auth/auth-store.js';
|
|
2
3
|
/**
|
|
3
4
|
* Create a test report via MCP endpoint
|
|
4
5
|
* Uses structured data generated by Claude Code
|
|
@@ -23,8 +24,8 @@ export async function createTestReport(options) {
|
|
|
23
24
|
timestamp: new Date().toISOString(),
|
|
24
25
|
};
|
|
25
26
|
try {
|
|
26
|
-
const mcpServerUrl =
|
|
27
|
-
const mcpToken =
|
|
27
|
+
const mcpServerUrl = getMcpServerUrl();
|
|
28
|
+
const mcpToken = getMcpToken();
|
|
28
29
|
// Try to create test report via MCP endpoint
|
|
29
30
|
// Claude Code should call this endpoint directly with the structured data
|
|
30
31
|
const response = await fetch(`${mcpServerUrl}/mcp`, {
|
|
@@ -103,8 +104,8 @@ export async function createTestReportResults(options) {
|
|
|
103
104
|
logInfo(`Creating ${testResults.length} test report results for report: ${testReportId}`);
|
|
104
105
|
}
|
|
105
106
|
try {
|
|
106
|
-
const mcpServerUrl =
|
|
107
|
-
const mcpToken =
|
|
107
|
+
const mcpServerUrl = getMcpServerUrl();
|
|
108
|
+
const mcpToken = getMcpToken();
|
|
108
109
|
const response = await fetch(`${mcpServerUrl}/mcp`, {
|
|
109
110
|
method: 'POST',
|
|
110
111
|
headers: {
|
|
@@ -157,8 +158,8 @@ async function manualMcpTestReportCreation(featureId, structuredReport, testResu
|
|
|
157
158
|
logInfo('Manually calling MCP test_reports/create endpoint with structured data');
|
|
158
159
|
}
|
|
159
160
|
try {
|
|
160
|
-
const mcpServerUrl =
|
|
161
|
-
const mcpToken =
|
|
161
|
+
const mcpServerUrl = getMcpServerUrl();
|
|
162
|
+
const mcpToken = getMcpToken();
|
|
162
163
|
// Manually construct and send the MCP request
|
|
163
164
|
const response = await fetch(`${mcpServerUrl}/mcp`, {
|
|
164
165
|
method: 'POST',
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Feedbacks service for pipeline integration
|
|
3
3
|
* Provides human-guided feedbacks to influence Claude Code behavior in each phase
|
|
4
4
|
*/
|
|
5
|
+
import { getMcpServerUrl, getMcpToken } from '../auth/auth-store.js';
|
|
5
6
|
import { downloadImagesForClaudeCode } from '../utils/image-downloader.js';
|
|
6
7
|
/**
|
|
7
8
|
* Fetch feedbacks for a specific phase
|
|
@@ -10,8 +11,8 @@ import { downloadImagesForClaudeCode } from '../utils/image-downloader.js';
|
|
|
10
11
|
*/
|
|
11
12
|
export async function getFeedbacksForPhase(options, phase, branchId) {
|
|
12
13
|
const { featureId, verbose } = options;
|
|
13
|
-
const mcpServerUrl =
|
|
14
|
-
const mcpToken =
|
|
14
|
+
const mcpServerUrl = getMcpServerUrl();
|
|
15
|
+
const mcpToken = getMcpToken();
|
|
15
16
|
// Convert phase name from hyphen to underscore format for database compatibility
|
|
16
17
|
// e.g., 'feature-analysis' -> 'feature_analysis'
|
|
17
18
|
const dbPhase = phase.replace(/-/g, '_');
|
|
@@ -207,8 +208,8 @@ function getPriorityBadge(priority) {
|
|
|
207
208
|
* Used after successful verification to track which feedbacks have been addressed
|
|
208
209
|
*/
|
|
209
210
|
export async function resolveFeedbacks(options, feedbackIds, verbose) {
|
|
210
|
-
const mcpServerUrl =
|
|
211
|
-
const mcpToken =
|
|
211
|
+
const mcpServerUrl = getMcpServerUrl();
|
|
212
|
+
const mcpToken = getMcpToken();
|
|
212
213
|
if (!feedbackIds || feedbackIds.length === 0) {
|
|
213
214
|
return;
|
|
214
215
|
}
|
package/dist/utils/validation.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getMcpServerUrl, getMcpToken } from '../auth/auth-store.js';
|
|
1
2
|
import { loadConfig, validateConfig } from '../config.js';
|
|
2
3
|
import { logInfo } from './logger.js';
|
|
3
4
|
/**
|
|
@@ -18,13 +19,13 @@ export const validateConfiguration = (options) => {
|
|
|
18
19
|
* Validate MCP environment variables and URL format
|
|
19
20
|
*/
|
|
20
21
|
export const validateMCPEnvironment = () => {
|
|
21
|
-
const mcpServerUrl =
|
|
22
|
-
const mcpToken =
|
|
22
|
+
const mcpServerUrl = getMcpServerUrl();
|
|
23
|
+
const mcpToken = getMcpToken();
|
|
23
24
|
if (!mcpServerUrl) {
|
|
24
|
-
throw new Error('
|
|
25
|
+
throw new Error('Not authenticated. Run `edsger login` or set EDSGER_MCP_SERVER_URL environment variable.');
|
|
25
26
|
}
|
|
26
27
|
if (!mcpToken) {
|
|
27
|
-
throw new Error('
|
|
28
|
+
throw new Error('Not authenticated. Run `edsger login` or set EDSGER_MCP_TOKEN environment variable.');
|
|
28
29
|
}
|
|
29
30
|
// Validate MCP server URL format
|
|
30
31
|
try {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { validateConfiguration } from './validation.js';
|
|
2
2
|
import { logInfo } from './logger.js';
|
|
3
|
+
import { getMcpServerUrl, getMcpToken } from '../auth/auth-store.js';
|
|
3
4
|
/**
|
|
4
5
|
* Validate workflow-specific environment variables
|
|
5
6
|
*/
|
|
6
7
|
export const validateWorkflowEnvironment = () => {
|
|
7
8
|
const productId = process.env.EDSGER_PRODUCT_ID;
|
|
8
|
-
const mcpServerUrl =
|
|
9
|
-
const mcpToken =
|
|
9
|
+
const mcpServerUrl = getMcpServerUrl();
|
|
10
|
+
const mcpToken = getMcpToken();
|
|
10
11
|
if (!productId) {
|
|
11
12
|
throw new Error('Product ID is required. Set EDSGER_PRODUCT_ID environment variable.');
|
|
12
13
|
}
|