@getjack/jack 0.1.34 → 0.1.36
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 +6 -6
- package/package.json +1 -1
- package/src/commands/down.ts +39 -7
- package/src/commands/link.ts +2 -4
- package/src/commands/logs.ts +2 -4
- package/src/commands/mcp.ts +12 -10
- package/src/commands/services.ts +4 -2
- package/src/commands/sync.ts +5 -6
- package/src/commands/update.ts +1 -0
- package/src/index.ts +8 -0
- package/src/lib/auth/client.ts +5 -2
- package/src/lib/binding-validator.ts +39 -3
- package/src/lib/build-helper.ts +18 -19
- package/src/lib/control-plane.ts +45 -0
- package/src/lib/do-config.ts +110 -0
- package/src/lib/do-export-validator.ts +26 -0
- package/src/lib/jsonc-edit.ts +292 -0
- package/src/lib/managed-deploy.ts +36 -1
- package/src/lib/project-link.ts +37 -0
- package/src/lib/project-operations.ts +31 -66
- package/src/lib/resources.ts +4 -5
- package/src/lib/schema.ts +8 -12
- package/src/lib/services/db-create.ts +2 -2
- package/src/lib/services/db-execute.ts +9 -6
- package/src/lib/services/db-list.ts +6 -4
- package/src/lib/services/endpoint-test.ts +275 -0
- package/src/lib/services/project-delete.ts +190 -0
- package/src/lib/services/project-environment.ts +579 -0
- package/src/lib/services/storage-config.ts +7 -309
- package/src/lib/services/storage-create.ts +2 -1
- package/src/lib/services/storage-delete.ts +3 -2
- package/src/lib/services/storage-info.ts +2 -1
- package/src/lib/services/storage-list.ts +6 -3
- package/src/lib/services/vectorize-config.ts +7 -264
- package/src/lib/services/vectorize-create.ts +2 -1
- package/src/lib/services/vectorize-delete.ts +6 -4
- package/src/lib/services/vectorize-list.ts +6 -3
- package/src/lib/storage/index.ts +21 -23
- package/src/lib/telemetry.ts +1 -0
- package/src/lib/wrangler-config.ts +43 -312
- package/src/lib/zip-packager.ts +28 -0
- package/src/mcp/test-utils.ts +31 -0
- package/src/mcp/tools/index.ts +280 -2
- package/src/templates/index.ts +5 -0
- package/src/templates/types.ts +4 -0
- package/templates/AI-BINDINGS.md +34 -76
- package/templates/CLAUDE.md +1 -1
- package/templates/ai-chat/src/index.ts +7 -14
- package/templates/ai-chat/src/jack-ai.ts +0 -6
- package/templates/chat/.jack.json +45 -0
- package/templates/chat/bun.lock +1584 -0
- package/templates/chat/components.json +23 -0
- package/templates/chat/index.html +12 -0
- package/templates/chat/package.json +41 -0
- package/templates/chat/src/chat-agent.ts +63 -0
- package/templates/chat/src/client/app.tsx +189 -0
- package/templates/chat/src/client/chat.tsx +222 -0
- package/templates/chat/src/client/components/prompt-kit/chat-container.tsx +47 -0
- package/templates/chat/src/client/components/prompt-kit/loader.tsx +33 -0
- package/templates/chat/src/client/components/prompt-kit/markdown.tsx +84 -0
- package/templates/chat/src/client/components/prompt-kit/message.tsx +54 -0
- package/templates/chat/src/client/components/prompt-kit/prompt-suggestion.tsx +20 -0
- package/templates/chat/src/client/components/prompt-kit/reasoning.tsx +134 -0
- package/templates/chat/src/client/components/prompt-kit/scroll-button.tsx +28 -0
- package/templates/chat/src/client/components/ui/button.tsx +38 -0
- package/templates/chat/src/client/lib/utils.ts +6 -0
- package/templates/chat/src/client/main.tsx +11 -0
- package/templates/chat/src/client/styles.css +125 -0
- package/templates/chat/src/index.ts +25 -0
- package/templates/chat/src/jack-ai.ts +94 -0
- package/templates/chat/tsconfig.json +18 -0
- package/templates/chat/vite.config.ts +14 -0
- package/templates/chat/wrangler.jsonc +18 -0
- package/templates/cron/.jack.json +18 -28
- package/templates/cron/schema.sql +10 -20
- package/templates/cron/src/admin.ts +321 -0
- package/templates/cron/src/index.ts +151 -81
- package/templates/cron/src/monitor.ts +124 -0
- package/templates/semantic-search/src/index.ts +5 -43
- package/templates/semantic-search/src/jack-ai.ts +0 -6
- package/templates/telegram-bot/.jack.json +56 -0
- package/templates/telegram-bot/bun.lock +41 -0
- package/templates/telegram-bot/package.json +16 -0
- package/templates/telegram-bot/src/index.ts +236 -0
- package/templates/telegram-bot/src/jack-ai.ts +100 -0
- package/templates/telegram-bot/tsconfig.json +11 -0
- package/templates/telegram-bot/wrangler.jsonc +8 -0
- package/templates/cron/src/jobs.ts +0 -139
- package/templates/cron/src/webhooks.ts +0 -95
- package/templates/semantic-search/src/jack-vectorize.ts +0 -169
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Uses wrangler CLI to delete Vectorize indexes.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { join } from "node:path";
|
|
8
7
|
import { $ } from "bun";
|
|
8
|
+
import { findWranglerConfig } from "../wrangler-config.ts";
|
|
9
9
|
import { removeVectorizeBinding } from "./vectorize-config.ts";
|
|
10
10
|
|
|
11
11
|
export interface DeleteVectorizeResult {
|
|
@@ -42,9 +42,11 @@ export async function deleteVectorizeIndex(
|
|
|
42
42
|
// Delete via wrangler
|
|
43
43
|
await deleteIndexViaWrangler(indexName);
|
|
44
44
|
|
|
45
|
-
// Remove binding from wrangler
|
|
46
|
-
const wranglerPath =
|
|
47
|
-
const bindingRemoved =
|
|
45
|
+
// Remove binding from wrangler config
|
|
46
|
+
const wranglerPath = findWranglerConfig(projectDir);
|
|
47
|
+
const bindingRemoved = wranglerPath
|
|
48
|
+
? await removeVectorizeBinding(wranglerPath, indexName)
|
|
49
|
+
: false;
|
|
48
50
|
|
|
49
51
|
return {
|
|
50
52
|
indexName,
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Lists Vectorize indexes configured in wrangler.jsonc with their metadata.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { findWranglerConfig } from "../wrangler-config.ts";
|
|
8
8
|
import { getExistingVectorizeBindings } from "./vectorize-config.ts";
|
|
9
9
|
import { getVectorizeInfo } from "./vectorize-info.ts";
|
|
10
10
|
|
|
@@ -23,9 +23,12 @@ export interface VectorizeListEntry {
|
|
|
23
23
|
* (dimensions, metric, vector count) via wrangler vectorize info for each index.
|
|
24
24
|
*/
|
|
25
25
|
export async function listVectorizeIndexes(projectDir: string): Promise<VectorizeListEntry[]> {
|
|
26
|
-
const wranglerPath =
|
|
26
|
+
const wranglerPath = findWranglerConfig(projectDir);
|
|
27
|
+
if (!wranglerPath) {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
27
30
|
|
|
28
|
-
// Get existing Vectorize bindings from wrangler
|
|
31
|
+
// Get existing Vectorize bindings from wrangler config
|
|
29
32
|
const bindings = await getExistingVectorizeBindings(wranglerPath);
|
|
30
33
|
|
|
31
34
|
if (bindings.length === 0) {
|
package/src/lib/storage/index.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
6
6
|
import { dirname, join } from "node:path";
|
|
7
|
+
import { parseJsonc } from "../jsonc.ts";
|
|
8
|
+
import { findWranglerConfig } from "../wrangler-config.ts";
|
|
7
9
|
|
|
8
10
|
// Re-export submodules
|
|
9
11
|
export * from "./checksum.ts";
|
|
@@ -63,34 +65,30 @@ export interface CloudProject {
|
|
|
63
65
|
* @throws Error if wrangler file not found or name not found
|
|
64
66
|
*/
|
|
65
67
|
export async function getProjectNameFromDir(projectDir: string): Promise<string> {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if (match?.[1]) {
|
|
72
|
-
return match[1];
|
|
73
|
-
}
|
|
74
|
-
} catch {
|
|
75
|
-
// File doesn't exist, try JSON
|
|
68
|
+
const configPath = findWranglerConfig(projectDir);
|
|
69
|
+
if (!configPath) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
"Could not find project name. Please ensure wrangler.toml or wrangler.jsonc exists with a 'name' field",
|
|
72
|
+
);
|
|
76
73
|
}
|
|
77
74
|
|
|
78
|
-
// Try wrangler.jsonc
|
|
79
|
-
const jsoncPath = join(projectDir, "wrangler.jsonc");
|
|
80
75
|
try {
|
|
81
|
-
const content = await Bun.file(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
76
|
+
const content = await Bun.file(configPath).text();
|
|
77
|
+
|
|
78
|
+
if (configPath.endsWith(".toml")) {
|
|
79
|
+
const match = content.match(/^name\s*=\s*["']([^"']+)["']/m);
|
|
80
|
+
if (match?.[1]) {
|
|
81
|
+
return match[1];
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
// .jsonc or .json
|
|
85
|
+
const config = parseJsonc<{ name?: string }>(content);
|
|
86
|
+
if (config.name) {
|
|
87
|
+
return config.name;
|
|
88
|
+
}
|
|
91
89
|
}
|
|
92
90
|
} catch {
|
|
93
|
-
//
|
|
91
|
+
// Parse failed
|
|
94
92
|
}
|
|
95
93
|
|
|
96
94
|
throw new Error(
|
package/src/lib/telemetry.ts
CHANGED
|
@@ -17,6 +17,7 @@ export const Events = {
|
|
|
17
17
|
COMMAND_COMPLETED: "command_completed",
|
|
18
18
|
COMMAND_FAILED: "command_failed",
|
|
19
19
|
PROJECT_CREATED: "project_created",
|
|
20
|
+
PROJECT_DELETED: "project_deleted",
|
|
20
21
|
DEPLOY_STARTED: "deploy_started",
|
|
21
22
|
CONFIG_CHANGED: "config_changed",
|
|
22
23
|
INTENT_MATCHED: "intent_matched",
|
|
@@ -1,10 +1,51 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Utilities for
|
|
2
|
+
* Utilities for wrangler config detection and modification.
|
|
3
|
+
*
|
|
4
|
+
* All wrangler config path resolution should go through this module.
|
|
5
|
+
* Priority: .jsonc > .toml > .json (jsonc is jack's default)
|
|
3
6
|
*/
|
|
4
7
|
|
|
5
8
|
import { existsSync } from "node:fs";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import {
|
|
11
|
+
addSectionBeforeClosingBrace,
|
|
12
|
+
findLastObjectEndInArray,
|
|
13
|
+
findMatchingBracket,
|
|
14
|
+
isOnlyCommentsAndWhitespace,
|
|
15
|
+
shouldAddCommaBefore,
|
|
16
|
+
} from "./jsonc-edit.ts";
|
|
6
17
|
import { parseJsonc } from "./jsonc.ts";
|
|
7
18
|
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// Wrangler Config Path Resolution
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
/** Canonical priority order: jsonc (jack's default) > toml > json */
|
|
24
|
+
const WRANGLER_CONFIG_NAMES = ["wrangler.jsonc", "wrangler.toml", "wrangler.json"] as const;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Find the wrangler config file in a project directory.
|
|
28
|
+
* Returns the full absolute path, or null if none found.
|
|
29
|
+
*/
|
|
30
|
+
export function findWranglerConfig(projectDir: string): string | null {
|
|
31
|
+
for (const name of WRANGLER_CONFIG_NAMES) {
|
|
32
|
+
const fullPath = join(projectDir, name);
|
|
33
|
+
if (existsSync(fullPath)) return fullPath;
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Check whether a project directory has any wrangler config file.
|
|
40
|
+
*/
|
|
41
|
+
export function hasWranglerConfig(projectDir: string): boolean {
|
|
42
|
+
return findWranglerConfig(projectDir) !== null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ============================================================================
|
|
46
|
+
// D1 Binding Config
|
|
47
|
+
// ============================================================================
|
|
48
|
+
|
|
8
49
|
export interface D1BindingConfig {
|
|
9
50
|
binding: string; // e.g., "DB" or "ANALYTICS_DB"
|
|
10
51
|
database_name: string; // e.g., "my-app-db"
|
|
@@ -145,317 +186,7 @@ function appendToD1DatabasesArray(content: string, bindingJson: string): string
|
|
|
145
186
|
* Inserts before the final closing brace.
|
|
146
187
|
*/
|
|
147
188
|
function addD1DatabasesSection(content: string, bindingJson: string): string {
|
|
148
|
-
|
|
149
|
-
const lastBraceIndex = content.lastIndexOf("}");
|
|
150
|
-
if (lastBraceIndex === -1) {
|
|
151
|
-
throw new Error("Invalid JSON: no closing brace found");
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Check what comes before the last brace to determine if we need a comma
|
|
155
|
-
const beforeBrace = content.slice(0, lastBraceIndex);
|
|
156
|
-
const needsComma = shouldAddCommaBefore(beforeBrace);
|
|
157
|
-
|
|
158
|
-
// Build the d1_databases section
|
|
159
|
-
const d1Section = `"d1_databases": [
|
|
160
|
-
${bindingJson}
|
|
161
|
-
]`;
|
|
162
|
-
|
|
163
|
-
// Find proper insertion point - look for last non-whitespace content
|
|
164
|
-
const trimmedBefore = beforeBrace.trimEnd();
|
|
165
|
-
const whitespaceAfterContent = beforeBrace.slice(trimmedBefore.length);
|
|
166
|
-
|
|
167
|
-
let insertion: string;
|
|
168
|
-
if (needsComma) {
|
|
169
|
-
insertion = `,\n\t${d1Section}`;
|
|
170
|
-
} else {
|
|
171
|
-
insertion = `\n\t${d1Section}`;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Reconstruct: content before + insertion + newline + closing brace
|
|
175
|
-
return trimmedBefore + insertion + "\n" + content.slice(lastBraceIndex);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Find the matching closing bracket/brace for an opening one
|
|
180
|
-
*/
|
|
181
|
-
function findMatchingBracket(
|
|
182
|
-
content: string,
|
|
183
|
-
startIndex: number,
|
|
184
|
-
openChar: string,
|
|
185
|
-
closeChar: string,
|
|
186
|
-
): number {
|
|
187
|
-
let depth = 0;
|
|
188
|
-
let inString = false;
|
|
189
|
-
let stringChar = "";
|
|
190
|
-
let escaped = false;
|
|
191
|
-
let inLineComment = false;
|
|
192
|
-
let inBlockComment = false;
|
|
193
|
-
|
|
194
|
-
for (let i = startIndex; i < content.length; i++) {
|
|
195
|
-
const char = content[i] ?? "";
|
|
196
|
-
const next = content[i + 1] ?? "";
|
|
197
|
-
|
|
198
|
-
// Handle line comments
|
|
199
|
-
if (inLineComment) {
|
|
200
|
-
if (char === "\n") {
|
|
201
|
-
inLineComment = false;
|
|
202
|
-
}
|
|
203
|
-
continue;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Handle block comments
|
|
207
|
-
if (inBlockComment) {
|
|
208
|
-
if (char === "*" && next === "/") {
|
|
209
|
-
inBlockComment = false;
|
|
210
|
-
i++;
|
|
211
|
-
}
|
|
212
|
-
continue;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Handle strings
|
|
216
|
-
if (inString) {
|
|
217
|
-
if (escaped) {
|
|
218
|
-
escaped = false;
|
|
219
|
-
continue;
|
|
220
|
-
}
|
|
221
|
-
if (char === "\\") {
|
|
222
|
-
escaped = true;
|
|
223
|
-
continue;
|
|
224
|
-
}
|
|
225
|
-
if (char === stringChar) {
|
|
226
|
-
inString = false;
|
|
227
|
-
stringChar = "";
|
|
228
|
-
}
|
|
229
|
-
continue;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// Check for comment start
|
|
233
|
-
if (char === "/" && next === "/") {
|
|
234
|
-
inLineComment = true;
|
|
235
|
-
i++;
|
|
236
|
-
continue;
|
|
237
|
-
}
|
|
238
|
-
if (char === "/" && next === "*") {
|
|
239
|
-
inBlockComment = true;
|
|
240
|
-
i++;
|
|
241
|
-
continue;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// Check for string start
|
|
245
|
-
if (char === '"' || char === "'") {
|
|
246
|
-
inString = true;
|
|
247
|
-
stringChar = char;
|
|
248
|
-
continue;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// Track bracket depth
|
|
252
|
-
if (char === openChar) {
|
|
253
|
-
depth++;
|
|
254
|
-
} else if (char === closeChar) {
|
|
255
|
-
depth--;
|
|
256
|
-
if (depth === 0) {
|
|
257
|
-
return i;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
return -1;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Check if content is only whitespace and comments
|
|
267
|
-
*/
|
|
268
|
-
function isOnlyCommentsAndWhitespace(content: string): boolean {
|
|
269
|
-
let inLineComment = false;
|
|
270
|
-
let inBlockComment = false;
|
|
271
|
-
|
|
272
|
-
for (let i = 0; i < content.length; i++) {
|
|
273
|
-
const char = content[i] ?? "";
|
|
274
|
-
const next = content[i + 1] ?? "";
|
|
275
|
-
|
|
276
|
-
if (inLineComment) {
|
|
277
|
-
if (char === "\n") {
|
|
278
|
-
inLineComment = false;
|
|
279
|
-
}
|
|
280
|
-
continue;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
if (inBlockComment) {
|
|
284
|
-
if (char === "*" && next === "/") {
|
|
285
|
-
inBlockComment = false;
|
|
286
|
-
i++;
|
|
287
|
-
}
|
|
288
|
-
continue;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
if (char === "/" && next === "/") {
|
|
292
|
-
inLineComment = true;
|
|
293
|
-
i++;
|
|
294
|
-
continue;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
if (char === "/" && next === "*") {
|
|
298
|
-
inBlockComment = true;
|
|
299
|
-
i++;
|
|
300
|
-
continue;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
if (!/\s/.test(char)) {
|
|
304
|
-
return false;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
return true;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Find the last closing brace of an object within an array range
|
|
313
|
-
*/
|
|
314
|
-
function findLastObjectEndInArray(content: string, startIndex: number, endIndex: number): number {
|
|
315
|
-
let lastBraceIndex = -1;
|
|
316
|
-
let inString = false;
|
|
317
|
-
let stringChar = "";
|
|
318
|
-
let escaped = false;
|
|
319
|
-
let inLineComment = false;
|
|
320
|
-
let inBlockComment = false;
|
|
321
|
-
|
|
322
|
-
for (let i = startIndex; i < endIndex; i++) {
|
|
323
|
-
const char = content[i] ?? "";
|
|
324
|
-
const next = content[i + 1] ?? "";
|
|
325
|
-
|
|
326
|
-
if (inLineComment) {
|
|
327
|
-
if (char === "\n") {
|
|
328
|
-
inLineComment = false;
|
|
329
|
-
}
|
|
330
|
-
continue;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
if (inBlockComment) {
|
|
334
|
-
if (char === "*" && next === "/") {
|
|
335
|
-
inBlockComment = false;
|
|
336
|
-
i++;
|
|
337
|
-
}
|
|
338
|
-
continue;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
if (inString) {
|
|
342
|
-
if (escaped) {
|
|
343
|
-
escaped = false;
|
|
344
|
-
continue;
|
|
345
|
-
}
|
|
346
|
-
if (char === "\\") {
|
|
347
|
-
escaped = true;
|
|
348
|
-
continue;
|
|
349
|
-
}
|
|
350
|
-
if (char === stringChar) {
|
|
351
|
-
inString = false;
|
|
352
|
-
stringChar = "";
|
|
353
|
-
}
|
|
354
|
-
continue;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
if (char === "/" && next === "/") {
|
|
358
|
-
inLineComment = true;
|
|
359
|
-
i++;
|
|
360
|
-
continue;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
if (char === "/" && next === "*") {
|
|
364
|
-
inBlockComment = true;
|
|
365
|
-
i++;
|
|
366
|
-
continue;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
if (char === '"' || char === "'") {
|
|
370
|
-
inString = true;
|
|
371
|
-
stringChar = char;
|
|
372
|
-
continue;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
if (char === "}") {
|
|
376
|
-
lastBraceIndex = i;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
return lastBraceIndex;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
/**
|
|
384
|
-
* Determine if we need to add a comma before new content.
|
|
385
|
-
* Looks at the last non-whitespace, non-comment character.
|
|
386
|
-
*/
|
|
387
|
-
function shouldAddCommaBefore(content: string): boolean {
|
|
388
|
-
// Strip trailing comments and whitespace to find last meaningful char
|
|
389
|
-
let i = content.length - 1;
|
|
390
|
-
const inLineComment = false;
|
|
391
|
-
|
|
392
|
-
// First pass: find where any trailing line comment starts
|
|
393
|
-
for (let j = content.length - 1; j >= 0; j--) {
|
|
394
|
-
if (content[j] === "\n") {
|
|
395
|
-
// Check if there's a // comment on this line
|
|
396
|
-
const lineStart = content.lastIndexOf("\n", j - 1) + 1;
|
|
397
|
-
const line = content.slice(lineStart, j);
|
|
398
|
-
const commentIndex = findLineCommentStart(line);
|
|
399
|
-
if (commentIndex !== -1) {
|
|
400
|
-
i = lineStart + commentIndex - 1;
|
|
401
|
-
}
|
|
402
|
-
break;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
// Skip whitespace
|
|
407
|
-
while (i >= 0 && /\s/.test(content[i] ?? "")) {
|
|
408
|
-
i--;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
if (i < 0) return false;
|
|
412
|
-
|
|
413
|
-
const lastChar = content[i];
|
|
414
|
-
// Need comma if last char is }, ], ", number, or identifier char
|
|
415
|
-
// Don't need comma if last char is { or [ or ,
|
|
416
|
-
return lastChar !== "{" && lastChar !== "[" && lastChar !== ",";
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/**
|
|
420
|
-
* Find the start of a line comment (//) in a string, respecting strings
|
|
421
|
-
*/
|
|
422
|
-
function findLineCommentStart(line: string): number {
|
|
423
|
-
let inString = false;
|
|
424
|
-
let stringChar = "";
|
|
425
|
-
let escaped = false;
|
|
426
|
-
|
|
427
|
-
for (let i = 0; i < line.length - 1; i++) {
|
|
428
|
-
const char = line[i] ?? "";
|
|
429
|
-
const next = line[i + 1] ?? "";
|
|
430
|
-
|
|
431
|
-
if (inString) {
|
|
432
|
-
if (escaped) {
|
|
433
|
-
escaped = false;
|
|
434
|
-
continue;
|
|
435
|
-
}
|
|
436
|
-
if (char === "\\") {
|
|
437
|
-
escaped = true;
|
|
438
|
-
continue;
|
|
439
|
-
}
|
|
440
|
-
if (char === stringChar) {
|
|
441
|
-
inString = false;
|
|
442
|
-
stringChar = "";
|
|
443
|
-
}
|
|
444
|
-
continue;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
if (char === '"' || char === "'") {
|
|
448
|
-
inString = true;
|
|
449
|
-
stringChar = char;
|
|
450
|
-
continue;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
if (char === "/" && next === "/") {
|
|
454
|
-
return i;
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
return -1;
|
|
189
|
+
return addSectionBeforeClosingBrace(content, `"d1_databases": [\n\t\t${bindingJson}\n\t]`);
|
|
459
190
|
}
|
|
460
191
|
|
|
461
192
|
/**
|
package/src/lib/zip-packager.ts
CHANGED
|
@@ -51,7 +51,17 @@ export interface ManifestData {
|
|
|
51
51
|
dimensions?: number;
|
|
52
52
|
metric?: string;
|
|
53
53
|
}>;
|
|
54
|
+
durable_objects?: Array<{
|
|
55
|
+
binding: string;
|
|
56
|
+
class_name: string;
|
|
57
|
+
}>;
|
|
54
58
|
};
|
|
59
|
+
migrations?: Array<{
|
|
60
|
+
tag: string;
|
|
61
|
+
new_sqlite_classes?: string[];
|
|
62
|
+
deleted_classes?: string[];
|
|
63
|
+
renamed_classes?: Array<{ from: string; to: string }>;
|
|
64
|
+
}>;
|
|
55
65
|
}
|
|
56
66
|
|
|
57
67
|
export type ZipProgressCallback = (current: number, total: number) => void;
|
|
@@ -238,6 +248,14 @@ function extractBindingsFromConfig(config?: WranglerConfig): ManifestData["bindi
|
|
|
238
248
|
}));
|
|
239
249
|
}
|
|
240
250
|
|
|
251
|
+
// Extract Durable Object bindings
|
|
252
|
+
if (config?.durable_objects?.bindings && config.durable_objects.bindings.length > 0) {
|
|
253
|
+
bindings.durable_objects = config.durable_objects.bindings.map((dob) => ({
|
|
254
|
+
binding: dob.name,
|
|
255
|
+
class_name: dob.class_name,
|
|
256
|
+
}));
|
|
257
|
+
}
|
|
258
|
+
|
|
241
259
|
// Return undefined if no bindings were extracted
|
|
242
260
|
return Object.keys(bindings).length > 0 ? bindings : undefined;
|
|
243
261
|
}
|
|
@@ -305,6 +323,16 @@ export async function packageForDeploy(
|
|
|
305
323
|
bindings: extractBindingsFromConfig(config),
|
|
306
324
|
};
|
|
307
325
|
|
|
326
|
+
// Extract migrations (top-level, for DO support)
|
|
327
|
+
if (config?.migrations?.length) {
|
|
328
|
+
manifest.migrations = config.migrations.map((m) => ({
|
|
329
|
+
tag: m.tag,
|
|
330
|
+
new_sqlite_classes: m.new_sqlite_classes,
|
|
331
|
+
deleted_classes: m.deleted_classes,
|
|
332
|
+
renamed_classes: m.renamed_classes,
|
|
333
|
+
}));
|
|
334
|
+
}
|
|
335
|
+
|
|
308
336
|
await Bun.write(manifestPath, JSON.stringify(manifest, null, 2));
|
|
309
337
|
|
|
310
338
|
// 4. Check for optional files (schema.sql and .secrets.json)
|
package/src/mcp/test-utils.ts
CHANGED
|
@@ -156,3 +156,34 @@ export async function callMcpGetProjectStatus(
|
|
|
156
156
|
|
|
157
157
|
return parseMcpToolResult(response);
|
|
158
158
|
}
|
|
159
|
+
|
|
160
|
+
export async function callMcpGetProjectEnvironment(
|
|
161
|
+
client: Client,
|
|
162
|
+
args: { project_path?: string },
|
|
163
|
+
): Promise<unknown> {
|
|
164
|
+
const response = await client.callTool({
|
|
165
|
+
name: "get_project_environment",
|
|
166
|
+
arguments: args,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
return parseMcpToolResult(response);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export async function callMcpTestEndpoint(
|
|
173
|
+
client: Client,
|
|
174
|
+
args: {
|
|
175
|
+
project_path?: string;
|
|
176
|
+
path: string;
|
|
177
|
+
method?: string;
|
|
178
|
+
headers?: Record<string, string>;
|
|
179
|
+
body?: string;
|
|
180
|
+
include_logs?: boolean;
|
|
181
|
+
},
|
|
182
|
+
): Promise<unknown> {
|
|
183
|
+
const response = await client.callTool({
|
|
184
|
+
name: "test_endpoint",
|
|
185
|
+
arguments: args,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
return parseMcpToolResult(response);
|
|
189
|
+
}
|