@wix/ditto-codegen-public 1.0.327 → 1.0.329
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/dist/opencode-tools/multi-edit.ts +62 -0
- package/dist/out.js +65 -21
- package/package.json +2 -2
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { tool } from "@opencode-ai/plugin";
|
|
2
|
+
import { readFile, writeFile } from "fs/promises";
|
|
3
|
+
import { join, isAbsolute } from "path";
|
|
4
|
+
|
|
5
|
+
export default tool({
|
|
6
|
+
description:
|
|
7
|
+
"Apply multiple find-and-replace edits across one or more files in a single call. " +
|
|
8
|
+
"Use this instead of calling edit multiple times. Each edit replaces oldString with newString " +
|
|
9
|
+
"in the named file. If oldString appears more than once and replaceAll is false, the edit fails — " +
|
|
10
|
+
"include more context in oldString to make it unique, or set replaceAll: true.",
|
|
11
|
+
args: {
|
|
12
|
+
edits: tool.schema
|
|
13
|
+
.array(
|
|
14
|
+
tool.schema.object({
|
|
15
|
+
path: tool.schema
|
|
16
|
+
.string()
|
|
17
|
+
.describe("File path relative to project root"),
|
|
18
|
+
oldString: tool.schema
|
|
19
|
+
.string()
|
|
20
|
+
.min(1)
|
|
21
|
+
.describe("Exact string to find. Must be unique unless replaceAll is true."),
|
|
22
|
+
newString: tool.schema.string().describe("Replacement string"),
|
|
23
|
+
replaceAll: tool.schema
|
|
24
|
+
.boolean()
|
|
25
|
+
.optional()
|
|
26
|
+
.describe("Replace every occurrence (default: false)"),
|
|
27
|
+
}),
|
|
28
|
+
)
|
|
29
|
+
.describe("Array of edits to apply in order"),
|
|
30
|
+
},
|
|
31
|
+
async execute(args, context) {
|
|
32
|
+
const results: string[] = [];
|
|
33
|
+
for (const e of args.edits) {
|
|
34
|
+
const fullPath = isAbsolute(e.path)
|
|
35
|
+
? e.path
|
|
36
|
+
: join(context.directory, e.path);
|
|
37
|
+
try {
|
|
38
|
+
const content = await readFile(fullPath, "utf-8");
|
|
39
|
+
const occurrences = content.split(e.oldString).length - 1;
|
|
40
|
+
if (occurrences === 0) {
|
|
41
|
+
results.push(`FAILED: ${e.path} - oldString not found`);
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (occurrences > 1 && !e.replaceAll) {
|
|
45
|
+
results.push(
|
|
46
|
+
`FAILED: ${e.path} - oldString appears ${occurrences} times; pass replaceAll: true or include more surrounding context`,
|
|
47
|
+
);
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
const updated = e.replaceAll
|
|
51
|
+
? content.split(e.oldString).join(e.newString)
|
|
52
|
+
: content.replace(e.oldString, e.newString);
|
|
53
|
+
await writeFile(fullPath, updated, "utf-8");
|
|
54
|
+
results.push(`OK: ${e.path}`);
|
|
55
|
+
} catch (err) {
|
|
56
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
57
|
+
results.push(`FAILED: ${e.path} - ${msg}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return results.join("\n");
|
|
61
|
+
},
|
|
62
|
+
});
|
package/dist/out.js
CHANGED
|
@@ -11701,7 +11701,8 @@ var require_constants5 = __commonJS({
|
|
|
11701
11701
|
exports2.WRITE_TOOLS = /* @__PURE__ */ new Set([
|
|
11702
11702
|
"write",
|
|
11703
11703
|
"edit",
|
|
11704
|
-
"batch-write"
|
|
11704
|
+
"batch-write",
|
|
11705
|
+
"multi-edit"
|
|
11705
11706
|
]);
|
|
11706
11707
|
exports2.BUILDER_TO_EXTENSION_LABEL = {
|
|
11707
11708
|
dashboardPage: "dashboard page",
|
|
@@ -11867,23 +11868,25 @@ MINIMIZE TEXT OUTPUT \u2014 CRITICAL:
|
|
|
11867
11868
|
TOOL USAGE:
|
|
11868
11869
|
- \`validate\` for all validation (tsc + build).
|
|
11869
11870
|
- \`uuid\` to generate UUIDs (supports count param for multiple). Do NOT use bash.
|
|
11870
|
-
-
|
|
11871
|
-
- \`batch-
|
|
11872
|
-
- \`
|
|
11871
|
+
- File operations \u2014 pick the BATCH tool whenever you have 2+ files; the single-file variants are 5\u201310\xD7 slower:
|
|
11872
|
+
- \`batch-write\` to create N new files in one call. NEVER call \`write\` more than once per turn \u2014 use batch-write instead. \`write\` is reserved for single-file creation.
|
|
11873
|
+
- \`batch-read\` to read N files in one call. NEVER call \`read\` more than once per turn \u2014 use batch-read instead.
|
|
11874
|
+
- \`multi-edit\` to apply N find-and-replace edits across one or more files in one call. NEVER call \`edit\` more than once per turn \u2014 use multi-edit instead. \`edit\` is reserved for a single edit to one file.
|
|
11875
|
+
- For tools where no batch variant exists (e.g. \`grep\`, \`glob\`), still emit MULTIPLE \`tool_use\` blocks in a SINGLE response when the calls are independent. Sequential turns waste a model round-trip per call.
|
|
11873
11876
|
- Before calling MCP tools, check if loaded skills already cover the API. Only use MCP for gaps.
|
|
11874
11877
|
- When using MCP to look up a Wix SDK method, ALWAYS call \`ReadFullDocsMethodSchema\` (not just \`ReadFullDocsArticle\`). The schema is the source of truth for parameter shapes. Code examples in docs may use incorrect call signatures.
|
|
11875
11878
|
- NEVER run preview, dev, release, or promote commands.
|
|
11876
11879
|
|
|
11877
11880
|
IMPLEMENTATION WORKFLOW:
|
|
11878
11881
|
1. **Plan**: Determine extension types using the \`wix-app\` skill. Generate ALL UUIDs upfront.
|
|
11879
|
-
2. **Build**: Create
|
|
11882
|
+
2. **Build**: Create every extension file in a SINGLE \`batch-write\` call. Build all extensions before registering.
|
|
11880
11883
|
3. **Register**: Register all extensions in \`src/extensions.ts\`.
|
|
11881
11884
|
4. **Validate**: Run \`validate\` (typecheck only). Fix any errors and re-validate until tsc passes. Then run \`validate({ runBuild: true })\` ONCE to verify the build. Pass \`installDeps: true\` ONLY when you added a new dependency to package.json in this iteration; otherwise omit it (node_modules is pre-installed).
|
|
11882
11885
|
5. **Stop**: Once validation passes, STOP. Do NOT refactor, clean up, or verify.
|
|
11883
11886
|
|
|
11884
11887
|
EFFICIENCY:
|
|
11885
|
-
-
|
|
11886
|
-
-
|
|
11888
|
+
- Always prefer the BATCH variant: \`batch-write\` over multiple \`write\`s, \`batch-read\` over multiple \`read\`s, \`multi-edit\` over multiple \`edit\`s.
|
|
11889
|
+
- When fixing type errors across N files, use ONE \`multi-edit\` call with all N edits.
|
|
11887
11890
|
|
|
11888
11891
|
FILE CREATION:
|
|
11889
11892
|
- NEVER rewrite the same file twice. Once written, move on.
|
|
@@ -13027,6 +13030,10 @@ var require_config = __commonJS({
|
|
|
13027
13030
|
"batch-write"
|
|
13028
13031
|
/* OpenCodeTool.BatchWrite */
|
|
13029
13032
|
]: "deny",
|
|
13033
|
+
[
|
|
13034
|
+
"multi-edit"
|
|
13035
|
+
/* OpenCodeTool.MultiEdit */
|
|
13036
|
+
]: "deny",
|
|
13030
13037
|
[
|
|
13031
13038
|
"validate"
|
|
13032
13039
|
/* OpenCodeTool.Validate */
|
|
@@ -13148,6 +13155,16 @@ var require_parser = __commonJS({
|
|
|
13148
13155
|
}
|
|
13149
13156
|
const tool = event.part.tool;
|
|
13150
13157
|
const metadata = event.part.state.metadata;
|
|
13158
|
+
if (tool === "batch-write") {
|
|
13159
|
+
for (const f of event.part.state.input?.files ?? []) {
|
|
13160
|
+
addFileChange(f.path, ditto_codegen_types_12.ExtensionGenerationOperation.INSERT);
|
|
13161
|
+
}
|
|
13162
|
+
}
|
|
13163
|
+
if (tool === "multi-edit") {
|
|
13164
|
+
for (const e of event.part.state.input?.edits ?? []) {
|
|
13165
|
+
addFileChange(e.path, ditto_codegen_types_12.ExtensionGenerationOperation.EDIT);
|
|
13166
|
+
}
|
|
13167
|
+
}
|
|
13151
13168
|
const operation = (0, constants_1.resolveFileOperation)(tool, metadata);
|
|
13152
13169
|
if (operation) {
|
|
13153
13170
|
const filePath = event.part.state.input?.filePath;
|
|
@@ -13259,6 +13276,9 @@ var require_parser = __commonJS({
|
|
|
13259
13276
|
if (input.files) {
|
|
13260
13277
|
return { files: input.files.map(({ path }) => ({ path })) };
|
|
13261
13278
|
}
|
|
13279
|
+
if (input.edits) {
|
|
13280
|
+
return { edits: input.edits.map(({ path }) => ({ path })) };
|
|
13281
|
+
}
|
|
13262
13282
|
if (input.filePath)
|
|
13263
13283
|
return { filePath: input.filePath };
|
|
13264
13284
|
return {
|
|
@@ -13369,7 +13389,8 @@ var require_extension_handler = __commonJS({
|
|
|
13369
13389
|
files: extensionFiles.map((f) => ({
|
|
13370
13390
|
path: f.path,
|
|
13371
13391
|
operation: f.operation
|
|
13372
|
-
}))
|
|
13392
|
+
})),
|
|
13393
|
+
extensionType: tracked.extensionType
|
|
13373
13394
|
}
|
|
13374
13395
|
};
|
|
13375
13396
|
}
|
|
@@ -13399,7 +13420,7 @@ var require_extension_handler = __commonJS({
|
|
|
13399
13420
|
if (!this.extensionTypesByPath.has(normalizedPath)) {
|
|
13400
13421
|
this.extensionTypesByPath.set(normalizedPath, extension.extensionType);
|
|
13401
13422
|
await (0, init_task_1.completeInitTask)(ctx);
|
|
13402
|
-
await this.createExtensionTask(normalizedPath, extension.label, filePath, ctx);
|
|
13423
|
+
await this.createExtensionTask(normalizedPath, extension.label, extension.extensionType, filePath, ctx);
|
|
13403
13424
|
}
|
|
13404
13425
|
if (!isCompleted)
|
|
13405
13426
|
return;
|
|
@@ -13433,12 +13454,12 @@ var require_extension_handler = __commonJS({
|
|
|
13433
13454
|
}
|
|
13434
13455
|
}
|
|
13435
13456
|
/** Registers a RUNNING sub-task in the job service for a detected extension. */
|
|
13436
|
-
async createExtensionTask(normalizedPath, extensionType, originalPath, ctx) {
|
|
13457
|
+
async createExtensionTask(normalizedPath, extensionLabel, extensionType, originalPath, ctx) {
|
|
13437
13458
|
const jobContext = ctx.getJobContext();
|
|
13438
13459
|
if (!jobContext)
|
|
13439
13460
|
return;
|
|
13440
13461
|
const extensionName = (0, constants_1.extractExtensionName)(originalPath);
|
|
13441
|
-
const description = `Creating ${extensionName} ${
|
|
13462
|
+
const description = `Creating ${extensionName} ${extensionLabel}`;
|
|
13442
13463
|
const extensionKey = `ext-${normalizedPath}`;
|
|
13443
13464
|
const taskId = (0, crypto_12.randomUUID)();
|
|
13444
13465
|
const extensionFolder = normalizedPath.substring(0, normalizedPath.lastIndexOf("/") + 1);
|
|
@@ -13446,7 +13467,8 @@ var require_extension_handler = __commonJS({
|
|
|
13446
13467
|
taskId,
|
|
13447
13468
|
description,
|
|
13448
13469
|
status: ditto_codegen_types_12.Status.RUNNING,
|
|
13449
|
-
extensionFolder
|
|
13470
|
+
extensionFolder,
|
|
13471
|
+
extensionType
|
|
13450
13472
|
};
|
|
13451
13473
|
ctx.trackedTasks.set(extensionKey, tracked);
|
|
13452
13474
|
try {
|
|
@@ -13675,9 +13697,8 @@ var require_task_tracker = __commonJS({
|
|
|
13675
13697
|
}
|
|
13676
13698
|
async handleWriteEvent(tool, state) {
|
|
13677
13699
|
const isCompleted = state.status === "completed";
|
|
13678
|
-
const
|
|
13679
|
-
const
|
|
13680
|
-
for (const fileState of fileStates) {
|
|
13700
|
+
const expanded = this.expandWriteEvent(tool, state);
|
|
13701
|
+
for (const { state: fileState, effectiveTool } of expanded) {
|
|
13681
13702
|
if (isCompleted) {
|
|
13682
13703
|
this.trackFileChange(effectiveTool, fileState);
|
|
13683
13704
|
}
|
|
@@ -13685,12 +13706,35 @@ var require_task_tracker = __commonJS({
|
|
|
13685
13706
|
await this.extensionHandler.handle(effectiveTool, fileState, ctx);
|
|
13686
13707
|
}
|
|
13687
13708
|
}
|
|
13688
|
-
|
|
13689
|
-
|
|
13690
|
-
|
|
13691
|
-
|
|
13692
|
-
|
|
13693
|
-
|
|
13709
|
+
/**
|
|
13710
|
+
* Expands a write-family tool event into per-file synthetic states so the
|
|
13711
|
+
* downstream extension/file-change collectors can stay tool-agnostic:
|
|
13712
|
+
* batch-write → N synthetic Write states (INSERT, exists=false)
|
|
13713
|
+
* multi-edit → N synthetic Edit states (EDIT)
|
|
13714
|
+
* write/edit → passed through unchanged
|
|
13715
|
+
*/
|
|
13716
|
+
expandWriteEvent(tool, state) {
|
|
13717
|
+
if (tool === "batch-write") {
|
|
13718
|
+
return (state.input?.files ?? []).map((f) => ({
|
|
13719
|
+
state: {
|
|
13720
|
+
status: state.status,
|
|
13721
|
+
input: { filePath: f.path, content: f.content },
|
|
13722
|
+
metadata: { exists: false }
|
|
13723
|
+
},
|
|
13724
|
+
effectiveTool: "write"
|
|
13725
|
+
}));
|
|
13726
|
+
}
|
|
13727
|
+
if (tool === "multi-edit") {
|
|
13728
|
+
return (state.input?.edits ?? []).map((e) => ({
|
|
13729
|
+
state: {
|
|
13730
|
+
status: state.status,
|
|
13731
|
+
input: { filePath: e.path, new_string: e.newString },
|
|
13732
|
+
metadata: { exists: true }
|
|
13733
|
+
},
|
|
13734
|
+
effectiveTool: "edit"
|
|
13735
|
+
}));
|
|
13736
|
+
}
|
|
13737
|
+
return [{ state, effectiveTool: tool }];
|
|
13694
13738
|
}
|
|
13695
13739
|
trackFileChange(tool, state) {
|
|
13696
13740
|
const filePath = state.input?.filePath || state.title;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/ditto-codegen-public",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.329",
|
|
4
4
|
"description": "AI-powered Wix CLI app generator - standalone executable",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "node build.mjs",
|
|
@@ -28,5 +28,5 @@
|
|
|
28
28
|
"esbuild": "^0.27.2",
|
|
29
29
|
"vitest": "^4.0.16"
|
|
30
30
|
},
|
|
31
|
-
"falconPackageHash": "
|
|
31
|
+
"falconPackageHash": "27be60515add05720642903acc4d87771920b49663a972e4bc664868"
|
|
32
32
|
}
|