pi-web-ui 0.64.5 → 0.64.6
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/README.md +2 -2
- package/dist/server/agent-service.js +95 -5
- package/dist/server/bg-servers.js +111 -26
- package/dist/server/client-state.js +2 -0
- package/dist/server/dsh/dsh-agent-service.js +2 -0
- package/dist/server/index.js +1 -0
- package/dist/server/process-utils.js +41 -0
- package/dist/server/protocol-version.js +1 -1
- package/dist/server/settings-service.js +33 -0
- package/dist/server/subagent-templates.js +14 -1
- package/dist/server/subagents.js +107 -11
- package/package.json +110 -110
- package/web/dist/assets/{TerminalPanel-7xM8bK8t.js → TerminalPanel-CoPFNu1d.js} +1 -1
- package/web/dist/assets/{abnfDiagram-VCTEODGH-dzrhTpxN.js → abnfDiagram-VCTEODGH-Dltz1N0G.js} +1 -1
- package/web/dist/assets/{arc-CvEtLzuM.js → arc-QOm2xRll.js} +1 -1
- package/web/dist/assets/{architectureDiagram-5GKGNRK7-1d4TEc2z.js → architectureDiagram-5GKGNRK7-L3XUBFbb.js} +1 -1
- package/web/dist/assets/{blockDiagram-I7D4REHJ-B8HBpC0d.js → blockDiagram-I7D4REHJ-CJmza4yx.js} +1 -1
- package/web/dist/assets/{c4Diagram-7LVT6UL2-CNGfPB3f.js → c4Diagram-7LVT6UL2-CwgA5WEW.js} +1 -1
- package/web/dist/assets/channel-VncP7yyT.js +1 -0
- package/web/dist/assets/{chunk-2Q5K7J3B-CSVK1bvg.js → chunk-2Q5K7J3B-DoqSiCVF.js} +1 -1
- package/web/dist/assets/{chunk-5VM5RSS4-BxIozqQs.js → chunk-5VM5RSS4-CO14GhQ1.js} +1 -1
- package/web/dist/assets/{chunk-F27PBJKO-QnkX6p93.js → chunk-F27PBJKO-kRFf9SDx.js} +1 -1
- package/web/dist/assets/{chunk-IMKFNOWR-kBTZpeLx.js → chunk-IMKFNOWR-Cm6JOqm0.js} +1 -1
- package/web/dist/assets/{chunk-JWPE2WC7-CcF10PqG.js → chunk-JWPE2WC7-DTpnGTdB.js} +1 -1
- package/web/dist/assets/{chunk-POPQ4Y6H-Ch9HWJm9.js → chunk-POPQ4Y6H-CdSt_7xq.js} +1 -1
- package/web/dist/assets/{chunk-SVP7TREG-D-6N0S8z.js → chunk-SVP7TREG-IQRTD_4U.js} +1 -1
- package/web/dist/assets/{chunk-TICWLB2K-CSDXk9NS.js → chunk-TICWLB2K-Duj1rt_5.js} +1 -1
- package/web/dist/assets/{chunk-XXDRQBXY-C7tgRoeO.js → chunk-XXDRQBXY-BFf3gcbL.js} +1 -1
- package/web/dist/assets/classDiagram-ZZMXUADV-BWCNDr-F.js +1 -0
- package/web/dist/assets/classDiagram-v2-VYDZK3BY-BWCNDr-F.js +1 -0
- package/web/dist/assets/{cose-bilkent-JH36ORCC-V45ICdWW.js → cose-bilkent-JH36ORCC-D5k0Z1dx.js} +1 -1
- package/web/dist/assets/{cynefin-OW5HDTMX-DkjrprMv.js → cynefin-OW5HDTMX-OsV-x0h-.js} +1 -1
- package/web/dist/assets/{cynefinDiagram-5FMLGOSQ-CSFzGNbH.js → cynefinDiagram-5FMLGOSQ-DM7XHm4s.js} +1 -1
- package/web/dist/assets/{dagre-GXQ25YYZ-B2tQ52ot.js → dagre-GXQ25YYZ-B0bIbgMh.js} +1 -1
- package/web/dist/assets/{diagram-S7CK7UJ4-CAeTly-S.js → diagram-S7CK7UJ4-lMVsMjfI.js} +1 -1
- package/web/dist/assets/{diagram-UQ7AKVKN-D6_khPwH.js → diagram-UQ7AKVKN-BJDbkaYf.js} +1 -1
- package/web/dist/assets/{diagram-VSXAHHWV-DDaGr2Z2.js → diagram-VSXAHHWV-1zUfVr-L.js} +1 -1
- package/web/dist/assets/{diagram-VX7I27RA-8nsSxNoG.js → diagram-VX7I27RA-B-Qy3dth.js} +1 -1
- package/web/dist/assets/{diagram-Z3DM3KII-CQFF2G65.js → diagram-Z3DM3KII-DbKcoZFP.js} +1 -1
- package/web/dist/assets/{ebnfDiagram-PWID7BFC-CmR6-1Mj.js → ebnfDiagram-PWID7BFC-CuMZBzDi.js} +1 -1
- package/web/dist/assets/{erDiagram-RLTQ6QDP-CCnQ4eXZ.js → erDiagram-RLTQ6QDP-Dkw_Uhg2.js} +1 -1
- package/web/dist/assets/{flowDiagram-HODETNUW-bpunOdNf.js → flowDiagram-HODETNUW-CwDYMy38.js} +1 -1
- package/web/dist/assets/{ganttDiagram-EL5Y4UJY-Do5WVm61.js → ganttDiagram-EL5Y4UJY-B2s3myqg.js} +1 -1
- package/web/dist/assets/{gitGraphDiagram-WWUBYQGX-DRBgLSBf.js → gitGraphDiagram-WWUBYQGX-CJ3rUTG5.js} +1 -1
- package/web/dist/assets/{index-D2iRpLNi.js → index-30RM921r.js} +19 -19
- package/web/dist/assets/index-B_lYcsGw.css +10 -0
- package/web/dist/assets/{infoDiagram-27XIBGKW-9xdIyGW9.js → infoDiagram-27XIBGKW-DuIoOHyL.js} +1 -1
- package/web/dist/assets/{ishikawaDiagram-5VMMS53U-C1HHSxnn.js → ishikawaDiagram-5VMMS53U-Fm14e_CH.js} +1 -1
- package/web/dist/assets/{journeyDiagram-3NMN7TZE-BTroj2Jo.js → journeyDiagram-3NMN7TZE-BuokOq_3.js} +1 -1
- package/web/dist/assets/{kanban-definition-UXKFOSKX-ByvuSwPg.js → kanban-definition-UXKFOSKX-D2FQMRnh.js} +1 -1
- package/web/dist/assets/{layout-CJG7qpZa.js → layout-CZUvkkNF.js} +1 -1
- package/web/dist/assets/{linear-CIQgXZYV.js → linear-tIFeS1QT.js} +1 -1
- package/web/dist/assets/{mermaid.core-CkrYNntI.js → mermaid.core-BI5_3AOv.js} +5 -5
- package/web/dist/assets/{mindmap-definition-YA3MSWOX-C2wu2sJd.js → mindmap-definition-YA3MSWOX-D5RmpgpB.js} +1 -1
- package/web/dist/assets/{pegDiagram-XKGWAZYB-pyyiTfDO.js → pegDiagram-XKGWAZYB-DpZxaRI3.js} +1 -1
- package/web/dist/assets/{pieDiagram-E7YTZNPT-BwJv35J9.js → pieDiagram-E7YTZNPT-Co7MADQz.js} +1 -1
- package/web/dist/assets/{quadrantDiagram-AXDQQJYC-1Q0wSsql.js → quadrantDiagram-AXDQQJYC-BsRraVQ-.js} +1 -1
- package/web/dist/assets/{railroadDiagram-O6MQD6OU-DWFZGo9j.js → railroadDiagram-O6MQD6OU-DW2pw5p_.js} +1 -1
- package/web/dist/assets/{requirementDiagram-BXWQKSXE-CNgNvQO7.js → requirementDiagram-BXWQKSXE-DeaEY9Dk.js} +1 -1
- package/web/dist/assets/{sankeyDiagram-P5KCCOFB-DWmOe-31.js → sankeyDiagram-P5KCCOFB-BlKg1xhH.js} +1 -1
- package/web/dist/assets/{sequenceDiagram-WJ2MYXX4-CvFRnceu.js → sequenceDiagram-WJ2MYXX4-C0ffpRmx.js} +1 -1
- package/web/dist/assets/{sizeCapture-INFHLROL-DNyzv4qr.js → sizeCapture-INFHLROL-DHFDdkAo.js} +1 -1
- package/web/dist/assets/{stateDiagram-D77RDMKH-CUOwyJAj.js → stateDiagram-D77RDMKH-CwKStGSS.js} +1 -1
- package/web/dist/assets/stateDiagram-v2-MP3YSRHH-B0qJoPpx.js +1 -0
- package/web/dist/assets/{swimlanes-42K2YHIH-B2tqXq5C.js → swimlanes-42K2YHIH-MB6Uskqk.js} +1 -1
- package/web/dist/assets/swimlanesDiagram-VR7AAH4N-IYPIFoU6.js +8 -0
- package/web/dist/assets/{timeline-definition-24CTP7MA-BC349pHg.js → timeline-definition-24CTP7MA-CkcuHQ1A.js} +1 -1
- package/web/dist/assets/{vennDiagram-4TSXK5OY-Dp_8OJ1R.js → vennDiagram-4TSXK5OY-DRiGv5ga.js} +1 -1
- package/web/dist/assets/{wardleyDiagram-VM6X3IG4-aZq6zGi4.js → wardleyDiagram-VM6X3IG4-Cwldlf89.js} +1 -1
- package/web/dist/assets/{xychartDiagram-S5SC5T6Z-Cyq-4VPK.js → xychartDiagram-S5SC5T6Z-Biqu8RpV.js} +1 -1
- package/web/dist/index.html +2 -2
- package/web/dist/assets/channel-DXmrQIC_.js +0 -1
- package/web/dist/assets/classDiagram-ZZMXUADV-sfceoHNh.js +0 -1
- package/web/dist/assets/classDiagram-v2-VYDZK3BY-sfceoHNh.js +0 -1
- package/web/dist/assets/index-BVwF4g4j.css +0 -10
- package/web/dist/assets/stateDiagram-v2-MP3YSRHH-CqyXAKwd.js +0 -1
- package/web/dist/assets/swimlanesDiagram-VR7AAH4N-DzTxUWmy.js +0 -8
package/dist/server/subagents.js
CHANGED
|
@@ -25,6 +25,21 @@
|
|
|
25
25
|
// ---------------------------------------------------------------------------
|
|
26
26
|
import { defineTool } from "@earendil-works/pi-coding-agent";
|
|
27
27
|
import { Type } from "typebox";
|
|
28
|
+
/**
|
|
29
|
+
* subagent_wait_all 的最长阻塞时间:必须短暂低于工具看门狗(默认 20 分钟,
|
|
30
|
+
* PI_WEB_TOOL_TIMEOUT_MS 可调),否则看门狗会先中止整个会话而不是让 wait
|
|
31
|
+
* 干净地超时返回。留 20% 余量。
|
|
32
|
+
*/
|
|
33
|
+
const WAIT_CAP_MS = (() => {
|
|
34
|
+
const v = Number(process.env.PI_WEB_TOOL_TIMEOUT_MS);
|
|
35
|
+
const watchdog = Number.isFinite(v) && v > 0 ? v : 20 * 60_000;
|
|
36
|
+
return Math.max(60_000, Math.floor(watchdog * 0.8));
|
|
37
|
+
})();
|
|
38
|
+
/** 子代理是否已到终态(运行结束、被中止或出错)。wait 工具据此判断
|
|
39
|
+
* 是否可以取结果;streaming=false 即可(error/canceled 都在快照里带标记)。 */
|
|
40
|
+
export function isSubagentTerminal(r) {
|
|
41
|
+
return !!r && !r.streaming;
|
|
42
|
+
}
|
|
28
43
|
/** 从 prompt 取首行作为标题(截断 40 字符)。 */
|
|
29
44
|
export function subagentTitle(prompt) {
|
|
30
45
|
const line = prompt.split("\n")[0]?.trim() ?? "";
|
|
@@ -46,16 +61,22 @@ export function makeSubagentTools(host) {
|
|
|
46
61
|
label: "Spawn subagent",
|
|
47
62
|
description: "在后台启动一个独立的子代理对话,用一个明确的指令去完成一项可独立交付的工作(调研/实现/审查等)。" +
|
|
48
63
|
"子代理会出现在左栏「运行的对话」列表(带子代理标识),用户可点开查看、补充、中止。主 agent 可并行派发多个:" +
|
|
49
|
-
"用 subagent_list 查看运行态、subagent_get_result 取结果、
|
|
64
|
+
"用 subagent_wait_all 一次性等全部完成(不用轮询)、subagent_list 查看运行态、subagent_get_result 取结果、" +
|
|
65
|
+
"subagent_steer 中途改向、subagent_stop 停止。" +
|
|
50
66
|
"适合:长耗时探索、并行调研、独立子任务委派。可选 template 参数:使用设置面板配置的子代理模板" +
|
|
51
|
-
"(角色系统提示词 +
|
|
67
|
+
"(角色系统提示词 + 技能/扩展白名单 + 可选模型);可选 model 参数:显式指定子代理模型(provider/id 格式," +
|
|
68
|
+
"如 \"anthropic/claude-opus-4-5\"),优先级高于模板与设置面板的默认模型;都不传 = 跟随主对话当前模型。",
|
|
52
69
|
promptSnippet: "spawn an independent background subagent for a deliverable task (parallel work)",
|
|
53
70
|
parameters: Type.Object({
|
|
54
71
|
prompt: Type.String({ description: "交给子代理的完整指令(要达成的目标 + 约束 + 期望产出)。" }),
|
|
55
72
|
type: Type.Optional(Type.String({ description: "子代理类型/角色名(如 explore/implement/review),用于展示。默认 general。" })),
|
|
56
73
|
template: Type.Optional(Type.String({
|
|
57
74
|
description: "可选:子代理模板名(设置面板「子代理模板」配置的预设,见 subagent_templates 工具)。" +
|
|
58
|
-
"模板 = 角色系统提示词 +
|
|
75
|
+
"模板 = 角色系统提示词 + 技能/扩展白名单 + 可选模型;不传 = 不使用模板,按主会话默认配置运行。",
|
|
76
|
+
})),
|
|
77
|
+
model: Type.Optional(Type.String({
|
|
78
|
+
description: "可选:子代理模型 \"provider/id\"(如 \"anthropic/claude-opus-4-5\"),显式指定本次子代理的模型," +
|
|
79
|
+
"优先级高于模板自带模型与设置面板默认模型;不传 = 模板模型 → 设置面板默认模型 → 跟随主对话当前模型。",
|
|
59
80
|
})),
|
|
60
81
|
cwd: Type.Optional(Type.String({ description: "子代理工作目录(相对/绝对)。默认继承主会话工作目录。" })),
|
|
61
82
|
}),
|
|
@@ -63,16 +84,17 @@ export function makeSubagentTools(host) {
|
|
|
63
84
|
if (p.template && !host.isTemplateUsable(p.template)) {
|
|
64
85
|
return text(`子代理模板不可用:${p.template}(不存在或已停用)。用 subagent_templates 查看当前可用模板清单;不传 template 则按默认配置运行。`);
|
|
65
86
|
}
|
|
66
|
-
const convId = await host.spawnSubagent(p.prompt, p.type ?? "general", p.cwd ?? ctx.cwd, p.template);
|
|
87
|
+
const convId = await host.spawnSubagent(p.prompt, p.type ?? "general", p.cwd ?? ctx.cwd, p.template, p.model);
|
|
67
88
|
return text(`子代理已启动(运行列表可见):${convId}\n类型:${p.type ?? "general"} · 标题:${subagentTitle(p.prompt)}` +
|
|
68
89
|
(p.template ? `\n模板:${p.template}` : "") +
|
|
69
|
-
`\n
|
|
90
|
+
(p.model ? `\n模型:${p.model}` : "") +
|
|
91
|
+
`\n用 subagent_wait_all 一次等全部完成(不用轮询),subagent_get_result 取单个结果,subagent_list 看运行态,subagent_steer 改向,subagent_stop 停止。`, { convId, template: p.template, model: p.model });
|
|
70
92
|
},
|
|
71
93
|
}),
|
|
72
94
|
defineTool({
|
|
73
95
|
name: "subagent_get_result",
|
|
74
96
|
label: "Get subagent result",
|
|
75
|
-
description: "
|
|
97
|
+
description: "取一个子代理的结果或当前运行态。若尚未完成,返回当前状态与已产出的文本;运行报错(如 provider 400)会在这里明确标出错误。",
|
|
76
98
|
promptSnippet: "fetch a subagent's result / current progress",
|
|
77
99
|
parameters: Type.Object({
|
|
78
100
|
runId: Type.String({ description: "subagent_spawn 返回的 convId。左栏点击同名对话可直接查看。" }),
|
|
@@ -81,10 +103,11 @@ export function makeSubagentTools(host) {
|
|
|
81
103
|
const r = host.getSubagent(p.runId);
|
|
82
104
|
if (!r)
|
|
83
105
|
return text(`未找到子代理 ${shortId(p.runId)}(可能已移出)。`, undefined);
|
|
106
|
+
const verdict = subagentVerdict(r);
|
|
84
107
|
if (r.streaming || r.state === "running") {
|
|
85
108
|
return text(`子代理 ${shortId(r.convId)}(${r.type})仍在运行(状态 ${r.state})。\n当前输出:\n${r.output || "(暂无输出)"}`, r);
|
|
86
109
|
}
|
|
87
|
-
return text(`子代理 ${shortId(r.convId)}(${r.type})状态:${r
|
|
110
|
+
return text(`子代理 ${shortId(r.convId)}(${r.type})状态:${verdict}\n${verdictText(r)}\n${r.output || "(无结果)"}`, r);
|
|
88
111
|
},
|
|
89
112
|
}),
|
|
90
113
|
defineTool({
|
|
@@ -104,14 +127,14 @@ export function makeSubagentTools(host) {
|
|
|
104
127
|
defineTool({
|
|
105
128
|
name: "subagent_list",
|
|
106
129
|
label: "List subagents",
|
|
107
|
-
description: "列出全部子代理的运行态:convId
|
|
130
|
+
description: "列出全部子代理的运行态:convId、类型、状态、标题、消息数(报错/中止的会在状态里标出)。",
|
|
108
131
|
promptSnippet: "list all subagents and their live status",
|
|
109
132
|
parameters: Type.Object({}),
|
|
110
133
|
execute: async () => {
|
|
111
134
|
const list = host.listSubagents();
|
|
112
135
|
if (list.length === 0)
|
|
113
136
|
return text("当前没有子代理。");
|
|
114
|
-
const lines = list.map((r) => `- ${r.convId} · ${r.type} · ${r
|
|
137
|
+
const lines = list.map((r) => `- ${r.convId} · ${r.type} · ${subagentVerdict(r)} · ${r.title}(msg: ${r.messageCount})`);
|
|
115
138
|
return text(lines.join("\n"));
|
|
116
139
|
},
|
|
117
140
|
}),
|
|
@@ -126,10 +149,60 @@ export function makeSubagentTools(host) {
|
|
|
126
149
|
return text(`已请求停止子代理 ${shortId(p.runId)}。`);
|
|
127
150
|
},
|
|
128
151
|
}),
|
|
152
|
+
defineTool({
|
|
153
|
+
name: "subagent_wait_all",
|
|
154
|
+
label: "Wait for subagents",
|
|
155
|
+
description: "一次性等待多个子代理全部完成(阻塞本回合直到它们都到达终态或超时),然后汇总返回每个的结果/错误——" +
|
|
156
|
+
"不用反复调 subagent_get_result 轮询。传 runIds 指定要等的子代理(subagent_spawn 返回的 convId);" +
|
|
157
|
+
"不传 = 等当前全部运行中的子代理。超时或本轮被中止时返回剩余未完成名单,可再次调用继续等。" +
|
|
158
|
+
"适合:并行派发多个子代理后收口。",
|
|
159
|
+
promptSnippet: "wait for multiple subagents to finish (no polling) and get all results",
|
|
160
|
+
parameters: Type.Object({
|
|
161
|
+
runIds: Type.Optional(Type.Array(Type.String({ description: "要等待的子代理 convId(subagent_spawn 返回值)。缺省 = 等当前全部运行中的。" }))),
|
|
162
|
+
timeoutSeconds: Type.Optional(Type.Integer({
|
|
163
|
+
description: `最多等待秒数(默认 600,上限约 ${Math.floor(WAIT_CAP_MS / 1000)}——必须低于工具看门狗,超时返回未完成名单可再调)。`,
|
|
164
|
+
minimum: 1,
|
|
165
|
+
maximum: Math.floor(WAIT_CAP_MS / 1000),
|
|
166
|
+
})),
|
|
167
|
+
}),
|
|
168
|
+
execute: async (_id, p, signal) => {
|
|
169
|
+
const wanted = new Set(p.runIds && p.runIds.length > 0 ? p.runIds : host.listSubagents().map((r) => r.convId));
|
|
170
|
+
const timeoutMs = Math.min(Math.max(p.timeoutSeconds ?? 600, 1), Math.floor(WAIT_CAP_MS / 1000)) * 1000;
|
|
171
|
+
const waitStart = Date.now();
|
|
172
|
+
const deadline = waitStart + timeoutMs;
|
|
173
|
+
// 已到终态的、(或已被移出找不到的)直接归位;剩下的阻塞轮询到
|
|
174
|
+
// 全部完成/超时/中止(移出 = 无法再等,立即按收口处理)。
|
|
175
|
+
const pending = () => [...wanted].filter((id) => {
|
|
176
|
+
const r = host.getSubagent(id);
|
|
177
|
+
return r !== undefined && !isSubagentTerminal(r);
|
|
178
|
+
});
|
|
179
|
+
while (pending().length > 0 && Date.now() < deadline && !(signal?.aborted ?? false)) {
|
|
180
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
181
|
+
}
|
|
182
|
+
const remaining = pending();
|
|
183
|
+
const lines = [...wanted]
|
|
184
|
+
.map((id) => {
|
|
185
|
+
const r = host.getSubagent(id);
|
|
186
|
+
if (!r)
|
|
187
|
+
return `- ${shortId(id)}:未找到(可能已移出)`;
|
|
188
|
+
const body = verdictText(r);
|
|
189
|
+
return (`- ${shortId(r.convId)}(${r.type})· ${r.title} · ${subagentVerdict(r)}` +
|
|
190
|
+
(body ? `\n ${body}` : "") +
|
|
191
|
+
(r.output ? `\n ${r.output.split("\n").slice(0, 30).join("\n ")}` : ""));
|
|
192
|
+
})
|
|
193
|
+
.join("\n");
|
|
194
|
+
const head = remaining.length === 0
|
|
195
|
+
? `全部 ${wanted.size} 个子代理已收口:`
|
|
196
|
+
: signal?.aborted
|
|
197
|
+
? `本轮被中止,${remaining.length} 个仍在运行:`
|
|
198
|
+
: `等待超过 ${Math.round(timeoutMs / 1000)}s 超时(实际等待 ${Math.round((Date.now() - waitStart) / 1000)}s),${remaining.length} 个仍在运行:`;
|
|
199
|
+
return text(`${head}\n${lines}\n` + promptRemaining(remaining));
|
|
200
|
+
},
|
|
201
|
+
}),
|
|
129
202
|
defineTool({
|
|
130
203
|
name: "subagent_templates",
|
|
131
204
|
label: "List subagent templates",
|
|
132
|
-
description: "列出设置面板「子代理模板」配置的可用模板(角色系统提示词 +
|
|
205
|
+
description: "列出设置面板「子代理模板」配置的可用模板(角色系统提示词 + 技能/扩展白名单 + 可选模型 的组合预设)," +
|
|
133
206
|
"供 subagent_spawn 的 template 参数选用。已停用的模板不会出现在这里。list 为空 = 未配置模板,子代理按默认配置运行。",
|
|
134
207
|
promptSnippet: "list configurable subagent templates (role prompt + skills/extensions whitelist presets)",
|
|
135
208
|
parameters: Type.Object({}),
|
|
@@ -138,7 +211,8 @@ export function makeSubagentTools(host) {
|
|
|
138
211
|
if (list.length === 0) {
|
|
139
212
|
return text("当前没有可用的子代理模板(设置面板 → 子代理模板 添加后可用)。子代理默认按主会话配置运行。");
|
|
140
213
|
}
|
|
141
|
-
const lines = list.map((t) => `- ${t.name}${t.description ? `:${t.description}` : ""}`
|
|
214
|
+
const lines = list.map((t) => `- ${t.name}${t.description ? `:${t.description}` : ""}` +
|
|
215
|
+
(t.model ? `(模型:${t.model})` : "(跟随主对话模型)"));
|
|
142
216
|
return text(`可用的子代理模板(subagent_spawn 的 template 参数传名字,如 subagent_spawn(template="${list[0]?.name}")):\n${lines.join("\n")}`);
|
|
143
217
|
},
|
|
144
218
|
}),
|
|
@@ -148,3 +222,25 @@ export function makeSubagentTools(host) {
|
|
|
148
222
|
function shortId(id) {
|
|
149
223
|
return id.slice(0, 8);
|
|
150
224
|
}
|
|
225
|
+
/** 人类可读的终态判定:报错 > 中止 > done > running。 */
|
|
226
|
+
function subagentVerdict(r) {
|
|
227
|
+
if (r.error)
|
|
228
|
+
return "error(报错)";
|
|
229
|
+
if (r.canceled)
|
|
230
|
+
return "canceled(已中止)";
|
|
231
|
+
return r.state;
|
|
232
|
+
}
|
|
233
|
+
/** 终态的可读说明(错误文本 / 中止说明 / 空)。运行中返回空。 */
|
|
234
|
+
function verdictText(r) {
|
|
235
|
+
if (r.error)
|
|
236
|
+
return `错误:${r.error}`;
|
|
237
|
+
if (r.canceled)
|
|
238
|
+
return "(被中止,未产出结论)";
|
|
239
|
+
return "";
|
|
240
|
+
}
|
|
241
|
+
/** 未完成部分的引导文案。 */
|
|
242
|
+
function promptRemaining(remaining) {
|
|
243
|
+
if (remaining.length === 0)
|
|
244
|
+
return "";
|
|
245
|
+
return `\n未完成:${remaining.map(shortId).join(", ")}。可再次调用 subagent_wait_all(或 subagent_steer 补充指令 / subagent_stop 中止)。`;
|
|
246
|
+
}
|
package/package.json
CHANGED
|
@@ -1,110 +1,110 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "pi-web-ui",
|
|
3
|
-
"version": "0.64.
|
|
4
|
-
"description": "Web chat interface for the pi coding agent, powered by the pi SDK (@earendil-works/pi-coding-agent) — one-command run, Docker/systemd/launchd deployable",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"author": {
|
|
7
|
-
"name": "xingshuyin",
|
|
8
|
-
"email": "xingshuyin@users.noreply.github.com"
|
|
9
|
-
},
|
|
10
|
-
"type": "module",
|
|
11
|
-
"bin": {
|
|
12
|
-
"pi-web-ui": "bin/pi-web-ui.mjs"
|
|
13
|
-
},
|
|
14
|
-
"main": "bin/pi-web-ui.mjs",
|
|
15
|
-
"files": [
|
|
16
|
-
"bin/",
|
|
17
|
-
"dist/",
|
|
18
|
-
"web/dist/",
|
|
19
|
-
"web/public/",
|
|
20
|
-
"themes/",
|
|
21
|
-
"deploy/",
|
|
22
|
-
"extensions/",
|
|
23
|
-
"README.md",
|
|
24
|
-
"LICENSE"
|
|
25
|
-
],
|
|
26
|
-
"keywords": [
|
|
27
|
-
"pi",
|
|
28
|
-
"pi-package",
|
|
29
|
-
"coding-agent",
|
|
30
|
-
"ai",
|
|
31
|
-
"chat",
|
|
32
|
-
"web-ui",
|
|
33
|
-
"terminal",
|
|
34
|
-
"llm"
|
|
35
|
-
],
|
|
36
|
-
"repository": {
|
|
37
|
-
"type": "git",
|
|
38
|
-
"url": "git+https://github.com/xing-shuyin/pi-web-ui.git"
|
|
39
|
-
},
|
|
40
|
-
"pi": {
|
|
41
|
-
"extensions": [
|
|
42
|
-
"./extensions"
|
|
43
|
-
]
|
|
44
|
-
},
|
|
45
|
-
"engines": {
|
|
46
|
-
"node": ">=22.19.0"
|
|
47
|
-
},
|
|
48
|
-
"scripts": {
|
|
49
|
-
"prepublishOnly": "npm run build",
|
|
50
|
-
"dev": "concurrently -k -n server,web -c blue,green \"npm:dev:server\" \"npm:dev:web\"",
|
|
51
|
-
"dev:server": "cross-env PI_WEB_PORT=8788 PI_WEB_ALLOW_ORIGINS=http://localhost:5173,http://127.0.0.1:5173 node --watch --import tsx server/index.ts",
|
|
52
|
-
"dev:web": "vite --config web/vite.config.ts",
|
|
53
|
-
"build": "npm run build:web && npm run build:server && npm run build:dsh-runtime",
|
|
54
|
-
"build:web": "vite build --config web/vite.config.ts",
|
|
55
|
-
"build:server": "tsc -p tsconfig.server.json",
|
|
56
|
-
"build:dsh-runtime": "node scripts/copy-dsh-runtime.mjs",
|
|
57
|
-
"typecheck": "tsc -p tsconfig.server.json --noEmit && tsc -p web/tsconfig.json --noEmit && tsc -p tsconfig.tests.json --noEmit",
|
|
58
|
-
"test": "vitest run",
|
|
59
|
-
"test:unit": "vitest run",
|
|
60
|
-
"test:smoke": "node tests/run-smoke.mjs",
|
|
61
|
-
"check:protocol": "node scripts/check-protocol-sync.mjs",
|
|
62
|
-
"test:freeze": "node tests/freeze-test.mjs",
|
|
63
|
-
"start": "node dist/server/index.js",
|
|
64
|
-
"format": "prettier --write server/ web/src/ extensions/ scripts/ bin/ tests/*.mjs tests/unit/ *.mjs",
|
|
65
|
-
"format:check": "prettier --check server/ web/src/ extensions/ scripts/ bin/ tests/*.mjs tests/unit/ *.mjs",
|
|
66
|
-
"lint": "oxlint server/ web/src/ extensions/ scripts/",
|
|
67
|
-
"lint:fix": "oxlint --fix server/ web/src/ extensions/ scripts/"
|
|
68
|
-
},
|
|
69
|
-
"dependencies": {
|
|
70
|
-
"@deepseek-ai/dsh-sdk-jsonrpc-server": "^0.1.1-rc.2",
|
|
71
|
-
"@deepseek-ai/dsh-sdk-protocol": "^0.1.1-rc.2",
|
|
72
|
-
"@earendil-works/pi-coding-agent": "^0.84.4",
|
|
73
|
-
"@xterm/addon-fit": "^0.11.0",
|
|
74
|
-
"@xterm/xterm": "^6.0.0",
|
|
75
|
-
"compression": "^1.8.1",
|
|
76
|
-
"express": "^4.21.2",
|
|
77
|
-
"highlight.js": "^11.10.0",
|
|
78
|
-
"mermaid": "^11.17.2",
|
|
79
|
-
"node-pty": "^1.1.0",
|
|
80
|
-
"react": "^18.3.1",
|
|
81
|
-
"react-dom": "^18.3.1",
|
|
82
|
-
"react-icons": "^5.7.0",
|
|
83
|
-
"react-markdown": "^9.0.1",
|
|
84
|
-
"rehype-highlight": "^7.0.1",
|
|
85
|
-
"remark-gfm": "^4.0.0",
|
|
86
|
-
"typebox": "^1.3.14",
|
|
87
|
-
"ws": "^8.18.0"
|
|
88
|
-
},
|
|
89
|
-
"devDependencies": {
|
|
90
|
-
"@types/compression": "^1.8.1",
|
|
91
|
-
"@types/express": "^4.17.21",
|
|
92
|
-
"@types/node": "^22.10.0",
|
|
93
|
-
"@types/react": "^18.3.12",
|
|
94
|
-
"@types/react-dom": "^18.3.1",
|
|
95
|
-
"@types/ws": "^8.5.13",
|
|
96
|
-
"@vitejs/plugin-react": "^4.3.4",
|
|
97
|
-
"concurrently": "^9.1.0",
|
|
98
|
-
"cross-env": "^10.1.0",
|
|
99
|
-
"oxlint": "^1.81.0",
|
|
100
|
-
"playwright-core": "^1.62.1",
|
|
101
|
-
"prettier": "^3.9.6",
|
|
102
|
-
"tsx": "^4.19.2",
|
|
103
|
-
"typescript": "^5.7.2",
|
|
104
|
-
"vite": "^6.0.3",
|
|
105
|
-
"vitest": "^4.1.11"
|
|
106
|
-
},
|
|
107
|
-
"allowScripts": {
|
|
108
|
-
"node-pty@1.1.0": true
|
|
109
|
-
}
|
|
110
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-web-ui",
|
|
3
|
+
"version": "0.64.6",
|
|
4
|
+
"description": "Web chat interface for the pi coding agent, powered by the pi SDK (@earendil-works/pi-coding-agent) — one-command run, Docker/systemd/launchd deployable",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "xingshuyin",
|
|
8
|
+
"email": "xingshuyin@users.noreply.github.com"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"bin": {
|
|
12
|
+
"pi-web-ui": "bin/pi-web-ui.mjs"
|
|
13
|
+
},
|
|
14
|
+
"main": "bin/pi-web-ui.mjs",
|
|
15
|
+
"files": [
|
|
16
|
+
"bin/",
|
|
17
|
+
"dist/",
|
|
18
|
+
"web/dist/",
|
|
19
|
+
"web/public/",
|
|
20
|
+
"themes/",
|
|
21
|
+
"deploy/",
|
|
22
|
+
"extensions/",
|
|
23
|
+
"README.md",
|
|
24
|
+
"LICENSE"
|
|
25
|
+
],
|
|
26
|
+
"keywords": [
|
|
27
|
+
"pi",
|
|
28
|
+
"pi-package",
|
|
29
|
+
"coding-agent",
|
|
30
|
+
"ai",
|
|
31
|
+
"chat",
|
|
32
|
+
"web-ui",
|
|
33
|
+
"terminal",
|
|
34
|
+
"llm"
|
|
35
|
+
],
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/xing-shuyin/pi-web-ui.git"
|
|
39
|
+
},
|
|
40
|
+
"pi": {
|
|
41
|
+
"extensions": [
|
|
42
|
+
"./extensions"
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=22.19.0"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"prepublishOnly": "npm run build",
|
|
50
|
+
"dev": "concurrently -k -n server,web -c blue,green \"npm:dev:server\" \"npm:dev:web\"",
|
|
51
|
+
"dev:server": "cross-env PI_WEB_PORT=8788 PI_WEB_ALLOW_ORIGINS=http://localhost:5173,http://127.0.0.1:5173 node --watch --import tsx server/index.ts",
|
|
52
|
+
"dev:web": "vite --config web/vite.config.ts",
|
|
53
|
+
"build": "npm run build:web && npm run build:server && npm run build:dsh-runtime",
|
|
54
|
+
"build:web": "vite build --config web/vite.config.ts",
|
|
55
|
+
"build:server": "tsc -p tsconfig.server.json",
|
|
56
|
+
"build:dsh-runtime": "node scripts/copy-dsh-runtime.mjs",
|
|
57
|
+
"typecheck": "tsc -p tsconfig.server.json --noEmit && tsc -p web/tsconfig.json --noEmit && tsc -p tsconfig.tests.json --noEmit",
|
|
58
|
+
"test": "vitest run",
|
|
59
|
+
"test:unit": "vitest run",
|
|
60
|
+
"test:smoke": "node tests/run-smoke.mjs",
|
|
61
|
+
"check:protocol": "node scripts/check-protocol-sync.mjs",
|
|
62
|
+
"test:freeze": "node tests/freeze-test.mjs",
|
|
63
|
+
"start": "node dist/server/index.js",
|
|
64
|
+
"format": "prettier --write server/ web/src/ extensions/ scripts/ bin/ tests/*.mjs tests/unit/ *.mjs",
|
|
65
|
+
"format:check": "prettier --check server/ web/src/ extensions/ scripts/ bin/ tests/*.mjs tests/unit/ *.mjs",
|
|
66
|
+
"lint": "oxlint server/ web/src/ extensions/ scripts/",
|
|
67
|
+
"lint:fix": "oxlint --fix server/ web/src/ extensions/ scripts/"
|
|
68
|
+
},
|
|
69
|
+
"dependencies": {
|
|
70
|
+
"@deepseek-ai/dsh-sdk-jsonrpc-server": "^0.1.1-rc.2",
|
|
71
|
+
"@deepseek-ai/dsh-sdk-protocol": "^0.1.1-rc.2",
|
|
72
|
+
"@earendil-works/pi-coding-agent": "^0.84.4",
|
|
73
|
+
"@xterm/addon-fit": "^0.11.0",
|
|
74
|
+
"@xterm/xterm": "^6.0.0",
|
|
75
|
+
"compression": "^1.8.1",
|
|
76
|
+
"express": "^4.21.2",
|
|
77
|
+
"highlight.js": "^11.10.0",
|
|
78
|
+
"mermaid": "^11.17.2",
|
|
79
|
+
"node-pty": "^1.1.0",
|
|
80
|
+
"react": "^18.3.1",
|
|
81
|
+
"react-dom": "^18.3.1",
|
|
82
|
+
"react-icons": "^5.7.0",
|
|
83
|
+
"react-markdown": "^9.0.1",
|
|
84
|
+
"rehype-highlight": "^7.0.1",
|
|
85
|
+
"remark-gfm": "^4.0.0",
|
|
86
|
+
"typebox": "^1.3.14",
|
|
87
|
+
"ws": "^8.18.0"
|
|
88
|
+
},
|
|
89
|
+
"devDependencies": {
|
|
90
|
+
"@types/compression": "^1.8.1",
|
|
91
|
+
"@types/express": "^4.17.21",
|
|
92
|
+
"@types/node": "^22.10.0",
|
|
93
|
+
"@types/react": "^18.3.12",
|
|
94
|
+
"@types/react-dom": "^18.3.1",
|
|
95
|
+
"@types/ws": "^8.5.13",
|
|
96
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
97
|
+
"concurrently": "^9.1.0",
|
|
98
|
+
"cross-env": "^10.1.0",
|
|
99
|
+
"oxlint": "^1.81.0",
|
|
100
|
+
"playwright-core": "^1.62.1",
|
|
101
|
+
"prettier": "^3.9.6",
|
|
102
|
+
"tsx": "^4.19.2",
|
|
103
|
+
"typescript": "^5.7.2",
|
|
104
|
+
"vite": "^6.0.3",
|
|
105
|
+
"vitest": "^4.1.11"
|
|
106
|
+
},
|
|
107
|
+
"allowScripts": {
|
|
108
|
+
"node-pty@1.1.0": true
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as l,j as n}from"./markdown-BJJLXG-8.js";import{u as O,b as M,T as z,a as W,F as Y,c as H,d as Z,e as q,f as ee,g as ne,h as te,i as se,r as ae}from"./index-
|
|
1
|
+
import{a as l,j as n}from"./markdown-BJJLXG-8.js";import{u as O,b as M,T as z,a as W,F as Y,c as H,d as Z,e as q,f as ee,g as ne,h as te,i as se,r as ae}from"./index-30RM921r.js";import{D as re,o as ie}from"./xterm-D1D2FVe3.js";import"./react-ezqUM1Or.js";function le(t){let c=null;return{clean:t.replace(/\r?\n?\[pi-term-exit:(-?\d+)\]\r?\n?/g,(a,h)=>(c=Number(h),`\r
|
|
2
2
|
`)).replace(/\r?\n?\x1b\[90m\[(?:进程已退出,退出码 |Process exited with code )-?\d+\]\x1b\[0m\r?\n?/g,`\r
|
|
3
3
|
`),exitCode:c}}function ce({conversationId:t,terminalId:c,command:f,cwd:a,title:h,active:u,running:b,exitCode:y,send:j,register:T}){const k=l.useRef(null),N=l.useRef(null),{locale:o}=O(),w=l.useRef(o);w.current=o;const F=f?JSON.stringify(f):"";l.useEffect(()=>{const m=k.current;if(!m)return;const r=new re({theme:M(),fontFamily:'"SF Mono", "JetBrains Mono", ui-monospace, Menlo, Consolas, monospace',fontSize:13,cursorBlink:!0,scrollback:8e3}),g=new ie;r.loadAddon(g),r.open(m),N.current={term:r,fit:g},u&&r.focus();const C=()=>{r.options.theme=M()};window.addEventListener(z,C),r.attachCustomKeyEventHandler(d=>{var A;if(d.type!=="keydown")return!0;const D=(A=d.key)==null?void 0:A.toLowerCase();if((d.ctrlKey||d.metaKey)&&D==="v")return!1;if(d.ctrlKey&&!d.shiftKey&&!d.altKey&&D==="c"&&r.hasSelection()){const E=r.textarea;return E&&(E.value=r.getSelection(),E.select()),!1}return!0});const _=T(t,c,{write:d=>r.write(le(d).clean),dispose:()=>r.dispose()}),$=()=>{try{g.fit(),j({type:"terminal_resize",terminalId:c,conversationId:t,cols:r.cols,rows:r.rows})}catch{}},B=requestAnimationFrame(()=>{try{g.fit()}catch{}j(f?{type:"run_command",terminalId:c,conversationId:t,command:f,cols:r.cols,rows:r.rows}:{type:"terminal_create",terminalId:c,title:h,locale:w.current,conversationId:t,cwd:a,cols:r.cols,rows:r.rows})}),S=r.onData(d=>{j({type:"terminal_input",terminalId:c,conversationId:t,data:d})});let v=null;return typeof ResizeObserver<"u"&&(v=new ResizeObserver(()=>{m.offsetWidth>0&&m.offsetHeight>0&&$()}),v.observe(m)),()=>{cancelAnimationFrame(B),S.dispose(),window.removeEventListener(z,C),v==null||v.disconnect(),_(),r.dispose(),N.current=null}},[t,c,F,j,T]),l.useEffect(()=>{if(!u)return;const m=requestAnimationFrame(()=>{const r=N.current;if(r){try{r.fit.fit(),j({type:"terminal_resize",terminalId:c,conversationId:t,cols:r.term.cols,rows:r.term.rows})}catch{}r.term.focus()}});return()=>cancelAnimationFrame(m)},[u]);const{t:R}=O(),x=l.useRef(void 0);return l.useEffect(()=>{if(b===x.current||(x.current=b,b!==!1))return;const m=N.current;m&&m.term.write(`\r
|
|
4
4
|
\x1B[90m${R("exitBanner",{code:y??""})}\x1B[0m\r
|
package/web/dist/assets/{abnfDiagram-VCTEODGH-dzrhTpxN.js → abnfDiagram-VCTEODGH-Dltz1N0G.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{g as p,r as u,d as a}from"./chunk-SVP7TREG-
|
|
1
|
+
import{g as p,r as u,d as a}from"./chunk-SVP7TREG-IQRTD_4U.js";import{p as f}from"./chunk-JWPE2WC7-DTpnGTdB.js";import{_ as n,l as o}from"./mermaid.core-BI5_3AOv.js";import{M as c,b as d}from"./cynefin-OW5HDTMX-OsV-x0h-.js";import"./index-30RM921r.js";import"./markdown-BJJLXG-8.js";import"./react-ezqUM1Or.js";var v=d().RailroadAbnf.parser.LangiumParser,i=n(e=>{const r=e.alternatives.map(g);return r.length===1?r[0]:{type:"choice",alternatives:r}},"transformAlternation"),g=n(e=>{const r=e.elements.map(y);return r.length===1?r[0]:{type:"sequence",elements:r}},"transformConcatenation"),b=n(e=>{if(e.includes("*")){const[t,s]=e.split("*"),l=t?parseInt(t,10):0,m=s?parseInt(s,10):1/0;return{min:l,max:m}}const r=parseInt(e,10);return{min:r,max:r}},"parseRepeat"),y=n(e=>{const r=A(e.primary);if(!e.repeat)return r;const{min:t,max:s}=b(e.repeat);return t===0&&s===1?{type:"optional",element:r}:{type:"repetition",element:r,min:t,max:s}},"transformElement"),A=n(e=>{switch(e.$type){case"AbnfStringLiteral":return{type:"terminal",value:e.value};case"AbnfNumVal":return{type:"terminal",value:e.value};case"AbnfRuleName":return{type:"nonterminal",name:e.name};case"AbnfGroup":return i(e.element);case"AbnfOptionalGroup":return{type:"optional",element:i(e.element)};default:throw new Error(`Unsupported ABNF primary node: ${e.$type}`)}},"transformPrimary"),P=n(e=>({name:e.name,definition:i(e.definition)}),"transformRule"),h=n(e=>{f(e,a),e.title&&a.setTitle(e.title),e.rules.map(r=>a.addRule(P(r)))},"populateDb"),R={parse:n(e=>{a.clear(),o.debug("[ABNF Parser] Starting Langium parse");const r=v.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new c(r);const t=r.value;o.debug("[ABNF Parser] Parsed rules:",t.rules.length),h(t),o.debug("[ABNF Parser] Parse complete")},"parse"),parser:{yy:a}},I={parser:R,db:a,renderer:u,styles:p};export{I as diagram};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a0 as ln,a1 as an,a2 as y,a3 as tn,a4 as H,a5 as q,a6 as _,a7 as un,a8 as rn,a9 as L,aa as o,ab as B,ac as sn,ad as on,ae as fn}from"./mermaid.core-
|
|
1
|
+
import{a0 as ln,a1 as an,a2 as y,a3 as tn,a4 as H,a5 as q,a6 as _,a7 as un,a8 as rn,a9 as L,aa as o,ab as B,ac as sn,ad as on,ae as fn}from"./mermaid.core-BI5_3AOv.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,I,D,v,A,C,a){var O=I-l,i=D-h,n=C-v,d=a-A,u=d*O-n*i;if(!(u*u<y))return u=(n*(h-A)-d*(l-v))/u,[l+u*O,h+u*i]}function W(l,h,I,D,v,A,C){var a=l-I,O=h-D,i=(C?A:-A)/L(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,F=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,R=m*m+g*g,T=v-A,P=u*c-f*s,S=(g<0?-1:1)*L(fn(0,T*T*R-P*P)),j=(P*g-m*S)/R,z=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=j-F,e=z-t,r=w-F,G=p-t;return x*x+e*e>r*r+G*G&&(j=w,z=p),{cx:j,cy:z,x01:-n,y01:-d,x11:j*(v/T-1),y11:z*(v/T-1)}}function hn(){var l=cn,h=yn,I=B(0),D=null,v=gn,A=dn,C=mn,a=null,O=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-an,c=A.apply(this,arguments)-an,F=un(c-f),t=c>f;if(a||(a=n=O()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(F>tn-y)a.moveTo(s*H(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*H(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=F,S=F,j=C.apply(this,arguments)/2,z=j>y&&(D?+D.apply(this,arguments):L(u*u+s*s)),w=_(un(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if(z>y){var G=sn(z/u*q(j)),M=sn(z/s*q(j));(P-=G*2)>y?(G*=t?1:-1,R+=G,T-=G):(P=0,R=T=(f+c)/2),(S-=M*2)>y?(M*=t?1:-1,m+=M,g-=M):(S=0,m=g=(f+c)/2)}var J=s*H(m),K=s*q(m),N=u*H(T),Q=u*q(T);if(w>y){var U=s*H(g),V=s*q(g),X=u*H(R),Y=u*q(R),E;if(F<rn)if(E=pn(J,K,X,Y,U,V,N,Q)){var Z=J-E[0],$=K-E[1],b=U-E[0],k=V-E[1],nn=1/q(on((Z*b+$*k)/(L(Z*Z+$*$)*L(b*b+k*k)))/2),en=L(E[0]*E[0]+E[1]*E[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}S>y?x>y?(e=W(X,Y,J,K,s,x,t),r=W(U,V,N,Q,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(J,K),a.arc(0,0,s,m,g,!t)):a.moveTo(J,K),!(u>y)||!(P>y)?a.lineTo(N,Q):p>y?(e=W(N,Q,U,V,u,-p,t),r=W(J,K,X,Y,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-rn/2;return[H(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:B(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:B(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:B(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:B(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:B(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:B(+n),i):A},i.padAngle=function(n){return arguments.length?(C=typeof n=="function"?n:B(+n),i):C},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};
|