@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.
- package/node_modules/@weavecode/cli/dist/cli.js +4 -4
- package/node_modules/@weavecode/cli/dist/commands/chpass.js +1 -1
- package/node_modules/@weavecode/cli/dist/commands/daemon-auth.js +1 -1
- package/node_modules/@weavecode/cli/dist/commands/daemon.d.ts +7 -0
- package/node_modules/@weavecode/cli/dist/commands/daemon.js +2 -2
- package/node_modules/@weavecode/cli/dist/commands/dashboard.js +2 -2
- package/node_modules/@weavecode/cli/dist/commands/doctor.js +1 -1
- package/node_modules/@weavecode/cli/dist/commands/init.js +1 -1
- package/node_modules/@weavecode/cli/dist/commands/scan.js +1 -1
- package/node_modules/@weavecode/cli/dist/commands/status.js +2 -2
- package/node_modules/@weavecode/cli/dist/commands/uninstall.js +1 -1
- package/node_modules/@weavecode/cli/dist/i18n/dict/en.js +1 -9
- package/node_modules/@weavecode/cli/dist/i18n/dict/zh.d.ts +0 -1
- package/node_modules/@weavecode/cli/dist/i18n/dict/zh.js +2 -10
- package/node_modules/@weavecode/cli/dist/i18n/index.js +1 -1
- package/node_modules/@weavecode/cli/dist/i18n/t.js +1 -1
- package/node_modules/@weavecode/cli/dist/init/claudemd-gen.d.ts +2 -3
- package/node_modules/@weavecode/cli/dist/init/claudemd-gen.js +4 -4
- package/node_modules/@weavecode/cli/dist/init/executor.js +3 -3
- package/node_modules/@weavecode/cli/dist/init/git-commit.js +2 -2
- package/node_modules/@weavecode/cli/dist/init/harnesses/claude.js +7 -7
- package/node_modules/@weavecode/cli/dist/init/harnesses/codex.js +1 -1
- package/node_modules/@weavecode/cli/dist/init/harnesses/zcode.d.ts +29 -0
- package/node_modules/@weavecode/cli/dist/init/harnesses/zcode.js +1 -0
- package/node_modules/@weavecode/cli/dist/init/instruction-link.js +1 -1
- package/node_modules/@weavecode/cli/dist/init/plugin-templates.js +1 -1
- package/node_modules/@weavecode/cli/dist/init/prompt.js +4 -4
- package/node_modules/@weavecode/cli/dist/init/uninstall.js +6 -6
- package/node_modules/@weavecode/cli/dist/init/wiring.js +1 -1
- package/node_modules/@weavecode/cli/dist/parser.js +1 -1
- package/node_modules/@weavecode/cli/dist/statusline/ansi.js +1 -1
- package/node_modules/@weavecode/cli/dist/statusline/mock-input.js +1 -1
- package/node_modules/@weavecode/cli/dist/statusline/preview.js +2 -2
- package/node_modules/@weavecode/cli/package.json +5 -5
- package/node_modules/@weavecode/core/dist/harness-checks.js +1 -1
- package/node_modules/@weavecode/core/dist/index.d.ts +1 -1
- package/node_modules/@weavecode/core/dist/index.js +1 -1
- package/node_modules/@weavecode/core/dist/platform.js +1 -1
- package/node_modules/@weavecode/core/dist/types.d.ts +0 -8
- package/node_modules/@weavecode/core/dist/types.js +1 -1
- package/node_modules/@weavecode/core/dist/utils/fs.js +1 -1
- package/node_modules/@weavecode/core/dist/utils/logger.js +1 -1
- package/node_modules/@weavecode/core/package.json +1 -1
- package/node_modules/@weavecode/harness/dist/claude/assets.d.ts +10 -0
- package/node_modules/@weavecode/harness/dist/claude/assets.js +4 -1
- package/node_modules/@weavecode/harness/dist/claude/capture.d.ts +4 -2
- package/node_modules/@weavecode/harness/dist/claude/capture.js +15 -9
- package/node_modules/@weavecode/harness/dist/claude/detect.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/event-source.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/index.d.ts +6 -1
- package/node_modules/@weavecode/harness/dist/claude/index.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/mcp-gen.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/messaging.js +2 -2
- package/node_modules/@weavecode/harness/dist/claude/model-aliases.d.ts +14 -0
- package/node_modules/@weavecode/harness/dist/claude/model-aliases.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/peers.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/plan.d.ts +2 -0
- package/node_modules/@weavecode/harness/dist/claude/plan.js +1 -0
- package/node_modules/@weavecode/harness/dist/claude/plugins.js +4 -4
- package/node_modules/@weavecode/harness/dist/claude/prompt-inbox.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/prompt.js +3 -3
- package/node_modules/@weavecode/harness/dist/claude/questions.js +2 -2
- package/node_modules/@weavecode/harness/dist/claude/settings-gen.js +1 -1
- package/node_modules/@weavecode/harness/dist/claude/side-question.d.ts +12 -0
- package/node_modules/@weavecode/harness/dist/claude/side-question.js +1 -0
- package/node_modules/@weavecode/harness/dist/claude/statusline/config.d.ts +200 -0
- package/node_modules/@weavecode/harness/dist/claude/statusline/config.js +1 -0
- package/node_modules/@weavecode/harness/dist/claude/statusline/generator.d.ts +12 -0
- package/node_modules/@weavecode/harness/dist/claude/statusline/generator.js +745 -0
- package/node_modules/@weavecode/harness/dist/claude/statusline/git-cache.d.ts +10 -0
- package/node_modules/@weavecode/harness/dist/claude/statusline/git-cache.js +1 -0
- package/node_modules/@weavecode/harness/dist/claude/statusline/surface.d.ts +20 -0
- package/node_modules/@weavecode/harness/dist/claude/statusline/surface.js +2 -0
- package/node_modules/@weavecode/harness/dist/claude/transcript.js +3 -3
- package/node_modules/@weavecode/harness/dist/codex/assets.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/detect.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/index.d.ts +1 -0
- package/node_modules/@weavecode/harness/dist/codex/index.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/mcp.d.ts +30 -0
- package/node_modules/@weavecode/harness/dist/codex/mcp.js +1 -0
- package/node_modules/@weavecode/harness/dist/codex/messaging.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/plugin-state.js +1 -1
- package/node_modules/@weavecode/harness/dist/codex/toml.js +9 -9
- package/node_modules/@weavecode/harness/dist/driver.d.ts +110 -2
- package/node_modules/@weavecode/harness/dist/driver.js +1 -1
- package/node_modules/@weavecode/harness/dist/init/generated.js +2 -2
- package/node_modules/@weavecode/harness/dist/init/pipeline.js +1 -1
- package/node_modules/@weavecode/harness/dist/registry-wiring.js +1 -1
- package/node_modules/@weavecode/harness/dist/shared/install-link.js +1 -1
- package/node_modules/@weavecode/harness/dist/zcode/assets.d.ts +8 -0
- package/node_modules/@weavecode/harness/dist/zcode/assets.js +1 -0
- package/node_modules/@weavecode/harness/dist/zcode/capture.d.ts +36 -0
- package/node_modules/@weavecode/harness/dist/zcode/capture.js +3 -0
- package/node_modules/@weavecode/harness/dist/zcode/detect.d.ts +2 -0
- package/node_modules/@weavecode/harness/dist/zcode/detect.js +1 -0
- package/node_modules/@weavecode/harness/dist/zcode/event-source.d.ts +8 -0
- package/node_modules/@weavecode/harness/dist/zcode/event-source.js +1 -0
- package/node_modules/@weavecode/harness/dist/zcode/index.d.ts +13 -0
- package/node_modules/@weavecode/harness/dist/zcode/index.js +1 -0
- package/node_modules/@weavecode/harness/dist/zcode/mcp.d.ts +6 -0
- package/node_modules/@weavecode/harness/dist/zcode/mcp.js +2 -0
- package/node_modules/@weavecode/harness/dist/zcode/messaging.d.ts +13 -0
- package/node_modules/@weavecode/harness/dist/zcode/messaging.js +1 -0
- package/node_modules/@weavecode/harness/dist/zcode/resume.d.ts +7 -0
- package/node_modules/@weavecode/harness/dist/zcode/resume.js +1 -0
- package/node_modules/@weavecode/harness/package.json +2 -2
- package/node_modules/@weavecode/server/dist/daemon/dev-entry.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/hook-pipeline.d.ts +8 -1
- package/node_modules/@weavecode/server/dist/daemon/hook-pipeline.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/hooks-routes.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/server.d.ts +7 -0
- package/node_modules/@weavecode/server/dist/daemon/server.js +8 -6
- package/node_modules/@weavecode/server/dist/daemon/session-probe.d.ts +13 -0
- package/node_modules/@weavecode/server/dist/daemon/session-probe.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/snapshot-refresher.d.ts +7 -1
- package/node_modules/@weavecode/server/dist/daemon/snapshot-refresher.js +1 -1
- package/node_modules/@weavecode/server/dist/daemon/sse-hub.d.ts +40 -0
- package/node_modules/@weavecode/server/dist/daemon/sse-hub.js +1 -0
- package/node_modules/@weavecode/server/dist/daemon/start.js +1 -1
- package/node_modules/@weavecode/server/dist/db/db.js +20 -2
- package/node_modules/@weavecode/server/dist/hooks/bus.d.ts +5 -0
- package/node_modules/@weavecode/server/dist/hooks/inbox-worker.d.ts +8 -1
- package/node_modules/@weavecode/server/dist/hooks/inbox-worker.js +3 -3
- package/node_modules/@weavecode/server/dist/hooks/message-deliverer.d.ts +29 -0
- package/node_modules/@weavecode/server/dist/hooks/message-deliverer.js +2 -2
- package/node_modules/@weavecode/server/dist/hooks/mirror.d.ts +9 -4
- package/node_modules/@weavecode/server/dist/hooks/mirror.js +4 -4
- package/node_modules/@weavecode/server/dist/hooks/session-purge.d.ts +3 -0
- package/node_modules/@weavecode/server/dist/hooks/session-purge.js +1 -1
- package/node_modules/@weavecode/server/dist/hooks/side-questions.d.ts +41 -0
- package/node_modules/@weavecode/server/dist/hooks/side-questions.js +1 -0
- package/node_modules/@weavecode/server/dist/hooks/toolkit.js +5 -5
- package/node_modules/@weavecode/server/dist/install/apply-update.js +1 -1
- package/node_modules/@weavecode/server/dist/install/capabilities.d.ts +10 -0
- package/node_modules/@weavecode/server/dist/install/capabilities.js +1 -1
- package/node_modules/@weavecode/server/dist/install/codex-toml.d.ts +8 -26
- package/node_modules/@weavecode/server/dist/install/codex-toml.js +1 -1
- package/node_modules/@weavecode/server/dist/install/global-config.d.ts +2 -4
- package/node_modules/@weavecode/server/dist/install/global-config.js +1 -2
- package/node_modules/@weavecode/server/dist/install/installer.d.ts +3 -5
- package/node_modules/@weavecode/server/dist/install/installer.js +1 -3
- package/node_modules/@weavecode/server/dist/install/mcp-rows.d.ts +5 -5
- package/node_modules/@weavecode/server/dist/install/mcp-rows.js +1 -1
- package/node_modules/@weavecode/server/dist/registry.js +2 -2
- package/node_modules/@weavecode/server/dist/repositories/hook-events.d.ts +7 -0
- package/node_modules/@weavecode/server/dist/repositories/hook-events.js +2 -2
- package/node_modules/@weavecode/server/dist/repositories/sessions.d.ts +15 -4
- package/node_modules/@weavecode/server/dist/repositories/sessions.js +2 -2
- package/node_modules/@weavecode/server/dist/repositories/side-questions.d.ts +50 -0
- package/node_modules/@weavecode/server/dist/repositories/side-questions.js +6 -0
- package/node_modules/@weavecode/server/dist/statusline/config.d.ts +4 -198
- package/node_modules/@weavecode/server/dist/statusline/config.js +1 -1
- package/node_modules/@weavecode/server/dist/statusline/generator.d.ts +5 -0
- package/node_modules/@weavecode/server/dist/statusline/generator.js +1 -717
- package/node_modules/@weavecode/server/dist/statusline/manager.d.ts +5 -5
- package/node_modules/@weavecode/server/dist/statusline/manager.js +3 -4
- package/node_modules/@weavecode/server/dist/surfaces.d.ts +11 -1
- package/node_modules/@weavecode/server/dist/surfaces.js +1 -1
- package/node_modules/@weavecode/server/package.json +4 -4
- package/node_modules/@weavecode/server/web/dist/assets/index-CHWbLAje.js +594 -0
- package/node_modules/@weavecode/server/web/dist/assets/index-D0s5v8QS.css +11 -0
- package/node_modules/@weavecode/server/web/dist/index.html +2 -2
- package/node_modules/@weavecode/templates/package.json +2 -2
- package/package.json +6 -6
- package/node_modules/@weavecode/server/web/dist/assets/index-D5WFh77i.css +0 -11
- package/node_modules/@weavecode/server/web/dist/assets/index-DJibaGnJ.js +0 -585
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { StatuslineFacts } from '../../driver.js';
|
|
2
|
+
/** 与生成脚本 initCache 同一套目录摘要:大小写不敏感、分隔符归一、去尾斜杠。 */
|
|
3
|
+
export declare function gitCacheKeyOf(cwd: string): string;
|
|
4
|
+
/**
|
|
5
|
+
* 渲染脚本把 git 三块的结果按目录分片落在 `git-<cwd 摘要>.json` 里(同一项目
|
|
6
|
+
* 的会话共享,TTL 见生成脚本)。dashboard 要摆同样的块就从这儿取——不做 git
|
|
7
|
+
* 探测、不算第二份事实:过期的条目一律不认(渲染侧同样会重探,认了就会和 TUI
|
|
8
|
+
* 对不上),文件读不到 / 条目不在即返回 null。
|
|
9
|
+
*/
|
|
10
|
+
export declare function statuslineFactsFromCache(cacheDir: string, cwd: string, now?: number): StatuslineFacts | null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readFileSync as g}from"node:fs";import{createHash as d}from"node:crypto";import f from"node:path";export function gitCacheKeyOf(a){return d("sha1").update(a.toLowerCase().replace(/\\/g,"/").replace(/\/+$/,"")).digest("hex").slice(0,16)}export function statuslineFactsFromCache(a,l,u=Date.now()){let c;try{c=JSON.parse(g(f.join(a,`git-${gitCacheKeyOf(l)}.json`),"utf-8"))}catch{return null}const s=t=>{const i=c.git?.[t];return!i||typeof i.expires!="number"||i.expires<=u?null:i.value??null},e={},o=s("branch");if(typeof o=="string"&&o){e.git={branch:o};const t=s("sync");t&&typeof t=="object"&&t.sync&&(e.git.ahead=t.ahead??"",e.git.behind=t.behind??"",e.git.sync=t.sync)}const n=s("git_user");n&&typeof n=="object"&&n.user&&(e.git_user={user:n.user,email:n.email??""});const r=s("changes");return r&&typeof r=="object"&&(e.changes={added:String(r.added??0),deleted:String(r.deleted??0),files:String(r.files??0)}),Object.keys(e).length>0?e:null}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { StatuslineSurface } from '../../driver.js';
|
|
2
|
+
/**
|
|
3
|
+
* Keep `.claude/settings.json`'s `statusLine` pointing at the generated script,
|
|
4
|
+
* with a `refreshInterval` (seconds) so Claude Code re-runs it on a timer during
|
|
5
|
+
* idle periods — updates after each assistant response are event-driven by
|
|
6
|
+
* Claude Code itself and need no weave-side polling. Preserves all other
|
|
7
|
+
* settings. Idempotent.
|
|
8
|
+
*/
|
|
9
|
+
export declare function ensureSettingsStatusLine(projectPath: string, opts: {
|
|
10
|
+
scriptPath: string;
|
|
11
|
+
refreshInterval: number;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Claude Code 的状态栏面:weave 生成脚本、宿主每轮调用它渲染在 TUI 底部。
|
|
15
|
+
*
|
|
16
|
+
* `segments` 就是 Claude Code statusline stdin JSON 能填的块(词表见
|
|
17
|
+
* `config.ts` 的 `SegmentKey`)——别的 harness 的面(或没有面)由它们自己声明,
|
|
18
|
+
* web 只渲染能力表给出的块。
|
|
19
|
+
*/
|
|
20
|
+
export declare const CLAUDE_STATUSLINE: StatuslineSurface;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{readFile as o,writeFile as m,mkdir as u,access as l}from"node:fs/promises";import n from"node:path";import{SEGMENT_ORDER as p}from"./config.js";import{generateStatuslineScript as f}from"./generator.js";import{statuslineFactsFromCache as d}from"./git-cache.js";const h=".claude/helpers",S="statusline.cjs",w=".claude/settings.json";async function g(t){try{return await l(t),!0}catch{return!1}}export async function ensureSettingsStatusLine(t,a){const e=n.join(t,w),i=process.platform==="win32";let r={};if(await g(e))try{r=JSON.parse(await o(e,"utf-8"))}catch{r={}}const s=a.scriptPath,c=i?`node "${s}"`:`node ${s}`;r.statusLine={type:"command",command:c,padding:0,refreshInterval:Math.max(1,Math.round(a.refreshInterval))},await u(n.dirname(e),{recursive:!0}),await m(e,`${JSON.stringify(r,null,2)}
|
|
2
|
+
`,"utf-8")}export const CLAUDE_STATUSLINE={segments:p,tui:"injectable",scriptRelPath:`${h}/${S}`,generate:(t,a)=>f(t,a),wire:ensureSettingsStatusLine,facts:d};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
const s="[Request interrupted by user";function c(n){return typeof n=="string"?n:Array.isArray(n)?n.map(t=>{const e=t?.text;return typeof e=="string"?e:""}).join(""):""}export function interruptMarkerAt(n){let t=null;for(const e of n.split(`
|
|
2
|
-
`)){if(!e.includes(s))continue;let
|
|
3
|
-
`)){if(!e.includes('"model"'))continue;let
|
|
4
|
-
`)){if(!e.includes("permissionMode"))continue;let
|
|
2
|
+
`)){if(!e.includes(s))continue;let o;try{o=JSON.parse(e)}catch{continue}const r=o;if(r?.type!=="user"||!c(r.message?.content).startsWith(s))continue;const i=Date.parse(String(r.timestamp));Number.isFinite(i)&&(t===null||i>t)&&(t=i)}return t}const u="<synthetic>";export function currentModelAt(n){let t=null;for(const e of n.split(`
|
|
3
|
+
`)){if(!e.includes('"model"'))continue;let o;try{o=JSON.parse(e)}catch{continue}const r=o,i=r?.message?.model??r?.model;typeof i!="string"||!i||i===u||(t=i)}return t}export function currentModeAt(n){let t=null;for(const e of n.split(`
|
|
4
|
+
`)){if(!e.includes("permissionMode"))continue;let o;try{o=JSON.parse(e)}catch{continue}const r=o?.permissionMode;typeof r!="string"||!r||(t=r)}return t}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import i from"node:path";import{FILE_ASSET_SPECS as n}from"../shared/file-specs.js";import{readCodexMcpServers as l,removeCodexMcpServer as d,writeCodexMcpServer as a}from"./mcp.js";const c=e=>i.join(e,".codex","config.toml");export const CODEX_ASSETS={harness:"codex",targetDir(e,r,o,s){const t=n[e].dirs.codex;if(r!=="user"||!t?.user)throw new Error(`"${e}" has no Codex ${r==="user"?"user":"project"} surface`);return i.join(s,...t.user.split("/"))},projectSkillsDir:()=>".codex/skills",globalSkillsRoots:e=>[i.join(e,...".agents/skills".split("/")),i.join(e,...".codex/skills".split("/"))],userConfigFile:e=>c(e),mcpScopes:()=>["user"],mcpDest:(e,r)=>e==="user"?c(r):void 0,pluginCacheDir:e=>i.join(e,".codex","plugins","cache"),async mcpRead(e,r,o){if(e!=="user")throw new Error("Codex MCP servers are user-level only (~/.codex/config.toml)");return l(c(o))},async mcpWrite(e,r,o,s,t){if(e!=="user")throw new Error("Codex MCP servers are user-level only (~/.codex/config.toml)");await a(s,t,c(o))},async mcpRemove(e,r,o,s){if(e!=="user")throw new Error("Codex MCP servers are user-level only (~/.codex/config.toml)");return d(s,c(o))},classify(e){return e===".codex"||e.startsWith(".codex/")?!0:e.slice(e.lastIndexOf("/")+1)==="AGENTS.md"},ignore(e){return!(e===".codex"||e.startsWith(".codex/")||e==="AGENTS.md")}};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync as
|
|
1
|
+
import{existsSync as s}from"node:fs";import n from"node:path";const o=[".codex","AGENTS.md"];function t(e){return o.some(r=>s(n.join(e,r)))}export const CODEX_DETECTOR={markers:o,present:t,detect:e=>({harness:"codex",present:t(e)})};
|
|
@@ -2,6 +2,7 @@ import type { HarnessDriver } from '../driver.js';
|
|
|
2
2
|
export { CODEX_DETECTOR } from './detect.js';
|
|
3
3
|
export { CODEX_PLUGIN_STATE } from './plugin-state.js';
|
|
4
4
|
export { CODEX_MESSAGING } from './messaging.js';
|
|
5
|
+
export * from './mcp.js';
|
|
5
6
|
export * from './toml.js';
|
|
6
7
|
/**
|
|
7
8
|
* Codex 接入模块的驱动:批 4a 补 assets 槽、批 5 补 detect、P2 补 pluginState
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{CODEX_ASSETS as
|
|
1
|
+
import{CODEX_ASSETS as o}from"./assets.js";import{CODEX_DETECTOR as t}from"./detect.js";import{CODEX_MESSAGING as e}from"./messaging.js";import{CODEX_PLUGIN_STATE as r}from"./plugin-state.js";export{CODEX_DETECTOR}from"./detect.js";export{CODEX_PLUGIN_STATE}from"./plugin-state.js";export{CODEX_MESSAGING}from"./messaging.js";export*from"./mcp.js";export*from"./toml.js";export const CODEX_DRIVER={id:"codex",displayName:"Codex",capabilities:["assets","detect","pluginState","messaging"],assets:o,detect:t,pluginState:r,messaging:e};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { McpServerConfig } from '../driver.js';
|
|
2
|
+
/**
|
|
3
|
+
* Codex config.toml 的 MCP 表示法(文本层 + fs 层):`[mcp_servers.<name>]`
|
|
4
|
+
* 这一形是 codex 自己的知识,调用方只传名字与 `McpServerConfig`。
|
|
5
|
+
*/
|
|
6
|
+
/** Read the `mcp_servers` map from config.toml text (empty when absent or
|
|
7
|
+
* unparseable). stdio servers only — entries without a `command` (e.g. remote
|
|
8
|
+
* url servers) are skipped. */
|
|
9
|
+
export declare function readCodexMcpFromText(text: string): Record<string, McpServerConfig>;
|
|
10
|
+
/** Insert or replace an `[mcp_servers.<name>]` entry in config.toml text,
|
|
11
|
+
* preserving everything else. Merge-validated: if preserving user-added keys
|
|
12
|
+
* produces invalid TOML, the section is written clean instead. */
|
|
13
|
+
export declare function upsertCodexMcpInText(text: string, name: string, config: McpServerConfig): string;
|
|
14
|
+
/** Remove an `[mcp_servers.<name>]` entry (with its sub-sections) from
|
|
15
|
+
* config.toml text. Returns whether a section was removed. */
|
|
16
|
+
export declare function removeCodexMcpFromText(text: string, name: string): {
|
|
17
|
+
text: string;
|
|
18
|
+
removed: boolean;
|
|
19
|
+
};
|
|
20
|
+
/** Read MCP servers from a config.toml (empty when absent/corrupt). */
|
|
21
|
+
export declare function readCodexMcpServers(file: string): Promise<Record<string, McpServerConfig>>;
|
|
22
|
+
/** Whether an `[mcp_servers.<name>]` section exists (cheap line-level check). */
|
|
23
|
+
export declare function codexMcpExists(name: string, file: string): Promise<boolean>;
|
|
24
|
+
/** Insert or replace an MCP server in a config.toml. Refuses to write a file
|
|
25
|
+
* that does not parse (protects the user's hand-written config); creates the
|
|
26
|
+
* file when absent. */
|
|
27
|
+
export declare function writeCodexMcpServer(name: string, config: McpServerConfig, file: string): Promise<void>;
|
|
28
|
+
/** Remove an MCP server section from a config.toml. Returns whether a section
|
|
29
|
+
* was removed (false = was not configured). */
|
|
30
|
+
export declare function removeCodexMcpServer(name: string, file: string): Promise<boolean>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readFile as p,writeFile as w,access as S,mkdir as M}from"node:fs/promises";import $ from"node:path";import{parse as m}from"smol-toml";import{CodexTomlCorruptError as l,parseSectionEntries as h,removeTomlSection as b,renderTomlHeader as j,renderTomlKey as A,renderTomlString as y,sameKey as d,splitTomlSections as v,upsertTomlSection as x}from"./toml.js";export function readCodexMcpFromText(r){let e;try{e=m(r)}catch{return{}}const n=e.mcp_servers;if(!n||typeof n!="object"||Array.isArray(n))return{};const t={};for(const[s,o]of Object.entries(n)){const i=C(o);i&&(t[s]=i)}return t}function C(r){if(!r||typeof r!="object"||Array.isArray(r))return null;const e=r;if(typeof e.command!="string")return null;const n={command:e.command};if(Array.isArray(e.args)){const t=e.args.filter(s=>typeof s=="string");t.length>0&&(n.args=t)}if(e.env&&typeof e.env=="object"&&!Array.isArray(e.env)){const t={};for(const[s,o]of Object.entries(e.env))typeof o=="string"&&(t[s]=o);Object.keys(t).length>0&&(n.env=t)}return n}function T(r,e,n,t,s){const o=[`command = ${y(e.command)}`];if(e.args&&e.args.length>0&&o.push(`args = [${e.args.map(y).join(", ")}]`),s&&n){const a=new Set(["command","args","env"]);for(const[c,u]of h(n.lines.slice(1)))a.has(c)||o.push(u)}const i=Object.entries(e.env??{}),f=s&&t?h(t.lines.slice(1)).filter(([a])=>!(a in(e.env??{}))):[];if(i.length>0||f.length>0){o.push(""),o.push(j([...r,"env"]));for(const[a,c]of i)o.push(`${A(a)} = ${y(c)}`);for(const[,a]of f)o.push(a)}return o}export function upsertCodexMcpInText(r,e,n){const t=["mcp_servers",e],s=_(r);if(s)throw s;const o=v(r),i=o.find(c=>d(c.key,t)),f=o.find(c=>d(c.key,[...t,"env"])),a=x(r,t,T(t,n,i,f,!0));try{return m(a),a}catch{const c=x(r,t,T(t,n,i,f,!1));try{return m(c),c}catch(u){throw new l(`unable to produce valid TOML for [mcp_servers.${e}]: ${u instanceof Error?u.message:String(u)}`)}}}export function removeCodexMcpFromText(r,e){return b(r,["mcp_servers",e])}function _(r){return v(r)[0].lines.find(e=>/^\s*mcp_servers\s*=/.test(e))?new l('~/.codex/config.toml defines "mcp_servers" as an inline value \u2014 weave only manages the [mcp_servers.<name>] section form'):null}async function E(r){try{return await p(r,"utf-8")}catch{return""}}async function g(r){try{return await S(r),!0}catch{return!1}}export async function readCodexMcpServers(r){return await g(r)?readCodexMcpFromText(await p(r,"utf-8")):{}}export async function codexMcpExists(r,e){return await g(e)?O(await p(e,"utf-8"),["mcp_servers",r]):!1}function O(r,e){return v(r).some(n=>d(n.key,e))}export async function writeCodexMcpServer(r,e,n){const t=await E(n);if(t.trim()!=="")try{m(t)}catch(s){throw new l(`${n} is not valid TOML \u2014 refusing to write: ${s instanceof Error?s.message:String(s)}`)}await M($.dirname(n),{recursive:!0}),await w(n,upsertCodexMcpInText(t,r,e),"utf-8")}export async function removeCodexMcpServer(r,e){if(!await g(e))return!1;const n=await p(e,"utf-8");try{m(n)}catch(o){throw new l(`${e} is not valid TOML \u2014 refusing to write: ${o instanceof Error?o.message:String(o)}`)}const{text:t,removed:s}=removeCodexMcpFromText(n,r);return s&&await w(e,t,"utf-8"),s}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const CODEX_MESSAGING={harness:"codex",discovery:!1,prompt:null,promptInbox:null,inject:null,headless:null,idleSignals:[],imageAttach:null,unsupportedReasons:{discovery:"Codex event ingestion is pending research (BACKLOG \xA710-6); sessions are not discoverable",prompt:"Codex has no native peer-messaging channel; prompts can only reach it via terminal text injection where the configured terminal supports it",inject:"Codex has no synchronous injection channel yet (pending research)",headless:"Codex resume is pending research",watch:"Codex idle signals are pending research; watch is unavailable"}};
|
|
1
|
+
export const CODEX_MESSAGING={harness:"codex",discovery:!1,prompt:null,promptInbox:null,inject:null,headless:null,idleSignals:[],imageAttach:null,sideQuestion:null,unsupportedReasons:{discovery:"Codex event ingestion is pending research (BACKLOG \xA710-6); sessions are not discoverable",prompt:"Codex has no native peer-messaging channel; prompts can only reach it via terminal text injection where the configured terminal supports it",inject:"Codex has no synchronous injection channel yet (pending research)",headless:"Codex resume is pending research",watch:"Codex idle signals are pending research; watch is unavailable",sideQuestion:"Codex side chat is pending research (BACKLOG \xA710-6)"}};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{access as
|
|
1
|
+
import{access as l,mkdir as m,readFile as i,writeFile as u}from"node:fs/promises";import{homedir as n}from"node:os";import p from"node:path";import{parse as s}from"smol-toml";import{CODEX_ASSETS as f}from"./assets.js";import{CodexTomlCorruptError as d,upsertCodexPluginEnabledInText as b}from"./toml.js";const c=e=>l(e).then(()=>!0,()=>!1);async function w(e){if(!await c(e))return{};try{const o=s(await i(e,"utf-8")).plugins;if(!o||typeof o!="object"||Array.isArray(o))return{};const r={};for(const[a,t]of Object.entries(o))t&&typeof t=="object"&&typeof t.enabled=="boolean"&&(r[a]=t.enabled);return r}catch{return{}}}export const CODEX_PLUGIN_STATE={readGlobalEnabled:()=>w(f.userConfigFile(n())),async writeGlobalEnabled(e,o){const r=f.userConfigFile(n());let a="";if(await c(r)){a=await i(r,"utf-8");try{s(a)}catch(t){throw new d(`${r} is not valid TOML \u2014 refusing to write: ${t instanceof Error?t.message:String(t)}`)}}await m(p.dirname(r),{recursive:!0}),await u(r,b(a,e,o),"utf-8")}};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
export class CodexTomlCorruptError extends Error{constructor(
|
|
2
|
-
`,f:"\f",r:"\r",'"':'"',"\\":"\\"};export function parseDottedKey(
|
|
3
|
-
`?
|
|
4
|
-
`),n=[];let
|
|
5
|
-
`}function b(
|
|
1
|
+
export class CodexTomlCorruptError extends Error{constructor(r){super(r),this.name="CodexTomlCorruptError"}}function $(t){return/[A-Za-z0-9_-]/.test(t)}function p(t){return t===" "||t===" "}const a={b:"\b",t:" ",n:`
|
|
2
|
+
`,f:"\f",r:"\r",'"':'"',"\\":"\\"};export function parseDottedKey(t){const r=[];let n=0;for(;;){for(;n<t.length&&p(t[n]);)n++;if(n>=t.length)return null;const e=t[n];if(e==='"'||e==="'"){n++;let o="";for(;n<t.length;){const l=t[n];if(e==='"'&&l==="\\"){const u=t[n+1];if(u===void 0||!(u in a))return null;o+=a[u],n+=2;continue}if(l===e)break;o+=l,n++}if(n>=t.length)return null;n++,r.push(o)}else{const o=n;for(;n<t.length&&$(t[n]);)n++;if(n===o)return null;r.push(t.slice(o,n))}for(;n<t.length&&p(t[n]);)n++;if(n>=t.length)return r;if(t[n]!==".")return null;n++}}export function sectionHeaderKey(t){const r=t.trim();if(!r.startsWith("["))return null;const n=r.startsWith("[[");let e=n?2:1,o="",l=!1;for(;e<r.length;){const s=r[e];if(s==='"'||s==="'"){const c=s;for(o+=c,e++;e<r.length;){if(c==='"'&&r[e]==="\\"){if(e+1>=r.length)return null;o+=r[e]+r[e+1],e+=2;continue}if(r[e]===c)break;o+=r[e],e++}if(e>=r.length)return null;o+=c,e++;continue}if(s==="]"){if(n){if(r[e+1]!=="]")return null;e+=2}else e++;l=!0;break}o+=s,e++}if(!l)return null;const u=r.slice(e).trim();return u!==""&&!u.startsWith("#")?null:parseDottedKey(o)}export function renderTomlKey(t){return/^[A-Za-z0-9_-]+$/.test(t)?t:`"${d(t)}"`}export function renderTomlHeader(t){return`[${t.map(renderTomlKey).join(".")}]`}function d(t){let r="";for(const n of t)n==="\\"?r+="\\\\":n==='"'?r+='\\"':n===`
|
|
3
|
+
`?r+="\\n":n==="\r"?r+="\\r":n===" "?r+="\\t":n<" "||n==="\x7F"?r+=`\\u${n.charCodeAt(0).toString(16).padStart(4,"0")}`:r+=n;return r}export function renderTomlString(t){const r=t.includes("\\"),n=!t.includes("'")&&!/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f\n]/.test(t);return r&&n?`'${t}'`:`"${d(t)}"`}export function splitTomlSections(t){const r=t.split(`
|
|
4
|
+
`),n=[];let e={key:null,lines:[]};for(const o of r){const l=sectionHeaderKey(o);l!==null?(n.push(e),e={key:l,lines:[o]}):e.lines.push(o)}return n.push(e),n}export function sameKey(t,r){return t!==null&&t.length===r.length&&t.every((n,e)=>n===r[e])}function g(t,r){return t!==null&&t.length>r.length&&r.every((n,e)=>t[e]===n)}function y(t){let r=0;for(let n=t.length-1;n>=0&&t[n].trim()==="";n--)r++;return r}function x(t){const r=t.replace(/(?:\r?\n)+[ \t]*$/,"");return r===""?"":`${r}
|
|
5
|
+
`}function b(t,r){const n=t.replace(/(?:\r?\n)+[ \t]*$/,"");return n.trim()===""?`${r.join(`
|
|
6
6
|
`)}
|
|
7
7
|
`:`${n}
|
|
8
8
|
|
|
9
|
-
${
|
|
9
|
+
${r.join(`
|
|
10
10
|
`)}
|
|
11
|
-
`}export function upsertTomlSection(
|
|
12
|
-
`))}export function removeTomlSection(
|
|
13
|
-
`)),removed:!0}}export function parseSectionEntries(
|
|
11
|
+
`}export function upsertTomlSection(t,r,n){const e=splitTomlSections(t);let o=-1,l=-1;const u=new Set;for(let i=0;i<e.length;i++){const h=e[i].key;sameKey(h,r)?(o<0&&(o=i),u.add(i),l=i):g(h,r)&&(u.add(i),l=i)}if(o<0)return b(t,[renderTomlHeader(r),...n]);const s=e[l].lines,c=s.slice(s.length-y(s)),m=[renderTomlHeader(r),...n,...c],f=[];for(let i=0;i<e.length;i++)i===o&&f.push(...m),!u.has(i)&&f.push(...e[i].lines);return x(f.join(`
|
|
12
|
+
`))}export function removeTomlSection(t,r){const n=splitTomlSections(t),e=new Set;for(let l=0;l<n.length;l++){const u=n[l].key;(sameKey(u,r)||g(u,r))&&e.add(l)}if(e.size===0)return{text:t,removed:!1};const o=[];for(let l=0;l<n.length;l++)e.has(l)||o.push(...n[l].lines);return{text:x(o.join(`
|
|
13
|
+
`)),removed:!0}}export function parseSectionEntries(t){const r=[];for(const n of t){const e=n.trim();if(e===""||e.startsWith("#")||e.startsWith("["))continue;const o=/^("[^"]*"|'[^']*'|[A-Za-z0-9_-]+)\s*=/.exec(e);if(!o)continue;const l=parseDottedKey(o[1]);l===null||l.length!==1||r.push([l[0],n])}return r}export function upsertCodexPluginEnabledInText(t,r,n){const e=["plugins",r],o=splitTomlSections(t).find(u=>sameKey(u.key,e)),l=[`enabled = ${n?"true":"false"}`];if(o)for(const[u,s]of parseSectionEntries(o.lines.slice(1)))u!=="enabled"&&l.push(s);return upsertTomlSection(t,e,l)}
|
|
@@ -7,7 +7,7 @@ import type { FileAssetCategory } from './shared/file-specs.js';
|
|
|
7
7
|
* 依赖硬约束:本包仅依赖 @weavecode/core(永不依赖 server/cli,防 statusline/i18n 成环)。
|
|
8
8
|
*/
|
|
9
9
|
/** 可插拔能力槽——driver 声明持有哪些,注册表按能力检索。 */
|
|
10
|
-
export type HarnessCapability = 'init' | 'events' | 'assets' | 'resume' | 'detect' | 'plugins' | 'pluginState' | 'messaging' | 'questions' | 'capture';
|
|
10
|
+
export type HarnessCapability = 'init' | 'events' | 'assets' | 'resume' | 'detect' | 'plugins' | 'pluginState' | 'messaging' | 'questions' | 'capture' | 'statusline';
|
|
11
11
|
/**
|
|
12
12
|
* 采集集成的 user 档状态(tool-object-model §2.6 基石)。
|
|
13
13
|
*/
|
|
@@ -90,6 +90,17 @@ export interface EventSource {
|
|
|
90
90
|
* server 保留原函数名作薄委托——`fileAssetTargetDir` / `skillsDirFor` /
|
|
91
91
|
* `classifyAgent` / `shouldIgnore` / global-config skills 常量 / codex-toml 路径。
|
|
92
92
|
*/
|
|
93
|
+
/**
|
|
94
|
+
* 一条 MCP 服务器的通用形(各 harness 的落盘表示法不同:claude 是 JSON 的
|
|
95
|
+
* `mcpServers[name]`,codex 是 TOML 的 `[mcp_servers.<name>]`——表示法归实现方)。
|
|
96
|
+
* 类型住这里而非 server:它出现在 [[AssetSurface]] 的方法签名上,server 反向
|
|
97
|
+
* import 会绕回来。
|
|
98
|
+
*/
|
|
99
|
+
export interface McpServerConfig {
|
|
100
|
+
command: string;
|
|
101
|
+
args?: string[];
|
|
102
|
+
env?: Record<string, string>;
|
|
103
|
+
}
|
|
93
104
|
export interface AssetSurface {
|
|
94
105
|
/** 所属 harness——按序遍历多个 surface 时回指归属(`classifyAgent` 消费)。 */
|
|
95
106
|
readonly harness: Harness;
|
|
@@ -115,6 +126,15 @@ export interface AssetSurface {
|
|
|
115
126
|
* 的 MCP 面 → undefined。web 按行渲染提示,不自拼 harness 路径。
|
|
116
127
|
*/
|
|
117
128
|
mcpDest(scope: 'project' | 'user', homedir: string): string | undefined;
|
|
129
|
+
/**
|
|
130
|
+
* 读某 scope 的 MCP 服务器映射(该 harness 无此 scope / 文件缺失 → 空对象)。
|
|
131
|
+
* 表示法归实现方:调用方只认名字与 `McpServerConfig`,不碰文件。
|
|
132
|
+
*/
|
|
133
|
+
mcpRead(scope: 'project' | 'user', projectPath: string, homedir: string): Promise<Record<string, McpServerConfig>>;
|
|
134
|
+
/** 写/覆盖一条(scope 必须在 `mcpScopes()` 内,否则抛)。 */
|
|
135
|
+
mcpWrite(scope: 'project' | 'user', projectPath: string, homedir: string, name: string, config: McpServerConfig): Promise<void>;
|
|
136
|
+
/** 删一条;返回是否真删掉了(false → 调用方给 404)。 */
|
|
137
|
+
mcpRemove(scope: 'project' | 'user', projectPath: string, homedir: string, name: string): Promise<boolean>;
|
|
118
138
|
/**
|
|
119
139
|
* 宿主插件缓存根(Claude `~/.claude/plugins/cache`;Codex `~/.codex/plugins/cache`);
|
|
120
140
|
* 无插件机制的 harness 返回 undefined。全局技能枚举与「某路径归属谁」消费。
|
|
@@ -153,7 +173,7 @@ export interface ResumeCommandSpec {
|
|
|
153
173
|
openArgs?(sessionId: string): string[];
|
|
154
174
|
}
|
|
155
175
|
/** 消息通道名——支持矩阵与原因文案的键。 */
|
|
156
|
-
export type MessagingChannel = 'discovery' | 'prompt' | 'inject' | 'headless' | 'watch';
|
|
176
|
+
export type MessagingChannel = 'discovery' | 'prompt' | 'inject' | 'headless' | 'watch' | 'sideQuestion';
|
|
157
177
|
/** 非抢占注入通道规格:注入可骑乘的事件(hook-handler 在这些事件上消化 outbox 行)。 */
|
|
158
178
|
export interface InjectChannelSpec {
|
|
159
179
|
rideEvents: readonly string[];
|
|
@@ -201,6 +221,30 @@ export interface ImageAttachSpec {
|
|
|
201
221
|
name: string;
|
|
202
222
|
}[]): string;
|
|
203
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* 旁路会话(宿主 TUI 里的侧问,claude = `/btw`)规格:问一次不打断主回合的
|
|
226
|
+
* 轻量提问。**宿主既不留转录也不发 prompt 事件**(claude 侧问查询 `skipTranscript`),
|
|
227
|
+
* 问题与回答都不落任何文件——所以「谁发的谁记」:weave 打出去的提问自己记,
|
|
228
|
+
* 回答按这里给的判据从采集事件里认领。null = 该 harness 没有这种机制。
|
|
229
|
+
*/
|
|
230
|
+
export interface SideQuestionSpec {
|
|
231
|
+
/** 提问命令(命令文法归 harness,server 只传用户原文)。 */
|
|
232
|
+
command(question: string): string;
|
|
233
|
+
/** 形态校验:单行、无控制字符(CR 会提前提交)、长度上限。 */
|
|
234
|
+
validate(question: string): {
|
|
235
|
+
ok: true;
|
|
236
|
+
text: string;
|
|
237
|
+
} | {
|
|
238
|
+
ok: false;
|
|
239
|
+
error: string;
|
|
240
|
+
};
|
|
241
|
+
/**
|
|
242
|
+
* 这条采集事件是不是一次旁路回答;是就返回全文,否则 null。
|
|
243
|
+
* 判据归 harness(claude:`SubagentStop` 且宿主没给这个 agent 留转录——
|
|
244
|
+
* 普通子 agent 与 skill 子 agent 都有转录,skipTranscript 的 fork 才没有)。
|
|
245
|
+
*/
|
|
246
|
+
answerOf(eventType: string, payload: unknown): string | null;
|
|
247
|
+
}
|
|
204
248
|
/** 信封渲染入参。 */
|
|
205
249
|
export interface MessageMeta {
|
|
206
250
|
/** 发起方展示名(dashboard / 会话标题 / cli)。 */
|
|
@@ -246,12 +290,37 @@ export interface BlockingQuestion {
|
|
|
246
290
|
* 自定义文本走 `n` 备注行。选项文案与描述在宿主这一形态下**不渲染**(右栏取而代之)。 */
|
|
247
291
|
previewMode?: boolean;
|
|
248
292
|
}
|
|
293
|
+
/** 一次工具调用带的计划内容(正文 / 计划文件路径,两样都可能缺)。 */
|
|
294
|
+
export interface PlanDraft {
|
|
295
|
+
/** 正文(模型直接给的,或写计划文件那次调用带的 content)。 */
|
|
296
|
+
text: string | null;
|
|
297
|
+
/** 计划文件路径:正文不在事件里时由 server 现读(批准后宿主可能已删)。 */
|
|
298
|
+
filePath: string | null;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* 计划模式面:ExitPlanMode 交出的「待批阅的计划」。正文两条来源——老模型塞在
|
|
302
|
+
* `tool_input.plan` 里;2.1.296 起 tool_input 恒空,宿主改成让模型先把计划写进
|
|
303
|
+
* 计划文件(路径随计划模式提醒下发,宿主自己不留副本),故正文也可能只在那次
|
|
304
|
+
* Write/Edit 的 content 里。dashboard 拿它当一条对话气泡摆出来给人批阅。
|
|
305
|
+
*/
|
|
306
|
+
export interface PlanSpec {
|
|
307
|
+
/** 提交计划待批阅的工具名。 */
|
|
308
|
+
readonly tool: string;
|
|
309
|
+
/** 写计划文件用的工具名(正文在这类调用的 content 里)。 */
|
|
310
|
+
readonly writeTools: readonly string[];
|
|
311
|
+
/** 计划文件路径里必有的一段:择行用(把整轮 Write 都捞回来太重)。 */
|
|
312
|
+
readonly fileHint: string;
|
|
313
|
+
/** 这次工具调用带的计划内容;与计划无关返回 null。 */
|
|
314
|
+
draftOf(toolName: string | null, toolInput: unknown, toolResponse: unknown): PlanDraft | null;
|
|
315
|
+
}
|
|
249
316
|
/**
|
|
250
317
|
* 阻塞式交互面(会话卡住等输入:AskUserQuestion / 计划确认 / 权限确认):
|
|
251
318
|
* 哪些工具会挂起、权限通知类型、问题面归一化与作答键序全归 harness——
|
|
252
319
|
* server 只做状态机与终端传输,web 只渲染不拼键序。
|
|
253
320
|
*/
|
|
254
321
|
export interface BlockingPromptSpec {
|
|
322
|
+
/** 计划模式规格;null = 该 harness 没有计划概念(不摆计划气泡)。 */
|
|
323
|
+
readonly plan: PlanSpec | null;
|
|
255
324
|
/** 阻塞工具名:PreToolUse 置位、PostToolUse 同名清除。 */
|
|
256
325
|
readonly blockingTools: readonly string[];
|
|
257
326
|
/** 权限确认的 Notification 类型(raw.notification_type);null = 无此机制。 */
|
|
@@ -326,6 +395,8 @@ export interface MessagingSurface {
|
|
|
326
395
|
renderEnvelope?(text: string, meta: MessageMeta): string;
|
|
327
396
|
/** 图片随 prompt 的对齐面;null = 该 harness 不支持收图(web 据此置灰附件钮)。 */
|
|
328
397
|
readonly imageAttach: ImageAttachSpec | null;
|
|
398
|
+
/** 旁路会话(侧问);null = 该 harness 没有这种机制(web 据此不渲染入口)。 */
|
|
399
|
+
readonly sideQuestion: SideQuestionSpec | null;
|
|
329
400
|
/** 不支持通道的语义原因(409 文案与 UI tooltip 直用)。 */
|
|
330
401
|
readonly unsupportedReasons?: Partial<Record<MessagingChannel, string>>;
|
|
331
402
|
}
|
|
@@ -434,6 +505,42 @@ export interface PluginSurface {
|
|
|
434
505
|
* 其余键保留,文件可创建)。 */
|
|
435
506
|
setEnabledOverride(projectPath: string, scope: PluginScope, key: string, state: EnableOverride): Promise<void>;
|
|
436
507
|
}
|
|
508
|
+
/** 生成状态栏脚本的运行参数——两样都是调用方(server)的事实:缓存落点归
|
|
509
|
+
* dataDir 布局,版本号归包身份;harness 不自取。 */
|
|
510
|
+
export interface StatuslineGenerateContext {
|
|
511
|
+
cacheDir: string;
|
|
512
|
+
version: string;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* 状态栏面:宿主能不能被注入自定义状态栏、能填哪些块、脚本落在哪、怎么接线。
|
|
516
|
+
*
|
|
517
|
+
* 「哪几块」是 harness 知识(claude 的块来自它 statusline stdin JSON 的字段),
|
|
518
|
+
* 故词表与渲染器都归各 harness 的实现;server 只做持久化与装配、web 只渲染
|
|
519
|
+
* 能力表给出来的块。`tui: 'none'` 的 harness 不是「没做」,而是宿主结构上没有
|
|
520
|
+
* 这个面(如 codex 的 `tui.status_line` 只能选内置条目、不接受 shell 命令)。
|
|
521
|
+
*/
|
|
522
|
+
export interface StatuslineSurface {
|
|
523
|
+
/** 该 harness 的状态栏能填哪些块(key 由 harness 定义,web 只认这串)。 */
|
|
524
|
+
readonly segments: readonly string[];
|
|
525
|
+
/** TUI 通道:`injectable` = 能注入宿主 TUI;`none` = 宿主没有这个面。 */
|
|
526
|
+
readonly tui: 'injectable' | 'none';
|
|
527
|
+
/** 脚本相对项目根的落点(posix,供 init 漂移检测比对面)。 */
|
|
528
|
+
readonly scriptRelPath: string;
|
|
529
|
+
/** 生成宿主运行的渲染脚本(配置形状归 harness,槽位不做假设)。 */
|
|
530
|
+
generate(config: unknown, ctx: StatuslineGenerateContext): string;
|
|
531
|
+
/** 把宿主指针接到脚本上(claude = `.claude/settings.json` 的 `statusLine` 键)。 */
|
|
532
|
+
wire(projectPath: string, opts: {
|
|
533
|
+
scriptPath: string;
|
|
534
|
+
refreshInterval: number;
|
|
535
|
+
}): Promise<void>;
|
|
536
|
+
/**
|
|
537
|
+
* 渲染脚本已经算好、留在缓存里的块事实(key = segment key,值 = token 表)——
|
|
538
|
+
* dashboard 侧要摆同样的块就从这儿取,不自算第二份。没有缓存即 null。
|
|
539
|
+
*/
|
|
540
|
+
facts?(cacheDir: string, cwd: string): StatuslineFacts | null;
|
|
541
|
+
}
|
|
542
|
+
/** 缓存里的块事实:与 `buildPreviewItems` 吃的 token 表同形。 */
|
|
543
|
+
export type StatuslineFacts = Record<string, Record<string, string>>;
|
|
437
544
|
/** 单个 harness 的驱动:id/displayName 必填,能力槽按批次补齐。 */
|
|
438
545
|
export interface HarnessDriver {
|
|
439
546
|
id: Harness;
|
|
@@ -449,6 +556,7 @@ export interface HarnessDriver {
|
|
|
449
556
|
messaging?: MessagingSurface;
|
|
450
557
|
questions?: BlockingPromptSpec;
|
|
451
558
|
capture?: CaptureSurface;
|
|
559
|
+
statusline?: StatuslineSurface;
|
|
452
560
|
}
|
|
453
561
|
/**
|
|
454
562
|
* 能力槽注册表:先到先得(同 id 重复注册抛错,对齐插件先加载者胜);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export class HarnessRegistry{drivers=new Map;register(
|
|
1
|
+
export class HarnessRegistry{drivers=new Map;register(r){if(this.drivers.has(r.id))throw new Error(`harness driver already registered: ${r.id}`);this.drivers.set(r.id,r);let i=!1;return()=>{i||(i=!0,this.drivers.get(r.id)===r&&this.drivers.delete(r.id))}}get(r){return this.drivers.get(r)}all(){return[...this.drivers.values()]}byCapability(r){return this.all().filter(i=>i.capabilities.includes(r))}initFor(r){return this.drivers.get(r)?.init}unregister(r){return this.drivers.delete(r)}}export function supports(e,r){return e.capabilities.includes(r)}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
`}function
|
|
1
|
+
import l from"node:path";import{generateHookHandler as i,readUserCapture as c}from"../claude/capture.js";import{generateAutoMemoryHook as u}from"../claude/helpers-gen.js";import{generateMcpJson as m,mergeMcpJson as h}from"../claude/mcp-gen.js";import{generateSettingsJson as f,mergeSettingsJson as g}from"../claude/settings-gen.js";export const WEAVE_CONTENT_MARKER="@version weave@";const d={preToolUse:!1,postToolUse:!1,userPromptSubmit:!1,sessionStart:!1,stop:!1,stopFailure:!1,subagentStop:!1,subagentStart:!1,notification:!1,postToolUseFailure:!1,permissionRequest:!1,permissionDenied:!1,preCompact:!1,sessionEnd:!1,preModelSwitch:!1,timeout:5e3,continueOnError:!0};function a(e){try{const o=JSON.parse(e);return typeof o=="object"&&o!==null&&!Array.isArray(o)?o:null}catch{return null}}function n(e){return JSON.stringify(e,null,2)+`
|
|
2
|
+
`}function p(e){return(o,r)=>{const t=a(o),s=a(r);return t===null||s===null?null:n(e(t,s))}}async function S(e){const o=l.join(e.projectPath,".claude","helpers"),r=(await c({home:e.platform.homeDir})).installed?d:e.hooks,t=[];return e.components.helpers&&t.push({relPath:".claude/helpers/hook-handler.cjs",weaveMarker:WEAVE_CONTENT_MARKER,content:i(e.version)},{relPath:".claude/helpers/auto-memory-hook.mjs",weaveMarker:WEAVE_CONTENT_MARKER,content:u(e.version)}),e.components.settings&&t.push({relPath:".claude/settings.json",content:n(f({components:e.components,hooks:r,platform:e.platform,helpersDir:o})),merge:p(g)}),e.components.mcp&&e.mcp.weave&&t.push({relPath:".mcp.json",content:n(m({platform:e.platform,includeWeaveServer:!0})),merge:p(h)}),t}const v={claude:S,codex:async()=>[]};export function generateInitFiles(e,o){return v[e](o)}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{readdir as
|
|
1
|
+
import{readdir as h,readFile as p,unlink as g,writeFile as A}from"node:fs/promises";import r from"node:path";import{ensureDir as m,fileExists as S,writeFileIfAbsent as b}from"@weavecode/core";export class InitPipeline{ctx;skipped=[];skipReasons=new Map;constructor(t){this.ctx=t}async runSurface(){await this.ensureDirs(),await this.writeSettings(),await this.writeMcp(),await this.copySkills(),await this.copyCommands(),await this.copyAgents(),await this.injectPluginTemplates(),await this.writeHelpers()}injectPluginTemplates(){}skip(t,i){this.skipped.push(t),this.skipReasons.set(t,i)}async writeOrMergeJson(t,i,n){if(!n&&await S(t)){const s=await D(t);return s===void 0?!1:(await j(t,d(s,i)),!0)}return await j(t,i),!0}async copyDirIfAbsent(t,i,n=!1){let s;try{s=await h(t,{withFileTypes:!0})}catch{return}await m(i);for(const e of s){const o=r.join(t,e.name),c=r.join(i,e.name);if(e.isDirectory())await this.copyDirIfAbsent(o,c,n);else{const u=await p(o,"utf-8");await b(c,u,n)}}}async sweepMarked(t,i,n){const s=new Set(i),e=[],o=async c=>{let u;try{u=await h(c,{withFileTypes:!0})}catch{return}for(const f of u){const w=r.join(c,f.name);if(f.isDirectory()){await o(w);continue}const k=r.relative(t,w).split(r.sep).join("/");if(s.has(k))continue;const y=await p(w,"utf-8").catch(()=>null);y!==null&&y.includes(n)&&(await g(w),e.push(w))}};return await o(t),e}}function d(a,t){const i={...a};for(const[n,s]of Object.entries(t)){const e=i[n];i[n]=l(e)&&l(s)?d(e,s):s}return i}function l(a){return typeof a=="object"&&a!==null&&!Array.isArray(a)}async function D(a){try{const t=await p(a,"utf-8"),i=JSON.parse(t);return l(i)?i:void 0}catch{return}}async function j(a,t){await m(r.dirname(a)),await A(a,JSON.stringify(t,null,2)+`
|
|
2
2
|
`,"utf-8")}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{CLAUDE_DRIVER as t}from"./claude/index.js";import{CODEX_DRIVER as o}from"./codex/index.js";import{HarnessRegistry as
|
|
1
|
+
import{CLAUDE_DRIVER as t}from"./claude/index.js";import{CODEX_DRIVER as o}from"./codex/index.js";import{HarnessRegistry as s}from"./driver.js";export const HARNESS_DRIVERS={claude:t,codex:o};export function registerRuntimeDrivers(r){for(const e of Object.values(HARNESS_DRIVERS))r.register(e)}export function createRuntimeRegistry(){const r=new s;return registerRuntimeDrivers(r),r}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{cp as
|
|
1
|
+
import{cp as c,lstat as e,mkdir as s,rm as l,symlink as m,unlink as u}from"node:fs/promises";import o from"node:path";export async function linkOrCopy(r,t){const n=o.resolve(r);await s(o.dirname(t),{recursive:!0});try{return await m(n,t,process.platform==="win32"?"junction":"dir"),"link"}catch(a){const i=a.code;if(i!=="EPERM"&&i!=="EEXIST"&&i!=="ENOTSUP")throw a}return await c(n,t,{recursive:!0}),"copy"}export async function removeInstalled(r){let t;try{t=await e(r)}catch{return"absent"}return t.isSymbolicLink()?(await u(r),"link"):(await l(r,{recursive:!0,force:!0}),"removed")}export async function installForm(r){try{return(await e(r)).isSymbolicLink()?"link":"copy"}catch{return"absent"}}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AssetSurface } from '../driver.js';
|
|
2
|
+
/**
|
|
3
|
+
* ZCode 资产表面(skills + 两档 MCP)——`skillRootsForBase` 按级别给两根:
|
|
4
|
+
* `.zcode/skills`(ZCode 原生)与 `.agents/skills`(agents 兼容根,与 codex 共用)。
|
|
5
|
+
* 单文件资产面(commands/agents/…)ZCode 都没有,`FILE_ASSET_SPECS` 里也就没有
|
|
6
|
+
* 它的行,`targetDir` 一律抛错。
|
|
7
|
+
*/
|
|
8
|
+
export declare const ZCODE_ASSETS: AssetSurface;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import c from"node:path";import{readZcodeMcp as l,removeZcodeMcp as n,upsertZcodeMcp as d,zcodeMcpFile as r}from"./mcp.js";const p=o=>c.join(o,".zcode","cli","config.json");export const ZCODE_ASSETS={harness:"zcode",targetDir(o){throw new Error(`"${o}" has no ZCode file-asset surface`)},projectSkillsDir:()=>".zcode/skills",globalSkillsRoots:o=>[c.join(o,...".zcode/skills".split("/")),c.join(o,...".agents/skills".split("/"))],userConfigFile:o=>p(o),mcpScopes:()=>["project","user"],mcpDest:(o,s)=>o==="project"?".zcode/config.json":c.join(s,...".zcode/cli/config.json".split("/")),mcpRead:(o,s,e)=>l(r(o,s,e)),mcpWrite:(o,s,e,i,t)=>d(r(o,s,e),i,t),mcpRemove:(o,s,e,i)=>n(r(o,s,e),i),classify(o){return o===".zcode"||o.startsWith(".zcode/")?!0:o.slice(o.lastIndexOf("/")+1)==="AGENTS.md"},ignore(o){return!(o===".zcode"||o.startsWith(".zcode/")||o==="AGENTS.md")}};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { CaptureDeps, CaptureScriptHealth, CaptureState, CaptureSurface } from '../driver.js';
|
|
2
|
+
/**
|
|
3
|
+
* ZCode 采集面:**入口只能写用户级**。它的项目级 hooks 要过工作区信任,而信任
|
|
4
|
+
* 开关只有 protocol server 传 true(CLI/TUI 路径不传)⇒ 项目 `.zcode/config.json`
|
|
5
|
+
* 里的 hooks 在 TUI 里恒被拒。故 weave 的一条 hook 写进 `~/.zcode/cli/config.json`,
|
|
6
|
+
* 指到一份**全局脚本**;脚本自己按 `CLAUDE_PROJECT_DIR` 认项目、读该项目的
|
|
7
|
+
* `.weave/token` 算 shard——不是 weave 项目就什么都不写(与 claude 同一份脚本逻辑)。
|
|
8
|
+
*/
|
|
9
|
+
/** `~/.zcode/cli/config.json`(ZCode 的 DEFAULT_BASE_DIR + DEFAULT_CONFIG_FILE)。 */
|
|
10
|
+
export declare const zcodeConfigFile: (home: string) => string;
|
|
11
|
+
/** 全局脚本落点:`<configDir>/weave/hooks/zcode/hook-handler.cjs`(= `<dataDir>/hooks/zcode/`)。 */
|
|
12
|
+
export declare function zcodeHookScript(configDir?: string): string;
|
|
13
|
+
/** 一组 hook 是 weave 的:它的进程要么是那条脚本、要么命令行里写着那个路径。 */
|
|
14
|
+
export declare function groupIsWeave(group: unknown): boolean;
|
|
15
|
+
/** 单事件的 weave hook 组(`type: 'process'` 直起 node,无 shell 转义)。 */
|
|
16
|
+
export declare function captureHookGroup(script: string): Array<Record<string, unknown>>;
|
|
17
|
+
export declare function readUserCapture(deps?: CaptureDeps): Promise<CaptureState>;
|
|
18
|
+
/**
|
|
19
|
+
* 生效采集脚本的健康(诊断面只读):zcode 只有用户级这一支,没有项目档可回落。
|
|
20
|
+
* `reportsInbox` 恒 false——ZCode 没有会话本地 inbox socket 这回事。
|
|
21
|
+
*/
|
|
22
|
+
export declare function readScriptHealth(deps?: CaptureDeps): Promise<CaptureScriptHealth>;
|
|
23
|
+
/**
|
|
24
|
+
* 用户级采集安装(幂等):全局脚本 + `~/.zcode/cli/config.json` 的 hooks 组。
|
|
25
|
+
* `hooks.enabled` 缺省 false(不写就完全不跑),故只在**键缺席**时写 true——
|
|
26
|
+
* 用户显式关过的不覆盖。
|
|
27
|
+
*/
|
|
28
|
+
export declare function installUserCapture(deps: CaptureDeps & {
|
|
29
|
+
version: string;
|
|
30
|
+
}): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* 用户级采集停用(幂等):摘配置里的 weave 组 + 删脚本(带 weave 标记才删)。
|
|
33
|
+
* 不动 `hooks.enabled`——用户自己的 hook 还要靠它。
|
|
34
|
+
*/
|
|
35
|
+
export declare function uninstallUserCapture(deps?: CaptureDeps): Promise<void>;
|
|
36
|
+
export declare const ZCODE_CAPTURE: CaptureSurface;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{access as k,mkdir as y,readFile as l,unlink as A,writeFile as f}from"node:fs/promises";import{homedir as i}from"node:os";import c from"node:path";import{detectPlatform as S,HARNESS_EVENTS as b}from"@weavecode/core";import{generateHookHandler as j}from"../claude/capture.js";export const zcodeConfigFile=e=>c.join(e,".zcode","cli","config.json");export function zcodeHookScript(e=S().configDir){return c.join(e,"weave","hooks","zcode","hook-handler.cjs")}const w="@version weave@",g="weave/hooks/zcode/hook-handler.cjs";function a(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function p(e){return e.replace(/\\/g,"/")}async function x(e){try{return await k(e),!0}catch{return!1}}async function d(e){let r;try{r=await l(e,"utf-8")}catch{return{}}let t;try{t=JSON.parse(r)}catch{throw new Error(`user config is not parseable JSON: ${e}`)}if(!a(t))throw new Error(`user config is not a JSON object: ${e}`);return t}export function groupIsWeave(e){if(!a(e))return!1;const r=e.hooks;return Array.isArray(r)?r.some(t=>{if(!a(t))return!1;const o=Array.isArray(t.args)?t.args.map(n=>p(String(n))):[];return(typeof t.command=="string"?p(t.command):"").includes(g)||o.some(n=>n.includes(g))}):!1}export function captureHookGroup(e){return[{hooks:[{type:"process",command:"node",args:[p(e)]}]}]}function v(e){if(!a(e))return{};const r={};for(const[t,o]of Object.entries(e)){if(!Array.isArray(o)){r[t]=o;continue}const n=o.filter(s=>!groupIsWeave(s));n.length>0&&(r[t]=n)}return r}function C(e){if(!a(e))return!1;const r=e.hooks;if(!a(r))return!1;const t=r.events;return a(t)?Object.values(t).some(o=>Array.isArray(o)&&o.some(groupIsWeave)):!1}export async function readUserCapture(e={}){const r=e.home??i(),t=await d(zcodeConfigFile(r)).catch(()=>({}));return{installed:C(t),helperPresent:await x(zcodeHookScript(e.configDir))}}export async function readScriptHealth(e={}){const r=e.home??i(),t=(await readUserCapture({home:r,configDir:e.configDir})).installed,o=zcodeHookScript(e.configDir);let n=null;try{n=await l(o,"utf-8")}catch{n=null}return{source:t?"user":"none",present:n!==null,weaveOwned:n!==null&&n.includes(w),generatedVersion:n?.match(/@version weave@(\S+)/)?.[1]??null,reportsInbox:!1,reportsPaneEnv:n!==null&&n.includes("terminalEnv()")}}export async function installUserCapture(e){const r=e.home??i(),t=zcodeHookScript(e.configDir);await y(c.dirname(t),{recursive:!0}),await f(t,j(e.version,"zcode"),"utf-8");const o=zcodeConfigFile(r),n=await d(o),s=a(n.hooks)?n.hooks:{};typeof s.enabled!="boolean"&&(s.enabled=!0),typeof s.timeoutMs!="number"&&(s.timeoutMs=5e3);const u=v(s.events);for(const h of b.zcode){const m=u[h];u[h]=Array.isArray(m)?[...m,...captureHookGroup(t)]:captureHookGroup(t)}s.events=u,n.hooks=s,await y(c.dirname(o),{recursive:!0}),await f(o,JSON.stringify(n,null,2)+`
|
|
2
|
+
`,"utf-8")}export async function uninstallUserCapture(e={}){const r=e.home??i(),t=zcodeConfigFile(r);try{const o=await d(t),n=o.hooks;if(a(n)){const s=v(n.events);Object.keys(s).length>0?n.events=s:delete n.events,o.hooks=n,await f(t,JSON.stringify(o,null,2)+`
|
|
3
|
+
`,"utf-8")}}catch{}try{const o=zcodeHookScript(e.configDir);(await l(o,"utf-8")).includes(w)&&await A(o)}catch{}}export const ZCODE_CAPTURE={harness:"zcode",readUserCapture:e=>readUserCapture(e),installUserCapture:e=>installUserCapture(e),uninstallUserCapture:e=>uninstallUserCapture(e),stripProjectCapture:async()=>{},scriptHealth:e=>readScriptHealth(e)};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{existsSync as s}from"node:fs";import n from"node:path";const o=[".zcode"];function t(e){return o.some(r=>s(n.join(e,r)))}export const ZCODE_DETECTOR={markers:o,present:t,detect:e=>({harness:"zcode",present:t(e)})};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ClaudeEventSource } from '../claude/event-source.js';
|
|
2
|
+
/**
|
|
3
|
+
* ZCode 事件接入:它的 hook stdin 是**Claude 兼容形**——`createCompatibleHookStdin`
|
|
4
|
+
* 在 ZCode 自己的 camelCase 主契约上补了 snake_case alias(`hook_event_name` /
|
|
5
|
+
* `session_id` / `tool_name` / `tool_input` / `stop_hook_active` …),故归一化与
|
|
6
|
+
* claude 同一份实现,只有归属 harness 不同。
|
|
7
|
+
*/
|
|
8
|
+
export declare const ZCODE_EVENT_SOURCE: ClaudeEventSource;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ClaudeEventSource as e}from"../claude/event-source.js";export const ZCODE_EVENT_SOURCE=new e("zcode");
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { HarnessDriver } from '../driver.js';
|
|
2
|
+
export { ZCODE_ASSETS } from './assets.js';
|
|
3
|
+
export { ZCODE_CAPTURE, zcodeConfigFile, zcodeHookScript } from './capture.js';
|
|
4
|
+
export { ZCODE_DETECTOR } from './detect.js';
|
|
5
|
+
export { ZCODE_EVENT_SOURCE } from './event-source.js';
|
|
6
|
+
export { ZCODE_MESSAGING } from './messaging.js';
|
|
7
|
+
export { ZCODE_RESUME } from './resume.js';
|
|
8
|
+
/**
|
|
9
|
+
* ZCode 接入模块的驱动(P0:只读看板 + 采集):assets / events / resume /
|
|
10
|
+
* detect / messaging / capture 已就位,plugins / questions 留 P2——init 槽
|
|
11
|
+
* 不在此(由 cli init/wiring 携带)。
|
|
12
|
+
*/
|
|
13
|
+
export declare const ZCODE_DRIVER: HarnessDriver;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ZCODE_ASSETS as E}from"./assets.js";import{ZCODE_CAPTURE as o}from"./capture.js";import{ZCODE_DETECTOR as e}from"./detect.js";import{ZCODE_EVENT_SOURCE as r}from"./event-source.js";import{ZCODE_MESSAGING as t}from"./messaging.js";import{ZCODE_RESUME as m}from"./resume.js";export{ZCODE_ASSETS}from"./assets.js";export{ZCODE_CAPTURE,zcodeConfigFile,zcodeHookScript}from"./capture.js";export{ZCODE_DETECTOR}from"./detect.js";export{ZCODE_EVENT_SOURCE}from"./event-source.js";export{ZCODE_MESSAGING}from"./messaging.js";export{ZCODE_RESUME}from"./resume.js";export const ZCODE_DRIVER={id:"zcode",displayName:"ZCode",capabilities:["assets","events","resume","detect","messaging","capture"],assets:E,events:r,resume:m,detect:e,messaging:t,capture:o};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { McpServerConfig } from '../driver.js';
|
|
2
|
+
export declare function readZcodeMcp(file: string): Promise<Record<string, McpServerConfig>>;
|
|
3
|
+
export declare function upsertZcodeMcp(file: string, name: string, config: McpServerConfig): Promise<void>;
|
|
4
|
+
export declare function removeZcodeMcp(file: string, name: string): Promise<boolean>;
|
|
5
|
+
/** 某 scope 的 MCP 落点:项目级 `.zcode/config.json`;用户级 `~/.zcode/cli/config.json`。 */
|
|
6
|
+
export declare function zcodeMcpFile(scope: 'project' | 'user', projectPath: string, homedir: string): string;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{mkdir as m,readFile as p,writeFile as d}from"node:fs/promises";import a from"node:path";function i(r){return typeof r=="object"&&r!==null&&!Array.isArray(r)}async function s(r){let e;try{e=await p(r,"utf-8")}catch{return{}}let t;try{t=JSON.parse(e)}catch(n){throw new Error(`${r} is not valid JSON \u2014 refusing to write: ${n instanceof Error?n.message:String(n)}`)}if(!i(t))throw new Error(`${r} is not a JSON object \u2014 refusing to write`);return t}async function f(r,e){await m(a.dirname(r),{recursive:!0}),await d(r,`${JSON.stringify(e,null,2)}
|
|
2
|
+
`,"utf-8")}function u(r){const e=r.mcp;return i(e)&&i(e.servers)?e.servers:{}}export async function readZcodeMcp(r){const e=u(await s(r)),t={};for(const[n,o]of Object.entries(e)){if(!i(o)||typeof o.command!="string")continue;const c={command:o.command};Array.isArray(o.args)&&(c.args=o.args),i(o.env)&&(c.env=o.env),t[n]=c}return t}export async function upsertZcodeMcp(r,e,t){const n=await s(r),o=i(n.mcp)?n.mcp:{},c={type:"stdio",command:t.command};t.args&&(c.args=t.args),t.env&&(c.env=t.env),o.servers={...u(n),[e]:c},n.mcp=o,await f(r,n)}export async function removeZcodeMcp(r,e){const t=await s(r),n=u(t);if(!(e in n))return!1;delete n[e];const o=i(t.mcp)?t.mcp:{};return o.servers=n,t.mcp=o,await f(r,t),!0}export function zcodeMcpFile(r,e,t){return r==="project"?a.join(e,".zcode","config.json"):a.join(t,".zcode","cli","config.json")}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { MessagingSurface } from '../driver.js';
|
|
2
|
+
/**
|
|
3
|
+
* ZCode 消息能力面:投递全走既有通用机制,只在两条 claude 专有通道上声明 null。
|
|
4
|
+
*
|
|
5
|
+
* prompt **恒 null**:两层都不通——ZCode 同名的 `SendMessage` 只发给本会话的
|
|
6
|
+
* 子 agent(不是 peer),而层② 终端要的 pane 不存在:会话跑在 ZCode 桌面应用
|
|
7
|
+
* 里(`zcode-agent` 子进程 + 应用自己的渲染面),不是任何终端模拟器的 pane。
|
|
8
|
+
*
|
|
9
|
+
* inject 骑 `INJECTABLE_EVENTS.zcode`(HookSpecificOutput 支持 additionalContext),
|
|
10
|
+
* 走 weave 既有的 outbox 镜像;watch 靠 `Stop`。headless 未接:`-p` 是字符串选项、
|
|
11
|
+
* 不吃 stdin,且 shell 模式与 detached 的组合在 win32 上丢管道(见 CLAUDE.md)。
|
|
12
|
+
*/
|
|
13
|
+
export declare const ZCODE_MESSAGING: MessagingSurface;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{HARNESS_LIFECYCLE as e,INJECTABLE_EVENTS as s}from"@weavecode/core";export const ZCODE_MESSAGING={harness:"zcode",discovery:!0,prompt:null,promptInbox:null,inject:{rideEvents:s.zcode},headless:null,idleSignals:[...e.zcode.close],imageAttach:null,sideQuestion:null,unsupportedReasons:{prompt:"ZCode sessions run inside the ZCode desktop app, not in a terminal pane, so there is no channel to type a prompt into (its SendMessage only reaches sub-agents of the same session)",headless:"ZCode's -p takes the prompt on the command line and does not read stdin; headless delivery is not wired",sideQuestion:"ZCode has no side-chat (btw) mechanism"}};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ResumeCommandSpec } from '../driver.js';
|
|
2
|
+
/**
|
|
3
|
+
* ZCode resume 命令规格:`zcode --resume <sessionId>` 接回既有会话(会话行在
|
|
4
|
+
* SQLite 里,`--resume` 按 id 取)。`-p` 只吃命令行字符串、不从 stdin 读 prompt,
|
|
5
|
+
* 故 headless 投递不给 zcode 开(messaging.headless = null)——`args` 只为形态完整。
|
|
6
|
+
*/
|
|
7
|
+
export declare const ZCODE_RESUME: ResumeCommandSpec;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const ZCODE_RESUME={supported:!0,bin:"zcode",args:(e,r)=>["--resume",e,"-p",r],openArgs:e=>["--resume",e]};
|