Update to Yaps Background Remover
Snapshot Nov 12, 2026 · 06:08 UTC · version 0.1.12
Package or technical metadata updated
Package or technical metadata updated
Observed in package metadata. These changes alone do not establish a new customer-facing feature.
Up to 3 plugins free · no card required.
All fields and original values.
These are saved file metadata. Open a changed file to read its text edits.
Package file
Sep 30, 2026 · 23:13 UTC
Not present
Nov 12, 2026 · 06:08 UTC
{"sha256":"cb5059cab8f88822aa8484ecebd5488dfe148145faa1990da96e10a619550165","size":499}
Package file
Sep 30, 2026 · 23:13 UTC
{"sha256":"d693f4e16e2a73d7f8765d97642fa8f01c2fbb8e29bb383fcf1ecd797afb0b18","size":7865}
Nov 12, 2026 · 06:08 UTC
Not present
Package file
Sep 30, 2026 · 23:13 UTC
{"sha256":"d693f4e16e2a73d7f8765d97642fa8f01c2fbb8e29bb383fcf1ecd797afb0b18","size":7865}
Nov 12, 2026 · 06:08 UTC
Not present
Package file
Sep 30, 2026 · 23:13 UTC
{"sha256":"d693f4e16e2a73d7f8765d97642fa8f01c2fbb8e29bb383fcf1ecd797afb0b18","size":7865}
Nov 12, 2026 · 06:08 UTC
Not present
Compare saved observations
Download comparison JSONChanged files
Choose a file to see its text changes. Binary or large files show metadata only.
.codex-plugin/assets/composer-icon.png →
.codex-plugin/assets/logo-dark.png →
.codex-plugin/assets/logo.png →
scripts/yaps-cli-discovery.mjs →
scripts/yaps-plugin-runner.mjs
− removed · + added
--- before +++ after @@ -106,10 +106,17 @@ if (value.includes("enoent") || value.includes("local_yaps_unreachable")) return "local_yaps_unreachable"; if (value.includes("keychain_unavailable")) return "credential_unavailable"; if (value.includes("verification_unavailable") || value.includes("refresh_failed")) return "account_cache_incomplete"; - for (const code of ["settings_path_mismatch", "credential_unavailable", "credential_missing", "account_cache_incomplete", "profile_lookup_failed", "platform_mismatch", "unauthenticated"]) { + for (const code of ["settings_path_mismatch", "desktop_account_unavailable", "credential_unavailable", "credential_missing", "account_cache_incomplete", "profile_lookup_failed", "platform_mismatch", "unauthenticated"]) { if (value.includes(code)) return code; } - if (value.includes("permission") || value.includes("denied")) return "permission_denied"; + if ( + value.includes("permission") || + value.includes("denied") || + value.includes("eperm") || + value.includes("eacces") || + value.includes("operation not permitted") || + value.includes("not permitted") + ) return "permission_denied"; if (value.includes("model") && (value.includes("unavailable") || value.includes("not found"))) return "model_unavailable"; if (value.includes("network") || value.includes("offline") || value.includes("econn")) return "network_unavailable"; if (value.includes("timeout") || value.includes("timed out")) return "timeout"; @@ -119,6 +126,16 @@ return "unknown"; } +// Yaps CLI exit codes (documented in `yaps --help`): 2 usage, 3 not_found, +// 130 cancelled. Text classification wins when it is more specific. +function classifyExit(code, output, launchError, yapsCli) { + const fromText = classifyError(output, launchError); + if (fromText !== "unknown" || !yapsCli) return fromText; + if (code === 2) return "invalid_input"; + if (code === 3) return "not_found"; + return "unknown"; +} + function pruneInbox(inbox) { try { const entries = readdirSync(inbox) @@ -177,10 +194,54 @@ const context = ownerKey && identity ? { root, ownerKey, identity, host, action: parsed.action, stage: parsed.stage } : null; const operationId = randomUUID(); const started = Date.now(); +let terminalWritten = false; +let cancelled = false; +let child = null; + +function finishOnce(status, errorCode = null) { + if (terminalWritten) return false; + terminalWritten = true; + writeEvent(context, status, operationId, errorCode, Date.now() - started); + return true; +} + writeEvent(context, "attempt", operationId); +// Reasons and thrown values can contain customer content, paths, or command +// output. Deliberately ignore them and persist only the reviewed `unknown` +// diagnostic. `uncaughtExceptionMonitor` observes without changing Node's +// normal fatal-exception behavior. +process.once("uncaughtExceptionMonitor", () => { + finishOnce("failure", "unknown"); +}); +process.once("unhandledRejection", () => { + finishOnce("failure", "unknown"); + process.exitCode = 1; +}); + +// Node runs `exit` listeners synchronously. This is the last cooperative +// boundary for a runner that reaches process teardown without a child `close` +// callback. It cannot run for SIGKILL, Windows TerminateProcess, power loss, or +// an OS crash. +process.once("exit", () => { + finishOnce(cancelled ? "cancelled" : "failure", cancelled ? "cancelled" : "unknown"); +}); + +for (const signal of ["SIGINT", "SIGTERM"]) { + process.once(signal, () => { + cancelled = true; + finishOnce("cancelled", "cancelled"); + if (child) { + try { child.kill(signal); } catch {} + } else { + process.exit(signal === "SIGINT" ? 130 : 143); + } + }); +} + let [command, ...commandArguments] = parsed.command; -if (isYapsCliCommand(command)) { +const runsYapsCli = isYapsCliCommand(command); +if (runsYapsCli) { const commandIsPath = command !== basename(command); const accountPreflight = isAuthStatusCommand(commandArguments); const requiresActiveAccount = commandRequiresActiveAccount(commandArguments); @@ -191,14 +252,14 @@ }); if (!session.path) { const failure = classifyCliResolutionFailure(session); - writeEvent(context, "failure", operationId, failure.code, Date.now() - started); + finishOnce("failure", failure.code); process.stderr.write(`${failure.message}\n`); process.exit(failure.exitCode); } if (accountPreflight) { const account = diagnoseAccount(session); if (session.authStatusSafety !== "safe" || !session.auth) { - writeEvent(context, "failure", operationId, account.code, Date.now() - started); + finishOnce("failure", account.code); process.stderr.write(`${account.message}\n`); process.exit(78); } @@ -208,36 +269,35 @@ diagnostic_code: session.auth.diagnosticCode, credential_status: "not_accessed", }; - writeEvent(context, "success", operationId, null, Date.now() - started); + if (account.code === "ready") finishOnce("success"); + else finishOnce("failure", account.code); process.stdout.write(`${JSON.stringify(sanitized, null, commandArguments.includes("--pretty") ? 2 : 0)}\n`); process.exit(0); } if (requiresActiveAccount) { const account = diagnoseAccount(session); if (account.code !== "ready") { - writeEvent(context, "failure", operationId, account.code, Date.now() - started); + finishOnce("failure", account.code); process.stderr.write(`${account.message}\n`); process.exit(77); } } command = session.path; - commandArguments = applyResolvedSettings(commandArguments, session.settingsPath); + commandArguments = applyResolvedSettings(commandArguments, session.settingsPath, { + followDesktopAccount: session.auth?.diagnosticCode === "followed_desktop_account", + }); } let outputTail = Buffer.alloc(0); let launchError = null; -let cancelled = false; -const child = spawn(command, commandArguments, { env: process.env, stdio: ["inherit", "pipe", "pipe"], windowsHide: true }); +child = spawn(command, commandArguments, { env: process.env, stdio: ["inherit", "pipe", "pipe"], windowsHide: true }); child.stdout.on("data", (chunk) => { outputTail = appendTail(outputTail, chunk); process.stdout.write(chunk); }); child.stderr.on("data", (chunk) => { outputTail = appendTail(outputTail, chunk); process.stderr.write(chunk); }); child.on("error", (error) => { launchError = error; }); -for (const signal of ["SIGINT", "SIGTERM"]) { - process.on(signal, () => { cancelled = true; try { child.kill(signal); } catch {} }); -} child.on("close", (code, signal) => { - const duration = Date.now() - started; - if (cancelled || signal) writeEvent(context, "cancelled", operationId, "cancelled", duration); - else if (code === 0) writeEvent(context, "success", operationId, null, duration); - else writeEvent(context, "failure", operationId, classifyError(outputTail.toString("utf8"), launchError), duration); - process.exitCode = code ?? (signal ? 1 : 127); + // A Yaps CLI stopped by Ctrl-C/SIGTERM (or `jobs cancel`) cleans up and exits 130. + if (cancelled || signal || code === 130) finishOnce("cancelled", "cancelled"); + else if (code === 0) finishOnce("success"); + else finishOnce("failure", classifyExit(code, outputTail.toString("utf8"), launchError, runsYapsCli)); + process.exitCode ??= code ?? (signal ? 1 : 127); });
Full technical diff · 13 changed fields
added /files/.claude-plugin~1plugin.json
Field was absent
{
"sha256": "cb5059cab8f88822aa8484ecebd5488dfe148145faa1990da96e10a619550165",
"size": 499
}removed /files/.codex-plugin~1assets~1composer-icon.png
{
"sha256": "d693f4e16e2a73d7f8765d97642fa8f01c2fbb8e29bb383fcf1ecd797afb0b18",
"size": 7865
}Field is absent
removed /files/.codex-plugin~1assets~1logo-dark.png
{
"sha256": "d693f4e16e2a73d7f8765d97642fa8f01c2fbb8e29bb383fcf1ecd797afb0b18",
"size": 7865
}Field is absent
removed /files/.codex-plugin~1assets~1logo.png
{
"sha256": "d693f4e16e2a73d7f8765d97642fa8f01c2fbb8e29bb383fcf1ecd797afb0b18",
"size": 7865
}Field is absent
changed /files/.codex-plugin~1plugin.json/sha256
"c8480186b56d17c135fcc317a9cac513dbae205a4a59870245eb125217c660db"
"e6337758779d65dc57ca0db201a648846c7e9d862e38cb56b41da5f5a75592be"
changed /files/.codex-plugin~1plugin.json/size
2649
2616
added /files/plugin.json
Field was absent
{
"sha256": "c896282eb5718b4d05459325fffd0874869bb1c192c79e571a2fc8a975b80763",
"size": 2830
}changed /files/scripts~1yaps-cli-discovery.mjs/sha256
"2264b812911bf5275f31d1f27f24f483269577a213fc97be7f36fc91a6b1bfc8"
"1d3808134d03a4d19f2b2eac3acea2d6af4b7538bcc0da84afe43bce09eca257"
changed /files/scripts~1yaps-cli-discovery.mjs/size
41185
50423
changed /files/scripts~1yaps-plugin-runner.mjs/sha256
"c5959de172d2c855d7edb39c433dd117dd1946719fe217486483d7b445a9619d"
"af9fc263e016cb959379f68fea158891d65e774b0457ed475f0a156f12ce34c9"
changed /files/scripts~1yaps-plugin-runner.mjs/size
10993
12836
changed /files/skills~1yaps-background-removal~1SKILL.md/sha256
"2fc4ab830f04c4e424954218fb51306d408dd0a59e5fdafd0ef3301b174b157c"
"924b2189a0c90fe09a3293bbfff5e2c65c33178bb5bfdfdbcd64a29972ef657a"
changed /files/skills~1yaps-background-removal~1SKILL.md/size
12382
12072
Full snapshot data
{
"files": {
".claude-plugin/plugin.json": {
"sha256": "cb5059cab8f88822aa8484ecebd5488dfe148145faa1990da96e10a619550165",
"size": 499
},
".codex-plugin/plugin.json": {
"sha256": "e6337758779d65dc57ca0db201a648846c7e9d862e38cb56b41da5f5a75592be",
"size": 2616
},
"README.md": {
"sha256": "003db95c89124f0633210dc427c65780e86c5e766ce9ed164cbe6405fadc6c14",
"size": 1896
},
"assets/yaps-icon.png": {
"sha256": "d693f4e16e2a73d7f8765d97642fa8f01c2fbb8e29bb383fcf1ecd797afb0b18",
"size": 7865
},
"plugin.json": {
"sha256": "c896282eb5718b4d05459325fffd0874869bb1c192c79e571a2fc8a975b80763",
"size": 2830
},
"scripts/yaps-cli-discovery.mjs": {
"sha256": "1d3808134d03a4d19f2b2eac3acea2d6af4b7538bcc0da84afe43bce09eca257",
"size": 50423
},
"scripts/yaps-plugin-runner.mjs": {
"sha256": "af9fc263e016cb959379f68fea158891d65e774b0457ed475f0a156f12ce34c9",
"size": 12836
},
"skills/yaps-background-removal/SKILL.md": {
"sha256": "924b2189a0c90fe09a3293bbfff5e2c65c33178bb5bfdfdbcd64a29972ef657a",
"size": 12072
},
"skills/yaps-background-removal/agents/openai.yaml": {
"sha256": "96125fd5e7c5b8316e8bb2b36b79076fa75b5b1e7bafa10cffc02def969deeef",
"size": 192
}
}
}SHA-256 of public snapshot: a675169d0816b02236f3ba106ab2fa3d54cfefd6b1412cefc8070829cfd816ac