@sapiom/agent-core
Advanced tools
+8
-0
| # @sapiom/orchestration-core | ||
| ## 0.10.6 | ||
| ### Patch Changes | ||
| - 651c407: Anchor esbuild to the agent project in `check()`, local runs, and `bundleForDeploy()` (`absWorkingDir`). Given no working directory esbuild adopts the caller's cwd and enumerates that cwd's ancestor chain in addition to the project's — so for the Studio Canvas, whose caller is the harness package buried inside the app, a directory nowhere near the user's agent could fail the build: reported as `Cannot read directory "../../../../../../../..": result too large` followed by `Could not resolve <project>/index.ts` on a project that was readable, installed, and passed `check` from a terminal (where cwd _is_ the project). Diagnostics become legible as a side effect — paths print relative to the working directory, so a project error reads `index.ts` instead of `../../../../../Users/me/agents/x/index.ts`. | ||
| Also report the real cause when a bundle fails because the project directory itself can't be read. `describeBundleFailure` probed only for a missing `node_modules`, which an unreadable or vanished project directory also answers — so a failure whose esbuild error was `Cannot read directory "…": permission denied` told the user to run `npm install` in a directory nothing could list. It now names the directory and the reason (permission denied, no longer exists, not a directory) and keeps the raw esbuild detail. | ||
| ## 0.10.5 | ||
@@ -4,0 +12,0 @@ |
@@ -9,4 +9,25 @@ "use strict"; | ||
| const node_path_1 = __importDefault(require("node:path")); | ||
| function directoryReadFailure(sourceDir) { | ||
| try { | ||
| (0, node_fs_1.readdirSync)(sourceDir); | ||
| return null; | ||
| } | ||
| catch (err) { | ||
| const code = err.code; | ||
| if (code === "ENOENT") | ||
| return `${sourceDir} no longer exists`; | ||
| if (code === "ENOTDIR") | ||
| return `${sourceDir} is not a directory`; | ||
| if (code === "EACCES" || code === "EPERM") { | ||
| return (`${sourceDir} can't be read (permission denied). Grant this app access to that ` + | ||
| `folder, or move the agent somewhere it can read`); | ||
| } | ||
| return `${sourceDir} can't be read (${code ?? "unknown error"})`; | ||
| } | ||
| } | ||
| function describeBundleFailure(sourceDir, err) { | ||
| const raw = err instanceof Error ? err.message : String(err); | ||
| const unreadable = directoryReadFailure(sourceDir); | ||
| if (unreadable) | ||
| return `${unreadable}. (esbuild: ${raw})`; | ||
| const nodeModules = node_path_1.default.join(sourceDir, "node_modules"); | ||
@@ -13,0 +34,0 @@ if (!(0, node_fs_1.existsSync)(nodeModules) && /Could not resolve/.test(raw)) { |
+25
-23
@@ -47,12 +47,13 @@ "use strict"; | ||
| async function bundleForDeploy(sourceDir) { | ||
| const entryFile = node_path_1.default.join(sourceDir, 'index.ts'); | ||
| const projectDir = node_path_1.default.resolve(sourceDir); | ||
| const entryFile = node_path_1.default.join(projectDir, "index.ts"); | ||
| if (!(0, node_fs_1.existsSync)(entryFile)) { | ||
| throw new errors_js_1.AgentOperationError({ | ||
| code: 'NO_ENTRY', | ||
| code: "NO_ENTRY", | ||
| message: `No index.ts found in ${sourceDir}.`, | ||
| hint: 'Run this from an agent project, or pass its directory.', | ||
| hint: "Run this from an agent project, or pass its directory.", | ||
| }); | ||
| } | ||
| const tmp = (0, node_fs_1.mkdtempSync)(node_path_1.default.join((0, node_os_1.tmpdir)(), 'sapiom-deploy-bundle-')); | ||
| const outfile = node_path_1.default.join(tmp, 'index.js'); | ||
| const tmp = (0, node_fs_1.mkdtempSync)(node_path_1.default.join((0, node_os_1.tmpdir)(), "sapiom-deploy-bundle-")); | ||
| const outfile = node_path_1.default.join(tmp, "index.js"); | ||
| try { | ||
@@ -64,9 +65,10 @@ let result; | ||
| outfile, | ||
| absWorkingDir: projectDir, | ||
| bundle: true, | ||
| platform: 'node', | ||
| target: 'node20', | ||
| format: 'esm', | ||
| packages: 'external', | ||
| platform: "node", | ||
| target: "node20", | ||
| format: "esm", | ||
| packages: "external", | ||
| metafile: true, | ||
| logLevel: 'silent', | ||
| logLevel: "silent", | ||
| }); | ||
@@ -76,10 +78,10 @@ } | ||
| throw new errors_js_1.AgentOperationError({ | ||
| code: 'BUNDLE_FAILED', | ||
| message: 'Failed to bundle the agent for deploy.', | ||
| code: "BUNDLE_FAILED", | ||
| message: "Failed to bundle the agent for deploy.", | ||
| hint: err instanceof Error ? err.message : String(err), | ||
| }); | ||
| } | ||
| const code = (0, node_fs_1.readFileSync)(outfile, 'utf8'); | ||
| const externals = collectExternalPackages(result.metafile, outfile); | ||
| const dependencies = resolveInstalledVersions(sourceDir, externals); | ||
| const code = (0, node_fs_1.readFileSync)(outfile, "utf8"); | ||
| const externals = collectExternalPackages(result.metafile, outfile, projectDir); | ||
| const dependencies = resolveInstalledVersions(projectDir, externals); | ||
| return { code, dependencies }; | ||
@@ -91,4 +93,4 @@ } | ||
| } | ||
| function collectExternalPackages(metafile, outfile) { | ||
| const key = Object.keys(metafile.outputs).find((k) => node_path_1.default.resolve(k) === node_path_1.default.resolve(outfile)); | ||
| function collectExternalPackages(metafile, outfile, workingDir) { | ||
| const key = Object.keys(metafile.outputs).find((k) => node_path_1.default.resolve(workingDir, k) === node_path_1.default.resolve(outfile)); | ||
| const imports = key ? metafile.outputs[key].imports : []; | ||
@@ -106,6 +108,6 @@ const names = new Set(); | ||
| function packageNameOf(importPath) { | ||
| if (importPath.startsWith('node:')) | ||
| if (importPath.startsWith("node:")) | ||
| return null; | ||
| const parts = importPath.split('/'); | ||
| if (importPath.startsWith('@')) | ||
| const parts = importPath.split("/"); | ||
| if (importPath.startsWith("@")) | ||
| return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : null; | ||
@@ -117,3 +119,3 @@ return parts[0] || null; | ||
| for (const pkg of packages) { | ||
| deps[pkg] = readInstalledVersion(sourceDir, pkg) ?? 'latest'; | ||
| deps[pkg] = readInstalledVersion(sourceDir, pkg) ?? "latest"; | ||
| } | ||
@@ -125,6 +127,6 @@ return deps; | ||
| while (true) { | ||
| const pkgJson = node_path_1.default.join(dir, 'node_modules', ...pkg.split('/'), 'package.json'); | ||
| const pkgJson = node_path_1.default.join(dir, "node_modules", ...pkg.split("/"), "package.json"); | ||
| if ((0, node_fs_1.existsSync)(pkgJson)) { | ||
| try { | ||
| const version = JSON.parse((0, node_fs_1.readFileSync)(pkgJson, 'utf8')).version; | ||
| const version = JSON.parse((0, node_fs_1.readFileSync)(pkgJson, "utf8")).version; | ||
| if (version) | ||
@@ -131,0 +133,0 @@ return version; |
@@ -106,2 +106,3 @@ "use strict"; | ||
| outfile: bundlePath, | ||
| absWorkingDir: sourceDir, | ||
| bundle: true, | ||
@@ -108,0 +109,0 @@ platform: "node", |
@@ -65,2 +65,3 @@ "use strict"; | ||
| outfile: bundlePath, | ||
| absWorkingDir: node_path_1.default.resolve(sourceDir), | ||
| bundle: true, | ||
@@ -67,0 +68,0 @@ platform: "node", |
@@ -1,5 +0,26 @@ | ||
| import { existsSync } from "node:fs"; | ||
| import { existsSync, readdirSync } from "node:fs"; | ||
| import path from "node:path"; | ||
| function directoryReadFailure(sourceDir) { | ||
| try { | ||
| readdirSync(sourceDir); | ||
| return null; | ||
| } | ||
| catch (err) { | ||
| const code = err.code; | ||
| if (code === "ENOENT") | ||
| return `${sourceDir} no longer exists`; | ||
| if (code === "ENOTDIR") | ||
| return `${sourceDir} is not a directory`; | ||
| if (code === "EACCES" || code === "EPERM") { | ||
| return (`${sourceDir} can't be read (permission denied). Grant this app access to that ` + | ||
| `folder, or move the agent somewhere it can read`); | ||
| } | ||
| return `${sourceDir} can't be read (${code ?? "unknown error"})`; | ||
| } | ||
| } | ||
| export function describeBundleFailure(sourceDir, err) { | ||
| const raw = err instanceof Error ? err.message : String(err); | ||
| const unreadable = directoryReadFailure(sourceDir); | ||
| if (unreadable) | ||
| return `${unreadable}. (esbuild: ${raw})`; | ||
| const nodeModules = path.join(sourceDir, "node_modules"); | ||
@@ -6,0 +27,0 @@ if (!existsSync(nodeModules) && /Could not resolve/.test(raw)) { |
+31
-29
@@ -1,18 +0,19 @@ | ||
| import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs'; | ||
| import { isBuiltin } from 'node:module'; | ||
| import { tmpdir } from 'node:os'; | ||
| import path from 'node:path'; | ||
| import * as esbuild from 'esbuild'; | ||
| import { AgentOperationError } from './errors.js'; | ||
| import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs"; | ||
| import { isBuiltin } from "node:module"; | ||
| import { tmpdir } from "node:os"; | ||
| import path from "node:path"; | ||
| import * as esbuild from "esbuild"; | ||
| import { AgentOperationError } from "./errors.js"; | ||
| export async function bundleForDeploy(sourceDir) { | ||
| const entryFile = path.join(sourceDir, 'index.ts'); | ||
| const projectDir = path.resolve(sourceDir); | ||
| const entryFile = path.join(projectDir, "index.ts"); | ||
| if (!existsSync(entryFile)) { | ||
| throw new AgentOperationError({ | ||
| code: 'NO_ENTRY', | ||
| code: "NO_ENTRY", | ||
| message: `No index.ts found in ${sourceDir}.`, | ||
| hint: 'Run this from an agent project, or pass its directory.', | ||
| hint: "Run this from an agent project, or pass its directory.", | ||
| }); | ||
| } | ||
| const tmp = mkdtempSync(path.join(tmpdir(), 'sapiom-deploy-bundle-')); | ||
| const outfile = path.join(tmp, 'index.js'); | ||
| const tmp = mkdtempSync(path.join(tmpdir(), "sapiom-deploy-bundle-")); | ||
| const outfile = path.join(tmp, "index.js"); | ||
| try { | ||
@@ -24,9 +25,10 @@ let result; | ||
| outfile, | ||
| absWorkingDir: projectDir, | ||
| bundle: true, | ||
| platform: 'node', | ||
| target: 'node20', | ||
| format: 'esm', | ||
| packages: 'external', | ||
| platform: "node", | ||
| target: "node20", | ||
| format: "esm", | ||
| packages: "external", | ||
| metafile: true, | ||
| logLevel: 'silent', | ||
| logLevel: "silent", | ||
| }); | ||
@@ -36,10 +38,10 @@ } | ||
| throw new AgentOperationError({ | ||
| code: 'BUNDLE_FAILED', | ||
| message: 'Failed to bundle the agent for deploy.', | ||
| code: "BUNDLE_FAILED", | ||
| message: "Failed to bundle the agent for deploy.", | ||
| hint: err instanceof Error ? err.message : String(err), | ||
| }); | ||
| } | ||
| const code = readFileSync(outfile, 'utf8'); | ||
| const externals = collectExternalPackages(result.metafile, outfile); | ||
| const dependencies = resolveInstalledVersions(sourceDir, externals); | ||
| const code = readFileSync(outfile, "utf8"); | ||
| const externals = collectExternalPackages(result.metafile, outfile, projectDir); | ||
| const dependencies = resolveInstalledVersions(projectDir, externals); | ||
| return { code, dependencies }; | ||
@@ -51,4 +53,4 @@ } | ||
| } | ||
| function collectExternalPackages(metafile, outfile) { | ||
| const key = Object.keys(metafile.outputs).find((k) => path.resolve(k) === path.resolve(outfile)); | ||
| function collectExternalPackages(metafile, outfile, workingDir) { | ||
| const key = Object.keys(metafile.outputs).find((k) => path.resolve(workingDir, k) === path.resolve(outfile)); | ||
| const imports = key ? metafile.outputs[key].imports : []; | ||
@@ -66,6 +68,6 @@ const names = new Set(); | ||
| function packageNameOf(importPath) { | ||
| if (importPath.startsWith('node:')) | ||
| if (importPath.startsWith("node:")) | ||
| return null; | ||
| const parts = importPath.split('/'); | ||
| if (importPath.startsWith('@')) | ||
| const parts = importPath.split("/"); | ||
| if (importPath.startsWith("@")) | ||
| return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : null; | ||
@@ -77,3 +79,3 @@ return parts[0] || null; | ||
| for (const pkg of packages) { | ||
| deps[pkg] = readInstalledVersion(sourceDir, pkg) ?? 'latest'; | ||
| deps[pkg] = readInstalledVersion(sourceDir, pkg) ?? "latest"; | ||
| } | ||
@@ -85,6 +87,6 @@ return deps; | ||
| while (true) { | ||
| const pkgJson = path.join(dir, 'node_modules', ...pkg.split('/'), 'package.json'); | ||
| const pkgJson = path.join(dir, "node_modules", ...pkg.split("/"), "package.json"); | ||
| if (existsSync(pkgJson)) { | ||
| try { | ||
| const version = JSON.parse(readFileSync(pkgJson, 'utf8')).version; | ||
| const version = JSON.parse(readFileSync(pkgJson, "utf8")).version; | ||
| if (version) | ||
@@ -91,0 +93,0 @@ return version; |
@@ -65,2 +65,3 @@ import { execFileSync } from "node:child_process"; | ||
| outfile: bundlePath, | ||
| absWorkingDir: sourceDir, | ||
| bundle: true, | ||
@@ -67,0 +68,0 @@ platform: "node", |
@@ -26,2 +26,3 @@ import { createHash } from "node:crypto"; | ||
| outfile: bundlePath, | ||
| absWorkingDir: path.resolve(sourceDir), | ||
| bundle: true, | ||
@@ -28,0 +29,0 @@ platform: "node", |
+2
-2
| { | ||
| "name": "@sapiom/agent-core", | ||
| "version": "0.10.5", | ||
| "version": "0.10.6", | ||
| "description": "Pure, stateless core functions for scaffolding, validating, and operating Sapiom agents — shared by the CLI and MCP packages.", | ||
@@ -40,5 +40,5 @@ "license": "MIT", | ||
| "esbuild": "^0.28.1", | ||
| "@sapiom/agent": "^0.9.3", | ||
| "@sapiom/agent-runtime": "^0.4.3", | ||
| "@sapiom/analytics-core": "^0.2.1", | ||
| "@sapiom/agent": "^0.9.3", | ||
| "@sapiom/tools": "^0.26.2" | ||
@@ -45,0 +45,0 @@ }, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
509333
0.68%5937
0.85%32
3.23%