@sapiom/agent-core
Advanced tools
+51
-0
| # @sapiom/orchestration-core | ||
| ## 0.10.7 | ||
| ### Patch Changes | ||
| - f21f6a6: Windows: sessions create and deliver their prompt, the canvas refreshes, and nothing pops a console window | ||
| The desktop app was unusable on Windows — every `POST /api/sessions` answered | ||
| `500 {"error":"internal error"}`, and when a session did start, its first | ||
| prompt never reached the agent. Root-caused on a real machine and fixed | ||
| end to end. | ||
| - **Sessions.** Claude Code's own native auto-updater had renamed the running | ||
| `claude.exe` to `claude.exe.old.<ts>` inside the app-managed npm prefix and | ||
| never written the replacement, so every spawn failed while `doctor` (which | ||
| shells `where`) still reported the agent present. Boot now verifies the | ||
| agent actually spawns, repairs the managed install when it doesn't, and sets | ||
| `DISABLE_AUTOUPDATER` for installs the app owns. The refusal itself names | ||
| the situation instead of "target could not be determined". | ||
| - **The first prompt.** It is held until the session reports ready, which only | ||
| happens when the generated `SessionStart` hook POSTs back — and Claude Code | ||
| runs hooks through Git Bash on Windows, which cannot resolve a `.cmd`, so | ||
| the desktop's `node.cmd`-only shims meant the hook never ran. The host now | ||
| ships npm's extensionless sh shim too, a 20s hook-timeout fallback rescues a | ||
| session whose hook chain is broken (gated on Claude's blocking-prompt | ||
| screens so it can never answer a trust dialog), `emit.cjs` gets budgets a | ||
| cold loopback survives (SessionStart only — the other hooks block the | ||
| agent), and multi-line prompts are paste-wrapped under ConPTY, which hides | ||
| the bracketed-paste announcement. | ||
| - **Console windows.** The `sapiom-dev` MCP server was launched via `npx`, | ||
| whose `cmd.exe` sat on screen as a persistent blank window; closing it | ||
| killed the server and every later tool call hung. The app now installs | ||
| `@sapiom/mcp` into its own prefix and launches it through the app binary | ||
| (GUI subsystem — no console can exist), and every `child_process` call | ||
| across the harness, agent-core, the MCP and the desktop passes | ||
| `windowsHide`. | ||
| - **Canvas.** `fs.watch` reports native separators, so the watcher's | ||
| POSIX-literal comparison never matched on Windows and `canvas.reload` was | ||
| never published — every canvas hot-reload was silently dead there (the | ||
| "Preparing your agent" placeholder outliving a finished install was the | ||
| visible symptom). | ||
| - **Diagnosis.** 500s now carry the real message (and errno) instead of | ||
| "internal error", the desktop tees its main-process log to | ||
| `<userData>/logs/main.log`, and spawn failures map to actionable 4xx. | ||
| - **Also:** Git is provisioned from git-for-windows' checksum-pinned MinGit | ||
| when a Windows machine has none (template clone and deploy shell out to a | ||
| real `git`); client-supplied `cwd` is normalized server-side and the SPA's | ||
| path helpers understand both separators; gateway requests time out instead | ||
| of hanging an MCP tool call for minutes; and the updater falls back to | ||
| HTTP/1.1, names a GitHub 429 for what it is, and bounds every path that can | ||
| reach GitHub. | ||
| ## 0.10.6 | ||
@@ -4,0 +55,0 @@ |
@@ -61,2 +61,3 @@ "use strict"; | ||
| stdio: ["ignore", "pipe", "pipe"], | ||
| windowsHide: true, | ||
| }); | ||
@@ -63,0 +64,0 @@ return null; |
+16
-1
@@ -32,2 +32,3 @@ "use strict"; | ||
| body: body === undefined ? undefined : JSON.stringify(body), | ||
| signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS), | ||
| }); | ||
@@ -38,3 +39,9 @@ } | ||
| } | ||
| const text = await res.text(); | ||
| let text; | ||
| try { | ||
| text = await res.text(); | ||
| } | ||
| catch (err) { | ||
| throw networkError(url, err); | ||
| } | ||
| const data = text ? safeParse(text) : undefined; | ||
@@ -98,3 +105,11 @@ if (!res.ok) { | ||
| } | ||
| const REQUEST_TIMEOUT_MS = 60000; | ||
| function networkError(url, err) { | ||
| if (err instanceof Error && err.name === 'TimeoutError') { | ||
| return new errors_js_1.AgentOperationError({ | ||
| code: 'NETWORK', | ||
| message: `Request to ${url} timed out after ${REQUEST_TIMEOUT_MS / 1000}s.`, | ||
| hint: 'Is this machine able to reach the Sapiom API (firewall/proxy)? Try again once connectivity is confirmed.', | ||
| }); | ||
| } | ||
| return new errors_js_1.AgentOperationError({ | ||
@@ -101,0 +116,0 @@ code: 'NETWORK', |
+19
-2
@@ -10,2 +10,11 @@ "use strict"; | ||
| const errors_js_1 = require("./errors.js"); | ||
| function gitMissingError(err) { | ||
| if (err?.code !== "ENOENT") | ||
| return null; | ||
| return new errors_js_1.AgentOperationError({ | ||
| code: "GIT_NOT_INSTALLED", | ||
| message: "git is not installed (or not on PATH).", | ||
| hint: "Install Git from https://git-scm.com/downloads, then retry. On Windows, install “Git for Windows” with default options and restart the app so the new PATH is picked up.", | ||
| }); | ||
| } | ||
| function git(args, cwd) { | ||
@@ -17,5 +26,9 @@ try { | ||
| stdio: ["ignore", "pipe", "pipe"], | ||
| windowsHide: true, | ||
| }).trim(); | ||
| } | ||
| catch (err) { | ||
| const missing = gitMissingError(err); | ||
| if (missing) | ||
| throw missing; | ||
| const raw = err.stderr?.toString().trim(); | ||
@@ -35,2 +48,3 @@ const hint = redactCredentials(raw || (err instanceof Error ? err.message : String(err))); | ||
| stdio: "ignore", | ||
| windowsHide: true, | ||
| }); | ||
@@ -46,3 +60,3 @@ } | ||
| try { | ||
| (0, node_child_process_1.execFileSync)("git", ["rev-parse", "HEAD"], { cwd: dir, stdio: "ignore" }); | ||
| (0, node_child_process_1.execFileSync)("git", ["rev-parse", "HEAD"], { cwd: dir, stdio: "ignore", windowsHide: true }); | ||
| } | ||
@@ -73,5 +87,8 @@ catch { | ||
| targetDir, | ||
| ], { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf8" }); | ||
| ], { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf8", windowsHide: true }); | ||
| } | ||
| catch (err) { | ||
| const missing = gitMissingError(err); | ||
| if (missing) | ||
| throw missing; | ||
| const stderr = err.stderr?.toString(); | ||
@@ -78,0 +95,0 @@ const raw = stderr?.trim() || (err instanceof Error ? err.message : String(err)); |
@@ -16,2 +16,3 @@ "use strict"; | ||
| maxBuffer: MAX_BUFFER_BYTES, | ||
| windowsHide: true, | ||
| }); | ||
@@ -18,0 +19,0 @@ return true; |
@@ -151,3 +151,3 @@ "use strict"; | ||
| try { | ||
| (0, node_child_process_1.execFileSync)("git", args, { cwd: dir, stdio: "ignore" }); | ||
| (0, node_child_process_1.execFileSync)("git", args, { cwd: dir, stdio: "ignore", windowsHide: true }); | ||
| return true; | ||
@@ -154,0 +154,0 @@ } |
@@ -20,2 +20,3 @@ import { execFileSync } from "node:child_process"; | ||
| stdio: ["ignore", "pipe", "pipe"], | ||
| windowsHide: true, | ||
| }); | ||
@@ -22,0 +23,0 @@ return null; |
+16
-1
@@ -28,2 +28,3 @@ import { AgentOperationError } from './errors.js'; | ||
| body: body === undefined ? undefined : JSON.stringify(body), | ||
| signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS), | ||
| }); | ||
@@ -34,3 +35,9 @@ } | ||
| } | ||
| const text = await res.text(); | ||
| let text; | ||
| try { | ||
| text = await res.text(); | ||
| } | ||
| catch (err) { | ||
| throw networkError(url, err); | ||
| } | ||
| const data = text ? safeParse(text) : undefined; | ||
@@ -93,3 +100,11 @@ if (!res.ok) { | ||
| } | ||
| const REQUEST_TIMEOUT_MS = 60000; | ||
| function networkError(url, err) { | ||
| if (err instanceof Error && err.name === 'TimeoutError') { | ||
| return new AgentOperationError({ | ||
| code: 'NETWORK', | ||
| message: `Request to ${url} timed out after ${REQUEST_TIMEOUT_MS / 1000}s.`, | ||
| hint: 'Is this machine able to reach the Sapiom API (firewall/proxy)? Try again once connectivity is confirmed.', | ||
| }); | ||
| } | ||
| return new AgentOperationError({ | ||
@@ -96,0 +111,0 @@ code: 'NETWORK', |
+19
-2
| import { execFileSync } from "node:child_process"; | ||
| import { AgentOperationError } from "./errors.js"; | ||
| function gitMissingError(err) { | ||
| if (err?.code !== "ENOENT") | ||
| return null; | ||
| return new AgentOperationError({ | ||
| code: "GIT_NOT_INSTALLED", | ||
| message: "git is not installed (or not on PATH).", | ||
| hint: "Install Git from https://git-scm.com/downloads, then retry. On Windows, install “Git for Windows” with default options and restart the app so the new PATH is picked up.", | ||
| }); | ||
| } | ||
| function git(args, cwd) { | ||
@@ -9,5 +18,9 @@ try { | ||
| stdio: ["ignore", "pipe", "pipe"], | ||
| windowsHide: true, | ||
| }).trim(); | ||
| } | ||
| catch (err) { | ||
| const missing = gitMissingError(err); | ||
| if (missing) | ||
| throw missing; | ||
| const raw = err.stderr?.toString().trim(); | ||
@@ -27,2 +40,3 @@ const hint = redactCredentials(raw || (err instanceof Error ? err.message : String(err))); | ||
| stdio: "ignore", | ||
| windowsHide: true, | ||
| }); | ||
@@ -38,3 +52,3 @@ } | ||
| try { | ||
| execFileSync("git", ["rev-parse", "HEAD"], { cwd: dir, stdio: "ignore" }); | ||
| execFileSync("git", ["rev-parse", "HEAD"], { cwd: dir, stdio: "ignore", windowsHide: true }); | ||
| } | ||
@@ -65,5 +79,8 @@ catch { | ||
| targetDir, | ||
| ], { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf8" }); | ||
| ], { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf8", windowsHide: true }); | ||
| } | ||
| catch (err) { | ||
| const missing = gitMissingError(err); | ||
| if (missing) | ||
| throw missing; | ||
| const stderr = err.stderr?.toString(); | ||
@@ -70,0 +87,0 @@ const raw = stderr?.trim() || (err instanceof Error ? err.message : String(err)); |
@@ -13,2 +13,3 @@ import { execFile } from "node:child_process"; | ||
| maxBuffer: MAX_BUFFER_BYTES, | ||
| windowsHide: true, | ||
| }); | ||
@@ -15,0 +16,0 @@ return true; |
@@ -140,3 +140,3 @@ import { execFileSync } from "node:child_process"; | ||
| try { | ||
| execFileSync("git", args, { cwd: dir, stdio: "ignore" }); | ||
| execFileSync("git", args, { cwd: dir, stdio: "ignore", windowsHide: true }); | ||
| return true; | ||
@@ -143,0 +143,0 @@ } |
+1
-1
| { | ||
| "name": "@sapiom/agent-core", | ||
| "version": "0.10.6", | ||
| "version": "0.10.7", | ||
| "description": "Pure, stateless core functions for scaffolding, validating, and operating Sapiom agents — shared by the CLI and MCP packages.", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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.
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.
515254
1.16%6005
1.15%