wyrm-mcp 9.2.0 → 9.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/auto-runs.js +1 -0
- package/dist/autoconfig.js +3 -3
- package/dist/capabilities.js +3 -3
- package/dist/causality.js +13 -8
- package/dist/cli.js +25 -22
- package/dist/cloud/cli.js +3 -3
- package/dist/cloud/sync-daemon-entrypoint.js +2 -2
- package/dist/cloud/sync-daemon.js +1 -1
- package/dist/color.js +1 -0
- package/dist/database.js +3 -3
- package/dist/deprecations.js +2 -2
- package/dist/events.js +6 -6
- package/dist/federation.js +10 -10
- package/dist/handlers/arg-keys.js +1 -0
- package/dist/handlers/capture.js +58 -58
- package/dist/handlers/causality.js +8 -8
- package/dist/handlers/cloud.js +85 -83
- package/dist/handlers/companion.js +10 -10
- package/dist/handlers/entity.js +1 -1
- package/dist/handlers/events.js +12 -12
- package/dist/handlers/failure.js +12 -12
- package/dist/handlers/goals.js +4 -4
- package/dist/handlers/intelligence.js +63 -63
- package/dist/handlers/mcpclient.js +1 -1
- package/dist/handlers/presence.js +3 -3
- package/dist/handlers/project-arg.js +1 -0
- package/dist/handlers/project.js +1 -1
- package/dist/handlers/quest.js +5 -3
- package/dist/handlers/recall.js +18 -18
- package/dist/handlers/registry.js +1 -1
- package/dist/handlers/resources.js +1 -1
- package/dist/handlers/review.js +3 -3
- package/dist/handlers/run.js +3 -3
- package/dist/handlers/search.js +3 -3
- package/dist/handlers/session.js +24 -24
- package/dist/handlers/share.js +5 -5
- package/dist/handlers/shims.js +1 -1
- package/dist/handlers/thread.js +2 -2
- package/dist/http-auth.js +1 -1
- package/dist/http-fast.js +15 -15
- package/dist/index.js +2 -2
- package/dist/logger.js +2 -2
- package/dist/receipt.js +1 -1
- package/dist/rehydration.js +24 -9
- package/dist/render.js +3 -3
- package/dist/setup.js +2 -3
- package/dist/sqlite-busy.js +1 -1
- package/dist/stale-servers.js +2 -0
- package/dist/stdio-lifecycle.js +1 -0
- package/dist/storage/index.js +3 -3
- package/dist/tool-manifest-v2.json +1 -1
- package/dist/tool-manifest.json +1 -1
- package/dist/ui-dashboard.js +9 -8
- package/dist/validate.js +1 -1
- package/dist/vault-exec.js +4 -0
- package/dist/vault.js +1 -1
- package/dist/wyrm-cli.js +105 -142
- package/dist/wyrm-manifest.json +3 -3
- package/dist/wyrm-ui.js +14 -7
- package/dist/wyrm.js +2 -0
- package/package.json +6 -4
- package/scripts/hooks/wyrm-citation-audit.mjs +155 -46
- package/scripts/hooks/wyrm-prompt-context.mjs +300 -0
- package/scripts/hooks/wyrm-run-auto.mjs +148 -37
- package/scripts/hooks/wyrm-session-rehydrate.mjs +142 -24
package/dist/tool-manifest.json
CHANGED
package/dist/ui-dashboard.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import{resolveBranding as n}from"./branding.js";function
|
|
1
|
+
import{resolveBranding as n}from"./branding.js";function i(t,a){const e=t??n(!1),r=JSON.stringify(a??"");return`<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'
|
|
6
|
+
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; connect-src 'self'; img-src 'self' data:; frame-ancestors 'none'">
|
|
7
7
|
<title>${e.product} Dashboard</title>
|
|
8
|
-
<link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
9
|
-
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
|
10
8
|
<style>
|
|
11
9
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
12
10
|
:root {
|
|
13
|
-
/* ghosts.lk Stealth-Silver: #050505 base, silver primary, green LED
|
|
11
|
+
/* ghosts.lk Stealth-Silver: #050505 base, silver primary, green LED.
|
|
12
|
+
Type is a local stack with no font download: a local-first dashboard must
|
|
13
|
+
make no off-box request and must look the same offline. Geist and
|
|
14
|
+
JetBrains Mono are used only when already installed on the machine. */
|
|
14
15
|
--bg: #050505;
|
|
15
16
|
--card: #0a0a0a;
|
|
16
17
|
--border: #1a1a1a;
|
|
@@ -21,10 +22,10 @@ import{resolveBranding as n}from"./branding.js";function o(t,a){const e=t??n(!1)
|
|
|
21
22
|
--neu: #9a9ca1;
|
|
22
23
|
--text: #fafafa;
|
|
23
24
|
--muted: oklch(0.70 0.01 250);
|
|
24
|
-
--mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
25
|
+
--mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
|
|
25
26
|
--nav-h: 56px;
|
|
26
27
|
}
|
|
27
|
-
html, body { height: 100%; background: var(--bg); color: var(--text); font-family: "Geist", ui-sans-serif, system-ui, -apple-system, sans-serif; font-size: 14px; line-height: 1.5; }
|
|
28
|
+
html, body { height: 100%; background: var(--bg); color: var(--text); font-family: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; font-size: 14px; line-height: 1.5; }
|
|
28
29
|
/* NAV */
|
|
29
30
|
nav {
|
|
30
31
|
position: fixed; top: 0; left: 0; right: 0; height: var(--nav-h);
|
|
@@ -1185,4 +1186,4 @@ loadAccount().then(router);
|
|
|
1185
1186
|
})();
|
|
1186
1187
|
<\/script>
|
|
1187
1188
|
</body>
|
|
1188
|
-
</html>`}export{
|
|
1189
|
+
</html>`}export{i as getUIDashboardHTML};
|
package/dist/validate.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
class
|
|
1
|
+
class u extends Error{field;constructor(e,n){super(`'${e}' ${n}`),this.name="ValidationError",this.field=e}}const o=r=>r==null;function w(r,e,n={}){if(o(e))return n.default;let t;if(typeof e=="number")t=e;else if(typeof e=="string"&&/^[+-]?\d+$/.test(e.trim()))t=Number(e.trim());else throw new u(r,"must be an integer");if(!Number.isInteger(t))throw new u(r,"must be an integer");if(n.min!==void 0&&t<n.min)throw new u(r,`must be >= ${n.min}`);if(n.max!==void 0&&t>n.max)throw new u(r,`must be <= ${n.max}`);return t}function b(r,e,n={}){const t=w(r,e,n);if(t===void 0)throw new u(r,"is required");return t}function $(r,e,n={}){if(o(e))return n.default;let t;if(typeof e=="number")t=e;else if(typeof e=="string"&&e.trim()!==""&&Number.isFinite(Number(e)))t=Number(e);else throw new u(r,"must be a number");if(!Number.isFinite(t))throw new u(r,"must be a finite number");if(n.min!==void 0&&t<n.min)throw new u(r,`must be >= ${n.min}`);if(n.max!==void 0&&t>n.max)throw new u(r,`must be <= ${n.max}`);return t}function c(r,e,n={}){if(o(e))return n.default;if(typeof e!="string")throw new u(r,"must be a string");if(n.minLen!==void 0&&e.length<n.minLen)throw new u(r,`must be at least ${n.minLen} characters`);if(n.maxLen!==void 0&&e.length>n.maxLen)throw new u(r,`must be at most ${n.maxLen} characters`);if(n.pattern&&!n.pattern.test(e))throw new u(r,"has an invalid format");return e}function y(r,e,n={}){const t=c(r,e,n);if(t===void 0)throw new u(r,"is required");return t}function d(r,e,n){if(o(e))return n;if(typeof e=="boolean")return e;if(e==="true"||e==="1"||e===1)return!0;if(e==="false"||e==="0"||e===0)return!1;throw new u(r,"must be a boolean")}function L(r,e){const n=d(r,e);if(n===void 0)throw new u(r,"is required (true or false)");return n}function N(r,e,n){if(typeof e=="string"){const t=e.trim(),i=/^(?:([a-z_]+):|#)(\d+)$/.exec(t);if(i){if(i[1]!==void 0&&n!==void 0&&i[1]!==n)throw new u(r,`must be a ${n} id (got a ${i[1]} ref)`);return w(r,i[2],{min:1})}}return w(r,e,{min:1})}function A(r,e,n,t){if(o(e))return t;if(typeof e!="string"||!n.includes(e))throw new u(r,`must be one of: ${n.join(", ")}`);return e}function p(r,e,n={}){if(o(e))return;const t=typeof e=="string"?e.split(",").map(i=>i.trim()).filter(Boolean):e;if(!Array.isArray(t))throw new u(r,"must be an array of strings (or a comma-separated string)");return x(r,t,n)}function g(r,e){const n=Array.from({length:r.length+1},(t,i)=>[i,...new Array(e.length).fill(0)]);for(let t=1;t<=e.length;t++)n[0][t]=t;for(let t=1;t<=r.length;t++)for(let i=1;i<=e.length;i++)n[t][i]=Math.min(n[t-1][i]+1,n[t][i-1]+1,n[t-1][i-1]+(r[t-1]===e[i-1]?0:1)),t>1&&i>1&&r[t-1]===e[i-2]&&r[t-2]===e[i-1]&&(n[t][i]=Math.min(n[t][i],n[t-2][i-2]+1));return n[r.length][e.length]}function l(r,e){const n=a=>a.toLowerCase().replace(/[_-]/g,""),t=n(r);let i,s=Math.max(1,Math.floor(t.length/4))+1;for(const a of e){const f=g(t,n(a));f<s&&(i=a,s=f)}return i}function I(r,e,n){let t=!1;const i=r.map((a,f)=>{const m=l(a,e);m===void 0&&(t=!0);const h=f===0?"is not a known argument":`'${a}' is not a known argument`;return m===void 0?h:`${h} (did you mean '${m}'?)`}),s=t&&n.length>0?`. Accepted: ${n.join(", ")}`:"";return new u(r[0],i.join("; ")+s)}function x(r,e,n={}){if(!o(e)){if(!Array.isArray(e))throw new u(r,"must be an array");if(n.maxItems!==void 0&&e.length>n.maxItems)throw new u(r,`must have at most ${n.maxItems} items`);return e.map((t,i)=>{if(typeof t!="string")throw new u(`${r}[${i}]`,"must be a string");if(n.maxLen!==void 0&&t.length>n.maxLen)throw new u(`${r}[${i}]`,`must be at most ${n.maxLen} characters`);return t})}}export{u as ValidationError,d as asBool,A as asEnum,N as asId,w as asInt,$ as asNumber,c as asString,x as asStringArray,p as asTags,l as closestName,L as requireBool,b as requireInt,y as requireString,I as unknownKeysError};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{spawn as h}from"node:child_process";import{writeSync as I}from"node:fs";import{constants as y}from"node:os";import{isatty as v}from"node:tty";import{shouldUseColor as _}from"./color.js";import{PARENT_POLL_MS as g,pidAlive as A}from"./stdio-lifecycle.js";import{KeyringUnavailableError as E,vaultGet as T}from"./vault.js";const C=["SIGINT","SIGTERM","SIGHUP"],M=1e4;function m(t){try{I(2,t)}catch{}}function f(t){const e=_(process.env,v(1));m(`\u274C ${e?"\x1B[91m":""}${t}${e?"\x1B[0m":""}
|
|
2
|
+
`)}async function $(t){const e=process.env.WYRM_VAULT_WAIT_SECONDS,n=Number(e),o=e===void 0||e.trim()===""||!Number.isFinite(n)?90:n,i=v(0)||o<=0?0:o*1e3,r=Date.now()+i;let a=1e3,p=!1;for(;;)try{return t()}catch(d){const s=r-Date.now();if(!(d instanceof E)||s<=0)throw d;p||(p=!0,m(`wyrm vault: the OS keyring is locked or not available yet (${d.detail}); waiting up to ${Math.round(i/1e3)}s for it. Set WYRM_VAULT_WAIT_SECONDS=0 to fail at once.
|
|
3
|
+
`)),await new Promise(l=>{setTimeout(l,Math.min(a,s))}),a=Math.min(a*2,1e4)}}function R(t){const e=t[0],n=t.indexOf("--");if(!e||n===-1||n+1>=t.length)return null;const o=t.slice(1,n),i=o.indexOf("--as"),r=i>=0?o[i+1]:e.toUpperCase().replace(/[^A-Z0-9]+/g,"_");return!r||r.includes("=")||r.includes("\0")?null:{name:e,envVar:r,command:t.slice(n+1)}}async function V(t){const e=R(t);if(!e){f("usage: wyrm vault exec <name> [--as ENVVAR] -- <command...>"),process.exitCode=1;return}let n;try{n=await $(()=>T(e.name))}catch(o){f(`vault: ${o.message}`),process.exitCode=1;return}if(n===void 0){f(`no secret named "${e.name}"`),process.exitCode=1;return}await L(e.command,e.envVar,n)}function L(t,e,n){return new Promise(()=>{const[o,...i]=t,r=h(o,i,{stdio:"inherit",env:{...process.env,[e]:n}});let a=!1,p;const d=C.map(c=>{const u=()=>{r.kill(c)};return process.on(c,u),[c,u]}),s=process.ppid,l=setInterval(()=>{process.ppid===s&&A(s)||(clearInterval(l),m(`wyrm vault exec: parent process ${s} exited; stopping ${o}
|
|
4
|
+
`),r.kill("SIGTERM"),p=setTimeout(()=>{r.exitCode===null&&r.signalCode===null&&r.kill("SIGKILL")},M))},g);l.unref(),s<=1&&clearInterval(l);const x=(c,u)=>{if(!a){a=!0,clearInterval(l),clearTimeout(p);for(const[w,S]of d)process.off(w,S);if(u){process.exitCode=128+(y.signals[u]??0),process.kill(process.pid,u);return}process.exit(c??1)}};r.once("exit",x),r.on("error",c=>{r.pid===void 0&&(f(`vault exec: could not run ${o}: ${c.message}`),x(1,null))})})}export{M as ORPHAN_KILL_GRACE_MS,R as parseVaultExecArgs,V as vaultExec,$ as withKeyringWait};
|
package/dist/vault.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createCipheriv as
|
|
1
|
+
import{createCipheriv as Q,createDecipheriv as Z,randomBytes as d,scryptSync as N,timingSafeEqual as ee}from"node:crypto";import{existsSync as o,readFileSync as u,writeFileSync as R,mkdirSync as T,chmodSync as S,unlinkSync as w,statSync as te,copyFileSync as F,openSync as re,fsyncSync as ne,closeSync as ie,writeSync as oe}from"node:fs";import{execFileSync as l}from"node:child_process";import{homedir as se,platform as k}from"node:os";import{join as A}from"node:path";const D="aes-256-gcm",m=12,M=16,f="wyrm-vault",J="Wyrm Vault master key";function a(){return process.env.WYRM_VAULT_DIR||A(se(),".wyrm")}function i(){return A(a(),"vault.enc")}function y(){return A(a(),"vault.key")}function ae(){return A(a(),"vault.salt")}function x(){return A(a(),"vault.meta")}function V(){const e=ae();if(o(e))return u(e);T(a(),{recursive:!0,mode:448});const t=o(i())?Buffer.from("wyrm-vault-v1"):d(16);R(e,t,{mode:384});try{S(e,384)}catch{}return t}function ce(){try{const e=JSON.parse(u(x(),"utf8"));if(e.backend==="keychain"||e.backend==="passphrase"||e.backend==="keyfile")return e.backend}catch{}return null}function L(e){try{T(a(),{recursive:!0,mode:448}),R(x(),JSON.stringify({backend:e,v:1}),{mode:384});try{S(x(),384)}catch{}}catch{}}function P(){return process.env.WYRM_VAULT_SECRETTOOL||"secret-tool"}function v(){return a()}function j(e){return!!e&&typeof e=="object"&&e.code==="ENOENT"}class Y extends Error{detail;code="WYRM_KEYRING_UNAVAILABLE";constructor(t){super(`the OS keyring is locked or unavailable (${t}), so the vault master key cannot be read. Unlock your login keyring and retry, or set WYRM_VAULT_PASSPHRASE if this vault uses a passphrase.`),this.detail=t,this.name="KeyringUnavailableError"}}function ue(e,t){const r=e,n=String(r.stderr??"").trim();if(r.code==="ETIMEDOUT"||r.signal)throw new Y(`lookup timed out${r.signal?` (${r.signal})`:""}`);if(t){if(r.status===44)return;throw new Y(n||`security exited ${r.status??"abnormally"}`)}if(!(r.status===1&&n===""))throw new Y(n||`secret-tool exited ${r.status??"abnormally"}`)}function O(){try{if(k()==="darwin"){const n=l("security",["find-generic-password","-s",f,"-a",v(),"-w"],{timeout:8e3,encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim();return n?Buffer.from(n,"base64"):void 0}const t=l(P(),["lookup","service",f,"path",v()],{timeout:8e3,encoding:"utf8",stdio:["ignore","pipe","pipe"]}).trim();return t?Buffer.from(t,"base64"):void 0}catch(e){if(j(e))throw new Error("OS keychain CLI not found (install libsecret/`secret-tool`), or use WYRM_VAULT_PASSPHRASE / `wyrm vault secure --backend passphrase`.");return ue(e,k()==="darwin")}}function H(e){const t=e.toString("base64");if(k()==="darwin"){l("security",["add-generic-password","-U","-s",f,"-a",v(),"-l",J,"-w",t],{timeout:8e3,stdio:["ignore","ignore","ignore"]});return}l(P(),["store","--label",J,"service",f,"path",v()],{timeout:8e3,input:t,stdio:["pipe","ignore","ignore"]})}function G(){try{k()==="darwin"?l("security",["delete-generic-password","-s",f,"-a",v()],{timeout:8e3,stdio:["ignore","ignore","ignore"]}):l(P(),["clear","service",f,"path",v()],{timeout:8e3,stdio:["ignore","ignore","ignore"]})}catch{}}function K(){try{return k()==="darwin"?(l("security",["find-generic-password","-s",f,"-a","__wyrm_probe__"],{timeout:8e3,stdio:["ignore","ignore","ignore"]}),!0):(l(P(),["lookup","service",f,"path","__wyrm_probe__"],{timeout:8e3,stdio:["ignore","ignore","ignore"]}),!0)}catch(e){if(j(e))return!1;const t=e.status;return t===1||k()==="darwin"&&t===44}}function le(){try{return O()!==void 0}catch{return!1}}function B(){if(process.env.WYRM_VAULT_PASSPHRASE)return"passphrase";const e=(process.env.WYRM_VAULT_BACKEND||"auto").toLowerCase();if(e==="passphrase"||e==="keychain"||e==="keyfile")return e;if(o(i())){const t=ce();if(t)return t}return le()?"keychain":o(y())?"keyfile":K()?"keychain":"keyfile"}function q(){const e=B(),t=o(i());if(e==="passphrase"){const n=process.env.WYRM_VAULT_PASSPHRASE;if(!n)throw new Error("passphrase backend selected but WYRM_VAULT_PASSPHRASE is not set.");return t||L("passphrase"),N(n,V(),32)}if(e==="keychain"){let n=O();if(!n){if(t)throw new Error("vault.enc exists but its master key is not in the OS keychain (keyring locked/unavailable, or the key was cleared). Unlock your login keyring and retry, or set WYRM_VAULT_PASSPHRASE if this vault uses a passphrase. Refusing to mint a new key \u2014 it cannot decrypt your existing secrets and would orphan them.");n=d(32),H(n),L("keychain")}if(n.length!==32)throw new Error("keychain holds a malformed master key (expected 32 bytes).");return n}const r=y();if(!o(r)){if(t)throw new Error("vault.enc exists but vault.key is missing \u2014 this vault was likely created under a different backend (keychain/passphrase). Unlock your OS keyring or set WYRM_VAULT_PASSPHRASE. Refusing to mint a new keyfile \u2014 it cannot decrypt your existing secrets and would orphan them.");T(a(),{recursive:!0,mode:448});const n=d(32);R(r,n,{mode:384});try{S(r,384)}catch{}return L("keyfile"),n}return u(r)}function U(e,t){if(e.length<m+M)throw new Error("vault file is corrupt (too short)");const r=e.subarray(0,m),n=e.subarray(m,m+M),h=e.subarray(m+M),c=Z(D,t,r);c.setAuthTag(n);const W=Buffer.concat([c.update(h),c.final()]);return JSON.parse(W.toString("utf8"))}function fe(e,t){const r=d(m),n=Q(D,t,r),h=Buffer.concat([n.update(JSON.stringify(e),"utf8"),n.final()]),c=n.getAuthTag();return Buffer.concat([r,c,h])}function ye(e){const t=i();if(!o(t))return{};try{return U(u(t),e)}catch{throw new Error("vault decrypt failed \u2014 wrong key/passphrase, or the vault was tampered with.")}}function z(e,t){T(a(),{recursive:!0,mode:448}),R(i(),fe(e,t),{mode:384});try{S(i(),384)}catch{}}function b(){return o(i())?ye(q()):{}}function X(e){z(e,q())}function Ae(e,t){if(!e||!/^[\w.\-:/@]+$/.test(e))throw new Error("invalid secret name");const r=b();r[e]=t,X(r)}function be(e){return b()[e]}function Ee(e){return e in b()}function he(){return Object.keys(b()).sort()}function _e(e){const t=b();return e in t?(delete t[e],X(t),!0):!1}function Re(){try{w(i())}catch{}try{w(x())}catch{}}function de(e){try{const t=te(e).size,r=re(e,"r+");try{if(t>0){const n=d(t);oe(r,n,0,t,0),ne(r)}}finally{ie(r)}}catch{}try{w(e)}catch{}}function pe(){if(!o(i()))return{key:null,from:B()};const e=u(i()),t=[];o(y())&&t.push({from:"keyfile",key:u(y())});try{const r=O();r&&t.push({from:"keychain",key:r})}catch{}process.env.WYRM_VAULT_PASSPHRASE&&t.push({from:"passphrase",key:N(process.env.WYRM_VAULT_PASSPHRASE,V(),32)});for(const r of t)try{return U(e,r.key),{key:r.key,from:r.from}}catch{}throw new Error("could not decrypt the current vault with any available key (keyfile / keychain / passphrase).")}function Te(e={}){const t=e.backend??"keychain",r=e.rotate??!0,{key:n,from:h}=pe(),c=n?U(u(i()),n):{},W=Object.keys(c).length;let s="";if(o(i())){s=i()+".bak."+new Date().toISOString().replace(/[:.]/g,"-"),F(i(),s);try{S(s,384)}catch{}}let g,E;if(t==="keychain"){if(!K())throw new Error("OS keychain not reachable \u2014 cannot migrate to keychain. Unlock your login keyring, or use `--backend passphrase`.");E=O(),g=r?d(32):E??d(32),H(g)}else{const p=process.env.WYRM_VAULT_PASSPHRASE;if(!p)throw new Error("migrate to passphrase requires WYRM_VAULT_PASSPHRASE to be set.");g=N(p,V(),32)}const C=()=>{if(t==="keychain")if(E)try{H(E)}catch{}else G()};try{z(c,g);const p=U(u(i()),g),_=Buffer.from(JSON.stringify(p)),$=Buffer.from(JSON.stringify(c));if(_.length!==$.length||!ee(_,$))throw new Error("post-migration verification mismatch")}catch(p){if(s){try{F(s,i())}catch(_){throw C(),new Error(`CRITICAL: vault rollback failed \u2014 vault.enc may be partially written. Restore manually: cp "${s}" "${i()}" (${_.message})`)}try{w(s)}catch{}}throw C(),new Error("migration aborted (vault left unchanged): "+p.message)}L(t);let I=!1;if(o(y())&&(de(y()),I=!0),t==="passphrase"&&G(),s){try{w(s)}catch{}s=""}return{from:h,to:t,rotated:r,secrets:W,backup:s,keyfileShredded:I}}function ke(){const e=B();let t=0;try{t=he().length}catch{}const r=o(y()),n=e==="keychain"?!0:(()=>{try{return K()}catch{return!1}})(),h=(e==="keychain"||e==="passphrase")&&!r;return{dir:a(),vault:i(),key:y(),backend:e,mode:e,count:t,keyfileOnDisk:r,keychainAvailable:n,secure:h}}function xe(){let e;try{e=ke()}catch{return[]}if(e.secure)return[];const t=[];return t.push(e.count>0?`\u26A0\uFE0F The credential vault holds ${e.count} secret(s) but the master key is a PLAINTEXT file (\`${e.key}\`) sitting beside the ciphertext \u2014 at-rest encryption is effectively defeated against anyone who can read \`${e.dir}\` (a backup, a synced dotfiles repo, an exfiltrated tarball).`:"\u26A0\uFE0F The credential vault's master key would be stored as a plaintext file beside the ciphertext."),t.push(e.keychainAvailable?'Fix in one step \u2014 run **`wyrm vault setup`** (moves the key into the OS keychain, rotates it, shreds the plaintext key). Then store secrets with `printf %s "$TOKEN" | wyrm vault set <name>` and use them via `wyrm vault exec <name> -- <cmd>` (never echoed).':"No OS keychain on this host \u2014 set `WYRM_VAULT_PASSPHRASE`, then run **`wyrm vault setup`** (derives the key from the passphrase; nothing on disk)."),t}export{Y as KeyringUnavailableError,B as resolveBackend,xe as vaultAdvisory,Re as vaultDestroy,be as vaultGet,Ee as vaultHas,he as vaultList,ke as vaultPaths,_e as vaultRemove,Te as vaultSecure,Ae as vaultSet};
|