@weavecode/weave 0.1.1 → 0.1.2

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.
Files changed (166) hide show
  1. package/node_modules/@weavecode/cli/dist/cli.js +4 -4
  2. package/node_modules/@weavecode/cli/dist/commands/chpass.js +1 -1
  3. package/node_modules/@weavecode/cli/dist/commands/daemon-auth.js +1 -1
  4. package/node_modules/@weavecode/cli/dist/commands/daemon.d.ts +7 -0
  5. package/node_modules/@weavecode/cli/dist/commands/daemon.js +2 -2
  6. package/node_modules/@weavecode/cli/dist/commands/dashboard.js +2 -2
  7. package/node_modules/@weavecode/cli/dist/commands/doctor.js +1 -1
  8. package/node_modules/@weavecode/cli/dist/commands/init.js +1 -1
  9. package/node_modules/@weavecode/cli/dist/commands/scan.js +1 -1
  10. package/node_modules/@weavecode/cli/dist/commands/status.js +2 -2
  11. package/node_modules/@weavecode/cli/dist/commands/uninstall.js +1 -1
  12. package/node_modules/@weavecode/cli/dist/i18n/dict/en.js +1 -9
  13. package/node_modules/@weavecode/cli/dist/i18n/dict/zh.d.ts +0 -1
  14. package/node_modules/@weavecode/cli/dist/i18n/dict/zh.js +2 -10
  15. package/node_modules/@weavecode/cli/dist/i18n/index.js +1 -1
  16. package/node_modules/@weavecode/cli/dist/i18n/t.js +1 -1
  17. package/node_modules/@weavecode/cli/dist/init/claudemd-gen.d.ts +2 -3
  18. package/node_modules/@weavecode/cli/dist/init/claudemd-gen.js +4 -4
  19. package/node_modules/@weavecode/cli/dist/init/executor.js +3 -3
  20. package/node_modules/@weavecode/cli/dist/init/git-commit.js +2 -2
  21. package/node_modules/@weavecode/cli/dist/init/harnesses/claude.js +7 -7
  22. package/node_modules/@weavecode/cli/dist/init/harnesses/codex.js +1 -1
  23. package/node_modules/@weavecode/cli/dist/init/harnesses/zcode.d.ts +29 -0
  24. package/node_modules/@weavecode/cli/dist/init/harnesses/zcode.js +1 -0
  25. package/node_modules/@weavecode/cli/dist/init/instruction-link.js +1 -1
  26. package/node_modules/@weavecode/cli/dist/init/plugin-templates.js +1 -1
  27. package/node_modules/@weavecode/cli/dist/init/prompt.js +4 -4
  28. package/node_modules/@weavecode/cli/dist/init/uninstall.js +6 -6
  29. package/node_modules/@weavecode/cli/dist/init/wiring.js +1 -1
  30. package/node_modules/@weavecode/cli/dist/parser.js +1 -1
  31. package/node_modules/@weavecode/cli/dist/statusline/ansi.js +1 -1
  32. package/node_modules/@weavecode/cli/dist/statusline/mock-input.js +1 -1
  33. package/node_modules/@weavecode/cli/dist/statusline/preview.js +2 -2
  34. package/node_modules/@weavecode/cli/package.json +5 -5
  35. package/node_modules/@weavecode/core/dist/harness-checks.js +1 -1
  36. package/node_modules/@weavecode/core/dist/index.d.ts +1 -1
  37. package/node_modules/@weavecode/core/dist/index.js +1 -1
  38. package/node_modules/@weavecode/core/dist/platform.js +1 -1
  39. package/node_modules/@weavecode/core/dist/types.d.ts +0 -8
  40. package/node_modules/@weavecode/core/dist/types.js +1 -1
  41. package/node_modules/@weavecode/core/dist/utils/fs.js +1 -1
  42. package/node_modules/@weavecode/core/dist/utils/logger.js +1 -1
  43. package/node_modules/@weavecode/core/package.json +1 -1
  44. package/node_modules/@weavecode/harness/dist/claude/assets.d.ts +10 -0
  45. package/node_modules/@weavecode/harness/dist/claude/assets.js +4 -1
  46. package/node_modules/@weavecode/harness/dist/claude/capture.d.ts +4 -2
  47. package/node_modules/@weavecode/harness/dist/claude/capture.js +15 -9
  48. package/node_modules/@weavecode/harness/dist/claude/detect.js +1 -1
  49. package/node_modules/@weavecode/harness/dist/claude/event-source.js +1 -1
  50. package/node_modules/@weavecode/harness/dist/claude/index.d.ts +6 -1
  51. package/node_modules/@weavecode/harness/dist/claude/index.js +1 -1
  52. package/node_modules/@weavecode/harness/dist/claude/mcp-gen.js +1 -1
  53. package/node_modules/@weavecode/harness/dist/claude/messaging.js +2 -2
  54. package/node_modules/@weavecode/harness/dist/claude/model-aliases.d.ts +14 -0
  55. package/node_modules/@weavecode/harness/dist/claude/model-aliases.js +1 -1
  56. package/node_modules/@weavecode/harness/dist/claude/peers.js +1 -1
  57. package/node_modules/@weavecode/harness/dist/claude/plan.d.ts +2 -0
  58. package/node_modules/@weavecode/harness/dist/claude/plan.js +1 -0
  59. package/node_modules/@weavecode/harness/dist/claude/plugins.js +4 -4
  60. package/node_modules/@weavecode/harness/dist/claude/prompt-inbox.js +1 -1
  61. package/node_modules/@weavecode/harness/dist/claude/prompt.js +3 -3
  62. package/node_modules/@weavecode/harness/dist/claude/questions.js +2 -2
  63. package/node_modules/@weavecode/harness/dist/claude/settings-gen.js +1 -1
  64. package/node_modules/@weavecode/harness/dist/claude/side-question.d.ts +12 -0
  65. package/node_modules/@weavecode/harness/dist/claude/side-question.js +1 -0
  66. package/node_modules/@weavecode/harness/dist/claude/statusline/config.d.ts +200 -0
  67. package/node_modules/@weavecode/harness/dist/claude/statusline/config.js +1 -0
  68. package/node_modules/@weavecode/harness/dist/claude/statusline/generator.d.ts +12 -0
  69. package/node_modules/@weavecode/harness/dist/claude/statusline/generator.js +745 -0
  70. package/node_modules/@weavecode/harness/dist/claude/statusline/git-cache.d.ts +10 -0
  71. package/node_modules/@weavecode/harness/dist/claude/statusline/git-cache.js +1 -0
  72. package/node_modules/@weavecode/harness/dist/claude/statusline/surface.d.ts +20 -0
  73. package/node_modules/@weavecode/harness/dist/claude/statusline/surface.js +2 -0
  74. package/node_modules/@weavecode/harness/dist/claude/transcript.js +3 -3
  75. package/node_modules/@weavecode/harness/dist/codex/assets.js +1 -1
  76. package/node_modules/@weavecode/harness/dist/codex/detect.js +1 -1
  77. package/node_modules/@weavecode/harness/dist/codex/index.d.ts +1 -0
  78. package/node_modules/@weavecode/harness/dist/codex/index.js +1 -1
  79. package/node_modules/@weavecode/harness/dist/codex/mcp.d.ts +30 -0
  80. package/node_modules/@weavecode/harness/dist/codex/mcp.js +1 -0
  81. package/node_modules/@weavecode/harness/dist/codex/messaging.js +1 -1
  82. package/node_modules/@weavecode/harness/dist/codex/plugin-state.js +1 -1
  83. package/node_modules/@weavecode/harness/dist/codex/toml.js +9 -9
  84. package/node_modules/@weavecode/harness/dist/driver.d.ts +110 -2
  85. package/node_modules/@weavecode/harness/dist/driver.js +1 -1
  86. package/node_modules/@weavecode/harness/dist/init/generated.js +2 -2
  87. package/node_modules/@weavecode/harness/dist/init/pipeline.js +1 -1
  88. package/node_modules/@weavecode/harness/dist/registry-wiring.js +1 -1
  89. package/node_modules/@weavecode/harness/dist/shared/install-link.js +1 -1
  90. package/node_modules/@weavecode/harness/dist/zcode/assets.d.ts +8 -0
  91. package/node_modules/@weavecode/harness/dist/zcode/assets.js +1 -0
  92. package/node_modules/@weavecode/harness/dist/zcode/capture.d.ts +36 -0
  93. package/node_modules/@weavecode/harness/dist/zcode/capture.js +3 -0
  94. package/node_modules/@weavecode/harness/dist/zcode/detect.d.ts +2 -0
  95. package/node_modules/@weavecode/harness/dist/zcode/detect.js +1 -0
  96. package/node_modules/@weavecode/harness/dist/zcode/event-source.d.ts +8 -0
  97. package/node_modules/@weavecode/harness/dist/zcode/event-source.js +1 -0
  98. package/node_modules/@weavecode/harness/dist/zcode/index.d.ts +13 -0
  99. package/node_modules/@weavecode/harness/dist/zcode/index.js +1 -0
  100. package/node_modules/@weavecode/harness/dist/zcode/mcp.d.ts +6 -0
  101. package/node_modules/@weavecode/harness/dist/zcode/mcp.js +2 -0
  102. package/node_modules/@weavecode/harness/dist/zcode/messaging.d.ts +13 -0
  103. package/node_modules/@weavecode/harness/dist/zcode/messaging.js +1 -0
  104. package/node_modules/@weavecode/harness/dist/zcode/resume.d.ts +7 -0
  105. package/node_modules/@weavecode/harness/dist/zcode/resume.js +1 -0
  106. package/node_modules/@weavecode/harness/package.json +2 -2
  107. package/node_modules/@weavecode/server/dist/daemon/dev-entry.js +1 -1
  108. package/node_modules/@weavecode/server/dist/daemon/hook-pipeline.d.ts +8 -1
  109. package/node_modules/@weavecode/server/dist/daemon/hook-pipeline.js +1 -1
  110. package/node_modules/@weavecode/server/dist/daemon/hooks-routes.js +1 -1
  111. package/node_modules/@weavecode/server/dist/daemon/server.d.ts +7 -0
  112. package/node_modules/@weavecode/server/dist/daemon/server.js +8 -6
  113. package/node_modules/@weavecode/server/dist/daemon/session-probe.d.ts +13 -0
  114. package/node_modules/@weavecode/server/dist/daemon/session-probe.js +1 -1
  115. package/node_modules/@weavecode/server/dist/daemon/snapshot-refresher.d.ts +7 -1
  116. package/node_modules/@weavecode/server/dist/daemon/snapshot-refresher.js +1 -1
  117. package/node_modules/@weavecode/server/dist/daemon/sse-hub.d.ts +40 -0
  118. package/node_modules/@weavecode/server/dist/daemon/sse-hub.js +1 -0
  119. package/node_modules/@weavecode/server/dist/daemon/start.js +1 -1
  120. package/node_modules/@weavecode/server/dist/db/db.js +20 -2
  121. package/node_modules/@weavecode/server/dist/hooks/bus.d.ts +5 -0
  122. package/node_modules/@weavecode/server/dist/hooks/inbox-worker.d.ts +8 -1
  123. package/node_modules/@weavecode/server/dist/hooks/inbox-worker.js +3 -3
  124. package/node_modules/@weavecode/server/dist/hooks/message-deliverer.d.ts +29 -0
  125. package/node_modules/@weavecode/server/dist/hooks/message-deliverer.js +2 -2
  126. package/node_modules/@weavecode/server/dist/hooks/mirror.d.ts +9 -4
  127. package/node_modules/@weavecode/server/dist/hooks/mirror.js +4 -4
  128. package/node_modules/@weavecode/server/dist/hooks/session-purge.d.ts +3 -0
  129. package/node_modules/@weavecode/server/dist/hooks/session-purge.js +1 -1
  130. package/node_modules/@weavecode/server/dist/hooks/side-questions.d.ts +41 -0
  131. package/node_modules/@weavecode/server/dist/hooks/side-questions.js +1 -0
  132. package/node_modules/@weavecode/server/dist/hooks/toolkit.js +5 -5
  133. package/node_modules/@weavecode/server/dist/install/apply-update.js +1 -1
  134. package/node_modules/@weavecode/server/dist/install/capabilities.d.ts +10 -0
  135. package/node_modules/@weavecode/server/dist/install/capabilities.js +1 -1
  136. package/node_modules/@weavecode/server/dist/install/codex-toml.d.ts +8 -26
  137. package/node_modules/@weavecode/server/dist/install/codex-toml.js +1 -1
  138. package/node_modules/@weavecode/server/dist/install/global-config.d.ts +2 -4
  139. package/node_modules/@weavecode/server/dist/install/global-config.js +1 -2
  140. package/node_modules/@weavecode/server/dist/install/installer.d.ts +3 -5
  141. package/node_modules/@weavecode/server/dist/install/installer.js +1 -3
  142. package/node_modules/@weavecode/server/dist/install/mcp-rows.d.ts +5 -5
  143. package/node_modules/@weavecode/server/dist/install/mcp-rows.js +1 -1
  144. package/node_modules/@weavecode/server/dist/registry.js +2 -2
  145. package/node_modules/@weavecode/server/dist/repositories/hook-events.d.ts +7 -0
  146. package/node_modules/@weavecode/server/dist/repositories/hook-events.js +2 -2
  147. package/node_modules/@weavecode/server/dist/repositories/sessions.d.ts +15 -4
  148. package/node_modules/@weavecode/server/dist/repositories/sessions.js +2 -2
  149. package/node_modules/@weavecode/server/dist/repositories/side-questions.d.ts +50 -0
  150. package/node_modules/@weavecode/server/dist/repositories/side-questions.js +6 -0
  151. package/node_modules/@weavecode/server/dist/statusline/config.d.ts +4 -198
  152. package/node_modules/@weavecode/server/dist/statusline/config.js +1 -1
  153. package/node_modules/@weavecode/server/dist/statusline/generator.d.ts +5 -0
  154. package/node_modules/@weavecode/server/dist/statusline/generator.js +1 -717
  155. package/node_modules/@weavecode/server/dist/statusline/manager.d.ts +5 -5
  156. package/node_modules/@weavecode/server/dist/statusline/manager.js +3 -4
  157. package/node_modules/@weavecode/server/dist/surfaces.d.ts +11 -1
  158. package/node_modules/@weavecode/server/dist/surfaces.js +1 -1
  159. package/node_modules/@weavecode/server/package.json +4 -4
  160. package/node_modules/@weavecode/server/web/dist/assets/index-CHWbLAje.js +594 -0
  161. package/node_modules/@weavecode/server/web/dist/assets/index-D0s5v8QS.css +11 -0
  162. package/node_modules/@weavecode/server/web/dist/index.html +2 -2
  163. package/node_modules/@weavecode/templates/package.json +2 -2
  164. package/package.json +6 -6
  165. package/node_modules/@weavecode/server/web/dist/assets/index-D5WFh77i.css +0 -11
  166. package/node_modules/@weavecode/server/web/dist/assets/index-DJibaGnJ.js +0 -585
@@ -18,6 +18,20 @@ export declare function modelAliasTargets(aliases: readonly string[], env?: Node
18
18
  * assistant 消息上照会模型,切完不跑一轮就什么都读不到。
19
19
  */
20
20
  export declare function switchedModelOf(eventType: string, raw: unknown): string | null;
21
+ /**
22
+ * 会话开/恢复(`SessionStart`)上关于模型的话:startup / compact 带 `model` 就报得出
23
+ * 真名;`source=resume` **不带**(实测:重开时宿主把模型落回默认,且这一拍转录里还
24
+ * 只有上一轮的照会)——故 model 为 null 不是「不知道」,是「旧答案作废、得重新读」。
25
+ * 这条事件与模型无关时返回 null。
26
+ */
27
+ export declare function startedModelOf(eventType: string, raw: unknown): {
28
+ model: string | null;
29
+ } | null;
30
+ /**
31
+ * 推理档位(`effort.level`):工具/回合类 hook 事件都带,与生成脚本填 `thinking`
32
+ * 块读的 stdin `effort.level` 是同一个事实、同一个键形。
33
+ */
34
+ export declare function effortLevelOf(raw: unknown): string | null;
21
35
  /**
22
36
  * 真名 → 别名:转录里照会的是真名(`custom_openai/ftm`),下拉得认成别名那档。
23
37
  * 认不出返回 null,调用方回落显示真名——不猜。
@@ -1 +1 @@
1
- import f from"node:fs";import u from"node:os";import{CLAUDE_ASSETS as c}from"./assets.js";export function modelAliasTargets(n,t=process.env,r=u.homedir()){const e=l(r);return n.map(o=>{const s=`ANTHROPIC_DEFAULT_${o.toUpperCase()}_MODEL`,i=e[s]??e[`${s}_NAME`]??t[s]??t[`${s}_NAME`]??o;return{alias:o,actual:i}})}export function switchedModelOf(n,t){if(n!=="PostModelSwitch")return null;const r=t?.to_model;return typeof r=="string"&&r?r:null}export function aliasOfModel(n,t){if(!t)return null;const r=t.slice(t.lastIndexOf("/")+1);return n.find(e=>e.actual===t||e.actual===r)?.alias??null}function l(n){let t=null;try{t=JSON.parse(f.readFileSync(c.userConfigFile(n),"utf8"))}catch{return{}}const r={};for(const[e,o]of Object.entries(t?.env??{}))typeof o=="string"&&(r[e]=o);return r}
1
+ import f from"node:fs";import i from"node:os";import{CLAUDE_ASSETS as u}from"./assets.js";export function modelAliasTargets(r,t=process.env,e=i.homedir()){const n=c(e);return r.map(o=>{const l=`ANTHROPIC_DEFAULT_${o.toUpperCase()}_MODEL`,s=n[l]??n[`${l}_NAME`]??t[l]??t[`${l}_NAME`]??o;return{alias:o,actual:s}})}export function switchedModelOf(r,t){if(r!=="PostModelSwitch")return null;const e=t?.to_model;return typeof e=="string"&&e?e:null}export function startedModelOf(r,t){if(r!=="SessionStart")return null;const e=t?.model;return{model:typeof e=="string"&&e?e:null}}export function effortLevelOf(r){const t=r?.effort?.level;return typeof t=="string"&&t?t:null}export function aliasOfModel(r,t){if(!t)return null;const e=t.slice(t.lastIndexOf("/")+1);return r.find(n=>n.actual===t||n.actual===e)?.alias??null}function c(r){let t=null;try{t=JSON.parse(f.readFileSync(u.userConfigFile(r),"utf8"))}catch{return{}}const e={};for(const[n,o]of Object.entries(t?.env??{}))typeof o=="string"&&(e[n]=o);return e}
@@ -1 +1 @@
1
- import{readdirSync as a,readFileSync as c}from"node:fs";import{homedir as m}from"node:os";import{join as i}from"node:path";export function resolveClaudePeer(s,n=i(m(),".claude","sessions")){let r;try{r=a(n)}catch{return null}for(const t of r){if(!/^\d+\.json$/.test(t))continue;let o;try{o=JSON.parse(c(i(n,t),"utf8"))}catch{continue}const e=o;if(e?.sessionId===s&&typeof e.name=="string"&&e.name)return{name:e.name}}return null}
1
+ import{readdirSync as i,readFileSync as c}from"node:fs";import{homedir as m}from"node:os";import{join as s}from"node:path";export function resolveClaudePeer(a,r=s(m(),".claude","sessions")){let t;try{t=i(r)}catch{return null}for(const n of t){if(!/^\d+\.json$/.test(n))continue;let o;try{o=JSON.parse(c(s(r,n),"utf8"))}catch{continue}const e=o;if(e?.sessionId===a&&typeof e.name=="string"&&e.name)return{name:e.name}}return null}
@@ -0,0 +1,2 @@
1
+ import type { PlanSpec } from '../driver.js';
2
+ export declare const CLAUDE_PLAN: PlanSpec;
@@ -0,0 +1 @@
1
+ const f=/[\\/]plans[\\/][^\\/]+\.md$/i,l=t=>typeof t=="string"&&t.trim()?t:null,o=t=>t&&typeof t=="object"?t:{};export const CLAUDE_PLAN={tool:"ExitPlanMode",writeTools:["Write","Edit","MultiEdit"],fileHint:"plans",draftOf(t,a,r){const e=o(a),n=o(r);if(t==="ExitPlanMode")return{text:l(e.plan)??l(n.plan),filePath:l(e.planFilePath)??l(n.filePath)};if(t==null||!CLAUDE_PLAN.writeTools.includes(t))return null;const i=l(e.file_path)??l(n.filePath);return!i||!f.test(i)?null:{text:l(e.content),filePath:i}}};
@@ -1,4 +1,4 @@
1
- import{spawn as C}from"node:child_process";import{homedir as O}from"node:os";import{cp as R,lstat as H,mkdir as x,readFile as L,readdir as V,writeFile as F}from"node:fs/promises";import r from"node:path";import{linkOrCopy as q,removeInstalled as B}from"../shared/install-link.js";import{CLAUDE_ASSETS as W}from"./assets.js";export const WEAVE_MARKETPLACE="weave";const z="weave-marketplace",Q=6e4,U=2e3,J=64*1024;export function claudeCommandLine(o){return["claude",...o.map(d=>`"${d.replace(/"/g,'\\"')}"`)].join(" ")}function X(o){if(!(o.exitCode!==null||o.signalCode!==null)){if(process.platform==="win32"&&o.pid!==void 0){C("taskkill",["/pid",String(o.pid),"/t","/f"],{windowsHide:!0,stdio:"ignore"}).unref();return}o.kill("SIGKILL")}}function $(o){return o.length>U?`${o.slice(0,U)}\u2026`:o}function K(o){try{const d=JSON.parse(o);return d&&typeof d=="object"&&!Array.isArray(d)?d:null}catch{return null}}const Y=(o,d)=>new Promise((E,A)=>{const v=process.platform==="win32",g=C(v?process.env.ComSpec||"cmd.exe":"claude",v?["/d","/s","/c",claudeCommandLine(o)]:o,{windowsHide:!0,windowsVerbatimArguments:v,stdio:["ignore","pipe","pipe"]}),y=`claude ${o.join(" ")}`;let k="",p="",l=!1;const j=c=>{l||(l=!0,clearTimeout(b),A(new Error($(c))))},b=setTimeout(()=>{X(g),j(`${y}: timed out after ${d.timeoutMs}ms`)},d.timeoutMs);g.stdout?.setEncoding("utf8"),g.stdout?.on("data",c=>{k.length<J&&(k+=c)}),g.stderr?.setEncoding("utf8"),g.stderr?.on("data",c=>{p.length<J&&(p+=c)}),g.on("error",c=>j(`${y}: ${c.message}`)),g.on("close",c=>{if(l)return;if(l=!0,clearTimeout(b),c===0){E({stdout:k,stderr:p});return}const h=[p,k].filter(Boolean).join(`
2
- `).trim()||`exit ${c}`;A(new Error($(`${y}: ${h}`)))})});export function createClaudePluginSurface(o={}){const d=o.exec??Y,E=e=>d(e,{timeoutMs:Q}),A=()=>W.userConfigFile(O()),v=()=>r.join(O(),".claude","plugins","installed_plugins.json"),g=()=>r.join(O(),".claude",z),y=e=>r.join(e,".claude","settings.json"),k=e=>r.join(e,".claude","settings.local.json"),p=(e,n)=>`${e}@${n??WEAVE_MARKETPLACE}`,l=async e=>{try{const n=JSON.parse(await L(e,"utf8"));return n&&typeof n=="object"&&!Array.isArray(n)?n:{}}catch{return{}}},j=async(e,n)=>{await x(r.dirname(e),{recursive:!0}),await F(e,`${JSON.stringify(n,null,2)}
3
- `,"utf8")},b=e=>{const n=e.enabledPlugins;return!n||typeof n!="object"||Array.isArray(n)?{}:Object.fromEntries(Object.entries(n).filter(([,t])=>typeof t=="boolean"))},c=e=>{const n=e.enabledPlugins;return n&&typeof n=="object"&&!Array.isArray(n)?{...n}:{}},h=async()=>{const n=(await l(v())).plugins;if(!n||typeof n!="object"||Array.isArray(n))return{};const t={};for(const[i,s]of Object.entries(n))Array.isArray(s)&&(t[i]=s);return t},I=(e,n,t)=>{const i=n?.[n.length-1];return{key:e,alreadyInstalled:t,...i?.scope?{scope:i.scope}:{},...i?.installPath?{installPath:i.installPath}:{},...i?.version?{version:i.version}:{}}},N=async(e,n,t={})=>{const i=g(),s=r.join(i,"plugins",n);await B(s),await x(r.dirname(s),{recursive:!0});const a=await L(r.join(e,".claude-plugin","plugin.json"),"utf8").then(()=>!0,()=>!1),u=await V(e).catch(()=>[]);if(a&&!u.includes("node_modules")&&!u.includes(".git"))await q(e,s);else if(await R(e,s,{recursive:!0,filter:S=>{const _=r.basename(S);return _!=="node_modules"&&_!==".git"}}),!a){const S=r.join(s,".claude-plugin","plugin.json");await x(r.dirname(S),{recursive:!0}),await F(S,JSON.stringify({name:n,version:t.version??"0.0.0",...t.description?{description:t.description}:{}},null,2)+`
4
- `,"utf8")}const f=r.join(i,".claude-plugin","marketplace.json"),w=await l(f),P=Array.isArray(w.plugins)?[...w.plugins]:[],M={name:n,source:`./plugins/${n}`},T=P.findIndex(S=>S?.name===n);return T>=0?P[T]=M:P.push(M),w.name=WEAVE_MARKETPLACE,w.owner||(w.owner={name:"weave"}),w.plugins=P,await j(f,w),i},G=async(e,n,t)=>{if(!e.dir)throw new Error(`marketplace dir required for ${n}@${e.name}`);if((await H(e.dir)).isSymbolicLink())return;const i=r.join(e.dir,".claude-plugin","marketplace.json"),s=await l(i),a=Array.isArray(s.plugins)?[...s.plugins]:[],u=`./${r.relative(e.dir,t).split(r.sep).join("/")}`,m={name:n,source:u},f=a.findIndex(w=>w?.name===n);f>=0?a[f]=m:a.push(m),s.name=e.name,s.owner||(s.owner={name:"weave"}),s.plugins=a,await j(i,s)};return{projectPluginDir:e=>r.join(e,".claude","plugins"),pluginKey:p,parsePluginKey(e){const n=e.lastIndexOf("@");return n>0?{name:e.slice(0,n),market:e.slice(n+1)}:{name:e,market:WEAVE_MARKETPLACE}},async globalInstall(e,n={}){let t=n.name;if(!t){const f=await l(r.join(e,".claude-plugin","plugin.json"));t=typeof f.name=="string"?f.name:void 0}if(!t)throw new Error(`plugin manifest missing name: ${e}`);const i=n.marketplace,s=p(t,i?.name),a=(await h())[s];if(a&&a.length>0)return I(s,a,!0);if(i)await G(i,t,e),await E(["plugin","marketplace","add",i.dir??""]);else{const f=await N(e,t,n);await E(["plugin","marketplace","add",f])}const{stdout:u}=await E(["plugin","install",s,"--scope","user","--json"]),m=K(u);if(m?.outcome==="failed")throw new Error($(String(m.message??"plugin install failed")));return I(s,(await h())[s],!1)},readInstalled:h,async isInstalled(e,n){const t=(await h())[p(e,n)];return!!t&&t.length>0},async uninstall(e,n){const t=p(e,n),i=(await h())[t];if(!i||i.length===0)return;const s=[...new Set(i.map(a=>a.scope??"user"))];for(const a of s){const{stdout:u}=await E(["plugin","uninstall",t,"--scope",a,"--json"]),m=K(u);if(m?.outcome==="failed")throw new Error($(String(m.message??"plugin uninstall failed")))}},async removeMarketplace(e){const n=await l(r.join(O(),".claude","plugins","known_marketplaces.json")),t=r.resolve(e),i=Object.entries(n).find(([,s])=>s&&typeof s=="object"&&typeof s.installLocation=="string"&&r.resolve(s.installLocation)===t)?.[0];i&&await E(["plugin","marketplace","remove",i])},async readProjectEnabled(e,n,t){return b(await l(y(e)))[p(n,t)]??!1},async setProjectEnabled(e,n,t,i){const s=y(e),a=await l(s);a.enabledPlugins={...c(a),[p(n,i)]:t},await j(s,a)},async readGlobalEnabled(){return b(await l(A()))},async writeGlobalEnabled(e,n){const t=A(),i=await l(t);i.enabledPlugins={...c(i),[e]:n},await j(t,i)},pluginScopes:()=>["user","project","local"],async readEnabledOverrides(e){const[n,t,i]=await Promise.all([l(A()).then(b),l(y(e)).then(b),l(k(e)).then(b)]);return{user:n,project:t,local:i}},async setEnabledOverride(e,n,t,i){const s=n==="user"?A():n==="project"?y(e):k(e),a=await l(s),u=c(a);i==="inherit"?delete u[t]:u[t]=i==="on",a.enabledPlugins=u,await j(s,a)}}}export const CLAUDE_PLUGINS=createClaudePluginSurface();
1
+ import{spawn as _}from"node:child_process";import{homedir as P}from"node:os";import{cp as U,lstat as D,mkdir as O,readFile as M,readdir as H,writeFile as N}from"node:fs/promises";import s from"node:path";import{linkOrCopy as V,removeInstalled as q}from"../shared/install-link.js";import{CLAUDE_ASSETS as B}from"./assets.js";export const WEAVE_MARKETPLACE="weave";const R="weave-marketplace",W=6e4,T=2e3,G=64*1024;export function claudeCommandLine(o){return["claude",...o.map(p=>`"${p.replace(/"/g,'\\"')}"`)].join(" ")}function z(o){if(!(o.exitCode!==null||o.signalCode!==null)){if(process.platform==="win32"&&o.pid!==void 0){_("taskkill",["/pid",String(o.pid),"/t","/f"],{windowsHide:!0,stdio:"ignore"}).unref();return}o.kill("SIGKILL")}}function S(o){return o.length>T?`${o.slice(0,T)}\u2026`:o}function J(o){try{const p=JSON.parse(o);return p&&typeof p=="object"&&!Array.isArray(p)?p:null}catch{return null}}const Q=(o,p)=>new Promise((b,h)=>{const $=process.platform==="win32",g=_($?process.env.ComSpec||"cmd.exe":"claude",$?["/d","/s","/c",claudeCommandLine(o)]:o,{windowsHide:!0,windowsVerbatimArguments:$,stdio:["ignore","pipe","pipe"]}),w=`claude ${o.join(" ")}`;let v="",m="",l=!1;const y=u=>{l||(l=!0,clearTimeout(j),h(new Error(S(u))))},j=setTimeout(()=>{z(g),y(`${w}: timed out after ${p.timeoutMs}ms`)},p.timeoutMs);g.stdout?.setEncoding("utf8"),g.stdout?.on("data",u=>{v.length<G&&(v+=u)}),g.stderr?.setEncoding("utf8"),g.stderr?.on("data",u=>{m.length<G&&(m+=u)}),g.on("error",u=>y(`${w}: ${u.message}`)),g.on("close",u=>{if(l)return;if(l=!0,clearTimeout(j),u===0){b({stdout:v,stderr:m});return}const A=[m,v].filter(Boolean).join(`
2
+ `).trim()||`exit ${u}`;h(new Error(S(`${w}: ${A}`)))})});export function createClaudePluginSurface(o={}){const p=o.exec??Q,b=e=>p(e,{timeoutMs:W}),h=()=>B.userConfigFile(P()),$=()=>s.join(P(),".claude","plugins","installed_plugins.json"),g=()=>s.join(P(),".claude",R),w=e=>s.join(e,".claude","settings.json"),v=e=>s.join(e,".claude","settings.local.json"),m=(e,n)=>`${e}@${n??WEAVE_MARKETPLACE}`,l=async e=>{try{const n=JSON.parse(await M(e,"utf8"));return n&&typeof n=="object"&&!Array.isArray(n)?n:{}}catch{return{}}},y=async(e,n)=>{await O(s.dirname(e),{recursive:!0}),await N(e,`${JSON.stringify(n,null,2)}
3
+ `,"utf8")},j=e=>{const n=e.enabledPlugins;return!n||typeof n!="object"||Array.isArray(n)?{}:Object.fromEntries(Object.entries(n).filter(([,a])=>typeof a=="boolean"))},u=e=>{const n=e.enabledPlugins;return n&&typeof n=="object"&&!Array.isArray(n)?{...n}:{}},A=async()=>{const e=(await l($())).plugins;if(!e||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[a,t]of Object.entries(e))Array.isArray(t)&&(n[a]=t);return n},x=(e,n,a)=>{const t=n?.[n.length-1];return{key:e,alreadyInstalled:a,...t?.scope?{scope:t.scope}:{},...t?.installPath?{installPath:t.installPath}:{},...t?.version?{version:t.version}:{}}},K=async(e,n,a={})=>{const t=g(),i=s.join(t,"plugins",n);await q(i),await O(s.dirname(i),{recursive:!0});const r=await M(s.join(e,".claude-plugin","plugin.json"),"utf8").then(()=>!0,()=>!1),d=await H(e).catch(()=>[]);if(r&&!d.includes("node_modules")&&!d.includes(".git"))await V(e,i);else if(await U(e,i,{recursive:!0,filter:k=>{const L=s.basename(k);return L!=="node_modules"&&L!==".git"}}),!r){const k=s.join(i,".claude-plugin","plugin.json");await O(s.dirname(k),{recursive:!0}),await N(k,JSON.stringify({name:n,version:a.version??"0.0.0",...a.description?{description:a.description}:{}},null,2)+`
4
+ `,"utf8")}const f=s.join(t,".claude-plugin","marketplace.json"),c=await l(f),E=Array.isArray(c.plugins)?[...c.plugins]:[],I={name:n,source:`./plugins/${n}`},C=E.findIndex(k=>k?.name===n);return C>=0?E[C]=I:E.push(I),c.name=WEAVE_MARKETPLACE,c.owner||(c.owner={name:"weave"}),c.plugins=E,await y(f,c),t},F=async(e,n,a)=>{if(!e.dir)throw new Error(`marketplace dir required for ${n}@${e.name}`);if((await D(e.dir)).isSymbolicLink())return;const t=s.join(e.dir,".claude-plugin","marketplace.json"),i=await l(t),r=Array.isArray(i.plugins)?[...i.plugins]:[],d=`./${s.relative(e.dir,a).split(s.sep).join("/")}`,f={name:n,source:d},c=r.findIndex(E=>E?.name===n);c>=0?r[c]=f:r.push(f),i.name=e.name,i.owner||(i.owner={name:"weave"}),i.plugins=r,await y(t,i)};return{projectPluginDir:e=>s.join(e,".claude","plugins"),pluginKey:m,parsePluginKey(e){const n=e.lastIndexOf("@");return n>0?{name:e.slice(0,n),market:e.slice(n+1)}:{name:e,market:WEAVE_MARKETPLACE}},async globalInstall(e,n={}){let a=n.name;if(!a){const c=await l(s.join(e,".claude-plugin","plugin.json"));a=typeof c.name=="string"?c.name:void 0}if(!a)throw new Error(`plugin manifest missing name: ${e}`);const t=n.marketplace,i=m(a,t?.name),r=(await A())[i];if(r&&r.length>0)return x(i,r,!0);if(t)await F(t,a,e),await b(["plugin","marketplace","add",t.dir??""]);else{const c=await K(e,a,n);await b(["plugin","marketplace","add",c])}const{stdout:d}=await b(["plugin","install",i,"--scope","user","--json"]),f=J(d);if(f?.outcome==="failed")throw new Error(S(String(f.message??"plugin install failed")));return x(i,(await A())[i],!1)},readInstalled:A,async isInstalled(e,n){const a=(await A())[m(e,n)];return!!a&&a.length>0},async uninstall(e,n){const a=m(e,n),t=(await A())[a];if(!t||t.length===0)return;const i=[...new Set(t.map(r=>r.scope??"user"))];for(const r of i){const{stdout:d}=await b(["plugin","uninstall",a,"--scope",r,"--json"]),f=J(d);if(f?.outcome==="failed")throw new Error(S(String(f.message??"plugin uninstall failed")))}},async removeMarketplace(e){const n=await l(s.join(P(),".claude","plugins","known_marketplaces.json")),a=s.resolve(e),t=Object.entries(n).find(([,i])=>i&&typeof i=="object"&&typeof i.installLocation=="string"&&s.resolve(i.installLocation)===a)?.[0];t&&await b(["plugin","marketplace","remove",t])},async readProjectEnabled(e,n,a){return j(await l(w(e)))[m(n,a)]??!1},async setProjectEnabled(e,n,a,t){const i=w(e),r=await l(i);r.enabledPlugins={...u(r),[m(n,t)]:a},await y(i,r)},async readGlobalEnabled(){return j(await l(h()))},async writeGlobalEnabled(e,n){const a=h(),t=await l(a);t.enabledPlugins={...u(t),[e]:n},await y(a,t)},pluginScopes:()=>["user","project","local"],async readEnabledOverrides(e){const[n,a,t]=await Promise.all([l(h()).then(j),l(w(e)).then(j),l(v(e)).then(j)]);return{user:n,project:a,local:t}},async setEnabledOverride(e,n,a,t){const i=n==="user"?h():n==="project"?w(e):v(e),r=await l(i),d=u(r);t==="inherit"?delete d[a]:d[a]=t==="on",r.enabledPlugins=d,await y(i,r)}}}export const CLAUDE_PLUGINS=createClaudePluginSurface();
@@ -1,3 +1,3 @@
1
- export const CLAUDE_PROMPT_INBOX={socketEnv:"CLAUDE_CODE_MESSAGING_SOCKET",tokenEnv:"CLAUDE_CODE_MESSAGING_TOKEN",requiresAuthOn:e=>e==="win32",frame:({token:e,text:s})=>{const n=[];return e&&n.push(JSON.stringify({type:"auth",token:e})),n.push(JSON.stringify({type:"user",message:{role:"user",content:s}})),n.join(`
1
+ export const CLAUDE_PROMPT_INBOX={socketEnv:"CLAUDE_CODE_MESSAGING_SOCKET",tokenEnv:"CLAUDE_CODE_MESSAGING_TOKEN",requiresAuthOn:t=>t==="win32",frame:({token:t,text:n})=>{const e=[];return t&&e.push(JSON.stringify({type:"auth",token:t})),e.push(JSON.stringify({type:"user",message:{role:"user",content:n}})),e.join(`
2
2
  `)+`
3
3
  `}};
@@ -1,5 +1,5 @@
1
- import{resolveClaudePeer as n}from"./peers.js";const t="[weave one-way injection \u2014 no reply is expected: do not call SendMessage or ListAgents, just act on this prompt in this session.]";export const CLAUDE_PROMPT_RELAY={bin:"claude",args:["-p","--no-session-persistence","--strict-mcp-config","--disable-slash-commands","--tools","SendMessage,ListAgents","-n","weave"],senderName:"weave",instruction:(e,s,o)=>`Send the following message verbatim to the Claude session named "${e}" using the SendMessage tool, then stop immediately. Do not use any other tool and do not wait for a reply \u2014 the handover is done once the tool call returns, so this process must exit promptly.
1
+ import{resolveClaudePeer as t}from"./peers.js";const n="[weave one-way injection \u2014 no reply is expected: do not call SendMessage or ListAgents, just act on this prompt in this session.]";export const CLAUDE_PROMPT_RELAY={bin:"claude",args:["-p","--no-session-persistence","--strict-mcp-config","--disable-slash-commands","--tools","SendMessage,ListAgents","-n","weave"],senderName:"weave",instruction:(e,s,o)=>`Send the following message verbatim to the Claude session named "${e}" using the SendMessage tool, then stop immediately. Do not use any other tool and do not wait for a reply \u2014 the handover is done once the tool call returns, so this process must exit promptly.
2
2
 
3
- ${o.oneWay?`${t}
3
+ ${o.oneWay?`${n}
4
4
 
5
- `:""}${s}`,resolve:n};
5
+ `:""}${s}`,resolve:t};
@@ -1,2 +1,2 @@
1
- import{HARNESS_LIFECYCLE as b}from"@weavecode/core";const f="\x1B[B",a=" ",S=2e3,m="(preview cannot be shown in full \u2014 compare the option labels and descriptions instead)",k="No preview available",g="n",w="press n to add notes",N=/[\p{M}\u200b-\u200f\u2028-\u202e\u2060-\u206f\u180b-\u180f\ufe0e\ufe0f]/u,T={key:"ExitPlanMode:approve",header:"Plan approval",question:"Approve this plan and start execution?",multiSelect:!1,options:[{keys:["1"],label:"Yes, auto-accept edits"},{keys:["2"],label:"Yes, manually approve edits"},{keys:["3"],label:"No, keep planning"}]},E=[{keys:["1"],label:"Yes"},{keys:["2"],label:"Yes, and don't ask again for this tool"},{keys:["3"],label:"No, and tell Claude what to do differently (esc)"}],v=[{keys:["1"],label:"Yes, and tell Claude what to do next"},{keys:["2"],label:"No"}],h={key:"AskUserQuestion:opaque",header:null,question:"The session is asking a question (options unavailable \u2014 answer in its terminal)",multiSelect:!1,options:[]};function A(e){if(!e||typeof e!="object")return null;const t=e,s=r(t.to_model),n=r(t.from_model);return!s||!n||s===n||t.prompt_cache_warm!==!0?null:{key:"model:switch",header:"Switch model?",question:`Your next response will be slower and use more tokens. This conversation is cached for the current model. Switching to ${s} means the full history gets re-read on your next message.`,multiSelect:!1,options:[{keys:["1"],label:`Yes, switch to ${s}`},{keys:["2"],label:"No, go back"}]}}function _(e){if(e==null||typeof e!="object")return"";try{const t=JSON.stringify(e);return!t||t==="{}"?"":t.length>160?`${t.slice(0,160)}\u2026`:t}catch{return""}}function O(e,t){return[t?{keys:[String(e+1)],label:"Type something",input:!0,textFocus:Array.from({length:e},()=>f),textTail:[a,"\r"]}:{keys:[String(e+1)],label:"Type something",input:!0,textTail:["\r"]},{keys:[String(e+2)],label:"Chat about this",chat:!0}]}function P(){return{key:"AskUserQuestion:submit",header:"Submit",question:"Review your answers",multiSelect:!1,submit:!0,options:[{keys:[a,"1"],label:"Submit answers"},{keys:[a,"2"],label:"Cancel"}]}}function r(e){return typeof e=="string"&&e?e:null}function I(e){if(!Array.isArray(e))return[];const t=[];for(const s of e){if(!s||typeof s!="object")continue;const n=r(s.label);if(!n)continue;const o=s.description;t.push({keys:[String(t.length+1)],label:n,description:typeof o=="string"&&o?o:null,preview:q(s.preview)})}return t}function q(e){return typeof e!="string"?null:e.length>S?m:e.replace(/�/g,"").trim()?N.test(e)?m:e:null}function R(e,t){return t<2?[String(e+1)]:[String(e===0?2:1),String(e+1)]}function C(e){return e.map((t,s)=>({keys:R(s,e.length),commit:["\r"],label:t.label,description:t.description,preview:t.preview??k}))}function M(e){const t=[];return e>=2&&t.push({keys:[g],label:"Notes:",description:w,input:!0,textTail:["\r"]}),t.push({keys:[String(e),f,"\r"],label:"Chat about this",chat:!0}),t}export const CLAUDE_BLOCKING_PROMPT={blockingTools:b.claude.questionTools,permissionNotificationType:"permission_prompt",silentPermissionModes:["bypassPermissions","dontAsk"],permissionQuestion(e){const t=e.toolName?`${e.toolName}${e.toolInput?` ${_(e.toolInput)}`:""}`:"",s=e.permissionMode==="auto"||/classifier/i.test(e.message??""),n=e.message?.trim()||"Claude needs your permission";return{key:"permission:confirm",header:s?"Permission (auto mode)":"Permission",question:t?`${n}
2
- ${t}`:n,multiSelect:!1,options:[...s?v:E]}},parseQuestions(e,t){if(e==="AskUserQuestion"){const s=t&&typeof t=="object"?t.questions:void 0;if(!Array.isArray(s))return[h];const n=[];for(const o of s){if(!o||typeof o!="object")continue;const l=r(o.question),c=r(o.header),u=o.multiSelect===!0,i=I(o.options);if(!l||i.length===0)continue;const d=c??l.slice(0,24),p=!u&&i.some(y=>y.preview!=null);n.push({key:`AskUserQuestion:${d}`,header:c,question:l,options:p?[...C(i),...M(i.length)]:[...i,...O(i.length,u)],multiSelect:u,previewMode:p})}return n.length===0?[h]:((n.length>=2||n.some(o=>o.multiSelect))&&n.push(P()),n)}return[T]},eventQuestion(e,t){return e==="PreModelSwitch"?A(t):null}};
1
+ import{HARNESS_LIFECYCLE as b}from"@weavecode/core";import{CLAUDE_PLAN as k}from"./plan.js";const m="\x1B[B",a=" ",g=2e3,f="(preview cannot be shown in full \u2014 compare the option labels and descriptions instead)",S="No preview available",w="n",v="press n to add notes",A=/[\p{M}\u200b-\u200f\u2028-\u202e\u2060-\u206f\u180b-\u180f\ufe0e\ufe0f]/u,N={key:"ExitPlanMode:approve",header:"Plan approval",question:"Approve this plan and start execution?",multiSelect:!1,options:[{keys:["1"],label:"Yes, auto-accept edits"},{keys:["2"],label:"Yes, manually approve edits"},{keys:["3"],label:"No, keep planning"}]},q=[{keys:["1"],label:"Yes"},{keys:["2"],label:"Yes, and don't ask again for this tool"},{keys:["3"],label:"No, and tell Claude what to do differently (esc)"}],C=[{keys:["1"],label:"Yes, and tell Claude what to do next"},{keys:["2"],label:"No"}],h={key:"AskUserQuestion:opaque",header:null,question:"The session is asking a question (options unavailable \u2014 answer in its terminal)",multiSelect:!1,options:[]};function T(e){if(!e||typeof e!="object")return null;const t=e,n=r(t.to_model),o=r(t.from_model);return!n||!o||n===o||t.prompt_cache_warm!==!0?null:{key:"model:switch",header:"Switch model?",question:`Your next response will be slower and use more tokens. This conversation is cached for the current model. Switching to ${n} means the full history gets re-read on your next message.`,multiSelect:!1,options:[{keys:["1"],label:`Yes, switch to ${n}`},{keys:["2"],label:"No, go back"}]}}function x(e){if(e==null||typeof e!="object")return"";try{const t=JSON.stringify(e);return!t||t==="{}"?"":t.length>160?`${t.slice(0,160)}\u2026`:t}catch{return""}}function P(e,t){return[t?{keys:[String(e+1)],label:"Type something",input:!0,textFocus:Array.from({length:e},()=>m),textTail:[a,"\r"]}:{keys:[String(e+1)],label:"Type something",input:!0,textTail:["\r"]},{keys:[String(e+2)],label:"Chat about this",chat:!0}]}function _(){return{key:"AskUserQuestion:submit",header:"Submit",question:"Review your answers",multiSelect:!1,submit:!0,options:[{keys:[a,"1"],label:"Submit answers"},{keys:[a,"2"],label:"Cancel"}]}}function r(e){return typeof e=="string"&&e?e:null}function $(e){if(!Array.isArray(e))return[];const t=[];for(const n of e){if(!n||typeof n!="object")continue;const o=r(n.label);if(!o)continue;const s=n.description;t.push({keys:[String(t.length+1)],label:o,description:typeof s=="string"&&s?s:null,preview:M(n.preview)})}return t}function M(e){return typeof e!="string"?null:e.length>g?f:e.replace(/�/g,"").trim()?A.test(e)?f:e:null}function Q(e,t){return t<2?[String(e+1)]:[String(e===0?2:1),String(e+1)]}function Y(e){return e.map((t,n)=>({keys:Q(n,e.length),commit:["\r"],label:t.label,description:t.description,preview:t.preview??S}))}function E(e){const t=[];return e>=2&&t.push({keys:[w],label:"Notes:",description:v,input:!0,textTail:["\r"]}),t.push({keys:[String(e),m,"\r"],label:"Chat about this",chat:!0}),t}export const CLAUDE_BLOCKING_PROMPT={plan:k,blockingTools:b.claude.questionTools,permissionNotificationType:"permission_prompt",silentPermissionModes:["bypassPermissions","dontAsk"],permissionQuestion(e){const t=e.toolName?`${e.toolName}${e.toolInput?` ${x(e.toolInput)}`:""}`:"",n=e.permissionMode==="auto"||/classifier/i.test(e.message??""),o=e.message?.trim()||"Claude needs your permission";return{key:"permission:confirm",header:n?"Permission (auto mode)":"Permission",question:t?`${o}
2
+ ${t}`:o,multiSelect:!1,options:[...n?C:q]}},parseQuestions(e,t){if(e==="AskUserQuestion"){const n=t&&typeof t=="object"?t.questions:void 0;if(!Array.isArray(n))return[h];const o=[];for(const s of n){if(!s||typeof s!="object")continue;const l=r(s.question),c=r(s.header),u=s.multiSelect===!0,i=$(s.options);if(!l||i.length===0)continue;const y=c??l.slice(0,24),p=!u&&i.some(d=>d.preview!=null);o.push({key:`AskUserQuestion:${y}`,header:c,question:l,options:p?[...Y(i),...E(i.length)]:[...i,...P(i.length,u)],multiSelect:u,previewMode:p})}return o.length===0?[h]:((o.length>=2||o.some(s=>s.multiSelect))&&o.push(_()),o)}return[N]},eventQuestion(e,t){return e==="PreModelSwitch"?T(t):null}};
@@ -1 +1 @@
1
- import{captureHookGroup as r,sweepWeaveHookEvents as m}from"./capture.js";const v=".claude/helpers/statusline.cjs",d="Generated by weave \u2014 do not edit manually",S=["Bash(npx weave:*)","Bash(pnpm:*)","Bash(npm:*)"],h=["Read(./.env)","Read(./.env.*)","Read(./secrets/*)"];export function generateSettingsJson(n){const{components:s,hooks:e,platform:p,helpersDir:o}=n,c={$comment:d};if(s.helpers){const t={};e.preToolUse&&(t.PreToolUse=r("PreToolUse",o)),e.postToolUse&&(t.PostToolUse=r("PostToolUse",o)),e.userPromptSubmit&&(t.UserPromptSubmit=r("UserPromptSubmit",o)),e.sessionStart&&(t.SessionStart=r("SessionStart",o)),e.stop&&(t.Stop=r("Stop",o)),e.stopFailure&&(t.StopFailure=r("StopFailure",o)),e.subagentStop&&(t.SubagentStop=r("SubagentStop",o)),e.subagentStart&&(t.SubagentStart=r("SubagentStart",o)),e.notification&&(t.Notification=r("Notification",o)),e.postToolUseFailure&&(t.PostToolUseFailure=r("PostToolUseFailure",o)),e.permissionRequest&&(t.PermissionRequest=r("PermissionRequest",o)),e.permissionDenied&&(t.PermissionDenied=r("PermissionDenied",o)),e.preCompact&&(t.PreCompact=r("PreCompact",o)),e.sessionEnd&&(t.SessionEnd=r("SessionEnd",o)),e.preModelSwitch&&(t.PreModelSwitch=r("PreModelSwitch",o),t.PostModelSwitch=r("PostModelSwitch",o)),c.hooks=t}return c.permissions={allow:[...S],deny:[...h]},c.env={WEAVE_ENABLED:"true"},s.helpers&&(c.statusLine={type:"command",command:p.os==="windows"?`node "${o}/statusline.cjs"`:"node "+o+"/statusline.cjs",padding:0,refreshInterval:30}),c}export function mergeSettingsJson(n,s){const e={...n},p=s.hooks;if(p&&typeof p=="object"){const i=m(l(e.hooks)?{...e.hooks}:{})??{};for(const[a,f]of Object.entries(p)){const u=i[a];u===void 0?i[a]=f:Array.isArray(u)&&(i[a]=[...u,...Array.isArray(f)?f:[]])}e.hooks=i}const o=e.statusLine;s.statusLine&&(o===void 0||E(o))&&(e.statusLine=s.statusLine);const c=s.permissions;if(c&&typeof c=="object"){const i=l(e.permissions)?e.permissions:{};for(const a of["allow","deny"]){const f=c[a],u=i[a];Array.isArray(f)?i[a]=A(u,f):u===void 0&&(i[a]=f)}e.permissions=i}const t=s.env;if(t&&typeof t=="object"){const i=l(e.env)?e.env:{};for(const[a,f]of Object.entries(t))i[a]===void 0&&(i[a]=f);e.env=i}return e}function l(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function E(n){if(!l(n))return!1;const s=n.command;return typeof s=="string"&&y(s,v)}function y(n,s){return n.replace(/\\/g,"/").includes(s)}function A(n,s){return Array.isArray(n)?[...n,...s.filter(e=>!n.includes(e))]:[...s]}export function stripWeaveSettings(n){const s={...n};if(l(s.hooks)){const e=m(s.hooks);e?s.hooks=e:delete s.hooks}if(E(s.statusLine)&&delete s.statusLine,l(s.permissions)){const e={...s.permissions},p=(o,c)=>{const t=e[o];if(!Array.isArray(t))return;const i=t.filter(a=>!c.includes(a));i.length>0?e[o]=i:delete e[o]};p("allow",S),p("deny",h),Object.keys(e).length>0?s.permissions=e:delete s.permissions}if(l(s.env)){const e={...s.env};delete e.WEAVE_ENABLED,Object.keys(e).length>0?s.env=e:delete s.env}return s.$comment===d&&delete s.$comment,s}
1
+ import{captureHookGroup as r,sweepWeaveHookEvents as d}from"./capture.js";const v=".claude/helpers/statusline.cjs",f="Generated by weave \u2014 do not edit manually",S=["Bash(npx weave:*)","Bash(pnpm:*)","Bash(npm:*)"],h=["Read(./.env)","Read(./.env.*)","Read(./secrets/*)"];export function generateSettingsJson(n){const{components:t,hooks:e,platform:l,helpersDir:o}=n,c={$comment:f};if(t.helpers){const s={};e.preToolUse&&(s.PreToolUse=r("PreToolUse",o)),e.postToolUse&&(s.PostToolUse=r("PostToolUse",o)),e.userPromptSubmit&&(s.UserPromptSubmit=r("UserPromptSubmit",o)),e.sessionStart&&(s.SessionStart=r("SessionStart",o)),e.stop&&(s.Stop=r("Stop",o)),e.stopFailure&&(s.StopFailure=r("StopFailure",o)),e.subagentStop&&(s.SubagentStop=r("SubagentStop",o)),e.subagentStart&&(s.SubagentStart=r("SubagentStart",o)),e.notification&&(s.Notification=r("Notification",o)),e.postToolUseFailure&&(s.PostToolUseFailure=r("PostToolUseFailure",o)),e.permissionRequest&&(s.PermissionRequest=r("PermissionRequest",o)),e.permissionDenied&&(s.PermissionDenied=r("PermissionDenied",o)),e.preCompact&&(s.PreCompact=r("PreCompact",o)),e.sessionEnd&&(s.SessionEnd=r("SessionEnd",o)),e.preModelSwitch&&(s.PreModelSwitch=r("PreModelSwitch",o),s.PostModelSwitch=r("PostModelSwitch",o)),c.hooks=s}return c.permissions={allow:[...S],deny:[...h]},c.env={WEAVE_ENABLED:"true"},t.helpers&&(c.statusLine={type:"command",command:l.os==="windows"?`node "${o}/statusline.cjs"`:"node "+o+"/statusline.cjs",padding:0,refreshInterval:30}),c}export function mergeSettingsJson(n,t){const e={...n},l=t.hooks;if(l&&typeof l=="object"){const i=d(u(e.hooks)?{...e.hooks}:{})??{};for(const[a,p]of Object.entries(l)){const m=i[a];m===void 0?i[a]=p:Array.isArray(m)&&(i[a]=[...m,...Array.isArray(p)?p:[]])}e.hooks=i}const o=e.statusLine;t.statusLine&&(o===void 0||y(o))&&(e.statusLine=t.statusLine);const c=t.permissions;if(c&&typeof c=="object"){const i=u(e.permissions)?e.permissions:{};for(const a of["allow","deny"]){const p=c[a],m=i[a];Array.isArray(p)?i[a]=b(m,p):m===void 0&&(i[a]=p)}e.permissions=i}const s=t.env;if(s&&typeof s=="object"){const i=u(e.env)?e.env:{};for(const[a,p]of Object.entries(s))i[a]===void 0&&(i[a]=p);e.env=i}return e}function u(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function y(n){if(!u(n))return!1;const t=n.command;return typeof t=="string"&&P(t,v)}function P(n,t){return n.replace(/\\/g,"/").includes(t)}function b(n,t){return Array.isArray(n)?[...n,...t.filter(e=>!n.includes(e))]:[...t]}export function stripWeaveSettings(n){const t={...n};if(u(t.hooks)){const e=d(t.hooks);e?t.hooks=e:delete t.hooks}if(y(t.statusLine)&&delete t.statusLine,u(t.permissions)){const e={...t.permissions},l=(o,c)=>{const s=e[o];if(!Array.isArray(s))return;const i=s.filter(a=>!c.includes(a));i.length>0?e[o]=i:delete e[o]};l("allow",S),l("deny",h),Object.keys(e).length>0?t.permissions=e:delete t.permissions}if(u(t.env)){const e={...t.env};delete e.WEAVE_ENABLED,Object.keys(e).length>0?t.env=e:delete t.env}return t.$comment===f&&delete t.$comment,t}
@@ -0,0 +1,12 @@
1
+ import type { SideQuestionSpec } from '../driver.js';
2
+ /**
3
+ * Claude 旁路会话面(`/btw`):往输入行打 `/btw <原文>` 即开一次侧问——不打断
4
+ * 主回合、宿主用一个 `maxTurns:1` 的轻量 fork 作答。
5
+ *
6
+ * 回答只能从采集事件里认:宿主给这类 fork 的查询开着 `skipTranscript`,**既不
7
+ * 留转录、也不发 prompt 事件**。判据 = `SubagentStop` 且 `agent_transcript_path`
8
+ * 在盘上不存在——普通子 agent 与 skill 子 agent 都有转录文件(实测),没有的
9
+ * 只剩 skipTranscript 那批 fork(侧问 / 压缩摘要 / 后台摘要,后两类由上一条
10
+ * 形状闸与「只认待答行」两道挡掉)。
11
+ */
12
+ export declare const CLAUDE_SIDE_QUESTION: SideQuestionSpec;
@@ -0,0 +1 @@
1
+ import{existsSync as i}from"node:fs";const a=2e3,E=/^[^\x00-\x1f\x7f]+$/,F=/^<(?:analysis|summary)>/,e=(u,t)=>u&&typeof u=="object"?u[t]:void 0;export const CLAUDE_SIDE_QUESTION={command(u){return`/btw ${u}`},validate(u){const t=u.trim();return t?t.length>a?{ok:!1,error:`\u95EE\u9898\u8FC7\u957F\uFF08\u4E0A\u9650 ${a} \u5B57\u7B26\uFF09`}:E.test(t)?{ok:!0,text:t}:{ok:!1,error:"\u95EE\u9898\u4E0D\u80FD\u542B\u6362\u884C\u6216\u63A7\u5236\u5B57\u7B26\uFF08\u4F1A\u63D0\u524D\u63D0\u4EA4\uFF09"}:{ok:!1,error:"\u95EE\u9898\u4E0D\u80FD\u4E3A\u7A7A"}},answerOf(u,t){if(u!=="SubagentStop")return null;const s=e(t,"raw"),r=e(s,"agent_transcript_path");if(typeof r!="string"||!r||i(r))return null;const o=e(s,"last_assistant_message");if(typeof o!="string")return null;const n=o.trim();return n&&!F.test(n)?n:null}};
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Statusline configuration — which segments a project's statusline renders, in
3
+ * what colour/style, and how they are laid out.
4
+ *
5
+ * Stored per-project as `.weave/statusline.json`; a global default template
6
+ * lives at `~/.weave/statusline.json`. The generator embeds the effective
7
+ * config into `helpers/statusline.cjs` so the script is self-contained.
8
+ *
9
+ * Layout model (informed by ruflo's statusline + ccstatusline):
10
+ * - `lines` : an ordered list of rows; each row is the left-to-right segment
11
+ * order of that line (draggable in the panel, across rows too).
12
+ * Rows are separated by a dim divider; the logo prefixes row 0.
13
+ * - `refreshInterval`: how often (seconds, min 1) Claude Code re-runs the
14
+ * generated script during idle periods. Updates are driven by
15
+ * Claude Code's own mechanism — the script is a one-shot command
16
+ * re-invoked after each assistant response (~300ms debounce)
17
+ * plus this timer; default 10s.
18
+ *
19
+ * When `powerline.enabled`, segments render as solid background blocks that
20
+ * join edge-to-edge (ccstatusline-style), each optionally prefixed by an icon.
21
+ * `align` pads the line so the content sits left, centre, or right.
22
+ *
23
+ * Segment data comes straight from Claude Code's statusline stdin JSON
24
+ * (`context_window.used_percentage`, `rate_limits.five_hour.used_percentage`,
25
+ * `effort.level`, `cost.total_cost_usd`, …), so the generated script needs no
26
+ * external daemon — it re-reads stdin on every render, which is the
27
+ * auto-refresh mechanism.
28
+ */
29
+ export type StatuslineNamedColor = 'gray' | 'red' | 'green' | 'yellow' | 'blue' | 'magenta' | 'cyan';
30
+ /**
31
+ * A colour is one of the seven ANSI names (classic SGR 31-36/90), an indexed
32
+ * 256-colour value (`ansi256:196` → `38;5;196`), or a truecolor hex value
33
+ * (`#ff8800` / `#f80` → `38;2;…`).
34
+ *
35
+ * The template-literal union keeps the seven names autocompletable while still
36
+ * admitting the extended encodings. It is deliberately permissive — anything
37
+ * shaped like a hex string type-checks — so `normalizeColor` in the manager is
38
+ * what actually validates values at rest.
39
+ */
40
+ export type StatuslineColor = StatuslineNamedColor | `ansi256:${number}` | `#${string}`;
41
+ /** The seven classic ANSI colour names, in palette order. */
42
+ export declare const NAMED_COLORS: readonly StatuslineNamedColor[];
43
+ /** All renderable segment kinds (maps to ccstatusline's data segments). */
44
+ export type SegmentKey = 'project' | 'git' | 'git_user' | 'changes' | 'model' | 'thinking' | 'context' | 'tokens' | 'cost' | 'rate' | 'time' | 'version' | 'output_style' | 'session' | 'exceeds200k' | 'fast_mode' | 'vim' | 'pr' | 'worktree' | 'agent';
45
+ export interface StatuslineSegment {
46
+ enabled: boolean;
47
+ color: StatuslineColor;
48
+ /** Render the segment in bold ANSI (`\x1b[1;…m`). */
49
+ bold: boolean;
50
+ /** Optional emoji/symbol prefix (e.g. `🤖`, `🌿`, `📁`). Empty when unused. */
51
+ icon: string;
52
+ /** Solid background block colour; `null` for no background (foreground only). */
53
+ backgroundColor: StatuslineColor | null;
54
+ /** Join this segment into the next block (no gap, inherited background). */
55
+ merge: boolean;
56
+ /** Context-bar display mode; ignored by other segments. */
57
+ style?: 'percent' | 'bar' | 'both';
58
+ /** Which rate-limit window `rate` reports; ignored by other segments. */
59
+ window?: 'five_hour' | 'seven_day' | 'spend';
60
+ /**
61
+ * Static text prefix, rendered as `<label><labelSeparator><value>` — e.g.
62
+ * `label: 'Cost'` yields `Cost: $0.45`. Empty/absent means no prefix, which
63
+ * is the behaviour every config had before labels existed.
64
+ */
65
+ label?: string;
66
+ /**
67
+ * Value template with `{token}` placeholders (see `SEGMENT_TOKENS` for the
68
+ * tokens each segment exposes). When set it replaces the built-in formatting
69
+ * for that segment; when absent the segment falls back to its legacy
70
+ * rendering, so existing configs are unaffected.
71
+ *
72
+ * e.g. `context.format = "[{bar}] {used}/{total} ({percent}%)"`
73
+ */
74
+ format?: string;
75
+ /**
76
+ * Which quantity the `tokens` segment reports: `session` (cumulative tokens
77
+ * for the whole session, read from the transcript) or `context` (tokens
78
+ * currently in the context window). Ignored by other segments.
79
+ */
80
+ metric?: 'session' | 'context';
81
+ }
82
+ /**
83
+ * Progress-bar appearance. Global rather than per-segment: a statusline reads
84
+ * as one design, and the reference layout uses a single bar style throughout.
85
+ */
86
+ export interface StatuslineBar {
87
+ /** Number of cells, clamped to 1-40. */
88
+ cells: number;
89
+ /** Filled-cell glyph. */
90
+ fill: string;
91
+ /** Empty-cell glyph. */
92
+ empty: string;
93
+ }
94
+ export type StatuslineAlign = 'left' | 'center' | 'right';
95
+ /** `global` = follow the global default template; `custom` = project-local. */
96
+ export type StatuslineSource = 'global' | 'custom';
97
+ /**
98
+ * Powerline glyph configuration. All glyph fields are optional Nerd-Font
99
+ * characters; `undefined` falls back to the classic triangle set and an empty
100
+ * string disables that glyph (caps only — the join separator is never empty).
101
+ */
102
+ export interface StatuslinePowerline {
103
+ enabled: boolean;
104
+ /** Block-join separator between adjacent blocks (default `` U+E0B0). */
105
+ separator?: string;
106
+ /** Row-start cap, painted in the first block's bg on a transparent
107
+ * background (default `` U+E0B2). Empty string disables. */
108
+ startCap?: string;
109
+ /** Row-end cap, painted in the last block's bg (default `` U+E0B0).
110
+ * Empty string disables. */
111
+ endCap?: string;
112
+ }
113
+ /** Classic triangle glyph set, used when the config leaves a field unset. */
114
+ export declare const POWERLINE_DEFAULT_GLYPHS: {
115
+ readonly separator: "";
116
+ readonly startCap: "";
117
+ readonly endCap: "";
118
+ };
119
+ export interface StatuslineConfig {
120
+ /** Rendered between segments when powerline blocks are off; powerline
121
+ * mode ignores it (the join glyph takes over). Default a single space. */
122
+ separator: string;
123
+ /** Alignment of each rendered row: left, centre or right. */
124
+ align: StatuslineAlign;
125
+ /**
126
+ * Text of the row-0 logo mark, rendered as `<logoText> v<version>`.
127
+ * weave's badge: the value is pinned to the shipped mark (only `logoColor`
128
+ * is user-configurable) and the panel offers no editor for it.
129
+ */
130
+ logoText: string;
131
+ /** Colour of the logo mark. */
132
+ logoColor: StatuslineColor;
133
+ /** ccstatusline-style solid background blocks. */
134
+ powerline: StatuslinePowerline;
135
+ /**
136
+ * Ordered lines; each line is the left-to-right segment order of that row.
137
+ * The panel adds/removes lines and reorders segments within/across them.
138
+ * Rows are separated by a dim divider; the logo prefixes the first row.
139
+ */
140
+ lines: SegmentKey[][];
141
+ /**
142
+ * How often Claude Code re-runs the statusline script (seconds, min 1).
143
+ * Event-driven updates (after each assistant response) happen regardless;
144
+ * this timer only bounds staleness during idle periods. Default 10s.
145
+ */
146
+ refreshInterval: number;
147
+ /** Project config origin: follow the global template, or project-local. */
148
+ source: StatuslineSource;
149
+ /** Progress-bar appearance, shared by every segment that draws a bar. */
150
+ bar: StatuslineBar;
151
+ /** Rendered between rows; an empty string (the default) draws nothing. */
152
+ divider: string;
153
+ /** Rendered between a segment's `label` and its value. Default `': '`. */
154
+ labelSeparator: string;
155
+ segments: Record<SegmentKey, StatuslineSegment>;
156
+ }
157
+ /** Default order in which enabled segments render left-to-right. */
158
+ export declare const SEGMENT_ORDER: SegmentKey[];
159
+ /**
160
+ * Legacy two-row split (single header + metrics) used to migrate old configs
161
+ * that had `layout: 'multi'`.
162
+ */
163
+ export declare const LEGACY_IDENTITY_LINE: SegmentKey[];
164
+ export declare const LEGACY_METRICS_LINE: SegmentKey[];
165
+ /**
166
+ * The shipped default: two powerline rows with text labels and a bracketed
167
+ * context bar.
168
+ *
169
+ * ```
170
+ * 🤖 Model: deepseek-flash[1M] 🧠 [░░░░░░░░░░░░] 39k/1.0M (4%) 🌿 main ✏️ (+1, -1)
171
+ * 🧩 Thinking: high 💸 Cost: $0.45 🔢 Total: 960.9k 📁 D:\…\weave-cli
172
+ * ```
173
+ *
174
+ * Needs a Nerd Font for the powerline joins; `PLAIN_STATUSLINE_CONFIG` is the
175
+ * same layout without them.
176
+ */
177
+ export declare const DEFAULT_STATUSLINE_CONFIG: StatuslineConfig;
178
+ /**
179
+ * The same layout with powerline blocks turned off, for terminals without a
180
+ * Nerd Font — segments fall back to the plain separator and no private-use
181
+ * glyphs are emitted.
182
+ */
183
+ export declare const PLAIN_STATUSLINE_CONFIG: StatuslineConfig;
184
+ /**
185
+ * Tokens each segment exposes to `StatuslineSegment.format`. Exported so the
186
+ * web panel and the CLI preview can offer the same vocabulary the generator
187
+ * understands — keep in lockstep with `segmentTokens` in `generator.ts`.
188
+ */
189
+ export declare const SEGMENT_TOKENS: Record<SegmentKey, readonly string[]>;
190
+ /**
191
+ * Built-in value formatting per segment, used when `format` is unset. Each one
192
+ * reproduces the rendering the generator hard-coded before `format` existed, so
193
+ * an untouched config produces byte-identical output.
194
+ *
195
+ * `context` is special-cased in the generator: its legacy output depended on
196
+ * `style`, so `DEFAULT_CONTEXT_FORMAT` below covers all three modes instead.
197
+ */
198
+ export declare const SEGMENT_DEFAULT_FORMAT: Record<SegmentKey, string>;
199
+ /** Legacy `context.style` → template, preserving each mode's old rendering. */
200
+ export declare const CONTEXT_STYLE_FORMAT: Record<'percent' | 'bar' | 'both', string>;
@@ -0,0 +1 @@
1
+ export const NAMED_COLORS=["gray","red","green","yellow","blue","magenta","cyan"],POWERLINE_DEFAULT_GLYPHS={separator:"\uE0B0",startCap:"\uE0B2",endCap:"\uE0B0"},SEGMENT_ORDER=["project","git_user","git","changes","model","thinking","context","tokens","cost","rate","time","version","output_style","session","exceeds200k","fast_mode","vim","pr","worktree","agent"],LEGACY_IDENTITY_LINE=["project","git","model"],LEGACY_METRICS_LINE=["context","tokens","cost","rate"];const e=o=>({enabled:!0,color:"gray",bold:!1,icon:"",backgroundColor:null,merge:!1,...o});export const DEFAULT_STATUSLINE_CONFIG={separator:" ",align:"left",logoText:"\u258A weave",logoColor:"magenta",powerline:{enabled:!0,separator:"\uE0B0",startCap:"\uE0B6",endCap:"\uE0B4"},lines:[["model","thinking","time"],["context","tokens","cost","rate"],["git_user","git","changes","project"]],refreshInterval:30,source:"global",bar:{cells:12,fill:"\u2588",empty:"\u2591"},divider:"",labelSeparator:": ",segments:{model:e({color:"#1f2335",backgroundColor:"#7aa2f7",bold:!0,icon:"\u{1F916}",label:"Model"}),context:e({color:"#c0caf5",backgroundColor:"#24283b",icon:"\u{1F9E0}",format:"[{bar}] {used}/{total} ({percent}%)"}),git:e({color:"#1f2335",backgroundColor:"#9ece6a",icon:"\u{1F33F}",format:"{branch} {sync}"}),git_user:e({color:"#1f2335",backgroundColor:"#7dcfff",icon:"\u{1F464}",format:"{user} <{email}>"}),changes:e({color:"#1f2335",backgroundColor:"#e0af68",icon:"\u270F\uFE0F",format:"(+{added}, -{deleted})"}),thinking:e({color:"#1f2335",backgroundColor:"#bb9af7",icon:"\u{1F9E9}",label:"Thinking"}),cost:e({color:"#1f2335",backgroundColor:"#73daca",icon:"\u{1F4B8}",label:"Cost"}),tokens:e({color:"#1f2335",backgroundColor:"#ff9e64",icon:"\u{1F522}",label:"Total",metric:"session"}),project:e({color:"#c0caf5",backgroundColor:"#2f334d",icon:"\u{1F4C1}",format:"{path}"}),rate:e({enabled:!1,color:"#f7768e",icon:"\u26A1",label:"Rate"}),time:e({enabled:!0,color:"gray",backgroundColor:"blue",icon:"\u{1F552}"}),version:e({enabled:!1,color:"#a9b1d6",icon:"\u2139\uFE0F",label:"CC",format:"{version}"}),output_style:e({enabled:!1,color:"#bb9af7",icon:"\u{1F3A8}",format:"{style}"}),session:e({enabled:!1,color:"#7dcfff",icon:"\u{1F3F7}\uFE0F",label:"Session",format:"{name}"}),exceeds200k:e({enabled:!1,color:"#f7768e",icon:"\u{1F6A8}",format:"{over}"}),fast_mode:e({enabled:!1,color:"#ff9e64",icon:"\u{1F680}",format:"{mode}"}),vim:e({enabled:!1,color:"#9ece6a",icon:"\u2328\uFE0F",format:"{mode}"}),pr:e({enabled:!1,color:"#73daca",icon:"\u{1F517}",label:"PR",format:"#{number}"}),worktree:e({enabled:!1,color:"#7aa2f7",icon:"\u{1FAB4}",format:"{name}"}),agent:e({enabled:!1,color:"#c0caf5",icon:"\u{1F3AD}",label:"Agent",format:"{name}"})}},PLAIN_STATUSLINE_CONFIG={...DEFAULT_STATUSLINE_CONFIG,powerline:{enabled:!1}},SEGMENT_TOKENS={project:["name","path"],git:["branch","repo","ahead","behind","sync"],git_user:["user","email"],changes:["added","deleted","files"],model:["model"],thinking:["level"],context:["bar","used","total","percent","remaining"],tokens:["total","percent"],cost:["cost","duration","api_duration","lines_added","lines_removed"],rate:["percent","limit","resets"],time:["time"],version:["version"],output_style:["style"],session:["name"],exceeds200k:["over"],fast_mode:["mode"],vim:["mode"],pr:["number","state","url"],worktree:["name","branch"],agent:["name"]},SEGMENT_DEFAULT_FORMAT={project:"{name}",git:"{branch} {sync}",git_user:"{user} <{email}>",changes:"{files}",model:"{model}",thinking:"{level}",context:"{percent}% {bar}",tokens:"{total}",cost:"{cost}",rate:"{limit} {percent}%",time:"{time}",version:"{version}",output_style:"{style}",session:"{name}",exceeds200k:"{over}",fast_mode:"{mode}",vim:"{mode}",pr:"#{number}",worktree:"{name}",agent:"{name}"},CONTEXT_STYLE_FORMAT={percent:"{percent}%",bar:"{bar}",both:"{percent}% {bar}"};
@@ -0,0 +1,12 @@
1
+ import type { StatuslineConfig } from './config.js';
2
+ /**
3
+ * 生成脚本的运行参数——两样都是调用方(server)的事实,harness 不自取:
4
+ * `cacheDir` 归 dataDir 布局(`<dataDir>/statusline/<session>.json`,按会话一个
5
+ * 文件,过期条目与陈旧文件由 daemon 的清扫器回收),`version` 归包身份(写进
6
+ * 脚本 banner)。
7
+ */
8
+ export interface GenerateStatuslineOptions {
9
+ cacheDir: string;
10
+ version: string;
11
+ }
12
+ export declare function generateStatuslineScript(config: StatuslineConfig, opts: GenerateStatuslineOptions): string;