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/index.d.cts CHANGED
@@ -2179,6 +2179,16 @@ declare class ToolRegistry extends EventEmitter {
2179
2179
  private plugins;
2180
2180
  constructor(config: ToolsConfig, workspaceRoot?: string);
2181
2181
  register(tool: BaseTool): void;
2182
+ /**
2183
+ * The directory every registered tool resolves relative paths against.
2184
+ *
2185
+ * Exposed so a caller that has to reason about a file a tool WROTE can look
2186
+ * in the same place the tool wrote it. `process.cwd()` is not that place
2187
+ * outside a plain CLI run: the hosted server's cwd is the app directory
2188
+ * while the run's workspace is the tenant's scratch dir, and Electron's cwd
2189
+ * is the app bundle rather than the user's chosen folder.
2190
+ */
2191
+ getWorkspaceRoot(): string;
2182
2192
  /**
2183
2193
  * Wait until a named tool is registered, resolving immediately if it already exists.
2184
2194
  * T3 workers can call this after encountering a missing-tool error to resume
@@ -3294,6 +3304,20 @@ declare class T3Worker extends BaseTier {
3294
3304
  */
3295
3305
  private coordinateFileIntents;
3296
3306
  private requiresArtifact;
3307
+ /**
3308
+ * Where a file a tool wrote actually lives.
3309
+ *
3310
+ * This used to be `process.cwd()`, which is only the workspace in a plain
3311
+ * CLI run. The hosted server runs with cwd at the app directory while the
3312
+ * run's workspace is the tenant's scratch dir, and Electron's cwd is the app
3313
+ * bundle rather than the folder the user picked. So the tool wrote
3314
+ * `<workspace>/report.docx`, verification stat'd `<cwd>/report.docx`, found
3315
+ * nothing, and the worker looped and then threw WorkerStallError — surfacing
3316
+ * as "no file was created" on a file that had in fact been created, followed
3317
+ * by a failed node. Asking the registry is exact: it is the same root every
3318
+ * registered tool was configured with (registry.registerDefaults).
3319
+ */
3320
+ private artifactRoot;
3297
3321
  private extractArtifactPaths;
3298
3322
  private verifyArtifacts;
3299
3323
  /**
package/dist/index.d.ts CHANGED
@@ -2179,6 +2179,16 @@ declare class ToolRegistry extends EventEmitter {
2179
2179
  private plugins;
2180
2180
  constructor(config: ToolsConfig, workspaceRoot?: string);
2181
2181
  register(tool: BaseTool): void;
2182
+ /**
2183
+ * The directory every registered tool resolves relative paths against.
2184
+ *
2185
+ * Exposed so a caller that has to reason about a file a tool WROTE can look
2186
+ * in the same place the tool wrote it. `process.cwd()` is not that place
2187
+ * outside a plain CLI run: the hosted server's cwd is the app directory
2188
+ * while the run's workspace is the tenant's scratch dir, and Electron's cwd
2189
+ * is the app bundle rather than the user's chosen folder.
2190
+ */
2191
+ getWorkspaceRoot(): string;
2182
2192
  /**
2183
2193
  * Wait until a named tool is registered, resolving immediately if it already exists.
2184
2194
  * T3 workers can call this after encountering a missing-tool error to resume
@@ -3294,6 +3304,20 @@ declare class T3Worker extends BaseTier {
3294
3304
  */
3295
3305
  private coordinateFileIntents;
3296
3306
  private requiresArtifact;
3307
+ /**
3308
+ * Where a file a tool wrote actually lives.
3309
+ *
3310
+ * This used to be `process.cwd()`, which is only the workspace in a plain
3311
+ * CLI run. The hosted server runs with cwd at the app directory while the
3312
+ * run's workspace is the tenant's scratch dir, and Electron's cwd is the app
3313
+ * bundle rather than the folder the user picked. So the tool wrote
3314
+ * `<workspace>/report.docx`, verification stat'd `<cwd>/report.docx`, found
3315
+ * nothing, and the worker looped and then threw WorkerStallError — surfacing
3316
+ * as "no file was created" on a file that had in fact been created, followed
3317
+ * by a failed node. Asking the registry is exact: it is the same root every
3318
+ * registered tool was configured with (registry.registerDefaults).
3319
+ */
3320
+ private artifactRoot;
3297
3321
  private extractArtifactPaths;
3298
3322
  private verifyArtifacts;
3299
3323
  /**
package/dist/index.js CHANGED
@@ -1862,7 +1862,7 @@ function reconcilePrice(model, live) {
1862
1862
  }
1863
1863
 
1864
1864
  // src/constants.ts
1865
- var CASCADE_VERSION = "0.71.0";
1865
+ var CASCADE_VERSION = "0.72.0";
1866
1866
  var CASCADE_CONFIG_DIR = ".cascade";
1867
1867
  var CASCADE_MD_FILE = "CASCADE.md";
1868
1868
  var CASCADE_IGNORE_FILE = ".cascadeignore";
@@ -7252,6 +7252,22 @@ ${assignment.expectedOutput}`;
7252
7252
  requiresArtifact() {
7253
7253
  return shouldRequireArtifact(this.assignment, this.tools.map((t) => t.name));
7254
7254
  }
7255
+ /**
7256
+ * Where a file a tool wrote actually lives.
7257
+ *
7258
+ * This used to be `process.cwd()`, which is only the workspace in a plain
7259
+ * CLI run. The hosted server runs with cwd at the app directory while the
7260
+ * run's workspace is the tenant's scratch dir, and Electron's cwd is the app
7261
+ * bundle rather than the folder the user picked. So the tool wrote
7262
+ * `<workspace>/report.docx`, verification stat'd `<cwd>/report.docx`, found
7263
+ * nothing, and the worker looped and then threw WorkerStallError — surfacing
7264
+ * as "no file was created" on a file that had in fact been created, followed
7265
+ * by a failed node. Asking the registry is exact: it is the same root every
7266
+ * registered tool was configured with (registry.registerDefaults).
7267
+ */
7268
+ artifactRoot() {
7269
+ return this.toolRegistry.getWorkspaceRoot?.() ?? process.cwd();
7270
+ }
7255
7271
  extractArtifactPaths(assignment) {
7256
7272
  const declared = (assignment.files ?? []).map((f) => f.trim()).filter((f) => f.includes("."));
7257
7273
  const haystack = `${assignment.description}
@@ -7263,11 +7279,11 @@ ${assignment.expectedOutput}`;
7263
7279
  const artifactPaths = this.extractArtifactPaths(assignment);
7264
7280
  if (!artifactPaths.length) return { ok: true, issues: [] };
7265
7281
  const issues = [];
7266
- const { exec: exec2 } = await import('child_process');
7282
+ const { execFile: execFile4 } = await import('child_process');
7267
7283
  const { promisify: promisify4 } = await import('util');
7268
- const execAsync2 = promisify4(exec2);
7284
+ const execFileAsync3 = promisify4(execFile4);
7269
7285
  for (const artifactPath of artifactPaths) {
7270
- const absolutePath = path26.resolve(process.cwd(), artifactPath);
7286
+ const absolutePath = path26.resolve(this.artifactRoot(), artifactPath);
7271
7287
  try {
7272
7288
  const stat = await fs5.stat(absolutePath);
7273
7289
  if (!stat.isFile()) {
@@ -7303,20 +7319,18 @@ ${assignment.expectedOutput}`;
7303
7319
  continue;
7304
7320
  }
7305
7321
  const ext = path26.extname(absolutePath).toLowerCase();
7306
- try {
7307
- if (ext === ".ts" || ext === ".tsx") {
7308
- await execAsync2(`npx tsc --noEmit ${absolutePath}`, { timeout: 1e4 });
7309
- } else if (ext === ".js" || ext === ".jsx") {
7310
- await execAsync2(`node --check ${absolutePath}`, { timeout: 1e4 });
7311
- } else if (ext === ".py") {
7312
- await execAsync2(`python -m py_compile ${absolutePath}`, { timeout: 1e4 });
7322
+ 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;
7323
+ if (check) {
7324
+ try {
7325
+ await execFileAsync3(check.cmd, check.args, { timeout: 1e4 });
7326
+ } catch (err) {
7327
+ const code = err.code;
7328
+ if (code === "ENOENT" || code === "EINVAL") continue;
7329
+ const e = err;
7330
+ issues.push(`Semantic error in ${artifactPath}:
7331
+ ${e.stderr || String(err)}
7332
+ ${e.stdout || ""}`);
7313
7333
  }
7314
- } catch (err) {
7315
- const stderr = err?.stderr || String(err);
7316
- const stdout = err?.stdout || "";
7317
- issues.push(`Semantic error in ${artifactPath}:
7318
- ${stderr}
7319
- ${stdout}`);
7320
7334
  }
7321
7335
  } catch {
7322
7336
  issues.push(`Required artifact was not created: ${artifactPath}`);
@@ -7395,7 +7409,7 @@ HIERARCHY CONTEXT: ${this.hierarchyContext}` : ""),
7395
7409
  async checkAcceptance(assignment) {
7396
7410
  const criteria = assignment.acceptance ?? [];
7397
7411
  if (!criteria.length) return [];
7398
- const resolve2 = (target) => path26.resolve(process.cwd(), target);
7412
+ const resolve2 = (target) => path26.resolve(this.artifactRoot(), target);
7399
7413
  return evaluateAcceptance(criteria, assignment.files ?? [], {
7400
7414
  stat: async (target) => {
7401
7415
  try {
@@ -12983,6 +12997,18 @@ var ToolRegistry = class extends EventEmitter {
12983
12997
  this.tools.set(tool.name, tool);
12984
12998
  this.emit("tool:added", tool.name);
12985
12999
  }
13000
+ /**
13001
+ * The directory every registered tool resolves relative paths against.
13002
+ *
13003
+ * Exposed so a caller that has to reason about a file a tool WROTE can look
13004
+ * in the same place the tool wrote it. `process.cwd()` is not that place
13005
+ * outside a plain CLI run: the hosted server's cwd is the app directory
13006
+ * while the run's workspace is the tenant's scratch dir, and Electron's cwd
13007
+ * is the app bundle rather than the user's chosen folder.
13008
+ */
13009
+ getWorkspaceRoot() {
13010
+ return this.workspaceRoot;
13011
+ }
12986
13012
  /**
12987
13013
  * Wait until a named tool is registered, resolving immediately if it already exists.
12988
13014
  * T3 workers can call this after encountering a missing-tool error to resume