@sma1lboy/kobe 0.8.78 → 0.8.79
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/dist/cli/index.js +2 -2
- package/dist/skills/kobe/SKILL.md +77 -3
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -281,7 +281,7 @@ ${z}`,Z);this.line=J,this.column=X,this.codeblock=z}}});function cO($,Z){let J=$
|
|
|
281
281
|
`)){let U=H.trim();if(!U)continue;if(!UJ(U))continue;let K;try{K=JSON.parse(U)}catch{continue}if(!LP(K)||typeof K.type!=="string")continue;let F=typeof K.timestamp==="string"?K.timestamp:new Date().toISOString(),L=LP(K.data)?K.data:{};if(K.type==="session.start"){let M=typeof L.sessionId==="string"?L.sessionId:void 0;if(M)z=M;continue}if(K.type==="user.message"){let M=typeof L.content==="string"?L.content:"";if(!M)continue;if(!W)W=Buffer.from(M.slice(0,B90),"utf8").toString("utf8");J.push({role:"user",blocks:[{type:"text",text:M}],timestamp:F,sessionId:z});continue}if(K.type==="assistant.message"){let M=[],_=typeof L.content==="string"?L.content:"";if(_)M.push({type:"text",text:_});let R=Array.isArray(L.toolRequests)?L.toolRequests:[];for(let V of R){if(!LP(V))continue;let C=typeof V.id==="string"?V.id:typeof V.toolCallId==="string"?V.toolCallId:"tool",f=typeof V.name==="string"?V.name:typeof V.toolName==="string"?V.toolName:"tool";M.push({type:"tool_call",callId:C,name:f,input:V.arguments??{}})}if(M.length>0)J.push({role:"assistant",blocks:M,timestamp:F,sessionId:z});continue}if(K.type==="tool.execution_start"){let M=typeof L.toolCallId==="string"?L.toolCallId:void 0,_=typeof L.toolName==="string"?L.toolName:"tool";if(M)X.set(M,_);continue}if(K.type==="tool.execution_complete"){let M=typeof L.toolCallId==="string"?L.toolCallId:void 0;if(!M)continue;let _=X.get(M)??(typeof L.toolName==="string"?L.toolName:"tool"),R=L.result??(L.success===!1?{success:!1}:void 0);J.push({role:"assistant",blocks:[{type:"tool_result",callId:M,output:R,isError:L.success===!1}],timestamp:F,sessionId:z});continue}if(K.type==="session.shutdown")Y=Kb(L)}return{messages:J,toolNameById:X,sessionId:z,usageMetrics:Y,firstUserMessage:W}}function LP($){return typeof $==="object"&&$!==null&&!Array.isArray($)}var tz,q90,B90=200;var Ob=a(()=>{az();JL();tz={copilotDir(){let $=process.env.COPILOT_HOME?.trim();if($)return $;return GQ.join(z90(),".copilot")},async readdir($){try{return await J90($)}catch{return[]}},async readFile($){return await qH($)},stat:Q90,async rm($){await X90($,{recursive:!0,force:!0})}};q90=MH({initial:H90,parseChunk:($,Z)=>U90($,Z)})});var qL,Lb,jb;var UL=a(()=>{qL=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],Lb=["\xB7","\u2722","\u2731","\u2736","\u273B","\u273D"],jb=[...Lb,...[...Lb].reverse()]});import{readFile as Vb,stat as N90}from"fs/promises";class BL{supportsCompletionMarkers(){return!0}async latestCompletion($){return(await this.latestActivity($)).marker}async latestActivityInFile($){return null}}function Cb($){return S4($).createTurnDetector()}function _b($,Z="claude",J=0){let X=null,z=0;for(let Y of $.split(`
|
|
282
282
|
`)){z++;let W=Db(Y);if(!W)continue;let H=AP(W.message)?W.message:W;if(H.role!=="assistant")continue;if(!("content"in H))continue;let U=Pb(W,J),K={id:`claude:${Z}:${U}:${z}`,timestampMs:U,source:"claude"};if(!X||K.timestampMs>=X.timestampMs)X=K}return X}function L90($){if($.type==="turn.completed")return!0;if($.type!=="event_msg")return!1;let Z=AP($.payload)?$.payload:void 0;return typeof Z?.type==="string"&&O90.has(Z.type)}function j90($,Z="codex"){let J=null,X=0;for(let z of $.split(`
|
|
283
283
|
`)){X++;let Y=Db(z);if(!Y||!L90(Y))continue;let W=Pb(Y,0),H={id:`codex:${Z}:${W}:${X}`,timestampMs:W,source:"codex"};if(!J||H.timestampMs>=J.timestampMs)J=H}return J}function Db($){let Z=$.trim();if(!Z)return null;try{let J=JSON.parse(Z);return AP(J)?J:null}catch{return null}}function Pb($,Z){let J=typeof $.timestamp==="string"?Date.parse($.timestamp):Number.NaN;return Number.isFinite(J)?J:Z}function AP($){return typeof $==="object"&&$!==null&&!Array.isArray($)}var Ab=($)=>N90($).then((Z)=>Z.mtimeMs,()=>0),M90,VP,F90,CP,FK,O90;var DP=a(()=>{ZP();YL();k7();M90={listSessionFiles:($)=>FH($),readFile:($)=>Vb($,"utf8"),statMtimeMs:Ab};VP=class VP extends BL{deps;vendor="claude";cache=new Map;constructor($=M90){super();this.deps=$}async latestActivity($){let Z=await this.deps.listSessionFiles($),J=Z[0]?.mtimeMs??0,X=null,z=new Map;for(let Y of Z.slice(0,4)){let W=this.cache.get(Y.path),H;if(W&&Y.mtimeMs>0&&W.mtimeMs===Y.mtimeMs)H=W.marker;else{let U=await this.deps.readFile(Y.path).catch(()=>"");H=_b(U,Y.path,Y.mtimeMs)}if(z.set(Y.path,{mtimeMs:Y.mtimeMs,marker:H}),H&&(!X||H.timestampMs>X.timestampMs))X=H}return this.cache=z,{marker:X,mtimeMs:J}}async latestActivityInFile($){let Z=await(this.deps.statMtimeMs??Ab)($);if(Z===0)return null;let J=await this.deps.readFile($).catch(()=>"");return{marker:_b(J,$,Z),mtimeMs:Z}}};F90={findLatestRollout:($)=>FP($),readFile:($)=>Vb($,"utf8")};CP=class CP extends BL{deps;vendor="codex";cache=null;constructor($=F90){super();this.deps=$}async latestActivity($){if(!$)return{marker:null,mtimeMs:0};let Z=await this.deps.findLatestRollout($);if(!Z)return{marker:null,mtimeMs:0};if(this.cache&&this.cache.path===Z.path&&Z.mtimeMs>0&&this.cache.mtimeMs===Z.mtimeMs)return{marker:this.cache.marker,mtimeMs:Z.mtimeMs};let J=await this.deps.readFile(Z.path).catch(()=>"");if(!J)return{marker:null,mtimeMs:Z.mtimeMs};let X=j90(J,Z.path);return this.cache={path:Z.path,mtimeMs:Z.mtimeMs,marker:X},{marker:X,mtimeMs:Z.mtimeMs}}};FK=class FK extends BL{vendor;constructor($){super();this.vendor=$}supportsCompletionMarkers(){return!1}async latestActivity(){return{marker:null,mtimeMs:0}}};O90=new Set(["task_complete","turn_complete","turn_aborted"])});function A90($){return{vendor:$,builtin:!1,displayName:$,defaultCommand:[$],history:PP,detectAccount:async()=>({binary:{found:!1,error:"custom engine: kobe has no account detector for it"},account:{kind:"none"}}),createHookAdapter:()=>new OK($),createTurnDetector:()=>new FK($)}}function S4($){return f7($)?RP[$]:A90($)}function Rb($){return S4($).history!==PP}function TP($){let Z=S4($).terminalTitle?.statusPrefixes;return Z&&Z.length>0?Z:Tb}function LH($,Z){let J=Z?TP(Z):Tb;for(let X of[...J].sort((z,Y)=>Y.length-z.length)){if(!$.startsWith(X))continue;let z=$.slice(X.length).trimStart();if(z.length===0)return $;return z}return $}function KL($,Z){let J=S4($).terminalTitle,X=J?.workingPrefixes;if(J?.ownsStatus!==!0||!X||X.length===0)return null;let z=Z.trim();if(z.length===0)return null;return X.some((Y)=>z.startsWith(Y))?"working":"rest"}function Sb(){return Object.values(RP).filter(($)=>$.quotaUsage).map(($)=>$.vendor)}var PP,_90,V90,C90,RP,Tb;var k7=a(()=>{g7();BJ();Cy();ZP();vy();dy();ny();YL();Hb();Bb();Ob();SP();UL();DP();PP={async listSessionIdsForWorktree(){return[]},async readHistory(){return[]},async transcriptPath(){return null},async latestTranscriptMtimeForWorktree(){return 0}},_90={async listSessionIdsForWorktree($){return[...await FH($)].sort((J,X)=>J.mtimeMs-X.mtimeMs).map((J)=>J.sessionId)},readHistory:($)=>Ey($),async transcriptPath($,Z){return(await FH(Z)).find((X)=>X.sessionId===$)?.path??null},latestTranscriptMtimeForWorktree:($)=>Iy($)},V90={listSessionIdsForWorktree:($)=>Qb($),readHistory:($)=>Gb($),transcriptPath:async($)=>await MP($)??null,latestTranscriptMtimeForWorktree:($)=>zb($)},C90={listSessionIdsForWorktree:($)=>Nb($),readHistory:($)=>Fb($),transcriptPath:async()=>null,latestTranscriptMtimeForWorktree:($)=>Mb($)},RP={claude:{vendor:"claude",builtin:!0,displayName:"Claude",defaultCommand:["claude"],history:_90,detectAccount:($)=>UH($),createHookAdapter:()=>new QP,createTurnDetector:()=>new VP,capabilities:_y,identity:Vy,spinnerFrames:jb,terminalTitle:{ownsStatus:!0,statusPrefixes:["\u2733","\u2802","\u2810","\u25D0","\u25D1"],workingPrefixes:["\u2802","\u2810","\u25D0","\u25D1"]},quotaUsage:()=>cy()},codex:{vendor:"codex",builtin:!0,displayName:"Codex",defaultCommand:["codex"],effortLevels:["none","low","medium","high","xhigh"],history:V90,detectAccount:($)=>BH($),createHookAdapter:()=>new OP,createTurnDetector:()=>new CP,capabilities:ly,identity:py,terminalTitle:{ownsStatus:!0,launchArgs:["-c",'tui.terminal_title=["activity","thread-title"]'],statusPrefixes:["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],workingPrefixes:["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"]},quotaUsage:()=>Ub()},copilot:{vendor:"copilot",builtin:!0,displayName:"Copilot",defaultCommand:["copilot"],history:C90,detectAccount:($)=>KH($),createHookAdapter:()=>new OK("copilot"),createTurnDetector:()=>new FK("copilot")},kimi:{vendor:"kimi",builtin:!0,displayName:"Kimi",defaultCommand:["kimi"],history:PP,detectAccount:($)=>$L($),createHookAdapter:()=>new OK("kimi"),createTurnDetector:()=>new FK("kimi")}};Tb=[...new Set(Object.values(RP).flatMap(($)=>$.terminalTitle?.statusPrefixes??[]))]});function IP($){return S4($).createHookAdapter()}class OK{vendor;constructor($){this.vendor=$}supportsHooks(){return!1}globalSettingsPath(){return""}activityDetailFromPayload(){return}sessionFromPayload(){return}async installActivityHooks(){}async removeActivityHooks(){}supportsWorktreeSync(){return!1}async removeWorktreeSyncHook(){}async installWorktreeWatchHook(){}async removeWorktreeWatchHook(){}}var SP=a(()=>{k7()});function NL($){return D90.includes($)}function Ib($){return P90.includes($)}var D90,P90;var EP=a(()=>{D90=["session-start","turn-start","turn-complete","turn-failed","turn-interrupted","awaiting-input","session-end","tool-pre","tool-post","tool-failed","pre-compact","post-compact","subagent-start","subagent-stop"];P90=["session-start","turn-start","turn-complete","turn-failed","turn-interrupted","awaiting-input","session-end"]});var hb={};x4(hb,{runHookSubcommand:()=>x90,readTextWithTimeout:()=>xb,parseWorktreeRemovePath:()=>bb,parseWorktreeAddPath:()=>yb,ensureGlobalKobeHooks:()=>fP});import{readFileSync as R90}from"fs";import{homedir as T90}from"os";import{join as xP,resolve as wP}from"path";async function xb($,Z=S90){let J;try{return await Promise.race([$(),new Promise((X)=>{J=setTimeout(()=>X(""),Z)})])}finally{if(J!==void 0)clearTimeout(J)}}async function fb(){try{let $=await xb(()=>Bun.stdin.text());if(!$.trim())return{};let Z=JSON.parse($);return Z&&typeof Z==="object"&&!Array.isArray(Z)?Z:{}}catch{return{}}}function Eb($,Z){for(let J=0;J<$.length;J++){if($[J]===Z)return $[J+1];if($[J].startsWith(`${Z}=`))return $[J].slice(Z.length+1)}return}function E90($){return!!$&&typeof $==="object"&&!Array.isArray($)}function gb($){let Z=[],J=/"([^"]*)"|'([^']*)'|(\S+)/g,X;while((X=J.exec($))!==null)Z.push(X[1]??X[2]??X[3]??"");return Z}function yb($){let Z=gb($),J=new Set(["-b","-B","--reason"]);for(let X=0;X+1<Z.length;X++){if(Z[X]!=="worktree"||Z[X+1]!=="add")continue;let z=X+2;while(z<Z.length){let Y=Z[z];if(Y==="&&"||Y==="||"||Y===";"||Y==="|"||Y===">"||Y===">>")break;if(Y.startsWith("-")){z+=J.has(Y)?2:1;continue}return Y}}return}function bb($){let Z=gb($);for(let J=0;J+1<Z.length;J++){if(Z[J]!=="worktree"||Z[J+1]!=="remove")continue;let X=J+2;while(X<Z.length){let z=Z[X];if(z==="&&"||z==="||"||z===";"||z==="|"||z===">"||z===">>")break;if(z.startsWith("-")){X+=1;continue}return z}}return}async function w90(){let $=await fb(),Z=E90($.tool_input)?$.tool_input:{},J=typeof Z.command==="string"?Z.command:"";if(!J.includes("worktree"))return;let X=typeof $.cwd==="string"&&$.cwd?$.cwd:process.cwd(),z=yb(J),Y=z?void 0:bb(J);if(!z&&!Y)return;let W=await iX();if(!W)return;try{if(z)await W.request("worktree.reconcile",{cwd:X,worktreePath:wP(X,z)});else if(Y)await W.request("worktree.archiveRemoved",{worktreePath:wP(X,Y)})}finally{W.close()}}async function x90($){let[Z,...J]=$;if(Z==="setup"){await b90(J);return}if(Z===I90){try{await w90()}catch{}return}try{if(!Z||!NL(Z))return;let X=await fb(),z=Eb(J,"--task-id"),Y=typeof X.cwd==="string"&&X.cwd?X.cwd:process.cwd(),W=process.env.KOBE_TASK_ID,H=process.env.KOBE_TAB_ID,U=Eb(J,"--engine"),K=vb().filter((_)=>!U||_.vendor===U),F;for(let _ of K)if(F=_.activityDetailFromPayload(Z,X),F)break;let L;for(let _ of K)if(L=_.sessionFromPayload(X),L)break;let M=await iX();if(!M)return;try{let _=z??W;await M.request("engine.reportEvent",{..._?{taskId:_}:{cwd:Y},kind:Z,...U?{engine:U}:{},...H?{tabId:H}:{},...F?{detail:F}:{},...L?{sessionId:L.sessionId}:{},...L?.transcriptPath?{transcriptPath:L.transcriptPath}:{}})}finally{M.close()}}catch(X){if(process.env.KOBE_HOOK_DEBUG)console.error(`[kobe hook] ${Z} failed:`,X instanceof Error?X.message:String(X))}}function f90(){return C8.map(($)=>IP($)).filter(($)=>$.supportsWorktreeSync())}function vb(){return C8.map(($)=>IP($)).filter(($)=>$.supportsHooks())}function kb(){return xP(T90(),".claude","settings.json")}function g90($){if(!$||$==="off")return;if($==="global")return kb();if($.startsWith("repo:"))return xP(wP($.slice(5)),".claude","settings.json");return $}async function fP(){try{let $=y90();for(let Z of vb()){let J=Z.globalSettingsPath();if(!J)continue;await Z.installActivityHooks(J,{toolEvents:$}),await Z.installWorktreeWatchHook(J)}await mb()}catch{}}function y90(){try{for(let $ of M5().plugins){if(!$.enabled)continue;try{let Z=R90(xP($.root,C2),"utf8");if(n2(Z).manifest.events.some((J)=>J.on.startsWith("tool.")))return!0}catch{}}}catch{}return!1}async function mb(){let $=f90();if($.length===0)return;let Z=v7(wb),J=new Set([kb()]),X=g90(Z);if(X)J.add(X);for(let z of $)for(let Y of J)await z.removeWorktreeSyncHook(Y);if(Z!=="off")m3(wb,"off")}async function b90($){await mb(),process.stdout.write(["kobe hook setup is deprecated and now a no-op (cleanup only).","","The old external-worktree sync used a global WorktreeCreate hook, which is","a VCS provider hook \u2014 its presence broke `claude --worktree` / EnterWorktree","in every repo. Any hook kobe previously installed has been removed.","","Sync is now automatic: a `claude --worktree` (or any session) started in a","worktree under a repo kobe already tracks is adopted as a task on launch.","To adopt existing worktrees on demand, use the New Task dialog or `kobe adopt`.",""].join(`
|
|
284
|
-
`))}var S90=500,I90="worktree-created",wb="externalWorktreeSync";var gP=a(()=>{L2();$Q();qJ();SP();EP();v$();g7()});var ML;var ub=a(()=>{ML={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/kobe",version:"0.8.
|
|
284
|
+
`))}var S90=500,I90="worktree-created",wb="externalWorktreeSync";var gP=a(()=>{L2();$Q();qJ();SP();EP();v$();g7()});var ML;var ub=a(()=>{ML={$schema:"https://json.schemastore.org/package.json",name:"@sma1lboy/kobe",version:"0.8.79",description:"TUI orchestrator for Claude Code (codename)",type:"module",packageManager:"bun@1.3.13",bin:{kobe:"dist/cli/index.js"},files:["dist/cli","dist/web-ui","dist/skills","dist/*.wav","README.md","LICENSE"],publishConfig:{access:"public"},repository:{type:"git",url:"git+https://github.com/Sma1lboy/kobe.git"},homepage:"https://github.com/Sma1lboy/kobe#readme",bugs:{url:"https://github.com/Sma1lboy/kobe/issues"},engines:{bun:">=1.3.11"},scripts:{dev:"KOBE_DEV=1 bun --conditions=browser ./src/cli/index.ts","dev:mock":"KOBE_DEV=1 bun ./src/tui-react/mock/host.tsx","dev:mock-react":"KOBE_DEV=1 bun ./src/tui-react/mock/host.tsx","dev:mock-react-task-dialogs":"KOBE_DEV=1 bun ./src/tui-react/component/mock-dialogs-host.tsx","dev:mock-react-filetree":"KOBE_DEV=1 bun ./src/tui-react/panes/filetree/mock-host.tsx","dev:mock-react-sidebar":"KOBE_DEV=1 bun ./src/tui-react/panes/sidebar/mock-host.tsx","dev:mock-react-terminal":"KOBE_DEV=1 bun ./src/tui-react/panes/terminal/mock-host.tsx","dev:mock-react-dialogs":"KOBE_DEV=1 bun ./src/tui-react/mock/dialogs-host.tsx","dev:mock-react-workspace":"KOBE_DEV=1 bun ./src/tui-react/workspace/mock-host.tsx","dev:sandbox":"bun run scripts/dev-sandbox.ts run","dev:sandbox:reset":"bun run scripts/dev-sandbox.ts reset",build:"bun run scripts/build.ts","build:with-web":"bun run build",compile:"bun run scripts/compile.ts",typecheck:"tsc --noEmit","check-i18n":"bun run scripts/check-i18n.ts",test:"bun run test:fast && bun run test:socket","perf:golden":"bun scripts/perf-golden.ts","pty:soak":"bun scripts/pty-soak.ts","test:fast":"vitest run --passWithNoTests --minWorkers=1 --maxWorkers=8","test:socket":"KOBE_INCLUDE_SOCKET=1 vitest run test/daemon --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:socket:coverage":"KOBE_INCLUDE_SOCKET=1 KOBE_COVERAGE_DAEMON=1 vitest run test/daemon --coverage --pool forks --minWorkers=1 --maxWorkers=4 --passWithNoTests","test:behavior":"KOBE_INCLUDE_BEHAVIOR=1 vitest run test/behavior --pool forks --minWorkers=1 --maxWorkers=1 --retry=2 --passWithNoTests","test:render":"bun test test/render --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir=coverage-render",coverage:"vitest run --coverage --passWithNoTests",bench:"vitest bench --run",lint:"biome check .",knip:"knip-bun",postinstall:"bun run scripts/check-preview-deps.ts || true",prepublishOnly:"bun run typecheck && bun run build"},"//":"biome.json + bunfig.toml live at the monorepo root since they apply repo-wide; bun.lock also lives at root (workspace-shared).",dependencies:{"@ansi-tools/parser":"^1.0.15","@opentui/core":"0.4.3","@opentui/react":"0.4.3","@xterm/addon-serialize":"^0.14.0","@xterm/addon-unicode11":"^0.9.0","@xterm/headless":"^6.0.0","node-pty":"^1.1.0",react:"^19.2.8",ws:"^8.18.0"},devDependencies:{"@biomejs/biome":"1.9.4","@sma1lboy/kobe-daemon":"0.7.12","@tsconfig/bun":"1.0.10","@types/bun":"1.3.14","@types/node":"25.6.2","@types/react":"^19.2.0","@vitest/coverage-v8":"2.1.9",knip:"^6.14.2","kobe-web":"workspace:*","react-devtools-core":"^7.0.1",typescript:"5.8.2",vitest:"2.1.9"},trustedDependencies:[]}});var db={};x4(db,{repoSlug:()=>ez,releasePageUrl:()=>hP,recommendedGlobalInstallCommand:()=>vP,isNewerSemver:()=>yP,fetchReleaseSummaries:()=>jK,fetchReleaseNotesRange:()=>mP,fetchReleaseNotes:()=>kP,compareSemver:()=>z3,checkLatestVersion:()=>$G,breakingVersionsCrossed:()=>LK,UPDATE_SCRIPT_URL:()=>FL,UPDATE_COMMAND:()=>o9,PACKAGE_NAME:()=>bP,CURRENT_VERSION:()=>V4,BREAKING_VERSIONS:()=>NJ});function ez(){let $=ML.repository?.url;if(!$)return null;let Z=$.match(/github\.com[:/]([^/]+)\/([^/.]+)/);if(!Z||!Z[1]||!Z[2])return null;return`${Z[1]}/${Z[2]}`}function vP(){return`npm install -g ${bP}@latest`}function LK($,Z,J=NJ){let[X,z]=z3($,Z)<=0?[$,Z]:[Z,$];return J.filter((Y)=>z3(Y,X)>0&&z3(Y,z)<=0)}async function k90($){let Z=new AbortController,J=setTimeout(()=>Z.abort(),OL);try{let X=$.replace("/","%2F"),z=await fetch(`https://registry.npmjs.org/${X}/latest`,{signal:Z.signal,headers:{accept:"application/json"}});if(!z.ok)return null;let Y=await z.json();if(typeof Y.version!=="string")return null;return Y.version}catch{return null}finally{clearTimeout(J)}}function yP($,Z){return z3($,Z)>0}function z3($,Z){let J=(Y)=>Y.split("-")[0]??Y,X=J($).split(".").map((Y)=>Number.parseInt(Y,10)),z=J(Z).split(".").map((Y)=>Number.parseInt(Y,10));for(let Y=0;Y<3;Y++){let W=X[Y]??0,H=z[Y]??0;if(Number.isNaN(W)||Number.isNaN(H))return 0;if(W>H)return 1;if(W<H)return-1}return 0}async function $G($={}){let Z=process.env.KOBE_FAKE_UPDATE;if(Z)return{current:V4,latest:Z,hasUpdate:yP(Z,V4)};if(lW()&&!$.force)return null;let J=await k90(bP);if(!J)return null;return{current:V4,latest:J,hasUpdate:yP(J,V4)}}function cb($){if(typeof $!=="string")return null;return $.match(/^v(\d+\.\d+\.\d+)$/)?.[1]??null}async function kP($){let Z=ez();if(!Z)return null;let J=`v${$}`,X=new AbortController,z=setTimeout(()=>X.abort(),OL);try{let Y=await fetch(`https://api.github.com/repos/${Z}/releases/tags/${J}`,{signal:X.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!Y.ok)return null;let W=await Y.json();if(typeof W.body!=="string"||typeof W.html_url!=="string")return null;return{body:W.body,url:W.html_url,version:$}}catch{return null}finally{clearTimeout(z)}}async function mP($){let Z=ez();if(!Z)return[];let J=$.limit??100,X=new AbortController,z=setTimeout(()=>X.abort(),OL);try{let Y=await fetch(`https://api.github.com/repos/${Z}/releases?per_page=${J}`,{signal:X.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!Y.ok)return[];let W=await Y.json();if(!Array.isArray(W))return[];return W.map((H)=>{let U=cb(H.tag_name);if(!U||typeof H.html_url!=="string"||typeof H.body!=="string")return null;if(z3(U,$.current)<=0)return null;if(z3(U,$.latest)>0)return null;return{version:U,url:H.html_url,body:H.body}}).filter((H)=>H!==null)}catch{return[]}finally{clearTimeout(z)}}async function jK($=12){let Z=ez();if(!Z)return[];let J=new AbortController,X=setTimeout(()=>J.abort(),OL);try{let z=await fetch(`https://api.github.com/repos/${Z}/releases?per_page=${$}`,{signal:J.signal,headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});if(!z.ok)return[];let Y=await z.json();if(!Array.isArray(Y))return[];return Y.map((W)=>{let H=cb(W.tag_name);if(!H||typeof W.html_url!=="string")return null;return{version:H,url:W.html_url}}).filter((W)=>W!==null)}catch{return[]}finally{clearTimeout(X)}}function hP($){let Z=ez();if(!Z)return null;return`https://github.com/${Z}/releases/tag/v${$}`}var V4,bP,FL="https://raw.githubusercontent.com/Sma1lboy/kobe/main/scripts/update.sh",o9,NJ,OL=3000;var R8=a(()=>{ub();R5();V4=ML.version,bP=ML.name;o9=`curl -fsSL ${FL} | sh`;NJ=[]});var pb={};x4(pb,{stampResetGate:()=>LL,resetGateBlockers:()=>lb,enforceResetGate:()=>cP,LAST_RUN_VERSION_KEY:()=>uP});function lb($,Z=V4,J=NJ){if(typeof $!=="string"||$.length===0)return[];let[X,z]=z3($,Z)<=0?[$,Z]:[Z,$];return J.filter((Y)=>z3(Y,X)>0&&z3(Y,z)<=0)}function cP(){let $=j$()[uP],Z=lb($);if(Z.length>0){let J=typeof $==="string"?$:"unknown";console.error([`kobe ${V4}: cannot start \u2014 version ${Z.join(", ")} introduced breaking changes`,`(last run: ${J}). Your daemon/session state may be incompatible.`,"","Run:"," kobe reset # stop daemon + PTY host + sessions (tasks kept)"," kobe reset --hard # additionally wipe the task index + UI state","","Then relaunch kobe. Worktrees are never touched."].join(`
|
|
285
285
|
`)),process.exit(1)}if($!==V4)LL()}function LL(){try{d2({[uP]:V4})}catch{}}var uP="app.lastRunVersion";var jL=a(()=>{j2();R8()});import{existsSync as ib,readFileSync as m90}from"fs";import{homedir as h90}from"os";import{join as ob,resolve as nb}from"path";import{fileURLToPath as u90}from"url";function _L(){let $=u90(import.meta.url);return[nb($,"../../../../../.agents/skills/kobe"),nb($,"../../skills/kobe")].find((J)=>ib(ob(J,"SKILL.md")))??null}function VL($={}){let Z=$.source!==void 0?$.source:_L(),J=$.agent===void 0?[]:typeof $.agent==="string"?[$.agent]:$.agent;return["skills","add",Z??d90,"--skill","kobe",...$.global===!1?[]:["--global"],...J.flatMap((X)=>["--agent",X])]}function ZG($={}){return`npx ${VL($).join(" ")}`}async function pP($,Z){return await Bun.spawn(["npx",...VL({...$===void 0?{}:{agent:$},global:Z})],{stdin:"inherit",stdout:"inherit",stderr:"inherit"}).exited}function CL($={}){let Z=$.home??h90(),J=$.cwd??process.cwd();return[Z,J].flatMap((X)=>c90.map((z)=>ob(X,z)))}function l90($){let Z=$.match(/kobe-skill-version:\s*(\d+)/);return Z?Number.parseInt(Z[1],10):null}function _K($){let Z=CL($).find((z)=>ib(z));if(!Z)return{installed:!1,installedVersion:null,currentVersion:dP,stale:!1};let J=null;try{J=l90(m90(Z,"utf8"))}catch{J=null}let X=J===null||J<dP;return{installed:!0,installedVersion:J,currentVersion:dP,stale:X}}function p90(){return new Promise(($)=>{process.stdin.resume(),process.stdin.once("data",(Z)=>{process.stdin.pause(),$(String(Z))})})}async function ab($={}){let Z=_K();if(!Z.installed){if(v7(lP)==="1")return;m3(lP,"1"),process.stderr.write(`
|
|
286
286
|
kobe: the kobe agent skill isn't installed \u2014 install it so your coding agent can drive kobe via \`kobe api\`:
|
|
287
287
|
${jH}
|
|
@@ -295,7 +295,7 @@ kobe: your kobe agent skill is out of date (${X}; this kobe wants v${Z.currentVe
|
|
|
295
295
|
kobe: a new version of the kobe agent skill is available (${X} \u2192 v${Z.currentVersion}).
|
|
296
296
|
Update now? [y]es / [n]o / [d]on't notify for this version: `);let Y=(await($.ask??p90)()).trim().toLowerCase();if(Y==="y"||Y==="yes"){let W=await($.install??pP)();if(W===0)process.stderr.write(`kobe: skill updated.
|
|
297
297
|
`);else process.stderr.write(`kobe: skill update failed (exit ${W}) \u2014 run \`${jH}\` manually.
|
|
298
|
-
`)}else if(Y.startsWith("d"))m3(J,"1")}var dP=
|
|
298
|
+
`)}else if(Y.startsWith("d"))m3(J,"1")}var dP=18,c90,jH="kobe skill install",d90="Sma1lboy/kobe",lP="skillHintSeen";var VK=a(()=>{v$();c90=[".agents/skills/kobe/SKILL.md",".claude/skills/kobe/SKILL.md"]});var AL=()=>{};var q1=vz((n90,DL)=>{(function(){function $(J0,S0){Object.defineProperty(X.prototype,J0,{get:function(){console.warn("%s(...) is deprecated in plain JavaScript React classes. %s",S0[0],S0[1])}})}function Z(J0){if(J0===null||typeof J0!=="object")return null;return J0=P0&&J0[P0]||J0["@@iterator"],typeof J0==="function"?J0:null}function J(J0,S0){J0=(J0=J0.constructor)&&(J0.displayName||J0.name)||"ReactClass";var e0=J0+"."+S0;u0[e0]||(console.error("Can't call %s on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the %s component.",S0,J0),u0[e0]=!0)}function X(J0,S0,e0){this.props=J0,this.context=S0,this.refs=G1,this.updater=e0||L0}function z(){}function Y(J0,S0,e0){this.props=J0,this.context=S0,this.refs=G1,this.updater=e0||L0}function W(){}function H(J0){return""+J0}function U(J0){try{H(J0);var S0=!1}catch(l1){S0=!0}if(S0){S0=console;var e0=S0.error,U1=typeof Symbol==="function"&&Symbol.toStringTag&&J0[Symbol.toStringTag]||J0.constructor.name||"Object";return e0.call(S0,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",U1),H(J0)}}function K(J0){if(J0==null)return null;if(typeof J0==="function")return J0.$$typeof===c0?null:J0.displayName||J0.name||null;if(typeof J0==="string")return J0;switch(J0){case l:return"Fragment";case n:return"Profiler";case d:return"StrictMode";case Q0:return"Suspense";case C0:return"SuspenseList";case k0:return"Activity"}if(typeof J0==="object")switch(typeof J0.tag==="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),J0.$$typeof){case v:return"Portal";case t:return J0.displayName||"Context";case Z0:return(J0._context.displayName||"Context")+".Consumer";case r:var S0=J0.render;return J0=J0.displayName,J0||(J0=S0.displayName||S0.name||"",J0=J0!==""?"ForwardRef("+J0+")":"ForwardRef"),J0;case z0:return S0=J0.displayName||null,S0!==null?S0:K(J0.type)||"Memo";case x0:S0=J0._payload,J0=J0._init;try{return K(J0(S0))}catch(e0){}}return null}function F(J0){if(J0===l)return"<>";if(typeof J0==="object"&&J0!==null&&J0.$$typeof===x0)return"<...>";try{var S0=K(J0);return S0?"<"+S0+">":"<...>"}catch(e0){return"<...>"}}function L(){var J0=J1.A;return J0===null?null:J0.getOwner()}function M(){return Error("react-stack-top-frame")}function _(J0){if(u1.call(J0,"key")){var S0=Object.getOwnPropertyDescriptor(J0,"key").get;if(S0&&S0.isReactWarning)return!1}return J0.key!==void 0}function R(J0,S0){function e0(){H4||(H4=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",S0))}e0.isReactWarning=!0,Object.defineProperty(J0,"key",{get:e0,configurable:!0})}function V(){var J0=K(this.type);return d5[J0]||(d5[J0]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),J0=this.props.ref,J0!==void 0?J0:null}function C(J0,S0,e0,U1,l1,I4){var _4=e0.ref;return J0={$$typeof:H0,type:J0,key:S0,props:e0,_owner:U1},(_4!==void 0?_4:null)!==null?Object.defineProperty(J0,"ref",{enumerable:!1,get:V}):Object.defineProperty(J0,"ref",{enumerable:!1,value:null}),J0._store={},Object.defineProperty(J0._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(J0,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(J0,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:l1}),Object.defineProperty(J0,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:I4}),Object.freeze&&(Object.freeze(J0.props),Object.freeze(J0)),J0}function f(J0,S0){return S0=C(J0.type,S0,J0.props,J0._owner,J0._debugStack,J0._debugTask),J0._store&&(S0._store.validated=J0._store.validated),S0}function T(J0){I(J0)?J0._store&&(J0._store.validated=1):typeof J0==="object"&&J0!==null&&J0.$$typeof===x0&&(J0._payload.status==="fulfilled"?I(J0._payload.value)&&J0._payload.value._store&&(J0._payload.value._store.validated=1):J0._store&&(J0._store.validated=1))}function I(J0){return typeof J0==="object"&&J0!==null&&J0.$$typeof===H0}function S(J0){var S0={"=":"=0",":":"=2"};return"$"+J0.replace(/[=:]/g,function(e0){return S0[e0]})}function x(J0,S0){return typeof J0==="object"&&J0!==null&&J0.key!=null?(U(J0.key),S(""+J0.key)):S0.toString(36)}function b(J0){switch(J0.status){case"fulfilled":return J0.value;case"rejected":throw J0.reason;default:switch(typeof J0.status==="string"?J0.then(W,W):(J0.status="pending",J0.then(function(S0){J0.status==="pending"&&(J0.status="fulfilled",J0.value=S0)},function(S0){J0.status==="pending"&&(J0.status="rejected",J0.reason=S0)})),J0.status){case"fulfilled":return J0.value;case"rejected":throw J0.reason}}throw J0}function k(J0,S0,e0,U1,l1){var I4=typeof J0;if(I4==="undefined"||I4==="boolean")J0=null;var _4=!1;if(J0===null)_4=!0;else switch(I4){case"bigint":case"string":case"number":_4=!0;break;case"object":switch(J0.$$typeof){case H0:case v:_4=!0;break;case x0:return _4=J0._init,k(_4(J0._payload),S0,e0,U1,l1)}}if(_4){_4=J0,l1=l1(_4);var U$=U1===""?"."+x(_4,0):U1;return F0(l1)?(e0="",U$!=null&&(e0=U$.replace(nJ,"$&/")+"/"),k(l1,S0,e0,"",function(j7){return j7})):l1!=null&&(I(l1)&&(l1.key!=null&&(_4&&_4.key===l1.key||U(l1.key)),e0=f(l1,e0+(l1.key==null||_4&&_4.key===l1.key?"":(""+l1.key).replace(nJ,"$&/")+"/")+U$),U1!==""&&_4!=null&&I(_4)&&_4.key==null&&_4._store&&!_4._store.validated&&(e0._store.validated=2),l1=e0),S0.push(l1)),1}if(_4=0,U$=U1===""?".":U1+":",F0(J0))for(var f4=0;f4<J0.length;f4++)U1=J0[f4],I4=U$+x(U1,f4),_4+=k(U1,S0,e0,I4,l1);else if(f4=Z(J0),typeof f4==="function")for(f4===J0.entries&&(y8||console.warn("Using Maps as children is not supported. Use an array of keyed ReactElements instead."),y8=!0),J0=f4.call(J0),f4=0;!(U1=J0.next()).done;)U1=U1.value,I4=U$+x(U1,f4++),_4+=k(U1,S0,e0,I4,l1);else if(I4==="object"){if(typeof J0.then==="function")return k(b(J0),S0,e0,U1,l1);throw S0=String(J0),Error("Objects are not valid as a React child (found: "+(S0==="[object Object]"?"object with keys {"+Object.keys(J0).join(", ")+"}":S0)+"). If you meant to render a collection of children, use an array instead.")}return _4}function u(J0,S0,e0){if(J0==null)return J0;var U1=[],l1=0;return k(J0,U1,"","",function(I4){return S0.call(e0,I4,l1++)}),U1}function o(J0){if(J0._status===-1){var S0=J0._ioInfo;S0!=null&&(S0.start=S0.end=performance.now()),S0=J0._result;var e0=S0();if(e0.then(function(l1){if(J0._status===0||J0._status===-1){J0._status=1,J0._result=l1;var I4=J0._ioInfo;I4!=null&&(I4.end=performance.now()),e0.status===void 0&&(e0.status="fulfilled",e0.value=l1)}},function(l1){if(J0._status===0||J0._status===-1){J0._status=2,J0._result=l1;var I4=J0._ioInfo;I4!=null&&(I4.end=performance.now()),e0.status===void 0&&(e0.status="rejected",e0.reason=l1)}}),S0=J0._ioInfo,S0!=null){S0.value=e0;var U1=e0.displayName;typeof U1==="string"&&(S0.name=U1)}J0._status===-1&&(J0._status=0,J0._result=e0)}if(J0._status===1)return S0=J0._result,S0===void 0&&console.error(`lazy: Expected the result of a dynamic import() call. Instead received: %s
|
|
299
299
|
|
|
300
300
|
Your code should look like:
|
|
301
301
|
const MyComponent = lazy(() => import('./MyComponent'))
|
|
@@ -3,7 +3,7 @@ name: kobe
|
|
|
3
3
|
description: Use when controlling kobe tasks, parallel coding attempts, hosted agent sessions, task lifecycle, or the daemon-owned issue tracker from a shell.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
<!-- kobe-skill-version:
|
|
6
|
+
<!-- kobe-skill-version: 18 — bump in lockstep with KOBE_SKILL_VERSION (src/lib/skill-install.ts). -->
|
|
7
7
|
|
|
8
8
|
# kobe shell control
|
|
9
9
|
|
|
@@ -61,6 +61,79 @@ in a kobe task. Do not recursively fan out from a spawned task.
|
|
|
61
61
|
When the check fails, none of this applies — use `kobe api` only if the
|
|
62
62
|
user asks for kobe by name.
|
|
63
63
|
|
|
64
|
+
## Vocabulary — what the user's words map to
|
|
65
|
+
|
|
66
|
+
| Term | What it is | Isolation it gives | Users also say |
|
|
67
|
+
|---|---|---|---|
|
|
68
|
+
| **Task** | one Worktree + branch + the Terminal Tabs inside it — one sidebar row | its own files AND its own branch | "a task", "a new one", "a separate attempt" |
|
|
69
|
+
| **Worktree** | that task's file tree on disk (`.task.worktreePath`) | — | "workspace", "this checkout", "this branch", "here" |
|
|
70
|
+
| **Terminal Tab** | one engine session inside a task | its own conversation, SAME files | "tab", "chattab", "another chat", "a second agent on this" |
|
|
71
|
+
| **Split** | the tree that divides ONE Terminal Tab into several regions (the `pane-open` verb's unit; a leaf is not called a pane) | none — same session's screen, same files | "split it", "side by side", "put the logs next to it" |
|
|
72
|
+
|
|
73
|
+
Two of those colloquialisms are traps, so read them as INTENT, not as
|
|
74
|
+
product terms: in kobe's own vocabulary **Workspace** is the center Terminal
|
|
75
|
+
Tab region of the UI (CONTEXT.md), not a checkout, and **ChatTab** is
|
|
76
|
+
retired vocabulary for Terminal Tab. A user saying "in this workspace" means
|
|
77
|
+
the worktree they are looking at — answer the intent, keep writing the real
|
|
78
|
+
term.
|
|
79
|
+
|
|
80
|
+
They nest — **Task ⊃ Terminal Tab ⊃ Split** — and isolation drops at every
|
|
81
|
+
level down:
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
new Task → own worktree + own branch (parallel work can't collide)
|
|
85
|
+
new Tab → own engine session, SAME files (a helper in the same checkout)
|
|
86
|
+
new Split → same session's screen, one tab divided (a monitor beside the work)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The distinction that decides every routing call: **a new tab shares the
|
|
90
|
+
worktree and branch; only a new task gets its own.** Two tabs in one task
|
|
91
|
+
edit the same files, so they can collide — that is a feature when the user
|
|
92
|
+
wants a helper in the same checkout, and a bug when they wanted parallel
|
|
93
|
+
attempts. A split isolates nothing at all: it is a layout, for watching
|
|
94
|
+
something (logs, `btop`, a test loop) next to the work — never the answer to
|
|
95
|
+
"do this work".
|
|
96
|
+
|
|
97
|
+
### Where does this work land?
|
|
98
|
+
|
|
99
|
+
Inside a kobe session (`$KOBE_TASK_ID` non-empty — check first: it is what
|
|
100
|
+
makes the tab/split rows addressable at all), match top to bottom and take
|
|
101
|
+
the first row that fits:
|
|
102
|
+
|
|
103
|
+
| The user says | Lands in | Command |
|
|
104
|
+
|---|---|---|
|
|
105
|
+
| "you do it", "just fix it", "change X to Y" | you, right here | no kobe verb — edit the files yourself |
|
|
106
|
+
| "try it N ways", "compare approaches" | N new tasks | `kobe api fan-out --repo "$PWD" --count N --prompt "…"` |
|
|
107
|
+
| "split", "side by side", "keep an eye on X while…" | a new region in the CURRENT tab | `kobe api pane-open --command "…"` |
|
|
108
|
+
| names a tab: "tell the agent in tab 3" | that exact tab | `kobe api send --task-id <id> --tab tab-3 --prompt "…"` |
|
|
109
|
+
| a LOCATION word: "in this workspace/worktree/checkout", "on this branch", "here", "same task" | THIS task, a NEW Terminal Tab | `kobe api send --task-id "$KOBE_TASK_ID" --tab new --prompt "…"` |
|
|
110
|
+
| **anything else — no row above matched** | a NEW task — new worktree + branch | `kobe api add --repo "$PWD" --prompt "…"` |
|
|
111
|
+
|
|
112
|
+
Order is the tiebreak: a count ("3 ways in this workspace") beats a location
|
|
113
|
+
word, and delegation language loses to "you do it" — the user asking YOU is
|
|
114
|
+
not asking for a fleet. Two more rules the table can't show:
|
|
115
|
+
|
|
116
|
+
- No location word at all ⇒ new task. It is the only routing whose isolation
|
|
117
|
+
cannot corrupt work-in-progress, so it is the safe default.
|
|
118
|
+
- "this repo" / "this project" are NOT location words — they name the repo,
|
|
119
|
+
not the checkout. Only worktree-scoped words route to a tab.
|
|
120
|
+
|
|
121
|
+
Outside a kobe session none of this applies: there is no "this task" to add
|
|
122
|
+
a tab to, so `add` / `fan-out` are the only routings available.
|
|
123
|
+
|
|
124
|
+
### Know where you are before you route
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
echo "$KOBE_TASK_ID / $KOBE_TAB_ID" # who you are (empty = not a kobe session)
|
|
128
|
+
kobe api get-task --task-id "$KOBE_TASK_ID" # .task.worktreePath, .task.branch, .running, .tabs[]
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`get-task` is the per-task read that answers "what is my worktree, my
|
|
132
|
+
branch, and which sibling tabs exist" — `.tabs[]` carries each tab's `id`, `kind`,
|
|
133
|
+
`vendor`, `lastTitle` and `alive`, which is exactly the target list for
|
|
134
|
+
`send --tab`. A tab flagged `unregistered: true` is a live session the tab
|
|
135
|
+
snapshot lost; it is addressable like any other.
|
|
136
|
+
|
|
64
137
|
## Discover before calling
|
|
65
138
|
|
|
66
139
|
```bash
|
|
@@ -95,8 +168,9 @@ kobe api send --task-id <id> --prompt "<complete next turn>"
|
|
|
95
168
|
# Reply home: no --task-id inside a dispatched task = the dispatcher's tab.
|
|
96
169
|
kobe api send --prompt "succeeded: <one line> (branch <final branch>)"
|
|
97
170
|
|
|
98
|
-
# A task can hold several
|
|
99
|
-
#
|
|
171
|
+
# A task can hold several Terminal Tabs. `get-task` lists ONE task's tabs (the
|
|
172
|
+
# usual read before addressing one); `inspect` is the wider diagnostic — every
|
|
173
|
+
# task's snapshot plus daemon activity and live pty sessions.
|
|
100
174
|
kobe api inspect --task-id <id>
|
|
101
175
|
kobe api send --task-id <id> --tab tab-3 --prompt "<turn>" # exact alive tab
|
|
102
176
|
kobe api send --task-id <id> --tab new --prompt "<turn>" # fresh engine tab
|
package/package.json
CHANGED