edsger 0.49.0 → 0.51.0
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 +25 -25
- package/dist/api/chat.d.ts +7 -7
- package/dist/api/chat.js +13 -13
- package/dist/api/cross-product.d.ts +10 -10
- package/dist/api/cross-product.js +30 -30
- package/dist/api/github.d.ts +5 -5
- package/dist/api/github.js +10 -10
- package/dist/api/intelligence.d.ts +3 -3
- package/dist/api/issues/approval-checker.d.ts +20 -0
- package/dist/api/issues/approval-checker.js +152 -0
- package/dist/api/issues/batch-operations.d.ts +17 -0
- package/dist/api/issues/batch-operations.js +100 -0
- package/dist/api/issues/get-issue.d.ts +5 -0
- package/dist/api/issues/get-issue.js +21 -0
- package/dist/api/issues/index.d.ts +8 -0
- package/dist/api/issues/index.js +10 -0
- package/dist/api/issues/issue-utils.d.ts +23 -0
- package/dist/api/issues/issue-utils.js +80 -0
- package/dist/api/issues/status-updater.d.ts +41 -0
- package/dist/api/issues/status-updater.js +122 -0
- package/dist/api/issues/test-cases.d.ts +29 -0
- package/dist/api/issues/test-cases.js +110 -0
- package/dist/api/issues/update-issue.d.ts +20 -0
- package/dist/api/issues/update-issue.js +83 -0
- package/dist/api/issues/user-stories.d.ts +21 -0
- package/dist/api/issues/user-stories.js +88 -0
- package/dist/api/products.d.ts +1 -1
- package/dist/api/tasks.d.ts +1 -1
- package/dist/api/test-reports.d.ts +2 -2
- package/dist/api/test-reports.js +4 -4
- package/dist/auth/login.js +1 -1
- package/dist/commands/agent-workflow/chat-worker.d.ts +7 -7
- package/dist/commands/agent-workflow/chat-worker.js +50 -50
- package/dist/commands/agent-workflow/index.d.ts +2 -2
- package/dist/commands/agent-workflow/index.js +3 -3
- package/dist/commands/agent-workflow/issue-worker.d.ts +14 -0
- package/dist/commands/agent-workflow/issue-worker.js +65 -0
- package/dist/commands/agent-workflow/processor.d.ts +9 -9
- package/dist/commands/agent-workflow/processor.js +90 -90
- package/dist/commands/build/index.js +2 -2
- package/dist/commands/find-bugs/index.d.ts +11 -0
- package/dist/commands/find-bugs/index.js +39 -0
- package/dist/commands/find-features/index.d.ts +14 -0
- package/dist/commands/find-features/index.js +42 -0
- package/dist/commands/init/prompts.js +1 -1
- package/dist/commands/init/templates.d.ts +1 -1
- package/dist/commands/init/templates.js +4 -4
- package/dist/commands/workflow/config/phase-configs.js +17 -17
- package/dist/commands/workflow/core/index.d.ts +1 -1
- package/dist/commands/workflow/core/index.js +2 -2
- package/dist/commands/workflow/core/issue-filter.d.ts +16 -0
- package/dist/commands/workflow/core/issue-filter.js +47 -0
- package/dist/commands/workflow/core/state-manager.d.ts +10 -10
- package/dist/commands/workflow/core/state-manager.js +10 -10
- package/dist/commands/workflow/core/workflow-logger.d.ts +9 -9
- package/dist/commands/workflow/core/workflow-logger.js +21 -21
- package/dist/commands/workflow/executors/phase-executor.d.ts +2 -2
- package/dist/commands/workflow/executors/phase-executor.js +32 -32
- package/dist/commands/workflow/issue-coordinator.d.ts +18 -0
- package/dist/commands/workflow/issue-coordinator.js +161 -0
- package/dist/commands/workflow/phase-orchestrator.d.ts +2 -2
- package/dist/commands/workflow/phase-orchestrator.js +82 -82
- package/dist/commands/workflow/processor.d.ts +7 -7
- package/dist/commands/workflow/processor.js +44 -44
- package/dist/config/issue-status.d.ts +56 -0
- package/dist/config/issue-status.js +130 -0
- package/dist/errors/index.d.ts +6 -6
- package/dist/errors/index.js +11 -11
- package/dist/index.js +61 -1
- package/dist/phases/app-store-generation/context.js +6 -6
- package/dist/phases/app-store-generation/index.js +2 -2
- package/dist/phases/app-store-generation/prompts.js +2 -2
- package/dist/phases/autonomous/index.d.ts +3 -3
- package/dist/phases/autonomous/index.js +37 -37
- package/dist/phases/autonomous/prompts.d.ts +2 -2
- package/dist/phases/autonomous/prompts.js +4 -4
- package/dist/phases/branch-planning/context.d.ts +3 -3
- package/dist/phases/branch-planning/context.js +12 -12
- package/dist/phases/branch-planning/index.d.ts +3 -3
- package/dist/phases/branch-planning/index.js +32 -32
- package/dist/phases/branch-planning/outcome.d.ts +5 -5
- package/dist/phases/branch-planning/outcome.js +12 -12
- package/dist/phases/branch-planning/prompts.d.ts +3 -3
- package/dist/phases/branch-planning/prompts.js +13 -13
- package/dist/phases/bug-fixing/analyzer.d.ts +2 -2
- package/dist/phases/bug-fixing/analyzer.js +13 -13
- package/dist/phases/bug-fixing/context-fetcher.d.ts +3 -3
- package/dist/phases/bug-fixing/context-fetcher.js +18 -18
- package/dist/phases/bug-fixing/mcp-server.js +17 -18
- package/dist/phases/chat-processor/context.d.ts +5 -5
- package/dist/phases/chat-processor/context.js +17 -17
- package/dist/phases/chat-processor/index.d.ts +4 -4
- package/dist/phases/chat-processor/index.js +17 -17
- package/dist/phases/chat-processor/product-context.d.ts +3 -3
- package/dist/phases/chat-processor/product-context.js +16 -16
- package/dist/phases/chat-processor/product-prompts.d.ts +1 -1
- package/dist/phases/chat-processor/product-prompts.js +10 -10
- package/dist/phases/chat-processor/product-tools.d.ts +2 -2
- package/dist/phases/chat-processor/product-tools.js +33 -33
- package/dist/phases/chat-processor/prompts.d.ts +3 -3
- package/dist/phases/chat-processor/prompts.js +22 -22
- package/dist/phases/chat-processor/tools.js +46 -46
- package/dist/phases/code-implementation/branch-pr-creator.d.ts +3 -3
- package/dist/phases/code-implementation/branch-pr-creator.js +5 -5
- package/dist/phases/code-implementation/context.d.ts +3 -3
- package/dist/phases/code-implementation/context.js +18 -18
- package/dist/phases/code-implementation/index.d.ts +4 -4
- package/dist/phases/code-implementation/index.js +88 -88
- package/dist/phases/code-implementation/outcome.d.ts +3 -3
- package/dist/phases/code-implementation/outcome.js +6 -6
- package/dist/phases/code-implementation/prompts.d.ts +1 -1
- package/dist/phases/code-implementation/prompts.js +6 -6
- package/dist/phases/code-implementation-verification/agent.d.ts +3 -3
- package/dist/phases/code-implementation-verification/agent.js +5 -5
- package/dist/phases/code-implementation-verification/index.d.ts +3 -3
- package/dist/phases/code-implementation-verification/index.js +11 -11
- package/dist/phases/code-implementation-verification/prompts.d.ts +3 -3
- package/dist/phases/code-implementation-verification/prompts.js +7 -7
- package/dist/phases/code-refine/context.d.ts +8 -8
- package/dist/phases/code-refine/context.js +29 -29
- package/dist/phases/code-refine/index.d.ts +2 -2
- package/dist/phases/code-refine/index.js +20 -20
- package/dist/phases/code-refine/prompts.d.ts +1 -1
- package/dist/phases/code-refine/prompts.js +3 -3
- package/dist/phases/code-refine/refine-iteration.d.ts +1 -1
- package/dist/phases/code-refine/refine-iteration.js +4 -4
- package/dist/phases/code-refine/retry-handler.js +2 -2
- package/dist/phases/code-refine-verification/github.d.ts +16 -0
- package/dist/phases/code-refine-verification/github.js +118 -32
- package/dist/phases/code-refine-verification/index.js +10 -10
- package/dist/phases/code-refine-verification/types.d.ts +17 -12
- package/dist/phases/code-review/context.d.ts +8 -8
- package/dist/phases/code-review/context.js +25 -25
- package/dist/phases/code-review/diff-utils.d.ts +1 -1
- package/dist/phases/code-review/diff-utils.js +1 -1
- package/dist/phases/code-review/index.d.ts +2 -2
- package/dist/phases/code-review/index.js +26 -26
- package/dist/phases/code-testing/analyzer.d.ts +2 -2
- package/dist/phases/code-testing/analyzer.js +18 -18
- package/dist/phases/code-testing/context-fetcher.d.ts +3 -3
- package/dist/phases/code-testing/context-fetcher.js +16 -16
- package/dist/phases/code-testing/prompts.d.ts +1 -1
- package/dist/phases/code-testing/prompts.js +5 -5
- package/dist/phases/find-bugs/index.d.ts +30 -0
- package/dist/phases/find-bugs/index.js +301 -0
- package/dist/phases/find-bugs/prompts.d.ts +22 -0
- package/dist/phases/find-bugs/prompts.js +101 -0
- package/dist/phases/find-bugs/state.d.ts +44 -0
- package/dist/phases/find-bugs/state.js +121 -0
- package/dist/phases/find-bugs/types.d.ts +21 -0
- package/dist/phases/find-bugs/types.js +16 -0
- package/dist/phases/find-features/index.d.ts +40 -0
- package/dist/phases/find-features/index.js +346 -0
- package/dist/phases/find-features/prompts.d.ts +37 -0
- package/dist/phases/find-features/prompts.js +118 -0
- package/dist/phases/find-features/state.d.ts +29 -0
- package/dist/phases/find-features/state.js +94 -0
- package/dist/phases/find-features/types.d.ts +27 -0
- package/dist/phases/find-features/types.js +16 -0
- package/dist/phases/functional-testing/analyzer.d.ts +2 -2
- package/dist/phases/functional-testing/analyzer.js +40 -40
- package/dist/phases/functional-testing/context-fetcher.d.ts +3 -3
- package/dist/phases/functional-testing/context-fetcher.js +16 -16
- package/dist/phases/functional-testing/http-fallback.d.ts +2 -2
- package/dist/phases/functional-testing/http-fallback.js +9 -9
- package/dist/phases/functional-testing/mcp-server.js +23 -24
- package/dist/phases/functional-testing/prompts.d.ts +1 -1
- package/dist/phases/functional-testing/prompts.js +4 -4
- package/dist/phases/functional-testing/test-report-creator.d.ts +2 -2
- package/dist/phases/functional-testing/test-report-creator.js +10 -10
- package/dist/phases/functional-testing/test-retry-handler.js +3 -3
- package/dist/phases/growth-analysis/context.js +6 -6
- package/dist/phases/growth-analysis/index.js +2 -2
- package/dist/phases/growth-analysis/prompts.js +2 -2
- package/dist/phases/intelligence-analysis/context.js +7 -7
- package/dist/phases/intelligence-analysis/index.js +3 -3
- package/dist/phases/issue-analysis/agent.d.ts +13 -0
- package/dist/phases/issue-analysis/agent.js +112 -0
- package/dist/phases/issue-analysis/context.d.ts +24 -0
- package/dist/phases/issue-analysis/context.js +138 -0
- package/dist/phases/issue-analysis/index.d.ts +8 -0
- package/dist/phases/issue-analysis/index.js +199 -0
- package/dist/phases/issue-analysis/outcome.d.ts +40 -0
- package/dist/phases/issue-analysis/outcome.js +280 -0
- package/dist/phases/issue-analysis/prompts.d.ts +10 -0
- package/dist/phases/issue-analysis/prompts.js +212 -0
- package/dist/phases/issue-analysis-verification/agent.d.ts +33 -0
- package/dist/phases/issue-analysis-verification/agent.js +124 -0
- package/dist/phases/issue-analysis-verification/index.d.ts +25 -0
- package/dist/phases/issue-analysis-verification/index.js +92 -0
- package/dist/phases/issue-analysis-verification/prompts.d.ts +10 -0
- package/dist/phases/issue-analysis-verification/prompts.js +100 -0
- package/dist/phases/output-contracts.js +37 -37
- package/dist/phases/pr-execution/context.d.ts +3 -3
- package/dist/phases/pr-execution/context.js +14 -14
- package/dist/phases/pr-execution/index.d.ts +2 -2
- package/dist/phases/pr-execution/index.js +22 -22
- package/dist/phases/pr-execution/outcome.d.ts +4 -4
- package/dist/phases/pr-execution/outcome.js +6 -6
- package/dist/phases/pr-execution/prompts.d.ts +4 -4
- package/dist/phases/pr-execution/prompts.js +6 -6
- package/dist/phases/pr-resolve/checklist-learner.js +2 -2
- package/dist/phases/pr-review/index.d.ts +1 -1
- package/dist/phases/pr-review/index.js +1 -1
- package/dist/phases/pr-review/prompts.d.ts +1 -1
- package/dist/phases/pr-review/prompts.js +1 -1
- package/dist/phases/pr-shared/context.d.ts +3 -3
- package/dist/phases/pr-shared/context.js +3 -3
- package/dist/phases/pr-splitting/context.d.ts +3 -3
- package/dist/phases/pr-splitting/context.js +16 -16
- package/dist/phases/pr-splitting/index.d.ts +4 -4
- package/dist/phases/pr-splitting/index.js +29 -29
- package/dist/phases/pr-splitting/outcome.d.ts +3 -3
- package/dist/phases/pr-splitting/outcome.js +7 -7
- package/dist/phases/pr-splitting/prompts.d.ts +3 -3
- package/dist/phases/pr-splitting/prompts.js +11 -11
- package/dist/phases/pull-request/creator.d.ts +4 -4
- package/dist/phases/pull-request/creator.js +25 -25
- package/dist/phases/pull-request/handler.d.ts +3 -3
- package/dist/phases/pull-request/handler.js +16 -16
- package/dist/phases/release-sync/index.js +2 -2
- package/dist/phases/run-sheet/agent.js +1 -2
- package/dist/phases/run-sheet/index.js +3 -3
- package/dist/phases/smoke-test/index.js +2 -2
- package/dist/phases/technical-design/context.d.ts +3 -3
- package/dist/phases/technical-design/context.js +11 -11
- package/dist/phases/technical-design/index.d.ts +2 -2
- package/dist/phases/technical-design/index.js +27 -27
- package/dist/phases/technical-design/outcome.d.ts +4 -4
- package/dist/phases/technical-design/outcome.js +6 -6
- package/dist/phases/technical-design/prompts.d.ts +2 -2
- package/dist/phases/technical-design/prompts.js +10 -10
- package/dist/phases/technical-design-verification/agent.d.ts +3 -3
- package/dist/phases/technical-design-verification/agent.js +4 -4
- package/dist/phases/technical-design-verification/index.d.ts +4 -4
- package/dist/phases/technical-design-verification/index.js +12 -12
- package/dist/phases/technical-design-verification/prompts.d.ts +3 -3
- package/dist/phases/technical-design-verification/prompts.js +6 -6
- package/dist/phases/test-cases-analysis/context.d.ts +5 -5
- package/dist/phases/test-cases-analysis/context.js +18 -18
- package/dist/phases/test-cases-analysis/formatters.js +7 -7
- package/dist/phases/test-cases-analysis/index.d.ts +1 -1
- package/dist/phases/test-cases-analysis/index.js +21 -21
- package/dist/phases/test-cases-analysis/outcome.d.ts +7 -7
- package/dist/phases/test-cases-analysis/outcome.js +13 -13
- package/dist/phases/test-cases-analysis/prompts.d.ts +3 -3
- package/dist/phases/test-cases-analysis/prompts.js +6 -6
- package/dist/phases/user-stories-analysis/context.d.ts +5 -5
- package/dist/phases/user-stories-analysis/context.js +18 -18
- package/dist/phases/user-stories-analysis/formatters.js +7 -7
- package/dist/phases/user-stories-analysis/index.d.ts +1 -1
- package/dist/phases/user-stories-analysis/index.js +21 -21
- package/dist/phases/user-stories-analysis/outcome.d.ts +7 -7
- package/dist/phases/user-stories-analysis/outcome.js +13 -13
- package/dist/phases/user-stories-analysis/prompts.d.ts +3 -3
- package/dist/phases/user-stories-analysis/prompts.js +10 -10
- package/dist/services/audit-logs.d.ts +10 -10
- package/dist/services/audit-logs.js +12 -12
- package/dist/services/branches.d.ts +6 -6
- package/dist/services/branches.js +16 -16
- package/dist/services/checklist.d.ts +3 -3
- package/dist/services/checklist.js +11 -11
- package/dist/services/coaching/coaching-agent.js +2 -2
- package/dist/services/coaching/coaching-loop.d.ts +1 -1
- package/dist/services/coaching/coaching-loop.js +2 -2
- package/dist/services/coaching/phase-coaching.d.ts +2 -2
- package/dist/services/coaching/phase-coaching.js +3 -3
- package/dist/services/coaching/self-rating.js +1 -1
- package/dist/services/feedbacks.d.ts +4 -4
- package/dist/services/feedbacks.js +8 -8
- package/dist/services/phase-hooks/bindings-fetcher.d.ts +4 -4
- package/dist/services/phase-hooks/bindings-fetcher.js +8 -8
- package/dist/services/phase-hooks/hook-executor.js +1 -1
- package/dist/services/phase-hooks/hook-logging.d.ts +2 -2
- package/dist/services/phase-hooks/hook-logging.js +4 -4
- package/dist/services/phase-hooks/hook-runner.d.ts +1 -1
- package/dist/services/phase-hooks/hook-runner.js +4 -4
- package/dist/services/phase-hooks/types.d.ts +3 -3
- package/dist/services/phase-ratings.d.ts +7 -7
- package/dist/services/phase-ratings.js +8 -8
- package/dist/services/pull-requests.d.ts +4 -4
- package/dist/services/pull-requests.js +11 -11
- package/dist/services/skill-resolver.d.ts +1 -1
- package/dist/services/skill-resolver.js +1 -1
- package/dist/skills/phase/app-store-generation/SKILL.md +9 -9
- package/dist/skills/phase/autonomous/SKILL.md +2 -2
- package/dist/skills/phase/branch-planning/SKILL.md +12 -12
- package/dist/skills/phase/bug-fixing/SKILL.md +1 -1
- package/dist/skills/phase/code-implementation/SKILL.md +6 -6
- package/dist/skills/phase/code-implementation-verification/SKILL.md +3 -3
- package/dist/skills/phase/code-testing/SKILL.md +5 -5
- package/dist/skills/phase/functional-testing/SKILL.md +3 -3
- package/dist/skills/phase/growth-analysis/SKILL.md +8 -8
- package/dist/skills/phase/incremental-sync/SKILL.md +6 -6
- package/dist/skills/phase/intelligence-analysis/SKILL.md +7 -7
- package/dist/skills/phase/{feature-analysis → issue-analysis}/SKILL.md +8 -8
- package/dist/skills/phase/pr-execution/SKILL.md +7 -7
- package/dist/skills/phase/pr-splitting/SKILL.md +14 -14
- package/dist/skills/phase/smoke-test/SKILL.md +1 -1
- package/dist/skills/phase/technical-design/SKILL.md +5 -5
- package/dist/skills/phase/test-cases-analysis/SKILL.md +4 -4
- package/dist/skills/phase/user-stories-analysis/SKILL.md +13 -13
- package/dist/system/session-manager.d.ts +3 -3
- package/dist/system/session-manager.js +3 -3
- package/dist/system/sleep-notification.js +2 -2
- package/dist/system/sleep-prevention.js +1 -1
- package/dist/types/index.d.ts +21 -21
- package/dist/types/issues.d.ts +35 -0
- package/dist/types/issues.js +1 -0
- package/dist/types/pipeline.d.ts +4 -4
- package/dist/updater/auto-updater.d.ts +2 -2
- package/dist/updater/auto-updater.js +3 -3
- package/dist/utils/conflict-resolver.d.ts +1 -1
- package/dist/utils/conflict-resolver.js +5 -5
- package/dist/utils/formatters.d.ts +4 -4
- package/dist/utils/formatters.js +29 -29
- package/dist/utils/git-branch-manager-async.d.ts +6 -6
- package/dist/utils/git-branch-manager-async.js +41 -41
- package/dist/utils/git-branch-manager.d.ts +11 -11
- package/dist/utils/git-branch-manager.js +42 -42
- package/dist/utils/image-downloader.d.ts +4 -4
- package/dist/utils/image-downloader.js +17 -17
- package/dist/utils/pipeline-logger.d.ts +1 -1
- package/dist/utils/pipeline-logger.js +5 -5
- package/dist/workspace/workspace-manager.d.ts +17 -17
- package/dist/workspace/workspace-manager.js +21 -21
- package/package.json +1 -1
- package/vitest.config.ts +10 -4
- /package/dist/skills/phase/{feature-analysis-verification → issue-analysis-verification}/SKILL.md +0 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Approval workflow integration for issue phases
|
|
3
|
+
* Checks if current issue status has been approved before executing next phase
|
|
4
|
+
*/
|
|
5
|
+
import { logError, logInfo, logWarning } from '../../utils/logger.js';
|
|
6
|
+
import { callMcpEndpoint } from '../mcp-client.js';
|
|
7
|
+
import { getIssue } from './get-issue.js';
|
|
8
|
+
/**
|
|
9
|
+
* Check if current issue status has been approved before executing next phase
|
|
10
|
+
* This should be called BEFORE executing a phase, not after
|
|
11
|
+
*
|
|
12
|
+
* @param issueId - Issue ID
|
|
13
|
+
* @param verbose - Verbose logging
|
|
14
|
+
* @returns Promise<ApprovalCheckResult> - Whether the phase can proceed
|
|
15
|
+
*/
|
|
16
|
+
export async function checkApprovalBeforePhaseExecution(issueId, verbose = false) {
|
|
17
|
+
try {
|
|
18
|
+
// 1. Get current issue to check its status and product_id
|
|
19
|
+
const issue = await getIssue(issueId, verbose);
|
|
20
|
+
const currentStatus = issue.status;
|
|
21
|
+
const productId = issue.product_id;
|
|
22
|
+
if (verbose) {
|
|
23
|
+
logInfo(`🔍 Checking approval for current status: ${currentStatus}`);
|
|
24
|
+
logInfo(`📦 Product ID: ${productId}`);
|
|
25
|
+
}
|
|
26
|
+
// 2. Check if current status requires approval
|
|
27
|
+
const requiresApprovalResult = (await callMcpEndpoint('approvals/requires_approval', {
|
|
28
|
+
product_id: productId,
|
|
29
|
+
issue_status: currentStatus,
|
|
30
|
+
}));
|
|
31
|
+
if (verbose) {
|
|
32
|
+
logInfo(`📋 MCP requires_approval response: ${JSON.stringify(requiresApprovalResult)}`);
|
|
33
|
+
}
|
|
34
|
+
const requiresApproval = requiresApprovalResult?.requires_approval === true;
|
|
35
|
+
if (!requiresApproval) {
|
|
36
|
+
if (verbose) {
|
|
37
|
+
logInfo(`✅ Current status ${currentStatus} does not require approval. Proceeding.`);
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
canProceed: true,
|
|
41
|
+
requiresApproval: false,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// 3. Status requires approval - check if already approved
|
|
45
|
+
if (verbose) {
|
|
46
|
+
logInfo(`🔒 Current status ${currentStatus} requires approval`);
|
|
47
|
+
}
|
|
48
|
+
const existingApprovals = (await callMcpEndpoint('approvals/issue_approvals', {
|
|
49
|
+
issue_id: issueId,
|
|
50
|
+
}));
|
|
51
|
+
// Check if there's an approved approval for the current status
|
|
52
|
+
const approvedApproval = existingApprovals?.approvals?.find((approval) => approval.requested_status === currentStatus &&
|
|
53
|
+
approval.approval_status === 'approved');
|
|
54
|
+
if (approvedApproval) {
|
|
55
|
+
if (verbose) {
|
|
56
|
+
logInfo(`✅ Found approved approval for ${currentStatus}. Proceeding.`);
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
canProceed: true,
|
|
60
|
+
requiresApproval: true,
|
|
61
|
+
approvalId: approvedApproval.id,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
// Check if there's already a pending approval for current status
|
|
65
|
+
const pendingApproval = existingApprovals?.approvals?.find((approval) => approval.requested_status === currentStatus &&
|
|
66
|
+
approval.approval_status === 'pending');
|
|
67
|
+
if (pendingApproval) {
|
|
68
|
+
if (verbose) {
|
|
69
|
+
logWarning(`⏳ Approval already pending for ${currentStatus}. Waiting for review.`);
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
canProceed: false,
|
|
73
|
+
requiresApproval: true,
|
|
74
|
+
approvalId: pendingApproval.id,
|
|
75
|
+
message: `Waiting for approval of current status: ${currentStatus}`,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
// No pending or approved approval - need to create one
|
|
79
|
+
if (verbose) {
|
|
80
|
+
logInfo(`🔔 No approval exists for ${currentStatus}. Creating approval request...`);
|
|
81
|
+
}
|
|
82
|
+
// Create approval request
|
|
83
|
+
const approvalId = await createApprovalRequestWithEmail(issueId, productId, currentStatus, verbose);
|
|
84
|
+
if (approvalId) {
|
|
85
|
+
return {
|
|
86
|
+
canProceed: false,
|
|
87
|
+
requiresApproval: true,
|
|
88
|
+
approvalId,
|
|
89
|
+
message: `Approval request created for status: ${currentStatus}`,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
logError('Failed to create approval request');
|
|
93
|
+
return {
|
|
94
|
+
canProceed: false,
|
|
95
|
+
requiresApproval: true,
|
|
96
|
+
message: `Failed to create approval request for status: ${currentStatus}`,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
101
|
+
logError(`Error checking approval before phase execution: ${errorMessage}`);
|
|
102
|
+
// On error, block execution to be safe
|
|
103
|
+
return {
|
|
104
|
+
canProceed: false,
|
|
105
|
+
requiresApproval: true,
|
|
106
|
+
message: `Error checking approval: ${errorMessage}`,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Create an approval request (emails are sent automatically by the MCP handler)
|
|
112
|
+
* This is for the CURRENT status, not the next status
|
|
113
|
+
*/
|
|
114
|
+
async function createApprovalRequestWithEmail(issueId, productId, currentStatus, verbose = false) {
|
|
115
|
+
try {
|
|
116
|
+
if (verbose) {
|
|
117
|
+
logInfo(`Creating approval request for current status: ${currentStatus}`);
|
|
118
|
+
}
|
|
119
|
+
// Create approval request via MCP endpoint
|
|
120
|
+
// Note: We're requesting approval for the current status
|
|
121
|
+
// The approval is asking: "Can we proceed from this status?"
|
|
122
|
+
// Email notifications are sent automatically by the MCP handler
|
|
123
|
+
const result = (await callMcpEndpoint('approvals/create', {
|
|
124
|
+
issue_id: issueId,
|
|
125
|
+
requested_status: currentStatus,
|
|
126
|
+
previous_status: null, // We're approving current status, not transitioning
|
|
127
|
+
}));
|
|
128
|
+
const approvalId = result?.approval_id;
|
|
129
|
+
if (!approvalId) {
|
|
130
|
+
logError('Failed to create approval request: No approval_id returned');
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
if (verbose) {
|
|
134
|
+
logInfo(`✅ Approval request created: ${approvalId}`);
|
|
135
|
+
// Log email results if available
|
|
136
|
+
if (result?.emails_sent) {
|
|
137
|
+
const sentCount = result.emails_sent.filter((e) => e.status === 'sent').length;
|
|
138
|
+
const failedCount = result.emails_sent.filter((e) => e.status !== 'sent').length;
|
|
139
|
+
logInfo(`📧 Sent approval emails to ${sentCount} assignee(s)`);
|
|
140
|
+
if (failedCount > 0) {
|
|
141
|
+
logWarning(`⚠️ Failed to send ${failedCount} email(s)`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return approvalId;
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
149
|
+
logError(`Failed to create approval request: ${errorMessage}`);
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type TestCaseStatus, type UserStoryStatus } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Batch update user story statuses
|
|
4
|
+
*/
|
|
5
|
+
export declare function batchUpdateUserStoryStatus(userStoryIds: string[], status: UserStoryStatus, verbose?: boolean): Promise<boolean>;
|
|
6
|
+
/**
|
|
7
|
+
* Batch update test case statuses
|
|
8
|
+
*/
|
|
9
|
+
export declare function batchUpdateTestCaseStatus(testCaseIds: string[], status: TestCaseStatus, verbose?: boolean): Promise<boolean>;
|
|
10
|
+
/**
|
|
11
|
+
* Batch delete user stories
|
|
12
|
+
*/
|
|
13
|
+
export declare function batchDeleteUserStories(userStoryIds: string[], verbose?: boolean): Promise<boolean>;
|
|
14
|
+
/**
|
|
15
|
+
* Batch delete test cases
|
|
16
|
+
*/
|
|
17
|
+
export declare function batchDeleteTestCases(testCaseIds: string[], verbose?: boolean): Promise<boolean>;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { logError, logInfo } from '../../utils/logger.js';
|
|
2
|
+
import { callMcpEndpoint } from '../mcp-client.js';
|
|
3
|
+
/**
|
|
4
|
+
* Batch update user story statuses
|
|
5
|
+
*/
|
|
6
|
+
export async function batchUpdateUserStoryStatus(userStoryIds, status, verbose) {
|
|
7
|
+
try {
|
|
8
|
+
if (verbose) {
|
|
9
|
+
logInfo(`Batch updating ${userStoryIds.length} user stories to status: ${status}`);
|
|
10
|
+
}
|
|
11
|
+
for (const id of userStoryIds) {
|
|
12
|
+
await callMcpEndpoint('user_stories/update_status', {
|
|
13
|
+
user_story_id: id,
|
|
14
|
+
status,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
if (verbose) {
|
|
18
|
+
logInfo('✅ Batch user story status update completed');
|
|
19
|
+
}
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
24
|
+
logError(`Failed to batch update user story statuses: ${errorMessage}`);
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Batch update test case statuses
|
|
30
|
+
*/
|
|
31
|
+
export async function batchUpdateTestCaseStatus(testCaseIds, status, verbose) {
|
|
32
|
+
try {
|
|
33
|
+
if (verbose) {
|
|
34
|
+
logInfo(`Batch updating ${testCaseIds.length} test cases to status: ${status}`);
|
|
35
|
+
}
|
|
36
|
+
for (const id of testCaseIds) {
|
|
37
|
+
await callMcpEndpoint('test_cases/update_status', {
|
|
38
|
+
test_case_id: id,
|
|
39
|
+
status,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
if (verbose) {
|
|
43
|
+
logInfo('✅ Batch test case status update completed');
|
|
44
|
+
}
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
49
|
+
logError(`Failed to batch update test case statuses: ${errorMessage}`);
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Batch delete user stories
|
|
55
|
+
*/
|
|
56
|
+
export async function batchDeleteUserStories(userStoryIds, verbose) {
|
|
57
|
+
try {
|
|
58
|
+
if (verbose) {
|
|
59
|
+
logInfo(`Batch deleting ${userStoryIds.length} user stories`);
|
|
60
|
+
}
|
|
61
|
+
for (const id of userStoryIds) {
|
|
62
|
+
await callMcpEndpoint('user_stories/delete', {
|
|
63
|
+
user_story_id: id,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (verbose) {
|
|
67
|
+
logInfo('✅ Batch user story deletion completed');
|
|
68
|
+
}
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
73
|
+
logError(`Failed to batch delete user stories: ${errorMessage}`);
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Batch delete test cases
|
|
79
|
+
*/
|
|
80
|
+
export async function batchDeleteTestCases(testCaseIds, verbose) {
|
|
81
|
+
try {
|
|
82
|
+
if (verbose) {
|
|
83
|
+
logInfo(`Batch deleting ${testCaseIds.length} test cases`);
|
|
84
|
+
}
|
|
85
|
+
for (const id of testCaseIds) {
|
|
86
|
+
await callMcpEndpoint('test_cases/delete', {
|
|
87
|
+
test_case_id: id,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
if (verbose) {
|
|
91
|
+
logInfo('✅ Batch test case deletion completed');
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
97
|
+
logError(`Failed to batch delete test cases: ${errorMessage}`);
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { logInfo } from '../../utils/logger.js';
|
|
2
|
+
import { callMcpEndpoint } from '../mcp-client.js';
|
|
3
|
+
/**
|
|
4
|
+
* Get issue details by ID
|
|
5
|
+
*/
|
|
6
|
+
export async function getIssue(issueId, verbose) {
|
|
7
|
+
if (verbose) {
|
|
8
|
+
logInfo(`Fetching issue details for: ${issueId}`);
|
|
9
|
+
}
|
|
10
|
+
const result = (await callMcpEndpoint('issues/get', {
|
|
11
|
+
issue_id: issueId,
|
|
12
|
+
}));
|
|
13
|
+
if (!result.issues || result.issues.length === 0) {
|
|
14
|
+
throw new Error(`Issue not found: ${issueId}`);
|
|
15
|
+
}
|
|
16
|
+
const issue = result.issues[0];
|
|
17
|
+
if (!issue || typeof issue !== 'object') {
|
|
18
|
+
throw new Error(`Invalid issue data returned for: ${issueId}`);
|
|
19
|
+
}
|
|
20
|
+
return issue;
|
|
21
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './batch-operations.js';
|
|
2
|
+
export * from './get-issue.js';
|
|
3
|
+
export * from './issue-utils.js';
|
|
4
|
+
export * from './status-updater.js';
|
|
5
|
+
export * from './test-cases.js';
|
|
6
|
+
export * from './update-issue.js';
|
|
7
|
+
export * from './user-stories.js';
|
|
8
|
+
export * from '../../types/issues.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Re-export all issue-related functions
|
|
2
|
+
export * from './batch-operations.js';
|
|
3
|
+
export * from './get-issue.js';
|
|
4
|
+
export * from './issue-utils.js';
|
|
5
|
+
export * from './status-updater.js';
|
|
6
|
+
export * from './test-cases.js';
|
|
7
|
+
export * from './update-issue.js';
|
|
8
|
+
export * from './user-stories.js';
|
|
9
|
+
// Re-export types
|
|
10
|
+
export * from '../../types/issues.js';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type IssueInfo } from '../../types/issues.js';
|
|
2
|
+
/**
|
|
3
|
+
* Claim the next available ready_for_ai issue for processing.
|
|
4
|
+
* Uses database-level locking (FOR UPDATE SKIP LOCKED) to prevent
|
|
5
|
+
* race conditions between multiple workers.
|
|
6
|
+
*
|
|
7
|
+
* @param productId - The product ID to claim an issue from
|
|
8
|
+
* @param verbose - Whether to log verbose output
|
|
9
|
+
* @returns The claimed issue or null if no issues available
|
|
10
|
+
*/
|
|
11
|
+
export declare function claimNextIssue(productId: string, verbose?: boolean): Promise<IssueInfo | null>;
|
|
12
|
+
/**
|
|
13
|
+
* Filter issues by status
|
|
14
|
+
*/
|
|
15
|
+
export declare function filterIssuesByStatus(issues: IssueInfo[], status: string): IssueInfo[];
|
|
16
|
+
/**
|
|
17
|
+
* Sort issues by updated_at (oldest first for processing)
|
|
18
|
+
*/
|
|
19
|
+
export declare function sortIssuesByUpdatedAt(issues: IssueInfo[]): IssueInfo[];
|
|
20
|
+
/**
|
|
21
|
+
* Get issues with ready_for_ai status for a product
|
|
22
|
+
*/
|
|
23
|
+
export declare function getReadyForAIIssues(productId: string, verbose?: boolean): Promise<IssueInfo[]>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { logError, logInfo } from '../../utils/logger.js';
|
|
2
|
+
import { callMcpEndpoint } from '../mcp-client.js';
|
|
3
|
+
/**
|
|
4
|
+
* Claim the next available ready_for_ai issue for processing.
|
|
5
|
+
* Uses database-level locking (FOR UPDATE SKIP LOCKED) to prevent
|
|
6
|
+
* race conditions between multiple workers.
|
|
7
|
+
*
|
|
8
|
+
* @param productId - The product ID to claim an issue from
|
|
9
|
+
* @param verbose - Whether to log verbose output
|
|
10
|
+
* @returns The claimed issue or null if no issues available
|
|
11
|
+
*/
|
|
12
|
+
export async function claimNextIssue(productId, verbose) {
|
|
13
|
+
if (verbose) {
|
|
14
|
+
logInfo(`Attempting to claim next ready_for_ai issue for product: ${productId}`);
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const result = (await callMcpEndpoint('issues/claim', {
|
|
18
|
+
product_id: productId,
|
|
19
|
+
}));
|
|
20
|
+
if (result.issue) {
|
|
21
|
+
if (verbose) {
|
|
22
|
+
logInfo(`✅ Claimed issue: ${result.issue.name} (${result.issue.id})`);
|
|
23
|
+
}
|
|
24
|
+
return result.issue;
|
|
25
|
+
}
|
|
26
|
+
if (verbose) {
|
|
27
|
+
logInfo('No issues available for processing');
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
33
|
+
logError(`Failed to claim issue: ${errorMessage}`);
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Filter issues by status
|
|
39
|
+
*/
|
|
40
|
+
export function filterIssuesByStatus(issues, status) {
|
|
41
|
+
return issues.filter((issue) => issue.status === status);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Sort issues by updated_at (oldest first for processing)
|
|
45
|
+
*/
|
|
46
|
+
export function sortIssuesByUpdatedAt(issues) {
|
|
47
|
+
return [...issues].sort((a, b) => {
|
|
48
|
+
const dateA = new Date(a.updated_at || 0).getTime();
|
|
49
|
+
const dateB = new Date(b.updated_at || 0).getTime();
|
|
50
|
+
return dateA - dateB;
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get issues with ready_for_ai status for a product
|
|
55
|
+
*/
|
|
56
|
+
export async function getReadyForAIIssues(productId, verbose) {
|
|
57
|
+
if (verbose) {
|
|
58
|
+
logInfo(`Fetching ready_for_ai issues for product: ${productId}`);
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
const result = (await callMcpEndpoint('issues/list', {
|
|
62
|
+
product_id: productId,
|
|
63
|
+
status: 'ready_for_ai',
|
|
64
|
+
}));
|
|
65
|
+
const issues = result.issues || [];
|
|
66
|
+
const sortedIssues = sortIssuesByUpdatedAt(issues);
|
|
67
|
+
if (verbose) {
|
|
68
|
+
logInfo(`✅ Found ${sortedIssues.length} ready_for_ai issues (oldest first)`);
|
|
69
|
+
sortedIssues.forEach((issue, index) => {
|
|
70
|
+
logInfo(` ${index + 1}. ${issue.name} (updated: ${issue.updated_at})`);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return sortedIssues;
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
77
|
+
logError(`Failed to fetch ready_for_ai issues: ${errorMessage}`);
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Issue status updater for workflow pipeline
|
|
3
|
+
* Updates issue status at each phase of the development workflow
|
|
4
|
+
*/
|
|
5
|
+
import type { IssueStatus } from '../../types/index.js';
|
|
6
|
+
interface StatusUpdateOptions {
|
|
7
|
+
readonly issueId: string;
|
|
8
|
+
readonly status: IssueStatus;
|
|
9
|
+
readonly verbose?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Check if moving from currentStatus to newStatus is forward progression
|
|
13
|
+
*
|
|
14
|
+
* Special cases for archived status:
|
|
15
|
+
* - Any status → archived: Always allowed (archiving from any state)
|
|
16
|
+
* - Archived → backlog: Always allowed (unarchiving restores to backlog)
|
|
17
|
+
*/
|
|
18
|
+
export declare function isForwardProgression(currentStatus: IssueStatus, newStatus: IssueStatus): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Update issue status via MCP endpoint
|
|
21
|
+
*/
|
|
22
|
+
export declare function updateIssueStatus({ issueId, status, verbose, }: StatusUpdateOptions): Promise<boolean>;
|
|
23
|
+
/**
|
|
24
|
+
* Map pipeline phase to issue status
|
|
25
|
+
*/
|
|
26
|
+
export declare const getStatusForPhase: (phase: string) => IssueStatus | null;
|
|
27
|
+
/**
|
|
28
|
+
* Update issue status based on pipeline phase
|
|
29
|
+
*
|
|
30
|
+
* @param issueId - The issue ID to update
|
|
31
|
+
* @param phase - The pipeline phase name
|
|
32
|
+
* @param verbose - Whether to log verbose output
|
|
33
|
+
* @returns Promise<boolean> - true if update succeeded, false if skipped or failed
|
|
34
|
+
*
|
|
35
|
+
* BREAKING CHANGE: This function was changed from synchronous to asynchronous in PR #87
|
|
36
|
+
* to support regression prevention checks. All callers must now use await/then to handle
|
|
37
|
+
* the Promise return type. The function now validates against status regression and will
|
|
38
|
+
* skip updates that would move an issue backward in the development workflow.
|
|
39
|
+
*/
|
|
40
|
+
export declare const updateIssueStatusForPhase: (issueId: string, phase: string, verbose?: boolean) => Promise<boolean>;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Issue status updater for workflow pipeline
|
|
3
|
+
* Updates issue status at each phase of the development workflow
|
|
4
|
+
*/
|
|
5
|
+
import { PHASE_STATUS_MAP, STATUS_PROGRESSION_ORDER, } from '../../config/issue-status.js';
|
|
6
|
+
import { logError, logInfo } from '../../utils/logger.js';
|
|
7
|
+
import { callMcpEndpoint } from '../mcp-client.js';
|
|
8
|
+
import { getIssue } from './get-issue.js';
|
|
9
|
+
/**
|
|
10
|
+
* Check if moving from currentStatus to newStatus is forward progression
|
|
11
|
+
*
|
|
12
|
+
* Special cases for archived status:
|
|
13
|
+
* - Any status → archived: Always allowed (archiving from any state)
|
|
14
|
+
* - Archived → backlog: Always allowed (unarchiving restores to backlog)
|
|
15
|
+
*/
|
|
16
|
+
export function isForwardProgression(currentStatus, newStatus) {
|
|
17
|
+
// Any status can transition to archived
|
|
18
|
+
if (newStatus === 'archived') {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
// Archived can only transition back to backlog (unarchive)
|
|
22
|
+
if (currentStatus === 'archived') {
|
|
23
|
+
return newStatus === 'backlog';
|
|
24
|
+
}
|
|
25
|
+
const currentIndex = STATUS_PROGRESSION_ORDER.indexOf(currentStatus);
|
|
26
|
+
const newIndex = STATUS_PROGRESSION_ORDER.indexOf(newStatus);
|
|
27
|
+
// Allow moving forward or staying at same level (for retries, etc.)
|
|
28
|
+
return newIndex >= currentIndex;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Update issue status via MCP endpoint
|
|
32
|
+
*/
|
|
33
|
+
export async function updateIssueStatus({ issueId, status, verbose = false, }) {
|
|
34
|
+
try {
|
|
35
|
+
if (verbose) {
|
|
36
|
+
logInfo(`Updating issue ${issueId} status to: ${status}`);
|
|
37
|
+
}
|
|
38
|
+
// Get current issue status to check for regression
|
|
39
|
+
let issue;
|
|
40
|
+
let currentStatus;
|
|
41
|
+
try {
|
|
42
|
+
issue = await getIssue(issueId, verbose);
|
|
43
|
+
currentStatus = issue.status;
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
47
|
+
logError(`Failed to get current issue status for ${issueId}: ${errorMessage}`);
|
|
48
|
+
// If we can't get the current status, we can't safely check for regression
|
|
49
|
+
// so we'll skip the update to prevent potential regression
|
|
50
|
+
if (verbose) {
|
|
51
|
+
logInfo('⚠️ Skipping status update due to inability to verify current status');
|
|
52
|
+
}
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
// Check if this would be a regression
|
|
56
|
+
if (!isForwardProgression(currentStatus, status)) {
|
|
57
|
+
const message = `⚠️ Skipping status regression: ${currentStatus} → ${status}. Only forward progression allowed.`;
|
|
58
|
+
if (verbose) {
|
|
59
|
+
logInfo(message);
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
// Only proceed if status actually changed
|
|
64
|
+
if (currentStatus === status) {
|
|
65
|
+
if (verbose) {
|
|
66
|
+
logInfo(`Status already at ${status}, no update needed`);
|
|
67
|
+
}
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
// Update status
|
|
71
|
+
await callMcpEndpoint('issues/update', {
|
|
72
|
+
issue_id: issueId,
|
|
73
|
+
status,
|
|
74
|
+
});
|
|
75
|
+
if (verbose) {
|
|
76
|
+
logInfo(`✅ Issue status updated successfully from ${currentStatus} to: ${status}`);
|
|
77
|
+
}
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
82
|
+
if (verbose) {
|
|
83
|
+
logError(`Failed to update issue status: ${errorMessage}`);
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Map pipeline phase to issue status
|
|
90
|
+
*/
|
|
91
|
+
export const getStatusForPhase = (phase) => {
|
|
92
|
+
// Use the externalized phase-to-status mapping
|
|
93
|
+
return PHASE_STATUS_MAP[phase] ?? null;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Update issue status based on pipeline phase
|
|
97
|
+
*
|
|
98
|
+
* @param issueId - The issue ID to update
|
|
99
|
+
* @param phase - The pipeline phase name
|
|
100
|
+
* @param verbose - Whether to log verbose output
|
|
101
|
+
* @returns Promise<boolean> - true if update succeeded, false if skipped or failed
|
|
102
|
+
*
|
|
103
|
+
* BREAKING CHANGE: This function was changed from synchronous to asynchronous in PR #87
|
|
104
|
+
* to support regression prevention checks. All callers must now use await/then to handle
|
|
105
|
+
* the Promise return type. The function now validates against status regression and will
|
|
106
|
+
* skip updates that would move an issue backward in the development workflow.
|
|
107
|
+
*/
|
|
108
|
+
export const updateIssueStatusForPhase = async (issueId, phase, verbose) => {
|
|
109
|
+
const status = getStatusForPhase(phase);
|
|
110
|
+
if (!status) {
|
|
111
|
+
const message = `⚠️ Unknown phase '${phase}' - skipping status update to prevent regression`;
|
|
112
|
+
if (verbose) {
|
|
113
|
+
logInfo(message);
|
|
114
|
+
}
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
return updateIssueStatus({
|
|
118
|
+
issueId,
|
|
119
|
+
status,
|
|
120
|
+
verbose,
|
|
121
|
+
});
|
|
122
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type TestCase, type TestCaseStatus } from '../../types/issues.js';
|
|
2
|
+
/**
|
|
3
|
+
* Get test cases for an issue
|
|
4
|
+
*/
|
|
5
|
+
export declare function getTestCases(issueId: string, verbose?: boolean): Promise<TestCase[]>;
|
|
6
|
+
/**
|
|
7
|
+
* Create a new test case for an issue
|
|
8
|
+
*/
|
|
9
|
+
export declare function createTestCase(issueId: string, testCase: {
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
is_critical?: boolean;
|
|
13
|
+
}, verbose?: boolean): Promise<boolean>;
|
|
14
|
+
/**
|
|
15
|
+
* Create multiple test cases for an issue
|
|
16
|
+
*/
|
|
17
|
+
export declare function createTestCases(mcpServerUrl: string, mcpToken: string, issueId: string, testCases: {
|
|
18
|
+
name: string;
|
|
19
|
+
description: string;
|
|
20
|
+
is_critical?: boolean;
|
|
21
|
+
}[], verbose?: boolean): Promise<boolean>;
|
|
22
|
+
/**
|
|
23
|
+
* Delete a test case
|
|
24
|
+
*/
|
|
25
|
+
export declare function deleteTestCase(testCaseId: string, verbose?: boolean): Promise<boolean>;
|
|
26
|
+
/**
|
|
27
|
+
* Update test case status
|
|
28
|
+
*/
|
|
29
|
+
export declare function updateTestCaseStatus(testCaseId: string, status: TestCaseStatus, verbose?: boolean): Promise<boolean>;
|