Update to Yaps Dictation
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":"be862377d658804f6c5f40a2ad3c604f5fbb5e4c3c2b4a63703ac27be46ecb13","size":495}
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": "be862377d658804f6c5f40a2ad3c604f5fbb5e4c3c2b4a63703ac27be46ecb13",
"size": 495
}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
"49349a9b79d61b782b137d465cecf4ae08c8fda743a688a0c73cb8f42752122d"
"3b03b1520ee0f02e97df2204c371d8b8efac544e89a7918ff5f4881651c9ab53"
changed /files/.codex-plugin~1plugin.json/size
2091
2067
added /files/plugin.json
Field was absent
{
"sha256": "edae9b664ae604a24eed9756db4d4686f9d26516721c7da8c228728bb0cccf74",
"size": 2269
}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-dictation~1SKILL.md/sha256
"adb90d54b35b8286de921a6727212e78fcbedd17bd7f10e5834b231d467cfa9b"
"42da4fe9ccd26a7cffc1cef9fd93db553e60981bf0dceab7ed42678cce344e4d"
changed /files/skills~1yaps-dictation~1SKILL.md/size
11434
11612
Full snapshot data
{
"files": {
".claude-plugin/plugin.json": {
"sha256": "be862377d658804f6c5f40a2ad3c604f5fbb5e4c3c2b4a63703ac27be46ecb13",
"size": 495
},
".codex-plugin/plugin.json": {
"sha256": "3b03b1520ee0f02e97df2204c371d8b8efac544e89a7918ff5f4881651c9ab53",
"size": 2067
},
"README.md": {
"sha256": "77784e1462c2066930fd2ce32a3aa08ac63da2278203fe86d9f4831cb26a1025",
"size": 1818
},
"assets/yaps-icon.png": {
"sha256": "d693f4e16e2a73d7f8765d97642fa8f01c2fbb8e29bb383fcf1ecd797afb0b18",
"size": 7865
},
"plugin.json": {
"sha256": "edae9b664ae604a24eed9756db4d4686f9d26516721c7da8c228728bb0cccf74",
"size": 2269
},
"scripts/yaps-cli-discovery.mjs": {
"sha256": "1d3808134d03a4d19f2b2eac3acea2d6af4b7538bcc0da84afe43bce09eca257",
"size": 50423
},
"scripts/yaps-plugin-runner.mjs": {
"sha256": "af9fc263e016cb959379f68fea158891d65e774b0457ed475f0a156f12ce34c9",
"size": 12836
},
"skills/yaps-dictation/SKILL.md": {
"sha256": "42da4fe9ccd26a7cffc1cef9fd93db553e60981bf0dceab7ed42678cce344e4d",
"size": 11612
},
"skills/yaps-dictation/agents/openai.yaml": {
"sha256": "2be3297a1e9b97a1ec98ff2e4b4967e28cb17c7847cfb1e150232bc69dc63c17",
"size": 186
}
}
}SHA-256 of public snapshot: ff97b3822c5b1c54580bf694ec8dd8075fb6fbe4875add783cbbfad500d388af