blade-code 0.8.2 → 0.8.3
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/blade.js +2 -2
- package/dist/{chunk-0z5qe4m2.js → chunk-1m63zddw.js} +1 -1
- package/dist/chunk-23h9grdr.js +1 -0
- package/dist/{chunk-6jq8h5s9.js → chunk-2c69g6t9.js} +2 -2
- package/dist/{chunk-p4yrmzyr.js → chunk-5sccs44n.js} +1 -1
- package/dist/{chunk-5ad4qmfj.js → chunk-5yt80bn2.js} +1 -1
- package/dist/chunk-6msfa7jh.js +9 -0
- package/dist/{chunk-yfcfx0zk.js → chunk-6spmzx13.js} +1 -1
- package/dist/chunk-724djh7r.js +1 -0
- package/dist/{chunk-81p4kz0b.js → chunk-7bqkkjxf.js} +1 -1
- package/dist/chunk-804j7say.js +1 -0
- package/dist/chunk-8yk5w2ks.js +1 -0
- package/dist/chunk-97qxd4yb.js +2 -0
- package/dist/{chunk-qwfqp465.js → chunk-9cr3jexy.js} +1 -1
- package/dist/{chunk-kne7h7p5.js → chunk-ar5564sf.js} +1 -1
- package/dist/{chunk-f3pvwxp8.js → chunk-b922cq7k.js} +3 -3
- package/dist/{chunk-w4xcmzjm.js → chunk-be7qz4cv.js} +1 -1
- package/dist/chunk-bqhghfmt.js +6 -0
- package/dist/{chunk-s1y8w68s.js → chunk-crbh6x86.js} +1 -1
- package/dist/{chunk-5fw9k1ff.js → chunk-d7nrqg5b.js} +2 -2
- package/dist/{chunk-9xvnrq7m.js → chunk-eyypmc9m.js} +2 -2
- package/dist/{chunk-j77gyhpf.js → chunk-fma9cbq5.js} +1 -1
- package/dist/chunk-ghf5tgjr.js +1 -0
- package/dist/{chunk-11s7t9dp.js → chunk-hqtskyc1.js} +2 -2
- package/dist/chunk-jc7k8pfn.js +22 -0
- package/dist/{chunk-eycs00af.js → chunk-kf43f8sy.js} +218 -218
- package/dist/{chunk-rxjt7ma7.js → chunk-kjc2aqww.js} +1 -1
- package/dist/chunk-kjddt9xy.js +1 -0
- package/dist/{chunk-6avkjdjc.js → chunk-m0ded6ky.js} +27 -27
- package/dist/{chunk-fpdqvnmq.js → chunk-mqqajem9.js} +2 -2
- package/dist/{chunk-a90mfxv9.js → chunk-msr67f6q.js} +1 -1
- package/dist/{chunk-y08szyf9.js → chunk-mvww9cmc.js} +20 -20
- package/dist/{chunk-fkaebj8c.js → chunk-nbpjzzrg.js} +1 -1
- package/dist/chunk-ncvr73ev.js +1 -0
- package/dist/{chunk-9b297mzh.js → chunk-qvtahmff.js} +1 -1
- package/dist/chunk-qwn46cd6.js +2 -0
- package/dist/{chunk-887qxhn5.js → chunk-sva5bdgz.js} +2 -2
- package/dist/{chunk-4fye39a8.js → chunk-t9cqscfq.js} +1 -1
- package/dist/chunk-tzr992v4.js +1 -0
- package/dist/{chunk-1x3846v7.js → chunk-vxpdjtqc.js} +1 -1
- package/dist/{chunk-6x6zqjcs.js → chunk-wcf80p9y.js} +1 -1
- package/dist/chunk-x8xfx9nv.js +1 -0
- package/dist/{chunk-8fp3q919.js → chunk-yewg510f.js} +2 -2
- package/dist/{chunk-w11ht6f9.js → chunk-zj3q4btp.js} +1 -1
- package/dist/chunk-zjks0ncc.js +6 -0
- package/dist/{chunk-0g9cb41d.js → chunk-zsyff0ky.js} +2 -2
- package/dist/web/assets/{FilePreview-60E51igH.js → FilePreview-B5g8yi8d.js} +1 -1
- package/dist/web/assets/{MarkdownRenderer-DU7jPn9K.js → MarkdownRenderer-qBCxzEb_.js} +1 -1
- package/dist/web/assets/{McpModal-CAMU6yrS.js → McpModal-C7y2Fsqc.js} +1 -1
- package/dist/web/assets/{SettingsModal-Cjj8NUQy.js → SettingsModal-Dmc7Dw_E.js} +1 -1
- package/dist/web/assets/{SettingsStore-CjvkbtuZ.js → SettingsStore-BfoB9tNV.js} +1 -1
- package/dist/web/assets/{SkillsModal-Cyc2JAFj.js → SkillsModal-CqFAIfj5.js} +1 -1
- package/dist/web/assets/{TerminalPanel-DI-Ls-U8.js → TerminalPanel-EHh8-9b9.js} +1 -1
- package/dist/web/assets/index-B-BRpW1c.js +16 -0
- package/dist/web/assets/index-Ch0eqSLM.css +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/chunk-1evg2hdd.js +0 -2
- package/dist/chunk-3wghk9bp.js +0 -1
- package/dist/chunk-510rwhx6.js +0 -1
- package/dist/chunk-83dkggbx.js +0 -1
- package/dist/chunk-8epvwyg8.js +0 -6
- package/dist/chunk-9jkbykwq.js +0 -1
- package/dist/chunk-a83s9mww.js +0 -1
- package/dist/chunk-btst30by.js +0 -6
- package/dist/chunk-e9t5ga1b.js +0 -1
- package/dist/chunk-gvf4gff0.js +0 -9
- package/dist/chunk-j14rn2dx.js +0 -22
- package/dist/chunk-kcjgbbec.js +0 -1
- package/dist/chunk-q223bq79.js +0 -1
- package/dist/chunk-x83a97eh.js +0 -1
- package/dist/chunk-zns65xsy.js +0 -2
- package/dist/web/assets/index-BC0ssrep.js +0 -16
- package/dist/web/assets/index-Ci6gCUjf.css +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
2
|
-
export{s as
|
|
1
|
+
import{nc as r}from"./chunk-zsyff0ky.js";function s(e,a,i){let t=r().resolveConfig(e),o=e.overrides;return{config:e,model:t,displayName:e.displayName??t.name,chat:{provider:e.provider,model:e.model,apiKey:process.env.BLADE_API_KEY,baseUrl:process.env.BLADE_BASE_URL??o?.baseUrl,temperature:o?.temperature??a.temperature,maxContextTokens:t.contextWindow,maxOutputTokens:o?.maxOutputTokens,timeout:o?.timeout??a.timeout,reasoningEnabled:t.reasoning&&i,fallbackModels:e.fallbackModels,enablePromptCaching:o?.enablePromptCaching,customHeaders:o?.customHeaders,apiVersion:o?.apiVersion,maxRetries:o?.maxRetries}}}function n(e){try{return e.displayName??r().getModel(e.provider,e.model).name}catch{return e.displayName??e.model}}
|
|
2
|
+
export{s as Ra,n as Sa};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import{Sb as V,Ub as j,Vb as y}from"./chunk-kjc2aqww.js";import{bc as O}from"./chunk-eyypmc9m.js";import{nc as x}from"./chunk-zsyff0ky.js";var N={currentModelId:"",models:[],temperature:0,maxOutputTokens:void 0,stream:!0,topP:0.9,topK:50,timeout:180000,theme:"dracula",uiTheme:"system",language:"zh-CN",fontSize:14,autoSaveSessions:!0,notifyBuild:!0,notifyErrors:!1,notifySounds:!1,privacyTelemetry:!1,privacyCrash:!0,debug:!1,mcpEnabled:!1,mcpServers:{},permissions:{allow:["Bash(pwd)","Bash(which *)","Bash(whoami)","Bash(hostname)","Bash(uname *)","Bash(date)","Bash(echo *)","Bash(ls *)","Bash(tree *)","Bash(git status)","Bash(git status -*)","Bash(git log *)","Bash(git diff *)","Bash(git show *)","Bash(git branch -* *)","Bash(git branch)","Bash(git tag -l *)","Bash(git tag --list *)","Bash(git stash list *)","Bash(git stash show *)","Bash(git rev-parse *)","Bash(git describe *)","Bash(git blame *)","Bash(git ls-files *)","Bash(git config --get *)","Bash(git config --list *)","Bash(git shortlog *)","Bash(git merge-base *)","Bash(git cat-file *)","Bash(git for-each-ref *)","Bash(git grep *)","Bash(git worktree list *)","Bash(git reflog show *)","Bash(git reflog)","Bash(git rev-list *)","Bash(git ls-remote *)","Bash(git remote -v)","Bash(git remote --verbose)","Bash(git remote)","Bash(gh pr view *)","Bash(gh pr list *)","Bash(gh pr diff *)","Bash(gh pr checks *)","Bash(gh pr status *)","Bash(gh issue view *)","Bash(gh issue list *)","Bash(gh issue status *)","Bash(gh run list *)","Bash(gh run view *)","Bash(gh repo view *)","Bash(gh auth status)","Bash(npm list *)","Bash(bun pm ls *)","Bash(npm view *)","Bash(npm outdated *)","Bash(pnpm list *)","Bash(yarn list *)","Bash(pip list *)","Bash(pip show *)"],ask:["Bash(curl *)","Bash(wget *)","Bash(aria2c *)","Bash(axel *)","Bash(rm -rf *)","Bash(rm -r *)","Bash(rm --recursive *)","Bash(nc *)","Bash(netcat *)","Bash(telnet *)","Bash(ncat *)"],deny:["Read(./.env)","Read(./.env.*)","Bash(rm -rf /)","Bash(rm -rf /*)","Bash(sudo *)","Bash(chmod 777 *)","Bash(bash *)","Bash(sh *)","Bash(zsh *)","Bash(fish *)","Bash(dash *)","Bash(eval *)","Bash(source *)","Bash(mkfs *)","Bash(fdisk *)","Bash(dd *)","Bash(format *)","Bash(parted *)","Bash(open http*)","Bash(open https*)","Bash(xdg-open http*)","Bash(xdg-open https*)"]},permissionMode:"default",hooks:{enabled:!1,defaultTimeout:60,timeoutBehavior:"ignore",failureBehavior:"ignore",maxConcurrentHooks:5,PreToolUse:[],PostToolUse:[],PostToolUseFailure:[],PermissionRequest:[],UserPromptSubmit:[],SessionStart:[],SessionEnd:[],Stop:[],SubagentStop:[],Notification:[],Compaction:[]},env:{},disableAllHooks:!1,maxTurns:-1,maxConcurrentTasks:3,maxQueuedTasks:100};import{promises as S}from"fs";import{merge as b}from"lodash-es";import D from"os";import $ from"path";var h={sonnet:"claude-sonnet-4-20250514",opus:"claude-opus-4-20250514",haiku:"claude-3-5-haiku-20241022",claude:"claude-sonnet-4-20250514",gpt4o:"gpt-4o",gpt4:"gpt-4o",o1:"o1",o3:"o3","o4-mini":"o4-mini",deepseek:"deepseek-chat","deepseek-v3":"deepseek-chat","deepseek-r1":"deepseek-reasoner","deepseek-v4":"deepseek-v4-0324",gemini:"gemini-2.5-pro",flash:"gemini-2.5-flash",qwen:"qwen3-235b-a22b","qwen-max":"qwen-max","qwen-plus":"qwen-plus"};function T(X){let K=X.toLowerCase().trim();return h[K]??X}var A=1,F=64,E=1,M=1e4;function L(X){return Number.isInteger(X)&&X>=1&&X<=64}function w(X){return Number.isInteger(X)&&X>=1&&X<=1e4}class U{static instance=null;runtimePermissionOverrides;constructor(){}static getInstance(){if(!U.instance)U.instance=new U;return U.instance}static resetInstance(){U.instance=null}async initialize(X){try{this.runtimePermissionOverrides=X?.permissions;let K=await this.loadConfigFiles(),Q=await this.loadSettingsFiles(),q={...K,...Q};if(X)q=this.mergeSettings(q,X);let H=this.normalizeConfig(q),J={...N,...H};if(this.resolveEnvInterpolation(J),process.env.BLADE_MODEL&&J.models?.length>0){let W=T(process.env.BLADE_MODEL),Y=J.models.find((Z)=>Z.id===W||Z.model===W||Z.id===process.env.BLADE_MODEL||Z.model===process.env.BLADE_MODEL);if(Y)J.currentModelId=Y.id}if(process.env.BLADE_DEBUG)J.debug=process.env.BLADE_DEBUG==="1"||process.env.BLADE_DEBUG==="true"||process.env.BLADE_DEBUG;if(J.models.length>0)this.validateConfig(J);if(J.debug)console.log("[ConfigManager] Configuration loaded successfully");return J}catch(K){return console.error("[ConfigManager] Failed to initialize:",K),N}}async loadConfigFiles(){let X=$.join(D.homedir(),".blade","config.json"),K=$.join(V(),".blade","config.json"),Q={},q=await this.loadJsonFile(X);if(q)Q={...Q,...q};let H=await this.loadJsonFile(K);if(H){let J={...Q.mcpServers||{},...H.mcpServers||{}};if(Q={...Q,...H},Object.keys(J).length>0)Q.mcpServers=J}return Q}async loadSettingsFiles(){let X=$.join(D.homedir(),".blade","settings.json"),K=$.join(V(),".blade","settings.json"),Q=$.join(V(),".blade","settings.local.json"),q={},H=await this.loadJsonFile(X);if(H)q=this.mergeSettings(q,H);let J=await this.loadJsonFile(K);if(J)q=this.mergeSettings(q,J);let W=await this.loadJsonFile(Q);if(W)q=this.mergeSettings(q,W);return q}async loadWorkspacePermissions(X,K){let Q={allow:[...K.allow],ask:[...K.ask],deny:[...K.deny]};if($.resolve(X)!==$.resolve(V())){let H=await this.loadWorkspacePermissionOverrides(V()),J=await this.loadJsonFile($.join(D.homedir(),".blade","settings.json")),W={allow:Array.from(new Set([...N.permissions.allow,...J?.permissions?.allow||[],...this.runtimePermissionOverrides?.allow||[]])),ask:Array.from(new Set([...N.permissions.ask,...J?.permissions?.ask||[],...this.runtimePermissionOverrides?.ask||[]])),deny:Array.from(new Set([...N.permissions.deny,...J?.permissions?.deny||[],...this.runtimePermissionOverrides?.deny||[]]))};for(let Y of["allow","ask","deny"]){let Z=new Set(H[Y].filter((R)=>!W[Y].includes(R)));Q[Y]=Q[Y].filter((R)=>!Z.has(R))}}let q=await this.loadWorkspacePermissionOverrides(X);for(let H of["allow","ask","deny"])Q[H]=Array.from(new Set([...Q[H],...q[H]]));return Q}async loadWorkspacePermissionOverrides(X){let K={allow:[],ask:[],deny:[]},Q=[$.join(X,".blade","settings.json"),$.join(X,".blade","settings.local.json")];for(let q of Q){let H=await this.loadJsonFile(q);if(!H?.permissions)continue;for(let J of["allow","ask","deny"])K[J]=Array.from(new Set([...K[J],...H.permissions[J]||[]]))}return K}mergeSettings(X,K){let Q={...JSON.parse(JSON.stringify(X)),...JSON.parse(JSON.stringify(K))};if(K.permissions)Q.permissions={allow:Array.from(new Set([...X.permissions?.allow||[],...K.permissions.allow||[]])),ask:Array.from(new Set([...X.permissions?.ask||[],...K.permissions.ask||[]])),deny:Array.from(new Set([...X.permissions?.deny||[],...K.permissions.deny||[]]))};if(K.hooks)Q.hooks=b({},Q.hooks,K.hooks);if(K.env)Q.env=b({},Q.env,K.env);if(K.mcpServers)Q.mcpServers={...Q.mcpServers||{},...K.mcpServers};if(K.disableAllHooks!==void 0)Q.disableAllHooks=K.disableAllHooks;if(K.permissionMode!==void 0)Q.permissionMode=K.permissionMode;if(K.maxTurns!==void 0)Q.maxTurns=K.maxTurns;return Q}resolveEnvInterpolation(X){let K=/\$\{?([A-Z_][A-Z0-9_]*)(:-([^}]+))?\}?/g,Q=(H)=>{if(typeof H==="string")return H.replace(K,(J,W,Y,Z)=>{return process.env[W]||Z||J});if(Array.isArray(H))return H.map(Q);if(typeof H==="object"&&H!==null){let J=H;for(let[W,Y]of Object.entries(J))J[W]=Q(Y);return J}return H},q=X;for(let[H,J]of Object.entries(q))q[H]=Q(J)}async loadJsonFile(X){try{if(await this.fileExists(X)){let K=await S.readFile(X,"utf-8");return JSON.parse(K)}}catch(K){console.warn(`[ConfigManager] Failed to load ${X}:`,K)}return null}async fileExists(X){try{return await S.access(X),!0}catch{return!1}}normalizeConfig(X){let K=JSON.parse(JSON.stringify(X)),Q=(H)=>H.trim().replace(/^`|`$/g,""),q=(H)=>{for(let[J,W]of Object.entries(H))if(typeof W==="string")H[J]=Q(W);else if(Array.isArray(W))W.forEach((Y,Z)=>{if(typeof Y==="string")W[Z]=Q(Y);else if(typeof Y==="object"&&Y!==null)q(Y)});else if(typeof W==="object"&&W!==null)q(W)};return q(K),K}validateConfig(X){let K=[];if(!X.models||X.models.length===0)K.push("没有可用的模型配置");if(!j(X.maxTurns))K.push(`maxTurns 必须是 ${y()}`);if(!L(X.maxConcurrentTasks))K.push(`maxConcurrentTasks 必须是 ${A}-${F} 之间的整数`);if(!w(X.maxQueuedTasks))K.push(`maxQueuedTasks 必须是 ${E}-${M} 之间的整数`);if(X.models&&X.models.length>0){if(!X.currentModelId)K.push("未设置当前模型 ID");else if(!X.models.find((q)=>q.id===X.currentModelId))K.push(`当前模型 ID "${X.currentModelId}" 在 models 列表中不存在`);for(let Q of X.models){let q=`模型 "${Q.displayName||Q.id}"`,H=["name","apiKey","baseUrl","maxContextTokens","maxOutputTokens","supportsThinking","thinkingBudget","thinkingMode"].filter((J)=>(J in Q));if(H.length>0)K.push(`${q}: 不再支持旧字段 ${H.join(", ")};请重新配置模型`);if(!Q.model)K.push(`${q}: model 字段必填`);if(!Q.provider)K.push(`${q}: provider 字段必填`);if(Q.overrides?.baseUrl&&!Q.overrides.baseUrl.startsWith("http"))K.push(`${q}: overrides.baseUrl "${Q.overrides.baseUrl}" 不是有效的 HTTP URL`);try{x().getModel(Q.provider,Q.model)}catch{K.push(`${q}: 内置 catalog 中不存在 ${Q.provider}/${Q.model}`)}}}if(K.length>0)throw Error(`配置验证失败:
|
|
2
|
+
${K.map((Q)=>` - ${Q}`).join(`
|
|
3
|
+
`)}
|
|
4
|
+
|
|
5
|
+
`+`请通过以下方式之一提供配置:
|
|
6
|
+
`+` 1. 首次启动: 运行 blade,系统会自动引导配置
|
|
7
|
+
`+` 2. 添加模型: blade 后输入 /model add
|
|
8
|
+
`+` 3. 初始化向导: 输入 /init
|
|
9
|
+
|
|
10
|
+
`+`配置文件示例 (~/.blade/config.json):
|
|
11
|
+
`+`{
|
|
12
|
+
"currentModelId": "model-id-123",
|
|
13
|
+
"models": [
|
|
14
|
+
{
|
|
15
|
+
"id": "model-id-123",
|
|
16
|
+
`+` "displayName": "默认模型",
|
|
17
|
+
`+` "provider": "deepseek",
|
|
18
|
+
"model": "deepseek-v4-pro"
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
`)}}function m(X,K={}){let Q={...X};if(K.debug!==void 0)Q.debug=K.debug===""?!0:K.debug;if(K.model){if(!X.models.some((H)=>H.id===K.model))throw Error(`模型配置未找到: ${K.model}`);Q.currentModelId=K.model}if(K.yolo===!0)Q.permissionMode="yolo";else if(K.permissionMode!==void 0)Q.permissionMode=K.permissionMode;if(K.maxTurns!==void 0)Q.maxTurns=K.maxTurns;if(K.maxConcurrentTasks!==void 0)Q.maxConcurrentTasks=K.maxConcurrentTasks;if(K.maxQueuedTasks!==void 0)Q.maxQueuedTasks=K.maxQueuedTasks;return Q.systemPrompt=K.systemPrompt,Q.appendSystemPrompt=K.appendSystemPrompt,Q.model=K.model,Q.resumeSessionId=K.sessionId,Q.forkSession=K.forkSession,Q.allowedTools=K.allowedTools,Q.disallowedTools=K.disallowedTools,Q.mcpConfigPaths=K.mcpConfig,Q.strictMcpConfig=K.strictMcpConfig,Q.addDirs=K.addDir,Q.outputFormat=K.outputFormat,Q.inputFormat=K.inputFormat,Q.print=K.print,Q.includePartialMessages=K.includePartialMessages,Q.replayUserMessages=K.replayUserMessages,Q.agentsConfig=K.agents,Q.settingSources=K.settingSources,Q}import{promises as G}from"node:fs";import k from"node:os";import B from"node:path";import{Mutex as C}from"async-mutex";import{merge as v}from"lodash-es";import u from"write-file-atomic";var P=O("Service"),_={models:{target:"config",defaultScope:"global",mergeStrategy:"replace",persistable:!0},currentModelId:{target:"config",defaultScope:"global",mergeStrategy:"replace",persistable:!0},temperature:{target:"config",defaultScope:"global",mergeStrategy:"replace",persistable:!0},maxOutputTokens:{target:"config",defaultScope:"global",mergeStrategy:"replace",persistable:!0},timeout:{target:"config",defaultScope:"global",mergeStrategy:"replace",persistable:!0},theme:{target:"config",defaultScope:"global",mergeStrategy:"replace",persistable:!0},uiTheme:{target:"config",defaultScope:"global",mergeStrategy:"replace",persistable:!0},language:{target:"config",defaultScope:"global",mergeStrategy:"replace",persistable:!0},debug:{target:"config",defaultScope:"global",mergeStrategy:"replace",persistable:!0},fontSize:{target:"config",defaultScope:"global",mergeStrategy:"replace",persistable:!0},autoSaveSessions:{target:"config",defaultScope:"global",mergeStrategy:"replace",persistable:!0},notifyBuild:{target:"config",defaultScope:"global",mergeStrategy:"replace",persistable:!0},notifyErrors:{target:"config",defaultScope:"global",mergeStrategy:"replace",persistable:!0},notifySounds:{target:"config",defaultScope:"global",mergeStrategy:"replace",persistable:!0},privacyTelemetry:{target:"config",defaultScope:"global",mergeStrategy:"replace",persistable:!0},privacyCrash:{target:"config",defaultScope:"global",mergeStrategy:"replace",persistable:!0},permissionMode:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!1},permissions:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!0},hooks:{target:"settings",defaultScope:"local",mergeStrategy:"deep-merge",persistable:!0},env:{target:"settings",defaultScope:"local",mergeStrategy:"deep-merge",persistable:!0},disableAllHooks:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!0},maxTurns:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!0},maxConcurrentTasks:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!0},maxQueuedTasks:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!0},mcpServers:{target:"config",defaultScope:"global",mergeStrategy:"replace",persistable:!0},stream:{target:"config",defaultScope:"global",mergeStrategy:"replace",persistable:!1},topP:{target:"config",defaultScope:"global",mergeStrategy:"replace",persistable:!1},topK:{target:"config",defaultScope:"global",mergeStrategy:"replace",persistable:!1},mcpEnabled:{target:"config",defaultScope:"global",mergeStrategy:"replace",persistable:!1},systemPrompt:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!1},appendSystemPrompt:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!1},initialMessage:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!1},resumeSessionId:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!1},forkSession:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!1},allowedTools:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!1},disallowedTools:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!1},mcpConfigPaths:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!1},strictMcpConfig:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!1},addDirs:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!1},outputFormat:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!1},inputFormat:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!1},print:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!1},includePartialMessages:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!1},replayUserMessages:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!1},agentsConfig:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!1},settingSources:{target:"settings",defaultScope:"local",mergeStrategy:"replace",persistable:!1}},_K=new Set(Object.entries(_).filter(([X,K])=>K.persistable).map(([X])=>X)),GK=new Set(Object.entries(_).filter(([X,K])=>!K.persistable).map(([X])=>X));class z{static instance=null;pendingUpdates=new Map;timers=new Map;fileLocks=new Map;lastSaveError=null;debounceDelay=300;constructor(){}static getInstance(){if(!z.instance)z.instance=new z;return z.instance}static resetInstance(){if(z.instance)for(let X of z.instance.timers.values())clearTimeout(X);z.instance=null}async save(X,K={}){this.validatePersistableFields(X);let Q=this.groupUpdatesByTarget(X,K.scope,K.projectDir);if(K.immediate)await Promise.all(Array.from(Q.entries()).map(([q,H])=>this.flushTarget(q,H)));else for(let[q,H]of Q)this.scheduleSave(q,H)}async flush(){for(let K of this.timers.values())clearTimeout(K);this.timers.clear();let X=Array.from(this.pendingUpdates.entries()).map(([K,Q])=>this.flushTarget(K,Q));this.pendingUpdates.clear(),await Promise.all(X)}getLastSaveError(){return this.lastSaveError}clearLastSaveError(){this.lastSaveError=null}async appendPermissionRule(X,K={}){await this.appendPermissionRuleForDecision(X,"allow",K)}async appendPermissionDenyRule(X,K={}){await this.appendPermissionRuleForDecision(X,"deny",K)}async appendPermissionRuleForDecision(X,K,Q){let q=Q.scope??"local",H=this.resolveFilePath("settings",q,Q.projectDir);await this.flushTargetWithModifier(H,(J)=>{let W=J.permissions??{allow:[],ask:[],deny:[]},Y={allow:K==="allow"?this.dedupeArray([...W.allow||[],X]):W.allow||[],ask:W.ask||[],deny:K==="deny"?this.dedupeArray([...W.deny||[],X]):W.deny||[]};return{...J,permissions:Y}})}async appendLocalPermissionRule(X,K={}){await this.appendPermissionRule(X,{...K,scope:"local"})}async appendLocalPermissionDenyRule(X,K={}){await this.appendPermissionDenyRule(X,{...K,scope:"local"})}validatePersistableFields(X){for(let K of Object.keys(X)){let Q=_[K];if(!Q)throw Error(`Unknown config field: ${K}`);if(!Q.persistable)throw Error(`Field "${K}" is non-persistable and cannot be saved to config files. Non-persistable fields are runtime-only and only valid for the current session.`)}}groupUpdatesByTarget(X,K,Q){let q=new Map;for(let[H,J]of Object.entries(X)){let W=_[H];if(!W)continue;let Y=K??W.defaultScope,Z=this.resolveFilePath(W.target,Y,Q);if(!q.has(Z))q.set(Z,{});q.get(Z)[H]=J}return q}resolveFilePath(X,K,Q){let q=Q??V();if(X==="config")return K==="global"?B.join(k.homedir(),".blade","config.json"):B.join(q,".blade","config.json");switch(K){case"local":return B.join(q,".blade","settings.local.json");case"project":return B.join(q,".blade","settings.json");case"global":return B.join(k.homedir(),".blade","settings.json");default:return B.join(q,".blade","settings.local.json")}}scheduleSave(X,K){let Q=this.pendingUpdates.get(X)??{},q=this.mergePendingUpdates(Q,K);this.pendingUpdates.set(X,q);let H=this.timers.get(X);if(H)clearTimeout(H);let J=setTimeout(async()=>{let W=this.pendingUpdates.get(X);if(W){this.pendingUpdates.delete(X),this.timers.delete(X);try{await this.flushTarget(X,W),this.lastSaveError=null}catch(Y){let Z=Y instanceof Error?Y:Error(String(Y));this.lastSaveError=Z,P.error(`Failed to save config to ${X}:`,Z.message),P.error("Stack trace:",Z.stack)}}},this.debounceDelay);this.timers.set(X,J)}mergePendingUpdates(X,K){let Q={...X};for(let[q,H]of Object.entries(K)){let J=_[q];if(!J){Q[q]=H;continue}switch(J.mergeStrategy){case"replace":Q[q]=H;break;case"append-dedupe":this.applyAppendDedupe(Q,q,H);break;case"deep-merge":this.applyDeepMerge(Q,q,H);break}}return Q}async flushTarget(X,K){let Q=this.fileLocks.get(X);if(!Q)Q=new C,this.fileLocks.set(X,Q);await Q.runExclusive(async()=>{await this.performWrite(X,K)})}async flushTargetWithModifier(X,K){let Q=this.fileLocks.get(X);if(!Q)Q=new C,this.fileLocks.set(X,Q);await Q.runExclusive(async()=>{await G.mkdir(B.dirname(X),{recursive:!0,mode:493});let q={};try{let J=await G.readFile(X,"utf-8");q=JSON.parse(J)}catch{q={}}let H=K(q);await this.atomicWrite(X,H)})}async performWrite(X,K){await G.mkdir(B.dirname(X),{recursive:!0,mode:493});let Q={};try{let H=await G.readFile(X,"utf-8");Q=JSON.parse(H)}catch{Q={}}let q={...Q};for(let[H,J]of Object.entries(K)){let W=_[H];if(!W){q[H]=J;continue}switch(W.mergeStrategy){case"replace":q[H]=J;break;case"append-dedupe":this.applyAppendDedupe(q,H,J);break;case"deep-merge":this.applyDeepMerge(q,H,J);break}}await this.atomicWrite(X,q)}applyAppendDedupe(X,K,Q){if(K==="permissions"&&typeof Q==="object"&&Q!==null){let q=X[K]??{allow:[],ask:[],deny:[]},H=Q;X[K]={allow:this.dedupeArray([...q.allow||[],...H.allow||[]]),ask:this.dedupeArray([...q.ask||[],...H.ask||[]]),deny:this.dedupeArray([...q.deny||[],...H.deny||[]])}}else if(Array.isArray(Q)){let q=Array.isArray(X[K])?X[K]:[];X[K]=this.dedupeArray([...q,...Q])}else X[K]=Q}applyDeepMerge(X,K,Q){if(typeof Q==="object"&&Q!==null&&!Array.isArray(Q)){let q=typeof X[K]==="object"&&X[K]!==null?X[K]:{};X[K]=v({},q,Q)}else X[K]=Q}dedupeArray(X){return Array.from(new Set(X))}async atomicWrite(X,K){await u(X,JSON.stringify(K,null,2),{mode:384,encoding:"utf-8"})}}function d(){return z.getInstance()}export{N as Ha,A as Ia,F as Ja,E as Ka,M as La,L as Ma,w as Na,U as Oa,m as Pa,d as Qa};
|