codemini-cli 0.4.5 → 0.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/deployment.md CHANGED
@@ -13,13 +13,13 @@ npm pack
13
13
  Expected output:
14
14
 
15
15
  ```text
16
- codemini-cli-0.4.5.tgz
16
+ codemini-cli-0.4.6.tgz
17
17
  ```
18
18
 
19
19
  If you want to verify the package contents:
20
20
 
21
21
  ```bash
22
- tar -tf codemini-cli-0.4.5.tgz
22
+ tar -tf codemini-cli-0.4.6.tgz
23
23
  ```
24
24
 
25
25
  ## 2. Copy To The Target Machine
@@ -34,7 +34,7 @@ Copy the generated `.tgz` file to the Win10 machine by one of these methods:
34
34
  Recommended target path:
35
35
 
36
36
  ```powershell
37
- C:\temp\codemini-cli-0.4.5.tgz
37
+ C:\temp\codemini-cli-0.4.6.tgz
38
38
  ```
39
39
 
40
40
  ## 3. Environment Requirements
@@ -58,7 +58,7 @@ npm -v
58
58
  Global install:
59
59
 
60
60
  ```powershell
61
- npm install -g C:\temp\codemini-cli-0.4.5.tgz
61
+ npm install -g C:\temp\codemini-cli-0.4.6.tgz
62
62
  ```
63
63
 
64
64
  If global install is blocked by company policy, install in a working directory instead:
@@ -66,7 +66,7 @@ If global install is blocked by company policy, install in a working directory i
66
66
  ```powershell
67
67
  mkdir C:\temp\coder-test
68
68
  cd C:\temp\coder-test
69
- npm install C:\temp\codemini-cli-0.4.5.tgz
69
+ npm install C:\temp\codemini-cli-0.4.6.tgz
70
70
  ```
71
71
 
72
72
  ## 5. Confirm Installation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codemini-cli",
3
- "version": "0.4.5",
3
+ "version": "0.4.6",
4
4
  "description": "Coding CLI optimized for small-model workflows and Windows PowerShell",
5
5
  "keywords": [
6
6
  "cli",
@@ -32,16 +32,40 @@ docs/requirements/{{date}}-project-requirements.md
32
32
 
33
33
  The HTML should be self-contained: inline CSS, inline JavaScript, no build step, no required external assets.
34
34
 
35
+ Use a clean, modern documentation style inspired by Notion and Linear unless the user asks otherwise:
36
+
37
+ - White background, warm neutral palette (#37352f text, #e9e9e7 borders), blue accents (#2383e2).
38
+ - Favor generous whitespace, clean typography, and subtle hover transitions over dense layouts.
39
+ - Cards should have rounded corners, minimal borders, and subtle shadow on hover.
40
+ - Tables should have uppercase header labels, no row background by default (only on hover).
41
+ - Use pill-shaped badges for evidence and risk labels — colored background + matching text, no emoji.
42
+ - Diagrams should look like polished internal architecture or business process documentation.
43
+ - Avoid playful palettes, strong gradients, decorative blobs, and visually loud illustrations.
44
+
45
+ Evidence badge class names — use `.tag` or `.badge` with these variants:
46
+
47
+ | Variant | Use for | Visual |
48
+ |---|---|---|
49
+ | `.tag.extracted` / `.badge.extracted` | Behavior directly supported by source code | Green text on green background |
50
+ | `.tag.inferred` / `.badge.inferred` | Reasonable inference from code relationships | Orange text on orange background |
51
+ | `.tag.unknown` / `.badge.unknown` | Needs user confirmation | Gray text on gray background |
52
+ | `.tag.warn` / `.badge.warn` | Medium risk or warning | Orange text on orange background |
53
+ | `.tag.danger` / `.badge.danger` | Critical/high risk | Red text on red background |
54
+ | `.tag.ok` / `.badge.ok` | Low risk or passed check | Green text on green background |
55
+
56
+ Risk level indicators in tables must use the badge variants above, never emoji. For example: `<span class="badge danger">CRITICAL</span>` not `🔴 CRITICAL`.
57
+
58
+ Wrap each requirement card in `<details class="card">` with a `<summary>` containing the API name and a one-line description. This makes all cards collapsible by default.
59
+
35
60
  When the target HTML file already exists and contains `REQUIREMENTS_*` marker sections, treat it as the canonical report shell. Edit those marker sections in place instead of replacing the whole file. Preserve the existing CSS, JavaScript, navigation, metadata, and surrounding structure unless the user explicitly asks to redesign the shell.
36
61
 
37
- Diagrams must be visible when the HTML is opened directly from disk:
62
+ Diagrams must be visible and polished when the HTML is opened directly from disk:
38
63
 
39
- - Prefer inline SVG for architecture maps, dependency graphs, sequence summaries, and state diagrams.
40
- - Use semantic SVG groups, `<title>`/`<desc>`, readable labels, arrow markers, and stable element ids so sections can link to diagram nodes.
41
- - For simple hierarchy diagrams, CSS grid/flex boxes with connector lines are also acceptable.
42
- - Do not rely on Mermaid rendering as the only visible diagram. Mermaid source may be included in a collapsible `<details>` block as an editable source-of-truth companion.
43
- - Use Mermaid CDN rendering only as optional progressive enhancement when the user accepts network access. The static inline SVG or CSS diagram must remain the fallback and primary offline view.
44
- - Avoid showing only raw Mermaid code blocks in the final HTML unless the user explicitly asks for source-only diagrams.
64
+ - Prefer custom inline SVG, CSS grid/flex diagrams, timeline layouts, swimlanes, and styled cards for architecture maps, dependency graphs, flow summaries, and state/lifecycle diagrams.
65
+ - Use semantic SVG groups, `<title>`/`<desc>`, readable labels, arrow markers, stable element ids, and source evidence links where useful.
66
+ - Keep diagrams evidence-based and readable. Prefer fewer correct nodes over a dense speculative map.
67
+ - Do not use Mermaid as the rendered diagram format unless the user explicitly asks for Mermaid source.
68
+ - Avoid showing raw diagram source blocks in the final HTML unless the user explicitly asks for source-only diagrams.
45
69
 
46
70
  For medium or large projects, do not generate the entire HTML document in one model response or one huge `write` call. Create the report incrementally:
47
71
 
@@ -69,10 +93,12 @@ This chunked approach is required for HTML reports because inline CSS, JavaScrip
69
93
  - Tool calls, MCP handlers, RPC methods, queue jobs, scheduled tasks, or exported SDK functions.
70
94
  - UI flows only after the backend/interface layer is mapped, unless the project is frontend-only.
71
95
  4. Connect each API/interface to requirements:
96
+ - Business capability supported by the interface.
72
97
  - User goal and actor.
73
98
  - Trigger and entry point.
74
99
  - Request/input shape.
75
100
  - Response/output shape.
101
+ - Business rules and decision points.
76
102
  - Validation and permission rules.
77
103
  - Data read/write behavior.
78
104
  - Internal modules called.
@@ -80,12 +106,13 @@ This chunked approach is required for HTML reports because inline CSS, JavaScrip
80
106
  - Error cases and retry/rollback behavior.
81
107
  - Observability, audit, and security notes.
82
108
  - Acceptance criteria.
109
+ - Open questions that block final confirmation.
83
110
  5. Generate diagrams:
84
111
  - Product flowchart for the main user journey.
85
112
  - API dependency graph linking endpoints/commands to modules, data stores, and external services.
86
113
  - Sequence diagram for at least one high-value flow.
87
114
  - State or lifecycle diagram when the domain has clear states.
88
- - Render each diagram as static inline SVG or CSS boxes in the HTML, with optional Mermaid source hidden in a collapsible details block.
115
+ - Render each diagram as polished inline HTML/CSS or SVG that is visible offline without external JavaScript.
89
116
  6. Write the report and preserve traceability:
90
117
  - Link sections with stable anchors.
91
118
  - Include code file paths for evidence.
@@ -158,30 +185,30 @@ Open questions:
158
185
 
159
186
  ## Diagram Patterns
160
187
 
161
- Use static diagrams when diagrams help compress complexity. In HTML output, render the visible diagram as inline SVG or CSS boxes. Include Mermaid only as optional source text when it helps future editing.
188
+ Use custom HTML/CSS/SVG diagrams when diagrams help compress complexity. The visual output should look intentional, readable, and report-quality, not like raw generated graph syntax.
162
189
 
163
190
  Inline SVG architecture map:
164
191
 
165
192
  ```html
166
- <figure class="diagram" id="system-architecture">
193
+ <figure class="diagram-card" id="system-architecture">
167
194
  <figcaption>System architecture</figcaption>
168
- <svg viewBox="0 0 960 520" role="img" aria-labelledby="arch-title arch-desc">
195
+ <svg viewBox="0 0 960 380" role="img" aria-labelledby="arch-title arch-desc">
169
196
  <title id="arch-title">System architecture</title>
170
- <desc id="arch-desc">CLI commands call runtime services, which use tools and data stores.</desc>
197
+ <desc id="arch-desc">CLI entry points call the runtime, which coordinates tools and persisted session state.</desc>
171
198
  <defs>
172
199
  <marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto">
173
200
  <path d="M0,0 L0,6 L9,3 z"></path>
174
201
  </marker>
175
202
  </defs>
176
- <g id="cli-layer">
177
- <rect x="40" y="40" width="220" height="90" rx="8"></rect>
178
- <text x="60" y="90">CLI Entry</text>
203
+ <g class="node">
204
+ <rect x="48" y="72" width="190" height="86" rx="10"></rect>
205
+ <text x="72" y="122">CLI Entry</text>
179
206
  </g>
180
- <g id="runtime-layer">
181
- <rect x="370" y="40" width="240" height="90" rx="8"></rect>
182
- <text x="390" y="90">Runtime</text>
207
+ <g class="node">
208
+ <rect x="386" y="72" width="210" height="86" rx="10"></rect>
209
+ <text x="410" y="122">Runtime</text>
183
210
  </g>
184
- <line x1="260" y1="85" x2="370" y2="85" marker-end="url(#arrow)"></line>
211
+ <line x1="238" y1="115" x2="386" y2="115" marker-end="url(#arrow)"></line>
185
212
  </svg>
186
213
  </figure>
187
214
  ```
@@ -189,50 +216,52 @@ Inline SVG architecture map:
189
216
  CSS box architecture map:
190
217
 
191
218
  ```html
192
- <section class="arch-map" aria-label="System architecture">
193
- <a class="arch-node" href="#api-chat">Chat command</a>
194
- <span class="arch-edge" aria-hidden="true">-></span>
195
- <a class="arch-node" href="#runtime-agent-loop">Agent loop</a>
196
- <span class="arch-edge" aria-hidden="true">-></span>
197
- <a class="arch-node" href="#tools-write">Tools</a>
219
+ <section class="dependency-map" aria-label="System architecture">
220
+ <a class="dep-node" href="#api-chat">Chat command</a>
221
+ <span class="dep-edge">→</span>
222
+ <a class="dep-node" href="#runtime-agent-loop">Agent loop</a>
223
+ <span class="dep-edge">→</span>
224
+ <a class="dep-node" href="#tools-write">Tools</a>
198
225
  </section>
199
226
  ```
200
227
 
201
- Optional Mermaid companion:
202
-
203
228
  Product flow:
204
229
 
205
- ```mermaid
206
- flowchart TD
207
- A[User starts task] --> B[System validates input]
208
- B --> C[System performs core action]
209
- C --> D[User receives result]
230
+ ```html
231
+ <ol class="flow-steps" aria-label="Product flow">
232
+ <li><strong>User starts task</strong><span>Input is collected from CLI or UI.</span></li>
233
+ <li><strong>System validates input</strong><span>Policy, mode, and project context are checked.</span></li>
234
+ <li><strong>System performs core action</strong><span>Runtime coordinates model calls and tools.</span></li>
235
+ <li><strong>User receives result</strong><span>Final answer, artifacts, and evidence are returned.</span></li>
236
+ </ol>
210
237
  ```
211
238
 
212
239
  API dependency map:
213
240
 
214
- ```mermaid
215
- graph LR
216
- API[API or command] --> Handler[Handler]
217
- Handler --> Service[Service]
218
- Service --> Store[(Data store)]
219
- Service --> External[External service]
241
+ ```html
242
+ <section class="dependency-map" aria-label="API dependency map">
243
+ <a class="dep-node" href="#api-command">API or command</a>
244
+ <span class="dep-edge">→</span>
245
+ <a class="dep-node" href="#handler">Handler</a>
246
+ <span class="dep-edge">→</span>
247
+ <a class="dep-node" href="#service">Service</a>
248
+ <span class="dep-edge">→</span>
249
+ <a class="dep-node" href="#store">Data store</a>
250
+ </section>
220
251
  ```
221
252
 
222
253
  Sequence flow:
223
254
 
224
- ```mermaid
225
- sequenceDiagram
226
- participant User
227
- participant API
228
- participant Service
229
- participant Store
230
- User->>API: Request
231
- API->>Service: Validate and execute
232
- Service->>Store: Read/write data
233
- Store-->>Service: Result
234
- Service-->>API: Domain result
235
- API-->>User: Response
255
+ ```html
256
+ <table class="sequence-table">
257
+ <thead><tr><th>Step</th><th>Sender</th><th>Receiver</th><th>Message</th></tr></thead>
258
+ <tbody>
259
+ <tr><td>1</td><td>User</td><td>API</td><td>Request</td></tr>
260
+ <tr><td>2</td><td>API</td><td>Service</td><td>Validate and execute</td></tr>
261
+ <tr><td>3</td><td>Service</td><td>Store</td><td>Read/write data</td></tr>
262
+ <tr><td>4</td><td>API</td><td>User</td><td>Response</td></tr>
263
+ </tbody>
264
+ </table>
236
265
  ```
237
266
 
238
267
  ## Quality Bar
@@ -245,3 +274,18 @@ The report is complete when:
245
274
  - Inferred requirements are labeled instead of stated as facts.
246
275
  - Open questions are grouped so the user can resolve them later.
247
276
  - The HTML can be opened directly from disk in a browser.
277
+
278
+ ## Content Guidelines
279
+
280
+ Avoid duplication between sections:
281
+
282
+ - The Executive Summary risk list should contain only the **top 2-3 most critical risks** with one-sentence descriptions. The full risk matrix belongs in the Security section only.
283
+ - Key capabilities in the summary should be a concise table (name + one-liner + evidence). Detailed descriptions belong in the per-API requirement cards.
284
+ - Non-functional findings should appear only in the Non-functional section, not duplicated in the summary.
285
+
286
+ Open questions should be **actionable and specific**:
287
+
288
+ - Do NOT list questions that can be answered by reading the source code (e.g. "What is the test coverage?", "Is there CI/CD?"). Instead, investigate and report the answer directly.
289
+ - Do NOT list questions about whether a feature exists — check the code first and report what you find.
290
+ - Only list questions that require **human decision-making**, **business context**, or **stakeholder input** that cannot be derived from the codebase.
291
+ - Each open question should clearly state what decision or confirmation is needed and why it matters.
@@ -42,7 +42,7 @@ function parseChatArgs(args) {
42
42
  return parsed;
43
43
  }
44
44
 
45
- export async function submitAndPrint(runtime, line, { output: out = process.stdout } = {}) {
45
+ export async function submitAndPrint(runtime, line, { output: out = process.stdout, showSystemTools = false } = {}) {
46
46
  let streamed = false;
47
47
  let atLineStart = true;
48
48
  const write = (text) => {
@@ -84,6 +84,9 @@ export async function submitAndPrint(runtime, line, { output: out = process.stdo
84
84
  writeActivity(event, 'tool:error');
85
85
  return;
86
86
  }
87
+ if (!showSystemTools && String(event?.type || '').startsWith('system_tool:')) {
88
+ return;
89
+ }
87
90
  if (event?.type === 'system_tool:start') {
88
91
  streamed = true;
89
92
  writeActivity(event, 'system:start');
@@ -321,6 +321,19 @@ const SUB_AGENT_CONTEXT_MAX_MESSAGES = 4;
321
321
  const SUB_AGENT_CONTEXT_MAX_CHARS = 1200;
322
322
  const SUB_AGENT_EVIDENCE_MAX_ITEMS = 3;
323
323
  const SUB_AGENT_HANDOFF_MAX_ITEMS = 6;
324
+ const PROJECT_REQUIREMENTS_SECTION_MARKERS = [
325
+ { key: 'summary', marker: 'REQUIREMENTS_SUMMARY', labels: ['1', 'summary', 'overview', 'project overview', 'executive summary', '项目概述', '项目总览', '概述'] },
326
+ { key: 'architecture', marker: 'REQUIREMENTS_ARCHITECTURE', labels: ['2', 'architecture', 'system architecture', 'system map', '架构', '系统架构图', '系统架构', '架构图'] },
327
+ { key: 'interfaces', marker: 'REQUIREMENTS_INTERFACE_INVENTORY', labels: ['3', 'interface inventory', 'interfaces', 'api inventory', '接口清单', '接口', 'api清单'] },
328
+ { key: 'requirements', marker: 'REQUIREMENTS_API_CARDS', labels: ['4', 'requirement cards', 'api cards', 'interface requirements', '接口需求卡片', '需求卡片'] },
329
+ { key: 'flows', marker: 'REQUIREMENTS_FLOWS', labels: ['5', 'flows', 'user flows', 'core flows', '核心用户流程', '用户流程', '流程'] },
330
+ { key: 'domain', marker: 'REQUIREMENTS_DOMAIN_MODEL', labels: ['6', 'domain model', 'data ownership', 'domain', '领域模型', '数据归属', '领域模型与数据归属'] },
331
+ { key: 'security', marker: 'REQUIREMENTS_SECURITY', labels: ['7', 'security', 'permissions', 'compliance', '权限', '安全', '合规', '权限、安全与合规'] },
332
+ { key: 'errors', marker: 'REQUIREMENTS_ERROR_HANDLING', labels: ['8', 'errors', 'edge cases', 'error handling', '异常处理', '边界情况', '异常处理与边界情况'] },
333
+ { key: 'nonfunctional', marker: 'REQUIREMENTS_NONFUNCTIONAL', labels: ['9', 'non-functional', 'nonfunctional', 'nfr', '非功能性需求', '非功能'] },
334
+ { key: 'questions', marker: 'REQUIREMENTS_OPEN_QUESTIONS', labels: ['10', 'open questions', 'unknowns', '待确认问题', '待确认', '问题'] },
335
+ { key: 'evidence', marker: 'REQUIREMENTS_EVIDENCE_INDEX', labels: ['11', 'evidence', 'source evidence', 'source evidence index', '源码证据索引', '证据索引', '源码证据'] }
336
+ ];
324
337
  const PLAN_MEMORY_MARKERS = {
325
338
  findings: ['<!-- plan-findings-start -->', '<!-- plan-findings-end -->'],
326
339
  progress: ['<!-- plan-progress-start -->', '<!-- plan-progress-end -->']
@@ -2993,7 +3006,41 @@ function renderAutoPlanMarkdown({
2993
3006
  return lines.join('\n');
2994
3007
  }
2995
3008
 
3009
+ function parseProjectRequirementsOptions(args = []) {
3010
+ const raw = args.join(' ').trim();
3011
+ const normalized = raw.toLowerCase();
3012
+ const hasIgnoreIntent = /(忽略|跳过|不生成|不要|无需|排除|exclude|skip|omit|without|no\s+)/i.test(raw);
3013
+ if (!hasIgnoreIntent) return { raw, ignoredSections: [] };
3014
+
3015
+ const ignored = [];
3016
+ for (const section of PROJECT_REQUIREMENTS_SECTION_MARKERS) {
3017
+ const matched = section.labels.some((label) => {
3018
+ const value = String(label).toLowerCase();
3019
+ if (/^\d+$/.test(value)) {
3020
+ return new RegExp(`(^|[^0-9])${value}([^0-9]|$)`).test(normalized);
3021
+ }
3022
+ return normalized.includes(value);
3023
+ });
3024
+ if (matched) ignored.push(section);
3025
+ }
3026
+ return { raw, ignoredSections: ignored };
3027
+ }
3028
+
3029
+ function renderProjectRequirementsSectionContract(ignoredSections = []) {
3030
+ const ignored = new Set(ignoredSections.map((section) => section.marker));
3031
+ const required = PROJECT_REQUIREMENTS_SECTION_MARKERS
3032
+ .filter((section) => !ignored.has(section.marker))
3033
+ .map((section) => section.marker);
3034
+ const lines = [`Required marker sections: ${required.join(', ')}.`];
3035
+ if (ignoredSections.length > 0) {
3036
+ lines.push(`User-requested omitted sections: ${ignoredSections.map((section) => `${section.key} (${section.marker})`).join(', ')}.`);
3037
+ lines.push('For omitted sections, leave the shell section visibly marked as omitted and do not spend analysis or writing budget filling it.');
3038
+ }
3039
+ return lines.join('\n');
3040
+ }
3041
+
2996
3042
  function buildProjectRequirementsSteps(renderedSkillPrompt, args = []) {
3043
+ const options = parseProjectRequirementsOptions(args);
2997
3044
  const userArgs = args.join(' ').trim();
2998
3045
  const requestedFocus = userArgs ? `User request/focus: ${userArgs}` : 'User request/focus: full workspace requirements report.';
2999
3046
  const reportDate = formatLocalDate();
@@ -3005,50 +3052,86 @@ function buildProjectRequirementsSteps(renderedSkillPrompt, args = []) {
3005
3052
  `Optional companion Markdown path: ${companionPath}`,
3006
3053
  'A pre-created HTML shell already exists at the primary report path.',
3007
3054
  'Fill or replace only the named marker sections in that shell instead of rewriting the whole document.',
3008
- 'Required marker sections: REQUIREMENTS_SUMMARY, REQUIREMENTS_ARCHITECTURE, REQUIREMENTS_INTERFACE_INVENTORY, REQUIREMENTS_API_CARDS, REQUIREMENTS_FLOWS, REQUIREMENTS_SECURITY, REQUIREMENTS_NONFUNCTIONAL, REQUIREMENTS_OPEN_QUESTIONS, REQUIREMENTS_EVIDENCE_INDEX.',
3055
+ renderProjectRequirementsSectionContract(options.ignoredSections),
3056
+ 'For diagrams, write polished inline HTML/CSS or SVG directly in the report. Do not use Mermaid unless the user explicitly asks for Mermaid source.',
3057
+ 'Use a light blue, white, and cool gray banking/financial visual style: conservative, dense, readable, and enterprise-grade.',
3058
+ 'Prioritize API/interface-level business requirements. Every major interface should map to business capability, actor, trigger, inputs, outputs, rules, permissions, data reads/writes, errors, acceptance criteria, and evidence.',
3009
3059
  'Use EXTRACTED, INFERRED, and UNKNOWN labels. Preserve source evidence paths.',
3010
3060
  'Do not invent dates; use the report paths above.'
3011
3061
  ].join('\n');
3012
3062
 
3013
3063
  return [
3014
3064
  {
3015
- title: 'Map project interfaces and evidence',
3065
+ title: '🧭 Map entry points and evidence sources',
3016
3066
  role: 'planner',
3017
3067
  task: [
3018
- 'Map project interfaces and evidence before any report writing.',
3068
+ 'Map project entry points and evidence sources before any report writing.',
3019
3069
  reportContract,
3020
3070
  'Inspect top-level docs, package manifests, route/command entry points, tests, and obvious interface files.',
3021
- 'Produce a concise interface inventory grouped by CLI commands, HTTP/API/RPC surfaces, tools, storage/config, UI flows, and operations.',
3071
+ 'Produce a concise evidence map grouped by docs, routes/commands, handlers, schemas, tests, configuration, storage, and operations.',
3022
3072
  'Include evidence paths and open questions. Do not write the final report.'
3023
3073
  ].join('\n')
3024
3074
  },
3025
3075
  {
3026
- title: 'Analyze runtime, tools, and providers',
3076
+ title: '📚 Build API and interface inventory',
3077
+ role: 'planner',
3078
+ task: [
3079
+ 'Build the canonical API/interface inventory using the evidence map.',
3080
+ reportContract,
3081
+ 'Enumerate every major HTTP endpoint, CLI command, tool call, MCP/RPC handler, queue/scheduled job, exported SDK function, and user-facing workflow entry point.',
3082
+ 'For each item include type, route/command/function, owner module, evidence path, likely actor, and whether it is EXTRACTED, INFERRED, or UNKNOWN.',
3083
+ 'Do not write the final report.'
3084
+ ].join('\n')
3085
+ },
3086
+ {
3087
+ title: '🧩 Decompose business requirements per API',
3088
+ role: 'advisor',
3089
+ task: [
3090
+ 'Decompose business requirements for each major API/interface from the inventory.',
3091
+ reportContract,
3092
+ 'For each interface capture business capability, actor, user goal, trigger, inputs, outputs, preconditions, main flow, alternate flows, business rules, acceptance criteria, and open questions.',
3093
+ 'Keep findings API-centered rather than module-centered. Do not write the final report.'
3094
+ ].join('\n')
3095
+ },
3096
+ {
3097
+ title: '🔐 Analyze validation, permissions, and compliance',
3098
+ role: 'advisor',
3099
+ task: [
3100
+ 'Analyze validation, authorization, security, audit, and compliance implications per API/interface.',
3101
+ reportContract,
3102
+ 'For each relevant interface identify validation rules, permission checks, sensitive data, audit/traceability needs, policy constraints, retry/rollback behavior, and UNKNOWN compliance gaps.',
3103
+ 'Return requirement-ready findings with evidence paths. Do not write the final report.'
3104
+ ].join('\n')
3105
+ },
3106
+ {
3107
+ title: '💾 Map data ownership and state changes',
3027
3108
  role: 'advisor',
3028
3109
  task: [
3029
- 'Analyze the core execution layer and tool/provider surfaces using the prior planner inventory.',
3110
+ 'Map data ownership, storage paths, state transitions, and side effects per API/interface.',
3030
3111
  reportContract,
3031
- 'Focus on runtime flow, agent loop, built-in/deferred tools, provider streaming/tool-call behavior, sessions, memory, and plan state.',
3032
- 'Return requirement-ready findings with evidence paths, inferred requirements, edge cases, and unknowns. Do not write the final report.'
3112
+ 'Identify data reads, data writes, config/session/memory/file/database ownership, lifecycle states, cache/index behavior, external dependencies, and operational side effects.',
3113
+ 'Return requirement-ready findings with evidence paths. Do not write the final report.'
3033
3114
  ].join('\n')
3034
3115
  },
3035
3116
  {
3036
- title: 'Analyze product flows, storage, security, and operations',
3117
+ title: '🔄 Connect user flows to API dependencies',
3037
3118
  role: 'advisor',
3038
3119
  task: [
3039
- 'Analyze user-facing workflows and non-functional requirements using the accumulated plan context.',
3120
+ 'Connect user-facing flows to the API/interface inventory and implementation dependencies.',
3040
3121
  reportContract,
3041
- 'Cover core product journeys, persistence paths, configuration, security/policy behavior, deployment/operations notes, error handling, and acceptance criteria.',
3042
- 'Return requirement-ready findings with evidence paths, inferred requirements, edge cases, and unknowns. Do not write the final report.'
3122
+ 'Create flow-ready findings for core journeys, API dependency maps, sequence summaries, error paths, and cross-interface handoffs.',
3123
+ 'Favor clear business process decomposition over broad architecture prose. Do not write the final report.'
3043
3124
  ].join('\n')
3044
3125
  },
3045
3126
  {
3046
- title: 'Write requirements HTML report',
3127
+ title: '🎨 Write banking-style requirements HTML report',
3047
3128
  role: 'coder',
3048
3129
  task: [
3049
3130
  'Create the final project requirements report from the accumulated plan context.',
3050
3131
  reportContract,
3051
3132
  'Follow the project-requirements skill instructions below exactly, including chunked HTML writing for medium/large reports.',
3133
+ 'Use the blue/white/gray banking-style shell and produce polished inline HTML/CSS/SVG diagrams. Keep the report professional, light, and conservative.',
3134
+ 'Organize the main requirements section primarily by API/interface business requirement cards.',
3052
3135
  'The final HTML must be self-contained and directly openable from disk.',
3053
3136
  'Write the primary report to the exact primary report path above. Create the companion Markdown only if useful.',
3054
3137
  'Skill instructions:',
@@ -3056,22 +3139,23 @@ function buildProjectRequirementsSteps(renderedSkillPrompt, args = []) {
3056
3139
  ].join('\n\n')
3057
3140
  },
3058
3141
  {
3059
- title: 'Review report coverage and traceability',
3142
+ title: '🔎 Review API coverage and traceability',
3060
3143
  role: 'reviewer',
3061
3144
  task: [
3062
3145
  'Review the generated requirements report against the project-requirements contract and accumulated evidence.',
3063
3146
  reportContract,
3064
- 'Check that major interfaces are represented, evidence paths are present, inferred/unknown content is labeled, diagrams are visible without Mermaid as the only renderer, and the report path matches the required local date.',
3147
+ 'Check that major APIs/interfaces are represented, business requirements are decomposed per API, evidence paths are present, inferred/unknown content is labeled, diagrams are visible as inline HTML/CSS/SVG without external rendering libraries, and the report path matches the required local date.',
3148
+ 'Check that the visual style is light blue/white/gray and suitable for banking/financial review.',
3065
3149
  'Report concrete gaps and risks only. Do not rewrite the whole report.'
3066
3150
  ].join('\n')
3067
3151
  },
3068
3152
  {
3069
- title: 'Summarize final requirements report',
3153
+ title: '🧾 Summarize final report and unresolved questions',
3070
3154
  role: 'summarizer',
3071
3155
  task: [
3072
3156
  'Synthesize the project requirements pipeline results into a concise final status for the user.',
3073
3157
  reportContract,
3074
- 'Mention the generated report path, what was covered, what was not verified, and the best next action.',
3158
+ 'Mention the generated report path, API/interface coverage, strongest business requirement findings, unresolved questions, what was not verified, and the best next action.',
3075
3159
  'Do not re-analyze the codebase unless the accumulated evidence is clearly insufficient.'
3076
3160
  ].join('\n')
3077
3161
  }
@@ -3138,7 +3222,9 @@ async function createProjectRequirementsShell({
3138
3222
  'interfaces',
3139
3223
  'requirements',
3140
3224
  'flows',
3225
+ 'domain',
3141
3226
  'security',
3227
+ 'errors',
3142
3228
  'nonfunctional',
3143
3229
  'questions',
3144
3230
  'evidence'
@@ -111,7 +111,7 @@ class FffMcpClient {
111
111
  capabilities: {},
112
112
  clientInfo: {
113
113
  name: 'codemini-cli',
114
- version: '0.4.5'
114
+ version: '0.4.6'
115
115
  }
116
116
  });
117
117
  this.sendNotification('notifications/initialized', {});
@@ -6,80 +6,397 @@
6
6
  <title>{{title}}</title>
7
7
  <style>
8
8
  :root {
9
- color-scheme: light dark;
10
- --bg: #f7f8fb;
9
+ color-scheme: light;
10
+ --bg: #ffffff;
11
+ --bg-muted: #f7f7f5;
12
+ --bg-hover: #f0f0ee;
11
13
  --panel: #ffffff;
12
- --text: #182033;
13
- --muted: #657086;
14
- --line: #d9deea;
15
- --accent: #2563eb;
16
- --ok: #147a4a;
17
- --warn: #a16207;
18
- --unknown: #7c3aed;
19
- }
20
- @media (prefers-color-scheme: dark) {
21
- :root {
22
- --bg: #111521;
23
- --panel: #181d2b;
24
- --text: #edf2ff;
25
- --muted: #a6afc3;
26
- --line: #30384f;
27
- --accent: #7aa2ff;
28
- }
14
+ --text: #37352f;
15
+ --text-secondary: #787774;
16
+ --line: #e9e9e7;
17
+ --line-strong: #dfdfde;
18
+ --accent: #2383e2;
19
+ --accent-hover: #1b6ec2;
20
+ --accent-bg: #e8f0fe;
21
+ --red: #eb5757;
22
+ --red-bg: #ffefef;
23
+ --orange: #e9730c;
24
+ --orange-bg: #fff4e5;
25
+ --green: #4dab6f;
26
+ --green-bg: #edf7f0;
27
+ --gray: #9b9a97;
28
+ --gray-bg: #f1f1f0;
29
+ --shadow-sm: 0 1px 2px rgba(0,0,0,0.04);
30
+ --shadow-md: 0 2px 8px rgba(0,0,0,0.06);
31
+ --radius: 6px;
32
+ --radius-lg: 10px;
33
+ --transition: 120ms ease;
29
34
  }
30
- * { box-sizing: border-box; }
35
+ * { box-sizing: border-box; margin: 0; }
31
36
  body {
32
- margin: 0;
33
37
  background: var(--bg);
34
38
  color: var(--text);
35
- font: 15px/1.55 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
39
+ font: 14.5px/1.6 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
40
+ -webkit-font-smoothing: antialiased;
41
+ -moz-osx-font-smoothing: grayscale;
36
42
  }
43
+ /* ── Header ── */
37
44
  header {
38
- padding: 32px min(5vw, 56px) 22px;
45
+ padding: 48px min(6vw, 80px) 28px;
39
46
  border-bottom: 1px solid var(--line);
40
- background: var(--panel);
47
+ background: var(--bg);
48
+ }
49
+ h1, h2, h3, h4 { line-height: 1.25; color: var(--text); }
50
+ h1 { margin: 0 0 8px; font-size: clamp(26px, 3.5vw, 38px); font-weight: 700; letter-spacing: -0.02em; }
51
+ h2 { margin: 40px 0 16px; font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }
52
+ h3 { margin: 20px 0 8px; font-size: 16px; font-weight: 600; }
53
+ a { color: var(--accent); text-decoration: none; transition: color var(--transition); }
54
+ a:hover { color: var(--accent-hover); text-decoration: underline; }
55
+ .meta {
56
+ color: var(--text-secondary);
57
+ font-size: 13px;
58
+ display: flex;
59
+ gap: 16px;
60
+ flex-wrap: wrap;
61
+ margin-top: 4px;
62
+ }
63
+ .meta span::before { content: ""; display: inline-block; width: 3px; height: 3px; border-radius: 50%; background: var(--gray); vertical-align: middle; margin-right: 8px; }
64
+ .meta span:first-child::before { display: none; }
65
+ /* ── Layout ── */
66
+ .layout {
67
+ display: grid;
68
+ grid-template-columns: minmax(200px, 260px) minmax(0, 1fr);
69
+ gap: 0;
70
+ min-height: calc(100vh - 140px);
71
+ }
72
+ /* ── Sidebar Nav ── */
73
+ nav {
74
+ position: sticky;
75
+ top: 0;
76
+ align-self: start;
77
+ height: calc(100vh - 140px);
78
+ overflow-y: auto;
79
+ border-right: 1px solid var(--line);
80
+ padding: 20px 12px 20px 0;
81
+ scrollbar-width: thin;
82
+ }
83
+ nav a {
84
+ display: flex;
85
+ align-items: center;
86
+ gap: 8px;
87
+ padding: 6px 12px;
88
+ border-radius: var(--radius);
89
+ text-decoration: none;
90
+ color: var(--text-secondary);
91
+ font-size: 13.5px;
92
+ font-weight: 500;
93
+ transition: all var(--transition);
94
+ border-bottom: none;
95
+ }
96
+ nav a:hover {
97
+ background: var(--bg-hover);
98
+ color: var(--text);
99
+ text-decoration: none;
100
+ }
101
+ nav a.active {
102
+ background: var(--bg-hover);
103
+ color: var(--text);
104
+ font-weight: 600;
105
+ }
106
+ nav a .nav-dot {
107
+ width: 6px;
108
+ height: 6px;
109
+ border-radius: 50%;
110
+ background: var(--line-strong);
111
+ flex-shrink: 0;
112
+ transition: background var(--transition);
113
+ }
114
+ nav a:hover .nav-dot,
115
+ nav a.active .nav-dot { background: var(--accent); }
116
+ /* ── Main Content ── */
117
+ main {
118
+ max-width: 920px;
119
+ padding: 8px min(5vw, 80px) 80px;
120
+ }
121
+ section {
122
+ padding: 4px 0 24px;
123
+ border-bottom: 1px solid var(--line);
124
+ }
125
+ section:last-child { border-bottom: none; }
126
+ /* ── Controls ── */
127
+ .controls { margin: 8px 0 24px; }
128
+ .controls-bar {
129
+ display: flex;
130
+ align-items: center;
131
+ gap: 8px;
132
+ flex-wrap: wrap;
41
133
  }
42
- h1, h2, h3 { line-height: 1.2; }
43
- h1 { margin: 0 0 10px; font-size: clamp(28px, 4vw, 44px); }
44
- h2 { margin: 36px 0 14px; font-size: 24px; }
45
- h3 { margin: 24px 0 10px; font-size: 18px; }
46
- a { color: var(--accent); }
47
- .meta { color: var(--muted); display: flex; gap: 16px; flex-wrap: wrap; }
48
- .layout { display: grid; grid-template-columns: minmax(180px, 260px) minmax(0, 1fr); gap: 28px; padding: 24px min(5vw, 56px) 56px; }
49
- nav { position: sticky; top: 16px; align-self: start; }
50
- nav a { display: block; padding: 8px 0; text-decoration: none; border-bottom: 1px solid color-mix(in srgb, var(--line), transparent 45%); }
51
- main { max-width: 1180px; }
52
- section { padding: 2px 0 18px; border-bottom: 1px solid var(--line); }
53
- .controls { display: flex; gap: 10px; flex-wrap: wrap; margin: 12px 0 22px; }
54
134
  input[type="search"] {
55
- width: min(520px, 100%);
56
- padding: 10px 12px;
135
+ width: min(400px, 100%);
136
+ padding: 7px 12px 7px 32px;
57
137
  border: 1px solid var(--line);
58
- border-radius: 8px;
59
- background: var(--panel);
138
+ border-radius: var(--radius);
139
+ background: var(--bg) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' fill='none' stroke='%239b9a97' stroke-width='2'%3E%3Ccircle cx='6' cy='6' r='4.5'/%3E%3Cpath d='M10 10l3 3'/%3E%3C/svg%3E") 10px center no-repeat;
140
+ color: var(--text);
141
+ font-size: 13.5px;
142
+ transition: border-color var(--transition), box-shadow var(--transition);
143
+ }
144
+ input[type="search"]:focus {
145
+ outline: none;
146
+ border-color: var(--accent);
147
+ box-shadow: 0 0 0 3px var(--accent-bg);
148
+ }
149
+ input[type="search"]::placeholder { color: var(--gray); }
150
+ .controls-bar button {
151
+ padding: 6px 14px;
152
+ border: 1px solid var(--line);
153
+ border-radius: var(--radius);
154
+ background: var(--bg);
155
+ color: var(--text-secondary);
156
+ cursor: pointer;
157
+ font-size: 12.5px;
158
+ font-weight: 500;
159
+ transition: all var(--transition);
160
+ }
161
+ .controls-bar button:hover {
162
+ background: var(--bg-hover);
60
163
  color: var(--text);
164
+ border-color: var(--line-strong);
61
165
  }
166
+ .no-results { color: var(--gray); padding: 32px 0; font-size: 14px; display: none; }
167
+ /* ── Cards ── */
62
168
  .card {
63
169
  border: 1px solid var(--line);
64
- border-radius: 8px;
170
+ border-radius: var(--radius-lg);
65
171
  background: var(--panel);
172
+ padding: 20px 24px;
173
+ margin: 16px 0;
174
+ transition: box-shadow var(--transition);
175
+ }
176
+ .card:hover { box-shadow: var(--shadow-md); }
177
+ /* ── Details (collapsible API cards) ── */
178
+ details.card summary {
179
+ cursor: pointer;
180
+ font-size: 15px;
181
+ font-weight: 600;
182
+ padding: 2px 0;
183
+ list-style: none;
184
+ display: flex;
185
+ align-items: center;
186
+ gap: 8px;
187
+ }
188
+ details.card summary::-webkit-details-marker { display: none; }
189
+ details.card summary::before {
190
+ content: "";
191
+ display: inline-block;
192
+ width: 0; height: 0;
193
+ border-left: 5px solid var(--text-secondary);
194
+ border-top: 4px solid transparent;
195
+ border-bottom: 4px solid transparent;
196
+ transition: transform var(--transition);
197
+ flex-shrink: 0;
198
+ }
199
+ details.card[open] summary::before { transform: rotate(90deg); }
200
+ details.card summary:hover { color: var(--accent); }
201
+ details.card[open] summary {
202
+ padding-bottom: 16px;
203
+ margin-bottom: 16px;
204
+ border-bottom: 1px solid var(--line);
205
+ }
206
+ /* ── Badges / Tags ── */
207
+ .tag, .badge {
208
+ display: inline-flex;
209
+ align-items: center;
210
+ gap: 4px;
211
+ border-radius: 4px;
212
+ padding: 1px 7px;
213
+ font-size: 11.5px;
214
+ font-weight: 600;
215
+ letter-spacing: 0.02em;
216
+ line-height: 20px;
217
+ white-space: nowrap;
218
+ }
219
+ .tag.extracted, .badge.extracted { color: var(--green); background: var(--green-bg); }
220
+ .tag.inferred, .badge.inferred { color: var(--orange); background: var(--orange-bg); }
221
+ .tag.unknown, .badge.unknown { color: var(--gray); background: var(--gray-bg); }
222
+ .tag.warn, .badge.warn { color: var(--orange); background: var(--orange-bg); }
223
+ .tag.danger, .badge.danger { color: var(--red); background: var(--red-bg); }
224
+ .tag.ok, .badge.ok { color: var(--green); background: var(--green-bg); }
225
+ /* ── Tables ── */
226
+ .table-wrap { overflow-x: auto; margin: 12px 0; border-radius: var(--radius); }
227
+ table, .spec-table, .sequence-table {
228
+ width: 100%;
229
+ border-collapse: collapse;
230
+ margin: 12px 0;
231
+ font-size: 13.5px;
232
+ }
233
+ th, td {
234
+ text-align: left;
235
+ vertical-align: top;
236
+ padding: 8px 12px;
237
+ border-bottom: 1px solid var(--line);
238
+ }
239
+ th {
240
+ color: var(--text-secondary);
241
+ font-size: 12px;
242
+ font-weight: 600;
243
+ text-transform: uppercase;
244
+ letter-spacing: 0.04em;
245
+ background: transparent;
246
+ }
247
+ tr:last-child td { border-bottom: none; }
248
+ tr:hover td { background: var(--bg-muted); }
249
+ /* ── Code ── */
250
+ code, pre {
251
+ font-family: "SFMono-Regular", "Menlo", "Consolas", "PT Mono", monospace;
252
+ }
253
+ code {
254
+ background: var(--bg-muted);
255
+ padding: 2px 5px;
256
+ border-radius: 3px;
257
+ font-size: 13px;
258
+ color: #eb5757;
259
+ }
260
+ pre {
261
+ overflow: auto;
66
262
  padding: 16px;
263
+ border-radius: var(--radius);
264
+ background: #fafaf8;
265
+ border: 1px solid var(--line);
266
+ font-size: 13px;
267
+ line-height: 1.5;
268
+ }
269
+ /* ── Diagrams ── */
270
+ .diagram, .diagram-card {
271
+ overflow: auto;
272
+ border: 1px solid var(--line);
273
+ border-radius: var(--radius-lg);
274
+ background: var(--bg);
275
+ padding: 20px;
276
+ margin: 16px 0;
277
+ }
278
+ .diagram-card figcaption {
279
+ color: var(--text-secondary);
280
+ font-weight: 600;
281
+ font-size: 13px;
282
+ margin: 0 0 16px;
283
+ text-transform: uppercase;
284
+ letter-spacing: 0.04em;
285
+ }
286
+ .diagram svg { max-width: 100%; height: auto; }
287
+ .diagram-card svg { width: 100%; height: auto; }
288
+ /* ── Flow Steps ── */
289
+ .flow-steps {
290
+ display: grid;
291
+ gap: 2px;
67
292
  margin: 12px 0;
293
+ padding: 0;
294
+ list-style: none;
295
+ counter-reset: step;
68
296
  }
69
- .tag { display: inline-flex; align-items: center; border-radius: 999px; padding: 2px 8px; font-size: 12px; font-weight: 700; }
70
- .tag.extracted { color: var(--ok); border: 1px solid color-mix(in srgb, var(--ok), transparent 45%); }
71
- .tag.inferred { color: var(--warn); border: 1px solid color-mix(in srgb, var(--warn), transparent 45%); }
72
- .tag.unknown { color: var(--unknown); border: 1px solid color-mix(in srgb, var(--unknown), transparent 45%); }
73
- table { width: 100%; border-collapse: collapse; margin: 12px 0; }
74
- th, td { text-align: left; vertical-align: top; padding: 9px 10px; border-bottom: 1px solid var(--line); }
75
- th { color: var(--muted); font-size: 13px; }
76
- code, pre { font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace; }
77
- pre { overflow: auto; padding: 14px; border-radius: 8px; background: color-mix(in srgb, var(--panel), var(--line) 18%); }
78
- .diagram { overflow: auto; }
79
- .placeholder { color: var(--muted); font-style: italic; }
297
+ .flow-steps li {
298
+ counter-increment: step;
299
+ border: 1px solid var(--line);
300
+ border-radius: var(--radius);
301
+ background: var(--bg-muted);
302
+ padding: 14px 16px 14px 48px;
303
+ position: relative;
304
+ transition: background var(--transition);
305
+ }
306
+ .flow-steps li:hover { background: var(--bg-hover); }
307
+ .flow-steps li::before {
308
+ content: counter(step);
309
+ position: absolute;
310
+ left: 16px;
311
+ top: 14px;
312
+ width: 22px;
313
+ height: 22px;
314
+ border-radius: 50%;
315
+ background: var(--accent);
316
+ color: #fff;
317
+ font-size: 11px;
318
+ font-weight: 700;
319
+ display: flex;
320
+ align-items: center;
321
+ justify-content: center;
322
+ }
323
+ .flow-steps span { display: block; color: var(--text-secondary); margin-top: 4px; font-size: 13px; }
324
+ /* ── Dependency Map ── */
325
+ .dependency-map {
326
+ display: flex;
327
+ align-items: center;
328
+ gap: 6px;
329
+ flex-wrap: wrap;
330
+ margin: 12px 0;
331
+ }
332
+ .dep-node {
333
+ border: 1px solid var(--line);
334
+ border-radius: var(--radius);
335
+ background: var(--bg-muted);
336
+ padding: 8px 14px;
337
+ text-decoration: none;
338
+ font-size: 13px;
339
+ font-weight: 500;
340
+ transition: all var(--transition);
341
+ }
342
+ .dep-node:hover {
343
+ background: var(--bg-hover);
344
+ border-color: var(--line-strong);
345
+ text-decoration: none;
346
+ color: var(--accent);
347
+ }
348
+ .dep-edge { color: var(--line-strong); font-weight: 400; font-size: 16px; }
349
+ /* ── Misc ── */
350
+ .diagram-status { color: var(--text-secondary); font-size: 13px; margin: 8px 0 0; }
351
+ .placeholder { color: var(--gray); font-style: italic; }
352
+ ul, ol { padding-left: 20px; }
353
+ li { margin: 4px 0; }
354
+ strong { font-weight: 600; }
355
+ /* ── Back to Top ── */
356
+ #back-to-top {
357
+ position: fixed; bottom: 28px; right: 28px;
358
+ padding: 8px 16px; border-radius: var(--radius);
359
+ background: var(--panel); color: var(--accent);
360
+ border: 1px solid var(--line); box-shadow: var(--shadow-md);
361
+ text-decoration: none; font-size: 13px; font-weight: 500;
362
+ opacity: 0; pointer-events: none;
363
+ transition: opacity 0.2s, box-shadow 0.2s;
364
+ }
365
+ #back-to-top:hover { box-shadow: var(--shadow-sm); }
366
+ #back-to-top.visible { opacity: 1; pointer-events: auto; }
367
+ /* ── Responsive ── */
80
368
  @media (max-width: 820px) {
81
369
  .layout { grid-template-columns: 1fr; }
82
- nav { position: static; }
370
+ nav {
371
+ position: static;
372
+ height: auto;
373
+ border-right: none;
374
+ border-bottom: 1px solid var(--line);
375
+ padding: 12px;
376
+ display: flex;
377
+ gap: 4px;
378
+ overflow-x: auto;
379
+ scrollbar-width: none;
380
+ }
381
+ nav::-webkit-scrollbar { display: none; }
382
+ nav a { white-space: nowrap; padding: 6px 10px; }
383
+ nav a .nav-dot { display: none; }
384
+ header { padding: 28px 20px 20px; }
385
+ main { padding: 8px 20px 60px; }
386
+ #back-to-top { bottom: 12px; right: 12px; }
387
+ }
388
+ /* ── Print ── */
389
+ @media print {
390
+ nav, .controls-bar, #back-to-top, .no-results { display: none !important; }
391
+ .layout { grid-template-columns: 1fr; padding: 0; }
392
+ .card { box-shadow: none; break-inside: avoid; border: 1px solid #ddd; }
393
+ .diagram-card { box-shadow: none; }
394
+ body { background: #fff; }
395
+ header { background: #fff; padding: 20px 0; }
396
+ main { padding: 0; max-width: 100%; }
397
+ a { color: #333; }
398
+ code { color: #333; }
399
+ * { color-adjust: exact; -webkit-print-color-adjust: exact; }
83
400
  }
84
401
  </style>
85
402
  </head>
@@ -94,19 +411,26 @@
94
411
  </header>
95
412
  <div class="layout">
96
413
  <nav aria-label="Report sections">
97
- <a href="#summary">Summary</a>
98
- <a href="#architecture">Architecture</a>
99
- <a href="#interfaces">Interfaces</a>
100
- <a href="#requirements">Requirements</a>
101
- <a href="#flows">Flows</a>
102
- <a href="#security">Security</a>
103
- <a href="#nonfunctional">Non-functional</a>
104
- <a href="#questions">Open Questions</a>
105
- <a href="#evidence">Evidence</a>
414
+ <a href="#summary"><span class="nav-dot"></span>Summary</a>
415
+ <a href="#architecture"><span class="nav-dot"></span>Architecture</a>
416
+ <a href="#interfaces"><span class="nav-dot"></span>Interfaces</a>
417
+ <a href="#requirements"><span class="nav-dot"></span>Requirements</a>
418
+ <a href="#flows"><span class="nav-dot"></span>Flows</a>
419
+ <a href="#domain"><span class="nav-dot"></span>Domain Model</a>
420
+ <a href="#security"><span class="nav-dot"></span>Security</a>
421
+ <a href="#errors"><span class="nav-dot"></span>Errors</a>
422
+ <a href="#nonfunctional"><span class="nav-dot"></span>Non-functional</a>
423
+ <a href="#questions"><span class="nav-dot"></span>Open Questions</a>
424
+ <a href="#evidence"><span class="nav-dot"></span>Evidence</a>
106
425
  </nav>
107
426
  <main>
108
427
  <div class="controls">
109
- <input id="report-search" type="search" placeholder="Filter cards, APIs, modules, and evidence">
428
+ <div class="controls-bar">
429
+ <input id="report-search" type="search" placeholder="Search APIs, modules, evidence...">
430
+ <button id="toggle-details" type="button">Expand all</button>
431
+ <button id="show-questions" type="button">Questions only</button>
432
+ </div>
433
+ <p class="no-results" id="no-results">No matching content found.</p>
110
434
  </div>
111
435
  <section id="summary">
112
436
  <h2>Executive Summary</h2>
@@ -138,12 +462,24 @@
138
462
  <p class="placeholder">Pending flow diagrams.</p>
139
463
  <!-- /REQUIREMENTS_FLOWS -->
140
464
  </section>
465
+ <section id="domain">
466
+ <h2>Domain Model And Data Ownership</h2>
467
+ <!-- REQUIREMENTS_DOMAIN_MODEL -->
468
+ <p class="placeholder">Pending domain model and data ownership.</p>
469
+ <!-- /REQUIREMENTS_DOMAIN_MODEL -->
470
+ </section>
141
471
  <section id="security">
142
- <h2>Security, Permissions, And Errors</h2>
472
+ <h2>Permissions, Security, And Compliance</h2>
143
473
  <!-- REQUIREMENTS_SECURITY -->
144
- <p class="placeholder">Pending security and error notes.</p>
474
+ <p class="placeholder">Pending permissions, security, and compliance notes.</p>
145
475
  <!-- /REQUIREMENTS_SECURITY -->
146
476
  </section>
477
+ <section id="errors">
478
+ <h2>Error Handling And Edge Cases</h2>
479
+ <!-- REQUIREMENTS_ERROR_HANDLING -->
480
+ <p class="placeholder">Pending error handling and edge cases.</p>
481
+ <!-- /REQUIREMENTS_ERROR_HANDLING -->
482
+ </section>
147
483
  <section id="nonfunctional">
148
484
  <h2>Non-functional Requirements</h2>
149
485
  <!-- REQUIREMENTS_NONFUNCTIONAL -->
@@ -164,15 +500,81 @@
164
500
  </section>
165
501
  </main>
166
502
  </div>
503
+ <a href="#" id="back-to-top">Back to top</a>
167
504
  <script>
168
- const search = document.querySelector('#report-search');
169
- search?.addEventListener('input', () => {
170
- const query = search.value.trim().toLowerCase();
171
- for (const card of document.querySelectorAll('.card, details, table')) {
172
- const matched = !query || card.textContent.toLowerCase().includes(query);
173
- card.style.display = matched ? '' : 'none';
174
- }
175
- });
505
+ (() => {
506
+ const search = document.querySelector('#report-search');
507
+ const noResults = document.querySelector('#no-results');
508
+ const sections = document.querySelectorAll('section[id]');
509
+ const cards = document.querySelectorAll('.card, details');
510
+ const tables = document.querySelectorAll('table');
511
+ const navLinks = document.querySelectorAll('nav a');
512
+
513
+ /* ── Scroll spy ── */
514
+ const observer = new IntersectionObserver(entries => {
515
+ entries.forEach(e => {
516
+ if (e.isIntersecting) {
517
+ navLinks.forEach(l => l.classList.toggle('active', l.getAttribute('href') === '#' + e.target.id));
518
+ }
519
+ });
520
+ }, { rootMargin: '-80px 0px -70% 0px', threshold: 0 });
521
+ sections.forEach(s => observer.observe(s));
522
+
523
+ /* ── Search ── */
524
+ search?.addEventListener('input', () => {
525
+ const query = search.value.trim().toLowerCase();
526
+ let anyVisible = false;
527
+ if (!query) {
528
+ cards.forEach(c => c.style.display = '');
529
+ tables.forEach(t => t.style.display = '');
530
+ sections.forEach(s => s.style.display = '');
531
+ noResults.style.display = 'none';
532
+ return;
533
+ }
534
+ sections.forEach(s => {
535
+ const inner = s.querySelectorAll('.card, details, table');
536
+ let sectionVisible = false;
537
+ inner.forEach(el => {
538
+ const matched = el.textContent.toLowerCase().includes(query);
539
+ el.style.display = matched ? '' : 'none';
540
+ if (matched) sectionVisible = true;
541
+ });
542
+ s.style.display = sectionVisible ? '' : 'none';
543
+ if (sectionVisible) anyVisible = true;
544
+ });
545
+ noResults.style.display = anyVisible ? 'none' : 'block';
546
+ });
547
+
548
+ /* ── Expand / Collapse all ── */
549
+ const toggleBtn = document.querySelector('#toggle-details');
550
+ let allOpen = false;
551
+ toggleBtn?.addEventListener('click', () => {
552
+ allOpen = !allOpen;
553
+ document.querySelectorAll('details.card').forEach(d => d.open = allOpen);
554
+ toggleBtn.textContent = allOpen ? 'Collapse all' : 'Expand all';
555
+ });
556
+
557
+ /* ── Show questions only ── */
558
+ const questionsBtn = document.querySelector('#show-questions');
559
+ let questionsOnly = false;
560
+ questionsBtn?.addEventListener('click', () => {
561
+ questionsOnly = !questionsOnly;
562
+ const target = document.querySelector('#questions');
563
+ if (questionsOnly) {
564
+ sections.forEach(s => s.style.display = s === target ? '' : 'none');
565
+ questionsBtn.textContent = 'Show all sections';
566
+ } else {
567
+ sections.forEach(s => s.style.display = '');
568
+ questionsBtn.textContent = 'Questions only';
569
+ }
570
+ });
571
+
572
+ /* ── Back to top ── */
573
+ const backToTop = document.querySelector('#back-to-top');
574
+ window.addEventListener('scroll', () => {
575
+ backToTop?.classList.toggle('visible', window.scrollY > 400);
576
+ }, { passive: true });
577
+ })();
176
578
  </script>
177
579
  </body>
178
580
  </html>