edsger 0.53.0 → 0.54.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/README.md +20 -0
- package/dist/api/financing.d.ts +47 -0
- package/dist/api/financing.js +37 -0
- package/dist/api/issues/approval-checker.d.ts +11 -9
- package/dist/api/issues/approval-checker.js +30 -41
- package/dist/api/issues/status-updater.d.ts +47 -20
- package/dist/api/issues/status-updater.js +114 -46
- package/dist/api/issues/update-issue.d.ts +5 -0
- package/dist/api/issues/update-issue.js +6 -0
- package/dist/commands/agent-workflow/processor.js +5 -1
- package/dist/commands/checklists/index.d.ts +5 -2
- package/dist/commands/checklists/index.js +73 -12
- package/dist/commands/checklists/tools.d.ts +14 -7
- package/dist/commands/checklists/tools.js +15 -208
- package/dist/commands/financing-deck/index.d.ts +8 -0
- package/dist/commands/financing-deck/index.js +66 -0
- package/dist/commands/find-architecture/index.d.ts +13 -0
- package/dist/commands/find-architecture/index.js +41 -0
- package/dist/commands/sync-github-issues/index.d.ts +11 -0
- package/dist/commands/sync-github-issues/index.js +42 -0
- package/dist/commands/sync-sentry-issues/index.d.ts +14 -0
- package/dist/commands/sync-sentry-issues/index.js +73 -0
- package/dist/commands/workflow/executors/phase-executor.js +6 -4
- package/dist/commands/workflow/phase-orchestrator.js +0 -1
- package/dist/config/issue-status.d.ts +18 -45
- package/dist/config/issue-status.js +21 -107
- package/dist/index.js +97 -3
- package/dist/phases/app-store-generation/agent.js +2 -1
- package/dist/phases/app-store-generation/index.js +11 -3
- package/dist/phases/autonomous/index.js +9 -6
- package/dist/phases/branch-planning/index.js +1 -2
- package/dist/phases/branch-planning/prompts.d.ts +1 -1
- package/dist/phases/branch-planning/prompts.js +3 -2
- package/dist/phases/bug-fixing/analyzer.js +6 -3
- package/dist/phases/bug-fixing/mcp-server.d.ts +18 -1
- package/dist/phases/bug-fixing/mcp-server.js +19 -76
- package/dist/phases/chat-processor/product-tools.d.ts +5 -8
- package/dist/phases/chat-processor/product-tools.js +6 -512
- package/dist/phases/chat-processor/tools.d.ts +5 -9
- package/dist/phases/chat-processor/tools.js +6 -704
- package/dist/phases/code-implementation/branch-pr-creator.js +7 -5
- package/dist/phases/code-implementation/index.js +6 -3
- package/dist/phases/code-implementation-verification/agent.js +6 -1
- package/dist/phases/code-refine/index.js +8 -6
- package/dist/phases/code-refine/refine-iteration.js +2 -1
- package/dist/phases/code-review/index.js +8 -6
- package/dist/phases/code-testing/analyzer.js +11 -8
- package/dist/phases/financing-deck/agent.d.ts +1 -0
- package/dist/phases/financing-deck/agent.js +96 -0
- package/dist/phases/financing-deck/context.d.ts +13 -0
- package/dist/phases/financing-deck/context.js +69 -0
- package/dist/phases/financing-deck/index.d.ts +15 -0
- package/dist/phases/financing-deck/index.js +89 -0
- package/dist/phases/financing-deck/prompts.d.ts +2 -0
- package/dist/phases/financing-deck/prompts.js +94 -0
- package/dist/phases/find-architecture/index.d.ts +44 -0
- package/dist/phases/find-architecture/index.js +248 -0
- package/dist/phases/find-architecture/prompts.d.ts +31 -0
- package/dist/phases/find-architecture/prompts.js +128 -0
- package/dist/phases/find-architecture/state.d.ts +21 -0
- package/dist/phases/find-architecture/state.js +17 -0
- package/dist/phases/find-architecture/types.d.ts +55 -0
- package/dist/phases/find-architecture/types.js +69 -0
- package/dist/phases/find-bugs/index.js +13 -4
- package/dist/phases/find-features/index.js +10 -5
- package/dist/phases/find-smells/index.js +10 -3
- package/dist/phases/functional-testing/analyzer.js +27 -17
- package/dist/phases/functional-testing/http-fallback.d.ts +1 -1
- package/dist/phases/functional-testing/http-fallback.js +32 -16
- package/dist/phases/functional-testing/mcp-server.d.ts +9 -1
- package/dist/phases/functional-testing/mcp-server.js +13 -132
- package/dist/phases/growth-analysis/agent.js +2 -2
- package/dist/phases/growth-analysis/index.js +9 -3
- package/dist/phases/intelligence-analysis/agent.js +2 -2
- package/dist/phases/intelligence-analysis/index.js +9 -2
- package/dist/phases/issue-analysis/agent.d.ts +9 -1
- package/dist/phases/issue-analysis/agent.js +68 -27
- package/dist/phases/issue-analysis/context.d.ts +5 -9
- package/dist/phases/issue-analysis/context.js +31 -76
- package/dist/phases/issue-analysis/index.js +32 -84
- package/dist/phases/issue-analysis/outcome.d.ts +3 -33
- package/dist/phases/issue-analysis/outcome.js +15 -253
- package/dist/phases/issue-analysis/prompts.d.ts +3 -5
- package/dist/phases/issue-analysis/prompts.js +45 -158
- package/dist/phases/issue-analysis-verification/agent.d.ts +4 -4
- package/dist/phases/issue-analysis-verification/agent.js +5 -5
- package/dist/phases/issue-analysis-verification/index.d.ts +4 -2
- package/dist/phases/issue-analysis-verification/index.js +9 -22
- package/dist/phases/issue-analysis-verification/prompts.d.ts +1 -2
- package/dist/phases/issue-analysis-verification/prompts.js +21 -46
- package/dist/phases/output-contracts.js +66 -78
- package/dist/phases/pr-execution/context.d.ts +2 -0
- package/dist/phases/pr-execution/context.js +1 -0
- package/dist/phases/pr-execution/index.js +28 -19
- package/dist/phases/pr-execution/prompts.d.ts +2 -1
- package/dist/phases/pr-execution/prompts.js +12 -10
- package/dist/phases/pr-resolve/index.js +2 -8
- package/dist/phases/pr-splitting/index.js +3 -3
- package/dist/phases/pr-splitting/prompts.d.ts +1 -1
- package/dist/phases/pr-splitting/prompts.js +3 -2
- package/dist/phases/pull-request/creator.js +10 -7
- package/dist/phases/pull-request/handler.js +3 -1
- package/dist/phases/release-sync/index.js +52 -43
- package/dist/phases/run-sheet/index.js +2 -1
- package/dist/phases/smoke-test/agent.js +2 -1
- package/dist/phases/smoke-test/index.js +4 -1
- package/dist/phases/sync-github-issues/index.d.ts +41 -0
- package/dist/phases/sync-github-issues/index.js +187 -0
- package/dist/phases/sync-github-issues/state.d.ts +26 -0
- package/dist/phases/sync-github-issues/state.js +18 -0
- package/dist/phases/sync-github-issues/types.d.ts +35 -0
- package/dist/phases/sync-github-issues/types.js +6 -0
- package/dist/phases/sync-sentry-issues/index.d.ts +29 -0
- package/dist/phases/sync-sentry-issues/index.js +153 -0
- package/dist/phases/sync-sentry-issues/sentry-client.d.ts +66 -0
- package/dist/phases/sync-sentry-issues/sentry-client.js +221 -0
- package/dist/phases/sync-sentry-issues/state.d.ts +23 -0
- package/dist/phases/sync-sentry-issues/state.js +18 -0
- package/dist/phases/sync-sentry-issues/types.d.ts +46 -0
- package/dist/phases/sync-sentry-issues/types.js +6 -0
- package/dist/phases/sync-shared/mcp.d.ts +81 -0
- package/dist/phases/sync-shared/mcp.js +111 -0
- package/dist/phases/technical-design/index.js +0 -1
- package/dist/phases/test-cases-analysis/agent.js +2 -1
- package/dist/phases/test-cases-analysis/index.js +0 -1
- package/dist/phases/user-stories-analysis/agent.js +2 -1
- package/dist/phases/user-stories-analysis/index.js +0 -1
- package/dist/services/coaching/coaching-agent.js +29 -4
- package/dist/services/feedbacks.d.ts +1 -1
- package/dist/services/repo-config.d.ts +17 -0
- package/dist/services/repo-config.js +50 -0
- package/dist/skills/phase/issue-analysis/SKILL.md +48 -92
- package/dist/skills/phase/issue-analysis-verification/SKILL.md +46 -31
- package/dist/tools/bootstrap.d.ts +45 -0
- package/dist/tools/bootstrap.js +50 -0
- package/dist/types/external-sources.d.ts +22 -0
- package/dist/types/external-sources.js +23 -0
- package/dist/types/index.d.ts +5 -10
- package/dist/types/issues.d.ts +2 -0
- package/dist/types/llm-responses.d.ts +1 -14
- package/dist/utils/formatters.js +1 -7
- package/dist/utils/git-branch-manager-async.js +9 -5
- package/dist/utils/git-branch-manager.js +17 -7
- package/dist/workspace/workspace-manager.d.ts +10 -0
- package/dist/workspace/workspace-manager.js +22 -1
- package/package.json +6 -2
- package/vitest.config.ts +4 -0
- package/.env.local +0 -12
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI command: `edsger sync-sentry-issues <productId>`
|
|
3
|
+
*
|
|
4
|
+
* Reads Sentry credentials from process.env (populated by `edsger config
|
|
5
|
+
* set` via ~/.edsger/env.json or by real environment variables). For an
|
|
6
|
+
* MVP we intentionally don't put per-product Sentry config in the
|
|
7
|
+
* database — the auth token is user-scoped, and org/project rarely
|
|
8
|
+
* change. If the friction shows up, follow up by adding columns on the
|
|
9
|
+
* products table and a settings UI.
|
|
10
|
+
*/
|
|
11
|
+
import { syncSentryIssues } from '../../phases/sync-sentry-issues/index.js';
|
|
12
|
+
import { logError, logInfo, logSuccess } from '../../utils/logger.js';
|
|
13
|
+
/**
|
|
14
|
+
* Pull Sentry creds from env. Returns a list of missing variable names so
|
|
15
|
+
* the CLI can give one clear "set these" message instead of dribbling
|
|
16
|
+
* errors.
|
|
17
|
+
*/
|
|
18
|
+
function readSentryEnv() {
|
|
19
|
+
const authToken = process.env.SENTRY_AUTH_TOKEN ?? '';
|
|
20
|
+
const org = process.env.SENTRY_ORG ?? '';
|
|
21
|
+
const project = process.env.SENTRY_PROJECT ?? '';
|
|
22
|
+
// SENTRY_URL is the official sentry-cli convention. SENTRY_BASE_URL is
|
|
23
|
+
// the older name we shipped first; accept both with the new one winning
|
|
24
|
+
// so users with the old desktop install + new CLI keep working.
|
|
25
|
+
const url = process.env.SENTRY_URL || process.env.SENTRY_BASE_URL || undefined;
|
|
26
|
+
const missing = [];
|
|
27
|
+
if (!authToken) {
|
|
28
|
+
missing.push('SENTRY_AUTH_TOKEN');
|
|
29
|
+
}
|
|
30
|
+
if (!org) {
|
|
31
|
+
missing.push('SENTRY_ORG');
|
|
32
|
+
}
|
|
33
|
+
if (!project) {
|
|
34
|
+
missing.push('SENTRY_PROJECT');
|
|
35
|
+
}
|
|
36
|
+
if (missing.length > 0) {
|
|
37
|
+
return { ok: false, missing };
|
|
38
|
+
}
|
|
39
|
+
return { ok: true, env: { authToken, org, project, baseUrl: url } };
|
|
40
|
+
}
|
|
41
|
+
export async function runSyncSentryIssues(productId, options = {}) {
|
|
42
|
+
const { verbose } = options;
|
|
43
|
+
logInfo(`Starting Sentry issue sync for product ${productId}`);
|
|
44
|
+
const env = readSentryEnv();
|
|
45
|
+
if (!env.ok) {
|
|
46
|
+
logError(`Sentry not configured. Missing: ${env.missing.join(', ')}. ` +
|
|
47
|
+
`Configure in the desktop app (Product Settings → Credentials) or ` +
|
|
48
|
+
`set them with \`edsger config set <KEY>=<VALUE>\`. ` +
|
|
49
|
+
`Optional: SENTRY_URL for self-hosted Sentry.`);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
const result = await syncSentryIssues({
|
|
53
|
+
productId,
|
|
54
|
+
authToken: env.env.authToken,
|
|
55
|
+
org: env.env.org,
|
|
56
|
+
project: env.env.project,
|
|
57
|
+
baseUrl: env.env.baseUrl,
|
|
58
|
+
verbose,
|
|
59
|
+
});
|
|
60
|
+
if (result.status === 'success') {
|
|
61
|
+
logSuccess(`Sentry sync completed: ${result.message}`);
|
|
62
|
+
if (result.source) {
|
|
63
|
+
logInfo(`Source: ${result.source}`);
|
|
64
|
+
}
|
|
65
|
+
if (result.fetchedCount !== undefined) {
|
|
66
|
+
logInfo(`Fetched ${result.fetchedCount} · created ${result.createdCount ?? 0} · updated ${result.updatedCount ?? 0} · refreshed ${result.refreshedCount ?? 0} · deleted ${result.deletedCount ?? 0}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
logError(`Sentry sync failed: ${result.message}`);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -130,9 +130,7 @@ async function validateAndLogChecklists(options, name, checklistContext, issueId
|
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
// Higher-order function for phase execution
|
|
133
|
-
export const createPhaseRunner = (phaseConfig) =>
|
|
134
|
-
// eslint-disable-next-line complexity
|
|
135
|
-
async (options, config) => {
|
|
133
|
+
export const createPhaseRunner = (phaseConfig) => async (options, config) => {
|
|
136
134
|
const { issueId, verbose } = options;
|
|
137
135
|
const { name, execute } = phaseConfig;
|
|
138
136
|
// Track phase duration for logging
|
|
@@ -143,7 +141,11 @@ async (options, config) => {
|
|
|
143
141
|
if (verbose) {
|
|
144
142
|
logDebug(`Checking approval before executing ${name} phase...`, verbose);
|
|
145
143
|
}
|
|
146
|
-
|
|
144
|
+
// The approval system keys configs on snake_case phase names
|
|
145
|
+
// (matching the workflow JSONB vocabulary), so convert from the
|
|
146
|
+
// kebab-case orchestrator name before checking.
|
|
147
|
+
const phaseSnakeCase = name.replace(/-/g, '_');
|
|
148
|
+
const approvalCheck = await checkApprovalBeforePhaseExecution(issueId, phaseSnakeCase, verbose);
|
|
147
149
|
if (!approvalCheck.canProceed) {
|
|
148
150
|
// Current status requires approval but hasn't been approved yet
|
|
149
151
|
// Block phase execution and return blocked result
|
|
@@ -36,7 +36,6 @@ const logAndMarkPhaseCompleted = async (result, verbose) => {
|
|
|
36
36
|
* Orchestrate phase execution based on execution mode
|
|
37
37
|
* Routes to appropriate phase sequence based on mode (only_*, from_*, full_pipeline)
|
|
38
38
|
*/
|
|
39
|
-
// eslint-disable-next-line complexity
|
|
40
39
|
export const runPipelineByMode = async (options, config, executionMode) => {
|
|
41
40
|
const { issueId, verbose } = options;
|
|
42
41
|
if (verbose) {
|
|
@@ -1,56 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Issue status configuration
|
|
3
|
-
* Defines the progression order and mappings for issue statuses
|
|
4
|
-
*/
|
|
5
|
-
import type { IssueStatus } from '../types/index.js';
|
|
6
|
-
/**
|
|
7
|
-
* Status progression order - higher index means more advanced status
|
|
8
|
-
* This defines the allowed forward progression through the issue workflow
|
|
9
|
-
*
|
|
10
|
-
* Business Logic Rules:
|
|
11
|
-
* - Issues can only move forward or stay at the same status level
|
|
12
|
-
* - No regression to earlier stages is allowed (e.g., cannot go back to 'backlog' from 'code_implementation')
|
|
13
|
-
* - Status updates preserve development momentum and prevent accidental rollbacks
|
|
2
|
+
* Issue lifecycle status configuration.
|
|
14
3
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* - Same status → same status: Allowed for retries, reprocessing, or status confirmation
|
|
18
|
-
* - code_refine_verification → code_refine: Handled by specific retry logic, not this progression
|
|
4
|
+
* Under the 2D model, issues.status carries 7 lifecycle values. Phase
|
|
5
|
+
* progress lives in the workflow JSONB column instead.
|
|
19
6
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
7
|
+
* The map kebab-case→workflow used by the worker is in
|
|
8
|
+
* ../api/issues/status-updater.ts (PHASE_NAME_TO_WORKFLOW)
|
|
9
|
+
* — this file only owns the lifecycle status enum + ordering used by
|
|
10
|
+
* isForwardProgression().
|
|
23
11
|
*/
|
|
24
|
-
|
|
12
|
+
import type { IssueStatus } from '../types/index.js';
|
|
25
13
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* This mapping ensures that each pipeline phase updates the issue to the appropriate
|
|
30
|
-
* status. Phase names use kebab-case (e.g., 'issue-analysis') while status values
|
|
31
|
-
* use snake_case (e.g., 'issue_analysis') to match database schema.
|
|
14
|
+
* Lifecycle progression order. Used by isForwardProgression() to reject
|
|
15
|
+
* regressions — e.g. you can move backlog → ready_for_ai but not the
|
|
16
|
+
* other way around.
|
|
32
17
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* and skip the status update to prevent unintended regression to 'backlog'.
|
|
18
|
+
* Special-cases (handled in isForwardProgression):
|
|
19
|
+
* - any status → archived: always allowed
|
|
20
|
+
* - archived → backlog: always allowed (unarchive)
|
|
37
21
|
*/
|
|
38
|
-
export declare const
|
|
22
|
+
export declare const STATUS_PROGRESSION_ORDER: readonly IssueStatus[];
|
|
39
23
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* Excluded statuses (system-managed):
|
|
44
|
-
* - *_verification statuses: Automatically entered after completing the corresponding phase
|
|
45
|
-
* - testing_in_progress: Automatically set when functional testing begins
|
|
46
|
-
* - testing_passed: Automatically set when all tests pass
|
|
47
|
-
* - testing_failed: Automatically set when tests fail
|
|
48
|
-
*
|
|
49
|
-
* These excluded statuses should not be shown in UI dropdowns for manual status changes
|
|
50
|
-
* because they represent intermediate states that are managed by the workflow system.
|
|
24
|
+
* Statuses a human can pick from a dropdown. AI-managed states
|
|
25
|
+
* (assigned_to_ai, in_progress) are written by the worker and not
|
|
26
|
+
* exposed for manual selection.
|
|
51
27
|
*/
|
|
52
28
|
export declare const HUMAN_SELECTABLE_STATUSES: readonly IssueStatus[];
|
|
53
|
-
/**
|
|
54
|
-
* Check if a status can be manually selected by a human user
|
|
55
|
-
*/
|
|
56
29
|
export declare function isHumanSelectableStatus(status: IssueStatus): boolean;
|
|
@@ -1,130 +1,44 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Issue status configuration
|
|
3
|
-
* Defines the progression order and mappings for issue statuses
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Status progression order - higher index means more advanced status
|
|
7
|
-
* This defines the allowed forward progression through the issue workflow
|
|
2
|
+
* Issue lifecycle status configuration.
|
|
8
3
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* - No regression to earlier stages is allowed (e.g., cannot go back to 'backlog' from 'code_implementation')
|
|
12
|
-
* - Status updates preserve development momentum and prevent accidental rollbacks
|
|
4
|
+
* Under the 2D model, issues.status carries 7 lifecycle values. Phase
|
|
5
|
+
* progress lives in the workflow JSONB column instead.
|
|
13
6
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
7
|
+
* The map kebab-case→workflow used by the worker is in
|
|
8
|
+
* ../api/issues/status-updater.ts (PHASE_NAME_TO_WORKFLOW)
|
|
9
|
+
* — this file only owns the lifecycle status enum + ordering used by
|
|
10
|
+
* isForwardProgression().
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Lifecycle progression order. Used by isForwardProgression() to reject
|
|
14
|
+
* regressions — e.g. you can move backlog → ready_for_ai but not the
|
|
15
|
+
* other way around.
|
|
18
16
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
17
|
+
* Special-cases (handled in isForwardProgression):
|
|
18
|
+
* - any status → archived: always allowed
|
|
19
|
+
* - archived → backlog: always allowed (unarchive)
|
|
22
20
|
*/
|
|
23
21
|
export const STATUS_PROGRESSION_ORDER = [
|
|
24
22
|
'backlog',
|
|
25
23
|
'ready_for_ai',
|
|
26
24
|
'assigned_to_ai',
|
|
27
|
-
'
|
|
28
|
-
'issue_analysis_verification',
|
|
29
|
-
'user_stories_analysis',
|
|
30
|
-
'user_stories_analysis_verification',
|
|
31
|
-
'test_cases_analysis',
|
|
32
|
-
'test_cases_analysis_verification',
|
|
33
|
-
'technical_design',
|
|
34
|
-
'technical_design_verification',
|
|
35
|
-
'branch_planning',
|
|
36
|
-
'branch_planning_verification',
|
|
37
|
-
'code_implementation',
|
|
38
|
-
'code_implementation_verification',
|
|
39
|
-
'pr_splitting',
|
|
40
|
-
'pr_splitting_verification',
|
|
41
|
-
'pr_execution',
|
|
42
|
-
'code_refine',
|
|
43
|
-
'code_refine_verification',
|
|
44
|
-
'bug_fixing',
|
|
45
|
-
'code_review',
|
|
46
|
-
'functional_testing',
|
|
47
|
-
'testing_in_progress',
|
|
48
|
-
'testing_passed',
|
|
49
|
-
'testing_failed',
|
|
50
|
-
'ready_for_review',
|
|
25
|
+
'in_progress',
|
|
51
26
|
'shipped',
|
|
27
|
+
'failed',
|
|
52
28
|
'archived',
|
|
53
29
|
];
|
|
54
30
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* This mapping ensures that each pipeline phase updates the issue to the appropriate
|
|
59
|
-
* status. Phase names use kebab-case (e.g., 'issue-analysis') while status values
|
|
60
|
-
* use snake_case (e.g., 'issue_analysis') to match database schema.
|
|
61
|
-
*
|
|
62
|
-
* All status values must match the database constraint in migration 20251019000000_update_feature_status_constraint.sql
|
|
63
|
-
*
|
|
64
|
-
* If a phase is not found in this mapping, updateIssueStatusForPhase will return null
|
|
65
|
-
* and skip the status update to prevent unintended regression to 'backlog'.
|
|
66
|
-
*/
|
|
67
|
-
export const PHASE_STATUS_MAP = {
|
|
68
|
-
'issue-analysis': 'issue_analysis',
|
|
69
|
-
'issue-analysis-verification': 'issue_analysis_verification',
|
|
70
|
-
'user-stories-analysis': 'user_stories_analysis',
|
|
71
|
-
'user-stories-analysis-verification': 'user_stories_analysis_verification',
|
|
72
|
-
'test-cases-analysis': 'test_cases_analysis',
|
|
73
|
-
'test-cases-analysis-verification': 'test_cases_analysis_verification',
|
|
74
|
-
'technical-design': 'technical_design',
|
|
75
|
-
'technical-design-verification': 'technical_design_verification',
|
|
76
|
-
'branch-planning': 'branch_planning',
|
|
77
|
-
'branch-planning-verification': 'branch_planning_verification',
|
|
78
|
-
'code-implementation': 'code_implementation',
|
|
79
|
-
'code-implementation-verification': 'code_implementation_verification',
|
|
80
|
-
'pr-splitting': 'pr_splitting',
|
|
81
|
-
'pr-splitting-verification': 'pr_splitting_verification',
|
|
82
|
-
'pr-execution': 'pr_execution',
|
|
83
|
-
'code-refine': 'code_refine',
|
|
84
|
-
'code-refine-verification': 'code_refine_verification',
|
|
85
|
-
'bug-fixing': 'bug_fixing',
|
|
86
|
-
'code-review': 'code_review',
|
|
87
|
-
'functional-testing': 'functional_testing',
|
|
88
|
-
'testing-in-progress': 'testing_in_progress',
|
|
89
|
-
'testing-passed': 'testing_passed',
|
|
90
|
-
'testing-failed': 'testing_failed',
|
|
91
|
-
'ready-for-review': 'ready_for_review',
|
|
92
|
-
};
|
|
93
|
-
/**
|
|
94
|
-
* Human-selectable statuses
|
|
95
|
-
* These are the statuses that a human user can manually set.
|
|
96
|
-
*
|
|
97
|
-
* Excluded statuses (system-managed):
|
|
98
|
-
* - *_verification statuses: Automatically entered after completing the corresponding phase
|
|
99
|
-
* - testing_in_progress: Automatically set when functional testing begins
|
|
100
|
-
* - testing_passed: Automatically set when all tests pass
|
|
101
|
-
* - testing_failed: Automatically set when tests fail
|
|
102
|
-
*
|
|
103
|
-
* These excluded statuses should not be shown in UI dropdowns for manual status changes
|
|
104
|
-
* because they represent intermediate states that are managed by the workflow system.
|
|
31
|
+
* Statuses a human can pick from a dropdown. AI-managed states
|
|
32
|
+
* (assigned_to_ai, in_progress) are written by the worker and not
|
|
33
|
+
* exposed for manual selection.
|
|
105
34
|
*/
|
|
106
35
|
export const HUMAN_SELECTABLE_STATUSES = [
|
|
107
36
|
'backlog',
|
|
108
37
|
'ready_for_ai',
|
|
109
|
-
'issue_analysis',
|
|
110
|
-
'user_stories_analysis',
|
|
111
|
-
'test_cases_analysis',
|
|
112
|
-
'technical_design',
|
|
113
|
-
'branch_planning',
|
|
114
|
-
'code_implementation',
|
|
115
|
-
'pr_splitting',
|
|
116
|
-
'pr_execution',
|
|
117
|
-
'code_refine',
|
|
118
|
-
'bug_fixing',
|
|
119
|
-
'code_review',
|
|
120
|
-
'functional_testing',
|
|
121
|
-
'ready_for_review',
|
|
122
38
|
'shipped',
|
|
123
39
|
'archived',
|
|
40
|
+
'failed',
|
|
124
41
|
];
|
|
125
|
-
/**
|
|
126
|
-
* Check if a status can be manually selected by a human user
|
|
127
|
-
*/
|
|
128
42
|
export function isHumanSelectableStatus(status) {
|
|
129
43
|
return HUMAN_SELECTABLE_STATUSES.includes(status);
|
|
130
44
|
}
|
package/dist/index.js
CHANGED
|
@@ -13,6 +13,8 @@ import { runBuild } from './commands/build/index.js';
|
|
|
13
13
|
import { runChecklists } from './commands/checklists/index.js';
|
|
14
14
|
import { runCodeReview } from './commands/code-review/index.js';
|
|
15
15
|
import { runConfigGet, runConfigList, runConfigSet, runConfigUnset, } from './commands/config/index.js';
|
|
16
|
+
import { runFinancingDeck } from './commands/financing-deck/index.js';
|
|
17
|
+
import { runFindArchitecture } from './commands/find-architecture/index.js';
|
|
16
18
|
import { runFindBugs } from './commands/find-bugs/index.js';
|
|
17
19
|
import { runFindFeatures } from './commands/find-features/index.js';
|
|
18
20
|
import { parseCategoriesOption, runFindSmells, } from './commands/find-smells/index.js';
|
|
@@ -25,8 +27,11 @@ import { runRefactor } from './commands/refactor/refactor.js';
|
|
|
25
27
|
import { runReleaseSyncCommand } from './commands/release-sync/index.js';
|
|
26
28
|
import { runRunSheetCommand } from './commands/run-sheet/index.js';
|
|
27
29
|
import { runSmokeTestCommand } from './commands/smoke-test/index.js';
|
|
30
|
+
import { runSyncGithubIssues } from './commands/sync-github-issues/index.js';
|
|
31
|
+
import { runSyncSentryIssues } from './commands/sync-sentry-issues/index.js';
|
|
28
32
|
import { runTaskWorker } from './commands/task-worker/index.js';
|
|
29
33
|
import { runWorkflow } from './commands/workflow/index.js';
|
|
34
|
+
import { DEFAULT_MAX_FILES as FIND_ARCHITECTURE_DEFAULT_MAX_FILES } from './phases/find-architecture/index.js';
|
|
30
35
|
import { DEFAULT_MAX_FILES as FIND_SMELLS_DEFAULT_MAX_FILES } from './phases/find-smells/index.js';
|
|
31
36
|
import { SMELL_CATEGORIES, } from './phases/find-smells/types.js';
|
|
32
37
|
import { logError, logInfo } from './utils/logger.js';
|
|
@@ -147,6 +152,27 @@ program
|
|
|
147
152
|
}
|
|
148
153
|
});
|
|
149
154
|
// ============================================================
|
|
155
|
+
// Subcommand: edsger financing-deck <productId>
|
|
156
|
+
// ============================================================
|
|
157
|
+
program
|
|
158
|
+
.command('financing-deck <productId>')
|
|
159
|
+
.description('Draft an investor pitch deck for a product (AI-generated)')
|
|
160
|
+
.requiredOption('--target-stage <stage>', 'Target stage: pre_seed | seed | series_a | series_b | series_c | growth')
|
|
161
|
+
.option('-v, --verbose', 'Verbose output')
|
|
162
|
+
.action(async (productId, opts) => {
|
|
163
|
+
try {
|
|
164
|
+
await runFinancingDeck({
|
|
165
|
+
financingDeck: productId,
|
|
166
|
+
financingTargetStage: opts.targetStage,
|
|
167
|
+
verbose: opts.verbose,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
172
|
+
process.exit(1);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
// ============================================================
|
|
150
176
|
// Subcommand: edsger intel <productId>
|
|
151
177
|
// ============================================================
|
|
152
178
|
program
|
|
@@ -240,18 +266,26 @@ program
|
|
|
240
266
|
}
|
|
241
267
|
});
|
|
242
268
|
// ============================================================
|
|
243
|
-
// Subcommand: edsger checklists <
|
|
269
|
+
// Subcommand: edsger checklists [productId] [--team-id <id>]
|
|
244
270
|
// ============================================================
|
|
245
271
|
program
|
|
246
|
-
.command('checklists
|
|
247
|
-
.description('Analyse a local directory and sync product checklists (create/update/delete) using AI')
|
|
272
|
+
.command('checklists [productId]')
|
|
273
|
+
.description('Analyse a local directory and sync product OR team checklists (create/update/delete) using AI. Pass a product ID positionally for product scope, or --team-id for team scope.')
|
|
248
274
|
.option('-v, --verbose', 'Verbose output')
|
|
249
275
|
.option('--dir <path>', 'Directory to analyse (defaults to current working directory)')
|
|
250
276
|
.option('--prompt <text>', 'Additional instructions for the AI agent')
|
|
277
|
+
.option('--team-id <id>', 'Sync TEAM-level checklists for this team instead of a product. The directory is treated as team standards / reference material.')
|
|
251
278
|
.action(async (productId, opts) => {
|
|
252
279
|
try {
|
|
280
|
+
if (!productId && !opts.teamId) {
|
|
281
|
+
throw new Error('Provide a product ID positionally or pass --team-id <id> for team scope.');
|
|
282
|
+
}
|
|
283
|
+
if (productId && opts.teamId) {
|
|
284
|
+
throw new Error('Pass either a product ID or --team-id, not both.');
|
|
285
|
+
}
|
|
253
286
|
await runChecklists({
|
|
254
287
|
checklistsProductId: productId,
|
|
288
|
+
checklistsTeamId: opts.teamId,
|
|
255
289
|
checklistsDir: opts.dir,
|
|
256
290
|
checklistsPrompt: opts.prompt,
|
|
257
291
|
verbose: opts.verbose,
|
|
@@ -384,6 +418,41 @@ program
|
|
|
384
418
|
}
|
|
385
419
|
});
|
|
386
420
|
// ============================================================
|
|
421
|
+
// Subcommand: edsger sync-github-issues <productId>
|
|
422
|
+
// ============================================================
|
|
423
|
+
program
|
|
424
|
+
.command('sync-github-issues <productId>')
|
|
425
|
+
.description("Mirror the product's connected GitHub repo issues into the local issues list (handles new, updated, closed, and deleted)")
|
|
426
|
+
.option('-v, --verbose', 'Verbose output')
|
|
427
|
+
.action(async (productId, opts) => {
|
|
428
|
+
try {
|
|
429
|
+
await runSyncGithubIssues(productId, opts);
|
|
430
|
+
}
|
|
431
|
+
catch (error) {
|
|
432
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
433
|
+
process.exit(1);
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
// ============================================================
|
|
437
|
+
// Subcommand: edsger sync-sentry-issues <productId>
|
|
438
|
+
//
|
|
439
|
+
// Requires SENTRY_AUTH_TOKEN, SENTRY_ORG, SENTRY_PROJECT in env (set via
|
|
440
|
+
// `edsger config set`). Optional SENTRY_BASE_URL for self-hosted Sentry.
|
|
441
|
+
// ============================================================
|
|
442
|
+
program
|
|
443
|
+
.command('sync-sentry-issues <productId>')
|
|
444
|
+
.description('Mirror Sentry project issues into the local issues list (requires SENTRY_AUTH_TOKEN, SENTRY_ORG, SENTRY_PROJECT env)')
|
|
445
|
+
.option('-v, --verbose', 'Verbose output')
|
|
446
|
+
.action(async (productId, opts) => {
|
|
447
|
+
try {
|
|
448
|
+
await runSyncSentryIssues(productId, opts);
|
|
449
|
+
}
|
|
450
|
+
catch (error) {
|
|
451
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
452
|
+
process.exit(1);
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
// ============================================================
|
|
387
456
|
// Subcommand: edsger find-features <productId>
|
|
388
457
|
// ============================================================
|
|
389
458
|
program
|
|
@@ -443,6 +512,31 @@ program
|
|
|
443
512
|
}
|
|
444
513
|
});
|
|
445
514
|
// ============================================================
|
|
515
|
+
// Subcommand: edsger find-architecture <productId>
|
|
516
|
+
// ============================================================
|
|
517
|
+
program
|
|
518
|
+
.command('find-architecture <productId>')
|
|
519
|
+
.description("AI-audit a product's repository for architectural concerns (layering, coupling, cycles, missing/duplicated abstractions, responsibility creep) and file each new finding as an issue")
|
|
520
|
+
.option('--full', 'Force a full scan even if previous-scan state exists')
|
|
521
|
+
.option('--branch <name>', 'Branch to scan (defaults to repo default branch)')
|
|
522
|
+
.option('--max-files <n>', `Upper bound on files the auditor may Read (default ${FIND_ARCHITECTURE_DEFAULT_MAX_FILES})`, (value) => {
|
|
523
|
+
const n = parseInt(value, 10);
|
|
524
|
+
if (Number.isNaN(n) || n <= 0) {
|
|
525
|
+
throw new Error('--max-files must be a positive integer');
|
|
526
|
+
}
|
|
527
|
+
return n;
|
|
528
|
+
})
|
|
529
|
+
.option('-v, --verbose', 'Verbose output')
|
|
530
|
+
.action(async (productId, opts) => {
|
|
531
|
+
try {
|
|
532
|
+
await runFindArchitecture(productId, opts);
|
|
533
|
+
}
|
|
534
|
+
catch (error) {
|
|
535
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
536
|
+
process.exit(1);
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
// ============================================================
|
|
446
540
|
// Subcommand: edsger pr-resolve <productId>
|
|
447
541
|
// ============================================================
|
|
448
542
|
program
|
|
@@ -94,7 +94,8 @@ export async function executeAppStoreQuery(currentPrompt, systemPrompt, config,
|
|
|
94
94
|
logDebug(`${content.text}`, verbose);
|
|
95
95
|
}
|
|
96
96
|
else if (content.type === 'tool_use') {
|
|
97
|
-
const
|
|
97
|
+
const input = (content.input ?? {});
|
|
98
|
+
const desc = input.description ?? input.command ?? 'Running...';
|
|
98
99
|
logInfo(`[Turn ${turnCount}] ${content.name}: ${typeof desc === 'string' ? desc.slice(0, 120) : 'Running...'}`);
|
|
99
100
|
}
|
|
100
101
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getAppStorePrimaryLocale, saveAppStoreListings, upsertAppStoreConfig, } from '../../api/app-store.js';
|
|
2
2
|
import { getGitHubConfigByProduct } from '../../api/github.js';
|
|
3
3
|
import { logError, logInfo, logSuccess } from '../../utils/logger.js';
|
|
4
|
-
import { cloneIssueRepo, ensureWorkspaceDir, } from '../../workspace/workspace-manager.js';
|
|
4
|
+
import { cleanupIssueRepo, cloneIssueRepo, ensureWorkspaceDir, } from '../../workspace/workspace-manager.js';
|
|
5
5
|
import { executeAppStoreQuery } from './agent.js';
|
|
6
6
|
import { prepareAppStoreContext } from './context.js';
|
|
7
7
|
import { createAppStoreSystemPrompt } from './prompts.js';
|
|
@@ -13,13 +13,14 @@ function truncateKeywords(keywords) {
|
|
|
13
13
|
}
|
|
14
14
|
return keywords.slice(0, 100).replace(/,[^,]*$/, '');
|
|
15
15
|
}
|
|
16
|
-
// eslint-disable-next-line complexity
|
|
17
16
|
export const generateAppStoreAssets = async (options, config) => {
|
|
18
17
|
const { productId, targetStore, screenshotsOnly, listingsOnly, verbose } = options;
|
|
19
18
|
if (verbose) {
|
|
20
19
|
logInfo(`Starting app store generation for product: ${productId}`);
|
|
21
20
|
logInfo(` Target store: ${targetStore}`);
|
|
22
21
|
}
|
|
22
|
+
let repoCwd;
|
|
23
|
+
let generationSucceeded = false;
|
|
23
24
|
try {
|
|
24
25
|
// Resolve locale: use explicit param, or fetch from Apple App Store Connect
|
|
25
26
|
let { locale } = options;
|
|
@@ -48,7 +49,8 @@ export const generateAppStoreAssets = async (options, config) => {
|
|
|
48
49
|
'Please configure a GitHub repo in the product settings before generating assets.');
|
|
49
50
|
}
|
|
50
51
|
const workspaceRoot = ensureWorkspaceDir();
|
|
51
|
-
const
|
|
52
|
+
const cloned = cloneIssueRepo(workspaceRoot, `app-store-${productId}`, githubConfig.owner, githubConfig.repo, githubConfig.token);
|
|
53
|
+
repoCwd = cloned.repoPath;
|
|
52
54
|
logInfo(`Repository cloned to: ${repoCwd}`);
|
|
53
55
|
// Prepare context and prompt
|
|
54
56
|
const { context, prompt: analysisPrompt } = await prepareAppStoreContext(productId, targetStore, locale, verbose, true);
|
|
@@ -126,6 +128,7 @@ export const generateAppStoreAssets = async (options, config) => {
|
|
|
126
128
|
}
|
|
127
129
|
}
|
|
128
130
|
const totalScreenshots = Object.values(savedScreenshots).flat().length;
|
|
131
|
+
generationSucceeded = true;
|
|
129
132
|
return {
|
|
130
133
|
productId,
|
|
131
134
|
status: 'success',
|
|
@@ -146,4 +149,9 @@ export const generateAppStoreAssets = async (options, config) => {
|
|
|
146
149
|
configIds: [],
|
|
147
150
|
};
|
|
148
151
|
}
|
|
152
|
+
finally {
|
|
153
|
+
if (generationSucceeded) {
|
|
154
|
+
cleanupIssueRepo(repoCwd);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
149
157
|
};
|
|
@@ -12,6 +12,7 @@ import { getIssue } from '../../api/issues/get-issue.js';
|
|
|
12
12
|
import { DEFAULT_MODEL } from '../../constants.js';
|
|
13
13
|
import { logIssuePhaseEvent } from '../../services/audit-logs.js';
|
|
14
14
|
import { createBranches, getCurrentBranch, updateBranch, } from '../../services/branches.js';
|
|
15
|
+
import { getDefaultBranchForIssue } from '../../services/repo-config.js';
|
|
15
16
|
import { prepareCustomBranchGitEnvironmentAsync, resetUncommittedChanges, } from '../../utils/git-branch-manager.js';
|
|
16
17
|
import { gitPush } from '../../utils/git-push.js';
|
|
17
18
|
import { logDebug, logError, logInfo } from '../../utils/logger.js';
|
|
@@ -128,7 +129,7 @@ function parseIterationResult(responseText) {
|
|
|
128
129
|
* Handle a successful iteration: push, create PR, and log
|
|
129
130
|
*/
|
|
130
131
|
async function handleSuccessfulIteration(opts) {
|
|
131
|
-
const { issueId, devBranchName, currentBranch, iterationResult, totalIterations, iterationDuration, startTime, endTime, existingPrUrl, verbose, } = opts;
|
|
132
|
+
const { issueId, devBranchName, currentBranch, iterationResult, totalIterations, iterationDuration, startTime, endTime, existingPrUrl, defaultBranch, verbose, } = opts;
|
|
132
133
|
// Get GitHub config for push authentication and PR creation
|
|
133
134
|
const githubConfig = await getGitHubConfig(issueId, verbose);
|
|
134
135
|
// Push to remote with authentication
|
|
@@ -144,7 +145,7 @@ async function handleSuccessfulIteration(opts) {
|
|
|
144
145
|
let prUrl = existingPrUrl;
|
|
145
146
|
let prNumber;
|
|
146
147
|
if (!prUrl) {
|
|
147
|
-
const prInfo = await createAutonomousPR(githubConfig, devBranchName, currentBranch, verbose);
|
|
148
|
+
const prInfo = await createAutonomousPR(githubConfig, devBranchName, currentBranch, defaultBranch, verbose);
|
|
148
149
|
({ prUrl, prNumber } = prInfo);
|
|
149
150
|
}
|
|
150
151
|
// Log iteration completion to audit logs
|
|
@@ -173,7 +174,7 @@ async function handleSuccessfulIteration(opts) {
|
|
|
173
174
|
*/
|
|
174
175
|
async function createAutonomousPR(
|
|
175
176
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
176
|
-
githubConfig, devBranchName, currentBranch, verbose) {
|
|
177
|
+
githubConfig, devBranchName, currentBranch, defaultBranch, verbose) {
|
|
177
178
|
if (!githubConfig.configured ||
|
|
178
179
|
!githubConfig.token ||
|
|
179
180
|
!githubConfig.owner ||
|
|
@@ -190,7 +191,7 @@ githubConfig, devBranchName, currentBranch, verbose) {
|
|
|
190
191
|
verbose,
|
|
191
192
|
};
|
|
192
193
|
logInfo(`📝 Creating pull request for autonomous work...`);
|
|
193
|
-
const prResult = await createBranchPullRequest(prConfig, devBranchName, currentBranch.name, currentBranch.description || 'Autonomous development implementation',
|
|
194
|
+
const prResult = await createBranchPullRequest(prConfig, devBranchName, currentBranch.name, currentBranch.description || 'Autonomous development implementation', defaultBranch);
|
|
194
195
|
if (prResult.success) {
|
|
195
196
|
logInfo(`✅ Pull request created: ${prResult.pullRequestUrl}`);
|
|
196
197
|
return {
|
|
@@ -299,10 +300,11 @@ export async function runAutonomousDevelopment(options, config, _checklistContex
|
|
|
299
300
|
}
|
|
300
301
|
}
|
|
301
302
|
}
|
|
302
|
-
// 4. Prepare git environment (checkout branch + rebase with
|
|
303
|
+
// 4. Prepare git environment (checkout branch + rebase with default branch)
|
|
304
|
+
const defaultBranch = await getDefaultBranchForIssue(issueId, verbose);
|
|
303
305
|
const { cleanup: cleanupGit } = await prepareCustomBranchGitEnvironmentAsync({
|
|
304
306
|
issueBranch: devBranchName,
|
|
305
|
-
baseBranch:
|
|
307
|
+
baseBranch: defaultBranch,
|
|
306
308
|
verbose,
|
|
307
309
|
resolveConflicts: true,
|
|
308
310
|
conflictResolverConfig: {
|
|
@@ -334,6 +336,7 @@ export async function runAutonomousDevelopment(options, config, _checklistContex
|
|
|
334
336
|
startTime,
|
|
335
337
|
endTime,
|
|
336
338
|
existingPrUrl: prUrl,
|
|
339
|
+
defaultBranch,
|
|
337
340
|
verbose,
|
|
338
341
|
});
|
|
339
342
|
prUrl = prInfo.prUrl || prUrl;
|
|
@@ -116,7 +116,6 @@ async function persistBranches(sortedBranches, issueId, verbose) {
|
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
-
// eslint-disable-next-line complexity
|
|
120
119
|
export const planIssueBranches = async (options, config) => {
|
|
121
120
|
const { issueId, verbose, replaceExisting } = options;
|
|
122
121
|
if (verbose) {
|
|
@@ -169,7 +168,7 @@ export const planIssueBranches = async (options, config) => {
|
|
|
169
168
|
// Build the user prompt based on mode
|
|
170
169
|
const contextInfo = formatContextForPrompt(context.issue, context.product, context.user_stories, context.test_cases);
|
|
171
170
|
const existingBranchesInfo = formatExistingBranchesForPrompt(context.existing_branches);
|
|
172
|
-
const systemPrompt = await createBranchPlanningSystemPrompt(config, issueId);
|
|
171
|
+
const systemPrompt = await createBranchPlanningSystemPrompt(config, issueId, undefined, verbose);
|
|
173
172
|
const userPrompt = await buildUserPrompt({
|
|
174
173
|
isIncrementalUpdate,
|
|
175
174
|
feedbacksContext,
|
|
@@ -2,7 +2,7 @@ import { type EdsgerConfig } from '../../types/index.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Create the system prompt for branch planning
|
|
4
4
|
*/
|
|
5
|
-
export declare function createBranchPlanningSystemPrompt(config: EdsgerConfig, issueId: string, projectDir?: string): Promise<string>;
|
|
5
|
+
export declare function createBranchPlanningSystemPrompt(config: EdsgerConfig, issueId: string, projectDir?: string, verbose?: boolean): Promise<string>;
|
|
6
6
|
/**
|
|
7
7
|
* Create the user prompt with context for branch planning
|
|
8
8
|
*/
|