@openadapter/koda 1.0.0-beta.14 → 1.0.0-beta.16

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.
@@ -1 +1 @@
1
- var p=Object.defineProperty;var t=(r,e)=>p(r,"name",{value:e,configurable:!0});import{existsSync as c,readFileSync as s,writeFileSync as l}from"node:fs";import{homedir as m}from"node:os";import{join as n}from"node:path";import{getAgentDir as f,VERSION as u}from"../config.js";function a(){return process.env.KODA_TELEMETRY==="0"||!!process.env.KODA_OFFLINE}t(a,"disabled");function y(){let r=process.env.OPENADAPTER_BASE_URL||"",e=process.env.OPENADAPTER_API_KEY||"";if(!r||!e)try{const o=process.env.KODA_CODING_AGENT_DIR||n(m(),".koda","agent"),i=JSON.parse(s(n(o,"models.json"),"utf-8"));r=r||i?.providers?.openadapter?.baseUrl||"",e=e||i?.providers?.openadapter?.apiKey||""}catch{}return e?{root:(r||"https://api.openadapter.in/v1").replace(/\/v1\/?$/,"").replace(/\/$/,""),key:e}:null}t(y,"getGateway");function d(r){if(a())return;const e=y();e&&fetch(`${e.root}/api/koda/telemetry`,{method:"POST",headers:{Authorization:`Bearer ${e.key}`,"Content-Type":"application/json"},body:JSON.stringify({type:r.type,version:u,os:process.platform,arch:process.arch,...r.error?{error:r.error.slice(0,300)}:{}}),signal:AbortSignal.timeout(4e3)}).catch(()=>{})}t(d,"sendKodaTelemetry");function O(r=f()){if(a())return;const e=n(r,".telemetry-last");try{const o=c(e)&&Number(s(e,"utf-8").trim())||0;if(Date.now()-o<1440*60*1e3)return;l(e,String(Date.now()),"utf-8")}catch{return}d({type:"session"})}t(O,"maybePingSession");export{O as maybePingSession,d as sendKodaTelemetry};
1
+ var f=Object.defineProperty;var n=(r,e)=>f(r,"name",{value:e,configurable:!0});import{randomUUID as u}from"node:crypto";import{existsSync as c,readFileSync as s,writeFileSync as p}from"node:fs";import{homedir as l}from"node:os";import{join as o}from"node:path";import{getAgentDir as m,VERSION as y}from"../config.js";function d(){return process.env.KODA_TELEMETRY==="0"||!!process.env.KODA_OFFLINE}n(d,"disabled");let t;function D(){if(t!==void 0)return t;t="";try{const r=process.env.KODA_CODING_AGENT_DIR||o(l(),".koda","agent"),e=o(r,".install-id");c(e)&&(t=s(e,"utf-8").trim()),t||(t=u(),p(e,t,"utf-8"))}catch{t=""}return t}n(D,"getInstallId");function A(){let r=process.env.OPENADAPTER_BASE_URL||"",e=process.env.OPENADAPTER_API_KEY||"";if(!r||!e)try{const i=process.env.KODA_CODING_AGENT_DIR||o(l(),".koda","agent"),a=JSON.parse(s(o(i,"models.json"),"utf-8"));r=r||a?.providers?.openadapter?.baseUrl||"",e=e||a?.providers?.openadapter?.apiKey||""}catch{}return e?{root:(r||"https://api.openadapter.in/v1").replace(/\/v1\/?$/,"").replace(/\/$/,""),key:e}:null}n(A,"getGateway");function g(r){if(d())return;const e=A();e&&fetch(`${e.root}/api/koda/telemetry`,{method:"POST",headers:{Authorization:`Bearer ${e.key}`,"Content-Type":"application/json"},body:JSON.stringify({type:r.type,version:y,os:process.platform,arch:process.arch,install_id:D()||void 0,...r.error?{error:r.error.slice(0,300)}:{}}),signal:AbortSignal.timeout(4e3)}).catch(()=>{})}n(g,"sendKodaTelemetry");function S(r=m()){if(d())return;const e=o(r,".telemetry-last");try{const i=c(e)&&Number(s(e,"utf-8").trim())||0;if(Date.now()-i<1440*60*1e3)return;p(e,String(Date.now()),"utf-8")}catch{return}g({type:"session"})}n(S,"maybePingSession");export{S as maybePingSession,g as sendKodaTelemetry};
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@openadapter/koda",
3
- "version": "1.0.0-beta.14",
3
+ "version": "1.0.0-beta.16",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@openadapter/koda",
9
- "version": "1.0.0-beta.14",
9
+ "version": "1.0.0-beta.16",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@modelcontextprotocol/sdk": "1.29.0",
13
- "@openadapter/koda-agent-core": "^1.0.0-beta.14",
14
- "@openadapter/koda-ai": "^1.0.0-beta.14",
15
- "@openadapter/koda-tui": "^1.0.0-beta.14",
13
+ "@openadapter/koda-agent-core": "^1.0.0-beta.16",
14
+ "@openadapter/koda-ai": "^1.0.0-beta.16",
15
+ "@openadapter/koda-tui": "^1.0.0-beta.16",
16
16
  "@silvia-odwyer/photon-node": "0.3.4",
17
17
  "chalk": "5.6.2",
18
18
  "cross-spawn": "7.0.6",
@@ -753,11 +753,11 @@
753
753
  ]
754
754
  },
755
755
  "node_modules/@openadapter/koda-agent-core": {
756
- "version": "1.0.0-beta.14",
757
- "resolved": "https://registry.npmjs.org/@openadapter/koda-agent-core/-/koda-agent-core-1.0.0-beta.14.tgz",
756
+ "version": "1.0.0-beta.16",
757
+ "resolved": "https://registry.npmjs.org/@openadapter/koda-agent-core/-/koda-agent-core-1.0.0-beta.16.tgz",
758
758
  "license": "MIT",
759
759
  "dependencies": {
760
- "@openadapter/koda-ai": "^1.0.0-beta.14",
760
+ "@openadapter/koda-ai": "^1.0.0-beta.16",
761
761
  "ignore": "7.0.5",
762
762
  "typebox": "1.1.38",
763
763
  "yaml": "2.9.0"
@@ -767,8 +767,8 @@
767
767
  }
768
768
  },
769
769
  "node_modules/@openadapter/koda-ai": {
770
- "version": "1.0.0-beta.14",
771
- "resolved": "https://registry.npmjs.org/@openadapter/koda-ai/-/koda-ai-1.0.0-beta.14.tgz",
770
+ "version": "1.0.0-beta.16",
771
+ "resolved": "https://registry.npmjs.org/@openadapter/koda-ai/-/koda-ai-1.0.0-beta.16.tgz",
772
772
  "license": "MIT",
773
773
  "dependencies": {
774
774
  "@anthropic-ai/sdk": "0.91.1",
@@ -790,8 +790,8 @@
790
790
  }
791
791
  },
792
792
  "node_modules/@openadapter/koda-tui": {
793
- "version": "1.0.0-beta.14",
794
- "resolved": "https://registry.npmjs.org/@openadapter/koda-tui/-/koda-tui-1.0.0-beta.14.tgz",
793
+ "version": "1.0.0-beta.16",
794
+ "resolved": "https://registry.npmjs.org/@openadapter/koda-tui/-/koda-tui-1.0.0-beta.16.tgz",
795
795
  "license": "MIT",
796
796
  "dependencies": {
797
797
  "get-east-asian-width": "1.6.0",
@@ -0,0 +1 @@
1
+ var u=Object.defineProperty;var t=(e,s)=>u(e,"name",{value:s,configurable:!0});import{spawnSync as b}from"node:child_process";function f(e){try{return b("git",["rev-parse","--is-inside-work-tree"],{cwd:e,encoding:"utf-8"}).stdout?.trim()==="true"}catch{return!1}}t(f,"inGitRepo");const d=/\b(vercel|netlify|fly\s+deploy|wrangler\s+(deploy|publish)|gcloud\b[^|;&]*\bdeploy|kubectl\s+apply|docker\s+push|(npm|pnpm|yarn|bun)\s+publish|gh\s+release\s+create|serverless\s+deploy|sst\s+deploy)\b/,p=[{cat:"rm-rf",label:"recursively force-delete files",re:/\brm\b[^|;&]*\s-[a-z]*r[a-z]*f|\brm\b[^|;&]*\s-[a-z]*f[a-z]*r|\brm\b[^|;&]*--recursive[^|;&]*--force|\brm\b[^|;&]*--force[^|;&]*--recursive/i},{cat:"sudo",label:"run a command as root (sudo)",re:/\bsudo\b/},{cat:"dd",label:"write a raw disk image (dd)",re:/\bdd\b[^|;&]*\bof=/},{cat:"mkfs",label:"format a filesystem (mkfs)",re:/\bmkfs\b/},{cat:"chmod-r",label:"recursively change permissions/ownership",re:/\bch(mod|own)\s+-[a-zA-Z]*R/},{cat:"kill",label:"kill processes",re:/\b(kill|pkill|killall)\b/},{cat:"sql-drop",label:"drop/truncate a database table",re:/\b(drop|truncate)\s+(table|database|schema)\b/i},{cat:"force-push",label:"force-push to git",re:/\bgit\s+push\b[^|;&]*\s(--force\b|-f\b|--force-with-lease\b)/},{cat:"publish",label:"publish a package",re:/\b(npm|pnpm|yarn|bun)\s+publish\b/},{cat:"deploy",label:"deploy / release",re:d}],g=[{cat:"remote-exec",label:"download and execute a remote script",re:/\b(curl|wget)\b[^|]*\|\s*(sudo\s+)?(ba|z|fi)?sh\b/}];function l(e){return e.trim().replace(/\s+/g," ")}t(l,"normalize");function O(e){for(const s of g)if(s.re.test(e))return{signature:`bash:${s.cat}:${l(e)}`,label:`${s.label}: ${l(e).slice(0,120)}`};for(const s of e.split(/\s*(?:&&|\|\||;|\|)\s*/).filter(Boolean))for(const o of p)if(o.re.test(s))return{signature:`bash:${o.cat}:${l(s)}`,label:`${o.label}: ${l(s).slice(0,120)}`};return null}t(O,"classifyBash");function m(e,s){return e==="bash"?O(String(s.command??"")):null}t(m,"classifyDanger");const i=t(()=>process.env.KODA_YOLO==="1","yoloOn");function y(e){const s=new Set;e.on("session_start",()=>{s.clear(),delete process.env.KODA_YOLO}),e.on("tool_call",async(o,r)=>{if(r.mode!=="tui"||!r.hasUI||process.env.KODA_JOBS_REHEARSAL==="1"||process.env.KODA_JOBS_ENFORCE==="1"||i())return;const n=m(o.toolName,o.input);if(!n||s.has(n.signature))return;const c=!f(r.cwd??process.cwd())?`Allow this? (NO UNDO \u2014 not a git repo) \u2014 ${n.label}`:`Allow this? \u2014 ${n.label}`;let a;try{a=await r.ui.select(c,["Allow once","Allow for this session","Deny"],{signal:r.signal})}catch{a=void 0}if(a!=="Allow once"){if(a==="Allow for this session"){s.add(n.signature);return}return{block:!0,reason:`The user denied permission to ${n.label}. Do NOT retry this command \u2014 pick a different approach or ask the user what they'd like instead.`}}}),e.registerCommand("yolo",{description:"Permissions: /yolo on (run dangerous actions without asking) \xB7 /yolo off (ask, default) \xB7 /yolo (status)",handler:t(async(o,r)=>{const n=o.trim().toLowerCase();n==="on"?(process.env.KODA_YOLO="1",r.ui.notify("AUTONOMOUS MODE ON \u2014 dangerous actions will run WITHOUT asking. Run /yolo off to re-enable prompts.","warning")):n==="off"?(delete process.env.KODA_YOLO,r.ui.notify("AUTONOMOUS MODE OFF \u2014 Koda will ask before dangerous actions.","info")):r.ui.notify(i()?"AUTONOMOUS MODE is ON \u2014 not asking before dangerous actions. /yolo off to re-enable.":"AUTONOMOUS MODE is OFF \u2014 asking before dangerous actions. /yolo on to skip prompts.","info")},"handler")})}t(y,"default");export{y as default};
@@ -0,0 +1,5 @@
1
+ var D=Object.defineProperty;var s=(n,t)=>D(n,"name",{value:t,configurable:!0});import{spawnSync as C}from"node:child_process";import{appendFileSync as F,mkdirSync as E,readFileSync as N}from"node:fs";import{homedir as A}from"node:os";import{dirname as B,join as w}from"node:path";import{matchesKey as m,truncateToWidth as b}from"@openadapter/koda-tui";function K(){return process.env.KODA_CODING_AGENT_DIR||w(A(),".koda","agent")}s(K,"agentDir");function I(n){return w(K(),"checkpoints",n)}s(I,"ckptDir");function $(n){return w(I(n),"index")}s($,"privIndex");function S(n){return w(I(n),"manifest.jsonl")}s(S,"manifestPath");function G(n){return`refs/koda/checkpoints/${n}`}s(G,"refName");function g(n,t,r={}){const i=C("git",t,{cwd:n,encoding:"utf-8",env:{...process.env,...r},timeout:2e4});return{ok:i.status===0,out:(i.stdout||"").trim(),err:(i.stderr||"").trim()}}s(g,"git");function M(n){const t=C("git",["rev-parse","--show-toplevel"],{cwd:n,encoding:"utf-8"});return t.status===0?t.stdout.trim():null}s(M,"repoRoot");function _(n,t){try{E(I(n),{recursive:!0}),F(S(n),`${JSON.stringify(t)}
2
+ `,"utf-8")}catch{}}s(_,"appendManifest");function L(n){try{return N(S(n),"utf-8").split(`
3
+ `).filter(Boolean).map(t=>JSON.parse(t))}catch{return[]}}s(L,"readManifest");function O(n,t,r,i,e="turn"){const o=$(t);try{E(B(o),{recursive:!0})}catch{}const c={GIT_INDEX_FILE:o};if(!g(n,["add","-A"],c).ok)return null;const l=g(n,["write-tree"],c);if(!l.ok)return null;const u=G(t),a=g(n,["rev-parse","-q","--verify",u]),f=a.ok?a.out:"";if(f&&e==="turn"){const k=g(n,["rev-parse",`${f}^{tree}`]);if(k.ok&&k.out===l.out)return _(t,{entryId:i,commit:f,label:r,ts:new Date().toISOString(),kind:e}),f}const h=f?["commit-tree",l.out,"-p",f,"-m",r]:["commit-tree",l.out,"-m",r],d=g(n,h);return!d.ok||!g(n,["update-ref",u,d.out]).ok?null:(_(t,{entryId:i,commit:d.out,label:r,ts:new Date().toISOString(),kind:e}),d.out)}s(O,"snapshot");function P(n,t,r){if(!O(n,t,"(before rewind)",null,"pre-restore"))return{ok:!1,err:"couldn't take a safety snapshot of the current state \u2014 restore aborted, nothing changed"};const e={GIT_INDEX_FILE:$(t)};if(!g(n,["add","-A"],e).ok)return{ok:!1,err:"couldn't stage the current worktree \u2014 restore aborted, nothing changed"};const o=g(n,["read-tree","-m","-u",r],e);return{ok:o.ok,err:o.err}}s(P,"restore");function j(n,t){const r=L(n),i=new Set,e=[];for(const o of r.reverse()){const c=`${o.commit}:${o.entryId}`;i.has(c)||(i.add(c),e.push({commit:o.commit,label:o.label,ts:o.ts,entryId:o.entryId,hasEntry:!!o.entryId&&t.has(o.entryId)}))}return e}s(j,"buildCheckpoints");function v(n){const t=Date.now()-new Date(n).getTime();if(!Number.isFinite(t)||t<0)return"";const r=Math.floor(t/6e4),i=Math.floor(r/60),e=Math.floor(i/24);return e>0?`${e}d ago`:i>0?`${i}h ago`:r>0?`${r}m ago`:"just now"}s(v,"ago");class J{static{s(this,"CheckpointPicker")}i=0;width=0;tui;theme;items;done;constructor(t,r,i,e){this.tui=t,this.theme=r,this.items=i,this.done=e}invalidate(){}handleInput(t){if(m(t,"escape")||m(t,"ctrl+c"))return this.done(null);if(m(t,"up"))this.i=Math.max(0,this.i-1);else if(m(t,"down"))this.i=Math.min(this.items.length-1,this.i+1);else return m(t,"return")||t==="\r"||t===`
4
+ `?this.done(this.items[this.i]??null):void 0;this.tui.requestRender()}render(t){const r=this.theme,i=[""];return i.push(b(r.fg("borderMuted","\u2500\u2500\u2500 ")+r.fg("accent","Rewind to a checkpoint")+r.fg("borderMuted",` ${"\u2500".repeat(Math.max(0,t-26))}`),t)),i.push(""),this.items.length?(this.items.forEach((e,o)=>{const c=o===this.i,l=c?r.fg("accent","\u2192 "):" ",u=v(e.ts).padEnd(9),a=e.label.length>t-18?`${e.label.slice(0,t-19)}\u2026`:e.label,f=c?r.fg("text",r.bold(a)):r.fg("text",a);i.push(b(`${l}${r.fg("dim",u)} ${f}`,t))}),i.push(""),i.push(b(` ${r.fg("muted","\u2191\u2193 move \xB7 Enter choose \xB7 Esc cancel")}`,t)),i):(i.push(` ${r.fg("muted","No checkpoints yet \u2014 they're taken automatically each turn in a git repo.")}`),i.push(""),i.push(` ${r.fg("dim","Esc to close")}`),i)}}function U(n){let t=!1;n.on("before_agent_start",(i,e)=>{if(e.mode!=="tui"||process.env.KODA_CKPT==="0"||process.env.KODA_JOBS_REHEARSAL==="1"||process.env.KODA_JOBS_ENFORCE==="1")return;const o=M(e.cwd??process.cwd());if(!o){t||(t=!0,e.ui.notify("No git repo here \u2014 checkpoints are OFF, so /rewind can't undo file changes. Destructive actions can't be rolled back. Run `git init` to turn checkpoints on.","warning"));return}const c=e.sessionManager.getSessionId(),l=e.sessionManager.getLeafId(),u=(i.prompt||"").replace(/\s+/g," ").trim().slice(0,80)||"(checkpoint)";try{O(o,c,u,l)}catch{}});const r={description:"Rewind to an earlier checkpoint \u2014 restore files, the conversation, or both",handler:s(async(i,e)=>{const o=M(e.cwd??process.cwd());if(!o){e.ui.notify("/rewind needs a git repository.","warning");return}const c=e.sessionManager.getSessionId(),l=new Set(e.sessionManager.getEntries().map(p=>p.id)),u=j(c,l);if(e.mode!=="tui"){e.ui.notify(u.length?u.map(p=>`${v(p.ts)} \u2014 ${p.label}`).join(`
5
+ `):"No checkpoints yet.","info");return}if(!u.length){e.ui.notify("No checkpoints yet \u2014 they're taken automatically each turn.","info");return}const a=await e.ui.custom((p,y,R,T)=>new J(p,y,u,T));if(!a)return;const f=a.hasEntry?["Files only","Conversation only","Both","Cancel"]:["Files only","Cancel"],h=await e.ui.select(`Restore "${a.label.slice(0,40)}" (${v(a.ts)}) \u2014 what?`,f);if(!h||h==="Cancel")return;const d=h==="Files only"||h==="Both",k=h==="Conversation only"||h==="Both";if(d){if(!e.isIdle()){if(!await e.ui.confirm("Agent is busy","Stop the current run before restoring files?"))return;e.abort(),await e.waitForIdle()}if(!await e.ui.confirm("Restore files",`Overwrite files in ${o} with the snapshot from ${v(a.ts)}? Changes since then will be lost. A safety snapshot of the current state is taken first (you can rewind back).`))return;const y=P(o,c,a.commit);if(!y.ok){e.ui.notify(`Files NOT restored: ${y.err||"git read-tree failed"}. Your working tree is unchanged.`,"error");return}e.ui.notify(`Files restored to "${a.label.slice(0,40)}". To undo, /rewind \u2192 pick "(before rewind)".`,"info")}k&&a.entryId&&await e.navigateTree(a.entryId)},"handler")};n.registerCommand("rewind",r),n.registerCommand("checkpoint",r)}s(U,"default");export{U as default};
@@ -134,6 +134,8 @@ const kodaExtensionBases = [
134
134
  "koda-vision",
135
135
  "koda-mcp",
136
136
  "koda-jobs",
137
+ "koda-permissions",
138
+ "koda-rewind",
137
139
  ];
138
140
  const kodaExtensions = kodaExtensionBases
139
141
  .map((base) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openadapter/koda",
3
- "version": "1.0.0-beta.14",
3
+ "version": "1.0.0-beta.16",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "piConfig": {
@@ -43,9 +43,9 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "@modelcontextprotocol/sdk": "1.29.0",
46
- "@openadapter/koda-agent-core": "^1.0.0-beta.14",
47
- "@openadapter/koda-ai": "^1.0.0-beta.14",
48
- "@openadapter/koda-tui": "^1.0.0-beta.14",
46
+ "@openadapter/koda-agent-core": "^1.0.0-beta.16",
47
+ "@openadapter/koda-ai": "^1.0.0-beta.16",
48
+ "@openadapter/koda-tui": "^1.0.0-beta.16",
49
49
  "@silvia-odwyer/photon-node": "0.3.4",
50
50
  "chalk": "5.6.2",
51
51
  "cross-spawn": "7.0.6",