@yorz/cli 0.3.0 → 0.3.5
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 +34 -54
- package/dist/cli/index.js +160 -39
- package/dist/gui/assets/{abnfDiagram-VRR7QNED-Dvg_gtwF.js → abnfDiagram-VRR7QNED-DQM-IUdR.js} +1 -1
- package/dist/gui/assets/{arc-DPHbXQf3.js → arc-WoQS9inO.js} +1 -1
- package/dist/gui/assets/{architectureDiagram-ZJ3FMSHR-d6PCjJn6.js → architectureDiagram-ZJ3FMSHR-BSJfE6nY.js} +1 -1
- package/dist/gui/assets/{blockDiagram-677ZJIJ3-BC2I0xtq.js → blockDiagram-677ZJIJ3-BXk0h_Na.js} +1 -1
- package/dist/gui/assets/{c4Diagram-LMCZKHZV-B-KrLqya.js → c4Diagram-LMCZKHZV-Sgnopqnh.js} +1 -1
- package/dist/gui/assets/channel-DAAPjLkv.js +1 -0
- package/dist/gui/assets/{chunk-2Q5K7J3B-D_6tE8D9.js → chunk-2Q5K7J3B-sWwRHI31.js} +1 -1
- package/dist/gui/assets/{chunk-32BRIVSS-Bjgyu8pc.js → chunk-32BRIVSS-6HJXOWs9.js} +1 -1
- package/dist/gui/assets/{chunk-5VM5RSS4-D2ExKDZn.js → chunk-5VM5RSS4-De_Y0Itz.js} +1 -1
- package/dist/gui/assets/{chunk-EX3LRPZG-CAgqmiG1.js → chunk-EX3LRPZG-CTtRnKWx.js} +1 -1
- package/dist/gui/assets/{chunk-JWPE2WC7-32xYgKDA.js → chunk-JWPE2WC7-Dp9usWZX.js} +1 -1
- package/dist/gui/assets/{chunk-MOJQB5TN-DmF1hIRM.js → chunk-MOJQB5TN-OoM3V1FE.js} +1 -1
- package/dist/gui/assets/{chunk-RYQCIY6F-BpygaLmn.js → chunk-RYQCIY6F-M8me5HDP.js} +1 -1
- package/dist/gui/assets/{chunk-V7JOEXUC-CL5xjYjs.js → chunk-V7JOEXUC-CLdvRo84.js} +1 -1
- package/dist/gui/assets/{chunk-VR4S4FIN-CUKOpnGv.js → chunk-VR4S4FIN-BMEciG-B.js} +1 -1
- package/dist/gui/assets/{chunk-XXDRQBXY-rH7GWHx4.js → chunk-XXDRQBXY-DT8b8q8Q.js} +1 -1
- package/dist/gui/assets/classDiagram-OUVF2IWQ-DU6pj67q.js +1 -0
- package/dist/gui/assets/classDiagram-v2-EOCWNBFH-DU6pj67q.js +1 -0
- package/dist/gui/assets/{cose-bilkent-JH36ORCC-Cq80riEI.js → cose-bilkent-JH36ORCC-C1w9npQD.js} +1 -1
- package/dist/gui/assets/{cynefin-VYW2F7L2-DhvCHInV.js → cynefin-VYW2F7L2-buyB6Ypi.js} +1 -1
- package/dist/gui/assets/{cynefinDiagram-TSTJHNR4-U9_xrCTX.js → cynefinDiagram-TSTJHNR4-DPQmwOX9.js} +1 -1
- package/dist/gui/assets/{dagre-VKFMJZFB-D39LwJ1s.js → dagre-VKFMJZFB-DfbmQsg3.js} +1 -1
- package/dist/gui/assets/{diagram-FQU43EPY-DyZSy6Y2.js → diagram-FQU43EPY-DZZkoYxF.js} +1 -1
- package/dist/gui/assets/{diagram-G47NLZAW-CWTyg-w3.js → diagram-G47NLZAW-DJyFDLgi.js} +1 -1
- package/dist/gui/assets/{diagram-NH7WQ7WH-Cfmxj_yc.js → diagram-NH7WQ7WH-CeIoika9.js} +1 -1
- package/dist/gui/assets/{diagram-OA4YK3LP-BWR9rLtc.js → diagram-OA4YK3LP-D3bJmzbA.js} +1 -1
- package/dist/gui/assets/{diagram-WEI45ONY-BtqMg5zg.js → diagram-WEI45ONY-5whYnN6Z.js} +1 -1
- package/dist/gui/assets/{ebnfDiagram-CCIWWBDH-GFU4rZWL.js → ebnfDiagram-CCIWWBDH-fRcOahPq.js} +1 -1
- package/dist/gui/assets/{erDiagram-Q63AITRT-ByNYUzxd.js → erDiagram-Q63AITRT-h22ShxWi.js} +1 -1
- package/dist/gui/assets/{flowDiagram-23GEKE2U-GIo3zItT.js → flowDiagram-23GEKE2U-CImBEPKl.js} +1 -1
- package/dist/gui/assets/{ganttDiagram-NO4QXBWP-BfDrggvI.js → ganttDiagram-NO4QXBWP-D7GfEoL1.js} +1 -1
- package/dist/gui/assets/{gitGraphDiagram-IHSO6WYX-wZAUbbfD.js → gitGraphDiagram-IHSO6WYX-BQlPqwV3.js} +1 -1
- package/dist/gui/assets/index-B_NGA1xd.css +1 -0
- package/dist/gui/assets/index-BnMXI8QL.js +673 -0
- package/dist/gui/assets/{infoDiagram-FWYZ7A6U-CbVgWslR.js → infoDiagram-FWYZ7A6U-dQgAvdfE.js} +1 -1
- package/dist/gui/assets/{ishikawaDiagram-FXEZZL3T-DiZGLvml.js → ishikawaDiagram-FXEZZL3T-Dsb8okiC.js} +1 -1
- package/dist/gui/assets/{journeyDiagram-5HDEW3XC-Bto56knB.js → journeyDiagram-5HDEW3XC-BVaJ8kFx.js} +1 -1
- package/dist/gui/assets/{kanban-definition-HUTT4EX6-CyuHCEsI.js → kanban-definition-HUTT4EX6-CtRRLwap.js} +1 -1
- package/dist/gui/assets/{linear-B9sLmbPn.js → linear-CtTzoPCE.js} +1 -1
- package/dist/gui/assets/{mermaid.core-bOetDHeS.js → mermaid.core-BO-VJXe-.js} +4 -4
- package/dist/gui/assets/{mindmap-definition-LN4V7U3C-BUliAfjd.js → mindmap-definition-LN4V7U3C-Djl0w9Df.js} +1 -1
- package/dist/gui/assets/{pegDiagram-2B236MQR-DFWc28Wx.js → pegDiagram-2B236MQR-D2VRUT1H.js} +1 -1
- package/dist/gui/assets/{pieDiagram-ENE6RG2P-DBqrT9tz.js → pieDiagram-ENE6RG2P-Bp7Ytwe1.js} +1 -1
- package/dist/gui/assets/{quadrantDiagram-ABIIQ3AL-CrPtmaKy.js → quadrantDiagram-ABIIQ3AL-Df4S5Uw8.js} +1 -1
- package/dist/gui/assets/{railroadDiagram-RFXS5EU6-CQhfd0gh.js → railroadDiagram-RFXS5EU6-1E9T3-eU.js} +1 -1
- package/dist/gui/assets/{requirementDiagram-TGXJPOKE-BaZ77i_q.js → requirementDiagram-TGXJPOKE-ClWnTEWR.js} +1 -1
- package/dist/gui/assets/{sankeyDiagram-HTMAVEWB-DC3Exphe.js → sankeyDiagram-HTMAVEWB-kV-szT-S.js} +1 -1
- package/dist/gui/assets/{sequenceDiagram-DBY2YBRQ-Bw7wZpQ8.js → sequenceDiagram-DBY2YBRQ-C17izAQ5.js} +1 -1
- package/dist/gui/assets/{sizeCapture-X5ZJPWSS-opzemt6R.js → sizeCapture-X5ZJPWSS-Qa6aDRpG.js} +1 -1
- package/dist/gui/assets/{stateDiagram-2N3HPSRC--RB2GGES.js → stateDiagram-2N3HPSRC-C84qUVRJ.js} +1 -1
- package/dist/gui/assets/stateDiagram-v2-6OUMAXLB-Ct4b-n_-.js +1 -0
- package/dist/gui/assets/{swimlanes-5IMT3BWC-Bf3o_9Jk.js → swimlanes-5IMT3BWC-BByVALRE.js} +2 -2
- package/dist/gui/assets/swimlanesDiagram-G3AALYLV-0XnzonY2.js +8 -0
- package/dist/gui/assets/{timeline-definition-FHXFAJF6-CT2bRE0k.js → timeline-definition-FHXFAJF6-BD9jOAZN.js} +1 -1
- package/dist/gui/assets/{vennDiagram-L72KCM5P-BYzZHPMG.js → vennDiagram-L72KCM5P-BqTRSqDu.js} +1 -1
- package/dist/gui/assets/{wardleyDiagram-EHGQE667-C0QK5-46.js → wardleyDiagram-EHGQE667-DqSSn_TX.js} +1 -1
- package/dist/gui/assets/{xychartDiagram-FW5EYKEG-CD_Qgw-N.js → xychartDiagram-FW5EYKEG-B5GDvD8r.js} +1 -1
- package/dist/gui/index.html +2 -2
- package/package.json +3 -3
- package/dist/gui/assets/channel-q4TDwCwL.js +0 -1
- package/dist/gui/assets/classDiagram-OUVF2IWQ-TaYrCNs6.js +0 -1
- package/dist/gui/assets/classDiagram-v2-EOCWNBFH-TaYrCNs6.js +0 -1
- package/dist/gui/assets/index-5bFeMSvk.css +0 -1
- package/dist/gui/assets/index-TN_K4jQM.js +0 -673
- package/dist/gui/assets/stateDiagram-v2-6OUMAXLB-CvRHcdjg.js +0 -1
- package/dist/gui/assets/swimlanesDiagram-G3AALYLV-D30sOFxA.js +0 -8
package/README.md
CHANGED
|
@@ -1,82 +1,75 @@
|
|
|
1
1
|
# YorZ
|
|
2
2
|
|
|
3
|
-
English | [中文](./README_CN.md)
|
|
3
|
+
**English** | [中文](./README_CN.md)
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Why YorZ
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
YorZ (Youzi) prevents vibe coding from turning programs into black boxes;
|
|
10
|
+
YorZ solves the problem that developers do not read specs in SDD (spec-driven development) workflows.
|
|
11
|
+
|
|
12
|
+
The speed at which Agents produce documents can also overload developers with information, pushing them out of the workflow;
|
|
13
|
+
YorZ lifts the information in spec documents into a graphical representation and provides a UI tailored to SDD workflows, reducing developer load and maximizing Agent output power.
|
|
14
|
+
|
|
15
|
+

|
|
10
16
|
|
|
11
17
|
## Features
|
|
12
18
|
|
|
13
|
-
|
|
19
|
+
- Built-in lightweight SDD skill
|
|
20
|
+
- UI tailored to SDD workflows
|
|
21
|
+
- Lift Agent output information into visual diagrams to improve reading comprehension
|
|
22
|
+
- Minimize user intervention in the flow while preserving authority over key decisions
|
|
23
|
+
- Provide a deep debug mode that uses evidence chains to diagnose hard problems Agents struggle to solve
|
|
24
|
+
- Support mainstream Coding Agents including Claude Code, OpenCode, and Codex
|
|
14
25
|
|
|
15
|
-
|
|
26
|
+
[_User Guide_](./docs/User-Guide.md)
|
|
16
27
|
|
|
17
|
-
|
|
28
|
+
## Installation
|
|
18
29
|
|
|
19
30
|
```bash
|
|
20
|
-
|
|
21
|
-
```
|
|
31
|
+
pnpm add -g @yorz/cli
|
|
22
32
|
|
|
23
|
-
|
|
33
|
+
# or
|
|
24
34
|
|
|
25
|
-
|
|
26
|
-
npx -p @yorz/cli yorz <command>
|
|
35
|
+
npm install -g @yorz/cli
|
|
27
36
|
```
|
|
28
37
|
|
|
29
38
|
## Quick Start
|
|
30
39
|
|
|
31
|
-
###
|
|
40
|
+
### Start the Service
|
|
32
41
|
|
|
33
42
|
```bash
|
|
34
43
|
yorz serve
|
|
35
44
|
```
|
|
36
45
|
|
|
37
|
-
|
|
46
|
+
Start the YorZ Service. It runs in the background by default. Open `http://localhost:7423` in your browser to access the dashboard.
|
|
38
47
|
|
|
39
|
-
On startup, `yorz serve` automatically
|
|
48
|
+
On startup, `yorz serve` automatically checks the `yorz-spec` skill. When it is missing or out of date, YorZ installs or updates it for all supported Agents (Claude Code / OpenCode / Codex), then prints the result before starting the Service.
|
|
40
49
|
|
|
41
|
-
|
|
50
|
+
To stop the background service:
|
|
42
51
|
|
|
43
52
|
```bash
|
|
44
|
-
yorz serve
|
|
45
|
-
yorz serve --open # auto-open browser
|
|
46
|
-
yorz serve --foreground # run in foreground
|
|
47
|
-
yorz serve stop # stop the background service
|
|
53
|
+
yorz serve stop
|
|
48
54
|
```
|
|
49
55
|
|
|
50
|
-
###
|
|
56
|
+
### Add a Project
|
|
51
57
|
|
|
52
58
|
```bash
|
|
53
59
|
yorz add /path/to/your/project
|
|
54
60
|
```
|
|
55
61
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
The `yorz-spec` skill — which teaches your AI agent how to drive spec documents through plan / tasks / execute / done stages — is installed and kept up to date automatically by `yorz serve` (see Step 1), so there's no manual install step.
|
|
59
|
-
|
|
60
|
-
### Step 3 — Start Coding with Your Agent
|
|
62
|
+
Initialize the directory as a YorZ project by creating `.yorz/` config, registering it with the Service, and adding `.yorz/tmp` to `.gitignore`.
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
```
|
|
65
|
-
.yorz/specs/260707.feat.my-feature/spec.md
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
Then ask your agent (Claude Code / OpenCode) to process it. The skill handles the rest — the GUI updates in real-time as the agent progresses.
|
|
64
|
+
The `yorz-spec` skill teaches your AI Agent how to drive spec documents through the plan / tasks / execute / done stages. It is installed and kept up to date automatically by `yorz serve` (see Step 1), so no manual installation is required.
|
|
69
65
|
|
|
70
66
|
## Command Reference
|
|
71
67
|
|
|
72
|
-
| Command
|
|
73
|
-
|
|
|
74
|
-
| `yorz serve`
|
|
75
|
-
| `yorz serve stop`
|
|
76
|
-
| `yorz add <path>`
|
|
77
|
-
| `yorz uninstall skills` | Remove the yorz-spec skill from agents. |
|
|
78
|
-
| `yorz lint [paths...]` | Lint `spec.md` / `review.md` files for structural rules. |
|
|
79
|
-
| `yorz lint --all` | Lint every spec under the project's specs directory. |
|
|
68
|
+
| Command | Description |
|
|
69
|
+
| ----------------- | ----------------------------------------------------------------- |
|
|
70
|
+
| `yorz serve` | Start or reuse the YorZ Service in the background. Multi-project. |
|
|
71
|
+
| `yorz serve stop` | Stop the background YorZ Service. |
|
|
72
|
+
| `yorz add <path>` | Initialize and register a directory as a YorZ project. |
|
|
80
73
|
|
|
81
74
|
### Global Options
|
|
82
75
|
|
|
@@ -85,13 +78,6 @@ Then ask your agent (Claude Code / OpenCode) to process it. The skill handles th
|
|
|
85
78
|
| `-V, --version` | Print the YorZ version. |
|
|
86
79
|
| `-h, --help` | Display help for any command. |
|
|
87
80
|
|
|
88
|
-
## Documentation
|
|
89
|
-
|
|
90
|
-
- [Vision](./docs/Vision.md) — The Decision OS vision and core philosophy.
|
|
91
|
-
- [Product Design](./docs/Prod-Design.md) — Product design document.
|
|
92
|
-
- [Architecture](./docs/Architecture.md) — Technical architecture design.
|
|
93
|
-
- [Decision OS for Software Development](./docs/Decision-OS-for-Software-Development.md) — Conceptual deep dive.
|
|
94
|
-
|
|
95
81
|
## Development
|
|
96
82
|
|
|
97
83
|
```bash
|
|
@@ -101,15 +87,9 @@ pnpm install
|
|
|
101
87
|
# Build CLI + GUI
|
|
102
88
|
pnpm build
|
|
103
89
|
|
|
104
|
-
# Development mode (watch +
|
|
90
|
+
# Development mode (watch + start service)
|
|
105
91
|
pnpm dev
|
|
106
92
|
|
|
107
93
|
# Run tests
|
|
108
94
|
pnpm test
|
|
109
95
|
```
|
|
110
|
-
|
|
111
|
-
## License
|
|
112
|
-
|
|
113
|
-
[GNU Lesser General Public License v3.0 or later](./LICENSE) (LGPL-3.0-or-later)
|
|
114
|
-
|
|
115
|
-
[](https://www.gnu.org/licenses/lgpl-3.0.txt)
|
package/dist/cli/index.js
CHANGED
|
@@ -21,7 +21,7 @@ import { Codex } from "@openai/codex-sdk";
|
|
|
21
21
|
import { createOpencode } from "@opencode-ai/sdk";
|
|
22
22
|
import { createInterface as createInterface$1 } from "node:readline/promises";
|
|
23
23
|
import MarkdownIt from "markdown-it";
|
|
24
|
-
const version = "0.3.
|
|
24
|
+
const version = "0.3.5";
|
|
25
25
|
const pkg = {
|
|
26
26
|
version
|
|
27
27
|
};
|
|
@@ -620,7 +620,7 @@ function createSpecsRoutes(resolveProject) {
|
|
|
620
620
|
if (!input.title && input.requirement) {
|
|
621
621
|
const prompt = buildDraftPrompt(input.type, input.requirement, input.draftId);
|
|
622
622
|
const { sessionId } = await p.sessions.createSession();
|
|
623
|
-
const handle = p.sessions.send(sessionId, prompt);
|
|
623
|
+
const handle = await p.sessions.send(sessionId, prompt);
|
|
624
624
|
return c.json({ runId: handle.runId, sessionId, draft: true }, 202);
|
|
625
625
|
}
|
|
626
626
|
try {
|
|
@@ -748,7 +748,7 @@ function createSpecsRoutes(resolveProject) {
|
|
|
748
748
|
const { sessionId } = await p.sessions.ensureSessionForSpec(specId);
|
|
749
749
|
const debugActive = await readDebugMdStatus(join(p.specsDir, specId)) === "debugging";
|
|
750
750
|
const prompt = parsed.debug ? buildDebugPrompt(p.specsDirRelative, specId, "new") : debugActive ? buildDebugPrompt(p.specsDirRelative, specId, "resume") : `请使用 yorz-spec skill 处理 spec:${p.specsDirRelative}/${specId}/spec.md`;
|
|
751
|
-
const handle = p.sessions.send(sessionId, prompt);
|
|
751
|
+
const handle = await p.sessions.send(sessionId, prompt);
|
|
752
752
|
return c.json({ ok: true, runId: handle.runId, sessionId });
|
|
753
753
|
}
|
|
754
754
|
return c.json({ ok: true });
|
|
@@ -762,7 +762,7 @@ function createSpecsRoutes(resolveProject) {
|
|
|
762
762
|
const { sessionId } = await p.sessions.ensureSessionForSpec(specId);
|
|
763
763
|
const debugActive = await readDebugMdStatus(join(p.specsDir, specId)) === "debugging";
|
|
764
764
|
const prompt = debugActive ? buildDebugPrompt(p.specsDirRelative, specId, "resume") : `请使用 yorz-spec skill 处理 spec:${p.specsDirRelative}/${specId}/spec.md`;
|
|
765
|
-
const handle = p.sessions.send(sessionId, prompt);
|
|
765
|
+
const handle = await p.sessions.send(sessionId, prompt);
|
|
766
766
|
return c.json({ runId: handle.runId, sessionId });
|
|
767
767
|
});
|
|
768
768
|
app.post("/projects/:projectId/specs/:id/explain", async (c) => {
|
|
@@ -793,7 +793,7 @@ ${text}
|
|
|
793
793
|
"""
|
|
794
794
|
`;
|
|
795
795
|
const { sessionId } = await p.sessions.ensureSessionForSpec(specId);
|
|
796
|
-
const handle = p.sessions.send(sessionId, prompt);
|
|
796
|
+
const handle = await p.sessions.send(sessionId, prompt);
|
|
797
797
|
return c.json({ runId: handle.runId, sessionId });
|
|
798
798
|
});
|
|
799
799
|
app.delete("/projects/:projectId/specs/:id", async (c) => {
|
|
@@ -1085,7 +1085,7 @@ function createSessionsRoutes(resolveProject) {
|
|
|
1085
1085
|
finalPrompt = buildChatPrompt(prompt, draftId, metas);
|
|
1086
1086
|
}
|
|
1087
1087
|
}
|
|
1088
|
-
const handle = p.sessions.send(c.req.param("sid"), finalPrompt);
|
|
1088
|
+
const handle = await p.sessions.send(c.req.param("sid"), finalPrompt);
|
|
1089
1089
|
return c.json({ runId: handle.runId, sessionId: handle.sessionId }, 202);
|
|
1090
1090
|
});
|
|
1091
1091
|
app.post("/projects/:projectId/sessions/:sid/abort", async (c) => {
|
|
@@ -1301,7 +1301,7 @@ function createSpecReviewRoutes(resolveProject) {
|
|
|
1301
1301
|
- 触发时间使用本机当前时间,格式 \`YYYY-MM-DD HH:mm:ss\`
|
|
1302
1302
|
`;
|
|
1303
1303
|
const { sessionId } = await p.sessions.ensureSessionForSpec(specId);
|
|
1304
|
-
const handle = p.sessions.send(sessionId, prompt);
|
|
1304
|
+
const handle = await p.sessions.send(sessionId, prompt);
|
|
1305
1305
|
return c.json({ runId: handle.runId, sessionId });
|
|
1306
1306
|
});
|
|
1307
1307
|
app.post("/projects/:projectId/specs/:id/git", async (c) => {
|
|
@@ -1324,7 +1324,7 @@ function createSpecReviewRoutes(resolveProject) {
|
|
|
1324
1324
|
const reviewRel = `${p.specsDirRelative}/${specId}/review.md`;
|
|
1325
1325
|
const prompt = buildGitOpsPrompt(action, specId, specRel, reviewRel);
|
|
1326
1326
|
const { sessionId } = await p.sessions.ensureSessionForSpec(specId);
|
|
1327
|
-
const handle = p.sessions.send(sessionId, prompt);
|
|
1327
|
+
const handle = await p.sessions.send(sessionId, prompt);
|
|
1328
1328
|
return c.json({ runId: handle.runId, sessionId });
|
|
1329
1329
|
});
|
|
1330
1330
|
app.get("/projects/:projectId/specs/:id/review", async (c) => {
|
|
@@ -2193,18 +2193,46 @@ const IGNORE_FILES = /* @__PURE__ */ new Set([".DS_Store", "Thumbs.db"]);
|
|
|
2193
2193
|
const MAX_RESULTS = 100;
|
|
2194
2194
|
const MAX_DEPTH = 15;
|
|
2195
2195
|
const MAX_SCAN = 5e3;
|
|
2196
|
+
const SCORE_MATCH = 16;
|
|
2197
|
+
const SCORE_CASE_MATCH = 2;
|
|
2198
|
+
const SCORE_BOUNDARY = 8;
|
|
2199
|
+
const SCORE_CONSECUTIVE = 24;
|
|
2200
|
+
const PENALTY_LEADING_CAP = 32;
|
|
2196
2201
|
function toPosix(p) {
|
|
2197
2202
|
return p.split(sep).join("/");
|
|
2198
2203
|
}
|
|
2199
|
-
function
|
|
2200
|
-
if (
|
|
2204
|
+
function isBoundary(target, index) {
|
|
2205
|
+
if (index === 0) return true;
|
|
2206
|
+
return /[/_.-]/.test(target[index - 1] ?? "");
|
|
2207
|
+
}
|
|
2208
|
+
function scoreFuzzyPath(query2, target) {
|
|
2209
|
+
if (!query2) return 0;
|
|
2201
2210
|
const q = query2.toLowerCase();
|
|
2202
2211
|
const t = target.toLowerCase();
|
|
2203
|
-
let
|
|
2204
|
-
for (let
|
|
2205
|
-
|
|
2212
|
+
let prev = [];
|
|
2213
|
+
for (let qi = 0; qi < q.length; qi++) {
|
|
2214
|
+
const current = new Array(t.length).fill(Number.NEGATIVE_INFINITY);
|
|
2215
|
+
let bestPrev = Number.NEGATIVE_INFINITY;
|
|
2216
|
+
for (let ti = 0; ti < t.length; ti++) {
|
|
2217
|
+
if (qi > 0 && prev[ti - 1] !== void 0) {
|
|
2218
|
+
bestPrev = Math.max(bestPrev, prev[ti - 1] + ti);
|
|
2219
|
+
}
|
|
2220
|
+
if (t[ti] !== q[qi]) continue;
|
|
2221
|
+
const base = SCORE_MATCH + (target[ti] === query2[qi] ? SCORE_CASE_MATCH : 0) + (isBoundary(target, ti) ? SCORE_BOUNDARY : 0);
|
|
2222
|
+
if (qi === 0) {
|
|
2223
|
+
current[ti] = base - Math.min(ti, PENALTY_LEADING_CAP);
|
|
2224
|
+
} else {
|
|
2225
|
+
const consecutive = ti > 0 && Number.isFinite(prev[ti - 1]) ? prev[ti - 1] + base + SCORE_CONSECUTIVE : Number.NEGATIVE_INFINITY;
|
|
2226
|
+
const gapped = Number.isFinite(bestPrev) ? bestPrev + base - ti : Number.NEGATIVE_INFINITY;
|
|
2227
|
+
current[ti] = Math.max(consecutive, gapped);
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
if (!current.some(Number.isFinite)) return null;
|
|
2231
|
+
prev = current;
|
|
2206
2232
|
}
|
|
2207
|
-
|
|
2233
|
+
const best = Math.max(...prev);
|
|
2234
|
+
if (!Number.isFinite(best)) return null;
|
|
2235
|
+
return best - target.length * 0.01;
|
|
2208
2236
|
}
|
|
2209
2237
|
function globToRegex(pattern) {
|
|
2210
2238
|
let p = pattern.trim();
|
|
@@ -2264,12 +2292,13 @@ async function walk(root, dir, query2, ignoreStack, results, scanCount, depth) {
|
|
|
2264
2292
|
} else if (entry.isFile()) {
|
|
2265
2293
|
if (IGNORE_FILES.has(entry.name)) continue;
|
|
2266
2294
|
if (isIgnored(relPath, combined)) continue;
|
|
2267
|
-
|
|
2295
|
+
const score = scoreFuzzyPath(query2, relPath);
|
|
2296
|
+
if (score === null) continue;
|
|
2268
2297
|
try {
|
|
2269
2298
|
const s = await stat(fullPath);
|
|
2270
|
-
results.push({ path: relPath, depth, mtime: s.mtimeMs });
|
|
2299
|
+
results.push({ path: relPath, depth, mtime: s.mtimeMs, score });
|
|
2271
2300
|
} catch {
|
|
2272
|
-
results.push({ path: relPath, depth, mtime: 0 });
|
|
2301
|
+
results.push({ path: relPath, depth, mtime: 0, score });
|
|
2273
2302
|
}
|
|
2274
2303
|
}
|
|
2275
2304
|
}
|
|
@@ -2297,6 +2326,7 @@ function createProjectFilesRoutes(resolveProject) {
|
|
|
2297
2326
|
await walk(p.path, p.path, query2, [], results, scanCount, 0);
|
|
2298
2327
|
if (query2) {
|
|
2299
2328
|
results.sort((a, b) => {
|
|
2329
|
+
if (a.score !== b.score) return b.score - a.score;
|
|
2300
2330
|
if (a.depth !== b.depth) return a.depth - b.depth;
|
|
2301
2331
|
return a.path.localeCompare(b.path);
|
|
2302
2332
|
});
|
|
@@ -2904,7 +2934,7 @@ function createApp(opts) {
|
|
|
2904
2934
|
return;
|
|
2905
2935
|
}
|
|
2906
2936
|
const { sessionId } = await main.sessions.ensureSessionForSpec(specId);
|
|
2907
|
-
main.sessions.send(
|
|
2937
|
+
void main.sessions.send(
|
|
2908
2938
|
sessionId,
|
|
2909
2939
|
`请使用 yorz-spec skill 处理 spec:${main.specsDirRelative}/${specId}/spec.md`
|
|
2910
2940
|
);
|
|
@@ -3533,6 +3563,8 @@ class ClaudeSession {
|
|
|
3533
3563
|
else options.resume = this.id;
|
|
3534
3564
|
try {
|
|
3535
3565
|
const q = query({ prompt, options });
|
|
3566
|
+
let usage;
|
|
3567
|
+
let completed = false;
|
|
3536
3568
|
for await (const msg of q) {
|
|
3537
3569
|
const m = msg;
|
|
3538
3570
|
if (!this.started && typeof m.session_id === "string") {
|
|
@@ -3555,9 +3587,13 @@ class ClaudeSession {
|
|
|
3555
3587
|
}
|
|
3556
3588
|
}
|
|
3557
3589
|
} else if (m.type === "result") {
|
|
3558
|
-
|
|
3590
|
+
usage = m.usage;
|
|
3591
|
+
} else if (m.type === "system" && m.subtype === "session_state_changed" && m.state === "idle") {
|
|
3592
|
+
completed = true;
|
|
3593
|
+
yield { type: "turn-completed", usage };
|
|
3559
3594
|
}
|
|
3560
3595
|
}
|
|
3596
|
+
if (!completed) yield { type: "turn-completed", usage };
|
|
3561
3597
|
} catch (err) {
|
|
3562
3598
|
if (ctrl.signal.aborted) return;
|
|
3563
3599
|
yield { type: "error", message: err instanceof Error ? err.message : String(err) };
|
|
@@ -3614,7 +3650,8 @@ class ClaudeAdapter {
|
|
|
3614
3650
|
return { listSessions: true, getMessages: true };
|
|
3615
3651
|
}
|
|
3616
3652
|
}
|
|
3617
|
-
const
|
|
3653
|
+
const DEFAULT_CODEX_STORAGE_ROOT = join(homedir(), ".codex");
|
|
3654
|
+
const TITLE_MAX_LENGTH$1 = 64;
|
|
3618
3655
|
function codexThreadOptions(cwd) {
|
|
3619
3656
|
return {
|
|
3620
3657
|
workingDirectory: cwd,
|
|
@@ -3636,6 +3673,40 @@ function detectAgentContextKind(text) {
|
|
|
3636
3673
|
}
|
|
3637
3674
|
return void 0;
|
|
3638
3675
|
}
|
|
3676
|
+
function textFromMessagePayload(payload) {
|
|
3677
|
+
const content = payload.content;
|
|
3678
|
+
if (!Array.isArray(content)) return "";
|
|
3679
|
+
const parts = [];
|
|
3680
|
+
for (const c of content) {
|
|
3681
|
+
const text = c?.text;
|
|
3682
|
+
if (typeof text === "string" && text.trim()) parts.push(text);
|
|
3683
|
+
}
|
|
3684
|
+
return parts.join("\n").trim();
|
|
3685
|
+
}
|
|
3686
|
+
function summarizeCodexPromptForTitle(text) {
|
|
3687
|
+
const [body] = text.split(/^\s*---\s*$/m);
|
|
3688
|
+
const cleaned = body.split("\n").map((line) => line.trim()).filter((line) => line && line !== "---" && !line.startsWith("- ![") && !line.startsWith("- [")).join(" ").replace(/`([^`]+)`/g, "$1").replace(/!\[[^\]]*]\([^)]+\)/g, "").replace(/\[([^\]]+)]\([^)]+\)/g, "$1").replace(/[@#>*_~]/g, "").replace(/\s+/g, " ").trim();
|
|
3689
|
+
if (!cleaned) return "";
|
|
3690
|
+
return cleaned.length > TITLE_MAX_LENGTH$1 ? `${cleaned.slice(0, TITLE_MAX_LENGTH$1 - 1)}…` : cleaned;
|
|
3691
|
+
}
|
|
3692
|
+
function parseCodexSessionIndex(text) {
|
|
3693
|
+
const out = /* @__PURE__ */ new Map();
|
|
3694
|
+
for (const line of text.split("\n")) {
|
|
3695
|
+
const trimmed = line.trim();
|
|
3696
|
+
if (!trimmed) continue;
|
|
3697
|
+
let obj;
|
|
3698
|
+
try {
|
|
3699
|
+
obj = JSON.parse(trimmed);
|
|
3700
|
+
} catch {
|
|
3701
|
+
continue;
|
|
3702
|
+
}
|
|
3703
|
+
const rec = obj;
|
|
3704
|
+
const id = typeof rec.id === "string" ? rec.id.trim() : "";
|
|
3705
|
+
const title = typeof rec.thread_name === "string" ? rec.thread_name.trim() : "";
|
|
3706
|
+
if (id && title) out.set(id, title);
|
|
3707
|
+
}
|
|
3708
|
+
return out;
|
|
3709
|
+
}
|
|
3639
3710
|
class CodexSession {
|
|
3640
3711
|
constructor(thread) {
|
|
3641
3712
|
this.thread = thread;
|
|
@@ -3693,8 +3764,9 @@ class CodexSession {
|
|
|
3693
3764
|
}
|
|
3694
3765
|
}
|
|
3695
3766
|
class CodexAdapter {
|
|
3696
|
-
constructor(cwd) {
|
|
3767
|
+
constructor(cwd, storageRoot = DEFAULT_CODEX_STORAGE_ROOT) {
|
|
3697
3768
|
this.cwd = cwd;
|
|
3769
|
+
this.storageRoot = storageRoot;
|
|
3698
3770
|
this.codex = new Codex();
|
|
3699
3771
|
}
|
|
3700
3772
|
kind = "codex";
|
|
@@ -3708,9 +3780,10 @@ class CodexAdapter {
|
|
|
3708
3780
|
/** Walk ~/.codex/sessions, keep rollouts whose session_meta.cwd matches this project. */
|
|
3709
3781
|
async listSessions() {
|
|
3710
3782
|
const files = await this.walkRollouts();
|
|
3783
|
+
const titleIndex = await this.readSessionIndex();
|
|
3711
3784
|
const out = [];
|
|
3712
3785
|
for (const file of files) {
|
|
3713
|
-
const meta = await this.readMeta(file);
|
|
3786
|
+
const meta = await this.readMeta(file, titleIndex);
|
|
3714
3787
|
if (!meta || meta.cwd !== this.cwd) continue;
|
|
3715
3788
|
out.push({
|
|
3716
3789
|
id: meta.id,
|
|
@@ -3748,9 +3821,7 @@ class CodexAdapter {
|
|
|
3748
3821
|
const text = c?.text;
|
|
3749
3822
|
if (typeof text === "string" && text) {
|
|
3750
3823
|
const contextKind = role === "user" ? detectAgentContextKind(text) : void 0;
|
|
3751
|
-
parts.push(
|
|
3752
|
-
contextKind ? { type: "text", text, contextKind } : { type: "text", text }
|
|
3753
|
-
);
|
|
3824
|
+
parts.push(contextKind ? { type: "text", text, contextKind } : { type: "text", text });
|
|
3754
3825
|
}
|
|
3755
3826
|
}
|
|
3756
3827
|
}
|
|
@@ -3777,12 +3848,23 @@ class CodexAdapter {
|
|
|
3777
3848
|
out.push(full);
|
|
3778
3849
|
}
|
|
3779
3850
|
};
|
|
3780
|
-
await walk2(
|
|
3851
|
+
await walk2(join(this.storageRoot, "sessions"));
|
|
3781
3852
|
return out;
|
|
3782
3853
|
}
|
|
3783
|
-
async
|
|
3854
|
+
async readSessionIndex() {
|
|
3855
|
+
try {
|
|
3856
|
+
return parseCodexSessionIndex(
|
|
3857
|
+
await readFile(join(this.storageRoot, "session_index.jsonl"), "utf8")
|
|
3858
|
+
);
|
|
3859
|
+
} catch {
|
|
3860
|
+
return /* @__PURE__ */ new Map();
|
|
3861
|
+
}
|
|
3862
|
+
}
|
|
3863
|
+
async readMeta(file, titleIndex) {
|
|
3784
3864
|
return new Promise((resolve2) => {
|
|
3785
3865
|
let settled = false;
|
|
3866
|
+
let meta = null;
|
|
3867
|
+
let title = "";
|
|
3786
3868
|
const finish = (v) => {
|
|
3787
3869
|
if (settled) return;
|
|
3788
3870
|
settled = true;
|
|
@@ -3803,25 +3885,33 @@ class CodexAdapter {
|
|
|
3803
3885
|
return;
|
|
3804
3886
|
}
|
|
3805
3887
|
const rec = obj;
|
|
3806
|
-
if (rec.type
|
|
3807
|
-
|
|
3888
|
+
if (rec.type === "session_meta" && rec.payload) {
|
|
3889
|
+
const id = String(rec.payload.id ?? "");
|
|
3890
|
+
const cwd = String(rec.payload.cwd ?? "");
|
|
3891
|
+
const tsRaw = rec.payload.timestamp;
|
|
3892
|
+
const ts = typeof tsRaw === "string" ? Date.parse(tsRaw) : Date.now();
|
|
3893
|
+
meta = { id, cwd, ts: Number.isNaN(ts) ? Date.now() : ts };
|
|
3808
3894
|
return;
|
|
3809
3895
|
}
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
const
|
|
3813
|
-
|
|
3814
|
-
|
|
3896
|
+
if (!meta || title || rec.type !== "response_item" || !rec.payload) return;
|
|
3897
|
+
if (rec.payload.type !== "message" || rec.payload.role !== "user") return;
|
|
3898
|
+
const text = textFromMessagePayload(rec.payload);
|
|
3899
|
+
if (!text || detectAgentContextKind(text)) return;
|
|
3900
|
+
title = summarizeCodexPromptForTitle(text);
|
|
3901
|
+
});
|
|
3902
|
+
rl.on("close", () => {
|
|
3903
|
+
if (!meta) finish(null);
|
|
3904
|
+
else finish({ ...meta, title: titleIndex.get(meta.id) || title || meta.id });
|
|
3815
3905
|
});
|
|
3816
|
-
rl.on("close", () => finish(null));
|
|
3817
3906
|
});
|
|
3818
3907
|
}
|
|
3819
3908
|
async findFileById(id) {
|
|
3820
3909
|
const files = await this.walkRollouts();
|
|
3821
3910
|
const match = files.find((f) => f.includes(id));
|
|
3822
3911
|
if (match) return match;
|
|
3912
|
+
const titleIndex = await this.readSessionIndex();
|
|
3823
3913
|
for (const f of files) {
|
|
3824
|
-
const meta = await this.readMeta(f);
|
|
3914
|
+
const meta = await this.readMeta(f, titleIndex);
|
|
3825
3915
|
if (meta?.id === id) return f;
|
|
3826
3916
|
}
|
|
3827
3917
|
return null;
|
|
@@ -3983,6 +4073,18 @@ class AdapterRegistry {
|
|
|
3983
4073
|
}
|
|
3984
4074
|
}
|
|
3985
4075
|
const SESSION_LIST_LIMIT = 30;
|
|
4076
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
4077
|
+
const TITLE_MAX_LENGTH = 64;
|
|
4078
|
+
function isOpaqueTitle(title, id) {
|
|
4079
|
+
const t = title?.trim();
|
|
4080
|
+
return !t || t === id || UUID_RE.test(t);
|
|
4081
|
+
}
|
|
4082
|
+
function summarizePromptForTitle(prompt) {
|
|
4083
|
+
const [body] = prompt.split(/^\s*---\s*$/m);
|
|
4084
|
+
const cleaned = body.split("\n").map((line) => line.trim()).filter((line) => line && line !== "---" && !line.startsWith("- ![") && !line.startsWith("- [")).join(" ").replace(/`([^`]+)`/g, "$1").replace(/!\[[^\]]*]\([^)]+\)/g, "").replace(/\[([^\]]+)]\([^)]+\)/g, "$1").replace(/[@#>*_~]/g, "").replace(/\s+/g, " ").trim();
|
|
4085
|
+
if (!cleaned) return "";
|
|
4086
|
+
return cleaned.length > TITLE_MAX_LENGTH ? `${cleaned.slice(0, TITLE_MAX_LENGTH - 1)}…` : cleaned;
|
|
4087
|
+
}
|
|
3986
4088
|
class SessionManager {
|
|
3987
4089
|
constructor(cwd, defaultKind, store) {
|
|
3988
4090
|
this.cwd = cwd;
|
|
@@ -4012,7 +4114,7 @@ class SessionManager {
|
|
|
4012
4114
|
const session = await adapter.createSession(title ? { title } : void 0);
|
|
4013
4115
|
const sessionId = session.id || randomUUID();
|
|
4014
4116
|
this.live.set(sessionId, { kind: k, session });
|
|
4015
|
-
await this.store.create(k, sessionId, title ??
|
|
4117
|
+
await this.store.create(k, sessionId, title ?? "", specId);
|
|
4016
4118
|
return { sessionId, kind: k };
|
|
4017
4119
|
}
|
|
4018
4120
|
/**
|
|
@@ -4047,7 +4149,17 @@ class SessionManager {
|
|
|
4047
4149
|
try {
|
|
4048
4150
|
for (const info of await adapter.listSessions()) {
|
|
4049
4151
|
nativeIds.add(info.id);
|
|
4050
|
-
|
|
4152
|
+
const indexed2 = byId.get(info.id);
|
|
4153
|
+
if (!indexed2) {
|
|
4154
|
+
byId.set(info.id, info);
|
|
4155
|
+
} else if (isOpaqueTitle(indexed2.title, indexed2.id) && !isOpaqueTitle(info.title, info.id)) {
|
|
4156
|
+
byId.set(info.id, {
|
|
4157
|
+
...indexed2,
|
|
4158
|
+
title: info.title,
|
|
4159
|
+
createdAt: Math.min(indexed2.createdAt, info.createdAt),
|
|
4160
|
+
updatedAt: Math.max(indexed2.updatedAt, info.updatedAt)
|
|
4161
|
+
});
|
|
4162
|
+
}
|
|
4051
4163
|
}
|
|
4052
4164
|
} catch {
|
|
4053
4165
|
}
|
|
@@ -4076,6 +4188,13 @@ class SessionManager {
|
|
|
4076
4188
|
else this.running.delete(sid);
|
|
4077
4189
|
this.statusEmitter.emit("status", { sessionId: sid, running });
|
|
4078
4190
|
}
|
|
4191
|
+
async maybeUpdateTitleFromPrompt(sid, prompt) {
|
|
4192
|
+
const indexed = await this.store.get(sid);
|
|
4193
|
+
if (!indexed || !isOpaqueTitle(indexed.title, indexed.id)) return;
|
|
4194
|
+
const title = summarizePromptForTitle(prompt);
|
|
4195
|
+
if (!title || isOpaqueTitle(title, sid)) return;
|
|
4196
|
+
await this.store.updateTitle(sid, title);
|
|
4197
|
+
}
|
|
4079
4198
|
async getMessages(sid) {
|
|
4080
4199
|
const kind = (await this.store.get(sid))?.kind ?? this.live.get(sid)?.kind ?? this.defaultKind;
|
|
4081
4200
|
const adapter = this.adapters.get(kind);
|
|
@@ -4092,10 +4211,12 @@ class SessionManager {
|
|
|
4092
4211
|
this.live.set(sid, ls);
|
|
4093
4212
|
return ls;
|
|
4094
4213
|
}
|
|
4095
|
-
send(sid, prompt) {
|
|
4214
|
+
async send(sid, prompt) {
|
|
4096
4215
|
const runId = randomUUID();
|
|
4097
4216
|
const emitter = this.emitterFor(sid);
|
|
4098
4217
|
let currentSid = sid;
|
|
4218
|
+
await this.maybeUpdateTitleFromPrompt(currentSid, prompt).catch(() => {
|
|
4219
|
+
});
|
|
4099
4220
|
this.setRunning(sid, true);
|
|
4100
4221
|
void (async () => {
|
|
4101
4222
|
try {
|
package/dist/gui/assets/{abnfDiagram-VRR7QNED-Dvg_gtwF.js → abnfDiagram-VRR7QNED-DQM-IUdR.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{g as p,r as u,d as a}from"./chunk-MOJQB5TN-
|
|
1
|
+
import{g as p,r as u,d as a}from"./chunk-MOJQB5TN-OoM3V1FE.js";import{p as f}from"./chunk-JWPE2WC7-Dp9usWZX.js";import{_ as n,l as o}from"./mermaid.core-BO-VJXe-.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-buyB6Ypi.js";import"./index-BnMXI8QL.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}},B={parser:R,db:a,renderer:u,styles:p};export{B as diagram};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Y as ln,$ as an,a0 as F,a1 as q,a2 as j,a3 as un,a4 as y,a5 as tn,a6 as J,a7 as _,a8 as rn,a9 as o,aa as on,ab as sn,ac as fn}from"./mermaid.core-
|
|
1
|
+
import{Y as ln,$ as an,a0 as F,a1 as q,a2 as j,a3 as un,a4 as y,a5 as tn,a6 as J,a7 as _,a8 as rn,a9 as o,aa as on,ab as sn,ac as fn}from"./mermaid.core-BO-VJXe-.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,z,a){var O=I-l,i=D-h,n=z-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 U(l,h,I,D,v,A,z){var a=l-I,O=h-D,i=(z?A:-A)/J(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,B=(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)*J(on(0,T*T*R-P*P)),Y=(P*g-m*S)/R,$=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=Y-B,e=$-t,r=w-B,C=p-t;return x*x+e*e>r*r+C*C&&(Y=w,$=p),{cx:Y,cy:$,x01:-n,y01:-d,x11:Y*(v/T-1),y11:$*(v/T-1)}}function hn(){var l=cn,h=yn,I=j(0),D=null,v=gn,A=dn,z=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)-un,c=A.apply(this,arguments)-un,B=rn(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(B>tn-y)a.moveTo(s*F(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*F(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=B,S=B,Y=z.apply(this,arguments)/2,$=Y>y&&(D?+D.apply(this,arguments):J(u*u+s*s)),w=_(rn(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if($>y){var C=sn($/u*q(Y)),K=sn($/s*q(Y));(P-=C*2)>y?(C*=t?1:-1,R+=C,T-=C):(P=0,R=T=(f+c)/2),(S-=K*2)>y?(K*=t?1:-1,m+=K,g-=K):(S=0,m=g=(f+c)/2)}var G=s*F(m),H=s*q(m),L=u*F(T),M=u*q(T);if(w>y){var N=s*F(g),Q=s*q(g),V=u*F(R),W=u*q(R),E;if(B<an)if(E=pn(G,H,V,W,N,Q,L,M)){var X=G-E[0],Z=H-E[1],b=N-E[0],k=Q-E[1],nn=1/q(fn((X*b+Z*k)/(J(X*X+Z*Z)*J(b*b+k*k)))/2),en=J(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=U(V,W,G,H,s,x,t),r=U(N,Q,L,M,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(G,H),a.arc(0,0,s,m,g,!t)):a.moveTo(G,H),!(u>y)||!(P>y)?a.lineTo(L,M):p>y?(e=U(L,M,N,Q,u,-p,t),r=U(G,H,V,W,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-an/2;return[F(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:j(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:j(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:j(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:j(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:j(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:j(+n),i):A},i.padAngle=function(n){return arguments.length?(z=typeof n=="function"?n:j(+n),i):z},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};
|