edsger 0.35.0 → 0.35.2

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.
@@ -19,6 +19,7 @@ export interface AppStoreConfig {
19
19
  export interface AppStoreListing {
20
20
  app_name: string;
21
21
  subtitle?: string;
22
+ promotional_text?: string;
22
23
  short_description?: string;
23
24
  description: string;
24
25
  keywords?: string;
@@ -1,3 +1,5 @@
1
+ import { readFileSync, readdirSync } from 'node:fs';
2
+ import { join } from 'node:path';
1
3
  import { query } from '@anthropic-ai/claude-agent-sdk';
2
4
  import { DEFAULT_MODEL } from '../../constants.js';
3
5
  import { logDebug, logError, logInfo } from '../../utils/logger.js';
@@ -8,12 +10,33 @@ function parseAppStoreResult(responseText) {
8
10
  try {
9
11
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
12
  let jsonResult = null;
11
- // Try to extract JSON from markdown code block
12
- const jsonBlockMatch = responseText.match(/```json\s*\n([\s\S]*?)\n\s*```/);
13
- if (jsonBlockMatch) {
14
- jsonResult = JSON.parse(jsonBlockMatch[1]);
13
+ // Try to extract JSON from markdown code block (check all occurrences, prefer last)
14
+ const jsonBlockMatches = [...responseText.matchAll(/```json\s*\n([\s\S]*?)\n\s*```/g)];
15
+ for (let i = jsonBlockMatches.length - 1; i >= 0; i--) {
16
+ try {
17
+ const candidate = JSON.parse(jsonBlockMatches[i][1]);
18
+ if (candidate && candidate.app_store) {
19
+ jsonResult = candidate;
20
+ break;
21
+ }
22
+ }
23
+ catch {
24
+ // Try next match
25
+ }
15
26
  }
16
- else {
27
+ if (!jsonResult) {
28
+ // Try to find a JSON object containing "app_store" anywhere in the text
29
+ const appStoreMatch = responseText.match(/\{[\s\S]*"app_store"\s*:\s*\{[\s\S]*\}/);
30
+ if (appStoreMatch) {
31
+ try {
32
+ jsonResult = JSON.parse(appStoreMatch[0]);
33
+ }
34
+ catch {
35
+ // Not valid JSON
36
+ }
37
+ }
38
+ }
39
+ if (!jsonResult) {
17
40
  // Try to parse the entire response as JSON
18
41
  jsonResult = JSON.parse(responseText);
19
42
  }
@@ -80,8 +103,22 @@ export async function executeAppStoreQuery(currentPrompt, systemPrompt, config,
80
103
  const responseText = message.result || lastAssistantResponse;
81
104
  const parsed = parseAppStoreResult(responseText);
82
105
  if (parsed.error) {
83
- logError(`Failed to parse result: ${parsed.error}`);
84
- structuredResult = null;
106
+ // Fallback: try accumulated assistant responses (may contain JSON code blocks)
107
+ if (lastAssistantResponse && responseText !== lastAssistantResponse) {
108
+ const fallback = parseAppStoreResult(lastAssistantResponse);
109
+ if (!fallback.error) {
110
+ logInfo('Parsed result from accumulated responses');
111
+ structuredResult = fallback.appStore;
112
+ }
113
+ else {
114
+ logError(`Failed to parse result: ${parsed.error}`);
115
+ structuredResult = null;
116
+ }
117
+ }
118
+ else {
119
+ logError(`Failed to parse result: ${parsed.error}`);
120
+ structuredResult = null;
121
+ }
85
122
  }
86
123
  else {
87
124
  structuredResult = parsed.appStore;
@@ -98,5 +135,36 @@ export async function executeAppStoreQuery(currentPrompt, systemPrompt, config,
98
135
  }
99
136
  }
100
137
  }
138
+ // File-based fallback: the agent may have written JSON to a file in the cwd
139
+ if (!structuredResult && cwd) {
140
+ structuredResult = tryParseJsonFilesInDir(cwd);
141
+ if (structuredResult) {
142
+ logInfo('Parsed result from JSON file written by agent');
143
+ }
144
+ }
101
145
  return structuredResult;
102
146
  }
147
+ /**
148
+ * Search for JSON files in the given directory that contain an app_store key.
149
+ */
150
+ function tryParseJsonFilesInDir(dir) {
151
+ try {
152
+ const files = readdirSync(dir).filter((f) => f.endsWith('.json'));
153
+ for (const file of files) {
154
+ try {
155
+ const content = readFileSync(join(dir, file), 'utf-8');
156
+ const parsed = parseAppStoreResult(content);
157
+ if (!parsed.error && parsed.appStore) {
158
+ return parsed.appStore;
159
+ }
160
+ }
161
+ catch {
162
+ // Skip unreadable files
163
+ }
164
+ }
165
+ }
166
+ catch {
167
+ // Directory not readable
168
+ }
169
+ return null;
170
+ }
@@ -42,6 +42,7 @@ ${hasCodebase ? '5' : '4'}. **Write Store Listings**: Generate optimized app nam
42
42
  **Store Listing Standards**:
43
43
  - App name: max 30 characters, compelling and searchable
44
44
  - Subtitle: max 30 characters (Apple), punchy value proposition
45
+ - Promotional text: max 170 characters (Apple), highlights current promotions or features — can be updated without a new app version
45
46
  - Short description: max 80 characters (Google Play)
46
47
  - Description: max 4000 characters, benefit-focused with feature bullets
47
48
  - Keywords: max 100 characters (Apple), comma-separated, no spaces after commas
@@ -59,6 +60,7 @@ Return ONLY a JSON object. No text before or after.
59
60
  "en-US": {
60
61
  "app_name": "Product Name",
61
62
  "subtitle": "Short value proposition",
63
+ "promotional_text": "Highlight a current promotion, new feature, or seasonal message (170 chars max)",
62
64
  "short_description": "One-liner for Google Play (80 chars max)",
63
65
  "description": "Full store description with features and benefits",
64
66
  "keywords": "keyword1,keyword2,keyword3",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edsger",
3
- "version": "0.35.0",
3
+ "version": "0.35.2",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "edsger": "dist/index.js"