@laitszkin/apollo-toolkit 3.9.7 → 3.11.0

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.
Files changed (55) hide show
  1. package/AGENTS.md +2 -0
  2. package/CHANGELOG.md +37 -0
  3. package/README.md +6 -0
  4. package/analyse-app-logs/scripts/__pycache__/filter_logs_by_time.cpython-312.pyc +0 -0
  5. package/analyse-app-logs/scripts/__pycache__/log_cli_utils.cpython-312.pyc +0 -0
  6. package/analyse-app-logs/scripts/__pycache__/search_logs.cpython-312.pyc +0 -0
  7. package/cjk-pdf/agents/openai.yaml +5 -0
  8. package/docs-to-voice/scripts/__pycache__/docs_to_voice.cpython-312.pyc +0 -0
  9. package/generate-spec/SKILL.md +26 -4
  10. package/generate-spec/agents/openai.yaml +1 -0
  11. package/generate-spec/references/TEMPLATE_SPEC.md +117 -0
  12. package/generate-spec/scripts/__pycache__/create-specscpython-312.pyc +0 -0
  13. package/init-project-html/SKILL.md +137 -0
  14. package/init-project-html/agents/openai.yaml +22 -0
  15. package/init-project-html/lib/atlas/assets/architecture.css +140 -0
  16. package/init-project-html/lib/atlas/assets/viewer.client.js +93 -0
  17. package/init-project-html/lib/atlas/cli.js +995 -0
  18. package/init-project-html/lib/atlas/layout.js +229 -0
  19. package/init-project-html/lib/atlas/render.js +485 -0
  20. package/init-project-html/lib/atlas/schema.js +310 -0
  21. package/init-project-html/lib/atlas/state.js +402 -0
  22. package/init-project-html/references/TEMPLATE_SPEC.md +137 -0
  23. package/init-project-html/references/architecture-page.template.html +35 -0
  24. package/init-project-html/references/architecture.css +1059 -0
  25. package/init-project-html/sample-demo/resources/project-architecture/assets/architecture.css +140 -0
  26. package/init-project-html/sample-demo/resources/project-architecture/assets/viewer.client.js +93 -0
  27. package/init-project-html/sample-demo/resources/project-architecture/atlas/atlas.index.yaml +34 -0
  28. package/init-project-html/sample-demo/resources/project-architecture/atlas/features/get-invite-codes.yaml +159 -0
  29. package/init-project-html/sample-demo/resources/project-architecture/atlas/features/invite-code-registration.yaml +160 -0
  30. package/init-project-html/sample-demo/resources/project-architecture/features/get-invite-codes/index.html +69 -0
  31. package/init-project-html/sample-demo/resources/project-architecture/features/get-invite-codes/invite-code-generator.html +50 -0
  32. package/init-project-html/sample-demo/resources/project-architecture/features/get-invite-codes/invite-issuance-service.html +72 -0
  33. package/init-project-html/sample-demo/resources/project-architecture/features/get-invite-codes/postgresql.html +66 -0
  34. package/init-project-html/sample-demo/resources/project-architecture/features/get-invite-codes/public-api.html +70 -0
  35. package/init-project-html/sample-demo/resources/project-architecture/features/get-invite-codes/web-get-invite-ui.html +67 -0
  36. package/init-project-html/sample-demo/resources/project-architecture/features/invite-code-registration/index.html +63 -0
  37. package/init-project-html/sample-demo/resources/project-architecture/features/invite-code-registration/postgresql.html +68 -0
  38. package/init-project-html/sample-demo/resources/project-architecture/features/invite-code-registration/public-api.html +65 -0
  39. package/init-project-html/sample-demo/resources/project-architecture/features/invite-code-registration/registration-service.html +79 -0
  40. package/init-project-html/sample-demo/resources/project-architecture/features/invite-code-registration/web-register-ui.html +67 -0
  41. package/init-project-html/sample-demo/resources/project-architecture/index.html +234 -0
  42. package/init-project-html/scripts/architecture.js +314 -0
  43. package/katex/scripts/__pycache__/render_katex.cpython-312.pyc +0 -0
  44. package/lib/cli.js +2 -0
  45. package/lib/tool-runner.js +7 -0
  46. package/merge-conflict-resolver/agents/openai.yaml +5 -0
  47. package/open-github-issue/scripts/__pycache__/open_github_issue.cpython-312.pyc +0 -0
  48. package/package.json +6 -2
  49. package/read-github-issue/scripts/__pycache__/find_issues.cpython-312.pyc +0 -0
  50. package/read-github-issue/scripts/__pycache__/read_issue.cpython-312.pyc +0 -0
  51. package/resolve-review-comments/scripts/__pycache__/review_threads.cpython-312.pyc +0 -0
  52. package/spec-to-project-html/SKILL.md +114 -0
  53. package/spec-to-project-html/agents/openai.yaml +18 -0
  54. package/spec-to-project-html/references/TEMPLATE_SPEC.md +111 -0
  55. package/text-to-short-video/scripts/__pycache__/enforce_video_aspect_ratio.cpython-312.pyc +0 -0
package/AGENTS.md CHANGED
@@ -77,6 +77,8 @@ This repository enables users to install and run a curated set of reusable agent
77
77
  - `node bin/apollo-toolkit.js codex openclaw trae` - 以非互動方式將技能安裝到指定目標。
78
78
  - `node bin/apollo-toolkit.js tools` - 列出 Apollo Toolkit 內建 CLI 工具。
79
79
  - `node bin/apollo-toolkit.js filter-logs app.log --start 2026-03-24T10:00:00Z` - 透過內建工具包裝器執行技能腳本。
80
+ - `node bin/apollo-toolkit.js architecture` - 開啟專案 `resources/project-architecture/index.html` 架構圖。
81
+ - `node bin/apollo-toolkit.js architecture diff` - 將 `docs/plans/**/architecture_diff/` 與目前架構圖配對成分頁式 before/after viewer(輸出至 `.apollo-toolkit/architecture-diff/`)。
80
82
  - `python3 scripts/validate_skill_frontmatter.py` - 驗證所有頂層技能 `SKILL.md` 的 frontmatter。
81
83
  - `python3 scripts/validate_openai_agent_config.py` - 驗證所有技能 `agents/openai.yaml` 設定。
82
84
  - `./scripts/install_skills.sh codex` - 用本地安裝腳本把技能安裝到 Codex 目錄。
package/CHANGELOG.md CHANGED
@@ -10,6 +10,43 @@ All notable changes to this repository are documented in this file.
10
10
 
11
11
  ### Fixed
12
12
 
13
+ ## [v3.11.0] - 2026-05-11
14
+
15
+ ### Added
16
+
17
+ - Declarative atlas CLI: every component (feature, sub-module, function, variable, dataflow step, error, edge, actor, meta) is now declared through `apltk architecture <verb> ...`. The CLI persists per-feature YAML under `resources/project-architecture/atlas/`, runs deterministic layout via `elkjs`, and re-renders HTML/SVG (with built-in pan/zoom) on every mutation.
18
+ - `--spec <spec_dir>` flag: spec-mode mutations write the overlay snapshot under `<spec_dir>/architecture_diff/atlas/` and render only the affected proposed-after HTML pages there; `apltk architecture diff` continues to pair pages by relative path.
19
+ - `apltk architecture` new verbs: `render`, `validate`, `undo`, plus per-component `add` / `set` / `remove` actions for features, sub-modules, functions, variables, dataflow steps, errors, and edges.
20
+ - Built-in pan/zoom client for the macro atlas (mouse wheel, drag, +/-/Fit toolbar, keyboard arrows) shipped as `lib/atlas/assets/viewer.client.js`.
21
+ - New test suites: `test/atlas-state.test.js`, `test/atlas-render.test.js`, `test/atlas-cli.test.js` covering YAML round-trip, overlay merge, layout no-overlap, rendering scope, and every CLI verb.
22
+ - New runtime dependencies: `elkjs` (layered layout) and `js-yaml` (YAML state).
23
+
24
+ ### Changed
25
+
26
+ - `init-project-html`, `spec-to-project-html`, and `generate-spec` SKILL.md / agents/openai.yaml / `references/TEMPLATE_SPEC.md`: rewritten around CLI verbs and the declarative atlas; binding rules now forbid hand-authoring HTML under `resources/project-architecture/**` or `architecture_diff/**` (the renderer owns layout, no-overlap, DOM, CSS, ARIA, pan/zoom).
27
+ - `init-project-html/sample-demo/`: converted to YAML source (`atlas/atlas.index.yaml` + `atlas/features/*.yaml`) and regenerated via the new CLI.
28
+ - `init-project-html/scripts/architecture.js`: now a thin shim — the legacy `open` / `diff` verbs stay sync for backward-compatible tests, while new declarative verbs (`feature add`, `submodule add`, etc.) route through `lib/atlas/cli.js`.
29
+ - `.gitignore`: ignore `node_modules/` for local development; document that `package-lock.json` must remain committed so `npm ci` installs and published installs resolve the same dependency tree (`elkjs`, `js-yaml`).
30
+
31
+ ### Fixed
32
+
33
+ ## [v3.10.0] - 2026-05-11
34
+
35
+ ### Added
36
+
37
+ - `init-project-html` skill: HTML architecture atlas (macro × sub-module SVG contract, sample demo, `references/TEMPLATE_SPEC.md` cheat sheet, `apltk architecture` helper script).
38
+ - `spec-to-project-html` skill: refresh `resources/project-architecture/**` from active `docs/plans/**` specs using the same atlas rules.
39
+ - `apltk architecture` and `apltk architecture diff`: open the project atlas or render a paginated before/after viewer from every `docs/plans/**/architecture_diff/` tree (pairs paths with `resources/project-architecture/`).
40
+ - `generate-spec/references/TEMPLATE_SPEC.md` and `spec-to-project-html/references/TEMPLATE_SPEC.md`: local copies of the atlas vocabulary + DOM cheat sheet so each skill is self-contained when installed.
41
+ - `cjk-pdf/agents/openai.yaml` and `merge-conflict-resolver/agents/openai.yaml` OpenAI agent interface stubs.
42
+ - `test/architecture-script.test.js` covering registration, diff classification, and viewer output paths.
43
+
44
+ ### Changed
45
+
46
+ - `generate-spec`: when a spec touches the atlas surface, emit `architecture_diff/` next to `spec.md` with path-aligned after-HTML (`_removed.txt` for deletions); keep rules in SKILL.md (reference file is non-authoritative).
47
+ - Root `README.md` and `AGENTS.md`: document `apltk architecture` / `architecture diff` examples.
48
+ - `.gitignore`: ignore `.apollo-toolkit/` (default output for the diff viewer).
49
+
13
50
  ## [v3.9.7] - 2026-05-09
14
51
 
15
52
  ### Changed
package/README.md CHANGED
@@ -25,6 +25,7 @@ A curated skill catalog for Codex, OpenClaw, Trae, Agents, and Claude Code with
25
25
  - implement-specs
26
26
  - implement-specs-with-subagents
27
27
  - implement-specs-with-worktree
28
+ - init-project-html
28
29
  - improve-observability
29
30
  - iterative-code-performance
30
31
  - iterative-code-quality
@@ -49,6 +50,7 @@ A curated skill catalog for Codex, OpenClaw, Trae, Agents, and Claude Code with
49
50
  - scheduled-runtime-health-check
50
51
  - shadow-api-model-research
51
52
  - solana-development
53
+ - spec-to-project-html
52
54
  - solve-issues-found-during-review
53
55
  - submission-readiness-check
54
56
  - systematic-debug
@@ -112,6 +114,10 @@ apltk tools
112
114
  apltk filter-logs app.log --start "2026-03-24T10:00:00Z"
113
115
  apltk create-specs "Membership upgrade flow" --change-name membership-upgrade-flow
114
116
  apltk open-github-issue --help
117
+
118
+ # Browse architecture HTML atlas and active-spec diffs
119
+ apltk architecture # opens resources/project-architecture/index.html
120
+ apltk architecture diff # paginates docs/plans/**/architecture_diff/ vs atlas
115
121
  ```
116
122
 
117
123
  ### Non-interactive install
@@ -0,0 +1,5 @@
1
+ interface:
2
+ display_name: "cjk-pdf"
3
+ short_description: "CJK-safe PDF rendering, font selection, and screenshot visual QA"
4
+ default_prompt: >-
5
+ Use $cjk-pdf when producing PDFs that include Chinese or mixed CJK text: verify macOS font paths, enforce content safety, delegate rendering to the external `pdf` skill, then run screenshot-based visual QA before returning the final artifact.
@@ -1,10 +1,11 @@
1
1
  ---
2
2
  name: generate-spec
3
3
  description: >-
4
- Author planning trees under docs/plans: run `apltk create-specs`, hydrate templates (`spec/tasks/checklist/contract/design`; add `coordination.md`/`preparation.md` when parallel/prep dictates), cite official docs for every material external dependency, plan tests with **`test-case-strategy`**, and block product code changes until explicit user approval completes.
5
- Use when drafting or refreshing specs before coding, restructuring multi-member batches, or recording clarifications—not when simply executing tasks from an approved plan (**`implement-specs*`** family instead).
6
- Reject ALWAYS vague `tasks.md` lines missing file target + mutation + verifier; SPLIT work when scope exceeds three modules; never overwrite a neighboring `{change}` directory for a different issue.
7
- Example bad: `- [ ] Add tests`… Example ok: `- [ ] src/auth/scope.rs deny unknown scopes Verify: cargo test scope::defaults`…
4
+ Author docs/plans trees: run `apltk create-specs`, hydrate `spec/tasks/checklist/contract/design` (+ `coordination.md`/`preparation.md` when parallel/prep dictates), cite official docs for external deps, plan tests via **`test-case-strategy`**, block code edits until explicit user approval.
5
+ Architecture-touching specs declare the proposed-after atlas via `apltk architecture --spec <spec_dir> <verb> ...`; the CLI writes overlay YAML to `<spec_dir>/architecture_diff/atlas/` and re-renders only the affected proposed-after HTML pages — never hand-author files under `architecture_diff/`.
6
+ Use when drafting/refreshing specs or restructuring batches not when executing approved plans (use **`implement-specs*`** instead).
7
+ Reject vague `tasks.md` missing file/mutation/verifier; SPLIT >3-module scope; never overwrite a neighbor `{change}`.
8
+ Bad: `- [ ] Add tests`… OK: `- [ ] src/auth/scope.rs — deny unknown scopes — Verify: cargo test scope::defaults`…
8
9
  ---
9
10
 
10
11
  # Generate Spec
@@ -26,6 +27,7 @@ description: >-
26
27
  - **`tasks.md` checklist items**: **every** `- [ ]` **MUST** specify (a) concrete file/function target, (b) specific modification and expected outcome, (c) a verification hook—**no** vague rows (`Implement integration`, `Add tests`). Forbidden vague items **MUST** be rewritten before approval.
27
28
  - **MUST** use `test-case-strategy` when planning non-trivial logic tests and checklist mapping (test IDs, drift checks). Every **non-trivial** `tasks.md` implementation item **MUST** name a focused unit drift check, another concrete verification hook, or **`N/A`** with a concrete reason.
28
29
  - **MUST NOT** modify implementation code before **explicit user approval** of the spec set. Clarifications **MUST** sync across affected files and **MUST** re-trigger approval. If scope becomes a **different issue**, **MUST** stop editing the old set and create a **new** `change_name`.
30
+ - **MUST** when the proposed change touches the architecture surface (feature / sub-module add / rename / remove, edge add / remove, `sub-vars` or function I/O deltas, internal dataflow / error deltas), declare the proposed-after state through `apltk architecture --spec <spec_dir> <verb> ...`. The CLI writes overlay YAML to `<spec_dir>/architecture_diff/atlas/` and renders only the affected proposed-after HTML pages under `<spec_dir>/architecture_diff/`; `apltk architecture diff` then pairs them with the base atlas by path. **MUST NOT** hand-author files under `architecture_diff/**` — the renderer owns layout, no-overlap, DOM, CSS, ARIA, and pan/zoom. For batch specs the overlay lives in each member spec's own directory only — **MUST NOT** duplicate at batch root. See this skill's own `references/TEMPLATE_SPEC.md` for the component schema cheat sheet and a quick worked example; the binding verbs and semantic rules live in `init-project-html/SKILL.md`.
29
31
  - Write prose in the **user’s language** by default; keep requirement/task/test IDs traceable across `spec.md`, `tasks.md`, and `checklist.md`.
30
32
  - **MUST** use **kebab-case** `change_name`; **MUST NOT** use spaces or arbitrary special characters in names.
31
33
 
@@ -79,6 +81,26 @@ Always materialize: `spec.md`, `tasks.md`, `checklist.md`, `contract.md`, `desig
79
81
  - **Pause →** Do **`design.md` / `contract.md`** stay **coarser than `tasks.md`** (no mirrored checkbox choreography / file paths)—yet still constrain ordering and forbidden hallucinations?
80
82
  - **Pause →** For parallel batches, does `design.md` **avoid** duplicating batch ownership grids already locked in **`coordination.md`**?
81
83
 
84
+ ### 3.5) Architecture diff (only when the proposal touches the architecture surface)
85
+
86
+ When the spec changes a feature module, sub-module, edge, variable, or function I/O, declare the proposed-after state through the CLI scoped to this spec directory:
87
+
88
+ ```bash
89
+ SPEC_DIR=docs/plans/<date>/<change_name>
90
+ apltk architecture --spec "$SPEC_DIR" feature add --slug ... --title "..." --story "..." --no-render
91
+ apltk architecture --spec "$SPEC_DIR" submodule add|set|remove --feature ... --slug ... --kind ... --role "..." --no-render
92
+ apltk architecture --spec "$SPEC_DIR" function|variable|dataflow|error add|remove ... --no-render
93
+ apltk architecture --spec "$SPEC_DIR" edge add|remove --from <feat>[/sub] --to <feat>[/sub] --kind ... --label "..." --no-render
94
+ apltk architecture --spec "$SPEC_DIR" render
95
+ apltk architecture --spec "$SPEC_DIR" validate
96
+ ```
97
+
98
+ The CLI writes overlay YAML under `$SPEC_DIR/architecture_diff/atlas/` and re-renders only the affected HTML pages under `$SPEC_DIR/architecture_diff/`. Cross-feature edges into features that are not declared in the overlay still resolve against the base atlas. For batch specs, scope each member spec's overlay to its own directory — never duplicate at the batch root. **Do not hand-edit** any file under `architecture_diff/`.
99
+
100
+ - **Pause →** Did I touch any file under `architecture_diff/` by hand? Revert and re-run the CLI verb instead.
101
+ - **Pause →** Does `apltk architecture --spec "$SPEC_DIR" validate` return OK? Resolve dangling edges and unknown enums before approval.
102
+ - **Pause →** Does `apltk architecture diff` pair the spec's pages correctly (modified / added / removed)? A page that shows as remove + add means a slug was renamed inadvertently.
103
+
82
104
  ### 4) Clarifications and approval
83
105
 
84
106
  On answers: update clarification/approval section in `checklist.md` first, then any of `spec.md`, `tasks.md`, `checklist.md`, `contract.md`, `design.md`; **MUST** obtain approval again after material edits. **MUST NOT** touch product code pre-approval.
@@ -4,3 +4,4 @@ interface:
4
4
  default_prompt: >-
5
5
  Use $generate-spec to create or update single-spec plans under docs/plans/<date>/<change_name>/ or parallel batches under docs/plans/<date>/<batch_name>/<change_name>/ with shared coordination.md and, only when specs cannot be parallel-safe without prior shared work, minimal non-business preparation.md; treat references/templates/*.md as binding format; member specs assume preparation finished—do not duplicate preparation tasks; surface collisions early and resolve ownership via coordination.md; fill BDD in spec.md; integrate $test-case-strategy into tasks/checklists.
6
6
  **Critical layering:** design.md + contract.md are higher-level guiding context only (architecture + cite-backed external truth; coarse INT-### / EXT-### anchors). tasks.md MUST be the ONLY enumerated runnable queue with path-level edits and verification hooks—derive tasks FROM spec + design + contract WITHOUT mirroring checklist rows into design/contract; optionally cite INT/EXT on task lines for traceability—never duplicate task choreography inside design.md or contract.md.
7
+ **Architecture diff:** When the spec touches the architecture surface (feature/sub-module add/rename/remove, edge changes, sub-vars / sub-io / dataflow / error deltas), declare the proposed-after state through `apltk architecture --spec <spec_dir> <verb> ...`. The CLI writes overlay YAML under `<spec_dir>/architecture_diff/atlas/` and renders only the affected HTML pages under `<spec_dir>/architecture_diff/`; `apltk architecture diff` then pairs them with the base atlas by path. NEVER hand-author files under `architecture_diff/**` — the renderer owns layout, no-overlap, DOM, CSS, ARIA, and pan/zoom. Use $init-project-html `SKILL.md` and `references/TEMPLATE_SPEC.md` for the verb cheat sheet (`feature`, `submodule`, `function`, `variable`, `dataflow`, `error`, `edge` add/remove/set + `meta set`, `actor add`, plus `render`, `validate`, `undo`). For batch specs scope each member's overlay to that member's directory only — never duplicate at the batch root. Always run `apltk architecture --spec <spec_dir> validate` after the final mutation and ensure `apltk architecture diff` pairs every changed page (modified / added / removed) correctly.
@@ -0,0 +1,117 @@
1
+ # Atlas component schema — reference cheat sheet (generate-spec copy)
2
+
3
+ > Reference material only. The binding rules for atlas pages (verbs, semantic contracts, evidence) live in `init-project-html/SKILL.md`. The binding rule for spec-time atlas changes (declare via CLI, never hand-author HTML) lives in this skill's own `generate-spec/SKILL.md`. This file lists the exact fields and enum values that `apltk architecture --spec <spec_dir>` accepts.
4
+
5
+ ## Where the overlay lands
6
+
7
+ When you run any `apltk architecture --spec <spec_dir> <verb> ...`, the CLI writes:
8
+
9
+ ```
10
+ <spec_dir>/architecture_diff/
11
+ ├── atlas/
12
+ │ ├── atlas.index.yaml # optional partial override of meta / actors / cross-feature edges / feature ordering
13
+ │ ├── features/<slug>.yaml # full proposed state of any changed feature
14
+ │ ├── _removed.yaml # {features: [...], submodules: [{feature, submodule}]}
15
+ │ ├── atlas.history.log
16
+ │ └── atlas.history.undo.json
17
+ ├── index.html # rendered when macro visibly changes
18
+ ├── features/<slug>/index.html # rendered when feature page visibly changes
19
+ ├── features/<slug>/<sub>.html # rendered when sub-module visibly changes
20
+ ├── _removed.txt # auto-written from _removed.yaml; consumed by `apltk architecture diff`
21
+ └── assets/ # architecture.css + viewer.client.js (copied by the renderer)
22
+ ```
23
+
24
+ `apltk architecture diff` scans every `docs/plans/**/architecture_diff/**/*.html`, pairs them with `resources/project-architecture/` by relative path, and classifies each as **modified**, **added**, or **removed**. The CLI's overlay path layout guarantees correct pairing — agents do not need to manage paths manually.
25
+
26
+ ## Components (mirrors `init-project-html/references/TEMPLATE_SPEC.md`)
27
+
28
+ The same component fields and enums apply in spec mode:
29
+
30
+ | Component | Required fields | Enum values |
31
+ | --------- | --------------- | ----------- |
32
+ | `meta` | `title` | — (`summary` optional) |
33
+ | `actor` | `id` (kebab-case), `label` | — |
34
+ | `feature` | `slug` (kebab-case), `title` | — (`story`, `dependsOn` optional) |
35
+ | `submodule` | `slug` (kebab-case), `kind` | `ui` `api` `service` `db` `pure-fn` `queue` `external` |
36
+ | `function` | `name` | `side`: `pure` `io` `write` `tx` `lock` `network` |
37
+ | `variable` | `name` | `scope`: `call` `tx` `persist` `instance` `loop` |
38
+ | `dataflow` step | string | — |
39
+ | `error` | `name` | — (`when`, `means` optional) |
40
+ | `edge` | `from`, `to`, `kind` | `kind`: `call` `return` `data-row` `failure` |
41
+
42
+ ## Verb cheat sheet (spec mode)
43
+
44
+ Always pass `--spec <spec_dir>`. Common patterns:
45
+
46
+ ```bash
47
+ # Open the spec directory once as a shell variable for readability:
48
+ SPEC_DIR=docs/plans/2026-05-11/add-2fa
49
+
50
+ # Add a new sub-module to an existing feature in the base atlas:
51
+ apltk architecture --spec "$SPEC_DIR" submodule add \
52
+ --feature register --slug 2fa --kind service \
53
+ --role "TOTP verification (planned: not yet implemented)" --no-render
54
+
55
+ # Adjust an existing sub-module's role / kind:
56
+ apltk architecture --spec "$SPEC_DIR" submodule set \
57
+ --feature register --slug api --role "Endpoint with 2FA gate" --no-render
58
+
59
+ # Add functions / variables / dataflow / errors:
60
+ apltk architecture --spec "$SPEC_DIR" function add \
61
+ --feature register --submodule 2fa --name VerifyTotp \
62
+ --in "ctx, code" --out "ok | ErrInvalidTotp" --side network \
63
+ --purpose "Checks the TOTP code against the user's seed." --no-render
64
+
65
+ apltk architecture --spec "$SPEC_DIR" variable add \
66
+ --feature register --submodule 2fa --name totp_seed \
67
+ --type "bytes[20]" --scope persist \
68
+ --purpose "Seed material for TOTP verification (per user)." --no-render
69
+
70
+ apltk architecture --spec "$SPEC_DIR" dataflow add \
71
+ --feature register --submodule 2fa --step "Load seed for userId" --no-render
72
+ apltk architecture --spec "$SPEC_DIR" dataflow add \
73
+ --feature register --submodule 2fa --step "Validate TOTP code window" --no-render
74
+
75
+ apltk architecture --spec "$SPEC_DIR" error add \
76
+ --feature register --submodule 2fa --name ErrInvalidTotp \
77
+ --when "Code mismatch within accepted window." \
78
+ --means "422 response with totp reason." --no-render
79
+
80
+ # Add intra-feature edge:
81
+ apltk architecture --spec "$SPEC_DIR" edge add \
82
+ --from register/api --to register/2fa --kind call \
83
+ --label "verify TOTP" --id e-api-2fa --no-render
84
+
85
+ # Removals (overlay records them in _removed.yaml; the renderer emits _removed.txt):
86
+ apltk architecture --spec "$SPEC_DIR" feature remove --slug legacy --no-render
87
+ apltk architecture --spec "$SPEC_DIR" submodule remove --feature register --slug v0-shim --no-render
88
+
89
+ # Render + validate once at the end (sed for batched mutations):
90
+ apltk architecture --spec "$SPEC_DIR" render
91
+ apltk architecture --spec "$SPEC_DIR" validate
92
+ ```
93
+
94
+ ## Important constraints (binding)
95
+
96
+ - **Never** hand-edit any file under `architecture_diff/` — the renderer rewrites them on every `apltk architecture --spec ... render` call.
97
+ - The base atlas under `resources/project-architecture/` is **read-only** in spec mode; CLI writes never touch it.
98
+ - Cross-feature edges into features that are not overlaid still resolve against the base atlas without re-declaring those features.
99
+ - For batch specs, scope each member's overlay to its own member directory; never duplicate at the batch root.
100
+
101
+ ## Worked example: end-to-end overlay for a new "add 2FA" spec
102
+
103
+ The CLI invocation above produces this overlay tree (rendered HTML omitted for brevity):
104
+
105
+ ```
106
+ docs/plans/2026-05-11/add-2fa/architecture_diff/
107
+ ├── atlas/
108
+ │ ├── atlas.index.yaml
109
+ │ └── features/register.yaml
110
+ ├── index.html
111
+ ├── features/register/index.html
112
+ ├── features/register/api.html
113
+ ├── features/register/2fa.html
114
+ └── assets/architecture.css
115
+ ```
116
+
117
+ Running `apltk architecture diff` then pairs `register/2fa.html` (added) and `register/api.html` + `register/index.html` + `index.html` (modified) with their base counterparts.
@@ -0,0 +1,137 @@
1
+ ---
2
+ name: init-project-html
3
+ description: >-
4
+ Declare the project HTML architecture atlas through `apltk architecture` CLI verbs instead of hand-writing SVG/HTML. The tool owns layout, no-overlap, DOM, CSS, and pan/zoom; the agent only declares features, sub-modules, functions, variables, dataflow steps, errors, and edges. Macro `index.html` always shows feature clusters with their sub-modules and every cross/intra-feature edge; each sub-module page describes only itself (function I/O + variables-with-business-purpose + internal dataflow + local errors); feature index pages stay lightweight. Read strategy avoids context loss: list feature modules first, then either dispatch one read-only subagent per feature and aggregate summaries before declaring, or process one feature at a time end-to-end. Anchor every declaration to repo evidence.
5
+ ---
6
+
7
+ # Init Project HTML
8
+
9
+ ## Dependencies
10
+
11
+ - Required: none (the CLI ships its own layout engine, CSS, and pan/zoom client; `apltk architecture` is installed with this toolkit).
12
+ - Conditional: `spec-to-project-html` when the same atlas needs spec-driven refresh — that skill uses the same CLI with `--spec`.
13
+ - Optional: `align-project-documents` when `docs/features` already names the user-visible capabilities.
14
+ - Fallback: codebase too large for one pass → use the subagent strategy below, document scanned roots and explicit omissions in `meta.summary`. **MUST NOT** declare components for code paths that were never read.
15
+
16
+ ## Non-negotiables
17
+
18
+ ### Rule 1 — Use the CLI; never hand-author atlas HTML
19
+
20
+ The atlas state lives in `resources/project-architecture/atlas/` (`atlas.index.yaml` + per-feature YAMLs). Every change goes through `apltk architecture <verb> ...`. After any mutation, the CLI re-renders `resources/project-architecture/**/*.html` with the correct layout, CSS, pan/zoom, and ARIA — agents **MUST NOT** edit those HTML files by hand or invent additional ones.
21
+
22
+ ### Rule 2 — Sub-module pages describe only themselves
23
+
24
+ What the CLI emits on each sub-module page is fixed:
25
+
26
+ - function I/O table (`function add --feature X --submodule Y --name fn --in ... --out ... --side ... --purpose ...`),
27
+ - variables-with-business-purpose table (`variable add --name v --type T --scope call|tx|persist|instance|loop --purpose ...`),
28
+ - internal dataflow steps (`dataflow add --step "..."`),
29
+ - local errors (`error add --name ErrX --when ... --means ...`).
30
+
31
+ Cross-boundary narratives ("I call X", "Y calls me") **MUST** be expressed as macro edges (`edge add --from X/sub --to Y/sub --kind call|return|data-row|failure --label ...`), never as sub-module page prose. The CLI enforces this by design — there is no verb to add cross-boundary text to a sub-module page.
32
+
33
+ ### Rule 3 — Read order: never let the codebase wipe the context window
34
+
35
+ Real production codebases dwarf the main agent's context. Reading the whole repo before declaring pushes early details out by the end, making macro edges and sub-module declarations contradict each other. **MUST** follow one of:
36
+
37
+ - **With subagents (preferred):** first enumerate the **feature-module list** (slug + entry + boundary resources only). Then dispatch **one read-only subagent per feature**. Each subagent deep-reads and returns ONLY a structured summary (sub-module list with kind/role; per sub-module: function I/O, variables-with-business-purpose, internal dataflow steps, errors; outbound edges to other features). The main agent collects every summary first, then drives the CLI in one pass to declare every component.
38
+ - **Without subagents:** process features **one at a time** — read feature A end-to-end, then declare it via the CLI (`feature add`, `submodule add`, `function add`, `variable add`, `dataflow add`, `error add`, intra-feature `edge add`). For cross-feature edges that point at not-yet-declared features, declare the placeholder feature with `feature add --slug <future> --title <future>` first, then add the edge; subsequent passes set the real title/story. Drop A's function-level details from working memory before reading feature B.
39
+
40
+ Both paths share one invariant: at any moment the main agent only holds *current-feature details + cross-feature boundary notes*. Run `apltk architecture validate` after the last feature to catch dangling edges, unknown endpoints, or missing required fields.
41
+
42
+ ### Rule 4 — Evidence over invention
43
+
44
+ - **MUST** anchor every declared feature, sub-module, function, variable, dataflow step, and edge to a concrete path / symbol / SQL / config; record scanned roots and any deliberate omissions in `meta.summary` via `apltk architecture meta set --summary "..."`.
45
+ - **MUST NOT** invent modules, integrations, or sub-modules just because the diagram "looks balanced". Empty rows are valid; lies are not.
46
+
47
+ ## Standards (summary)
48
+
49
+ - **Evidence**: every CLI declaration traces to a path/symbol/SQL/config; uncertain areas surface as `TBD` strings or are omitted with a recorded reason.
50
+ - **Execution**: feature-module list (shallow) → branch by environment (subagent fan-out or sequential read-declare) → `apltk architecture validate` → handover report.
51
+ - **Quality**: macro SVG carries every cross-feature data-row edge that exists in the system; sub-module declarations are self-only; pan/zoom + Fit work in the rendered HTML; `apltk architecture validate` returns OK.
52
+ - **Output**: `resources/project-architecture/atlas/` (YAML state) + `resources/project-architecture/**/*.html` (renderer output) — both managed by the CLI.
53
+
54
+ ## How to use `apltk architecture`
55
+
56
+ Each verb is a single mutation; the CLI auto-renders after every change. Pass `--no-render` when batching mutations. Global flags: `--project <root>`, `--spec <spec_dir>` (writes to overlay; see `spec-to-project-html`), `--no-render`, `--no-open`.
57
+
58
+ | Verb | Use it to… |
59
+ | --- | --- |
60
+ | `apltk architecture meta set --title ... --summary ...` | Set the macro title + atlas summary (read order, scanned roots, deliberate omissions). |
61
+ | `apltk architecture actor add --id end-user --label "End user"` | Add a top-level actor (optional; appears in macro context). |
62
+ | `apltk architecture feature add --slug <kebab> --title "..." --story "..." [--depends-on a,b]` | Declare a feature module (user-visible capability). |
63
+ | `apltk architecture submodule add --feature <slug> --slug <kebab> --kind ui\|api\|service\|db\|pure-fn\|queue\|external --role "..."` | Declare a sub-module under a feature. |
64
+ | `apltk architecture function add --feature X --submodule Y --name fn --in "T1, T2" --out "R \| ErrX" --side pure\|io\|write\|tx\|lock\|network --purpose "..."` | Add a function I/O row. |
65
+ | `apltk architecture variable add --feature X --submodule Y --name v --type T --scope call\|tx\|persist\|instance\|loop --purpose "..."` | Add a variable-with-business-purpose row. |
66
+ | `apltk architecture dataflow add --feature X --submodule Y --step "..." [--at N]` | Append (or insert at index `N`) an internal dataflow step. |
67
+ | `apltk architecture dataflow reorder --feature X --submodule Y --from i --to j` | Move a step within the same sub-module. |
68
+ | `apltk architecture error add --feature X --submodule Y --name ErrCode --when "..." --means "..."` | Add a local error row. |
69
+ | `apltk architecture edge add --from <feature>[/sub] --to <feature>[/sub] --kind call\|return\|data-row\|failure --label "..." [--id <stable>]` | Add an edge. Intra-feature edges (both endpoints in the same feature with sub-modules) land in the feature YAML; cross-feature edges land in `atlas.index.yaml`. |
70
+ | `apltk architecture feature\|submodule\|function\|variable\|error\|edge remove ...` | Remove a previously declared component. Removing a feature drops every sub-module and edge that referenced it. |
71
+ | `apltk architecture feature\|submodule set ...` | Update fields (e.g. retitle a feature, change a sub-module's role) without re-adding. |
72
+ | `apltk architecture render` | Force-regenerate HTML from current YAML state (useful after editing YAML directly, though hand-editing is discouraged). |
73
+ | `apltk architecture validate` | Schema + referential integrity check; fails on dangling edges, unknown enums, duplicate slugs. |
74
+ | `apltk architecture undo` | Revert the most recent mutation (single-level snapshot). |
75
+ | `apltk architecture open` | Open the rendered macro `index.html` in a browser. |
76
+ | `apltk architecture diff` | Render the paginated before/after viewer for every active spec under `docs/plans/**/architecture_diff/`. |
77
+
78
+ ## Workflow
79
+
80
+ ### 1) Whole-repo inventory — list feature modules, not function bodies
81
+
82
+ Scan the shipped source for **user-visible capabilities** (each one = one feature module): entry routes, CLI commands, UI pages, cron jobs, runners, event handlers, CDC streams. Record only kebab-case slug + one-line user story + boundary points (entry symbol, outbound DB tables / queue topics / external services).
83
+
84
+ - **Pause →** Is the list actually complete? Note skipped roots with reason; no silent skips.
85
+ - **Pause →** Did I dive into function bodies here? Roll back — keep only structural notes.
86
+
87
+ ### 2) Branch the deep-read by environment (Rule 3)
88
+
89
+ #### 2A) With subagents (preferred)
90
+
91
+ Dispatch one read-only subagent per feature. Require this summary template (no source-code excerpts):
92
+
93
+ > **Feature `<slug>` summary**
94
+ > - Sub-module list: one row per `<sub-module-slug>` (kind: ui / api / service / db / pure-fn / queue / external; one-line role).
95
+ > - Per sub-module: function signatures (in / out / side / purpose), variables-with-business-purpose, internal dataflow steps, errors raised.
96
+ > - **Outbound boundaries**: call edges to other features' sub-modules; data-row edges through shared DB tables / topics / cache keys with another feature; mark direction.
97
+
98
+ Main agent collects every summary, then drives the CLI in one pass:
99
+
100
+ ```bash
101
+ apltk architecture meta set --title "..." --summary "..." --no-render
102
+ apltk architecture feature add --slug <slug> --title "..." --story "..." --no-render
103
+ # repeat submodule / function / variable / dataflow / error / edge add for the whole atlas
104
+ apltk architecture render
105
+ apltk architecture validate
106
+ ```
107
+
108
+ #### 2B) Without subagents — feature-by-feature read-declare loop
109
+
110
+ Process the list from step 1 one feature at a time (topological hint: read-from data sources and pure helpers first, user-facing entries last). Per feature:
111
+
112
+ 1. **Deep-read** every sub-module of this feature.
113
+ 2. **Declare immediately** via the CLI (`feature add`, then `submodule add` × N, then `function`/`variable`/`dataflow`/`error` rows, then intra-feature `edge add`).
114
+ 3. **Cross-feature edges**: if the target feature has not been declared yet, declare a placeholder with `feature add --slug <future> --title <future>`, add the edge, then refine the placeholder on a later pass.
115
+ 4. **Drop function-level details from working memory** before moving to the next feature.
116
+
117
+ After the last feature:
118
+
119
+ - Refine any placeholder features that were used to carry cross-feature edges.
120
+ - Run `apltk architecture validate` — must return OK.
121
+
122
+ ### 3) Handover report
123
+
124
+ Report: feature count, sub-module count, macro edge counts (call / return / data-row / failure), uncovered paths + reasons, the read strategy actually used (2A or 2B), and the location of the rendered atlas (`resources/project-architecture/index.html`).
125
+
126
+ ## Sample hints
127
+
128
+ - Multiple SQL paths on `service ↔ db` → call `edge add` once per SQL path so the macro shows them as separate edges.
129
+ - Retry loops between `service ↔ generator(pure)` → call/return pair in the macro plus a dataflow step in the service describing the retry budget.
130
+ - Cross-feature DB hand-off (A writes, B reads) → declare both sides' `INSERT_*` / `SELECT_*` functions on the `db` sub-module, then `edge add --kind data-row` from producer feature/submodule to consumer feature/submodule.
131
+ - Third-party systems → declare as `--kind external` sub-modules; the trust boundary becomes visible because the renderer styles them differently.
132
+
133
+ ## References
134
+
135
+ - `lib/atlas/schema.js` — single source of truth for component fields, enums, and validation. `references/TEMPLATE_SPEC.md` mirrors that schema as a quick-reference cheat sheet.
136
+ - `lib/atlas/cli.js` — full verb dispatch (run `apltk architecture --help` for the live usage).
137
+ - `init-project-html/sample-demo/` — end-to-end YAML + rendered HTML for two features.
@@ -0,0 +1,22 @@
1
+ interface:
2
+ display_name: "init-project-html"
3
+ short_description: "Declare the project HTML architecture atlas through `apltk architecture` CLI verbs"
4
+ default_prompt: >-
5
+ Use $init-project-html. Its `SKILL.md` is the authoritative rulebook; `references/TEMPLATE_SPEC.md` is a component-schema cheat sheet.
6
+ NEVER hand-author files under `resources/project-architecture/**/*.html`. The atlas state lives in YAML under `resources/project-architecture/atlas/` and every mutation goes through `apltk architecture <verb> ...`; the CLI owns layout, no-overlap, DOM, CSS, ARIA, and pan/zoom.
7
+ Read strategy to avoid context loss on large codebases. STEP 1: enumerate the feature-module list (slug + entry + boundary resources) WITHOUT diving into function bodies.
8
+ STEP 2: branch by environment.
9
+ (2A, preferred) if subagents are available, dispatch ONE read-only subagent per feature; each returns ONLY a structured summary (sub-modules with kind/role; per sub-module: function I/O, variables-with-business-purpose, internal dataflow steps, errors raised; outbound edges to other features). The main agent collects every summary first, then runs the CLI in one batched pass.
10
+ (2B, no subagents) process features ONE AT A TIME — deep-read feature A, IMMEDIATELY drive the CLI (`feature add`, `submodule add` x N, `function add` / `variable add` / `dataflow add` / `error add` rows, intra-feature `edge add`), drop A's function-level details from working memory, then move to feature B. For cross-feature edges pointing at a not-yet-declared feature, declare a placeholder with `feature add --slug <future> --title <future>` first and refine its title/story on a later pass.
11
+ CLI verbs to declare components (always kebab-case slugs; pass `--no-render` to batch then call `apltk architecture render` once at the end):
12
+ `apltk architecture meta set --title "..." --summary "..."`,
13
+ `apltk architecture actor add --id <kebab> --label "..."`,
14
+ `apltk architecture feature add --slug <kebab> --title "..." --story "..." [--depends-on a,b]`,
15
+ `apltk architecture submodule add --feature X --slug Y --kind ui|api|service|db|pure-fn|queue|external --role "..."`,
16
+ `apltk architecture function add --feature X --submodule Y --name fn --in "T1, T2" --out "R | ErrX" --side pure|io|write|tx|lock|network --purpose "..."`,
17
+ `apltk architecture variable add --feature X --submodule Y --name v --type T --scope call|tx|persist|instance|loop --purpose "..."`,
18
+ `apltk architecture dataflow add --feature X --submodule Y --step "..." [--at N]`,
19
+ `apltk architecture error add --feature X --submodule Y --name ErrCode --when "..." --means "..."`,
20
+ `apltk architecture edge add --from <feature>[/sub] --to <feature>[/sub] --kind call|return|data-row|failure --label "..." [--id <stable>]`.
21
+ Intra-feature edges (both endpoints in the same feature with sub-modules) land in the feature YAML; cross-feature edges land in `atlas.index.yaml`. After the last mutation run `apltk architecture validate` — must return OK; resolve every reported error before reporting completion.
22
+ Each sub-module page describes ONLY itself (`sub-io` function I/O + `sub-vars` variables-with-business-purpose + `sub-dataflow` internal flow + `sub-errors` local errors) — express any cross-boundary interaction as a macro edge, never as sub-module page prose. Anchor every declaration to a concrete path / symbol / SQL / config; mark TBD when evidence is missing; record scanned roots and deliberate omissions in `meta.summary`. Report which read strategy (2A or 2B) was actually used and the location of the rendered atlas (`resources/project-architecture/index.html`).
@@ -0,0 +1,140 @@
1
+ /* architecture.css — styling for the declarative atlas. The CLI copies
2
+ * this file into <outDir>/assets/. Style hooks (class names) are owned
3
+ * by render.js so agents never need to touch HTML by hand. */
4
+
5
+ :root {
6
+ color-scheme: light dark;
7
+ --bg: #0f172a;
8
+ --panel: #111827;
9
+ --panel-soft: #1f2937;
10
+ --text: #e5e7eb;
11
+ --muted: #9ca3af;
12
+ --border: #334155;
13
+ --accent: #38bdf8;
14
+ --kind-ui: #38bdf8;
15
+ --kind-api: #818cf8;
16
+ --kind-service: #34d399;
17
+ --kind-db: #fbbf24;
18
+ --kind-pure-fn: #cbd5e1;
19
+ --kind-queue: #a78bfa;
20
+ --kind-external: #fb7185;
21
+ --edge-call: #60a5fa;
22
+ --edge-return: #94a3b8;
23
+ --edge-data-row: #fbbf24;
24
+ --edge-failure: #fb7185;
25
+ }
26
+
27
+ * { box-sizing: border-box; }
28
+ html, body { margin: 0; padding: 0; background: var(--bg); color: var(--text); font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif; }
29
+
30
+ a { color: var(--accent); text-decoration: none; }
31
+ a:hover { text-decoration: underline; }
32
+
33
+ h1, h2 { margin: 0 0 12px; font-weight: 600; letter-spacing: -0.01em; }
34
+ h1 { font-size: 28px; }
35
+ h2 { font-size: 18px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.08em; font-size: 13px; }
36
+
37
+ p { line-height: 1.55; color: var(--text); }
38
+
39
+ /* ---- atlas (macro) ---- */
40
+ .atlas-header { padding: 28px 40px 16px; border-bottom: 1px solid var(--border); background: var(--panel); }
41
+ .atlas-summary { color: var(--muted); max-width: 80ch; margin: 8px 0 0; }
42
+
43
+ .atlas-main { display: grid; grid-template-columns: minmax(0, 3fr) minmax(280px, 1fr); gap: 24px; padding: 24px 40px 48px; }
44
+
45
+ .atlas-canvas { background: var(--panel); border: 1px solid var(--border); border-radius: 12px; padding: 16px; position: relative; }
46
+ .atlas-canvas__toolbar { position: absolute; top: 16px; right: 16px; display: flex; gap: 4px; z-index: 2; }
47
+ .atlas-canvas__toolbar button { background: var(--panel-soft); color: var(--text); border: 1px solid var(--border); padding: 4px 12px; border-radius: 6px; cursor: pointer; font-size: 13px; }
48
+ .atlas-canvas__toolbar button:hover { border-color: var(--accent); color: var(--accent); }
49
+
50
+ .atlas-canvas__viewport { width: 100%; max-height: 72vh; overflow: hidden; border-radius: 8px; background: #0b1220; }
51
+ .atlas-canvas__viewport.is-grabbing { cursor: grabbing; }
52
+ .atlas-canvas__viewport:not(.is-grabbing) { cursor: grab; }
53
+
54
+ .atlas-svg { width: 100%; height: auto; max-height: 72vh; display: block; user-select: none; touch-action: none; }
55
+
56
+ .atlas-legend { list-style: none; padding: 12px 4px 0; margin: 0; display: flex; gap: 18px; flex-wrap: wrap; font-size: 12px; color: var(--muted); }
57
+ .atlas-legend li { display: inline-flex; align-items: center; gap: 6px; }
58
+ .legend-swatch { display: inline-block; width: 18px; height: 4px; border-radius: 2px; }
59
+ .legend-swatch--call { background: var(--edge-call); }
60
+ .legend-swatch--return { background: var(--edge-return); }
61
+ .legend-swatch--data-row { background: var(--edge-data-row); }
62
+ .legend-swatch--failure { background: var(--edge-failure); }
63
+
64
+ .atlas-index { background: var(--panel); border: 1px solid var(--border); border-radius: 12px; padding: 16px; max-height: 80vh; overflow: auto; }
65
+
66
+ .atlas-submodule-index { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 10px; }
67
+ .atlas-submodule-index__item a { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 4px 8px; padding: 8px 10px; background: var(--panel-soft); border: 1px solid var(--border); border-radius: 8px; color: inherit; }
68
+ .atlas-submodule-index__item a:hover { border-color: var(--accent); }
69
+ .atlas-submodule-index__feature { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; grid-column: 1 / 3; }
70
+ .atlas-submodule-index__sub { font-weight: 600; }
71
+ .atlas-submodule-index__kind { font-size: 11px; padding: 1px 8px; border-radius: 999px; background: var(--panel); border: 1px solid var(--border); color: var(--muted); }
72
+ .atlas-submodule-index__role { margin: 4px 10px 0; font-size: 12px; color: var(--muted); }
73
+
74
+ /* ---- SVG macro ---- */
75
+ .m-cluster__bg { fill: rgba(15, 23, 42, 0.55); stroke: var(--border); stroke-width: 1; }
76
+ .m-cluster__title { font-family: ui-sans-serif, system-ui, sans-serif; font-size: 14px; fill: var(--text); font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; }
77
+ .m-node rect { fill: var(--panel-soft); stroke: var(--border); stroke-width: 1; transition: stroke 120ms ease; }
78
+ .m-node:hover rect { stroke: var(--accent); }
79
+ .m-node__title { font-size: 13px; font-weight: 600; fill: var(--text); }
80
+ .m-node__kind { font-size: 11px; fill: var(--muted); }
81
+ .m-node__role { font-size: 11px; fill: var(--muted); }
82
+
83
+ .m-node--ui rect { stroke: var(--kind-ui); }
84
+ .m-node--api rect { stroke: var(--kind-api); }
85
+ .m-node--service rect { stroke: var(--kind-service); }
86
+ .m-node--db rect { stroke: var(--kind-db); }
87
+ .m-node--pure-fn rect { stroke: var(--kind-pure-fn); }
88
+ .m-node--queue rect { stroke: var(--kind-queue); }
89
+ .m-node--external rect { stroke: var(--kind-external); }
90
+
91
+ .m-edge path { stroke-width: 1.6; }
92
+ .m-edge--call path { stroke: var(--edge-call); }
93
+ .m-edge--return path { stroke: var(--edge-return); stroke-dasharray: 6 4; }
94
+ .m-edge--data-row path { stroke: var(--edge-data-row); }
95
+ .m-edge--failure path { stroke: var(--edge-failure); }
96
+
97
+ .m-arrow path { fill: currentColor; }
98
+ .m-arrow--call { color: var(--edge-call); }
99
+ .m-arrow--return { color: var(--edge-return); }
100
+ .m-arrow--data-row { color: var(--edge-data-row); }
101
+ .m-arrow--failure { color: var(--edge-failure); }
102
+
103
+ .m-edge__label { fill: var(--muted); font-size: 11px; }
104
+
105
+ /* ---- feature page ---- */
106
+ .feature-header, .submodule-header { padding: 24px 40px 12px; border-bottom: 1px solid var(--border); background: var(--panel); }
107
+ .feature-breadcrumb, .submodule-breadcrumb { font-size: 13px; color: var(--muted); margin-bottom: 8px; }
108
+ .feature-depends { font-size: 13px; color: var(--muted); margin: 8px 0 0; }
109
+ .feature-main, .submodule-main { padding: 24px 40px 48px; display: flex; flex-direction: column; gap: 32px; }
110
+ .feature-story p { max-width: 80ch; }
111
+
112
+ .submodule-nav { list-style: none; padding: 0; margin: 0; display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
113
+ .submodule-card { background: var(--panel); border: 1px solid var(--border); border-radius: 10px; padding: 12px 14px; }
114
+ .submodule-card__link { display: flex; align-items: center; justify-content: space-between; color: inherit; font-weight: 600; }
115
+ .submodule-card__kind { font-size: 11px; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--border); color: var(--muted); }
116
+ .submodule-card__role { margin: 8px 0 0; font-size: 13px; color: var(--muted); }
117
+
118
+ .feature-edges__list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 8px; }
119
+ .feature-edges__item { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 2fr); gap: 8px; padding: 8px 12px; background: var(--panel); border: 1px solid var(--border); border-radius: 8px; font-size: 13px; }
120
+ .feature-edges__kind { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; align-self: center; }
121
+ .feature-edges__item--call { border-left: 4px solid var(--edge-call); }
122
+ .feature-edges__item--return { border-left: 4px solid var(--edge-return); }
123
+ .feature-edges__item--data-row { border-left: 4px solid var(--edge-data-row); }
124
+ .feature-edges__item--failure { border-left: 4px solid var(--edge-failure); }
125
+
126
+ /* ---- submodule page ---- */
127
+ .submodule-kind { display: inline-block; font-size: 12px; padding: 2px 10px; border-radius: 999px; border: 1px solid var(--border); color: var(--muted); margin-left: 8px; vertical-align: middle; text-transform: uppercase; letter-spacing: 0.06em; }
128
+ .submodule-role { color: var(--muted); margin: 8px 0 0; max-width: 80ch; }
129
+
130
+ .sub-table { width: 100%; border-collapse: collapse; font-size: 13px; }
131
+ .sub-table th, .sub-table td { padding: 8px 12px; border-bottom: 1px solid var(--border); text-align: left; vertical-align: top; }
132
+ .sub-table th { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; background: var(--panel); }
133
+
134
+ .sub-section__empty { color: var(--muted); font-style: italic; font-size: 13px; }
135
+
136
+ .sub-dataflow__svg { width: 100%; max-width: 480px; }
137
+ .sub-dataflow__step rect { fill: var(--panel); stroke: var(--border); }
138
+ .sub-dataflow__step text { fill: var(--text); font-size: 13px; }
139
+ .sub-dataflow__arrow { stroke: var(--muted); stroke-width: 1.4; }
140
+ .sub-dataflow__empty { color: var(--muted); font-style: italic; }