cascade-ai 0.71.0 → 0.72.0

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/cli.js CHANGED
@@ -1757,7 +1757,7 @@ var CASCADE_VERSION, CASCADE_CONFIG_FILE, CASCADE_DB_FILE, CASCADE_DASHBOARD_SEC
1757
1757
  var init_constants = __esm({
1758
1758
  "src/constants.ts"() {
1759
1759
  init_pricing();
1760
- CASCADE_VERSION = "0.71.0";
1760
+ CASCADE_VERSION = "0.72.0";
1761
1761
  CASCADE_CONFIG_FILE = ".cascade/config.json";
1762
1762
  CASCADE_DB_FILE = ".cascade/memory.db";
1763
1763
  CASCADE_DASHBOARD_SECRET_FILE = ".cascade/dashboard-secret";
@@ -9821,6 +9821,22 @@ ${assignment.expectedOutput}`;
9821
9821
  requiresArtifact() {
9822
9822
  return shouldRequireArtifact(this.assignment, this.tools.map((t) => t.name));
9823
9823
  }
9824
+ /**
9825
+ * Where a file a tool wrote actually lives.
9826
+ *
9827
+ * This used to be `process.cwd()`, which is only the workspace in a plain
9828
+ * CLI run. The hosted server runs with cwd at the app directory while the
9829
+ * run's workspace is the tenant's scratch dir, and Electron's cwd is the app
9830
+ * bundle rather than the folder the user picked. So the tool wrote
9831
+ * `<workspace>/report.docx`, verification stat'd `<cwd>/report.docx`, found
9832
+ * nothing, and the worker looped and then threw WorkerStallError — surfacing
9833
+ * as "no file was created" on a file that had in fact been created, followed
9834
+ * by a failed node. Asking the registry is exact: it is the same root every
9835
+ * registered tool was configured with (registry.registerDefaults).
9836
+ */
9837
+ artifactRoot() {
9838
+ return this.toolRegistry.getWorkspaceRoot?.() ?? process.cwd();
9839
+ }
9824
9840
  extractArtifactPaths(assignment) {
9825
9841
  const declared = (assignment.files ?? []).map((f) => f.trim()).filter((f) => f.includes("."));
9826
9842
  const haystack = `${assignment.description}
@@ -9832,11 +9848,11 @@ ${assignment.expectedOutput}`;
9832
9848
  const artifactPaths = this.extractArtifactPaths(assignment);
9833
9849
  if (!artifactPaths.length) return { ok: true, issues: [] };
9834
9850
  const issues = [];
9835
- const { exec: exec3 } = await import('child_process');
9851
+ const { execFile: execFile3 } = await import('child_process');
9836
9852
  const { promisify: promisify4 } = await import('util');
9837
- const execAsync3 = promisify4(exec3);
9853
+ const execFileAsync2 = promisify4(execFile3);
9838
9854
  for (const artifactPath of artifactPaths) {
9839
- const absolutePath = path34.resolve(process.cwd(), artifactPath);
9855
+ const absolutePath = path34.resolve(this.artifactRoot(), artifactPath);
9840
9856
  try {
9841
9857
  const stat = await fs11.stat(absolutePath);
9842
9858
  if (!stat.isFile()) {
@@ -9872,20 +9888,18 @@ ${assignment.expectedOutput}`;
9872
9888
  continue;
9873
9889
  }
9874
9890
  const ext = path34.extname(absolutePath).toLowerCase();
9875
- try {
9876
- if (ext === ".ts" || ext === ".tsx") {
9877
- await execAsync3(`npx tsc --noEmit ${absolutePath}`, { timeout: 1e4 });
9878
- } else if (ext === ".js" || ext === ".jsx") {
9879
- await execAsync3(`node --check ${absolutePath}`, { timeout: 1e4 });
9880
- } else if (ext === ".py") {
9881
- await execAsync3(`python -m py_compile ${absolutePath}`, { timeout: 1e4 });
9891
+ const check = ext === ".ts" || ext === ".tsx" ? { cmd: "npx", args: ["tsc", "--noEmit", absolutePath] } : ext === ".js" || ext === ".jsx" ? { cmd: process.execPath, args: ["--check", absolutePath] } : ext === ".py" ? { cmd: "python", args: ["-m", "py_compile", absolutePath] } : null;
9892
+ if (check) {
9893
+ try {
9894
+ await execFileAsync2(check.cmd, check.args, { timeout: 1e4 });
9895
+ } catch (err) {
9896
+ const code = err.code;
9897
+ if (code === "ENOENT" || code === "EINVAL") continue;
9898
+ const e = err;
9899
+ issues.push(`Semantic error in ${artifactPath}:
9900
+ ${e.stderr || String(err)}
9901
+ ${e.stdout || ""}`);
9882
9902
  }
9883
- } catch (err) {
9884
- const stderr = err?.stderr || String(err);
9885
- const stdout = err?.stdout || "";
9886
- issues.push(`Semantic error in ${artifactPath}:
9887
- ${stderr}
9888
- ${stdout}`);
9889
9903
  }
9890
9904
  } catch {
9891
9905
  issues.push(`Required artifact was not created: ${artifactPath}`);
@@ -9964,7 +9978,7 @@ HIERARCHY CONTEXT: ${this.hierarchyContext}` : ""),
9964
9978
  async checkAcceptance(assignment) {
9965
9979
  const criteria = assignment.acceptance ?? [];
9966
9980
  if (!criteria.length) return [];
9967
- const resolve2 = (target) => path34.resolve(process.cwd(), target);
9981
+ const resolve2 = (target) => path34.resolve(this.artifactRoot(), target);
9968
9982
  return evaluateAcceptance(criteria, assignment.files ?? [], {
9969
9983
  stat: async (target) => {
9970
9984
  try {
@@ -15380,6 +15394,18 @@ var ToolRegistry = class extends EventEmitter {
15380
15394
  this.tools.set(tool.name, tool);
15381
15395
  this.emit("tool:added", tool.name);
15382
15396
  }
15397
+ /**
15398
+ * The directory every registered tool resolves relative paths against.
15399
+ *
15400
+ * Exposed so a caller that has to reason about a file a tool WROTE can look
15401
+ * in the same place the tool wrote it. `process.cwd()` is not that place
15402
+ * outside a plain CLI run: the hosted server's cwd is the app directory
15403
+ * while the run's workspace is the tenant's scratch dir, and Electron's cwd
15404
+ * is the app bundle rather than the user's chosen folder.
15405
+ */
15406
+ getWorkspaceRoot() {
15407
+ return this.workspaceRoot;
15408
+ }
15383
15409
  /**
15384
15410
  * Wait until a named tool is registered, resolving immediately if it already exists.
15385
15411
  * T3 workers can call this after encountering a missing-tool error to resume