edsger 0.35.1 → 0.35.3
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.
|
@@ -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
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
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
|
-
|
|
84
|
-
|
|
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
|
+
}
|
|
@@ -53,8 +53,25 @@ export const generateAppStoreAssets = async (options, config
|
|
|
53
53
|
if (!aiResult) {
|
|
54
54
|
throw new Error('No results received from AI');
|
|
55
55
|
}
|
|
56
|
-
const
|
|
56
|
+
const rawListings = (aiResult.listings ||
|
|
57
57
|
{});
|
|
58
|
+
// Enforce Apple field limits on AI-generated content
|
|
59
|
+
const listings = {};
|
|
60
|
+
for (const [loc, listing] of Object.entries(rawListings)) {
|
|
61
|
+
listings[loc] = {
|
|
62
|
+
...listing,
|
|
63
|
+
app_name: listing.app_name?.slice(0, 30) ?? '',
|
|
64
|
+
subtitle: listing.subtitle?.slice(0, 30),
|
|
65
|
+
promotional_text: listing.promotional_text?.slice(0, 170),
|
|
66
|
+
short_description: listing.short_description?.slice(0, 80),
|
|
67
|
+
description: listing.description?.slice(0, 4000) ?? '',
|
|
68
|
+
keywords: listing.keywords
|
|
69
|
+
? listing.keywords.length > 100
|
|
70
|
+
? listing.keywords.slice(0, 100).replace(/,[^,]*$/, '')
|
|
71
|
+
: listing.keywords
|
|
72
|
+
: undefined,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
58
75
|
const screenshotSpecs = (aiResult.screenshots || []);
|
|
59
76
|
logInfo(`AI generated: ${Object.keys(listings).length} locale(s), ${screenshotSpecs.length} screenshot spec(s)`);
|
|
60
77
|
// Ensure store configs exist
|