@wix/ditto-codegen-public 1.0.366 → 1.0.368

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,7 +1,21 @@
1
1
  import { tool } from "@opencode-ai/plugin";
2
- import { writeFile, mkdir } from "fs/promises";
2
+ import { writeFile, mkdir, stat } from "fs/promises";
3
3
  import { join, dirname, isAbsolute } from "path";
4
4
 
5
+ // Overwriting a non-trivial existing file re-emits the whole file (slow/costly);
6
+ // such edits must use multi-edit. Smaller files are scaffolding stubs (allowed).
7
+ const EXISTING_FILE_REWRITE_GUARD_BYTES = 2048;
8
+
9
+ // Size of an existing regular file, or null if absent/not a file (a fresh create).
10
+ async function existingFileSize(path: string): Promise<number | null> {
11
+ try {
12
+ const s = await stat(path);
13
+ return s.isFile() ? s.size : null;
14
+ } catch {
15
+ return null;
16
+ }
17
+ }
18
+
5
19
  function unescapeString(str: string): string {
6
20
  return str.replace(/\\(n|t|r|"|\\)/g, (_, c: string) => {
7
21
  if (c === "n") return "\n";
@@ -18,8 +32,8 @@ function normalizeToolString(text: string): string {
18
32
 
19
33
  export default tool({
20
34
  description:
21
- "Write multiple files at once. Creates directories as needed. " +
22
- "Use this instead of calling write/edit multiple times for new files.",
35
+ "Write multiple new files in one call (creates dirs). " +
36
+ "For an existing file, use multi-edit instead; batch-write rejects overwriting a non-trivial existing file.",
23
37
  args: {
24
38
  files: tool.schema
25
39
  .array(
@@ -39,6 +53,16 @@ export default tool({
39
53
  ? f.path
40
54
  : join(context.directory, f.path);
41
55
  try {
56
+ const existingSize = await existingFileSize(fullPath);
57
+ if (
58
+ existingSize !== null &&
59
+ existingSize > EXISTING_FILE_REWRITE_GUARD_BYTES
60
+ ) {
61
+ results.push(
62
+ `BLOCKED: ${f.path} exists; use multi-edit to change existing files.`,
63
+ );
64
+ continue;
65
+ }
42
66
  await mkdir(dirname(fullPath), { recursive: true });
43
67
  const content =
44
68
  typeof f.content === "string"
package/dist/out.js CHANGED
@@ -11246,7 +11246,7 @@ ${(0, prompt_utils_1.formatChatHistory)(recentHistory, "CONVERSATION CONTEXT")}
11246
11246
  INSTRUCTIONS:
11247
11247
  1. Read the latest user request carefully
11248
11248
  2. If it asks to CREATE something new, create it as a new extension using skills
11249
- 3. If it asks to MODIFY existing code, make those specific changes
11249
+ 3. If it asks to MODIFY existing code, edit only what is needed with \`multi-edit\`; never rewrite a whole file.
11250
11250
  4. Do NOT ignore the user's request or substitute your own interpretation`;
11251
11251
  }
11252
11252
  function buildIterationPrompt(chatHistory) {
@@ -11498,6 +11498,67 @@ var require_rules_writer = __commonJS({
11498
11498
  }
11499
11499
  });
11500
11500
 
11501
+ // dist/opencode-integration/node-modules-guard.js
11502
+ var require_node_modules_guard = __commonJS({
11503
+ "dist/opencode-integration/node-modules-guard.js"(exports2) {
11504
+ "use strict";
11505
+ Object.defineProperty(exports2, "__esModule", { value: true });
11506
+ exports2.GUARD_PLUGIN_PATH = exports2.GUARD_MESSAGE = exports2.MAX_SPELUNK_CALLS = void 0;
11507
+ exports2.isSpelunkCommand = isSpelunkCommand;
11508
+ exports2.buildGuardPluginSource = buildGuardPluginSource;
11509
+ exports2.writeGuardPlugin = writeGuardPlugin;
11510
+ var promises_1 = require("fs/promises");
11511
+ var os_1 = require("os");
11512
+ var path_1 = require("path");
11513
+ var logger_12 = require_logger();
11514
+ var READ_VERB_RE = /(^|[\s|;&(])(grep|rg|cat|head|tail|sed|awk|less|more|strings|find)\b/;
11515
+ var SDK_INTERNALS_RE = /node_modules\/(@wix|vite|astro)\b/;
11516
+ exports2.MAX_SPELUNK_CALLS = 2;
11517
+ exports2.GUARD_MESSAGE = `BLOCKED: node_modules is not a documentation source, and the exploratory budget (${exports2.MAX_SPELUNK_CALLS} lookups) is used up. The API you are hunting is already documented:
11518
+ - Wix Data items CRUD: import { items } from "@wix/data" (items.query/get/insert/update/remove).
11519
+ - Dashboard host SDK (toasts, navigation): import { dashboard } from "@wix/dashboard".
11520
+ For anything more (CSS-module/asset typing, component config, etc.), re-read the wix-app skill's references with batch-read, or call SearchWixSDKDocumentation / ReadFullDocsMethodSchema. Do not retry this command.`;
11521
+ function isSpelunkCommand(command) {
11522
+ return READ_VERB_RE.test(command) && SDK_INTERNALS_RE.test(command);
11523
+ }
11524
+ var GLOBAL_PLUGIN_DIR = (0, path_1.join)((0, os_1.homedir)(), ".config", "opencode", "plugin");
11525
+ var GUARD_PLUGIN_FILENAME = "node-modules-guard.ts";
11526
+ exports2.GUARD_PLUGIN_PATH = (0, path_1.join)(GLOBAL_PLUGIN_DIR, GUARD_PLUGIN_FILENAME);
11527
+ function buildGuardPluginSource() {
11528
+ return `// Generated by @wix/ditto-codegen (node-modules-guard) \u2014 do not edit.
11529
+ const READ_VERB_RE = /${READ_VERB_RE.source}/;
11530
+ const SDK_INTERNALS_RE = /${SDK_INTERNALS_RE.source}/;
11531
+ const MAX_SPELUNK_CALLS = ${exports2.MAX_SPELUNK_CALLS};
11532
+ const GUARD_MESSAGE = ${JSON.stringify(exports2.GUARD_MESSAGE)};
11533
+
11534
+ let spelunkCalls = 0;
11535
+
11536
+ export const NodeModulesGuard = async () => ({
11537
+ "tool.execute.before": async (
11538
+ input: { tool: string },
11539
+ output: { args: { command?: string } },
11540
+ ) => {
11541
+ if (input.tool !== "bash") return;
11542
+ const command = output.args?.command ?? "";
11543
+ if (!READ_VERB_RE.test(command) || !SDK_INTERNALS_RE.test(command)) return;
11544
+ spelunkCalls += 1;
11545
+ if (spelunkCalls > MAX_SPELUNK_CALLS) {
11546
+ throw new Error(GUARD_MESSAGE);
11547
+ }
11548
+ },
11549
+ });
11550
+ `;
11551
+ }
11552
+ async function writeGuardPlugin() {
11553
+ await (0, promises_1.mkdir)(GLOBAL_PLUGIN_DIR, { recursive: true });
11554
+ await (0, promises_1.writeFile)(exports2.GUARD_PLUGIN_PATH, buildGuardPluginSource(), "utf-8");
11555
+ logger_12.logger.info("[OpenCode] Wrote node_modules guard plugin", {
11556
+ path: exports2.GUARD_PLUGIN_PATH
11557
+ });
11558
+ }
11559
+ }
11560
+ });
11561
+
11501
11562
  // ../../node_modules/@wix/ambassador-ctp-ditto-v1-blueprint/cjs/build/types.impl.js
11502
11563
  var require_types_impl2 = __commonJS({
11503
11564
  "../../node_modules/@wix/ambassador-ctp-ditto-v1-blueprint/cjs/build/types.impl.js"(exports2) {
@@ -13476,9 +13537,13 @@ TOOL USAGE:
13476
13537
  - 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.
13477
13538
  - Before calling MCP tools, check if loaded skills already cover the API. Only use MCP for gaps.
13478
13539
  - 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.
13479
- - To discover API shapes, method signatures, or type definitions: ALWAYS try \`SearchWixSDKDocumentation\` or \`ReadFullDocsMethodSchema\` via wix-mcp first. ONLY fall back to grepping \`node_modules\` if the MCP tools return no useful results. Grepping \`node_modules\` as a first resort wastes turns, inflates context, and produces unreliable results \u2014 SDK internals are not a documentation source.
13540
+ - To discover API shapes, method signatures, or type definitions: ALWAYS try \`SearchWixSDKDocumentation\` or \`ReadFullDocsMethodSchema\` via wix-mcp first. ONLY fall back to grepping \`node_modules\` if the MCP tools return no useful results. Grepping \`node_modules\` as a first resort wastes turns, inflates context, and produces unreliable results \u2014 SDK internals are not a documentation source. ENFORCED: after 2 such lookups, further bash inspection of \`node_modules\` Wix/vite/astro internals is rejected.
13480
13541
  - NEVER run preview, dev, release, or promote commands.
13481
13542
 
13543
+ KNOWN WIX APIS (already documented \u2014 do NOT rediscover these from node_modules; for full detail consult the \`wix-app\` skill's references or \`ReadFullDocsMethodSchema\`):
13544
+ - Wix Data items CRUD: \`import { items } from "@wix/data"\` \u2014 \`items.query(collectionId)\`, \`items.get\`, \`items.insert\`, \`items.update\` (replaces the WHOLE item \u2014 send all fields), \`items.remove\`.
13545
+ - Dashboard host SDK (toasts, navigation, modals): \`import { dashboard } from "@wix/dashboard"\`.
13546
+
13482
13547
  IMPLEMENTATION WORKFLOW:
13483
13548
  1. **Plan**: Determine extension types using the \`wix-app\` skill. Generate ALL UUIDs upfront. Include a \`progress\` call (e.g. "Planning extensions").
13484
13549
  2. **Research**: Load relevant SDK docs and skills for each extension type. Include a \`progress\` call (e.g. "Reading documentation").
@@ -13730,6 +13795,7 @@ var require_config = __commonJS({
13730
13795
  var constants_1 = require_constants5();
13731
13796
  var experiments_1 = require_experiments();
13732
13797
  var rules_writer_12 = require_rules_writer();
13798
+ var node_modules_guard_12 = require_node_modules_guard();
13733
13799
  var environments_12 = require_environments();
13734
13800
  exports2.DEFAULT_TIMEOUT_MS = 20 * 60 * 1e3;
13735
13801
  exports2.DEFAULT_MODEL = "anthropic/claude-sonnet-4-6";
@@ -13806,6 +13872,9 @@ var require_config = __commonJS({
13806
13872
  }
13807
13873
  },
13808
13874
  instructions: instructionPaths,
13875
+ // Blocks node_modules SDK-spelunking bash turns after a small exploratory
13876
+ // budget and steers back to the loaded references (see node-modules-guard.ts).
13877
+ plugin: [node_modules_guard_12.GUARD_PLUGIN_PATH],
13809
13878
  autoupdate: false,
13810
13879
  share: "disabled",
13811
13880
  lsp: false,
@@ -20996,6 +21065,7 @@ var logger_1 = require_logger();
20996
21065
  var skills_installer_1 = require_skills_installer();
20997
21066
  var rules_writer_1 = require_rules_writer();
20998
21067
  var tools_writer_1 = require_tools_writer();
21068
+ var node_modules_guard_1 = require_node_modules_guard();
20999
21069
  var plugin_artifacts_1 = require_plugin_artifacts();
21000
21070
  var config_1 = require_config();
21001
21071
  var environments_1 = require_environments();
@@ -21054,7 +21124,8 @@ async function initOpenCode() {
21054
21124
  (0, rules_writer_1.writeRuleFiles)([...envConfig.codegenRules, ...pluginArtifacts.rules]),
21055
21125
  (0, rules_writer_1.writeRuleFiles)(envConfig.askRules),
21056
21126
  (0, skills_installer_1.applySkillsOverride)((0, codegen_flow_helpers_1.getOutputPath)(), logger_1.logger),
21057
- (0, tools_writer_1.writeToolFiles)(pluginArtifacts.tools)
21127
+ (0, tools_writer_1.writeToolFiles)(pluginArtifacts.tools),
21128
+ (0, node_modules_guard_1.writeGuardPlugin)()
21058
21129
  ]);
21059
21130
  }
21060
21131
  async function main(ctx) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/ditto-codegen-public",
3
- "version": "1.0.366",
3
+ "version": "1.0.368",
4
4
  "description": "AI-powered Wix CLI app generator - standalone executable",
5
5
  "scripts": {
6
6
  "build": "node build.mjs",
@@ -29,5 +29,5 @@
29
29
  "esbuild": "^0.27.2",
30
30
  "vitest": "^4.0.16"
31
31
  },
32
- "falconPackageHash": "fcb0cf778e55a780aca1cac6efea4c192f6bfc82a53a21a0068e72de"
32
+ "falconPackageHash": "04ef867afd4c765b5f00fab8d163c32d045403ff32f4c83530f52728"
33
33
  }