edsger 0.36.2 → 0.37.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/.claude/settings.local.json +23 -3
- package/.env.local +12 -0
- package/dist/api/features/__tests__/regression-prevention.test.d.ts +5 -0
- package/dist/api/features/__tests__/regression-prevention.test.js +338 -0
- package/dist/api/features/__tests__/status-updater.integration.test.d.ts +5 -0
- package/dist/api/features/__tests__/status-updater.integration.test.js +497 -0
- package/dist/api/growth.d.ts +23 -1
- package/dist/api/growth.js +25 -0
- package/dist/commands/app-store/index.js +2 -6
- package/dist/commands/code-review/index.js +3 -3
- package/dist/commands/growth-analysis/index.js +2 -0
- package/dist/commands/init/index.js +3 -3
- package/dist/commands/workflow/pipeline-runner.d.ts +17 -0
- package/dist/commands/workflow/pipeline-runner.js +393 -0
- package/dist/commands/workflow/runner.d.ts +26 -0
- package/dist/commands/workflow/runner.js +119 -0
- package/dist/commands/workflow/workflow-runner.d.ts +26 -0
- package/dist/commands/workflow/workflow-runner.js +119 -0
- package/dist/index.js +4 -0
- package/dist/phases/app-store-generation/__tests__/screenshot-composer.test.js +452 -32
- package/dist/phases/app-store-generation/assets/inter-latin-ext.woff2 +0 -0
- package/dist/phases/app-store-generation/assets/inter-latin.woff2 +0 -0
- package/dist/phases/app-store-generation/inter-font.d.ts +20 -0
- package/dist/phases/app-store-generation/inter-font.js +49 -0
- package/dist/phases/app-store-generation/screenshot-composer.js +183 -19
- package/dist/phases/code-implementation/analyzer-helpers.d.ts +28 -0
- package/dist/phases/code-implementation/analyzer-helpers.js +177 -0
- package/dist/phases/code-implementation/analyzer.d.ts +32 -0
- package/dist/phases/code-implementation/analyzer.js +629 -0
- package/dist/phases/code-implementation/context-fetcher.d.ts +17 -0
- package/dist/phases/code-implementation/context-fetcher.js +86 -0
- package/dist/phases/code-implementation/mcp-server.d.ts +1 -0
- package/dist/phases/code-implementation/mcp-server.js +93 -0
- package/dist/phases/code-implementation/prompts-improvement.d.ts +5 -0
- package/dist/phases/code-implementation/prompts-improvement.js +108 -0
- package/dist/phases/code-implementation-verification/verifier.d.ts +31 -0
- package/dist/phases/code-implementation-verification/verifier.js +196 -0
- package/dist/phases/code-refine/analyzer.d.ts +41 -0
- package/dist/phases/code-refine/analyzer.js +561 -0
- package/dist/phases/code-refine/context-fetcher.d.ts +94 -0
- package/dist/phases/code-refine/context-fetcher.js +423 -0
- package/dist/phases/code-refine-verification/analysis/llm-analyzer.d.ts +22 -0
- package/dist/phases/code-refine-verification/analysis/llm-analyzer.js +134 -0
- package/dist/phases/code-refine-verification/verifier.d.ts +47 -0
- package/dist/phases/code-refine-verification/verifier.js +597 -0
- package/dist/phases/code-review/analyzer.d.ts +29 -0
- package/dist/phases/code-review/analyzer.js +363 -0
- package/dist/phases/code-review/context-fetcher.d.ts +92 -0
- package/dist/phases/code-review/context-fetcher.js +296 -0
- package/dist/phases/feature-analysis/analyzer-helpers.d.ts +10 -0
- package/dist/phases/feature-analysis/analyzer-helpers.js +47 -0
- package/dist/phases/feature-analysis/analyzer.d.ts +11 -0
- package/dist/phases/feature-analysis/analyzer.js +208 -0
- package/dist/phases/feature-analysis/context-fetcher.d.ts +26 -0
- package/dist/phases/feature-analysis/context-fetcher.js +134 -0
- package/dist/phases/feature-analysis/http-fallback.d.ts +20 -0
- package/dist/phases/feature-analysis/http-fallback.js +95 -0
- package/dist/phases/feature-analysis/mcp-server.d.ts +1 -0
- package/dist/phases/feature-analysis/mcp-server.js +144 -0
- package/dist/phases/feature-analysis/prompts-improvement.d.ts +8 -0
- package/dist/phases/feature-analysis/prompts-improvement.js +109 -0
- package/dist/phases/feature-analysis-verification/verifier.d.ts +37 -0
- package/dist/phases/feature-analysis-verification/verifier.js +147 -0
- package/dist/phases/growth-analysis/context.d.ts +2 -2
- package/dist/phases/growth-analysis/context.js +18 -4
- package/dist/phases/growth-analysis/index.d.ts +2 -0
- package/dist/phases/growth-analysis/index.js +21 -13
- package/dist/phases/technical-design/analyzer-helpers.d.ts +25 -0
- package/dist/phases/technical-design/analyzer-helpers.js +39 -0
- package/dist/phases/technical-design/analyzer.d.ts +21 -0
- package/dist/phases/technical-design/analyzer.js +461 -0
- package/dist/phases/technical-design/context-fetcher.d.ts +12 -0
- package/dist/phases/technical-design/context-fetcher.js +39 -0
- package/dist/phases/technical-design/http-fallback.d.ts +17 -0
- package/dist/phases/technical-design/http-fallback.js +151 -0
- package/dist/phases/technical-design/mcp-server.d.ts +1 -0
- package/dist/phases/technical-design/mcp-server.js +157 -0
- package/dist/phases/technical-design/prompts-improvement.d.ts +5 -0
- package/dist/phases/technical-design/prompts-improvement.js +93 -0
- package/dist/phases/technical-design-verification/verifier.d.ts +53 -0
- package/dist/phases/technical-design-verification/verifier.js +170 -0
- package/dist/services/feature-branches.d.ts +77 -0
- package/dist/services/feature-branches.js +205 -0
- package/dist/services/video/device-frames.d.ts +1 -1
- package/dist/services/video/device-frames.js +81 -3
- package/dist/services/video/index.d.ts +1 -1
- package/dist/services/video/index.js +12 -6
- package/dist/services/video/screenshot-generator.js +5 -8
- package/dist/services/video/video-assembler.js +2 -6
- package/dist/types/index.d.ts +2 -0
- package/dist/utils/validation.d.ts +11 -2
- package/dist/utils/validation.js +93 -6
- package/dist/workflow-runner/config/phase-configs.d.ts +5 -0
- package/dist/workflow-runner/config/phase-configs.js +120 -0
- package/dist/workflow-runner/core/feature-filter.d.ts +16 -0
- package/dist/workflow-runner/core/feature-filter.js +46 -0
- package/dist/workflow-runner/core/index.d.ts +8 -0
- package/dist/workflow-runner/core/index.js +12 -0
- package/dist/workflow-runner/core/pipeline-evaluator.d.ts +24 -0
- package/dist/workflow-runner/core/pipeline-evaluator.js +32 -0
- package/dist/workflow-runner/core/state-manager.d.ts +24 -0
- package/dist/workflow-runner/core/state-manager.js +42 -0
- package/dist/workflow-runner/core/workflow-logger.d.ts +20 -0
- package/dist/workflow-runner/core/workflow-logger.js +65 -0
- package/dist/workflow-runner/executors/phase-executor.d.ts +8 -0
- package/dist/workflow-runner/executors/phase-executor.js +248 -0
- package/dist/workflow-runner/feature-workflow-runner.d.ts +26 -0
- package/dist/workflow-runner/feature-workflow-runner.js +119 -0
- package/dist/workflow-runner/index.d.ts +2 -0
- package/dist/workflow-runner/index.js +2 -0
- package/dist/workflow-runner/pipeline-runner.d.ts +17 -0
- package/dist/workflow-runner/pipeline-runner.js +393 -0
- package/dist/workflow-runner/workflow-processor.d.ts +54 -0
- package/dist/workflow-runner/workflow-processor.js +170 -0
- package/package.json +2 -2
- package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.d.ts +0 -4
- package/dist/services/lifecycle-agent/__tests__/phase-criteria.test.js +0 -133
- package/dist/services/lifecycle-agent/__tests__/transition-rules.test.d.ts +0 -4
- package/dist/services/lifecycle-agent/__tests__/transition-rules.test.js +0 -336
- package/dist/services/lifecycle-agent/index.d.ts +0 -24
- package/dist/services/lifecycle-agent/index.js +0 -25
- package/dist/services/lifecycle-agent/phase-criteria.d.ts +0 -57
- package/dist/services/lifecycle-agent/phase-criteria.js +0 -335
- package/dist/services/lifecycle-agent/transition-rules.d.ts +0 -60
- package/dist/services/lifecycle-agent/transition-rules.js +0 -184
- package/dist/services/lifecycle-agent/types.d.ts +0 -190
- package/dist/services/lifecycle-agent/types.js +0 -12
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checklist verification agent for feature analysis
|
|
3
|
+
* This agent independently reviews checklist compliance to ensure objectivity
|
|
4
|
+
*/
|
|
5
|
+
import { query } from '@anthropic-ai/claude-code';
|
|
6
|
+
import { logInfo, logError } from '../../utils/logger.js';
|
|
7
|
+
import { createChecklistVerificationPrompt, createChecklistVerificationSystemPrompt, } from './prompts.js';
|
|
8
|
+
function userMessage(content) {
|
|
9
|
+
return {
|
|
10
|
+
type: 'user',
|
|
11
|
+
message: { role: 'user', content: content },
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
async function* prompt(verificationPrompt) {
|
|
15
|
+
yield userMessage(verificationPrompt);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Verify checklist compliance using an independent AI agent
|
|
19
|
+
* This agent acts as a "challenger" to validate the claims made by the analysis agent
|
|
20
|
+
*/
|
|
21
|
+
export async function verifyChecklistCompliance(options, config) {
|
|
22
|
+
const { checklistContext, analysisContext, createdUserStories, createdTestCases, verbose, } = options;
|
|
23
|
+
const totalChecklistItems = checklistContext.checklists.reduce((sum, checklist) => sum + checklist.items.length, 0);
|
|
24
|
+
if (verbose) {
|
|
25
|
+
logInfo('🔍 Starting checklist verification...');
|
|
26
|
+
logInfo(` Verifying ${totalChecklistItems} checklist items`);
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const systemPrompt = createChecklistVerificationSystemPrompt(config);
|
|
30
|
+
const verificationPrompt = createChecklistVerificationPrompt({
|
|
31
|
+
checklistContext,
|
|
32
|
+
analysisContext,
|
|
33
|
+
createdUserStories,
|
|
34
|
+
createdTestCases,
|
|
35
|
+
});
|
|
36
|
+
let lastAssistantResponse = '';
|
|
37
|
+
let verificationResult = null;
|
|
38
|
+
if (verbose) {
|
|
39
|
+
logInfo('🤖 Starting verification agent query...');
|
|
40
|
+
}
|
|
41
|
+
// Use Claude Code SDK for verification
|
|
42
|
+
for await (const message of query({
|
|
43
|
+
prompt: prompt(verificationPrompt),
|
|
44
|
+
options: {
|
|
45
|
+
appendSystemPrompt: systemPrompt,
|
|
46
|
+
model: config.claude.model || 'sonnet',
|
|
47
|
+
maxTurns: 100,
|
|
48
|
+
permissionMode: 'bypassPermissions',
|
|
49
|
+
},
|
|
50
|
+
})) {
|
|
51
|
+
if (verbose) {
|
|
52
|
+
logInfo(` Received message type: ${message.type}`);
|
|
53
|
+
}
|
|
54
|
+
// Capture assistant responses
|
|
55
|
+
if (message.type === 'assistant' && message.message?.content) {
|
|
56
|
+
for (const content of message.message.content) {
|
|
57
|
+
if (content.type === 'text') {
|
|
58
|
+
lastAssistantResponse += content.text + '\n';
|
|
59
|
+
if (verbose) {
|
|
60
|
+
console.log(`\n🔍 ${content.text}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (message.type === 'result') {
|
|
66
|
+
if (message.subtype === 'success') {
|
|
67
|
+
logInfo('\n✅ Verification completed, parsing results...');
|
|
68
|
+
try {
|
|
69
|
+
const responseText = message.result || lastAssistantResponse;
|
|
70
|
+
// Try to extract JSON from markdown code block
|
|
71
|
+
const jsonBlockMatch = responseText.match(/```json\s*\n([\s\S]*?)\n\s*```/);
|
|
72
|
+
let jsonResult = null;
|
|
73
|
+
if (jsonBlockMatch) {
|
|
74
|
+
jsonResult = JSON.parse(jsonBlockMatch[1]);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
jsonResult = JSON.parse(responseText);
|
|
78
|
+
}
|
|
79
|
+
if (jsonResult && jsonResult.verification) {
|
|
80
|
+
verificationResult = jsonResult.verification;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
throw new Error('Invalid verification JSON structure');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
logError(`Failed to parse verification result: ${error}`);
|
|
88
|
+
// Return default "uncertain" result
|
|
89
|
+
verificationResult = createUncertainVerificationResult(checklistContext, 'Failed to parse verification response');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
logError(`\n⚠️ Verification incomplete: ${message.subtype}`);
|
|
94
|
+
verificationResult = createUncertainVerificationResult(checklistContext, `Verification incomplete: ${message.subtype}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (!verificationResult) {
|
|
99
|
+
verificationResult = createUncertainVerificationResult(checklistContext, 'No verification result received');
|
|
100
|
+
}
|
|
101
|
+
if (verbose) {
|
|
102
|
+
logInfo('\n📊 Verification Summary:');
|
|
103
|
+
logInfo(` Total items: ${verificationResult.total_items}`);
|
|
104
|
+
logInfo(` ✅ Confirmed: ${verificationResult.confirmed_count}`);
|
|
105
|
+
logInfo(` ❌ Rejected: ${verificationResult.rejected_count}`);
|
|
106
|
+
logInfo(` ⚠️ Uncertain: ${verificationResult.uncertain_count}`);
|
|
107
|
+
logInfo(` Summary: ${verificationResult.summary}`);
|
|
108
|
+
if (verificationResult.rejected_count > 0) {
|
|
109
|
+
logInfo('\n❌ Rejected items:');
|
|
110
|
+
verificationResult.item_verifications
|
|
111
|
+
.filter((v) => v.verification_status === 'rejected')
|
|
112
|
+
.forEach((v) => {
|
|
113
|
+
logInfo(` - ${v.checklist_item_id}`);
|
|
114
|
+
logInfo(` Reason: ${v.verification_reason}`);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return verificationResult;
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
logError(`Checklist verification failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
122
|
+
return createUncertainVerificationResult(checklistContext, `Verification error: ${error instanceof Error ? error.message : String(error)}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Create a default "uncertain" verification result when verification fails
|
|
127
|
+
*/
|
|
128
|
+
function createUncertainVerificationResult(checklistContext, reason) {
|
|
129
|
+
// Get all checklist items
|
|
130
|
+
const allItems = checklistContext.checklists.flatMap((checklist) => checklist.items.map((item) => ({
|
|
131
|
+
checklist_item_id: item.id,
|
|
132
|
+
})));
|
|
133
|
+
return {
|
|
134
|
+
all_verified: false,
|
|
135
|
+
total_items: allItems.length,
|
|
136
|
+
confirmed_count: 0,
|
|
137
|
+
rejected_count: 0,
|
|
138
|
+
uncertain_count: allItems.length,
|
|
139
|
+
item_verifications: allItems.map((item) => ({
|
|
140
|
+
checklist_item_id: item.checklist_item_id,
|
|
141
|
+
is_satisfied: false,
|
|
142
|
+
verification_status: 'uncertain',
|
|
143
|
+
verification_reason: reason,
|
|
144
|
+
})),
|
|
145
|
+
summary: `Verification could not be completed: ${reason}`,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
@@ -11,11 +11,11 @@ export declare function fetchGrowthAnalysisContext(productId: string, verbose?:
|
|
|
11
11
|
/**
|
|
12
12
|
* Format context into a prompt string for the AI
|
|
13
13
|
*/
|
|
14
|
-
export declare function formatContextForPrompt(context: GrowthAnalysisContext): string;
|
|
14
|
+
export declare function formatContextForPrompt(context: GrowthAnalysisContext, guidance?: string): string;
|
|
15
15
|
/**
|
|
16
16
|
* Prepare the full analysis prompt with all context
|
|
17
17
|
*/
|
|
18
|
-
export declare function prepareGrowthAnalysisContext(productId: string, verbose?: boolean, hasCodebase?: boolean): Promise<{
|
|
18
|
+
export declare function prepareGrowthAnalysisContext(productId: string, verbose?: boolean, hasCodebase?: boolean, guidance?: string): Promise<{
|
|
19
19
|
context: GrowthAnalysisContext;
|
|
20
20
|
analysisPrompt: string;
|
|
21
21
|
}>;
|
|
@@ -30,7 +30,7 @@ export async function fetchGrowthAnalysisContext(productId, verbose) {
|
|
|
30
30
|
/**
|
|
31
31
|
* Format context into a prompt string for the AI
|
|
32
32
|
*/
|
|
33
|
-
export function formatContextForPrompt(context) {
|
|
33
|
+
export function formatContextForPrompt(context, guidance) {
|
|
34
34
|
const { product, previousCampaigns } = context;
|
|
35
35
|
const campaignsList = previousCampaigns.length > 0
|
|
36
36
|
? previousCampaigns
|
|
@@ -45,6 +45,16 @@ export function formatContextForPrompt(context) {
|
|
|
45
45
|
.map((f) => `- **${f.name}**: ${f.description || 'No description'} (Status: ${f.status || 'unknown'})`)
|
|
46
46
|
.join('\n')
|
|
47
47
|
: 'No features listed.';
|
|
48
|
+
const guidanceSection = guidance
|
|
49
|
+
? `
|
|
50
|
+
|
|
51
|
+
## Human Growth Guidance
|
|
52
|
+
The product owner has provided the following direction for this growth analysis. **You MUST follow this guidance closely** — it takes priority over your own judgement for content direction, themes, audience, and channel selection.
|
|
53
|
+
|
|
54
|
+
${guidance}
|
|
55
|
+
|
|
56
|
+
---`
|
|
57
|
+
: '';
|
|
48
58
|
return `# Growth Analysis Context
|
|
49
59
|
|
|
50
60
|
## Product Information
|
|
@@ -54,23 +64,27 @@ export function formatContextForPrompt(context) {
|
|
|
54
64
|
|
|
55
65
|
## Product Features (${product.features?.length || 0})
|
|
56
66
|
${featuresList}
|
|
67
|
+
${guidanceSection}
|
|
57
68
|
|
|
58
69
|
## Previous Growth Campaigns (${previousCampaigns.length})
|
|
59
70
|
${campaignsList}
|
|
60
71
|
|
|
61
72
|
---
|
|
62
73
|
|
|
63
|
-
**Important**: Analyze the product above and create a growth strategy. Each content suggestion must be DIFFERENT from all previous campaigns listed above. Use the product name, description, and features to write specific, concrete content — never use placeholder text.`;
|
|
74
|
+
**Important**: Analyze the product above and create a growth strategy.${guidance ? ' Follow the human growth guidance provided above for direction, themes, and tone.' : ''} Each content suggestion must be DIFFERENT from all previous campaigns listed above. Use the product name, description, and features to write specific, concrete content — never use placeholder text.`;
|
|
64
75
|
}
|
|
65
76
|
/**
|
|
66
77
|
* Prepare the full analysis prompt with all context
|
|
67
78
|
*/
|
|
68
|
-
export async function prepareGrowthAnalysisContext(productId, verbose, hasCodebase = false) {
|
|
79
|
+
export async function prepareGrowthAnalysisContext(productId, verbose, hasCodebase = false, guidance) {
|
|
69
80
|
if (verbose) {
|
|
70
81
|
logInfo('Fetching growth analysis context via MCP endpoints...');
|
|
82
|
+
if (guidance) {
|
|
83
|
+
logInfo(`Human guidance provided: "${guidance.substring(0, 80)}${guidance.length > 80 ? '...' : ''}"`);
|
|
84
|
+
}
|
|
71
85
|
}
|
|
72
86
|
const context = await fetchGrowthAnalysisContext(productId, verbose);
|
|
73
|
-
const contextInfo = formatContextForPrompt(context);
|
|
87
|
+
const contextInfo = formatContextForPrompt(context, guidance);
|
|
74
88
|
const analysisPrompt = createGrowthAnalysisPromptWithContext(productId, contextInfo, hasCodebase);
|
|
75
89
|
return { context, analysisPrompt };
|
|
76
90
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getGitHubConfigByProduct } from '../../api/github.js';
|
|
2
|
-
import { saveGrowthAnalysis } from '../../api/growth.js';
|
|
2
|
+
import { saveGrowthAnalysis, updateGrowthAnalysis } from '../../api/growth.js';
|
|
3
3
|
import { generateGrowthVideo, } from '../../services/video/index.js';
|
|
4
4
|
import { logError, logInfo, logSuccess, logWarning, } from '../../utils/logger.js';
|
|
5
5
|
import { cloneFeatureRepo, ensureWorkspaceDir, } from '../../workspace/workspace-manager.js';
|
|
@@ -52,7 +52,7 @@ contentSuggestions) {
|
|
|
52
52
|
export const analyseGrowth = async (options, config
|
|
53
53
|
// eslint-disable-next-line complexity -- orchestration function with context assembly, agent execution, and result processing
|
|
54
54
|
) => {
|
|
55
|
-
const { productId, verbose } = options;
|
|
55
|
+
const { productId, verbose, guidance, analysisId } = options;
|
|
56
56
|
if (verbose) {
|
|
57
57
|
logInfo(`Starting growth analysis for product ID: ${productId}`);
|
|
58
58
|
}
|
|
@@ -78,7 +78,7 @@ export const analyseGrowth = async (options, config
|
|
|
78
78
|
logInfo(`Could not clone repo (continuing without codebase): ${error instanceof Error ? error.message : String(error)}`);
|
|
79
79
|
}
|
|
80
80
|
const hasCodebase = !!repoCwd;
|
|
81
|
-
const { context: _context, analysisPrompt } = await prepareGrowthAnalysisContext(productId, verbose, hasCodebase);
|
|
81
|
+
const { context: _context, analysisPrompt } = await prepareGrowthAnalysisContext(productId, verbose, hasCodebase, guidance);
|
|
82
82
|
const systemPrompt = createGrowthAnalysisSystemPrompt(hasCodebase);
|
|
83
83
|
if (verbose) {
|
|
84
84
|
logInfo('Starting AI query for growth analysis...');
|
|
@@ -95,21 +95,29 @@ export const analyseGrowth = async (options, config
|
|
|
95
95
|
const targetChannels = (analysisResult.target_channels || []);
|
|
96
96
|
const contentSuggestions = (analysisResult.content_suggestions || []);
|
|
97
97
|
const searchContext = analysisResult.search_context || null;
|
|
98
|
-
const savedAnalysis =
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
98
|
+
const savedAnalysis = analysisId
|
|
99
|
+
? await updateGrowthAnalysis(analysisId, {
|
|
100
|
+
analysis_content: analysisContent,
|
|
101
|
+
target_channels: targetChannels,
|
|
102
|
+
content_suggestions: contentSuggestions,
|
|
103
|
+
search_context: searchContext,
|
|
104
|
+
status: 'completed',
|
|
105
|
+
}, verbose)
|
|
106
|
+
: await saveGrowthAnalysis({
|
|
107
|
+
product_id: productId,
|
|
108
|
+
analysis_content: analysisContent,
|
|
109
|
+
target_channels: targetChannels,
|
|
110
|
+
content_suggestions: contentSuggestions,
|
|
111
|
+
search_context: searchContext,
|
|
112
|
+
growth_guidance: guidance ?? null,
|
|
113
|
+
status: 'completed',
|
|
114
|
+
}, verbose);
|
|
106
115
|
logInfo(`Growth analysis completed: ${targetChannels.length} channels, ${contentSuggestions.length} suggestions`);
|
|
107
116
|
// Process video generation for applicable content suggestions
|
|
108
117
|
const videoPlans = extractVideoPlans(contentSuggestions);
|
|
109
118
|
const videoResults = new Map();
|
|
110
119
|
if (videoPlans.length > 0) {
|
|
111
120
|
logInfo(`\nFound ${videoPlans.length} content suggestion(s) with video plans`);
|
|
112
|
-
const analysisId = savedAnalysis?.id || productId;
|
|
113
121
|
// Log all planned videos
|
|
114
122
|
for (const { index, plan } of videoPlans) {
|
|
115
123
|
const suggestion = contentSuggestions[index];
|
|
@@ -122,7 +130,7 @@ export const analyseGrowth = async (options, config
|
|
|
122
130
|
logInfo(`\nGenerating ${videoPlans.length} video(s) (max ${MAX_CONCURRENT_VIDEOS} concurrent)...`);
|
|
123
131
|
const settled = await runWithConcurrencyLimit(videoPlans.map(({ index, plan }) => () => generateGrowthVideo(plan, {
|
|
124
132
|
productId,
|
|
125
|
-
analysisId,
|
|
133
|
+
analysisId: analysisId ?? '',
|
|
126
134
|
verbose,
|
|
127
135
|
}).then((result) => ({ index, result }))), MAX_CONCURRENT_VIDEOS);
|
|
128
136
|
for (const outcome of settled) {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type ChecklistVerificationResult } from '../technical-design-verification/agent.js';
|
|
2
|
+
export interface TechnicalDesignResult {
|
|
3
|
+
featureId: string;
|
|
4
|
+
technicalDesign: string | null;
|
|
5
|
+
status: 'success' | 'error';
|
|
6
|
+
summary: string;
|
|
7
|
+
verificationResult?: ChecklistVerificationResult;
|
|
8
|
+
iterations?: number;
|
|
9
|
+
data?: {
|
|
10
|
+
checklist_item_results?: any[];
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Build successful design result
|
|
16
|
+
*/
|
|
17
|
+
export declare function buildDesignResult(featureId: string, technicalDesign: string, summary: string, iterations: number, checklistItemResults?: any[]): TechnicalDesignResult;
|
|
18
|
+
/**
|
|
19
|
+
* Build verification failure result
|
|
20
|
+
*/
|
|
21
|
+
export declare function buildVerificationFailureResult(featureId: string, technicalDesign: string, verificationResult: ChecklistVerificationResult, iterations: number): TechnicalDesignResult;
|
|
22
|
+
/**
|
|
23
|
+
* Build error result when no design was generated
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildNoResultsError(featureId: string): TechnicalDesignResult;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build successful design result
|
|
3
|
+
*/
|
|
4
|
+
export function buildDesignResult(featureId, technicalDesign, summary, iterations, checklistItemResults) {
|
|
5
|
+
return {
|
|
6
|
+
featureId,
|
|
7
|
+
technicalDesign,
|
|
8
|
+
status: 'success',
|
|
9
|
+
summary,
|
|
10
|
+
iterations,
|
|
11
|
+
data: checklistItemResults
|
|
12
|
+
? { checklist_item_results: checklistItemResults }
|
|
13
|
+
: undefined,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Build verification failure result
|
|
18
|
+
*/
|
|
19
|
+
export function buildVerificationFailureResult(featureId, technicalDesign, verificationResult, iterations) {
|
|
20
|
+
return {
|
|
21
|
+
featureId,
|
|
22
|
+
technicalDesign,
|
|
23
|
+
status: 'error',
|
|
24
|
+
summary: `Checklist verification failed after ${iterations} iterations: ${verificationResult.summary}`,
|
|
25
|
+
verificationResult,
|
|
26
|
+
iterations,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build error result when no design was generated
|
|
31
|
+
*/
|
|
32
|
+
export function buildNoResultsError(featureId) {
|
|
33
|
+
return {
|
|
34
|
+
featureId,
|
|
35
|
+
technicalDesign: null,
|
|
36
|
+
status: 'error',
|
|
37
|
+
summary: 'Failed to generate technical design - no valid result received',
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { EdsgerConfig } from '../../types/index.js';
|
|
2
|
+
import { ChecklistPhaseContext } from '../../services/checklist.js';
|
|
3
|
+
export interface TechnicalDesignOptions {
|
|
4
|
+
featureId: string;
|
|
5
|
+
verbose?: boolean;
|
|
6
|
+
maxVerificationIterations?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface TechnicalDesignResult {
|
|
9
|
+
featureId: string;
|
|
10
|
+
technicalDesign: string | null;
|
|
11
|
+
status: 'success' | 'error';
|
|
12
|
+
summary: string;
|
|
13
|
+
verificationResult?: any;
|
|
14
|
+
iterations?: number;
|
|
15
|
+
savedViaHttp?: boolean;
|
|
16
|
+
data?: {
|
|
17
|
+
checklist_item_results?: any[];
|
|
18
|
+
[key: string]: any;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export declare const generateTechnicalDesign: (options: TechnicalDesignOptions, config: EdsgerConfig, checklistContext?: ChecklistPhaseContext | null) => Promise<TechnicalDesignResult>;
|