@tocca-systems/twp-cli 0.79.0 → 0.81.0

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,41 +0,0 @@
1
- import { createRequire as __twpCreateRequire } from 'node:module';
2
- const require = __twpCreateRequire(import.meta.url);
3
- import{isTrustworthyCacheFile,writePrivateFileAtomic}from"./chunk-D233KKXW.js";import{AuthSession,loadCredentials,withFileLock}from"./chunk-XNLIEUAW.js";import{httpFetch}from"./chunk-J7QYPKVK.js";import{parseVersionCore}from"./chunk-DXXFUNYN.js";import{effectiveApiUrl,effectiveRelayUrl,resolveConfiguredModel,resolveProfile}from"./chunk-EDF4U5BT.js";import{ensureTwpHome,twpHomeDir}from"./chunk-RZVI6PMW.js";import{stripTerminalControls}from"./chunk-NHYMHCAT.js";var MAX_EVENT_BYTES=8*1024*1024;var SseBufferOverflowError=class extends Error{constructor(limit){super(`SSE \u306E\u30A4\u30D9\u30F3\u30C8\u5883\u754C\uFF08\u7A7A\u884C\uFF09\u304C ${limit} \u30D0\u30A4\u30C8\u4EE5\u5185\u306B\u73FE\u308C\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u4E0A\u6D41\u306E\u5FDC\u7B54\u304C\u58CA\u308C\u3066\u3044\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002`)}};var SseParser=class{constructor(maxEventBytes=MAX_EVENT_BYTES){this.maxEventBytes=maxEventBytes}maxEventBytes;buffer="";pendingCr=false;push(chunk){
4
- let pending=this.pendingCr?`\r${chunk}`:chunk;this.pendingCr=pending.endsWith("\r");if(this.pendingCr)pending=pending.slice(0,-1);this.buffer+=pending.replace(/\r\n/g,"\n").replace(/\r/g,"\n");if(this.buffer.length>this.maxEventBytes){this.buffer="";this.pendingCr=false;throw new SseBufferOverflowError(this.maxEventBytes)}const events=[];for(;;){const boundary=this.buffer.indexOf("\n\n");if(boundary===-1)break;const block=this.buffer.slice(0,boundary);this.buffer=this.buffer.slice(boundary+2);const parsed=parseBlock(
5
- block);if(parsed)events.push(parsed)}return events}flush(){const rest=(this.pendingCr?`${this.buffer}
6
- `:this.buffer).trim();this.buffer="";this.pendingCr=false;if(rest==="")return[];const parsed=parseBlock(rest);return parsed?[parsed]:[]}};function parseBlock(block){let event="message";const data=[];for(const line of block.split("\n")){if(line.startsWith(":"))continue;const colon=line.indexOf(":");const field=colon===-1?line:line.slice(0,colon);let value=colon===-1?"":line.slice(colon+1);if(value.startsWith(" "))value=value.slice(1);if(field==="event")event=value;else if(field==="data")data.push(
7
- value)}if(data.length===0)return null;return{event,data:data.join("\n")}}var MODELS=[{id:"claude-opus-5",label:"Claude Opus 5",note:"\u6700\u3082\u9AD8\u6027\u80FD\u3002\u65E2\u5B9A"},{id:"claude-sonnet-5",label:"Claude Sonnet 5",note:"\u30D0\u30E9\u30F3\u30B9\u578B"},{id:"claude-haiku-4-5",label:"Claude Haiku 4.5",note:"\u9AD8\u901F\u30FB\u4F4E\u30B3\u30B9\u30C8"}];var DEFAULT_MODEL="claude-opus-5";function isSafeModelId(id){return/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(id)}function modelLabel(id){const known=MODELS.find(m=>m.id===id);if(known)return known.label;
8
- return prettifyClaudeId(id)??stripTerminalControls(id).slice(0,128)}function prettifyClaudeId(id){const match=/^claude-([a-z]+)((?:-\d+)+)$/.exec(id);if(!match)return null;const family=match[1]??"";const version=(match[2]??"").replace(/^-/,"").split("-").join(".");return`Claude ${family.charAt(0).toUpperCase()}${family.slice(1)} ${version}`}function modelNote(id){return MODELS.find(m=>m.id===id)?.note??""}function toModelInfos(ids){return ids.map(id=>({id,label:modelLabel(id),note:modelNote(id)}))}function blockLength(block){if(block.type==="text")return block.text.length;if(block.type==="tool_result")return block.content.length;return block.name.length+JSON.stringify(block.input).length}function emptyUsage(){return{inputTokens:0,cacheReadTokens:0,cacheWriteTokens:0,outputTokens:0}}var RelayError=class extends Error{constructor(kind,message,status){super(message);this.kind=kind;this.status=status;this.name="RelayError"}kind;status};var MODELS_TIMEOUT_MS=5e3;var RelayClient=class{constructor(relayUrl,session,fetchImpl=httpFetch,cliVersion="\
9
- 0.0.0-dev"){this.relayUrl=relayUrl;this.session=session;this.fetchImpl=fetchImpl;this.cliVersion=cliVersion}relayUrl;session;fetchImpl;cliVersion;async fetchModelCatalog(){const res=await this.send("GET","/api/cli/v1/models",void 0,AbortSignal.timeout(MODELS_TIMEOUT_MS));const body=await res.json().catch(()=>null);const ids=(body?.models??[]).map(m=>m.id).filter(id=>typeof id==="string"&&isSafeModelId(id));if(ids.length===0){throw new RelayError("upstream","\u30E2\u30C7\u30EB\u4E00\u89A7\u304C\u7A7A\u3067\u3057\u305F\uFF08\u30EA\u30EC\u30FC\u306E\u8A2D\u5B9A\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\uFF09")}
10
- const floor=body?.min_supported_version;const minSupportedVersion=typeof floor==="string"&&parseVersionCore(floor)!==null?floor.trim():null;return{ids,minSupportedVersion}}async stream(request,hooks){let res;try{res=await this.send("POST","/api/cli/v1/messages/stream",toWireBody(request),hooks.signal)}catch(err){if(isAbortError(err)||hooks.signal?.aborted===true){return{text:"",usage:emptyUsage(),toolUses:[],stopReason:null,aborted:true,upstreamError:null}}throw err}const body=res.body;if(!body){
11
- throw new RelayError("upstream","\u30EA\u30EC\u30FC\u304C\u5FDC\u7B54\u672C\u6587\u3092\u8FD4\u3057\u307E\u305B\u3093\u3067\u3057\u305F")}const parser=new SseParser;const decoder=new TextDecoder;const usage=emptyUsage();let text="";let stopReason=null;let streamError=null;const reader=body.getReader();const building=new Map;const toolUses=[];const finalizeBlock=index=>{const pending=building.get(index);if(!pending)return;building.delete(index);const input=pending.json.trim()===""?{}:safeJson(pending.
12
- json);if(input===null){streamError=`\u30C4\u30FC\u30EB ${pending.name} \u306E\u5F15\u6570\u3092\u89E3\u91C8\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F`;return}toolUses.push({type:"tool_use",id:pending.id,name:pending.name,input})};const handle=events=>{for(const ev of events){const parsed=safeJson(ev.data);if(!parsed)continue;const type=typeof parsed["type"]==="string"?parsed["type"]:ev.event;if(type==="message_start"){const message=parsed["message"];applyUsage(usage,message?.usage);continue}
13
- if(type==="content_block_start"){const block=parsed["content_block"];const index=numberOr(parsed["index"],-1);if(block?.type==="tool_use"&&typeof block.id==="string"&&typeof block.name==="string"){const seeded=block.input;const initial=typeof seeded==="object"&&seeded!==null&&!Array.isArray(seeded)?JSON.stringify(seeded):"";building.set(index,{id:block.id,name:block.name,json:initial==="{}"?"":initial})}continue}if(type==="content_block_delta"){const delta=parsed["delta"];if(delta?.type==="text_\
14
- delta"&&typeof delta.text==="string"&&delta.text!==""){text+=delta.text;hooks.onTextDelta(delta.text);continue}if(delta?.type==="input_json_delta"&&typeof delta.partial_json==="string"){const pending=building.get(numberOr(parsed["index"],-1));if(pending)pending.json+=delta.partial_json}continue}if(type==="content_block_stop"){finalizeBlock(numberOr(parsed["index"],-1));continue}if(type==="message_delta"){applyUsage(usage,parsed["usage"]);const delta=parsed["delta"];if(typeof delta?.stop_reason===
15
- "string")stopReason=delta.stop_reason;continue}if(type==="error"){const err=parsed["error"];streamError=typeof err?.message==="string"?err.message:"\u30B9\u30C8\u30EA\u30FC\u30E0\u304C\u4E2D\u65AD\u3055\u308C\u307E\u3057\u305F"}}};const onAbort=()=>{void reader.cancel().catch(()=>void 0)};if(hooks.signal){if(hooks.signal.aborted)onAbort();else hooks.signal.addEventListener("abort",onAbort,{once:true})}try{for(;;){const{done,value}=await reader.read();if(done)break;handle(parser.push(decoder.decode(
16
- value,{stream:true})))}handle(parser.flush())}catch(err){if(err instanceof SseBufferOverflowError){streamError=err.message}else if(!isAbortError(err)&&hooks.signal?.aborted!==true){throw new RelayError("network",`\u30B9\u30C8\u30EA\u30FC\u30E0\u304C\u5207\u65AD\u3055\u308C\u307E\u3057\u305F: ${errorMessage(err)}`)}}finally{hooks.signal?.removeEventListener("abort",onAbort);void reader.cancel().catch(()=>void 0)}for(const index of[...building.keys()])finalizeBlock(index);return{text,usage,toolUses,
17
- stopReason,aborted:hooks.signal?.aborted===true,upstreamError:streamError===null?null:stripTerminalControls(streamError)}}async send(method,path2,body,signal){let token;try{token=await this.session.getAccessToken()}catch(err){throw new RelayError("not_logged_in",errorMessage(err))}let res=await this.fetchOrThrow(method,path2,token,body,signal);if(res.status===401){try{token=await this.session.refresh(token)}catch(err){throw new RelayError("not_logged_in",errorMessage(err))}res=await this.fetchOrThrow(
18
- method,path2,token,body,signal)}if(!res.ok)throw await toRelayError(res);return res}async fetchOrThrow(method,path2,token,body,signal){try{return await this.fetchImpl(`${this.relayUrl}${path2}`,{method,headers:{Accept:body===void 0?"application/json":"text/event-stream, application/json",Authorization:`Bearer ${token}`,"User-Agent":`twp-cli/${this.cliVersion}`,...body!==void 0?{"Content-Type":"application/json"}:{}},...body!==void 0?{body:JSON.stringify(body)}:{},...signal?{signal}:{}})}catch(err){
19
- if(isAbortError(err))throw err;throw new RelayError("network",`\u30E2\u30C7\u30EB\u53D6\u6B21\u30B5\u30FC\u30D0\u306B\u63A5\u7D9A\u3067\u304D\u307E\u305B\u3093\uFF08${this.relayUrl}\uFF09: ${errorMessage(err)}`)}}};function toWireBody(request){const messages=request.messages.map((m,i)=>({role:m.role,content:m.content.map((block,j)=>{const isLastBlockOfLastMessage=i===request.messages.length-1&&j===m.content.length-1;return isLastBlockOfLastMessage&&m.role==="user"?{...block,cache_control:{type:"\
20
- ephemeral"}}:block})}));return{model:request.model,max_tokens:request.maxTokens,...request.system!==void 0?{system:request.system}:{},...request.tools&&request.tools.length>0?{tools:request.tools}:{},messages}}async function toRelayError(res){const body=await res.json().catch(()=>null);const nested=typeof body?.error==="object"&&body.error!==null?body.error:void 0;const message=stripTerminalControls(body?.message??nested?.message??`HTTP ${res.status}`);if(res.status===401){return new RelayError(
21
- "unauthorized","\u30E2\u30C7\u30EB\u53D6\u6B21\u306E\u8A8D\u8A3C\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002`twp login`\uFF08\u30D6\u30E9\u30A6\u30B6\u59D4\u8B72\uFF09\u307E\u305F\u306F `twp login --password` \u3067\u30ED\u30B0\u30A4\u30F3\u3057\u76F4\u3057\u3066\u304F\u3060\u3055\u3044\uFF08`twp login --token` \u3067\u4FDD\u5B58\u3057\u305F\u901A\u5E38\u30C8\u30FC\u30AF\u30F3\u306F\u30E2\u30C7\u30EB\u53D6\u6B21\u306B\u306F\u4F7F\u3048\u307E\u305B\u3093\uFF09\u3002",401)}if(res.status===403){
22
- return new RelayError("cli_disabled",message,403)}if(res.status===429){return new RelayError("rate_limit",message,429)}if(res.status===400){const detail=body?.details;if(Array.isArray(detail?.allowed_models)){return new RelayError("model_not_allowed",`${message}
23
- \u5229\u7528\u3067\u304D\u308B\u30E2\u30C7\u30EB: ${detail.allowed_models.join(" / ")}`,400)}return new RelayError("validation",message,400)}if(res.status===503){return new RelayError("unavailable",message,503)}return new RelayError("upstream",message,res.status)}function applyUsage(target,source){if(typeof source!=="object"||source===null)return;const usage=source;target.inputTokens=numberOr(usage["input_tokens"],target.inputTokens);target.cacheReadTokens=numberOr(usage["cache_read_input_tokens"],
24
- target.cacheReadTokens);target.cacheWriteTokens=numberOr(usage["cache_creation_input_tokens"],target.cacheWriteTokens);target.outputTokens=numberOr(usage["output_tokens"],target.outputTokens)}function numberOr(value,fallback){return typeof value==="number"&&Number.isFinite(value)?value:fallback}function safeJson(text){try{const parsed=JSON.parse(text);return typeof parsed==="object"&&parsed!==null?parsed:null}catch{return null}}function isAbortError(err){return err instanceof Error&&(err.name===
25
- "AbortError"||err.name==="TimeoutError")}function errorMessage(err){return err instanceof Error?err.message:String(err)}import fs from"fs";import path from"path";function modelCachePath(env=process.env){return path.join(twpHomeDir(env),"models.json")}function modelCacheLockPath(env=process.env){return path.join(twpHomeDir(env),"models.lock")}function builtinCatalog(){return{ids:MODELS.map(m=>m.id),source:"builtin",fetchedAt:null,minSupportedVersion:null}}function readCacheFile(env){const file=modelCachePath(env);if(!isTrustworthyCacheFile(file)){return{version:1,entries:{}}}const parsed=JSON.parse(fs.readFileSync(file,"utf8"));if(!parsed||typeof parsed!==
26
- "object"||typeof parsed.entries!=="object"||parsed.entries===null){return{version:1,entries:{}}}return parsed}function readFloor(entry){const raw=entry.min_supported_version;return typeof raw==="string"&&parseVersionCore(raw)!==null?raw.trim():null}function loadCachedVersionFloor(profile,relayUrl,env=process.env){try{const entry=readCacheFile(env).entries?.[profile];if(!entry||entry.relay_url!==relayUrl)return{minSupportedVersion:null,fetchedAt:null};return{minSupportedVersion:readFloor(entry),fetchedAt:typeof entry.
27
- fetched_at==="string"?entry.fetched_at:null}}catch{return{minSupportedVersion:null,fetchedAt:null}}}function loadCachedCatalog(profile,relayUrl,env=process.env){try{const parsed=readCacheFile(env).entries?.[profile];if(!parsed||parsed.relay_url!==relayUrl)return null;const ids=Array.isArray(parsed.models)?parsed.models.filter(id=>typeof id==="string"&&isSafeModelId(id)):[];if(ids.length===0)return null;return{ids,source:"cache",fetchedAt:typeof parsed.fetched_at==="string"?parsed.fetched_at:null,
28
- minSupportedVersion:readFloor(parsed)}}catch{return null}}async function saveCatalog(profile,relayUrl,ids,minSupportedVersion,env=process.env,now=Date.now){try{ensureTwpHome(env);await withFileLock(modelCacheLockPath(env),async()=>{let file;try{file=readCacheFile(env)}catch{file={version:1,entries:{}}}const entries={...file.entries??{}};entries[profile]={relay_url:relayUrl,fetched_at:new Date(now()).toISOString(),models:ids,min_supported_version:minSupportedVersion};writePrivateFileAtomic(modelCachePath(
29
- env),`${JSON.stringify({version:1,entries},null,2)}
30
- `)})}catch{}}async function loadCatalog(client,profile,relayUrl,env=process.env){try{const{ids,minSupportedVersion}=await client.fetchModelCatalog();await saveCatalog(profile,relayUrl,ids,minSupportedVersion,env);return{ids,source:"server",fetchedAt:new Date().toISOString(),minSupportedVersion}}catch{return loadCachedCatalog(profile,relayUrl,env)??builtinCatalog()}}function pickModel(catalog,configured){const fallback=catalog.ids[0]??MODELS[0]?.id??DEFAULT_MODEL;if(!configured||configured==="")return{
31
- model:fallback};if(catalog.ids.includes(configured))return{model:configured};if(catalog.source==="builtin"){return{model:configured,warning:`\u30E2\u30C7\u30EB\u4E00\u89A7\u3092\u53D6\u5F97\u3067\u304D\u306A\u304B\u3063\u305F\u305F\u3081\u3001\u6307\u5B9A\u3055\u308C\u305F ${configured} \u3092\u305D\u306E\u307E\u307E\u4F7F\u3044\u307E\u3059\uFF08\u5229\u7528\u3067\u304D\u306A\u3044\u5834\u5408\u306F\u30EA\u30EC\u30FC\u304C 400 \u3092\u8FD4\u3057\u307E\u3059\uFF09`}}return{model:fallback,warning:`${configured}\
32
- \u306F\u5229\u7528\u3067\u304D\u306A\u3044\u305F\u3081 ${fallback} \u3092\u4F7F\u3044\u307E\u3059\uFF08\u5229\u7528\u53EF\u80FD: ${catalog.ids.join(" / ")}\uFF09`}}var DEFAULT_CONTEXT_WINDOW_TOKENS=2e5;var DEFAULT_MAX_TOKENS=8192;var TRIM_THRESHOLD=.8;var ContextManager=class{constructor(contextWindowTokens=DEFAULT_CONTEXT_WINDOW_TOKENS){this.contextWindowTokens=contextWindowTokens}contextWindowTokens;messages=[];totals=emptyUsage();turns=0;lastPromptTokens=0;pendingChars=0;droppedMessages=0;addUser(text){this.pendingChars+=text.length;const last=this.messages[this.messages.length-1];if(last?.role==="user"){last.content.push({type:"text",text});return}this.
33
- messages.push({role:"user",content:[{type:"text",text}]})}addToolExchange(assistantText,toolUses,results){if(toolUses.length===0)return;const blocks=[];if(assistantText.trim()!=="")blocks.push({type:"text",text:assistantText});blocks.push(...toolUses);this.messages.push({role:"assistant",content:blocks});this.messages.push({role:"user",content:results});this.pendingChars+=blocks.reduce((n,b)=>n+blockLength(b),0);this.pendingChars+=results.reduce((n,b)=>n+blockLength(b),0)}completeTurn(assistantText){
34
- const text=assistantText.trim();if(text===""){const last=this.messages[this.messages.length-1];if(last?.role==="user"&&!hasToolResult(last)){this.messages.pop();this.pendingChars=Math.max(0,this.pendingChars-lengthOf(last))}return false}this.messages.push({role:"assistant",content:[{type:"text",text:assistantText}]});this.pendingChars+=assistantText.length;this.turns+=1;return true}applyUsage(usage){this.totals={inputTokens:this.totals.inputTokens+usage.inputTokens,cacheReadTokens:this.totals.cacheReadTokens+
35
- usage.cacheReadTokens,cacheWriteTokens:this.totals.cacheWriteTokens+usage.cacheWriteTokens,outputTokens:this.totals.outputTokens+usage.outputTokens};const prompt=usage.inputTokens+usage.cacheReadTokens+usage.cacheWriteTokens;if(prompt>0){this.lastPromptTokens=prompt;this.pendingChars=0}}history(){return this.messages.map(m=>({role:m.role,content:m.content.map(copyBlock)}))}isEmpty(){return this.messages.length===0}clear(){this.messages=[];this.totals=emptyUsage();this.turns=0;this.lastPromptTokens=
36
- 0;this.pendingChars=0;this.droppedMessages=0}trimToFit(maxTokens=DEFAULT_MAX_TOKENS){const limit=Math.max(1,Math.floor((this.contextWindowTokens-maxTokens)*TRIM_THRESHOLD));let dropped=0;while(this.estimatedPromptTokens()>limit&&this.messages.length>1){const removed=this.messages.shift();if(!removed)break;const removedTokens=Math.ceil(lengthOf(removed)/4);this.lastPromptTokens=Math.max(0,this.lastPromptTokens-removedTokens);dropped+=1}while(this.messages.length>0){const head2=this.messages[0];if(!head2)
37
- break;const orphanResult=hasToolResult(head2)&&this.messages.length>1;if(head2.role!=="assistant"&&!orphanResult)break;this.messages.shift();this.lastPromptTokens=Math.max(0,this.lastPromptTokens-Math.ceil(lengthOf(head2)/4));dropped+=1}const head=this.messages[0];if(head&&hasToolResult(head)){const before=lengthOf(head);const kept=head.content.filter(block=>block.type!=="tool_result");head.content=kept.length>0?kept:[{type:"text",text:"\uFF08\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u4E0A\u9650\u306E\u305F\u3081\u3001\u76F4\u524D\u306E\u30C4\u30FC\u30EB\u5B9F\u884C\u7D50\u679C\u306F\u5C65\u6B74\u304B\u3089\u5916\u308C\u307E\u3057\u305F\uFF09"}];
38
- const freed=before-lengthOf(head);this.lastPromptTokens=Math.max(0,this.lastPromptTokens-Math.ceil(freed/4));this.pendingChars=Math.max(0,this.pendingChars-freed);dropped+=1}this.droppedMessages+=dropped;return dropped}estimatedPromptTokens(){if(this.lastPromptTokens===0){return Math.ceil(this.totalChars()/4)}return this.lastPromptTokens+Math.ceil(this.pendingChars/4)}snapshot(){const used=this.estimatedPromptTokens();const remaining=Math.round((this.contextWindowTokens-used)/this.contextWindowTokens*
39
- 100);return{totals:{...this.totals},turns:this.turns,lastPromptTokens:this.lastPromptTokens,remainingPercent:Math.max(0,Math.min(100,remaining)),droppedMessages:this.droppedMessages}}totalChars(){return this.messages.reduce((sum,m)=>sum+lengthOf(m),0)}};function lengthOf(message){return message.content.reduce((sum,block)=>sum+blockLength(block),0)}function copyBlock(block){return block.type==="tool_use"?{...block,input:{...block.input}}:{...block}}function hasToolResult(message){return message.content.
40
- some(block=>block.type==="tool_result")}function createRuntime(opts){const env=opts.env??process.env;const cwd=opts.cwd??process.cwd();const profile=resolveProfile(opts.profile,env,cwd);const creds=loadCredentials(profile.name,env);const apiUrl=effectiveApiUrl(profile,creds?.api_url,env);const relayUrl=effectiveRelayUrl(profile,creds?.relay_url,env);const session=new AuthSession(profile.name,apiUrl,env);const client=new RelayClient(relayUrl,session,httpFetch,opts.cliVersion);const configured=resolveConfiguredModel(opts.model,profile.name,
41
- env,cwd);return{profileName:profile.name,apiUrl,relayUrl,client,session,context:new ContextManager,loggedIn:creds!==null,configuredModel:configured?.model??null,loadCatalog:()=>loadCatalog(client,profile.name,relayUrl,env),loadCachedFloor:()=>loadCachedVersionFloor(profile.name,relayUrl,env)}}export{modelLabel,toModelInfos,emptyUsage,RelayError,DEFAULT_MAX_TOKENS,builtinCatalog,loadCachedCatalog,pickModel,createRuntime};