yycode 0.3.2__py3-none-any.whl
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.
- agent/__init__.py +33 -0
- agent/acp/__init__.py +2 -0
- agent/acp/approval_adapter.py +134 -0
- agent/acp/content_adapter.py +45 -0
- agent/acp/jsonrpc.py +92 -0
- agent/acp/server.py +197 -0
- agent/acp/session_manager.py +193 -0
- agent/acp/update_adapter.py +192 -0
- agent/app_paths.py +25 -0
- agent/approval.py +169 -0
- agent/cancellation.py +52 -0
- agent/change_snapshot.py +186 -0
- agent/context_compressor.py +116 -0
- agent/graph.py +137 -0
- agent/llm_retry.py +434 -0
- agent/logger.py +97 -0
- agent/lsp/__init__.py +13 -0
- agent/lsp/client.py +151 -0
- agent/lsp/manager.py +234 -0
- agent/lsp/types.py +119 -0
- agent/message_context_manager.py +322 -0
- agent/message_format.py +105 -0
- agent/nodes/llm_node.py +58 -0
- agent/nodes/state.py +12 -0
- agent/nodes/task_guard_node.py +50 -0
- agent/nodes/tools_node.py +70 -0
- agent/plan_snapshot.py +70 -0
- agent/providers/__init__.py +13 -0
- agent/providers/anthropic_provider.py +268 -0
- agent/providers/base.py +52 -0
- agent/providers/openai_provider.py +279 -0
- agent/providers/text_tool_calls.py +118 -0
- agent/runtime/approval_service.py +184 -0
- agent/runtime/context.py +43 -0
- agent/runtime/tool_events.py +368 -0
- agent/runtime/tool_executor.py +208 -0
- agent/runtime/tool_output.py +261 -0
- agent/runtime/tool_registry.py +91 -0
- agent/runtime/tool_scheduler.py +35 -0
- agent/runtime/workflow_guard.py +217 -0
- agent/runtime/workspace.py +5 -0
- agent/runtime/workspace_tools.py +22 -0
- agent/session.py +787 -0
- agent/session_replay.py +95 -0
- agent/session_store.py +186 -0
- agent/skills.py +254 -0
- agent/streaming.py +248 -0
- agent/subagent.py +634 -0
- agent/task_memory.py +340 -0
- agent/todo_manager.py +304 -0
- agent/tool_retry.py +106 -0
- agent/tui/__init__.py +14 -0
- agent/tui/app.py +1325 -0
- agent/tui/approval.py +53 -0
- agent/tui/commands/__init__.py +6 -0
- agent/tui/commands/base.py +48 -0
- agent/tui/commands/clear.py +37 -0
- agent/tui/commands/help.py +27 -0
- agent/tui/commands/registry.py +94 -0
- agent/tui/help_content.py +108 -0
- agent/tui/renderers.py +1961 -0
- agent/tui/runner.py +439 -0
- agent/tui/state.py +653 -0
- main.py +465 -0
- tools/__init__.py +50 -0
- tools/apply_patch.py +305 -0
- tools/bash.py +76 -0
- tools/diff_utils.py +139 -0
- tools/edit_file.py +40 -0
- tools/git_diff.py +72 -0
- tools/git_show.py +65 -0
- tools/grep.py +149 -0
- tools/list_files.py +90 -0
- tools/list_skills.py +24 -0
- tools/load_skill.py +30 -0
- tools/lsp_definition.py +27 -0
- tools/lsp_diagnostics.py +32 -0
- tools/lsp_document_symbols.py +23 -0
- tools/lsp_hover.py +29 -0
- tools/lsp_references.py +37 -0
- tools/lsp_utils.py +38 -0
- tools/lsp_workspace_symbols.py +23 -0
- tools/read_file.py +61 -0
- tools/read_many_files.py +50 -0
- tools/safety.py +50 -0
- tools/subagent.py +57 -0
- tools/todo.py +89 -0
- tools/verify.py +107 -0
- tools/web_search.py +250 -0
- tools/workspace.py +36 -0
- tools/workspace_state.py +60 -0
- tools/write_file.py +88 -0
- utils/__init__.py +5 -0
- utils/retry.py +13 -0
- yycode-0.3.2.data/data/skills/code_review.md +61 -0
- yycode-0.3.2.data/data/skills/code_workflow.md +404 -0
- yycode-0.3.2.data/data/skills/drawio/SKILL.md +636 -0
- yycode-0.3.2.data/data/skills/drawio/agents/openai.yaml +19 -0
- yycode-0.3.2.data/data/skills/drawio/assets/demo-erd.drawio +84 -0
- yycode-0.3.2.data/data/skills/drawio/assets/demo-layered-cn.drawio +91 -0
- yycode-0.3.2.data/data/skills/drawio/assets/demo-layered-cn.png +0 -0
- yycode-0.3.2.data/data/skills/drawio/assets/demo-layered.drawio +112 -0
- yycode-0.3.2.data/data/skills/drawio/assets/demo-layered.png +0 -0
- yycode-0.3.2.data/data/skills/drawio/assets/demo-ml.drawio +90 -0
- yycode-0.3.2.data/data/skills/drawio/assets/demo-ring-cn.drawio +68 -0
- yycode-0.3.2.data/data/skills/drawio/assets/demo-ring-cn.png +0 -0
- yycode-0.3.2.data/data/skills/drawio/assets/demo-ring.drawio +86 -0
- yycode-0.3.2.data/data/skills/drawio/assets/demo-ring.png +0 -0
- yycode-0.3.2.data/data/skills/drawio/assets/demo-sequence.drawio +116 -0
- yycode-0.3.2.data/data/skills/drawio/assets/demo-star-cn.drawio +66 -0
- yycode-0.3.2.data/data/skills/drawio/assets/demo-star-cn.png +0 -0
- yycode-0.3.2.data/data/skills/drawio/assets/demo-star.drawio +79 -0
- yycode-0.3.2.data/data/skills/drawio/assets/demo-star.png +0 -0
- yycode-0.3.2.data/data/skills/drawio/assets/demo-uml-class.drawio +64 -0
- yycode-0.3.2.data/data/skills/drawio/assets/microservices-example.drawio +173 -0
- yycode-0.3.2.data/data/skills/drawio/assets/microservices-example.png +0 -0
- yycode-0.3.2.data/data/skills/drawio/assets/workflow-cn.drawio +120 -0
- yycode-0.3.2.data/data/skills/drawio/assets/workflow-cn.png +0 -0
- yycode-0.3.2.data/data/skills/drawio/assets/workflow.drawio +120 -0
- yycode-0.3.2.data/data/skills/drawio/assets/workflow.png +0 -0
- yycode-0.3.2.data/data/skills/drawio/docs/index.html +469 -0
- yycode-0.3.2.data/data/skills/drawio/docs/zh.html +456 -0
- yycode-0.3.2.data/data/skills/drawio/references/style-extraction.md +254 -0
- yycode-0.3.2.data/data/skills/drawio/styles/schema.json +112 -0
- yycode-0.3.2.data/data/skills/plan.md +115 -0
- yycode-0.3.2.data/data/skills/ppt/SKILL.md +254 -0
- yycode-0.3.2.dist-info/METADATA +12 -0
- yycode-0.3.2.dist-info/RECORD +131 -0
- yycode-0.3.2.dist-info/WHEEL +5 -0
- yycode-0.3.2.dist-info/entry_points.txt +2 -0
- yycode-0.3.2.dist-info/top_level.txt +4 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
# Style Extraction — agent reference
|
|
2
|
+
|
|
3
|
+
Loaded on demand by `SKILL.md` when the user asks to learn a style ("learn my style from `<path>` as `<name>`") or when the agent needs to render a sample after extraction.
|
|
4
|
+
|
|
5
|
+
## Sample diagram (for approval render)
|
|
6
|
+
|
|
7
|
+
After extracting a candidate preset, render this seven-node sample using the candidate's palette/shapes/fonts/edges. Each role appears exactly once; six edges, one dashed, exercise `edges.arrow`, `edges.style`, and `edges.dashedFor`.
|
|
8
|
+
|
|
9
|
+
**Layout (TB):**
|
|
10
|
+
- Row 1 (y=40): `gateway` centered at x=340
|
|
11
|
+
- Row 2 (y=180): `security` (x=80), `service` (x=340), `queue` (x=600)
|
|
12
|
+
- Row 3 (y=340): `database` (x=80), `external` (x=340), `error` (x=600)
|
|
13
|
+
|
|
14
|
+
**Template — substitute `{{...}}` placeholders from the candidate preset.**
|
|
15
|
+
|
|
16
|
+
The vertex style for role `R` is built as:
|
|
17
|
+
`<shapes[R]>;whiteSpace=wrap;html=1;fillColor=<palette[roles[R]].fillColor>;strokeColor=<palette[roles[R]].strokeColor>;fontFamily=<font.fontFamily>;fontSize=<font.fontSize>`
|
|
18
|
+
- If `extras.sketch=true`, append `;sketch=1` to every vertex style AND every edge style.
|
|
19
|
+
- If `extras.globalStrokeWidth !== 1` (i.e., any value other than the drawio default of 1, including `0.5`), append `;strokeWidth=<n>` to every vertex style AND every edge style.
|
|
20
|
+
|
|
21
|
+
The edge style is built as:
|
|
22
|
+
`<edges.style>;<edges.arrow>`
|
|
23
|
+
- Per-edge routing keys (`exitX/entryX/...`) are added as literals below.
|
|
24
|
+
- Edge 15 exercises `edges.dashedFor`:
|
|
25
|
+
- If `edges.dashedFor` is **non-empty**, use its first entry as the edge's `value` (label) AND append `;dashed=1` to the edge style.
|
|
26
|
+
- If `edges.dashedFor` is empty (`[]`), use the label `cross-call` and do NOT append `;dashed=1` — the preset has no dashed convention, so the sample must not fake one.
|
|
27
|
+
|
|
28
|
+
**Placeholder expansion (applied when filling the XML):**
|
|
29
|
+
- `{{VSTYLE:<role>}}` expands to the vertex-style formula above with `R = <role>`. Write the result as a literal string; do not URL-encode.
|
|
30
|
+
- `{{ESTYLE}}` expands to the edge-style formula above.
|
|
31
|
+
- `{{EDGE15_LABEL}}` and `{{EDGE15_DASH}}` follow the Edge-15 rule above.
|
|
32
|
+
|
|
33
|
+
```xml
|
|
34
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
35
|
+
<mxfile host="drawio" version="26.0.0">
|
|
36
|
+
<diagram name="Preset Sample">
|
|
37
|
+
<mxGraphModel>
|
|
38
|
+
<root>
|
|
39
|
+
<mxCell id="0" />
|
|
40
|
+
<mxCell id="1" parent="0" />
|
|
41
|
+
|
|
42
|
+
<!-- Row 1: gateway -->
|
|
43
|
+
<mxCell id="2" value="Gateway" style="{{VSTYLE:gateway}}" vertex="1" parent="1">
|
|
44
|
+
<mxGeometry x="340" y="40" width="160" height="60" as="geometry" />
|
|
45
|
+
</mxCell>
|
|
46
|
+
|
|
47
|
+
<!-- Row 2: security | service | queue -->
|
|
48
|
+
<mxCell id="3" value="Auth" style="{{VSTYLE:security}}" vertex="1" parent="1">
|
|
49
|
+
<mxGeometry x="80" y="180" width="160" height="60" as="geometry" />
|
|
50
|
+
</mxCell>
|
|
51
|
+
<mxCell id="4" value="Service" style="{{VSTYLE:service}}" vertex="1" parent="1">
|
|
52
|
+
<mxGeometry x="340" y="180" width="160" height="60" as="geometry" />
|
|
53
|
+
</mxCell>
|
|
54
|
+
<mxCell id="5" value="Queue" style="{{VSTYLE:queue}}" vertex="1" parent="1">
|
|
55
|
+
<mxGeometry x="600" y="180" width="160" height="60" as="geometry" />
|
|
56
|
+
</mxCell>
|
|
57
|
+
|
|
58
|
+
<!-- Row 3: database | external | error -->
|
|
59
|
+
<mxCell id="6" value="Database" style="{{VSTYLE:database}}" vertex="1" parent="1">
|
|
60
|
+
<mxGeometry x="80" y="340" width="160" height="70" as="geometry" />
|
|
61
|
+
</mxCell>
|
|
62
|
+
<mxCell id="7" value="External API" style="{{VSTYLE:external}}" vertex="1" parent="1">
|
|
63
|
+
<mxGeometry x="340" y="340" width="160" height="60" as="geometry" />
|
|
64
|
+
</mxCell>
|
|
65
|
+
<mxCell id="8" value="Error Sink" style="{{VSTYLE:error}}" vertex="1" parent="1">
|
|
66
|
+
<mxGeometry x="600" y="340" width="160" height="60" as="geometry" />
|
|
67
|
+
</mxCell>
|
|
68
|
+
|
|
69
|
+
<!-- Edges -->
|
|
70
|
+
<mxCell id="10" value="" style="{{ESTYLE}};exitX=0.25;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0" edge="1" parent="1" source="2" target="3">
|
|
71
|
+
<mxGeometry relative="1" as="geometry" />
|
|
72
|
+
</mxCell>
|
|
73
|
+
<mxCell id="11" value="" style="{{ESTYLE}};exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0" edge="1" parent="1" source="2" target="4">
|
|
74
|
+
<mxGeometry relative="1" as="geometry" />
|
|
75
|
+
</mxCell>
|
|
76
|
+
<mxCell id="12" value="" style="{{ESTYLE}};exitX=0.75;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0" edge="1" parent="1" source="2" target="5">
|
|
77
|
+
<mxGeometry relative="1" as="geometry" />
|
|
78
|
+
</mxCell>
|
|
79
|
+
<mxCell id="13" value="" style="{{ESTYLE}};exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0" edge="1" parent="1" source="4" target="7">
|
|
80
|
+
<mxGeometry relative="1" as="geometry" />
|
|
81
|
+
</mxCell>
|
|
82
|
+
<mxCell id="14" value="" style="{{ESTYLE}};exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0" edge="1" parent="1" source="4" target="6">
|
|
83
|
+
<mxGeometry relative="1" as="geometry" />
|
|
84
|
+
</mxCell>
|
|
85
|
+
<mxCell id="15" value="{{EDGE15_LABEL}}" style="{{ESTYLE}}{{EDGE15_DASH}};exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0" edge="1" parent="1" source="4" target="8">
|
|
86
|
+
<mxGeometry relative="1" as="geometry" />
|
|
87
|
+
</mxCell>
|
|
88
|
+
|
|
89
|
+
</root>
|
|
90
|
+
</mxGraphModel>
|
|
91
|
+
</diagram>
|
|
92
|
+
</mxfile>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Rendering the sample
|
|
96
|
+
|
|
97
|
+
1. Write the filled XML to `/tmp/drawio-preset-<name>.drawio`.
|
|
98
|
+
2. Run the same `draw.io -x -f png -e -s 2 -o <preset-name>-sample.png <tmp>.drawio` command the main workflow uses.
|
|
99
|
+
3. Save the PNG as `./preset-<name>-sample.png` (the user's working directory).
|
|
100
|
+
4. Show the user: preset summary table + PNG path + provenance/confidence line.
|
|
101
|
+
|
|
102
|
+
### Approval loop
|
|
103
|
+
|
|
104
|
+
- "save" / "looks good" → write candidate to `~/.drawio-skill/styles/<name>.json`; delete tempfile and sample PNG.
|
|
105
|
+
- "change <field> to <value>" → edit the in-memory candidate; re-render; re-ask.
|
|
106
|
+
- "cancel" → delete tempfile and sample PNG; no save.
|
|
107
|
+
|
|
108
|
+
### If sample render fails (draw.io CLI missing / export error)
|
|
109
|
+
|
|
110
|
+
Still show the summary table and the provenance line. Note: *"Could not render sample PNG (CLI unavailable). Save anyway on your OK."* Do not block.
|
|
111
|
+
|
|
112
|
+
## XML extraction path
|
|
113
|
+
|
|
114
|
+
Input: a `.drawio` file path. Output: candidate preset JSON. Deterministic, no LLM inference.
|
|
115
|
+
|
|
116
|
+
### Steps
|
|
117
|
+
|
|
118
|
+
1. **Parse the file.** Read the XML, collect every `<mxCell>` with a `style=` attribute, split into vertices (`vertex="1"`) and edges (`edge="1"`).
|
|
119
|
+
2. **Tokenize each `style=` string** on `;`. Each element is either `key=value` or a bare keyword (e.g., `rhombus`, `ellipse`, `rounded=1`).
|
|
120
|
+
3. **Extract palette.** For every vertex, take the `(fillColor, strokeColor)` pair (skip vertices with neither). Count frequency. Keep the top ≤7 pairs.
|
|
121
|
+
4. **Extract shape vocabulary + role mapping.** For each vertex determine a shape class by precedence:
|
|
122
|
+
`cylinder3 > ellipse > rhombus > swimlane > rounded=1 > rounded=0`.
|
|
123
|
+
Then infer the semantic role from the vertex's shape class and its `value` (label) attribute. **Evaluate the rules below in order; first match wins.**
|
|
124
|
+
- `cylinder3` → `database`
|
|
125
|
+
- `rhombus` → `decision`
|
|
126
|
+
- `swimlane` → `container`
|
|
127
|
+
- `dashed=1` present + **grey-family fill** (hex where the R, G, and B channels all fall within ±16 of each other, i.e., near-achromatic) → `external`
|
|
128
|
+
- label matches `/queue|bus|kafka|rabbit/i` → `queue`
|
|
129
|
+
- label matches `/gateway|api|lb|load/i` → `gateway`
|
|
130
|
+
- label matches `/auth|login|jwt|oauth/i` → `security`
|
|
131
|
+
- label matches `/error|fail|alert/i` → `error`
|
|
132
|
+
- everything else → `service`
|
|
133
|
+
|
|
134
|
+
For each **role that has a canonical palette slot** — `service`, `database`, `queue`, `gateway`, `error`, `external`, `security` — the most frequent `(role, color-pair)` mapping wins. The pair goes into the role's canonical palette slot:
|
|
135
|
+
`service→primary, database→success, queue→warning, gateway→accent, error→danger, external→neutral, security→secondary`.
|
|
136
|
+
Set `roles[role]` to that slot name.
|
|
137
|
+
|
|
138
|
+
**Decision and container shapes do not get a `roles[...]` entry** — they are recorded only in `shapes.decision` and `shapes.container`. Any color pairs observed on decision/container vertices still participate in the palette (they can fill leftover slots) but are not tied to a semantic role.
|
|
139
|
+
|
|
140
|
+
Leftover color pairs (not claimed by any role-slot mapping) fill remaining empty palette slots in descending-frequency order.
|
|
141
|
+
|
|
142
|
+
Record the shape class string used per role in `shapes[role]`. The six named shape keys are `service`, `database`, `queue`, `decision`, `external`, `container` — `gateway`, `error`, and `security` roles inherit `shapes.service` and do not get their own `shapes[...]` entry. Example: `shapes.database = "shape=cylinder3"`.
|
|
143
|
+
|
|
144
|
+
5. **Extract fonts.** Compute modal `fontFamily` and `fontSize` across vertices; emit them as `font.fontFamily` and `font.fontSize`. Also track `fontStyle` per vertex as a **working variable** (not an output field — the schema has no top-level `font.fontStyle`). If a distinguishable subset of vertices uses a larger `fontSize` combined with `fontStyle=1` (bold), treat that subset as titles: set `font.titleFontSize` to their modal size and `font.titleBold: true`. Otherwise omit both title fields.
|
|
145
|
+
|
|
146
|
+
6. **Extract edge defaults.** Take the modal edge style string, but strip these per-edge coordinate keys before counting: `entryX`, `entryY`, `exitX`, `exitY`, `entryDx`, `entryDy`, `exitDx`, `exitDy`. Record arrow style from `endArrow`/`endFill` separately in `edges.arrow`.
|
|
147
|
+
If any edges have `dashed=1`, collect their `value` (label) attributes. If ≥2 share a common token (e.g., all are labeled "async" or "optional"), add that token to `edges.dashedFor`.
|
|
148
|
+
|
|
149
|
+
7. **Extract extras.** `sketch=1` seen on any vertex or edge → `extras.sketch = true`. Modal `strokeWidth` across vertices → `extras.globalStrokeWidth` (default `1`).
|
|
150
|
+
|
|
151
|
+
8. **Set provenance.**
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"source": { "type": "xml", "path": "<input absolute path>", "extracted_at": "YYYY-MM-DD" },
|
|
155
|
+
"confidence": "high"
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### XML edge cases
|
|
160
|
+
|
|
161
|
+
| Situation | Behavior |
|
|
162
|
+
|---|---|
|
|
163
|
+
| Source has <3 distinct color pairs | Leave unfilled slots as `null`. Downgrade `confidence` to `"medium"`. Summary warns the user. |
|
|
164
|
+
| Source has >7 color pairs | Keep the top 7 by frequency. Summary warns that some colors were dropped. |
|
|
165
|
+
| Non-standard `shape=` keywords (e.g., `shape=mxgraph.aws4.*`) | These do not match the Step 4 precedence ladder, so the vertex falls through to `rounded=0` for shape-class purposes. Iconography is lost; color, label, and edge style are still captured. Role inference still runs via the label-regex rules. Summary notes: *"Non-standard shape library detected — iconography not preserved in preset (color and label captured)."* |
|
|
166
|
+
| Non-English labels | The English-keyword regexes in step 4 will mostly miss; most vertices collapse to `service`. Palette/shapes/font/edges still captured correctly (they don't depend on label text). `confidence` stays `"high"`. Summary notes: *"Role labels not in English — `service`/`database`/`decision`/`container`/`external` inferred from shape class; other roles not mapped."* |
|
|
167
|
+
| File has no `<mxCell vertex="1">` at all | Stop. Refuse to save. Message: *"Nothing to learn from — source file has no shapes."* |
|
|
168
|
+
|
|
169
|
+
## Image extraction path
|
|
170
|
+
|
|
171
|
+
Input: path to a PNG/JPG (or any vision-readable image format). Output: candidate preset JSON. Inference-based; `confidence: "medium"` at best.
|
|
172
|
+
|
|
173
|
+
**Prerequisite:** the agent's vision capability must be available (same mechanism the main workflow's self-check uses). If vision is not available, stop and tell the user:
|
|
174
|
+
*"Image-based learning needs a vision-enabled model (Claude Sonnet or Opus). Re-run on such a model, or provide the `.drawio` source file instead."*
|
|
175
|
+
|
|
176
|
+
### Steps
|
|
177
|
+
|
|
178
|
+
1. **Read the image.** Use the agent's vision input — the same path the main workflow's step 5 uses to read exported PNGs during self-check.
|
|
179
|
+
|
|
180
|
+
2. **Extract palette by visual inspection.** Identify distinct fill-color regions on shape bodies.
|
|
181
|
+
|
|
182
|
+
For each distinct fill:
|
|
183
|
+
- `fillColor` — quantize each RGB channel to the nearest multiple of 16. If the resulting HSL lightness is below 0.75, raise it to 0.85 (keep hue and saturation; set L=0.85; HSL→RGB round-trip). Emit as `#RRGGBB`. Drawio-standard pastels occupy L≈0.85–0.96; below 0.75 reads as "too dark for a fill color" and this step lifts it back into that range.
|
|
184
|
+
- `strokeColor` — read the matching border. If unreadable, derive from fill by darkening ~25% (match HSL, drop L by 0.25).
|
|
185
|
+
|
|
186
|
+
Map each `(fillColor, strokeColor)` pair to a named slot using this decision order:
|
|
187
|
+
|
|
188
|
+
1. **Grey check first.** If the fill has R, G, and B channels all within ±16 of each other (same definition as the XML path's grey-family rule), OR HSL saturation < 0.20, classify as `neutral`. This check wins regardless of hue angle.
|
|
189
|
+
2. **Hue band otherwise.** Use these explicit HSL hue ranges:
|
|
190
|
+
- 180°–260° → `primary` (blue)
|
|
191
|
+
- 80°–170° → `success` (green)
|
|
192
|
+
- 45°–65° → `warning` (yellow)
|
|
193
|
+
- 20°–44° → `accent` (orange)
|
|
194
|
+
- 0°–19° or 320°–360° → `danger` (red/pink)
|
|
195
|
+
- 260°–320° → `secondary` (purple)
|
|
196
|
+
3. **No band matched** (gap regions at 65°–80° or 170°–180°) → spill to the nearest band by angular distance.
|
|
197
|
+
|
|
198
|
+
**Collision rule.** If ≥2 distinct fills land in the same slot, sort them by total pixel area covered in the image (descending). The largest keeps the canonical slot. Remaining fills spill to the **nearest empty slot** measured by hue-band angular distance — first to adjacent bands on either side, then farther out. If every slot is already filled, drop the extras and warn in the summary.
|
|
199
|
+
|
|
200
|
+
3. **Extract shape vocabulary.** Classify every visible shape by silhouette:
|
|
201
|
+
- rounded rectangle → `rounded=1`
|
|
202
|
+
- sharp rectangle → `rounded=0`
|
|
203
|
+
- circle / oval → `ellipse`
|
|
204
|
+
- diamond → `rhombus`
|
|
205
|
+
- cylinder (rectangle with curved top/bottom) → `shape=cylinder3`
|
|
206
|
+
- titled container (header bar + nested children inside) → `swimlane;startSize=30`
|
|
207
|
+
- dashed-bordered rectangle → `rounded=1;dashed=1`
|
|
208
|
+
|
|
209
|
+
Role assignment uses the **same label-text + shape rules as the XML path step 4**. Visible labels are read via vision.
|
|
210
|
+
|
|
211
|
+
4. **Extract fonts.** Best-effort. Distinguishable categories:
|
|
212
|
+
- clearly serif → `fontFamily: "Georgia"`
|
|
213
|
+
- clearly monospaced → `fontFamily: "Courier New"`
|
|
214
|
+
- otherwise → `fontFamily: "Helvetica"`
|
|
215
|
+
|
|
216
|
+
Size by relative appearance:
|
|
217
|
+
- small → `fontSize: 11`
|
|
218
|
+
- medium → `fontSize: 12`
|
|
219
|
+
- large → `fontSize: 14`
|
|
220
|
+
|
|
221
|
+
If titles/container headers are distinctly larger or bolder → set `titleFontSize` accordingly and `titleBold: true`.
|
|
222
|
+
|
|
223
|
+
5. **Extract edge defaults.**
|
|
224
|
+
- Right-angle orthogonal arrows → `edges.style = "edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1"`.
|
|
225
|
+
- Curved arrows → append `;curved=1` to `edges.style`.
|
|
226
|
+
- Filled triangle arrowheads → `edges.arrow = "endArrow=classic;endFill=1"`.
|
|
227
|
+
- Open V-shaped arrowheads → `edges.arrow = "endArrow=open;endFill=0"`.
|
|
228
|
+
- Any dashed arrows near labels like "optional", "async", "fallback", "secondary" → add those label tokens to `edges.dashedFor`.
|
|
229
|
+
|
|
230
|
+
6. **Extract extras.**
|
|
231
|
+
- Visibly hand-drawn / rough / sketch look (wavy strokes, uneven fills) → `extras.sketch = true`.
|
|
232
|
+
- Heavy strokes (clearly >1.5× normal) → `extras.globalStrokeWidth = 2`.
|
|
233
|
+
- Otherwise default: `extras = { "sketch": false, "globalStrokeWidth": 1 }`.
|
|
234
|
+
|
|
235
|
+
7. **Set provenance and confidence.**
|
|
236
|
+
```json
|
|
237
|
+
{
|
|
238
|
+
"source": { "type": "image", "path": "<input absolute path>", "extracted_at": "YYYY-MM-DD" },
|
|
239
|
+
"confidence": "medium"
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
Adjustments:
|
|
243
|
+
- <3 distinct shapes identifiable → `confidence: "low"`.
|
|
244
|
+
- Image path stays at `"medium"` by default. The only path to `"high"` is a strictly-verifiable signal: the source image was exported from drawio itself (recognizable drawio default chrome, grid, or a visible drawio watermark), **and** all seven palette slots are filled, **and** all seven roles are labeled. This preserves the semantic gap between inference-based (image) and parse-based (XML) provenance.
|
|
245
|
+
|
|
246
|
+
### Image edge cases
|
|
247
|
+
|
|
248
|
+
| Situation | Behavior |
|
|
249
|
+
|---|---|
|
|
250
|
+
| Vision unavailable | Stop as described above — do not fall back to guessing. |
|
|
251
|
+
| Image has <3 identifiable shapes | Continue; mark `confidence: "low"`; summary explicitly warns the user that the preset is a loose approximation. |
|
|
252
|
+
| Image has no visible labels | Role assignment collapses to shape-class only: cylinders → `database`, diamonds → `decision`, swimlanes → `container`, dashed-bordered rectangles with grey fill → `external`, everything else → `service`. Palette/font/edges still captured. Summary notes: *"No labels readable — semantic roles beyond shape-class not inferred."* |
|
|
253
|
+
| Two palette slots would land in the same hue family | Keep the more frequent one in its canonical slot; spill the other to the adjacent empty slot (rule in step 2). |
|
|
254
|
+
| Image has more than 7 distinct fills | Keep the 7 most area-covering fills per the Step 2 collision rule. Summary warns that some colors were dropped. |
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://github.com/Agents365-ai/drawio-skill/styles/schema.json",
|
|
4
|
+
"title": "drawio-skill preset",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["name", "version", "palette", "roles", "shapes", "font", "edges"],
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {
|
|
9
|
+
"$schema": { "type": "string" },
|
|
10
|
+
"name": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]*$" },
|
|
11
|
+
"version": { "type": "integer", "const": 1 },
|
|
12
|
+
"default": { "type": "boolean" },
|
|
13
|
+
"confidence": { "type": "string", "enum": ["low", "medium", "high"] },
|
|
14
|
+
"source": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"additionalProperties": false,
|
|
17
|
+
"properties": {
|
|
18
|
+
"type": { "type": "string", "enum": ["xml", "image", "built-in", "hand-authored"] },
|
|
19
|
+
"path": { "type": "string" },
|
|
20
|
+
"extracted_at": { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$" }
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"palette": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"additionalProperties": false,
|
|
26
|
+
"required": ["primary", "success", "warning", "accent", "danger", "neutral", "secondary"],
|
|
27
|
+
"properties": {
|
|
28
|
+
"primary": { "$ref": "#/$defs/colorPair" },
|
|
29
|
+
"success": { "$ref": "#/$defs/colorPair" },
|
|
30
|
+
"warning": { "$ref": "#/$defs/colorPair" },
|
|
31
|
+
"accent": { "$ref": "#/$defs/colorPair" },
|
|
32
|
+
"danger": { "$ref": "#/$defs/colorPair" },
|
|
33
|
+
"neutral": { "$ref": "#/$defs/colorPair" },
|
|
34
|
+
"secondary": { "$ref": "#/$defs/colorPair" }
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"roles": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"additionalProperties": false,
|
|
40
|
+
"properties": {
|
|
41
|
+
"service": { "$ref": "#/$defs/slotName" },
|
|
42
|
+
"database": { "$ref": "#/$defs/slotName" },
|
|
43
|
+
"queue": { "$ref": "#/$defs/slotName" },
|
|
44
|
+
"gateway": { "$ref": "#/$defs/slotName" },
|
|
45
|
+
"error": { "$ref": "#/$defs/slotName" },
|
|
46
|
+
"external": { "$ref": "#/$defs/slotName" },
|
|
47
|
+
"security": { "$ref": "#/$defs/slotName" }
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"shapes": {
|
|
51
|
+
"type": "object",
|
|
52
|
+
"additionalProperties": { "type": "string" },
|
|
53
|
+
"properties": {
|
|
54
|
+
"service": { "type": "string" },
|
|
55
|
+
"database": { "type": "string" },
|
|
56
|
+
"queue": { "type": "string" },
|
|
57
|
+
"decision": { "type": "string" },
|
|
58
|
+
"external": { "type": "string" },
|
|
59
|
+
"container": { "type": "string" }
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"font": {
|
|
63
|
+
"type": "object",
|
|
64
|
+
"additionalProperties": false,
|
|
65
|
+
"required": ["fontFamily", "fontSize"],
|
|
66
|
+
"properties": {
|
|
67
|
+
"fontFamily": { "type": "string" },
|
|
68
|
+
"fontSize": { "type": "integer", "minimum": 8, "maximum": 36 },
|
|
69
|
+
"titleFontSize": { "type": "integer", "minimum": 8, "maximum": 48 },
|
|
70
|
+
"titleBold": { "type": "boolean" }
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"edges": {
|
|
74
|
+
"type": "object",
|
|
75
|
+
"additionalProperties": false,
|
|
76
|
+
"required": ["style", "arrow"],
|
|
77
|
+
"properties": {
|
|
78
|
+
"style": { "type": "string" },
|
|
79
|
+
"arrow": { "type": "string" },
|
|
80
|
+
"dashedFor": { "type": "array", "items": { "type": "string" } }
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"extras": {
|
|
84
|
+
"type": "object",
|
|
85
|
+
"additionalProperties": false,
|
|
86
|
+
"properties": {
|
|
87
|
+
"sketch": { "type": "boolean" },
|
|
88
|
+
"globalStrokeWidth": { "type": "number", "minimum": 0.5, "maximum": 6 }
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"$defs": {
|
|
93
|
+
"colorPair": {
|
|
94
|
+
"oneOf": [
|
|
95
|
+
{ "type": "null" },
|
|
96
|
+
{
|
|
97
|
+
"type": "object",
|
|
98
|
+
"additionalProperties": false,
|
|
99
|
+
"required": ["fillColor", "strokeColor"],
|
|
100
|
+
"properties": {
|
|
101
|
+
"fillColor": { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$" },
|
|
102
|
+
"strokeColor": { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$" }
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
},
|
|
107
|
+
"slotName": {
|
|
108
|
+
"type": "string",
|
|
109
|
+
"enum": ["primary", "success", "warning", "accent", "danger", "neutral", "secondary"]
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plan
|
|
3
|
+
description: "Use when the user types /plan or asks to clarify requirements, discuss options, or produce a concrete project-aware plan before implementation. This skill uses a planning-only subagent with lightweight read-only discovery and must not execute edits, verification, builds, or commands."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Plan Skill
|
|
7
|
+
|
|
8
|
+
Use this skill when the user wants to discuss a solution before execution, especially when the
|
|
9
|
+
message starts with `/plan`.
|
|
10
|
+
|
|
11
|
+
## Goal
|
|
12
|
+
|
|
13
|
+
Produce a concrete, project-aware plan without implementing it.
|
|
14
|
+
|
|
15
|
+
The plan may inspect the workspace using read-only tools, but it must not modify files, run
|
|
16
|
+
verification, run shell commands, request approval, or perform implementation work.
|
|
17
|
+
|
|
18
|
+
When the plan may involve file changes, first identify the likely affected files or directories
|
|
19
|
+
and explain why each one may need changes. Return these as a concise list before implementation
|
|
20
|
+
steps. If no file changes are expected or the affected files are not yet clear, state that
|
|
21
|
+
explicitly.
|
|
22
|
+
|
|
23
|
+
## Allowed Actions
|
|
24
|
+
|
|
25
|
+
Use lightweight read-only discovery when it helps make the plan concrete:
|
|
26
|
+
|
|
27
|
+
- `workspace_state`
|
|
28
|
+
- `git_diff`
|
|
29
|
+
- `list_files`
|
|
30
|
+
- `grep`
|
|
31
|
+
- `read_file`
|
|
32
|
+
- `read_many_files`
|
|
33
|
+
- `git_show`
|
|
34
|
+
- `subagent` with `role="architect"` or `role="explorer"` only
|
|
35
|
+
|
|
36
|
+
Discovery budget:
|
|
37
|
+
|
|
38
|
+
- Prefer 3-6 read-only tool calls.
|
|
39
|
+
- Read only the files or snippets needed to understand the current design.
|
|
40
|
+
- Avoid large file dumps and unrelated project exploration.
|
|
41
|
+
- Reuse recent discovery from the conversation when repeating `/plan` on the same topic.
|
|
42
|
+
|
|
43
|
+
## Forbidden Actions
|
|
44
|
+
|
|
45
|
+
Do not call these while this skill is active:
|
|
46
|
+
|
|
47
|
+
- `apply_patch`
|
|
48
|
+
- `write_file`
|
|
49
|
+
- `edit_file`
|
|
50
|
+
- `bash`
|
|
51
|
+
- `verify`
|
|
52
|
+
- implementation-oriented `subagent role="worker"`
|
|
53
|
+
- approval-seeking or approval-dependent actions
|
|
54
|
+
|
|
55
|
+
If the user asks to execute after planning, stop planning and wait for explicit confirmation such
|
|
56
|
+
as "按这个执行", "开始修改", or "implement this".
|
|
57
|
+
|
|
58
|
+
## Required Subagent
|
|
59
|
+
|
|
60
|
+
Use a separate planning subagent for non-trivial `/plan` requests:
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
subagent(
|
|
64
|
+
role="architect",
|
|
65
|
+
task="Clarify the user's requirements and produce a planning-only solution. Do not modify files, run commands, verify, or implement. Use the provided discovery summary to identify likely affected files or directories, assumptions, options, recommended approach, risks, and questions.",
|
|
66
|
+
context="[user goal + lightweight discovery summary + current constraints]"
|
|
67
|
+
)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Use `role="explorer"` only when the main uncertainty is where behavior lives in the codebase.
|
|
71
|
+
The explorer must remain read-only and return evidence, not implementation.
|
|
72
|
+
|
|
73
|
+
## Multi-Round `/plan`
|
|
74
|
+
|
|
75
|
+
Repeated `/plan` in the same conversation continues discussion of the latest plan by default.
|
|
76
|
+
|
|
77
|
+
When revising a prior plan:
|
|
78
|
+
|
|
79
|
+
- Treat the latest user feedback as the new steering input.
|
|
80
|
+
- Reuse the previous plan summary and only do more discovery if the user changes area or scope.
|
|
81
|
+
- Return a revised plan, not a complete rewrite unless the user asks for one.
|
|
82
|
+
|
|
83
|
+
## Output Format
|
|
84
|
+
|
|
85
|
+
Return a concise plan in Chinese unless the user asks otherwise:
|
|
86
|
+
|
|
87
|
+
```text
|
|
88
|
+
**方案草案**
|
|
89
|
+
|
|
90
|
+
目标:
|
|
91
|
+
- ...
|
|
92
|
+
|
|
93
|
+
当前理解:
|
|
94
|
+
- ...
|
|
95
|
+
|
|
96
|
+
预计文件改动:
|
|
97
|
+
- path/to/file.py:需要修改的原因
|
|
98
|
+
- path/to/other.md:需要更新的原因
|
|
99
|
+
- 暂无明确文件变更:原因
|
|
100
|
+
|
|
101
|
+
推荐方案:
|
|
102
|
+
- ...
|
|
103
|
+
|
|
104
|
+
可选方案:
|
|
105
|
+
- ...
|
|
106
|
+
|
|
107
|
+
风险与边界:
|
|
108
|
+
- ...
|
|
109
|
+
|
|
110
|
+
待确认:
|
|
111
|
+
- ...
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Keep the final response compact. Do not include hidden reasoning, raw tool dumps, or long
|
|
115
|
+
subagent transcripts. The main context should retain only the useful plan summary.
|