Update to Yaps Subtitle Generator
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":"6d21b70c3bc86d33cb0f5119e7426c63dc176a2cd86f28c50ed714b01d24cf99","size":497}
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": "6d21b70c3bc86d33cb0f5119e7426c63dc176a2cd86f28c50ed714b01d24cf99",
"size": 497
}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
"5f7c35b3a66f43f628e6f920b5e38211a68f90fa4ec61f07264e7f415257c17f"
"61b454faf81f239117f418e3c20612af30d52630440b1bb3740f7e5469eb0570"
changed /files/.codex-plugin~1plugin.json/size
2268
2244
added /files/plugin.json
Field was absent
{
"sha256": "02bdbb897b423fc118945ca093791462ca0b790bf591b1efb53bb8128079c6ae",
"size": 2458
}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-srt-generator~1SKILL.md/sha256
"acacbc28caadafcba2e136d0af0168ecd829678d3c76f4edcb7ed8c15c55deed"
"b719aa1ac47342002bc6f12387342e6b2855c9b284a5ee00aa5eb6edc05a4dc3"
changed /files/skills~1yaps-srt-generator~1SKILL.md/size
10903
11081
Full snapshot data
{
"files": {
".claude-plugin/plugin.json": {
"sha256": "6d21b70c3bc86d33cb0f5119e7426c63dc176a2cd86f28c50ed714b01d24cf99",
"size": 497
},
".codex-plugin/plugin.json": {
"sha256": "61b454faf81f239117f418e3c20612af30d52630440b1bb3740f7e5469eb0570",
"size": 2244
},
"README.md": {
"sha256": "12b1113e0f47506a7491263b103cec94a0a43668f1e474bed2140f0c178a8932",
"size": 1676
},
"assets/yaps-icon.png": {
"sha256": "d693f4e16e2a73d7f8765d97642fa8f01c2fbb8e29bb383fcf1ecd797afb0b18",
"size": 7865
},
"plugin.json": {
"sha256": "02bdbb897b423fc118945ca093791462ca0b790bf591b1efb53bb8128079c6ae",
"size": 2458
},
"scripts/yaps-cli-discovery.mjs": {
"sha256": "1d3808134d03a4d19f2b2eac3acea2d6af4b7538bcc0da84afe43bce09eca257",
"size": 50423
},
"scripts/yaps-plugin-runner.mjs": {
"sha256": "af9fc263e016cb959379f68fea158891d65e774b0457ed475f0a156f12ce34c9",
"size": 12836
},
"skills/yaps-srt-generator/SKILL.md": {
"sha256": "b719aa1ac47342002bc6f12387342e6b2855c9b284a5ee00aa5eb6edc05a4dc3",
"size": 11081
},
"skills/yaps-srt-generator/agents/openai.yaml": {
"sha256": "9dd63efd18e4b43e7fa851f90807ec6a9a4d497207b9bd04bc4ecd1bc20b8bc6",
"size": 194
}
}
}SHA-256 of public snapshot: 11f46508ca5510bbf794f6795d642bf35ef091fd2088953089ec96a027752846