Fix review findings: importer DoS, sync data loss, views/profile rendering, docs

Source importers: lstat before open so FIFOs no longer hang the directory
walk; replace the quadratic Rust macro regex with a linear scan.
Three-way sync: report page add/add and delete-vs-modify as conflicts
instead of silently overwriting or resurrecting; canonical comparison so
key order is not a change; the sync action withholds output and fails on
conflicts unless --force. Story publishing escapes <, >, & and U+2028/9
inside the embedded JSON.
Views: drop parentId of unselected containers, re-layout instead of
manual geometry, validate before serialising; flatten() merges identical
nodes repeated across pages so C4 output works with every analysis
action. Dark theme edge labels get a background; tube-map corridors sit
above the stations; C4 containers keep the swimlane style and orphan
relationships land on the matching page; router keeps container header
bands as obstacles; sequence self-messages loop on one side.
Docs: SKILL.md lists all 23 CLI actions and how each capability family
is invoked, task wrappers for query/test/what-if/doctor, capability
tables and --page scope corrected, maintenance snippet uses the real
synchronous action signature, duplicated rule bullets moved to the rule
references, coverage matrix wording made verifiable.

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
2026-09-06 17:01:50 +03:00
co-authored by Claude Code
parent 7610235781
commit 6584df0666
32 changed files with 801 additions and 209 deletions
+7 -11
View File
@@ -1,6 +1,6 @@
# Agents365 capability coverage
> Evidence basis: clean-room behavioral comparison of 42 peer tools. Peer source and bundled assets were not copied because the inspected mirror had no complete license file.
> Evidence basis: internal comparison against a 42-entry peer-tool feature list (tool names as listed in the matrix; no version or commit was recorded, so the comparison is **not independently verifiable**). Peer source and bundled assets were not copied. The "Native evidence" column points to files in this repository and is verifiable; the "Remaining gap" column reflects the internal feature list only.
## Reading the classifications
@@ -32,16 +32,16 @@ These are strict peer-parity labels. A `partial` row can still contain substanti
| `ciimports.py` | **partial** | `scripts/src/services/source-importers/index.ts`<br>`scripts/src/services/source-importers/index.test.ts` | The service imports a bounded generic jobs/needs object, but lacks CLI registration, repository workflow discovery, triggers, runners, matrices, reusable workflows, GitLab stages, and inferred stage dependencies. |
| `composeimports.py` | **partial** | `scripts/src/services/source-importers/index.ts`<br>`scripts/src/services/source-importers/index.test.ts` | Services, depends_on, and simple named volumes are covered through a service API; links, volumes_from, long-form mounts, network grouping, conventional-file discovery, and CLI exposure remain absent. |
| `compress.py` | **partial** | `scripts/src/services/profiles/compression.ts`<br>`scripts/src/services/profiles/compression.test.ts` | A deterministic BFS clustering service emits summary and full IR pages, but there is no Draw.io-facing action, exact loss-aware detail-file workflow, label-propagation parity, or member-cell drill-down target contract. |
| `dbxicons.py` | **optional-deferred** | `scripts/src/services/shape-catalog/shape-catalog.ts`<br>clean-room 42-tool mapping audit | No licensed Databricks manifest, aliases, variants, pinned-ref embedding, refresh operation, host allowlist, or CLI action was delivered. |
| `dbxicons.py` | **optional-deferred** | `scripts/src/services/shape-catalog/shape-catalog.ts`<br>internal peer feature-list comparison (not independently verifiable) | No licensed Databricks manifest, aliases, variants, pinned-ref embedding, refresh operation, host allowlist, or CLI action was delivered. |
| `diagram_ir.py` | **partial** | `scripts/src/model/diagram-ir.ts`<br>`scripts/src/services/semantic-lifecycle/import-drawio.ts`<br>`scripts/src/services/semantic-lifecycle/analysis.ts`<br>`scripts/src/services/semantic-lifecycle/sync.ts`<br>`scripts/src/services/semantic-lifecycle/publishing.ts` | Versioned IR, loss-aware import, views, query, policies, failure impact, sync, and story publishing exist, but articulation analysis, a unified architecture-review contract, contrast analysis, multilingual labeling, and explicit peer-IR-v1 compatibility are incomplete. |
| `diagramctl.py` | **partial** | `scripts/src/cli/commands.ts`<br>`scripts/src/cli/semantic-lifecycle.test.ts`<br>`scripts/src/actions/doctor/action.ts`<br>`scripts/src/actions/sync/action.ts` | Lifecycle actions are registered in the existing --action CLI, but integrated importer, profile, transform, and reverse-export services are not registered. There is no uniform peer-equivalent result envelope. |
| `diagramctl_mcp.py` | **optional-deferred** | `scripts/src/cli/commands.ts`<br>clean-room 42-tool mapping audit | No optional MCP package, JSON-RPC initialization, tools/list, tools/call bridge, closed schemas, timeout handling, or MCP entrypoint exists. |
| `diagramctl_mcp.py` | **optional-deferred** | `scripts/src/cli/commands.ts`<br>internal peer feature-list comparison (not independently verifiable) | No optional MCP package, JSON-RPC initialization, tools/list, tools/call bridge, closed schemas, timeout handling, or MCP entrypoint exists. |
| `dockerimports.py` | **optional-deferred** | `scripts/src/services/source-importers/index.ts`<br>`scripts/src/services/source-importers/index.test.ts` | The importer registry has Docker Compose but no Docker inspect snapshot kind, container/network/volume instance normalization, redaction contract, stdin parity, or action. |
| `drawio2mermaid.py` | **partial** | `scripts/src/services/transforms/reverse.ts`<br>`scripts/src/services/transforms/reverse.test.ts`<br>`scripts/src/services/semantic-lifecycle/import-drawio.ts` | A deterministic IR-to-Mermaid service exists, but there is no Draw.io-to-Mermaid CLI/action, shape-form mapping, direction/fence controls, or lossy-conversion report. |
| `drawio2pptx.py` | **optional-deferred** | `scripts/src/cli/commands.ts`<br>clean-room 42-tool mapping audit | No optional Draw.io renderer adapter, per-page raster loop, PPTX writer, slide sizing, scale option, or structured unavailable result exists. |
| `drawio2pptx.py` | **optional-deferred** | `scripts/src/cli/commands.ts`<br>internal peer feature-list comparison (not independently verifiable) | No optional Draw.io renderer adapter, per-page raster loop, PPTX writer, slide sizing, scale option, or structured unavailable result exists. |
| `drawiodiff.py` | **partial** | `scripts/src/services/transforms/semantic-diff.ts`<br>`scripts/src/services/transforms/semantic-diff.test.ts`<br>`scripts/src/services/semantic-lifecycle/import-drawio.ts` | The IR service classifies added, removed, changed, moved, and rerouted entities, but no CLI/action composes Draw.io import with diffing, no by-label ambiguity mode exists, and no color-coded graph output or summary diagram is emitted. |
| `drawiohtml.py` | **optional-deferred** | `scripts/src/services/semantic-lifecycle/publishing.ts`<br>`scripts/src/actions/story/action.ts` | Story HTML is a different semantic publisher; there is no page-to-SVG export adapter, SVG sanitizer, tabbed viewer, pan/zoom/search UI, drill-down link rewrite, or publish-viewer action. |
| `edgeports.py` | **rejected** | `scripts/src/services/authoring-router/orthogonal-router.ts`<br>`scripts/src/services/authoring-router/orthogonal-router.test.ts`<br>clean-room 42-tool mapping audit | Only routing during authoring exists. The post-import boundary-port editor, pinned-port preservation, dry-run, idempotence, and transactional Draw.io write path were not selected for this post-phase implementation. |
| `edgeports.py` | **rejected** | `scripts/src/services/authoring-router/orthogonal-router.ts`<br>`scripts/src/services/authoring-router/orthogonal-router.test.ts`<br>internal peer feature-list comparison (not independently verifiable) | Only routing during authoring exists. The post-import boundary-port editor, pinned-port preservation, dry-run, idempotence, and transactional Draw.io write path were not selected for this post-phase implementation. |
| `encode_drawio_url.py` | **optional-deferred** | `scripts/src/cli/commands.ts`<br>`scripts/package.json` | Compression primitives are available transitively, but there is no byte-compatible URL encoder, viewer/edit modes, size policy, privacy warning, or CLI action. |
| `explain.py` | **partial** | `scripts/src/services/transforms/reverse.ts`<br>`scripts/src/services/transforms/reverse.test.ts` | Structured Markdown for IR pages, nodes, and flows exists as a service, but no Draw.io-facing explain action, tier/type inference, C4 context, unknown-section reporting, or output-file contract is exposed. |
| `goimports.py` | **partial** | `scripts/src/services/source-importers/index.ts`<br>`scripts/src/services/source-importers/index.test.ts` | Bounded Go import extraction exists, but it emits imported paths as library nodes rather than resolving only intra-module packages; module discovery, grouping, transitive reduction, and CLI exposure are absent. |
@@ -54,14 +54,14 @@ These are strict peer-parity labels. A `partial` row can still contain substanti
| `pyimports.py` | **partial** | `scripts/src/services/source-importers/index.ts`<br>`scripts/src/services/source-importers/index.test.ts` | Bounded import/from extraction and dynamic-import diagnostics exist, but relative and absolute intra-project resolution, stdlib/third-party exclusion, package grouping, transitive reduction, syntax-error diagnostics, and CLI exposure are absent. |
| `raster2drawio.py` | **partial** | `scripts/src/actions/build/action.ts`<br>`scripts/src/authoring/ir-to-drawio.ts`<br>`scripts/src/services/layout/layout-engine.ts`<br>`scripts/src/model/diagram-ir.ts` | Generic IR build supports explicit geometry, styles, edges, and automatic layout, but there is no raster-extracted graph compatibility schema/action, x/y/w/h shorthand conversion, partial-coordinate policy, confidence/provenance convention, or extraction-warning envelope. |
| `relabel.py` | **partial** | `scripts/src/services/transforms/relabel.ts`<br>`scripts/src/services/transforms/relabel.test.ts` | A strict complete-map IR relabel service preserves non-label structure, but there is no extraction mode, page-name handling, UserObject traversal contract, partial-map/unmatched reporting, Draw.io transactional write, or CLI action. |
| `repair_png.py` | **optional-deferred** | `scripts/src/cli/commands.ts`<br>clean-room 42-tool mapping audit | No PNG chunk validator, signature-specific repair, atomic in-place replacement, idempotence gate, version gate, or optional action exists. |
| `repair_png.py` | **optional-deferred** | `scripts/src/cli/commands.ts`<br>internal peer feature-list comparison (not independently verifiable) | No PNG chunk validator, signature-specific repair, atomic in-place replacement, idempotence gate, version gate, or optional action exists. |
| `restyle.py` | **partial** | `scripts/src/services/themes/theme-service.ts`<br>`scripts/src/services/themes/theme-service.test.ts` | Five validated built-in themes and immutable IR application exist, but the peer-style palette-slot schema, user preset loader, hue/neutral color remapping, global extras, versioned JSON schema, Draw.io transactional action, and CLI exposure are incomplete. |
| `runbook.py` | **partial** | `scripts/src/services/profiles/runbook.ts`<br>`scripts/src/services/profiles/runbook.test.ts` | The service emits escaped self-contained interactive HTML from an explicit RunbookGraph, but it does not parse Draw.io, infer node types/start nodes/choices, report fallback selection, or expose a publish-runbook action. |
| `rustimports.py` | **partial** | `scripts/src/services/source-importers/index.ts`<br>`scripts/src/services/source-importers/index.test.ts` | A bounded subset recognizes mod and simple use roots and diagnoses macros, but crate/self/super resolution, module-file discovery, complete brace expansion, external-crate exclusion, grouping, reduction, and CLI exposure are absent. |
| `seqlayout.py` | **partial** | `scripts/src/services/profiles/sequence.ts`<br>`scripts/src/services/profiles/sequence.test.ts` | Participants, ordered messages, lifelines, activations, return validation, and editable geometry are implemented as a service, but notes are unsupported and no sequence schema file, input action, direction/options contract, or CLI registration exists. |
| `shapesearch.py` | **partial** | `scripts/src/services/shape-catalog/shape-catalog.ts`<br>`scripts/src/services/shape-catalog/shape-catalog.test.ts` | Deterministic exact/alias/fuzzy search exists for eight hand-curated generic shapes, not the licensed 10k+ palette index; compound/tag/Soundex ranking, dimensions, gzip integrity controls, expected ecosystem queries, and CLI output are missing. |
| `sqlerd.py` | **partial** | `scripts/src/services/source-importers/index.ts`<br>`scripts/src/services/source-importers/index.test.ts` | A narrow line-oriented subset finds simple tables and REFERENCES edges, but columns/types, PK/FK markers, quoted/schema identifiers, composite keys, schema grouping, crow's-foot styles, unsupported-syntax diagnostics, and CLI exposure are missing. |
| `svgflow.py` | **optional-deferred** | `scripts/src/cli/commands.ts`<br>clean-room 42-tool mapping audit | No optional Draw.io SVG export adapter, SVG parser/sanitizer, connector detection, animation injection, reduced-motion handling, or export-flow-svg action exists. |
| `svgflow.py` | **optional-deferred** | `scripts/src/cli/commands.ts`<br>internal peer feature-list comparison (not independently verifiable) | No optional Draw.io SVG export adapter, SVG parser/sanitizer, connector detection, animation injection, reduced-motion handling, or export-flow-svg action exists. |
| `tfimports.py` | **partial** | `scripts/src/services/source-importers/index.ts`<br>`scripts/src/services/source-importers/index.test.ts` | A bounded line-oriented resource/reference subset exists, but modules, multiline/nested HCL handling, comments/string false-positive guarantees, diagnostics for dynamic expressions, cloud styles, grouping, transitive reduction, no-icons mode, and CLI exposure are incomplete. |
| `tfstate.py` | **optional-deferred** | `scripts/src/services/source-importers/index.ts`<br>`scripts/src/services/source-importers/index.test.ts` | No Terraform show-JSON snapshot source kind, nested module traversal, count/for_each instance expansion, sensitive-value redaction, state relationship extraction, stdin parity, or optional action exists. |
| `timelapse.py` | **partial** | `scripts/src/services/profiles/timelapse.ts`<br>`scripts/src/services/profiles/timelapse.test.ts` | The service classifies changes across caller-supplied IR snapshots, but it has no scoped git history/archive adapter, deterministic commit sampling, importer allowlist, Draw.io frame rendering, HTML player, resource limits, or CLI action. |
@@ -71,7 +71,3 @@ These are strict peer-parity labels. A `partial` row can still contain substanti
## Architectural boundary
The retained implementation stays in the existing TypeScript/Node.js stack with pnpm, Taskfile, `@maxgraph/core`, and the established action-based CLI. Python, Graphviz, Eclipse Layout Kernel (ELK), Model Context Protocol (MCP), browser services, network icon retrieval, and Draw.io Desktop are not mandatory dependencies. Optional adapters must report availability honestly.
## Delivery note
This matrix describes the combined integrated candidate and deliberate scope decisions. Gitea publication and Hermes runtime installation are separate gates and must not be inferred from this document.
+81 -50
View File
@@ -1,12 +1,12 @@
# diagrams-drawio — Capabilities
This file lists all capabilities an agent can use from this skill.
This file lists all capabilities an agent can use from this skill. The seven capability families below use the same headings and order as the list at the top of [SKILL.md](../SKILL.md).
---
## Capability 1 — Deterministic YAML generation
Build native `.drawio` XML from a validated semantic Diagram IR:
Build native `.drawio` XML from a validated semantic Diagram IR (CLI action `build`, `task generate`):
```bash
node dist/cli/commands.js --action build --file architecture.yaml --output architecture.drawio
@@ -18,22 +18,14 @@ IR v1 remains compatible. IR v2 adds multiple pages, containers and semantic kin
## Capability 2 — Direct XML generation
Create `.drawio` files (and optionally export to PNG/SVG/PDF) from a description or requirements.
Create `.drawio` files (and optionally export to PNG/SVG/PDF) from a description or requirements. The agent authors the mxGraphModel XML directly and then runs the mandatory `validate` action (`task validate`).
See [SKILL.md](../SKILL.md) for the generation workflow, XML format, page sizes, element shapes, and well-formedness rules.
See [rules-layout.md](./rules-layout.md) for mandatory connector and layout rules.
See [rules-layout.md](./rules-layout.md) and [rules-style.md](./rules-style.md) for mandatory connector, layout, and style rules.
---
## Capability 3 — Semantic lifecycle
The native TypeScript core supports loss-aware Draw.io import and deterministic round trips; transactional stable-ID edit batches; linked audience views; semantic query, architecture policy, and failure what-if analysis; three-way synchronization; accessible self-contained story HTML; and a non-launching doctor report.
See [semantic-lifecycle.md](./semantic-lifecycle.md) for command contracts, safety behavior, built-in policy identifiers, and examples.
---
## Capability 4 — Diagram analysis (drawio-tools CLI)
## Capability 3 — Diagram analysis (drawio-tools CLI)
A **TypeScript / Node.js** CLI tool for programmatic analysis of `.drawio` files.
Entry point: `node dist/cli/commands.js` (run from the skill's `scripts/` directory), or `task run -- --file=… --action=…`.
@@ -46,7 +38,7 @@ node dist/cli/commands.js --file <path> --action <action> [--page <index>] [--ou
# short flags: -f, -a, -p, -o, -h
```
`--page` selects the diagram tab (0-based, default 0). Ignored by `summary` (processes all pages).
`--page` selects the diagram tab (0-based, default 0). Only the actions marked `--page` below honour it; actions marked "page 0 only" always analyse the first page, and all-page actions ignore it.
Always prints YAML to stdout. Exit code `0` on success, `1` on error.
### Actions
@@ -57,7 +49,41 @@ Always prints YAML to stdout. Exit code `0` on success, `1` on error.
|---|---|---|
| `build` | YAML Diagram IR | Validate and convert a YAML specification to native `.drawio`; requires `--output` |
#### Semantic lifecycle
#### Inventory
| Action | Scope | Description |
|---|---|---|
| `summary` | All pages | Full inventory of shapes + edges for every page/tab |
| `page-summary` | `--page` | Full inventory of shapes + edges for one page |
| `page-hierarchy` | `--page` | Recursive containment tree with totalLevels (nesting depth count) |
| `page-hierarchy-full` | `--page` | Same as page-hierarchy + full geometry (x, y, width, height) per shape at each nesting level |
| `page-connectors-summary` | page 0 only | Per-connector details: type, label, waypoints, source/target names |
#### Validation
| Action | Scope | Description |
|---|---|---|
| `validate` | All pages | **Mandatory final gate** — XML well-formedness + maxGraph compile + sanity check (vertices/edges > 0). Run before finishing any diagram work |
| `quality` | All pages | Objective clipping, overflow, placeholder, external-asset, palette, page-density, and edge-density checks with explicit severity |
| `page-connectors-validation` | page 0 only | Connector-shape overlaps + connector crossings + corner-port, header-edge, and single-port violations |
| `page-labels-validation` | page 0 only | Empty labels, duplicate labels, labels > 80 chars |
| `page-shape-bbox-validation` | page 0 only | Non-containment bounding box overlaps between shapes |
| `page-orphans` | page 0 only | Isolated shapes (no edges) + dangling connectors (missing endpoints) |
#### Layout
| Action | Scope | Description |
|---|---|---|
| `page-recommendations` | page 0 only | Smallest standard page size (A4→A3→A2→A1→custom) that fits content with 80 px margin |
| `page-negative-space-summary` | `--page` | Free horizontal corridors (negative space) per nesting level, bbox-based and text-aware; input for connector routing and [negative-space-diagram.md](./negative-space-diagram.md) |
> For install/build instructions, source structure, and how to add new actions, see [maintenance.md](./maintenance.md).
---
## Capability 4 — Semantic lifecycle
The native TypeScript core supports loss-aware Draw.io import and deterministic round trips; transactional stable-ID edit batches; linked audience views; semantic query, architecture policy, and failure what-if analysis; three-way synchronization; accessible self-contained story HTML; and a non-launching doctor report. Every action below also has a same-named `task` wrapper (`task import`, `task edit`, …).
| Action | Scope | Description |
|---|---|---|
@@ -71,44 +97,49 @@ Always prints YAML to stdout. Exit code `0` on success, `1` on error.
| `story` | Diagram IR v2 | Write self-contained accessible offline HTML; optional `--fail` overlay |
| `doctor` | Local environment | Report optional backend availability without launching processes or requiring a model file |
#### Inventory
| Action | Scope | Description |
|---|---|---|
| `summary` | All pages | Full inventory of shapes + edges for every page/tab |
| `page-summary` | Single page (`--page`) | Full inventory of shapes + edges for one page |
| `page-hierarchy` | Page 0 | Recursive containment tree with totalLevels (nesting depth count) |
| `page-hierarchy-full` | Page 0 | Same as page-hierarchy + full geometry (x, y, width, height) per shape at each nesting level |
| `page-connectors-summary` | Page 0 | Per-connector details: type, label, waypoints, source/target names |
#### Validation
| Action | Scope | Description |
|---|---|---|
| `validate` | All pages | **Mandatory final gate** — XML well-formedness + maxGraph compile + sanity check (vertices/edges > 0). Run before finishing any diagram work |
| `quality` | All pages | Objective clipping, overflow, placeholder, external-asset, palette, page-density, and edge-density checks with explicit severity |
| `page-connectors-validation` | Page 0 | Connector-shape overlaps + connector crossings |
| `page-labels-validation` | Page 0 | Empty labels, duplicate labels, labels > 80 chars |
| `page-shape-bbox-validation` | Page 0 | Non-containment bounding box overlaps between shapes |
| `page-orphans` | Page 0 | Isolated shapes (no edges) + dangling connectors (missing endpoints) |
#### Layout
| Action | Scope | Description |
|---|---|---|
| `page-recommendations` | Page 0 | Smallest standard page size (A4→A3→A2→A1→custom) that fits content with 80 px margin |
> For install/build instructions, source structure, and how to add new actions, see [maintenance.md](./maintenance.md).
See [semantic-lifecycle.md](./semantic-lifecycle.md) for command contracts, safety behavior, built-in policy identifiers, and examples.
---
## Capability 5 — Native service libraries
## Capability 5 — Safe source importers
The package includes additional strict TypeScript APIs under `scripts/src/services/`:
**Library only** — not reachable as a CLI action. Import from `dist/services/source-importers/index.js` (source `scripts/src/services/source-importers/index.ts`):
- `source-importers/` — conservative, bounded source/configuration topology extraction with diagnostics and no code execution;
- `themes/` and `shape-catalog/` — five validated themes and an offline generic shape catalog;
- `transforms/` — reverse Mermaid/Markdown, semantic diff, complete-map relabeling, and accessible bounded heatmaps;
- `profiles/` — C4, sequence, tube map, compression, runbook, timelapse, and build-up profiles.
```ts
import { importSource } from "<skill>/scripts/dist/services/source-importers/index.js";
```
These services are covered by the native test suite but are not registered CLI actions. Their exact peer-relative coverage and deliberate omissions are listed in [agents365-capability-coverage.md](./agents365-capability-coverage.md).
`importSource({ sourceKind, path, input })` performs conservative, bounded topology extraction with diagnostics and no code execution for `python`, `javascript`, `typescript`, `go`, `rust`, `terraform`, `kubernetes`, `docker-compose`, `sql`, `openapi`, and `ci` inputs, returning a Diagram IR v2 plus diagnostics and provenance.
---
## Capability 6 — Toolbox transforms
**Library only** — not reachable as a CLI action. Modules under `dist/services/` (source `scripts/src/services/`):
| Module | Exports | Purpose |
|---|---|---|
| `themes/theme-service.js` | `applyTheme`, `validateTheme`, `contrastRatio` | Five validated built-in themes, immutable IR application |
| `shape-catalog/shape-catalog.js` | `searchShapes` | Offline generic shape search (exact/alias/fuzzy) |
| `transforms/reverse.js` | `diagramIRToMermaid`, `diagramIRToStructuredMarkdown` | Reverse Mermaid / Markdown from IR |
| `transforms/semantic-diff.js` | `semanticDiff` | Added/removed/changed/moved/rerouted classification between two IR models |
| `transforms/relabel.js` | `relabelDiagram` | Strict complete-map relabeling preserving structure |
| `transforms/heatmap.js` | `applyMetricsHeatmap` | Accessible bounded metric heatmaps with legend metadata |
---
## Capability 7 — Specialized profiles
**Library only** — not reachable as a CLI action. Import from `dist/services/profiles/index.js` (source `scripts/src/services/profiles/index.ts`):
```ts
import { projectC4, createSequenceDiagram, createTubeMap, compressExecutiveView,
createRunbookHtml, createArchitectureTimelapse, createBuildup }
from "<skill>/scripts/dist/services/profiles/index.js";
```
C4 projection, sequence diagram layout, tube map routing, executive-view compression, runbook HTML, architecture timelapse, and dependency-ordered build-up frames.
---
Capabilities 5–7 are covered by the native test suite but are not registered CLI actions. Their exact peer-relative coverage and deliberate omissions are listed in [agents365-capability-coverage.md](./agents365-capability-coverage.md).
+23 -8
View File
@@ -36,7 +36,7 @@ The git repository is the source of truth. Install dependencies and build inside
```bash
cd <skill>/scripts
pnpm install
pnpm install --frozen-lockfile
task build # or: pnpm run build
```
@@ -99,7 +99,11 @@ src/
│ │ └── page-summary.ts # buildPageSummary() — shared per-page serialisation helper
│ ├── hierarchy-builder/
│ │ └── hierarchy-builder.ts # buildHierarchy() — shared BFS depth map + containment tree
│ └── semantic-lifecycle/ # import, edit, views/query/policy/what-if, sync, story, atomic I/O
│ ├── semantic-lifecycle/ # import, edit, views/query/policy/what-if, sync, story, atomic I/O
│ ├── layout/, authoring-router/ # deterministic layout + obstacle-aware routing used by build (ir-to-drawio)
│ ├── connector-router/ # edge path reconstruction used by page-connectors-summary/-validation
│ ├── maxgraph-loader/ # jsdom polyfill + maxGraph state loader (used by validate and negative-space)
│ └── source-importers/, transforms/, themes/, shape-catalog/, profiles/ # library-only services (no CLI action)
└── actions/
├── build|import|edit|views|query|test|what-if|sync|story|doctor/
│ # authoring and semantic lifecycle actions
@@ -113,6 +117,8 @@ src/
├── page-orphans/ # isolated shapes + dangling connectors
├── page-recommendations/ # page size recommendation
├── page-hierarchy-full/ # nesting levels with full shape geometry (x, y, width, height)
├── page-negative-space-summary/ # free horizontal corridors per nesting level (bbox + text-aware)
├── quality/ # all-pages clipping/overflow/placeholder/palette/density checks with severity
└── validate/ # MANDATORY final gate — XML well-formedness + maxGraph compile + sanity check
```
@@ -145,25 +151,34 @@ Each action exports `run(filePath, pageIndex?, outputPath?, options?): Record<st
## Adding a new action
1. Create `src/actions/<name>/action.ts` exporting:
1. Create `src/actions/<name>/action.ts` exporting a **synchronous** `run` (the dispatcher in `commands.ts` reads `result.summary` / `result.failed` without `await`, so an `async` function or a returned `Promise` would break exit-code handling). Copy the signature from an existing action, e.g. `src/actions/page-hierarchy/action.ts`:
```ts
export async function run(filePath: string, pageIndex?: number): Promise<Record<string, unknown>>
export function run(filePath: string, pageIndex: number = 0): Record<string, unknown> {
const pages = parseAllPages(filePath);
const page = pages[pageIndex];
if (!page) {
return { error: true, message: `Page index ${pageIndex} not found` };
}
// ...
return { action: "<name>", /* ... */ };
}
```
The full `ActionModule` contract is `run(filePath: string, pageIndex?: number, outputPath?: string, options?: LifecycleActionOptions): Record<string, unknown>`; declare only the parameters you use. Set `failed: true` in the result to make the CLI exit with code `1`.
2. Register it in `src/cli/commands.ts` under `ACTIONS`:
```ts
"my-action": () => import("../actions/my-action/action.js"),
```
3. Use `parseDiagram(filePath)` (first page) or `parseAllPages(filePath)` (all pages) from the parser
3. Use `parseAllPages(filePath)[pageIndex]` to honour `--page`, or `parseDiagram(filePath)` when the action is deliberately page-0-only; `parseAllPages` for all-page actions. Document the choice in the Scope column of `capabilities.md`
4. Optionally import `buildPageSummary(page)` from `page-summary.ts` for standard shape/edge serialisation
5. Return a plain object — the CLI serialises it to YAML automatically
6. Run `pnpm run build` to compile and verify no TypeScript errors
6. Run `task build` (or `pnpm run build`) to compile and verify no TypeScript errors, then add the action to `capabilities.md`, the `Actions:` list in `commands.ts --help`, and the Taskfile descriptions
### Naming convention
Actions follow `{object}-{action}` naming:
- `page-*` — operates on a single diagram page (uses `--page`, default 0)
- `summary` — operates on all pages
- `page-*` — operates on a single diagram page (`page-summary`, `page-hierarchy`, `page-hierarchy-full`, `page-negative-space-summary` honour `--page`; the remaining `page-*` actions currently analyse page 0 only)
- `summary`, `validate`, `quality` — operate on all pages
---
+43 -1
View File
@@ -27,7 +27,49 @@ These rules are **MANDATORY** — apply them when generating any diagram.
- `startSize=40`, 1 row h=80: total = 40+40+80+40 = 200 (children at y=80)
- `startSize=40`, 2 rows h=40 each: total = 40+40+40+40+40+40 = 240 (row1 at y=80, row2 at y=160)
After generating or editing a diagram, run `page-spacing-audit` and `page-swimlane-audit` to verify.
After generating or editing a diagram, run `page-shape-bbox-validation`, `page-connectors-validation`, and `page-hierarchy-full` (geometry per nesting level) to verify.
### Page size
- Use page dimensions that fully fit the diagram, **including margins, legends, and connector routing corridors** — never let content clip the page edge
- `page-recommendations` reports the smallest standard page size that fits the content with an 80 px margin
### Parent (container) sizing — MANDATORY
**A parent shape must always be large enough to fully enclose all its children, including inner padding.** When children grow (added, resized, or repositioned), expand the parent using:
```
parent.width = max_child_right + right_padding (right_padding ≥ 40, divisible by 40)
parent.height = max_child_bottom + bottom_padding (bottom_padding ≥ 40, divisible by 40)
```
Where `max_child_right = max(child.x + child.width)` and `max_child_bottom = max(child.y + child.height)` over all children (relative to the parent). Left/top inner padding must also be ≥ 40 pt and divisible by 40 pt.
- **Cascade rule:** parent expansion may force *its* parent to expand. Walk up the containment tree and resize each ancestor until the outermost container fits all descendants
- **Re-check after expansion:** when a parent grows, re-verify sibling spacing at every affected level — all gaps must remain divisible by 40 pt
### Grouping and complexity
- Keep diagram complexity medium: group services into logical zones/layers (swimlanes or containers per major domain) instead of scattering many unrelated services
- Never route dense connector bundles directly through container titles/headers (see label-crossing prohibition below)
### Connector labels and legends
- In dense diagrams keep connector labels **off the connector path**; if labels are needed, place them in a clearly empty corridor, a side note, or a dedicated legend
- Prefer a separate legend for flow explanations whenever connector labels would clutter the diagram
- Keep legends **outside the main routing area** so no connector crosses legend text
- Connector labels must never overlap shapes, cards, icons, or other text
### Final visual inspection
Before completion, re-open or visually inspect the diagram and check specifically for:
- shape overlap (including external actors, cards, icons, notes, legends, containers)
- connector overlap with cards/icons
- connector label overlap
- text overflowing card boundaries
- page clipping
- inconsistent spacing between lanes/columns and between rows
- missing canonical vendor shapes
---
+10 -1
View File
@@ -15,9 +15,17 @@ These rules are **MANDATORY** — apply them when generating any diagram.
- **Swimlane body height (total − startSize) must be divisible by 40** — so total height = 40 + N×40 = a multiple of 40
- Example: `startSize=40`, body=80 → total=120 ✓; body=160 → total=200 ✓
- Use ≤ 3 primary color families; create hierarchy with shades
- Use dashed connectors only for semantically distinct flows (async, backup, admin)
- Keep connector colors simple and consistent; use dashed connectors only for semantically distinct flows (async, backup, admin, private)
- Avoid borders on shapes unless needed for visual separation or canonical styling
- Shape size is driven by **content**, not routing — typically 80–160px tall per label line
### Text fit and cards
- Avoid long text inside narrow shapes; use wider cards or wrap the label in a dedicated text area inside the card
- Service names must fit within the visual card width and never extend beyond card boundaries
- For service-card diagrams use one consistent card pattern: icon on the left, service label on the right, enough padding around both
- When using canonical vendor icons, **preserve the original icon styling**; adjust the surrounding card/container layout instead of modifying the icon style
---
## Connector routing rules — MANDATORY
@@ -27,6 +35,7 @@ These rules are **MANDATORY** — apply them when generating any diagram.
- **Connectors must never attach at a shape corner** — the exit/entry point must lie on the middle of a side: top-center, bottom-center, left-center, or right-center. A point that is simultaneously on both an X-edge (left or right) AND a Y-edge (top or bottom) of the shape bounding box is a corner and is forbidden. Use the midpoint of the chosen side: `x_mid = (x1+x2)/2` for top/bottom sides, `y_mid = (y1+y2)/2` for left/right sides.
- These rules ensure a clean "bus-bar" fan-out/fan-in pattern and prevent connectors from diverging at their source or converging at their target at different positions, which creates visual clutter and increases crossing risk.
- Exception: shapes with only a single outgoing or single incoming connector — the single-port rule trivially holds. The corner rule still applies.
- **Arrowheads stay outside shape interiors** — connectors touch the shape/card edge and never pass through the body.
- When computing waypoints: use `page-negative-space-summary` to find free X corridors per row, then pick an exit/entry coordinate that lies within a free corridor at the next traversed level. This minimises connector-shape overlaps and connector crossings.
- **Waypoints must never be closer than 20px to any shape** — the first waypoint after a shape exit must be at least 20px away from the shape's edge in the direction of travel (e.g., if exiting bottom at y=520, first waypoint y ≥ 540; if exiting right at x=1040, first waypoint x ≥ 1060). The last waypoint before a shape entry must likewise be at least 20px away from the shape's edge. This 20px clearance also applies to any waypoint relative to same-level sibling shapes the connector passes by — the waypoint must not come within 20px of any sibling shape's bounding box side it is adjacent to.
+1 -1
View File
@@ -32,7 +32,7 @@ node dist/cli/commands.js --action edit \
--output edited.drawio
```
A batch targets one page and supports typed `add`, `update`, `move`, `delete`, and `connect` operations. Supported preconditions are `exists`, `not-exists`, and `property-equals`, each expressed with a `type` and `id`. Unknown precondition or operation types, update payloads that attempt to change `id`, duplicate identifiers, invalid parents/endpoints, and non-cascading deletion of referenced elements fail closed and abort the entire batch. Dry runs return a preview and write nothing.
A batch targets one page and supports typed `add`, `update`, `move`, `delete`, and `connect` operations. Supported preconditions are `exists`, `not-exists`, and `property-equals`, each expressed with a `type` and `id`; `property-equals` additionally requires `property` (the property name) and `value` (the exact expected value). The shipped `examples/edit-batch.yaml` is tied to `examples/platform-v2.yaml` (page `system`, node `api`) — build or import that model first, or adapt the IDs before applying the batch to another model. Unknown precondition or operation types, update payloads that attempt to change `id`, duplicate identifiers, invalid parents/endpoints, and non-cascading deletion of referenced elements fail closed and abort the entire batch. Dry runs return a preview and write nothing.
## Linked audience views