@kynver-app/runtime 0.2.130 → 0.2.138

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 CHANGED
@@ -17,11 +17,16 @@ Standalone Kynver AgentOS execution runtime and CLI (`kynver`) — run Kynver's
17
17
 
18
18
  ```bash
19
19
  npm install -g @kynver-app/runtime
20
- kynver bootstrap --api-base-url https://www.kynver.com
21
- kynver start
20
+ kynver
22
21
  ```
23
22
 
24
- That is the whole golden path: `bootstrap` links this machine to your account and workspace; `start` brings the agent online (keeper-supervised daemon — Ctrl-C stops it). For a persistent background agent on Linux: `kynver start --install-systemd`.
23
+ That's it. The first time, `kynver` links this computer to your Kynver account: it opens the approval page in your browser (the link and code are printed too), you click approve, and it sets up this computer and brings Kynver online. After that, `kynver` just starts it. If Kynver is already running on this computer it says "Kynver is already running ✓" and does nothing else. `kynver stop` stops it.
24
+
25
+ While it runs, the window stays calm: a short status block ("Kynver is online ✓ · linked to … · chat: Claude Code"), then one line per chat message it answers. Problems are printed in plain words with the command that fixes them. The full log is always in `~/.kynver/logs/kynver.log`; `kynver --verbose` (or `KYNVER_VERBOSE=1`) shows it in the window as well.
26
+
27
+ **Website chat on this computer** turns on by itself when Claude Code (or Codex) is installed, and `kynver` says so once: "Website chat will use Claude Code on this computer. Turn off: kynver setup --no-chat-oauth". The choice is saved, so `kynver` and `kynver start` follow it with no flag.
28
+
29
+ Other Kynver sites (staging, local dev): `kynver --api-base-url https://your-kynver-site`. For a persistent background agent on Linux: `kynver start --install-systemd`. The step-by-step commands (`kynver bootstrap`, `kynver setup`, `kynver start`, `kynver daemon --run …`) still work exactly as before.
25
30
 
26
31
  ### Windows: Kynver Desktop
27
32
 
@@ -29,7 +34,7 @@ On Windows x64 there is also **Kynver Desktop**, which bundles this runtime and
29
34
  install and no terminal. It is offered in **Account → Settings** (next to these commands) only once a release is
30
35
  published, and a scenario is declared supported only after it has been tested end to end; until then the command line
31
36
  above is the way in. Only one runtime may work for a workspace on a computer: quit Desktop before running
32
- `kynver start`, and stop the CLI before starting Desktop.
37
+ `kynver`, and stop the CLI (`kynver stop`) before starting Desktop.
33
38
 
34
39
  ### What `kynver bootstrap` does
35
40
 
@@ -37,11 +42,11 @@ above is the way in. Only one runtime may work for a workspace on a computer: qu
37
42
  2. **Workspace resolution** — resolves your account's primary AgentOS workspace. If the account is not approved for Agentic OS yet, bootstrap says so and links the request page (see Requirements above).
38
43
  3. **Machine setup** — persists `~/.kynver/config.json` (API base URL, workspace id, repo discovery, worker caps, box identity) and mints a scoped `krc1.*` runner credential.
39
44
 
40
- Bootstrap does **not** start any work — bringing workers online is `kynver start`.
45
+ Bootstrap does **not** start any work — bringing workers online is `kynver` (or `kynver start`). Bare `kynver` runs bootstrap for you on a computer that isn't linked yet.
41
46
 
42
47
  ### Troubleshooting → `kynver doctor runner-install`
43
48
 
44
- If `bootstrap` or `start` fails, or the agent seems dead:
49
+ If `kynver` (or `bootstrap` / `start`) fails, or the agent seems dead:
45
50
 
46
51
  ```bash
47
52
  kynver doctor runner-install
@@ -74,7 +79,8 @@ Global env secrets are accepted on by-id callbacks **only** when the deployment
74
79
  ## CLI verbs
75
80
 
76
81
  ```text
77
- bootstrap | start | status | setup | login | daemon
82
+ (no verb) — start Kynver (links this computer first if needed)
83
+ stop | bootstrap | start | status | setup | login | daemon
78
84
  run create | list | status | dispatch | sweep
79
85
  worker start | status | tail | stop | complete
80
86
  runner credential [mint|status|list|revoke|rotate]
@@ -1 +1 @@
1
- import{verify as I,createPublicKey as k}from"node:crypto";function u(e){return JSON.stringify(f(e))}function f(e){if(Array.isArray(e))return e.map(f);if(e&&typeof e=="object"){let n={};for(let r of Object.keys(e).sort())n[r]=f(e[r]);return n}return e}function c(e){if(!e)return null;let n=e.trim();if(!n)return null;if(/^[0-9a-fA-F]{64}$/.test(n))return new Uint8Array(n.match(/.{2}/g).map(r=>parseInt(r,16)));try{let r=Buffer.from(n,"base64");if(r.length===32)return new Uint8Array(r)}catch{}return null}function g(e=process.env){if(e.NODE_ENV==="production")return!1;let n=e.KYNVER_ALLOW_DEV_SIGNING_KEYS?.trim().toLowerCase();return n==="1"||n==="true"||n==="yes"||n==="on"?!0:e.NODE_ENV==="test"||e.VITEST==="true"}import{createHash as b,createPublicKey as B,verify as E}from"node:crypto";var w=Buffer.from("302a300506032b6570032100","hex"),p="ca-6297fb8e1773",A={[p]:"16ae5cb2a61f8c94cf1b86e8258f9c2f2ff6aba5e6136250a422209b6e866881","ca-456fd128f3b3":"f29cbd559410c2578d7f9732ccd86570073355ccdb36af0d1b7dff15908466e7"};function C(e){return`ca-${b("sha256").update(Buffer.from(e)).digest("hex").slice(0,12)}`}function y(e,n=process.env){let r=c(n.KYNVER_COMMAND_AUTH_PUBLIC_KEY);if(r)return C(r)!==e?null:r;let t=A[e];return!t||e===p&&!g(n)?null:c(t)}var V=720*60*60,x="change",P=Buffer.from("302a300506032b6570032100","hex");function _(e){if(!e||typeof e!="object"||Array.isArray(e))return!1;let n=e;if(typeof n.signature!="string"||!n.signature||typeof n.publicKeyId!="string"||!n.publicKeyId)return!1;let r=n.payload;return!(!r||typeof r!="object"||r.v!==1||r.kind!=="chat-access-change"||typeof r.agentOsId!="string"||!r.agentOsId||typeof r.boxId!="string"||!r.boxId||typeof r.access!="string"||!r.access||!Array.isArray(r.folders)||!r.folders.every(t=>typeof t=="string")||typeof r.changedAt!="string"||Number.isNaN(Date.parse(r.changedAt))||typeof r.exp!="number"||!Number.isFinite(r.exp)||typeof r.nonce!="string"||!r.nonce)}function j(e){return!e||typeof e!="object"||Array.isArray(e)?null:e[x]??null}function R(e,n){return e.length===n.length&&e.every((r,t)=>r===n[t])}function S(e,n){let r=Date.parse(e),t=Date.parse(n);return Number.isNaN(r)?!1:Number.isNaN(t)?!0:r>t}function U(e,n,r={}){let t=r.env??process.env,h=r.nowSec??Math.floor(Date.now()/1e3);if(e==null)return{ok:!1,code:"missing",reason:"the turn carries no signed settings-change record for this raise"};if(!_(e))return{ok:!1,code:"malformed",reason:"malformed settings-change record"};let{payload:o}=e;if(o.agentOsId!==n.agentOsId)return{ok:!1,code:"mismatch",reason:"settings-change record is for another workspace"};if(o.boxId!==n.boxId)return{ok:!1,code:"mismatch",reason:"settings-change record is for another computer"};if(o.access!==n.access||!R(o.folders,n.folders))return{ok:!1,code:"mismatch",reason:"settings-change record does not match the access the turn asks for"};if(o.exp<=h)return{ok:!1,code:"expired",reason:"settings-change record expired \u2014 save the setting again in Computers settings"};let d=y(e.publicKeyId,t);if(!d)return{ok:!1,code:"no_verification_key",reason:`no verification key for publicKeyId "${e.publicKeyId}"`};let a;try{a=Buffer.from(e.signature,"base64url")}catch{return{ok:!1,code:"bad_signature",reason:"signature is not base64url"}}if(a.length!==64)return{ok:!1,code:"bad_signature",reason:"signature is not a 64-byte Ed25519 signature"};let l=!1;try{let i=Buffer.from(u(o),"utf8"),m=k({key:Buffer.concat([P,Buffer.from(d)]),format:"der",type:"spki"});l=I(null,i,m,a)}catch(i){return{ok:!1,code:"bad_signature",reason:`signature verification failed: ${i.message}`}}if(!l)return{ok:!1,code:"bad_signature",reason:"Ed25519 signature mismatch"};let s=r.lastApplied??null;return s&&(s.nonce===o.nonce||!S(o.changedAt,s.changedAt))?{ok:!1,code:"replayed",reason:"settings-change record is not newer than the one this computer last applied"}:{ok:!0,payload:o}}export{x as CHAT_ACCESS_CHANGE_RECORD_FIELD,V as CHAT_ACCESS_CHANGE_RECORD_TTL_SEC,S as isChangedAtAfter,_ as isSignedChatAccessChangeRecordShape,j as readChatAccessChangeRecord,U as verifyChatAccessChangeRecord};
1
+ import{verify as k,createPublicKey as x}from"node:crypto";function c(e){return JSON.stringify(u(e))}function u(e){if(Array.isArray(e))return e.map(u);if(e&&typeof e=="object"){let n={};for(let r of Object.keys(e).sort())n[r]=u(e[r]);return n}return e}function d(e){if(!e)return null;let n=e.trim();if(!n)return null;if(/^[0-9a-fA-F]{64}$/.test(n))return new Uint8Array(n.match(/.{2}/g).map(r=>parseInt(r,16)));try{let r=Buffer.from(n,"base64");if(r.length===32)return new Uint8Array(r)}catch{}return null}function p(e){if(!e)return[];let n=[];for(let r of e.split(/[,\s]+/)){let t=d(r);t&&n.push(t)}return n}function y(e=process.env){if(e.NODE_ENV==="production")return!1;let n=e.KYNVER_ALLOW_DEV_SIGNING_KEYS?.trim().toLowerCase();return n==="1"||n==="true"||n==="yes"||n==="on"?!0:e.NODE_ENV==="test"||e.VITEST==="true"}import{createHash as A,createPublicKey as B,verify as O}from"node:crypto";var N=Buffer.from("302a300506032b6570032100","hex"),h="ca-6297fb8e1773",C={[h]:"16ae5cb2a61f8c94cf1b86e8258f9c2f2ff6aba5e6136250a422209b6e866881","ca-456fd128f3b3":"f29cbd559410c2578d7f9732ccd86570073355ccdb36af0d1b7dff15908466e7"};function I(e){return`ca-${A("sha256").update(Buffer.from(e)).digest("hex").slice(0,12)}`}function m(e,n=process.env){let r=p(n.KYNVER_COMMAND_AUTH_PUBLIC_KEY);if(r.length>0)return r.find(a=>I(a)===e)??null;let t=C[e];return!t||e===h&&!y(n)?null:d(t)}var V=720*60*60,P="change",_=Buffer.from("302a300506032b6570032100","hex");function R(e){if(!e||typeof e!="object"||Array.isArray(e))return!1;let n=e;if(typeof n.signature!="string"||!n.signature||typeof n.publicKeyId!="string"||!n.publicKeyId)return!1;let r=n.payload;return!(!r||typeof r!="object"||r.v!==1||r.kind!=="chat-access-change"||typeof r.agentOsId!="string"||!r.agentOsId||typeof r.boxId!="string"||!r.boxId||typeof r.access!="string"||!r.access||!Array.isArray(r.folders)||!r.folders.every(t=>typeof t=="string")||typeof r.changedAt!="string"||Number.isNaN(Date.parse(r.changedAt))||typeof r.exp!="number"||!Number.isFinite(r.exp)||typeof r.nonce!="string"||!r.nonce)}function j(e){return!e||typeof e!="object"||Array.isArray(e)?null:e[P]??null}function K(e,n){return e.length===n.length&&e.every((r,t)=>r===n[t])}function S(e,n){let r=Date.parse(e),t=Date.parse(n);return Number.isNaN(r)?!1:Number.isNaN(t)?!0:r>t}function H(e,n,r={}){let t=r.env??process.env,a=r.nowSec??Math.floor(Date.now()/1e3);if(e==null)return{ok:!1,code:"missing",reason:"the turn carries no signed settings-change record for this raise"};if(!R(e))return{ok:!1,code:"malformed",reason:"malformed settings-change record"};let{payload:o}=e;if(o.agentOsId!==n.agentOsId)return{ok:!1,code:"mismatch",reason:"settings-change record is for another workspace"};if(o.boxId!==n.boxId)return{ok:!1,code:"mismatch",reason:"settings-change record is for another computer"};if(o.access!==n.access||!K(o.folders,n.folders))return{ok:!1,code:"mismatch",reason:"settings-change record does not match the access the turn asks for"};if(o.exp<=a)return{ok:!1,code:"expired",reason:"settings-change record expired \u2014 save the setting again in Computers settings"};let l=m(e.publicKeyId,t);if(!l)return{ok:!1,code:"no_verification_key",reason:`no verification key for publicKeyId "${e.publicKeyId}"`};let s;try{s=Buffer.from(e.signature,"base64url")}catch{return{ok:!1,code:"bad_signature",reason:"signature is not base64url"}}if(s.length!==64)return{ok:!1,code:"bad_signature",reason:"signature is not a 64-byte Ed25519 signature"};let g=!1;try{let f=Buffer.from(c(o),"utf8"),b=x({key:Buffer.concat([_,Buffer.from(l)]),format:"der",type:"spki"});g=k(null,f,b,s)}catch(f){return{ok:!1,code:"bad_signature",reason:`signature verification failed: ${f.message}`}}if(!g)return{ok:!1,code:"bad_signature",reason:"Ed25519 signature mismatch"};let i=r.lastApplied??null;return i&&(i.nonce===o.nonce||!S(o.changedAt,i.changedAt))?{ok:!1,code:"replayed",reason:"settings-change record is not newer than the one this computer last applied"}:{ok:!0,payload:o}}export{P as CHAT_ACCESS_CHANGE_RECORD_FIELD,V as CHAT_ACCESS_CHANGE_RECORD_TTL_SEC,S as isChangedAtAfter,R as isSignedChatAccessChangeRecordShape,j as readChatAccessChangeRecord,H as verifyChatAccessChangeRecord};
@@ -1 +1 @@
1
- import{createHash as A,verify as _,createPublicKey as E}from"node:crypto";function i(r){return JSON.stringify(c(r))}function c(r){if(Array.isArray(r))return r.map(c);if(r&&typeof r=="object"){let e={};for(let n of Object.keys(r).sort())e[n]=c(r[n]);return e}return r}function d(r){if(!r)return null;let e=r.trim();if(!e)return null;if(/^[0-9a-fA-F]{64}$/.test(e))return new Uint8Array(e.match(/.{2}/g).map(n=>parseInt(n,16)));try{let n=Buffer.from(e,"base64");if(n.length===32)return new Uint8Array(n)}catch{}return null}function h(r=process.env){if(r.NODE_ENV==="production")return!1;let e=r.KYNVER_ALLOW_DEV_SIGNING_KEYS?.trim().toLowerCase();return e==="1"||e==="true"||e==="yes"||e==="on"?!0:r.NODE_ENV==="test"||r.VITEST==="true"}import{createHash as v,createPublicKey as j,verify as L}from"node:crypto";var V=Buffer.from("302a300506032b6570032100","hex"),m="ca-6297fb8e1773",x={[m]:"16ae5cb2a61f8c94cf1b86e8258f9c2f2ff6aba5e6136250a422209b6e866881","ca-456fd128f3b3":"f29cbd559410c2578d7f9732ccd86570073355ccdb36af0d1b7dff15908466e7"};function C(r){return`ca-${v("sha256").update(Buffer.from(r)).digest("hex").slice(0,12)}`}function b(r,e=process.env){let n=d(e.KYNVER_COMMAND_AUTH_PUBLIC_KEY);if(n)return C(n)!==r?null:n;let o=x[r];return!o||r===m&&!h(e)?null:d(o)}var F=900,k="turnEnvelope",T=Buffer.from("302a300506032b6570032100","hex");function P(r){if(!r||typeof r!="object"||Array.isArray(r))return r;let e={...r};return delete e[k],e}function S(r){return A("sha256").update(i(P(r)),"utf8").digest("hex")}function w(r){return!r||typeof r!="object"||Array.isArray(r)?null:r[k]??null}function R(r){if(!r||typeof r!="object")return!1;let e=r;if(typeof e.signature!="string"||!e.signature||typeof e.publicKeyId!="string"||!e.publicKeyId)return!1;let n=e.payload;return!(!n||typeof n!="object"||n.v!==1||n.kind!=="chat-turn"||typeof n.turnId!="string"||!n.turnId||typeof n.agentOsId!="string"||!n.agentOsId||n.userId!==null&&(typeof n.userId!="string"||!n.userId)||n.boxId!==null&&typeof n.boxId!="string"||n.access!==null&&(!n.access||typeof n.access!="object"||Array.isArray(n.access))||typeof n.payloadHash!="string"||!/^[0-9a-f]{64}$/.test(n.payloadHash)||typeof n.exp!="number"||!Number.isFinite(n.exp)||typeof n.nonce!="string"||!n.nonce)}function N(r,e){let n=r&&typeof r=="object"&&!Array.isArray(r)?r.computerAccess??null:null;return n===null&&e===null?!0:n===null||e===null?!1:i(n)===i(e)}var I=class{constructor(e=1e4){this.maxEntries=e}maxEntries;byNonce=new Map;byTurn=new Map;consume(e){let n=e.nowSec??Math.floor(Date.now()/1e3);this.purge(n);let o=this.byNonce.get(e.nonce);if(o)return o.turnId!==e.turnId?{ok:!1,replay:p(o,"turn_mismatch")}:o.state==="verified"?{ok:!0,redelivered:!0}:{ok:!1,replay:p(o,o.state==="started"?"in_flight":"already_ran")};let a=this.byTurn.get(e.turnId);if(a){if(a.state!=="verified")return{ok:!1,replay:p(a,a.state==="started"?"in_flight":"already_ran")};this.byNonce.delete(a.nonce);let t={...a,nonce:e.nonce,untilSec:Math.max(a.untilSec,e.expSec+60)};return this.byNonce.set(e.nonce,t),this.byTurn.set(e.turnId,t),{ok:!0,redelivered:!0}}if(this.byNonce.size>=this.maxEntries){let t=this.byNonce.values().next().value;t&&this.forget(t)}let s={nonce:e.nonce,turnId:e.turnId,firstSeenSec:n,state:"verified",untilSec:e.expSec+60};return this.byNonce.set(e.nonce,s),this.byTurn.set(e.turnId,s),{ok:!0,redelivered:!1}}markStarted(e){let n=this.byTurn.get(e);return n?(n.state==="verified"&&(n.state="started"),!0):!1}markFinished(e){let n=this.byTurn.get(e);return n?(n.state="finished",!0):!1}stateOf(e){return this.byTurn.get(e)?.state??null}purge(e=Math.floor(Date.now()/1e3)){for(let n of[...this.byNonce.values()])n.untilSec<=e&&this.forget(n)}forget(e){this.byNonce.delete(e.nonce),this.byTurn.get(e.turnId)===e&&this.byTurn.delete(e.turnId)}get size(){return this.byNonce.size}};function p(r,e){return{state:e,firstSeenAt:new Date(r.firstSeenSec*1e3).toISOString(),turnId:r.turnId}}function K(r){return E({key:Buffer.concat([T,Buffer.from(r)]),format:"der",type:"spki"})}function Y(r,e,n={}){let o=n.env??process.env,a=n.nowSec??Math.floor(Date.now()/1e3),s=w(r);if(s===null)return{ok:!1,code:"unsigned",reason:"turn carries no signed envelope"};if(!R(s))return{ok:!1,code:"malformed",reason:"malformed chat-turn envelope"};let t=s;if(t.payload.agentOsId!==e.agentOsId)return{ok:!1,code:"agent_os_mismatch",reason:"envelope is for another workspace"};if(t.payload.turnId!==e.turnId)return{ok:!1,code:"turn_id_mismatch",reason:"envelope is for another turn"};if(t.payload.exp<=a)return{ok:!1,code:"expired",reason:"envelope expired"};let y=b(t.publicKeyId,o);if(!y)return{ok:!1,code:"no_verification_key",reason:`no verification key for publicKeyId "${t.publicKeyId}"`};let f;try{f=Buffer.from(t.signature,"base64url")}catch{return{ok:!1,code:"bad_signature",reason:"signature is not base64url"}}if(f.length!==64)return{ok:!1,code:"bad_signature",reason:"signature is not a 64-byte Ed25519 signature"};let g=!1;try{let l=Buffer.from(i(t.payload),"utf8");g=_(null,l,K(y),f)}catch(l){return{ok:!1,code:"bad_signature",reason:`signature verification failed: ${l.message}`}}if(!g)return{ok:!1,code:"bad_signature",reason:"Ed25519 signature mismatch"};if(S(r)!==t.payload.payloadHash)return{ok:!1,code:"payload_tampered",reason:"turn payload does not match its signed hash"};if(!N(r,t.payload.access))return{ok:!1,code:"access_mismatch",reason:"computer access on the turn differs from the signed setting"};if(!n.nonces)return{ok:!0,payload:t.payload,redelivered:!1};let u=n.nonces.consume({nonce:t.payload.nonce,turnId:t.payload.turnId,expSec:t.payload.exp,nowSec:a});return u.ok?{ok:!0,payload:t.payload,redelivered:u.redelivered}:{ok:!1,code:"replayed",reason:`envelope nonce already used on this computer (${B(u.replay)})`,replay:u.replay}}function B(r){return`${r.state==="in_flight"?"this computer is running that turn now":r.state==="already_ran"?"that turn already ran here":`the nonce belongs to turn ${r.turnId}`}; first seen ${r.firstSeenAt}`}export{k as CHAT_TURN_ENVELOPE_FIELD,F as CHAT_TURN_ENVELOPE_TTL_SEC,I as ChatTurnNonceCache,N as chatTurnAccessMatches,S as hashChatTurnPayload,R as isSignedChatTurnEnvelopeShape,w as readChatTurnEnvelope,P as stripChatTurnEnvelope,Y as verifyChatTurnEnvelope};
1
+ import{createHash as _,verify as E,createPublicKey as T}from"node:crypto";function i(r){return JSON.stringify(c(r))}function c(r){if(Array.isArray(r))return r.map(c);if(r&&typeof r=="object"){let e={};for(let n of Object.keys(r).sort())e[n]=c(r[n]);return e}return r}function d(r){if(!r)return null;let e=r.trim();if(!e)return null;if(/^[0-9a-fA-F]{64}$/.test(e))return new Uint8Array(e.match(/.{2}/g).map(n=>parseInt(n,16)));try{let n=Buffer.from(e,"base64");if(n.length===32)return new Uint8Array(n)}catch{}return null}function h(r){if(!r)return[];let e=[];for(let n of r.split(/[,\s]+/)){let o=d(n);o&&e.push(o)}return e}function m(r=process.env){if(r.NODE_ENV==="production")return!1;let e=r.KYNVER_ALLOW_DEV_SIGNING_KEYS?.trim().toLowerCase();return e==="1"||e==="true"||e==="yes"||e==="on"?!0:r.NODE_ENV==="test"||r.VITEST==="true"}import{createHash as x,createPublicKey as j,verify as U}from"node:crypto";var M=Buffer.from("302a300506032b6570032100","hex"),b="ca-6297fb8e1773",A={[b]:"16ae5cb2a61f8c94cf1b86e8258f9c2f2ff6aba5e6136250a422209b6e866881","ca-456fd128f3b3":"f29cbd559410c2578d7f9732ccd86570073355ccdb36af0d1b7dff15908466e7"};function C(r){return`ca-${x("sha256").update(Buffer.from(r)).digest("hex").slice(0,12)}`}function I(r,e=process.env){let n=h(e.KYNVER_COMMAND_AUTH_PUBLIC_KEY);if(n.length>0)return n.find(a=>C(a)===r)??null;let o=A[r];return!o||r===b&&!m(e)?null:d(o)}var Y=900,v="turnEnvelope",P=Buffer.from("302a300506032b6570032100","hex");function S(r){if(!r||typeof r!="object"||Array.isArray(r))return r;let e={...r};return delete e[v],e}function w(r){return _("sha256").update(i(S(r)),"utf8").digest("hex")}function R(r){return!r||typeof r!="object"||Array.isArray(r)?null:r[v]??null}function K(r){if(!r||typeof r!="object")return!1;let e=r;if(typeof e.signature!="string"||!e.signature||typeof e.publicKeyId!="string"||!e.publicKeyId)return!1;let n=e.payload;return!(!n||typeof n!="object"||n.v!==1||n.kind!=="chat-turn"||typeof n.turnId!="string"||!n.turnId||typeof n.agentOsId!="string"||!n.agentOsId||n.userId!==null&&(typeof n.userId!="string"||!n.userId)||n.boxId!==null&&typeof n.boxId!="string"||n.access!==null&&(!n.access||typeof n.access!="object"||Array.isArray(n.access))||typeof n.payloadHash!="string"||!/^[0-9a-f]{64}$/.test(n.payloadHash)||typeof n.exp!="number"||!Number.isFinite(n.exp)||typeof n.nonce!="string"||!n.nonce)}function N(r,e){let n=r&&typeof r=="object"&&!Array.isArray(r)?r.computerAccess??null:null;return n===null&&e===null?!0:n===null||e===null?!1:i(n)===i(e)}var k=class{constructor(e=1e4){this.maxEntries=e}maxEntries;byNonce=new Map;byTurn=new Map;consume(e){let n=e.nowSec??Math.floor(Date.now()/1e3);this.purge(n);let o=this.byNonce.get(e.nonce);if(o)return o.turnId!==e.turnId?{ok:!1,replay:p(o,"turn_mismatch")}:o.state==="verified"?{ok:!0,redelivered:!0}:{ok:!1,replay:p(o,o.state==="started"?"in_flight":"already_ran")};let a=this.byTurn.get(e.turnId);if(a){if(a.state!=="verified")return{ok:!1,replay:p(a,a.state==="started"?"in_flight":"already_ran")};this.byNonce.delete(a.nonce);let t={...a,nonce:e.nonce,untilSec:Math.max(a.untilSec,e.expSec+60)};return this.byNonce.set(e.nonce,t),this.byTurn.set(e.turnId,t),{ok:!0,redelivered:!0}}if(this.byNonce.size>=this.maxEntries){let t=this.byNonce.values().next().value;t&&this.forget(t)}let s={nonce:e.nonce,turnId:e.turnId,firstSeenSec:n,state:"verified",untilSec:e.expSec+60};return this.byNonce.set(e.nonce,s),this.byTurn.set(e.turnId,s),{ok:!0,redelivered:!1}}markStarted(e){let n=this.byTurn.get(e);return n?(n.state==="verified"&&(n.state="started"),!0):!1}markFinished(e){let n=this.byTurn.get(e);return n?(n.state="finished",!0):!1}stateOf(e){return this.byTurn.get(e)?.state??null}purge(e=Math.floor(Date.now()/1e3)){for(let n of[...this.byNonce.values()])n.untilSec<=e&&this.forget(n)}forget(e){this.byNonce.delete(e.nonce),this.byTurn.get(e.turnId)===e&&this.byTurn.delete(e.turnId)}get size(){return this.byNonce.size}};function p(r,e){return{state:e,firstSeenAt:new Date(r.firstSeenSec*1e3).toISOString(),turnId:r.turnId}}function B(r){return T({key:Buffer.concat([P,Buffer.from(r)]),format:"der",type:"spki"})}function J(r,e,n={}){let o=n.env??process.env,a=n.nowSec??Math.floor(Date.now()/1e3),s=R(r);if(s===null)return{ok:!1,code:"unsigned",reason:"turn carries no signed envelope"};if(!K(s))return{ok:!1,code:"malformed",reason:"malformed chat-turn envelope"};let t=s;if(t.payload.agentOsId!==e.agentOsId)return{ok:!1,code:"agent_os_mismatch",reason:"envelope is for another workspace"};if(t.payload.turnId!==e.turnId)return{ok:!1,code:"turn_id_mismatch",reason:"envelope is for another turn"};if(t.payload.exp<=a)return{ok:!1,code:"expired",reason:"envelope expired"};let y=I(t.publicKeyId,o);if(!y)return{ok:!1,code:"no_verification_key",reason:`no verification key for publicKeyId "${t.publicKeyId}"`};let f;try{f=Buffer.from(t.signature,"base64url")}catch{return{ok:!1,code:"bad_signature",reason:"signature is not base64url"}}if(f.length!==64)return{ok:!1,code:"bad_signature",reason:"signature is not a 64-byte Ed25519 signature"};let g=!1;try{let l=Buffer.from(i(t.payload),"utf8");g=E(null,l,B(y),f)}catch(l){return{ok:!1,code:"bad_signature",reason:`signature verification failed: ${l.message}`}}if(!g)return{ok:!1,code:"bad_signature",reason:"Ed25519 signature mismatch"};if(w(r)!==t.payload.payloadHash)return{ok:!1,code:"payload_tampered",reason:"turn payload does not match its signed hash"};if(!N(r,t.payload.access))return{ok:!1,code:"access_mismatch",reason:"computer access on the turn differs from the signed setting"};if(!n.nonces)return{ok:!0,payload:t.payload,redelivered:!1};let u=n.nonces.consume({nonce:t.payload.nonce,turnId:t.payload.turnId,expSec:t.payload.exp,nowSec:a});return u.ok?{ok:!0,payload:t.payload,redelivered:u.redelivered}:{ok:!1,code:"replayed",reason:`envelope nonce already used on this computer (${O(u.replay)})`,replay:u.replay}}function O(r){return`${r.state==="in_flight"?"this computer is running that turn now":r.state==="already_ran"?"that turn already ran here":`the nonce belongs to turn ${r.turnId}`}; first seen ${r.firstSeenAt}`}export{v as CHAT_TURN_ENVELOPE_FIELD,Y as CHAT_TURN_ENVELOPE_TTL_SEC,k as ChatTurnNonceCache,N as chatTurnAccessMatches,w as hashChatTurnPayload,K as isSignedChatTurnEnvelopeShape,R as readChatTurnEnvelope,S as stripChatTurnEnvelope,J as verifyChatTurnEnvelope};
@@ -1 +1 @@
1
- import{createHash as m,createPublicKey as h,verify as d}from"node:crypto";function u(e){return JSON.stringify(s(e))}function s(e){if(Array.isArray(e))return e.map(s);if(e&&typeof e=="object"){let n={};for(let r of Object.keys(e).sort())n[r]=s(e[r]);return n}return e}function f(e){if(!e)return null;let n=e.trim();if(!n)return null;if(/^[0-9a-fA-F]{64}$/.test(n))return new Uint8Array(n.match(/.{2}/g).map(r=>parseInt(r,16)));try{let r=Buffer.from(n,"base64");if(r.length===32)return new Uint8Array(r)}catch{}return null}function l(e=process.env){if(e.NODE_ENV==="production")return!1;let n=e.KYNVER_ALLOW_DEV_SIGNING_KEYS?.trim().toLowerCase();return n==="1"||n==="true"||n==="yes"||n==="on"?!0:e.NODE_ENV==="test"||e.VITEST==="true"}var K=120,b=Buffer.from("302a300506032b6570032100","hex"),c="ca-6297fb8e1773",I={[c]:"16ae5cb2a61f8c94cf1b86e8258f9c2f2ff6aba5e6136250a422209b6e866881","ca-456fd128f3b3":"f29cbd559410c2578d7f9732ccd86570073355ccdb36af0d1b7dff15908466e7"};function A(e){return`ca-${m("sha256").update(Buffer.from(e)).digest("hex").slice(0,12)}`}function p(e,n=process.env){let r=f(n.KYNVER_COMMAND_AUTH_PUBLIC_KEY);if(r)return A(r)!==e?null:r;let t=I[e];return!t||e===c&&!l(n)?null:f(t)}function g(e){return h({key:Buffer.concat([b,Buffer.from(e)]),format:"der",type:"spki"})}function P(e,n){return!Array.isArray(e)||e.length!==n.length?!1:e.every((r,t)=>typeof r=="string"&&r===n[t])}function k(e){if(!e||typeof e!="object")return!1;let n=e;if(typeof n.signature!="string"||!n.signature||typeof n.publicKeyId!="string"||!n.publicKeyId)return!1;let r=n.payload;return!(!r||typeof r!="object"||r.v!==1||typeof r.agentOsId!="string"||!r.agentOsId||!Array.isArray(r.argv)||r.argv.some(t=>typeof t!="string")||typeof r.userId!="string"||!r.userId||typeof r.exp!="number"||!Number.isFinite(r.exp)||typeof r.nonce!="string"||!r.nonce)}function O(e,n,r=process.env,t=Math.floor(Date.now()/1e3)){if(!k(e))return{ok:!1,reason:"malformed command authorization proof"};if(e.payload.agentOsId!==n.agentOsId)return{ok:!1,reason:"agentOsId mismatch"};if(!P(e.payload.argv,n.argv))return{ok:!1,reason:"argv mismatch"};if(e.payload.exp<=t)return{ok:!1,reason:"proof expired"};let a=p(e.publicKeyId,r);if(!a)return{ok:!1,reason:`no verification key for publicKeyId "${e.publicKeyId}"`};let o;try{o=Buffer.from(e.signature,"base64url")}catch{return{ok:!1,reason:"signature is not base64url"}}if(o.length!==64)return{ok:!1,reason:"signature is not a 64-byte Ed25519 signature"};try{let i=Buffer.from(u(e.payload),"utf8");return d(null,i,g(a),o)?{ok:!0,payload:e.payload}:{ok:!1,reason:"Ed25519 signature mismatch"}}catch(i){return{ok:!1,reason:`signature verification failed: ${i.message}`}}}var S=120;function x(e){if(!e||typeof e!="object")return!1;let n=e;if(typeof n.signature!="string"||!n.signature||typeof n.publicKeyId!="string"||!n.publicKeyId)return!1;let r=n.payload;return!(!r||typeof r!="object"||r.v!==1||r.kind!=="chat"||typeof r.agentOsId!="string"||!r.agentOsId||typeof r.exp!="number"||!Number.isFinite(r.exp)||typeof r.nonce!="string"||!r.nonce)}function T(e,n,r=process.env,t=Math.floor(Date.now()/1e3)){if(!x(e))return{ok:!1,reason:"malformed chat-turn authorization proof"};if(e.payload.agentOsId!==n.agentOsId)return{ok:!1,reason:"agentOsId mismatch"};if(e.payload.exp<=t)return{ok:!1,reason:"proof expired"};let a=p(e.publicKeyId,r);if(!a)return{ok:!1,reason:`no verification key for publicKeyId "${e.publicKeyId}"`};let o;try{o=Buffer.from(e.signature,"base64url")}catch{return{ok:!1,reason:"signature is not base64url"}}if(o.length!==64)return{ok:!1,reason:"signature is not a 64-byte Ed25519 signature"};try{let i=Buffer.from(u(e.payload),"utf8");return d(null,i,g(a),o)?{ok:!0,payload:e.payload}:{ok:!1,reason:"Ed25519 signature mismatch"}}catch(i){return{ok:!1,reason:`signature verification failed: ${i.message}`}}}export{S as CHAT_TURN_AUTH_PROOF_TTL_SEC,c as COMMAND_AUTH_DEV_FALLBACK_PUBLIC_KEY_ID,K as COMMAND_AUTH_PROOF_TTL_SEC,I as PINNED_COMMAND_AUTH_PUBLIC_KEYS,P as argvMatchesProof,A as deriveCommandAuthKeyId,x as isSignedChatTurnAuthProofShape,k as isSignedCommandAuthProofShape,p as resolveCommandAuthPublicKey,T as verifyChatTurnAuthorizationProof,O as verifyCommandAuthorizationProof};
1
+ import{createHash as h,createPublicKey as b,verify as c}from"node:crypto";function u(e){return JSON.stringify(s(e))}function s(e){if(Array.isArray(e))return e.map(s);if(e&&typeof e=="object"){let n={};for(let r of Object.keys(e).sort())n[r]=s(e[r]);return n}return e}function f(e){if(!e)return null;let n=e.trim();if(!n)return null;if(/^[0-9a-fA-F]{64}$/.test(n))return new Uint8Array(n.match(/.{2}/g).map(r=>parseInt(r,16)));try{let r=Buffer.from(n,"base64");if(r.length===32)return new Uint8Array(r)}catch{}return null}function l(e){if(!e)return[];let n=[];for(let r of e.split(/[,\s]+/)){let t=f(r);t&&n.push(t)}return n}function d(e=process.env){if(e.NODE_ENV==="production")return!1;let n=e.KYNVER_ALLOW_DEV_SIGNING_KEYS?.trim().toLowerCase();return n==="1"||n==="true"||n==="yes"||n==="on"?!0:e.NODE_ENV==="test"||e.VITEST==="true"}var E=120,I=Buffer.from("302a300506032b6570032100","hex"),p="ca-6297fb8e1773",A={[p]:"16ae5cb2a61f8c94cf1b86e8258f9c2f2ff6aba5e6136250a422209b6e866881","ca-456fd128f3b3":"f29cbd559410c2578d7f9732ccd86570073355ccdb36af0d1b7dff15908466e7"};function P(e){return`ca-${h("sha256").update(Buffer.from(e)).digest("hex").slice(0,12)}`}function y(e,n=process.env){let r=l(n.KYNVER_COMMAND_AUTH_PUBLIC_KEY);if(r.length>0)return r.find(o=>P(o)===e)??null;let t=A[e];return!t||e===p&&!d(n)?null:f(t)}function g(e){return b({key:Buffer.concat([I,Buffer.from(e)]),format:"der",type:"spki"})}function k(e,n){return!Array.isArray(e)||e.length!==n.length?!1:e.every((r,t)=>typeof r=="string"&&r===n[t])}function x(e){if(!e||typeof e!="object")return!1;let n=e;if(typeof n.signature!="string"||!n.signature||typeof n.publicKeyId!="string"||!n.publicKeyId)return!1;let r=n.payload;return!(!r||typeof r!="object"||r.v!==1||typeof r.agentOsId!="string"||!r.agentOsId||!Array.isArray(r.argv)||r.argv.some(t=>typeof t!="string")||typeof r.userId!="string"||!r.userId||typeof r.exp!="number"||!Number.isFinite(r.exp)||typeof r.nonce!="string"||!r.nonce)}function O(e,n,r=process.env,t=Math.floor(Date.now()/1e3)){if(!x(e))return{ok:!1,reason:"malformed command authorization proof"};if(e.payload.agentOsId!==n.agentOsId)return{ok:!1,reason:"agentOsId mismatch"};if(!k(e.payload.argv,n.argv))return{ok:!1,reason:"argv mismatch"};if(e.payload.exp<=t)return{ok:!1,reason:"proof expired"};let o=y(e.publicKeyId,r);if(!o)return{ok:!1,reason:`no verification key for publicKeyId "${e.publicKeyId}"`};let i;try{i=Buffer.from(e.signature,"base64url")}catch{return{ok:!1,reason:"signature is not base64url"}}if(i.length!==64)return{ok:!1,reason:"signature is not a 64-byte Ed25519 signature"};try{let a=Buffer.from(u(e.payload),"utf8");return c(null,a,g(o),i)?{ok:!0,payload:e.payload}:{ok:!1,reason:"Ed25519 signature mismatch"}}catch(a){return{ok:!1,reason:`signature verification failed: ${a.message}`}}}var R=120;function C(e){if(!e||typeof e!="object")return!1;let n=e;if(typeof n.signature!="string"||!n.signature||typeof n.publicKeyId!="string"||!n.publicKeyId)return!1;let r=n.payload;return!(!r||typeof r!="object"||r.v!==1||r.kind!=="chat"||typeof r.agentOsId!="string"||!r.agentOsId||typeof r.exp!="number"||!Number.isFinite(r.exp)||typeof r.nonce!="string"||!r.nonce)}function w(e,n,r=process.env,t=Math.floor(Date.now()/1e3)){if(!C(e))return{ok:!1,reason:"malformed chat-turn authorization proof"};if(e.payload.agentOsId!==n.agentOsId)return{ok:!1,reason:"agentOsId mismatch"};if(e.payload.exp<=t)return{ok:!1,reason:"proof expired"};let o=y(e.publicKeyId,r);if(!o)return{ok:!1,reason:`no verification key for publicKeyId "${e.publicKeyId}"`};let i;try{i=Buffer.from(e.signature,"base64url")}catch{return{ok:!1,reason:"signature is not base64url"}}if(i.length!==64)return{ok:!1,reason:"signature is not a 64-byte Ed25519 signature"};try{let a=Buffer.from(u(e.payload),"utf8");return c(null,a,g(o),i)?{ok:!0,payload:e.payload}:{ok:!1,reason:"Ed25519 signature mismatch"}}catch(a){return{ok:!1,reason:`signature verification failed: ${a.message}`}}}export{R as CHAT_TURN_AUTH_PROOF_TTL_SEC,p as COMMAND_AUTH_DEV_FALLBACK_PUBLIC_KEY_ID,E as COMMAND_AUTH_PROOF_TTL_SEC,A as PINNED_COMMAND_AUTH_PUBLIC_KEYS,k as argvMatchesProof,P as deriveCommandAuthKeyId,C as isSignedChatTurnAuthProofShape,x as isSignedCommandAuthProofShape,y as resolveCommandAuthPublicKey,w as verifyChatTurnAuthorizationProof,O as verifyCommandAuthorizationProof};