edsger 0.26.4 → 0.27.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.
Files changed (137) hide show
  1. package/dist/api/cross-product.d.ts +31 -0
  2. package/dist/api/cross-product.js +111 -0
  3. package/dist/api/mcp-client.d.ts +6 -1
  4. package/dist/api/mcp-client.js +11 -5
  5. package/dist/auth/auth-store.d.ts +52 -0
  6. package/dist/auth/auth-store.js +117 -0
  7. package/dist/auth/login.d.ts +18 -0
  8. package/dist/auth/login.js +179 -0
  9. package/dist/commands/agent-workflow/feature-worker.d.ts +14 -0
  10. package/dist/commands/agent-workflow/feature-worker.js +65 -0
  11. package/dist/commands/agent-workflow/index.d.ts +13 -0
  12. package/dist/commands/agent-workflow/index.js +103 -0
  13. package/dist/commands/agent-workflow/processor.d.ts +48 -0
  14. package/dist/commands/agent-workflow/processor.js +260 -0
  15. package/dist/constants.d.ts +5 -0
  16. package/dist/constants.js +28 -0
  17. package/dist/index.js +67 -3
  18. package/dist/phases/pr-execution/index.d.ts +3 -1
  19. package/dist/phases/pr-execution/index.js +16 -32
  20. package/dist/phases/pr-execution/outcome.d.ts +0 -3
  21. package/dist/phases/pr-execution/outcome.js +2 -2
  22. package/dist/phases/pr-execution/pr-executor.d.ts +22 -10
  23. package/dist/phases/pr-execution/pr-executor.js +28 -74
  24. package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.d.ts +4 -0
  25. package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.js +133 -0
  26. package/dist/services/lifecycle-agent/__tests__/transition-rules.test.d.ts +4 -0
  27. package/dist/services/lifecycle-agent/__tests__/transition-rules.test.js +336 -0
  28. package/dist/services/lifecycle-agent/index.d.ts +24 -0
  29. package/dist/services/lifecycle-agent/index.js +25 -0
  30. package/dist/services/lifecycle-agent/phase-criteria.d.ts +57 -0
  31. package/dist/services/lifecycle-agent/phase-criteria.js +335 -0
  32. package/dist/services/lifecycle-agent/transition-rules.d.ts +60 -0
  33. package/dist/services/lifecycle-agent/transition-rules.js +184 -0
  34. package/dist/services/lifecycle-agent/types.d.ts +190 -0
  35. package/dist/services/lifecycle-agent/types.js +12 -0
  36. package/dist/services/pull-requests.d.ts +1 -0
  37. package/dist/system/session-manager.d.ts +55 -0
  38. package/dist/system/session-manager.js +130 -0
  39. package/dist/system/sleep-notification.d.ts +15 -0
  40. package/dist/system/sleep-notification.js +105 -0
  41. package/dist/system/sleep-prevention.d.ts +20 -0
  42. package/dist/system/sleep-prevention.js +112 -0
  43. package/dist/types/index.d.ts +2 -0
  44. package/dist/updater/auto-updater.d.ts +39 -0
  45. package/dist/updater/auto-updater.js +128 -0
  46. package/dist/utils/logger.js +12 -4
  47. package/dist/workspace/workspace-manager.d.ts +64 -0
  48. package/dist/workspace/workspace-manager.js +149 -0
  49. package/package.json +1 -1
  50. package/.claude/settings.local.json +0 -28
  51. package/.env.local +0 -12
  52. package/dist/api/features/__tests__/regression-prevention.test.d.ts +0 -5
  53. package/dist/api/features/__tests__/regression-prevention.test.js +0 -338
  54. package/dist/api/features/__tests__/status-updater.integration.test.d.ts +0 -5
  55. package/dist/api/features/__tests__/status-updater.integration.test.js +0 -497
  56. package/dist/commands/workflow/pipeline-runner.d.ts +0 -17
  57. package/dist/commands/workflow/pipeline-runner.js +0 -393
  58. package/dist/commands/workflow/runner.d.ts +0 -26
  59. package/dist/commands/workflow/runner.js +0 -119
  60. package/dist/commands/workflow/workflow-runner.d.ts +0 -26
  61. package/dist/commands/workflow/workflow-runner.js +0 -119
  62. package/dist/phases/code-implementation/analyzer-helpers.d.ts +0 -28
  63. package/dist/phases/code-implementation/analyzer-helpers.js +0 -177
  64. package/dist/phases/code-implementation/analyzer.d.ts +0 -32
  65. package/dist/phases/code-implementation/analyzer.js +0 -629
  66. package/dist/phases/code-implementation/context-fetcher.d.ts +0 -17
  67. package/dist/phases/code-implementation/context-fetcher.js +0 -86
  68. package/dist/phases/code-implementation/mcp-server.d.ts +0 -1
  69. package/dist/phases/code-implementation/mcp-server.js +0 -93
  70. package/dist/phases/code-implementation/prompts-improvement.d.ts +0 -5
  71. package/dist/phases/code-implementation/prompts-improvement.js +0 -108
  72. package/dist/phases/code-implementation-verification/verifier.d.ts +0 -31
  73. package/dist/phases/code-implementation-verification/verifier.js +0 -196
  74. package/dist/phases/code-refine/analyzer.d.ts +0 -41
  75. package/dist/phases/code-refine/analyzer.js +0 -561
  76. package/dist/phases/code-refine/context-fetcher.d.ts +0 -94
  77. package/dist/phases/code-refine/context-fetcher.js +0 -423
  78. package/dist/phases/code-refine-verification/analysis/llm-analyzer.d.ts +0 -22
  79. package/dist/phases/code-refine-verification/analysis/llm-analyzer.js +0 -134
  80. package/dist/phases/code-refine-verification/verifier.d.ts +0 -47
  81. package/dist/phases/code-refine-verification/verifier.js +0 -597
  82. package/dist/phases/code-review/analyzer.d.ts +0 -29
  83. package/dist/phases/code-review/analyzer.js +0 -363
  84. package/dist/phases/code-review/context-fetcher.d.ts +0 -92
  85. package/dist/phases/code-review/context-fetcher.js +0 -296
  86. package/dist/phases/feature-analysis/analyzer-helpers.d.ts +0 -10
  87. package/dist/phases/feature-analysis/analyzer-helpers.js +0 -47
  88. package/dist/phases/feature-analysis/analyzer.d.ts +0 -11
  89. package/dist/phases/feature-analysis/analyzer.js +0 -208
  90. package/dist/phases/feature-analysis/context-fetcher.d.ts +0 -26
  91. package/dist/phases/feature-analysis/context-fetcher.js +0 -134
  92. package/dist/phases/feature-analysis/http-fallback.d.ts +0 -20
  93. package/dist/phases/feature-analysis/http-fallback.js +0 -95
  94. package/dist/phases/feature-analysis/mcp-server.d.ts +0 -1
  95. package/dist/phases/feature-analysis/mcp-server.js +0 -144
  96. package/dist/phases/feature-analysis/prompts-improvement.d.ts +0 -8
  97. package/dist/phases/feature-analysis/prompts-improvement.js +0 -109
  98. package/dist/phases/feature-analysis-verification/verifier.d.ts +0 -37
  99. package/dist/phases/feature-analysis-verification/verifier.js +0 -147
  100. package/dist/phases/technical-design/analyzer-helpers.d.ts +0 -25
  101. package/dist/phases/technical-design/analyzer-helpers.js +0 -39
  102. package/dist/phases/technical-design/analyzer.d.ts +0 -21
  103. package/dist/phases/technical-design/analyzer.js +0 -461
  104. package/dist/phases/technical-design/context-fetcher.d.ts +0 -12
  105. package/dist/phases/technical-design/context-fetcher.js +0 -39
  106. package/dist/phases/technical-design/http-fallback.d.ts +0 -17
  107. package/dist/phases/technical-design/http-fallback.js +0 -151
  108. package/dist/phases/technical-design/mcp-server.d.ts +0 -1
  109. package/dist/phases/technical-design/mcp-server.js +0 -157
  110. package/dist/phases/technical-design/prompts-improvement.d.ts +0 -5
  111. package/dist/phases/technical-design/prompts-improvement.js +0 -93
  112. package/dist/phases/technical-design-verification/verifier.d.ts +0 -53
  113. package/dist/phases/technical-design-verification/verifier.js +0 -170
  114. package/dist/services/feature-branches.d.ts +0 -77
  115. package/dist/services/feature-branches.js +0 -205
  116. package/dist/workflow-runner/config/phase-configs.d.ts +0 -5
  117. package/dist/workflow-runner/config/phase-configs.js +0 -120
  118. package/dist/workflow-runner/core/feature-filter.d.ts +0 -16
  119. package/dist/workflow-runner/core/feature-filter.js +0 -46
  120. package/dist/workflow-runner/core/index.d.ts +0 -8
  121. package/dist/workflow-runner/core/index.js +0 -12
  122. package/dist/workflow-runner/core/pipeline-evaluator.d.ts +0 -24
  123. package/dist/workflow-runner/core/pipeline-evaluator.js +0 -32
  124. package/dist/workflow-runner/core/state-manager.d.ts +0 -24
  125. package/dist/workflow-runner/core/state-manager.js +0 -42
  126. package/dist/workflow-runner/core/workflow-logger.d.ts +0 -20
  127. package/dist/workflow-runner/core/workflow-logger.js +0 -65
  128. package/dist/workflow-runner/executors/phase-executor.d.ts +0 -8
  129. package/dist/workflow-runner/executors/phase-executor.js +0 -248
  130. package/dist/workflow-runner/feature-workflow-runner.d.ts +0 -26
  131. package/dist/workflow-runner/feature-workflow-runner.js +0 -119
  132. package/dist/workflow-runner/index.d.ts +0 -2
  133. package/dist/workflow-runner/index.js +0 -2
  134. package/dist/workflow-runner/pipeline-runner.d.ts +0 -17
  135. package/dist/workflow-runner/pipeline-runner.js +0 -393
  136. package/dist/workflow-runner/workflow-processor.d.ts +0 -54
  137. package/dist/workflow-runner/workflow-processor.js +0 -170
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Cross-product API - Fetch features across all products
3
+ *
4
+ * Used in the new default mode (agent workflow) where the CLI
5
+ * processes features from all products the user has access to,
6
+ * not just a single product.
7
+ */
8
+ import { FeatureInfo } from '../types/features.js';
9
+ export interface ProductSummary {
10
+ id: string;
11
+ name: string;
12
+ description?: string;
13
+ status?: string;
14
+ }
15
+ export interface FeatureWithProduct extends FeatureInfo {
16
+ product_name?: string;
17
+ }
18
+ /**
19
+ * List all products the authenticated user has access to
20
+ */
21
+ export declare function listProducts(verbose?: boolean): Promise<ProductSummary[]>;
22
+ /**
23
+ * List all ready_for_ai features across all products
24
+ * Iterates through all accessible products and collects their features
25
+ */
26
+ export declare function listAllReadyFeatures(verbose?: boolean): Promise<FeatureWithProduct[]>;
27
+ /**
28
+ * Claim a specific feature for processing
29
+ * Unlike the product-level claim, this claims a specific feature by ID
30
+ */
31
+ export declare function claimFeatureById(featureId: string, productId: string, verbose?: boolean): Promise<FeatureInfo | null>;
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Cross-product API - Fetch features across all products
3
+ *
4
+ * Used in the new default mode (agent workflow) where the CLI
5
+ * processes features from all products the user has access to,
6
+ * not just a single product.
7
+ */
8
+ import { callMcpEndpoint } from './mcp-client.js';
9
+ import { logInfo, logError } from '../utils/logger.js';
10
+ /**
11
+ * List all products the authenticated user has access to
12
+ */
13
+ export async function listProducts(verbose) {
14
+ if (verbose) {
15
+ logInfo('Fetching products...');
16
+ }
17
+ try {
18
+ const result = (await callMcpEndpoint('products/list', {}));
19
+ const products = result.products || [];
20
+ if (verbose) {
21
+ logInfo(`Found ${products.length} product(s)`);
22
+ }
23
+ return products;
24
+ }
25
+ catch (error) {
26
+ logError(`Failed to list products: ${error instanceof Error ? error.message : String(error)}`);
27
+ throw error;
28
+ }
29
+ }
30
+ /**
31
+ * List all ready_for_ai features across all products
32
+ * Iterates through all accessible products and collects their features
33
+ */
34
+ export async function listAllReadyFeatures(verbose) {
35
+ if (verbose) {
36
+ logInfo('Fetching ready_for_ai features across all products...');
37
+ }
38
+ try {
39
+ // First, get all products
40
+ const products = await listProducts(verbose);
41
+ if (products.length === 0) {
42
+ if (verbose) {
43
+ logInfo('No products found');
44
+ }
45
+ return [];
46
+ }
47
+ // Fetch ready_for_ai features for all products in parallel
48
+ const featureResults = await Promise.allSettled(products.map(async (product) => {
49
+ const result = (await callMcpEndpoint('features/list', {
50
+ product_id: product.id,
51
+ status: 'ready_for_ai',
52
+ }));
53
+ return (result.features || []).map((feature) => ({
54
+ ...feature,
55
+ product_name: product.name,
56
+ }));
57
+ }));
58
+ const allFeatures = [];
59
+ featureResults.forEach((result, i) => {
60
+ if (result.status === 'fulfilled') {
61
+ allFeatures.push(...result.value);
62
+ }
63
+ else if (verbose) {
64
+ logInfo(`Could not fetch features for product: ${products[i].name}`);
65
+ }
66
+ });
67
+ // Sort by updated_at (oldest first)
68
+ allFeatures.sort((a, b) => {
69
+ const dateA = new Date(a.updated_at || 0).getTime();
70
+ const dateB = new Date(b.updated_at || 0).getTime();
71
+ return dateA - dateB;
72
+ });
73
+ if (verbose) {
74
+ logInfo(`Found ${allFeatures.length} ready_for_ai feature(s) across ${products.length} product(s)`);
75
+ allFeatures.forEach((f, i) => {
76
+ logInfo(` ${i + 1}. [${f.product_name}] ${f.name}`);
77
+ });
78
+ }
79
+ return allFeatures;
80
+ }
81
+ catch (error) {
82
+ logError(`Failed to list features: ${error instanceof Error ? error.message : String(error)}`);
83
+ throw error;
84
+ }
85
+ }
86
+ /**
87
+ * Claim a specific feature for processing
88
+ * Unlike the product-level claim, this claims a specific feature by ID
89
+ */
90
+ export async function claimFeatureById(featureId, productId, verbose) {
91
+ if (verbose) {
92
+ logInfo(`Claiming feature: ${featureId}`);
93
+ }
94
+ try {
95
+ const result = (await callMcpEndpoint('features/claim', {
96
+ product_id: productId,
97
+ feature_id: featureId,
98
+ }));
99
+ if (result.feature) {
100
+ if (verbose) {
101
+ logInfo(`Claimed feature: ${result.feature.name}`);
102
+ }
103
+ return result.feature;
104
+ }
105
+ return null;
106
+ }
107
+ catch (error) {
108
+ logError(`Failed to claim feature: ${error instanceof Error ? error.message : String(error)}`);
109
+ return null;
110
+ }
111
+ }
@@ -1,5 +1,10 @@
1
1
  /**
2
2
  * Common MCP client utilities for making HTTP requests to MCP servers
3
+ *
4
+ * Supports two authentication modes:
5
+ * 1. Stored auth via `edsger login` (~/.edsger/auth.json)
6
+ * 2. Environment variables (EDSGER_MCP_SERVER_URL, EDSGER_MCP_TOKEN)
7
+ * Environment variables take precedence over stored auth.
3
8
  */
4
9
  export interface McpRequestOptions {
5
10
  method: string;
@@ -8,7 +13,7 @@ export interface McpRequestOptions {
8
13
  }
9
14
  /**
10
15
  * Helper function to make HTTP requests to the MCP server
11
- * Reads EDSGER_MCP_SERVER_URL and EDSGER_MCP_TOKEN from environment variables
16
+ * Uses stored auth from `edsger login` or environment variables
12
17
  */
13
18
  export declare function callMcpEndpoint(method: string, params: unknown): Promise<unknown>;
14
19
  /**
@@ -1,18 +1,24 @@
1
1
  /**
2
2
  * Common MCP client utilities for making HTTP requests to MCP servers
3
+ *
4
+ * Supports two authentication modes:
5
+ * 1. Stored auth via `edsger login` (~/.edsger/auth.json)
6
+ * 2. Environment variables (EDSGER_MCP_SERVER_URL, EDSGER_MCP_TOKEN)
7
+ * Environment variables take precedence over stored auth.
3
8
  */
9
+ import { getMcpServerUrl, getMcpToken } from '../auth/auth-store.js';
4
10
  /**
5
11
  * Helper function to make HTTP requests to the MCP server
6
- * Reads EDSGER_MCP_SERVER_URL and EDSGER_MCP_TOKEN from environment variables
12
+ * Uses stored auth from `edsger login` or environment variables
7
13
  */
8
14
  export async function callMcpEndpoint(method, params) {
9
- const mcpServerUrl = process.env.EDSGER_MCP_SERVER_URL;
10
- const mcpToken = process.env.EDSGER_MCP_TOKEN;
15
+ const mcpServerUrl = getMcpServerUrl();
16
+ const mcpToken = getMcpToken();
11
17
  if (!mcpServerUrl) {
12
- throw new Error('EDSGER_MCP_SERVER_URL environment variable is not set');
18
+ throw new Error('Not authenticated. Run `edsger login` or set EDSGER_MCP_SERVER_URL environment variable.');
13
19
  }
14
20
  if (!mcpToken) {
15
- throw new Error('EDSGER_MCP_TOKEN environment variable is not set');
21
+ throw new Error('Not authenticated. Run `edsger login` or set EDSGER_MCP_TOKEN environment variable.');
16
22
  }
17
23
  try {
18
24
  const response = await fetch(`${mcpServerUrl}/mcp`, {
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Auth Store - Persistent authentication storage for the Edsger CLI
3
+ *
4
+ * Stores auth credentials in ~/.edsger/auth.json
5
+ * Provides read/write/clear operations for auth tokens
6
+ */
7
+ export interface AuthConfig {
8
+ /** MCP server URL (e.g., https://xxx.supabase.co/functions/v1) */
9
+ mcpServerUrl: string;
10
+ /** MCP auth token */
11
+ mcpToken: string;
12
+ /** Timestamp of when login was performed */
13
+ loggedInAt: string;
14
+ /** Edsger.ai base URL */
15
+ edsgerBaseUrl?: string;
16
+ }
17
+ /**
18
+ * Save auth configuration to ~/.edsger/auth.json
19
+ */
20
+ export declare function saveAuth(config: AuthConfig): void;
21
+ /**
22
+ * Load auth configuration from ~/.edsger/auth.json
23
+ * Returns null if no auth file exists.
24
+ * Results are cached in memory to avoid repeated disk reads.
25
+ */
26
+ export declare function loadAuth(): AuthConfig | null;
27
+ /**
28
+ * Clear stored auth (logout)
29
+ */
30
+ export declare function clearAuth(): void;
31
+ /**
32
+ * Check if user is logged in (has stored auth)
33
+ */
34
+ export declare function isLoggedIn(): boolean;
35
+ /**
36
+ * Get the MCP server URL from stored auth or environment variable
37
+ * Stored auth takes lower priority than environment variables
38
+ */
39
+ export declare function getMcpServerUrl(): string | undefined;
40
+ /**
41
+ * Get the MCP token from stored auth or environment variable
42
+ * Environment variable takes precedence
43
+ */
44
+ export declare function getMcpToken(): string | undefined;
45
+ /**
46
+ * Get the Edsger base URL (defaults to https://edsger.ai)
47
+ */
48
+ export declare function getEdsgerBaseUrl(): string;
49
+ /**
50
+ * Get the auth file path (for display purposes)
51
+ */
52
+ export declare function getAuthFilePath(): string;
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Auth Store - Persistent authentication storage for the Edsger CLI
3
+ *
4
+ * Stores auth credentials in ~/.edsger/auth.json
5
+ * Provides read/write/clear operations for auth tokens
6
+ */
7
+ import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync, chmodSync } from 'fs';
8
+ import { join } from 'path';
9
+ import { homedir } from 'os';
10
+ const EDSGER_DIR = join(homedir(), '.edsger');
11
+ const AUTH_FILE = join(EDSGER_DIR, 'auth.json');
12
+ /** In-memory cache for auth config to avoid repeated disk reads */
13
+ let _authCache = undefined;
14
+ /**
15
+ * Ensure the ~/.edsger directory exists with restricted permissions
16
+ */
17
+ function ensureEdsgerDir() {
18
+ if (!existsSync(EDSGER_DIR)) {
19
+ mkdirSync(EDSGER_DIR, { recursive: true, mode: 0o700 });
20
+ }
21
+ }
22
+ /**
23
+ * Save auth configuration to ~/.edsger/auth.json
24
+ */
25
+ export function saveAuth(config) {
26
+ ensureEdsgerDir();
27
+ writeFileSync(AUTH_FILE, JSON.stringify(config, null, 2), 'utf-8');
28
+ // Restrict file permissions to owner only (contains sensitive token)
29
+ try {
30
+ chmodSync(AUTH_FILE, 0o600);
31
+ }
32
+ catch {
33
+ // chmod may fail on Windows, ignore
34
+ }
35
+ // Update cache
36
+ _authCache = config;
37
+ }
38
+ /**
39
+ * Load auth configuration from ~/.edsger/auth.json
40
+ * Returns null if no auth file exists.
41
+ * Results are cached in memory to avoid repeated disk reads.
42
+ */
43
+ export function loadAuth() {
44
+ if (_authCache !== undefined) {
45
+ return _authCache;
46
+ }
47
+ try {
48
+ if (!existsSync(AUTH_FILE)) {
49
+ _authCache = null;
50
+ return null;
51
+ }
52
+ const content = readFileSync(AUTH_FILE, 'utf-8');
53
+ _authCache = JSON.parse(content);
54
+ return _authCache;
55
+ }
56
+ catch {
57
+ _authCache = null;
58
+ return null;
59
+ }
60
+ }
61
+ /**
62
+ * Clear stored auth (logout)
63
+ */
64
+ export function clearAuth() {
65
+ _authCache = undefined;
66
+ try {
67
+ if (existsSync(AUTH_FILE)) {
68
+ unlinkSync(AUTH_FILE);
69
+ }
70
+ }
71
+ catch {
72
+ // Ignore errors during cleanup
73
+ }
74
+ }
75
+ /**
76
+ * Check if user is logged in (has stored auth)
77
+ */
78
+ export function isLoggedIn() {
79
+ return loadAuth() !== null;
80
+ }
81
+ /**
82
+ * Get the MCP server URL from stored auth or environment variable
83
+ * Stored auth takes lower priority than environment variables
84
+ */
85
+ export function getMcpServerUrl() {
86
+ // Environment variable takes precedence
87
+ if (process.env.EDSGER_MCP_SERVER_URL) {
88
+ return process.env.EDSGER_MCP_SERVER_URL;
89
+ }
90
+ const auth = loadAuth();
91
+ return auth?.mcpServerUrl;
92
+ }
93
+ /**
94
+ * Get the MCP token from stored auth or environment variable
95
+ * Environment variable takes precedence
96
+ */
97
+ export function getMcpToken() {
98
+ // Environment variable takes precedence
99
+ if (process.env.EDSGER_MCP_TOKEN) {
100
+ return process.env.EDSGER_MCP_TOKEN;
101
+ }
102
+ const auth = loadAuth();
103
+ return auth?.mcpToken;
104
+ }
105
+ /**
106
+ * Get the Edsger base URL (defaults to https://edsger.ai)
107
+ */
108
+ export function getEdsgerBaseUrl() {
109
+ const auth = loadAuth();
110
+ return auth?.edsgerBaseUrl || process.env.EDSGER_BASE_URL || 'https://edsger.ai';
111
+ }
112
+ /**
113
+ * Get the auth file path (for display purposes)
114
+ */
115
+ export function getAuthFilePath() {
116
+ return AUTH_FILE;
117
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Login Command - Browser-based authentication for Edsger CLI
3
+ *
4
+ * Opens the user's browser to edsger.ai/cli/auth where they can
5
+ * copy a token, then paste it into the CLI to complete login.
6
+ */
7
+ /**
8
+ * Run the login flow
9
+ */
10
+ export declare function runLogin(): Promise<void>;
11
+ /**
12
+ * Run the logout flow
13
+ */
14
+ export declare function runLogout(): Promise<void>;
15
+ /**
16
+ * Show current login status
17
+ */
18
+ export declare function runStatus(): Promise<void>;
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Login Command - Browser-based authentication for Edsger CLI
3
+ *
4
+ * Opens the user's browser to edsger.ai/cli/auth where they can
5
+ * copy a token, then paste it into the CLI to complete login.
6
+ */
7
+ import { createInterface } from 'readline';
8
+ import { execSync } from 'child_process';
9
+ import { platform } from 'os';
10
+ import { saveAuth, loadAuth, clearAuth, getEdsgerBaseUrl, getAuthFilePath } from './auth-store.js';
11
+ import { logInfo, logSuccess, logError, logWarning } from '../utils/logger.js';
12
+ /**
13
+ * Open a URL in the user's default browser
14
+ */
15
+ function openBrowser(url) {
16
+ try {
17
+ const os = platform();
18
+ if (os === 'darwin') {
19
+ execSync(`open "${url}"`);
20
+ }
21
+ else if (os === 'win32') {
22
+ execSync(`start "${url}"`);
23
+ }
24
+ else {
25
+ // Linux - try xdg-open, then fallback to common browsers
26
+ try {
27
+ execSync(`xdg-open "${url}"`);
28
+ }
29
+ catch {
30
+ try {
31
+ execSync(`sensible-browser "${url}"`);
32
+ }
33
+ catch {
34
+ return false;
35
+ }
36
+ }
37
+ }
38
+ return true;
39
+ }
40
+ catch {
41
+ return false;
42
+ }
43
+ }
44
+ /**
45
+ * Read a line from stdin (with optional masking for sensitive input)
46
+ */
47
+ function readLine(prompt) {
48
+ const rl = createInterface({
49
+ input: process.stdin,
50
+ output: process.stdout,
51
+ });
52
+ return new Promise((resolve) => {
53
+ rl.question(prompt, (answer) => {
54
+ rl.close();
55
+ resolve(answer.trim());
56
+ });
57
+ });
58
+ }
59
+ /** Default MCP server URL */
60
+ const MCP_SERVER_URL = 'https://ktkogvogdaffjmvrewiu.supabase.co/functions/v1';
61
+ /**
62
+ * Run the login flow
63
+ */
64
+ export async function runLogin() {
65
+ const baseUrl = getEdsgerBaseUrl();
66
+ const authUrl = `${baseUrl}/cli/auth`;
67
+ logInfo('Starting Edsger CLI login...');
68
+ console.log();
69
+ // Check if already logged in
70
+ const existingAuth = loadAuth();
71
+ if (existingAuth) {
72
+ logWarning('You are already logged in.');
73
+ const answer = await readLine('Do you want to re-login? (y/N): ');
74
+ if (answer.toLowerCase() !== 'y') {
75
+ logInfo('Login cancelled. Using existing credentials.');
76
+ return;
77
+ }
78
+ }
79
+ // Open browser
80
+ console.log(` Opening browser to: ${authUrl}`);
81
+ console.log();
82
+ const opened = openBrowser(authUrl);
83
+ if (!opened) {
84
+ logWarning(`Could not open browser automatically.`);
85
+ console.log(` Please open this URL manually:`);
86
+ console.log(` ${authUrl}`);
87
+ console.log();
88
+ }
89
+ console.log(' 1. Sign in to edsger.ai (if not already signed in)');
90
+ console.log(' 2. Click "Generate CLI Token" on the page');
91
+ console.log(' 3. Copy the CLI Token and paste it below');
92
+ console.log();
93
+ const mcpServerUrl = process.env.EDSGER_MCP_SERVER_URL || MCP_SERVER_URL;
94
+ // Read token
95
+ const mcpToken = await readLine('CLI Token: ');
96
+ if (!mcpToken) {
97
+ logError('Token is required. Login cancelled.');
98
+ return;
99
+ }
100
+ // Validate the token by making a test request
101
+ logInfo('Validating credentials...');
102
+ try {
103
+ const response = await fetch(`${mcpServerUrl}/mcp`, {
104
+ method: 'POST',
105
+ headers: {
106
+ 'Content-Type': 'application/json',
107
+ Authorization: `Bearer ${mcpToken}`,
108
+ },
109
+ body: JSON.stringify({
110
+ jsonrpc: '2.0',
111
+ method: 'products/list',
112
+ params: {},
113
+ id: 'login-validation',
114
+ }),
115
+ });
116
+ if (!response.ok) {
117
+ logError(`Authentication failed: HTTP ${response.status}`);
118
+ logError('Please check your token and try again.');
119
+ return;
120
+ }
121
+ const data = await response.json();
122
+ if (data.error) {
123
+ logError(`Authentication failed: ${data.error.message}`);
124
+ return;
125
+ }
126
+ // Save auth
127
+ saveAuth({
128
+ mcpServerUrl,
129
+ mcpToken,
130
+ loggedInAt: new Date().toISOString(),
131
+ edsgerBaseUrl: baseUrl,
132
+ });
133
+ console.log();
134
+ logSuccess('Login successful!');
135
+ logInfo(`Credentials saved to ${getAuthFilePath()}`);
136
+ // Show available products
137
+ const products = data.result?.products || [];
138
+ if (products.length > 0) {
139
+ console.log();
140
+ logInfo(`You have access to ${products.length} product(s):`);
141
+ products.forEach((p, i) => {
142
+ console.log(` ${i + 1}. ${p.name} (${p.id})`);
143
+ });
144
+ }
145
+ console.log();
146
+ logInfo('You can now run `edsger` to start processing features.');
147
+ }
148
+ catch (error) {
149
+ logError(`Connection failed: ${error instanceof Error ? error.message : String(error)}`);
150
+ logError('Please check the MCP server URL and try again.');
151
+ }
152
+ }
153
+ /**
154
+ * Run the logout flow
155
+ */
156
+ export async function runLogout() {
157
+ const auth = loadAuth();
158
+ if (!auth) {
159
+ logInfo('You are not logged in.');
160
+ return;
161
+ }
162
+ clearAuth();
163
+ logSuccess('Logged out successfully.');
164
+ logInfo(`Credentials removed from ${getAuthFilePath()}`);
165
+ }
166
+ /**
167
+ * Show current login status
168
+ */
169
+ export async function runStatus() {
170
+ const auth = loadAuth();
171
+ if (!auth) {
172
+ logInfo('Not logged in. Run `edsger login` to authenticate.');
173
+ return;
174
+ }
175
+ logInfo('Login status:');
176
+ console.log(` Server: ${auth.mcpServerUrl}`);
177
+ console.log(` Logged in at: ${auth.loggedInAt}`);
178
+ console.log(` Token: ${auth.mcpToken.substring(0, 8)}...${auth.mcpToken.substring(auth.mcpToken.length - 4)}`);
179
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Feature Worker - Child process entry point for processing a single feature
3
+ *
4
+ * This file is spawned by the parent AgentWorkflowProcessor via child_process.fork().
5
+ * Each worker runs in its own process with its own cwd, which:
6
+ * 1. Allows concurrent feature processing (no shared process.chdir())
7
+ * 2. After auto-update, new workers load the latest code from disk
8
+ *
9
+ * Communication with parent via IPC messages:
10
+ * - Parent sends: { type: 'start', featureId, verbose, config }
11
+ * - Worker sends: { type: 'result', success: boolean, featureId }
12
+ * - Worker sends: { type: 'log', level, message } for logging
13
+ */
14
+ export {};
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Feature Worker - Child process entry point for processing a single feature
3
+ *
4
+ * This file is spawned by the parent AgentWorkflowProcessor via child_process.fork().
5
+ * Each worker runs in its own process with its own cwd, which:
6
+ * 1. Allows concurrent feature processing (no shared process.chdir())
7
+ * 2. After auto-update, new workers load the latest code from disk
8
+ *
9
+ * Communication with parent via IPC messages:
10
+ * - Parent sends: { type: 'start', featureId, verbose, config }
11
+ * - Worker sends: { type: 'result', success: boolean, featureId }
12
+ * - Worker sends: { type: 'log', level, message } for logging
13
+ */
14
+ import { runFeatureWorkflow } from '../workflow/feature-coordinator.js';
15
+ import { evaluatePipelineResults } from '../workflow/core/pipeline-evaluator.js';
16
+ function sendMessage(msg) {
17
+ if (process.send) {
18
+ process.send(msg);
19
+ }
20
+ }
21
+ function log(level, message) {
22
+ sendMessage({ type: 'log', level, message });
23
+ }
24
+ async function handleStart(msg) {
25
+ const { featureId, verbose, config } = msg;
26
+ try {
27
+ log('info', `Worker started for feature: ${featureId}`);
28
+ const results = await runFeatureWorkflow({ featureId, verbose }, config);
29
+ const allSuccessful = evaluatePipelineResults(results);
30
+ sendMessage({
31
+ type: 'result',
32
+ featureId,
33
+ success: allSuccessful,
34
+ });
35
+ }
36
+ catch (error) {
37
+ const errorMessage = error instanceof Error ? error.message : String(error);
38
+ log('error', `Worker error for feature ${featureId}: ${errorMessage}`);
39
+ sendMessage({
40
+ type: 'result',
41
+ featureId,
42
+ success: false,
43
+ error: errorMessage,
44
+ });
45
+ }
46
+ }
47
+ // Listen for messages from parent
48
+ process.on('message', (msg) => {
49
+ if (msg.type === 'start') {
50
+ handleStart(msg).finally(() => {
51
+ // Exit worker process after completion
52
+ process.exit(0);
53
+ });
54
+ }
55
+ });
56
+ // Handle uncaught errors
57
+ process.on('uncaughtException', (error) => {
58
+ sendMessage({
59
+ type: 'result',
60
+ featureId: 'unknown',
61
+ success: false,
62
+ error: `Uncaught exception: ${error.message}`,
63
+ });
64
+ process.exit(1);
65
+ });
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Agent Workflow - New default workflow mode
3
+ *
4
+ * This is the new cross-product workflow that:
5
+ * 1. Uses stored auth from `edsger login` (no per-repo env config needed)
6
+ * 2. Fetches ready_for_ai features across ALL products
7
+ * 3. Clones repos using GitHub App installation tokens
8
+ * 4. Manages workspace directories with feature ID naming
9
+ * 5. Runs continuously with auto-update, sleep prevention, and session management
10
+ * 6. Responds to web dashboard commands (pause/resume/stop)
11
+ */
12
+ import { CliOptions } from '../../types/index.js';
13
+ export declare function runAgentWorkflow(options: CliOptions): Promise<void>;