codemini-cli 0.4.5 → 0.4.7
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 +5 -5
- package/package.json +1 -1
- package/skills/project-requirements/SKILL.md +94 -50
- package/src/commands/chat.js +4 -1
- package/src/core/agent-loop.js +10 -1
- package/src/core/chat-runtime.js +124 -19
- package/src/core/fff-adapter.js +1 -1
- package/templates/project-requirements/report-shell.html +475 -73
package/deployment.md
CHANGED
|
@@ -13,13 +13,13 @@ npm pack
|
|
|
13
13
|
Expected output:
|
|
14
14
|
|
|
15
15
|
```text
|
|
16
|
-
codemini-cli-0.4.
|
|
16
|
+
codemini-cli-0.4.7.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.
|
|
22
|
+
tar -tf codemini-cli-0.4.7.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.
|
|
37
|
+
C:\temp\codemini-cli-0.4.7.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.
|
|
61
|
+
npm install -g C:\temp\codemini-cli-0.4.7.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.
|
|
69
|
+
npm install C:\temp\codemini-cli-0.4.7.tgz
|
|
70
70
|
```
|
|
71
71
|
|
|
72
72
|
## 5. Confirm Installation
|
package/package.json
CHANGED
|
@@ -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,
|
|
40
|
-
- Use semantic SVG groups, `<title>`/`<desc>`, readable labels, arrow markers,
|
|
41
|
-
-
|
|
42
|
-
- Do not
|
|
43
|
-
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
177
|
-
<rect x="
|
|
178
|
-
<text x="
|
|
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
|
|
181
|
-
<rect x="
|
|
182
|
-
<text x="
|
|
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="
|
|
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="
|
|
193
|
-
<a class="
|
|
194
|
-
<span class="
|
|
195
|
-
<a class="
|
|
196
|
-
<span class="
|
|
197
|
-
<a class="
|
|
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
|
-
```
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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
|
-
```
|
|
215
|
-
|
|
216
|
-
API
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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
|
-
```
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
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.
|
package/src/commands/chat.js
CHANGED
|
@@ -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');
|
package/src/core/agent-loop.js
CHANGED
|
@@ -779,7 +779,16 @@ export async function runAgentLoop({
|
|
|
779
779
|
if (onEvent) onEvent({ type: 'tool:start', name: displayName, id: call.id, arguments: effectiveArgs });
|
|
780
780
|
const handler = toolHandlers[toolName];
|
|
781
781
|
if (!handler) {
|
|
782
|
-
|
|
782
|
+
const available = Object.keys(toolHandlers).join(', ');
|
|
783
|
+
const msg = `Unknown tool: "${toolName}". Available tools: ${available || '(none)'}`;
|
|
784
|
+
if (onEvent) {
|
|
785
|
+
onEvent({ type: 'tool:error', name: displayName, id: call.id, arguments: effectiveArgs, durationMs: 0, summary: trimInline(msg, 200) });
|
|
786
|
+
}
|
|
787
|
+
return {
|
|
788
|
+
callId: call.id,
|
|
789
|
+
content: JSON.stringify({ error: msg }),
|
|
790
|
+
error: true
|
|
791
|
+
};
|
|
783
792
|
}
|
|
784
793
|
|
|
785
794
|
const blockedReason = blockedExplorationReason(toolName, effectiveArgs, analysisGuard);
|
package/src/core/chat-runtime.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
3065
|
+
title: '🧭 Map entry points and evidence sources',
|
|
3016
3066
|
role: 'planner',
|
|
3017
3067
|
task: [
|
|
3018
|
-
'Map project
|
|
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
|
|
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: '
|
|
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
|
-
'
|
|
3110
|
+
'Map data ownership, storage paths, state transitions, and side effects per API/interface.',
|
|
3030
3111
|
reportContract,
|
|
3031
|
-
'
|
|
3032
|
-
'Return requirement-ready findings with evidence paths
|
|
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: '
|
|
3117
|
+
title: '🔄 Connect user flows to API dependencies',
|
|
3037
3118
|
role: 'advisor',
|
|
3038
3119
|
task: [
|
|
3039
|
-
'
|
|
3120
|
+
'Connect user-facing flows to the API/interface inventory and implementation dependencies.',
|
|
3040
3121
|
reportContract,
|
|
3041
|
-
'
|
|
3042
|
-
'
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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'
|
|
@@ -3255,8 +3341,23 @@ async function runProjectRequirementsPipeline({
|
|
|
3255
3341
|
name: custom.name,
|
|
3256
3342
|
summary: error instanceof Error ? error.message : String(error)
|
|
3257
3343
|
});
|
|
3344
|
+
onAgentEvent({ type: 'skill:end', name: custom.name });
|
|
3258
3345
|
}
|
|
3259
|
-
|
|
3346
|
+
if (manifestPath) {
|
|
3347
|
+
await updateProjectRequirementsManifest(manifestPath, {
|
|
3348
|
+
status: 'failed',
|
|
3349
|
+
failedCount: steps.length,
|
|
3350
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3351
|
+
}).catch(() => {});
|
|
3352
|
+
}
|
|
3353
|
+
return {
|
|
3354
|
+
type: 'assistant',
|
|
3355
|
+
text: `Project requirements pipeline failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
3356
|
+
planFile,
|
|
3357
|
+
reportPath,
|
|
3358
|
+
manifestPath,
|
|
3359
|
+
aborted: true
|
|
3360
|
+
};
|
|
3260
3361
|
}
|
|
3261
3362
|
if (onAgentEvent) {
|
|
3262
3363
|
onAgentEvent({
|
|
@@ -4929,8 +5030,12 @@ export async function createChatRuntime({
|
|
|
4929
5030
|
name: custom.name,
|
|
4930
5031
|
summary: error instanceof Error ? error.message : String(error)
|
|
4931
5032
|
});
|
|
5033
|
+
onAgentEvent({ type: 'skill:end', name: custom.name });
|
|
4932
5034
|
}
|
|
4933
|
-
|
|
5035
|
+
return {
|
|
5036
|
+
type: 'system',
|
|
5037
|
+
text: `Skill "${custom.name}" failed: ${error instanceof Error ? error.message : String(error)}`
|
|
5038
|
+
};
|
|
4934
5039
|
}
|
|
4935
5040
|
if (custom.metadata.type === 'skill' && onAgentEvent) {
|
|
4936
5041
|
onAgentEvent({ type: 'skill:end', name: custom.name });
|
package/src/core/fff-adapter.js
CHANGED
|
@@ -6,80 +6,397 @@
|
|
|
6
6
|
<title>{{title}}</title>
|
|
7
7
|
<style>
|
|
8
8
|
:root {
|
|
9
|
-
color-scheme: light
|
|
10
|
-
--bg: #
|
|
9
|
+
color-scheme: light;
|
|
10
|
+
--bg: #ffffff;
|
|
11
|
+
--bg-muted: #f7f7f5;
|
|
12
|
+
--bg-hover: #f0f0ee;
|
|
11
13
|
--panel: #ffffff;
|
|
12
|
-
--text: #
|
|
13
|
-
--
|
|
14
|
-
--line: #
|
|
15
|
-
--
|
|
16
|
-
--
|
|
17
|
-
--
|
|
18
|
-
--
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
:
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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:
|
|
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:
|
|
45
|
+
padding: 48px min(6vw, 80px) 28px;
|
|
39
46
|
border-bottom: 1px solid var(--line);
|
|
40
|
-
background: var(--
|
|
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(
|
|
56
|
-
padding:
|
|
135
|
+
width: min(400px, 100%);
|
|
136
|
+
padding: 7px 12px 7px 32px;
|
|
57
137
|
border: 1px solid var(--line);
|
|
58
|
-
border-radius:
|
|
59
|
-
background: var(--
|
|
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:
|
|
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
|
-
.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
.
|
|
79
|
-
.
|
|
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 {
|
|
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="#
|
|
103
|
-
<a href="#
|
|
104
|
-
<a href="#
|
|
105
|
-
<a href="#
|
|
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
|
-
<
|
|
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>
|
|
472
|
+
<h2>Permissions, Security, And Compliance</h2>
|
|
143
473
|
<!-- REQUIREMENTS_SECURITY -->
|
|
144
|
-
<p class="placeholder">Pending security and
|
|
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
|
-
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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>
|