@capagents/forgeqe 1.0.4 → 1.0.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/HOW_TO_USE.md +60 -3
- package/docs/user-guide.html +63 -5
- package/package.json +1 -1
- package/prompts/README.md +1 -0
- package/prompts/brain.md +4 -1
- package/prompts/refine.md +17 -0
- package/src/brain/index.ts +4 -3
- package/src/brain/prompt.ts +34 -2
- package/src/capabilities/registry.ts +12 -0
- package/src/capabilities/status.ts +4 -3
- package/src/mcp/reporttools.ts +101 -0
- package/src/mcp/tools.ts +4 -0
- package/src/refine.ts +116 -0
- package/src/tui/App.tsx +477 -47
- package/src/tui/components.tsx +78 -3
- package/src/tui/inspector.tsx +181 -39
- package/src/tui/next.ts +43 -0
- package/src/tui/palette.tsx +173 -0
- package/src/tui/refine-panel.tsx +94 -0
- package/src/tui/setup.ts +37 -0
- package/src/tui/suggest.ts +111 -0
- package/src/tui/transcript.tsx +125 -7
- package/src/usage.ts +1 -1
package/HOW_TO_USE.md
CHANGED
|
@@ -66,6 +66,7 @@ Everything ForgeQE can do, by area. ForgeQE's agent answers "can you…?" questi
|
|
|
66
66
|
| Release | **Requirement coverage and release readiness**: Gives requirement coverage and a GO / GO WITH RISKS / NO-GO verdict for a sprint, area, epic, or stories, from test cases, results, bugs, and flaky tests; can publish it to the wiki. | `release_readiness` | [docs](#requirement-coverage-and-release-readiness) |
|
|
67
67
|
| Operations | **Scheduled monitoring with alerts**: Runs checks on a schedule and alerts Teams or email when one keeps failing, and again when it recovers. | `monitor` | [docs](#9-monitoring) |
|
|
68
68
|
| Operations | **Teams and email notifications**: Tells the team in Microsoft Teams channels or by email when a suite fails or passes, when a release readiness verdict is in, and when the domain evaluation falls below its gate, with the failing cases, their bugs, and links to the report and the CI build. Each channel picks its events; the agent also posts a summary to a channel when asked. | `notify` | [docs](#17-notifications) |
|
|
69
|
+
| Release | **Reports you can share**: Writes up what ForgeQE's agent found, such as release status across projects, open defects, or pipeline health, as a Markdown file and an HTML page in the reports folder, with a summary in the chat and links to open them. | `write_report` | [docs](#reports-from-the-agent) |
|
|
69
70
|
| Operations | **CI pipelines**: Writes a GitHub Actions or Azure Pipelines workflow that runs ForgeQE, stores the secrets it needs, pushes a branch, and makes the pipeline green. | `push_branch`, `set_ci_secret` | [docs](#8-pipelines) |
|
|
70
71
|
| Systems | **Work with Azure DevOps, Jira, and Confluence**: Reads anything in the configured systems (work items, issues, queries, boards, pages), makes changes the user asks for, and builds Azure DevOps dashboards and wiki pages. | `query_api`, `read_confluence`, `create_ado_dashboard`, `write_ado_wiki_page` | [docs](README.md#azure-devops-jira-and-other-systems) |
|
|
71
72
|
| Setup | **Setup, skills, and documentation**: Shows the model profiles and MCP servers, installs or repairs the browser engine, creates a forgeqe.yaml, manages skills, and answers questions about ForgeQE from its documentation and this list. | `forgeqe_setup`, `capabilities` | [docs](#2-scaffold-config) |
|
|
@@ -366,12 +367,63 @@ While a run is going, the bar under the prompt shows a spinner, the tokens used,
|
|
|
366
367
|
|
|
367
368
|
The text is the agent's own result. Failed runs show `✗ Task failed` with the reason, and stopped runs show `■ Run stopped`. `forgeqe run` prints the same summary at the end.
|
|
368
369
|
|
|
370
|
+
### Reports from the agent
|
|
371
|
+
|
|
372
|
+
Ask for a report and ForgeQE's agent writes one you can share: "create a release report for all projects", "write up the open defects", "summarise this sprint's test results as a report". It gathers the facts with its tools (Azure DevOps, Jira, the runs it made), then saves the report with `write_report` as a Markdown file and an HTML page in the reports folder (`export.out_dir`, `.forgeqe/reports/` by default):
|
|
373
|
+
|
|
374
|
+
```
|
|
375
|
+
.forgeqe/reports/release-status-all-projects-20261009-001512/
|
|
376
|
+
report.md # to edit, paste into a wiki, or attach
|
|
377
|
+
report.html # to open or share; light and dark, tables scroll on a phone
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
The chat gets a short summary and a card with both paths as links, and **Open the report** appears as a next step. The report holds only what the agent read in that request. To post it, ask for it ("post the report to the release channel") once `notify.channels` is set up; the reports folder is linked when it is served (`notify.report_url`).
|
|
381
|
+
|
|
382
|
+
### The screen
|
|
383
|
+
|
|
384
|
+
On a terminal 120 columns wide or more, the shell splits in two once you send a request:
|
|
385
|
+
|
|
386
|
+
- **Left (40%)**: the **Session** panel (model and profile, folder, domain, requests so far), the conversation, and the prompt.
|
|
387
|
+
- **Right (60%)**: a status line with who is working, for how long, and a **■ Stop** button (a running suite adds a progress bar, `██████░░░░░░ 5/8`); then **Plan** (the agent's to-do list, then each browser step or suite case with ✓, ✗ and why, ◐ running), **Activity** (every tool call, browser step, and the agents' reasoning), **Files** (each file read ◉, written ✚, or edited ✎, newest first), **Context** (how full the model's context window is, and the skills, product knowledge, domain, and MCP servers in it), and **Tokens** (total, input, output, cached; no prices, which are in reports and `forgeqe models`).
|
|
388
|
+
|
|
389
|
+
On a narrower terminal the chat fills the screen, and Ctrl-O switches between the chat and the same panels.
|
|
390
|
+
|
|
391
|
+
**Buttons.** Under the prompt: **✦ Refine** (Ctrl-R; it fills in once there is text to refine) and **⌕ Search** (Ctrl-P, the command palette); while a request runs, **■ Stop** (Esc) takes Refine's place. In the status line above the panels: **▦ Panels** (Shift-Tab) and **⤢ Wide chat**, which gives the conversation the whole width for reading a long answer; **◧ Split view**, under the prompt, brings the panels back. On a narrow terminal, **◧ Details** (Ctrl-O) and **⇄ Profile** (Tab) are under the prompt. Each is clickable.
|
|
392
|
+
|
|
393
|
+
**Progress.** While a request runs, the status line above the panels shows a bar for how far the agent's plan has got (`███████░░░░░ 2/3`), or the suite's cases while a suite runs.
|
|
394
|
+
|
|
395
|
+
**Replies.** The agent's answers lead with the answer, then short headed sections; lists keep their bullets in a column, so a wrapped line stays under its text instead of running back to the margin.
|
|
396
|
+
|
|
397
|
+
**Moving between panels.** Shift-Tab (or a click) moves the keys from the prompt to Plan, Activity, then Files; the focused panel's border lights up and shows its keys. Esc, or typing, goes back to the prompt.
|
|
398
|
+
|
|
399
|
+
| Panel | Keys |
|
|
400
|
+
|-------|------|
|
|
401
|
+
| Plan | ↑/↓ select a step, Enter puts the whole step, with why it failed, in the chat |
|
|
402
|
+
| Activity | ↑/↓, PgUp/PgDn scroll; `a` all, `e` errors, `s` steps (browser steps and reasoning), `t` tools (tool calls and files); the filter buttons are clickable too |
|
|
403
|
+
| Files | ↑/↓ select, Enter (or a click) opens the file |
|
|
404
|
+
|
|
405
|
+
**Links.** Report folders, report files, and web addresses in the chat are links: Cmd-click (Ctrl-click on Windows and Linux) opens them in terminals that support links, such as VS Code, iTerm2, Windows Terminal, and recent GNOME Terminal. A path that no longer exists stays plain text.
|
|
406
|
+
|
|
407
|
+
**Setup checklist.** Until everything is set up, the start screen shows what most features rest on: **Model** (a live model profile), **Coding agent**, **Work items** (Azure DevOps, Jira, TestRail, Zephyr, qTest, or Xray), **Domain**, and **Notifications**, each ✓ or ○. Click an open item to see how to set it up; **Work items** starts `/auth`. The checks are the same ones `/features` uses, so the two always agree.
|
|
408
|
+
|
|
409
|
+
**Command palette.** Ctrl-P opens a palette of every action, command, profile, and example request; type a few letters to find one ("rr" finds *Refine my request*, "auth" finds the sign-in commands), ↑/↓ to choose, Enter to run it. Example requests are put in the prompt for you to edit, never sent straight away.
|
|
410
|
+
|
|
411
|
+
**`/` and `@` in the prompt.** Typing `/` lists the commands that match; typing `@` suggests references: recent runs (*last run*, then each by its folder), files in the repository by name or path (`@Login` finds `pages/Login.ts`), and, after `@` and a number such as `@1761`, the Azure DevOps work item with its title (read-only). Tab completes, ↑/↓ choose, Esc closes the list.
|
|
412
|
+
|
|
413
|
+
**Refine.** Ctrl-R (or *Refine my request* in the palette) turns what you typed into a precise request before it is sent. A read-only agent checks it against this setup: what ForgeQE can do here, the systems that are set up, the project's sprints and test cases, and recent runs. It shows the refined request with what it **checked** ✓, what it **assumed** ~, and what is **missing** ?. Enter uses it, `e` puts it in the prompt to edit, Esc keeps yours. Refine never runs anything, writes files, or changes a work item.
|
|
414
|
+
|
|
415
|
+
**Next steps.** When a request finishes, up to three suggestions appear above the prompt: from what it produced (*Open the report*, *Write a test for this run*, *Why did it fail?*, *Rerun the cases that failed*) and from the agent's answer, which suggests the follow-ups you are likely to want (*Write a release report*, *Show the failed CD logs*). Click one or press Alt-1 to Alt-3; suggestions that start work are put in the prompt first, to adjust and send.
|
|
416
|
+
|
|
369
417
|
| Key | Action |
|
|
370
418
|
|-----|--------|
|
|
371
419
|
| Enter | Send the message or command |
|
|
372
|
-
| Tab | Next LLM profile from `llms.json`; the conversation carries over to the new model |
|
|
373
|
-
|
|
|
374
|
-
|
|
|
420
|
+
| Tab | Next LLM profile from `llms.json`; the conversation carries over to the new model. While `/` or `@` suggestions show, completes the selected one |
|
|
421
|
+
| Shift-Tab | Move between the chat and the Plan, Activity, and Files panels |
|
|
422
|
+
| Ctrl-P | Command palette |
|
|
423
|
+
| Ctrl-R | Refine the request in the prompt |
|
|
424
|
+
| Ctrl-O | Chat or details, on a terminal narrower than 120 columns |
|
|
425
|
+
| Alt-1 to Alt-3 | Take a suggested next step |
|
|
426
|
+
| Esc | Ask to stop the run: **Stop run**, **Stop and close ForgeQE**, or **Keep running**. In a panel, back to the prompt |
|
|
375
427
|
| Ctrl-C | Ask to close ForgeQE: **Close** or **Cancel**. A second Ctrl-C closes straight away |
|
|
376
428
|
|
|
377
429
|
In the button prompt, ←/→ or Tab move between buttons, Enter confirms, Esc cancels, and a mouse click works too. `esc stop` and `ctrl+c close` in the bar under the prompt are also clickable. **Stop and close** waits until the browser has shut down and the run's files are saved, then closes ForgeQE.
|
|
@@ -1533,6 +1585,11 @@ Start with `--debug` (or set `FORGEQE_DEBUG=1`) for more: the browser engine log
|
|
|
1533
1585
|
| `/auth [system]`, `/auth logout <system>` | Sign in to a system in the browser (the token is typed unseen), forget one; `/auth` alone shows what is signed in |
|
|
1534
1586
|
| `/clear`, `/help`, `/exit` | Clear the transcript, show help, quit |
|
|
1535
1587
|
| Drag with the mouse | Copy the selected text |
|
|
1588
|
+
| Ctrl-P | Command palette: actions, commands, profiles, example requests |
|
|
1589
|
+
| Ctrl-R | Refine the request before sending it |
|
|
1590
|
+
| `/`, `@` | Suggest commands; suggest runs, files, and work items to reference |
|
|
1591
|
+
| Shift-Tab | Move between the chat and the Plan, Activity, and Files panels |
|
|
1592
|
+
| Cmd/Ctrl-click a path | Open a report, file, or web address |
|
|
1536
1593
|
|
|
1537
1594
|
---
|
|
1538
1595
|
|
package/docs/user-guide.html
CHANGED
|
@@ -286,7 +286,7 @@ forgeqe docs --copy ./docs # copy the guide, the architecture page, and the re
|
|
|
286
286
|
<div class="area"><a class="area-name" href="#area-pull-requests"><span class="mono">Pull requests</span></a><ul class="tiles"><li><a class="tile" href="#cap-pr-review"><b>Review pull requests</b><span>Review PR 42 and focus on error handling</span></a></li><li><a class="tile" href="#cap-pr-impact"><b>Pull request impact and test selection</b><span>What does PR 42 impact?</span></a></li></ul></div>
|
|
287
287
|
<div class="area"><a class="area-name" href="#area-api"><span class="mono">API</span></a><ul class="tiles"><li><a class="tile" href="#cap-api-testing"><b>API and contract testing</b><span>Turn the last run's API calls into tests</span></a></li></ul></div>
|
|
288
288
|
<div class="area"><a class="area-name" href="#area-quality"><span class="mono">Quality</span></a><ul class="tiles"><li><a class="tile" href="#cap-accessibility-performance"><b>Accessibility and page performance</b><span>Is the checkout page accessible?</span></a></li><li><a class="tile" href="#cap-visual-comparison"><b>Visual comparison with baselines</b><span>What changed visually since the last run?</span></a></li></ul></div>
|
|
289
|
-
<div class="area"><a class="area-name" href="#area-release"><span class="mono">Release</span></a><ul class="tiles"><li><a class="tile" href="#cap-release-readiness"><b>Requirement coverage and release readiness</b><span>Are we ready to release?</span></a></li></ul></div>
|
|
289
|
+
<div class="area"><a class="area-name" href="#area-release"><span class="mono">Release</span></a><ul class="tiles"><li><a class="tile" href="#cap-release-readiness"><b>Requirement coverage and release readiness</b><span>Are we ready to release?</span></a></li><li><a class="tile" href="#cap-reports"><b>Reports you can share</b><span>Create a release report for all projects</span></a></li></ul></div>
|
|
290
290
|
<div class="area"><a class="area-name" href="#area-operations"><span class="mono">Operations</span></a><ul class="tiles"><li><a class="tile" href="#cap-monitoring"><b>Scheduled monitoring with alerts</b><span>Check the login flow every 15 minutes and alert Teams</span></a></li><li><a class="tile" href="#cap-notifications"><b>Teams and email notifications</b><span>Post the results to the QA channel</span></a></li><li><a class="tile" href="#cap-pipelines"><b>CI pipelines</b><span>Add a GitHub Actions workflow that runs tests/cases.yaml on every PR, and make it green</span></a></li></ul></div>
|
|
291
291
|
<div class="area"><a class="area-name" href="#area-systems"><span class="mono">Systems</span></a><ul class="tiles"><li><a class="tile" href="#cap-systems"><b>Work with Azure DevOps, Jira, and Confluence</b><span>Show the open bugs in this sprint</span></a></li></ul></div>
|
|
292
292
|
<div class="area"><a class="area-name" href="#area-setup"><span class="mono">Setup</span></a><ul class="tiles"><li><a class="tile" href="#cap-setup-help"><b>Setup, skills, and documentation</b><span>What can you do?</span></a></li></ul></div>
|
|
@@ -543,20 +543,51 @@ Add a GitHub Actions workflow that runs tests/cases.yaml on every PR, and make i
|
|
|
543
543
|
┃ Saved .forgeqe/reports/20260928-172700/ run.json · workflow.yaml · trace.md · report.html
|
|
544
544
|
</code></pre>
|
|
545
545
|
<p>The text is the agent's own result. Failed runs show <code>✗ Task failed</code> with the reason, and stopped runs show <code>■ Run stopped</code>. <code>forgeqe run</code> prints the same summary at the end.</p>
|
|
546
|
+
</div>
|
|
547
|
+
<section class="doc sub" id="doc-how_to_use-the-screen"><h4>The screen</h4><div class="prose"><p>On a terminal 120 columns wide or more, the shell splits in two once you send a request:</p>
|
|
548
|
+
<ul>
|
|
549
|
+
<li><strong>Left (40%)</strong>: the <strong>Session</strong> panel (model and profile, folder, domain, requests so far), the conversation, and the prompt.</li>
|
|
550
|
+
<li><strong>Right (60%)</strong>: a status line with who is working, for how long, and a <strong>■ Stop</strong> button (a running suite adds a progress bar, <code>██████░░░░░░ 5/8</code>); then <strong>Plan</strong> (the agent's to-do list, then each browser step or suite case with ✓, ✗ and why, ◐ running), <strong>Activity</strong> (every tool call, browser step, and the agents' reasoning), <strong>Files</strong> (each file read ◉, written ✚, or edited ✎, newest first), <strong>Context</strong> (how full the model's context window is, and the skills, product knowledge, domain, and MCP servers in it), and <strong>Tokens</strong> (total, input, output, cached; no prices, which are in reports and <code>forgeqe models</code>).</li>
|
|
551
|
+
</ul>
|
|
552
|
+
<p>On a narrower terminal the chat fills the screen, and Ctrl-O switches between the chat and the same panels.</p>
|
|
553
|
+
<p><strong>Buttons.</strong> Under the prompt: <strong>✦ Refine</strong> (Ctrl-R; it fills in once there is text to refine) and <strong>⌕ Search</strong> (Ctrl-P, the command palette); while a request runs, <strong>■ Stop</strong> (Esc) takes Refine's place. In the status line above the panels: <strong>▦ Panels</strong> (Shift-Tab) and <strong>⤢ Wide chat</strong>, which gives the conversation the whole width for reading a long answer; <strong>◧ Split view</strong>, under the prompt, brings the panels back. On a narrow terminal, <strong>◧ Details</strong> (Ctrl-O) and <strong>⇄ Profile</strong> (Tab) are under the prompt. Each is clickable.</p>
|
|
554
|
+
<p><strong>Progress.</strong> While a request runs, the status line above the panels shows a bar for how far the agent's plan has got (<code>███████░░░░░ 2/3</code>), or the suite's cases while a suite runs.</p>
|
|
555
|
+
<p><strong>Replies.</strong> The agent's answers lead with the answer, then short headed sections; lists keep their bullets in a column, so a wrapped line stays under its text instead of running back to the margin.</p>
|
|
556
|
+
<p><strong>Moving between panels.</strong> Shift-Tab (or a click) moves the keys from the prompt to Plan, Activity, then Files; the focused panel's border lights up and shows its keys. Esc, or typing, goes back to the prompt.</p>
|
|
557
|
+
<div class="tbl"><table>
|
|
558
|
+
<thead>
|
|
559
|
+
<tr><th>Panel</th><th>Keys</th></tr>
|
|
560
|
+
</thead>
|
|
561
|
+
<tbody>
|
|
562
|
+
<tr><td>Plan</td><td>↑/↓ select a step, Enter puts the whole step, with why it failed, in the chat</td></tr>
|
|
563
|
+
<tr><td>Activity</td><td>↑/↓, PgUp/PgDn scroll; <code>a</code> all, <code>e</code> errors, <code>s</code> steps (browser steps and reasoning), <code>t</code> tools (tool calls and files); the filter buttons are clickable too</td></tr>
|
|
564
|
+
<tr><td>Files</td><td>↑/↓ select, Enter (or a click) opens the file</td></tr>
|
|
565
|
+
</tbody>
|
|
566
|
+
</table></div>
|
|
567
|
+
<p><strong>Links.</strong> Report folders, report files, and web addresses in the chat are links: Cmd-click (Ctrl-click on Windows and Linux) opens them in terminals that support links, such as VS Code, iTerm2, Windows Terminal, and recent GNOME Terminal. A path that no longer exists stays plain text.</p>
|
|
568
|
+
<p><strong>Setup checklist.</strong> Until everything is set up, the start screen shows what most features rest on: <strong>Model</strong> (a live model profile), <strong>Coding agent</strong>, <strong>Work items</strong> (Azure DevOps, Jira, TestRail, Zephyr, qTest, or Xray), <strong>Domain</strong>, and <strong>Notifications</strong>, each ✓ or ○. Click an open item to see how to set it up; <strong>Work items</strong> starts <code>/auth</code>. The checks are the same ones <code>/features</code> uses, so the two always agree.</p>
|
|
569
|
+
<p><strong>Command palette.</strong> Ctrl-P opens a palette of every action, command, profile, and example request; type a few letters to find one ("rr" finds <em>Refine my request</em>, "auth" finds the sign-in commands), ↑/↓ to choose, Enter to run it. Example requests are put in the prompt for you to edit, never sent straight away.</p>
|
|
570
|
+
<p><strong><code>/</code> and <code>@</code> in the prompt.</strong> Typing <code>/</code> lists the commands that match; typing <code>@</code> suggests references: recent runs (<em>last run</em>, then each by its folder), files in the repository by name or path (<code>@Login</code> finds <code>pages/Login.ts</code>), and, after <code>@</code> and a number such as <code>@1761</code>, the Azure DevOps work item with its title (read-only). Tab completes, ↑/↓ choose, Esc closes the list.</p>
|
|
571
|
+
<p><strong>Refine.</strong> Ctrl-R (or <em>Refine my request</em> in the palette) turns what you typed into a precise request before it is sent. A read-only agent checks it against this setup: what ForgeQE can do here, the systems that are set up, the project's sprints and test cases, and recent runs. It shows the refined request with what it <strong>checked</strong> ✓, what it <strong>assumed</strong> ~, and what is <strong>missing</strong> ?. Enter uses it, <code>e</code> puts it in the prompt to edit, Esc keeps yours. Refine never runs anything, writes files, or changes a work item.</p>
|
|
572
|
+
<p><strong>Next steps.</strong> When a request finishes, up to three suggestions appear above the prompt: from what it produced (<em>Open the report</em>, <em>Write a test for this run</em>, <em>Why did it fail?</em>, <em>Rerun the cases that failed</em>) and from the agent's answer, which suggests the follow-ups you are likely to want (<em>Write a release report</em>, <em>Show the failed CD logs</em>). Click one or press Alt-1 to Alt-3; suggestions that start work are put in the prompt first, to adjust and send.</p>
|
|
546
573
|
<div class="tbl"><table>
|
|
547
574
|
<thead>
|
|
548
575
|
<tr><th>Key</th><th>Action</th></tr>
|
|
549
576
|
</thead>
|
|
550
577
|
<tbody>
|
|
551
578
|
<tr><td>Enter</td><td>Send the message or command</td></tr>
|
|
552
|
-
<tr><td>Tab</td><td>Next LLM profile from <code>llms.json</code>; the conversation carries over to the new model</td></tr>
|
|
553
|
-
<tr><td>
|
|
554
|
-
<tr><td>
|
|
579
|
+
<tr><td>Tab</td><td>Next LLM profile from <code>llms.json</code>; the conversation carries over to the new model. While <code>/</code> or <code>@</code> suggestions show, completes the selected one</td></tr>
|
|
580
|
+
<tr><td>Shift-Tab</td><td>Move between the chat and the Plan, Activity, and Files panels</td></tr>
|
|
581
|
+
<tr><td>Ctrl-P</td><td>Command palette</td></tr>
|
|
582
|
+
<tr><td>Ctrl-R</td><td>Refine the request in the prompt</td></tr>
|
|
583
|
+
<tr><td>Ctrl-O</td><td>Chat or details, on a terminal narrower than 120 columns</td></tr>
|
|
584
|
+
<tr><td>Alt-1 to Alt-3</td><td>Take a suggested next step</td></tr>
|
|
585
|
+
<tr><td>Esc</td><td>Ask to stop the run: <strong>Stop run</strong>, <strong>Stop and close ForgeQE</strong>, or <strong>Keep running</strong>. In a panel, back to the prompt</td></tr>
|
|
555
586
|
<tr><td>Ctrl-C</td><td>Ask to close ForgeQE: <strong>Close</strong> or <strong>Cancel</strong>. A second Ctrl-C closes straight away</td></tr>
|
|
556
587
|
</tbody>
|
|
557
588
|
</table></div>
|
|
558
589
|
<p>In the button prompt, ←/→ or Tab move between buttons, Enter confirms, Esc cancels, and a mouse click works too. <code>esc stop</code> and <code>ctrl+c close</code> in the bar under the prompt are also clickable. <strong>Stop and close</strong> waits until the browser has shut down and the run's files are saved, then closes ForgeQE.</p>
|
|
559
|
-
</div>
|
|
590
|
+
</div></section>
|
|
560
591
|
</section>
|
|
561
592
|
<section class="doc" id="doc-how_to_use-4-without-the-shell">
|
|
562
593
|
<h3>Without the shell</h3>
|
|
@@ -1531,6 +1562,28 @@ forgeqe visual approve --page /home # make this run's /home the baseline (asks
|
|
|
1531
1562
|
</section>
|
|
1532
1563
|
</div>
|
|
1533
1564
|
</article>
|
|
1565
|
+
<article class="spec feat" id="cap-reports">
|
|
1566
|
+
<div class="hd"><span class="mono">Release</span><h3>Reports you can share</h3></div>
|
|
1567
|
+
<p class="ds">Writes up what ForgeQE's agent found, such as release status across projects, open defects, or pipeline health, as a Markdown file and an HTML page in the reports folder, with a summary in the chat and links to open them.</p>
|
|
1568
|
+
<div class="facts">
|
|
1569
|
+
<div class="fact"><span class="mono">Ask it</span><ul class="asks"><li>Create a release report for all projects</li><li>Write up the open defects as a report I can share</li></ul></div>
|
|
1570
|
+
<div class="fact"><span class="mono">What it needs</span><ul class="needs"><li><span class="need req">Required</span><span>A live model profile in llms.json (an API key or Microsoft Entra ID sign-in)</span></li></ul></div>
|
|
1571
|
+
<div class="fact"><span class="mono">Limits</span><ul class="plainlist"><li>The report holds what the agent read with its tools in this request; it does not invent figures, and it does not publish the page anywhere unless the reports folder is served (notify.report_url).</li></ul></div>
|
|
1572
|
+
<div class="fact"><span class="mono">Tools</span><p class="tools"><code>write_report</code></p></div>
|
|
1573
|
+
</div>
|
|
1574
|
+
<div class="detail"><span class="mono">In detail</span>
|
|
1575
|
+
<section class="doc" id="doc-how_to_use-reports-from-the-agent">
|
|
1576
|
+
<h4>Reports from the agent</h4>
|
|
1577
|
+
<div class="prose"><p>Ask for a report and ForgeQE's agent writes one you can share: "create a release report for all projects", "write up the open defects", "summarise this sprint's test results as a report". It gathers the facts with its tools (Azure DevOps, Jira, the runs it made), then saves the report with <code>write_report</code> as a Markdown file and an HTML page in the reports folder (<code>export.out_dir</code>, <code>.forgeqe/reports/</code> by default):</p>
|
|
1578
|
+
<pre><code>.forgeqe/reports/release-status-all-projects-20261009-001512/
|
|
1579
|
+
report.md # to edit, paste into a wiki, or attach
|
|
1580
|
+
report.html # to open or share; light and dark, tables scroll on a phone
|
|
1581
|
+
</code></pre>
|
|
1582
|
+
<p>The chat gets a short summary and a card with both paths as links, and <strong>Open the report</strong> appears as a next step. The report holds only what the agent read in that request. To post it, ask for it ("post the report to the release channel") once <code>notify.channels</code> is set up; the reports folder is linked when it is served (<code>notify.report_url</code>).</p>
|
|
1583
|
+
</div>
|
|
1584
|
+
</section>
|
|
1585
|
+
</div>
|
|
1586
|
+
</article>
|
|
1534
1587
|
</section>
|
|
1535
1588
|
<section class="chapter" id="area-operations" aria-labelledby="area-operations-h">
|
|
1536
1589
|
<header class="chead"><span class="mono">11</span><h2 id="area-operations-h">Operations</h2><p>Monitoring and CI pipelines</p></header>
|
|
@@ -2024,6 +2077,11 @@ agents: [browser]
|
|
|
2024
2077
|
<tr><td><code>/auth [system]</code>, <code>/auth logout <system></code></td><td>Sign in to a system in the browser (the token is typed unseen), forget one; <code>/auth</code> alone shows what is signed in</td></tr>
|
|
2025
2078
|
<tr><td><code>/clear</code>, <code>/help</code>, <code>/exit</code></td><td>Clear the transcript, show help, quit</td></tr>
|
|
2026
2079
|
<tr><td>Drag with the mouse</td><td>Copy the selected text</td></tr>
|
|
2080
|
+
<tr><td>Ctrl-P</td><td>Command palette: actions, commands, profiles, example requests</td></tr>
|
|
2081
|
+
<tr><td>Ctrl-R</td><td>Refine the request before sending it</td></tr>
|
|
2082
|
+
<tr><td><code>/</code>, <code>@</code></td><td>Suggest commands; suggest runs, files, and work items to reference</td></tr>
|
|
2083
|
+
<tr><td>Shift-Tab</td><td>Move between the chat and the Plan, Activity, and Files panels</td></tr>
|
|
2084
|
+
<tr><td>Cmd/Ctrl-click a path</td><td>Open a report, file, or web address</td></tr>
|
|
2027
2085
|
</tbody>
|
|
2028
2086
|
</table></div>
|
|
2029
2087
|
<hr />
|
package/package.json
CHANGED
package/prompts/README.md
CHANGED
|
@@ -16,6 +16,7 @@ project; leave it as it is to keep getting ForgeQE's improvements when you updat
|
|
|
16
16
|
| api-scenarios.md | Plans API scenarios from test cases or plain English |
|
|
17
17
|
| explore-charters.md | Plans exploratory charters for a story |
|
|
18
18
|
| eval-judge.md | Scores the agent's test cases in `forgeqe eval domain` |
|
|
19
|
+
| refine.md | Refine (ctrl+r) in the shell: makes what you typed precise, checked against what ForgeQE knows |
|
|
19
20
|
| skill-rule.md | How agents use skills (included in most prompts) |
|
|
20
21
|
| domain-rule.md | How agents apply the product's industry risks and regulations, declared or worked out (included in every agent that analyses requirements or designs, writes, reviews, or heals tests) |
|
|
21
22
|
| browser-*.md | The browser agent: error recovery, when a goal counts as done, recording checks, clicking so runs become tests, step verdicts for test cases, picking skills |
|
package/prompts/brain.md
CHANGED
|
@@ -163,4 +163,7 @@ Rules:
|
|
|
163
163
|
- Never ask for an API token, API key, or password for Azure DevOps, GitHub, Jira, Confluence, TestRail, Zephyr, qTest, Xray, or a model provider in the chat. When one of them is not set up, or rejects the credentials (401, 403, "needs <NAME> in the environment"), tell the user to type /auth <system> in the shell (or run forgeqe auth login <system> in a terminal): it signs in through the browser and saves the token, and you get it on the next message. /auth <ENV_NAME> saves any other secret the same way. Website logins for browser runs are different: those go through the logins tool.
|
|
164
164
|
- Never push except with push_branch, never to the default branch, and never force.
|
|
165
165
|
- Stay inside the working directory, except to read ForgeQE's run and memory folders.
|
|
166
|
-
- Replies are shown as markdown:
|
|
166
|
+
- Replies are shown as markdown in a narrow chat pane, so write for scanning: one or two plain sentences with the answer first, then a short `##` heading per group if there is more than one, bullets of one line each, and bold only for the one word or figure that matters in a line (a status, a count), never whole sentences. Use a table only for two or three short columns. Keep replies short and concrete; test cases, tests, and reviews you were asked for are given in full, and only your own commentary is kept short.
|
|
167
|
+
- When the user asks for a report, a write-up, or a summary to share ("create a release report", "write up the open defects"), gather the facts with your tools, then save it with write_report and reply with three to five lines of summary; the shell shows the report's paths as links, so do not repeat them. Never only paste a long report into the reply.
|
|
168
|
+
- Do not end a reply with "If you want, I can…" options: put up to three follow-ups the user is likely to want next in the structured answer's next (a short label, and the request as the user would type it). They are shown as buttons.
|
|
169
|
+
- End every turn with the structured answer: reply (what you did and found, or your question), outcome, and next.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: refine
|
|
3
|
+
description: "Turns what the user typed into a precise request for ForgeQE's agent, checked against what ForgeQE knows."
|
|
4
|
+
used_by: "the shell's Refine (ctrl+r)"
|
|
5
|
+
---
|
|
6
|
+
You refine a request the user typed for ForgeQE, a test automation assistant, before it is sent to ForgeQE's agent. You do not carry the request out, and you do not change anything.
|
|
7
|
+
|
|
8
|
+
Make it a request the agent can act on without guessing:
|
|
9
|
+
- Keep the user's intent and scope exactly. Do not add work they did not ask for, and do not drop anything they did.
|
|
10
|
+
- Name things the way ForgeQE knows them: the system and project ("Azure DevOps project QI-Payments"), ids ("test plan 412, suite 77", "story 1761", "SHOP-12"), files and folders, and the profile. Use "This session" and the capabilities tool to know what ForgeQE can do, but describe the action in plain words ("run the test cases", "write a Playwright test"): never name ForgeQE's tools or capability ids.
|
|
11
|
+
- Resolve references from the session and the conversation ("the last run", "that story", "the payments plan") into what they point to, but only when exactly one thing fits.
|
|
12
|
+
- Check what you can with your read-only tools: that a work item, test plan, suite, or run exists, what it is called, how many cases it has. Mark each fact you state as checked or assumed.
|
|
13
|
+
- Never invent an id, a URL, a project, or a file. What you cannot resolve or check goes in missing, as a short question for the user.
|
|
14
|
+
- Keep the user's settings when they give them (browsers at once, headed, whether results go back), and add none they did not.
|
|
15
|
+
- Write the refined request as the user would say it, in one to four sentences, in their language.
|
|
16
|
+
|
|
17
|
+
Finish with the structured result: refined (the request), grounded (each fact you state, and whether you checked it), assumed (what you took to be meant, in a few words each), and missing (questions, if any).
|
package/src/brain/index.ts
CHANGED
|
@@ -8,7 +8,7 @@ import type { AppConfig } from "../config.ts"
|
|
|
8
8
|
import { externalMcp, externalNotes, type ExternalPlan } from "../mcp/external.ts"
|
|
9
9
|
import { MCP_NAME, TOOL_TIMEOUT_MS, localToolServer } from "../mcp/server.ts"
|
|
10
10
|
import { TOOLS, environmentNotes, type ToolContext } from "../mcp/tools.ts"
|
|
11
|
-
import { brainPrompt, BRAIN_SCHEMA, type BrainReport } from "./prompt.ts"
|
|
11
|
+
import { brainPrompt, BRAIN_SCHEMA, cleanFollowUps, type BrainReport, type FollowUp } from "./prompt.ts"
|
|
12
12
|
import { redactSecrets } from "../sessionLogins.ts"
|
|
13
13
|
import { logEvent } from "../sessionLog.ts"
|
|
14
14
|
import { loadSkills } from "../skills/registry.ts"
|
|
@@ -16,7 +16,7 @@ import { domainNotes } from "../domain.ts"
|
|
|
16
16
|
|
|
17
17
|
export const BRAIN_AGENT = "forgeqe"
|
|
18
18
|
|
|
19
|
-
export type BrainAnswer = { reply: string; outcome: "done" | "failed" | "needs_input" | "stopped"; error?: string }
|
|
19
|
+
export type BrainAnswer = { reply: string; outcome: "done" | "failed" | "needs_input" | "stopped"; error?: string; next?: FollowUp[] }
|
|
20
20
|
|
|
21
21
|
export type Brain = {
|
|
22
22
|
model: string
|
|
@@ -173,7 +173,8 @@ export async function openBrain(opts: BrainOptions): Promise<Brain> {
|
|
|
173
173
|
if (stopped || out.error === "stopped" || opts.signal?.aborted) return { reply: "", outcome: "stopped" }
|
|
174
174
|
const reply = out.report?.reply?.trim() || out.text.trim()
|
|
175
175
|
if (out.error && !out.report) return { reply, outcome: "failed", error: out.error }
|
|
176
|
-
|
|
176
|
+
const next = cleanFollowUps(out.report?.next)
|
|
177
|
+
return { reply, outcome: out.report?.outcome || (out.error ? "failed" : "done"), error: out.error, ...(next.length ? { next } : {}) }
|
|
177
178
|
},
|
|
178
179
|
abort: () => {
|
|
179
180
|
stopped = true
|
package/src/brain/prompt.ts
CHANGED
|
@@ -6,14 +6,46 @@ export const brainPrompt = () => prompt("brain")
|
|
|
6
6
|
export const BRAIN_SCHEMA = {
|
|
7
7
|
type: "object",
|
|
8
8
|
properties: {
|
|
9
|
-
reply: { type: "string", description: "What you did and found, or the question you need answered
|
|
9
|
+
reply: { type: "string", description: "What you did and found, or the question you need answered: Markdown, answer first, short lines." },
|
|
10
10
|
outcome: {
|
|
11
11
|
type: "string",
|
|
12
12
|
enum: ["done", "failed", "needs_input"],
|
|
13
13
|
description: "done: the request was carried out and everything checked passed. failed: a run, test, or pipeline failed or could not be done. needs_input: you asked the user something.",
|
|
14
14
|
},
|
|
15
|
+
next: {
|
|
16
|
+
type: "array",
|
|
17
|
+
maxItems: 3,
|
|
18
|
+
description: "Up to three follow-ups the user is likely to want next, shown as buttons; empty when there is no clear next step.",
|
|
19
|
+
items: {
|
|
20
|
+
type: "object",
|
|
21
|
+
properties: {
|
|
22
|
+
label: { type: "string", description: "Two to five words, e.g. Write a release report" },
|
|
23
|
+
request: { type: "string", description: "The request as the user would type it, complete on its own" },
|
|
24
|
+
},
|
|
25
|
+
required: ["label", "request"],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
15
28
|
},
|
|
16
29
|
required: ["reply", "outcome"],
|
|
17
30
|
} as const
|
|
18
31
|
|
|
19
|
-
|
|
32
|
+
/** A follow-up the agent suggests: a button label, and the request it puts in the prompt. */
|
|
33
|
+
export type FollowUp = { label: string; request: string }
|
|
34
|
+
|
|
35
|
+
export type BrainReport = { reply?: string; outcome?: "done" | "failed" | "needs_input"; next?: FollowUp[] }
|
|
36
|
+
|
|
37
|
+
/** The follow-ups worth showing: well-formed, short enough for a button, at most three, no repeats. */
|
|
38
|
+
export function cleanFollowUps(next: unknown): FollowUp[] {
|
|
39
|
+
if (!Array.isArray(next)) return []
|
|
40
|
+
const seen = new Set<string>()
|
|
41
|
+
const out: FollowUp[] = []
|
|
42
|
+
for (const n of next) {
|
|
43
|
+
const label = typeof n?.label === "string" ? n.label.replace(/\s+/g, " ").trim() : ""
|
|
44
|
+
const request = typeof n?.request === "string" ? n.request.trim() : ""
|
|
45
|
+
if (!label || !request || label.length > 40 || seen.has(label.toLowerCase())) continue
|
|
46
|
+
seen.add(label.toLowerCase())
|
|
47
|
+
out.push({ label, request })
|
|
48
|
+
if (out.length === 3) break
|
|
49
|
+
}
|
|
50
|
+
return out
|
|
51
|
+
}
|
|
@@ -290,6 +290,18 @@ export const CAPABILITIES: Capability[] = [
|
|
|
290
290
|
limits: ["Automatic notifications come from runs nobody is watching (forgeqe suite, forgeqe run, pipelines, the MCP server), not from the interactive shell, where the agent posts only when asked."],
|
|
291
291
|
docs: [{ doc: "HOW_TO_USE.md", heading: "17. Notifications" }],
|
|
292
292
|
},
|
|
293
|
+
{
|
|
294
|
+
id: "reports",
|
|
295
|
+
area: "Release",
|
|
296
|
+
title: "Reports you can share",
|
|
297
|
+
summary:
|
|
298
|
+
"Writes up what ForgeQE's agent found, such as release status across projects, open defects, or pipeline health, as a Markdown file and an HTML page in the reports folder, with a summary in the chat and links to open them.",
|
|
299
|
+
tools: ["write_report"],
|
|
300
|
+
examples: ["Create a release report for all projects", "Write up the open defects as a report I can share"],
|
|
301
|
+
requires: [{ kind: "live_model" }],
|
|
302
|
+
limits: ["The report holds what the agent read with its tools in this request; it does not invent figures, and it does not publish the page anywhere unless the reports folder is served (notify.report_url)."],
|
|
303
|
+
docs: [{ doc: "HOW_TO_USE.md", heading: "Reports from the agent" }],
|
|
304
|
+
},
|
|
293
305
|
{
|
|
294
306
|
id: "pipelines",
|
|
295
307
|
area: "Operations",
|
|
@@ -56,7 +56,8 @@ export type CapabilityStatus = {
|
|
|
56
56
|
inputs: string[]
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
/** What `r` is missing in this setup, and how to fix it; null when it is met. */
|
|
60
|
+
export function requirementGap(r: Requirement, cfg: AppConfig, probes: Probes = MACHINE): Omit<Gap, "requirement" | "optional"> | null {
|
|
60
61
|
switch (r.kind) {
|
|
61
62
|
case "live_model":
|
|
62
63
|
return cfg.llm.provider === "none" || cfg.llm.provider === "mock"
|
|
@@ -89,7 +90,7 @@ function gap(r: Requirement, cfg: AppConfig, probes: Probes): Omit<Gap, "require
|
|
|
89
90
|
case "input":
|
|
90
91
|
return null
|
|
91
92
|
case "either": {
|
|
92
|
-
const gaps = r.of.map((alt) =>
|
|
93
|
+
const gaps = r.of.map((alt) => requirementGap(alt, cfg, probes))
|
|
93
94
|
if (gaps.some((g) => !g)) return null
|
|
94
95
|
return { missing: gaps.map((g) => g!.missing).join(", or "), fix: gaps.map((g) => g!.fix).join("; or ") }
|
|
95
96
|
}
|
|
@@ -99,7 +100,7 @@ function gap(r: Requirement, cfg: AppConfig, probes: Probes): Omit<Gap, "require
|
|
|
99
100
|
export function capabilityStatus(c: Capability, cfg: AppConfig, probes: Probes = MACHINE): CapabilityStatus {
|
|
100
101
|
const gaps: Gap[] = []
|
|
101
102
|
for (const r of c.requires) {
|
|
102
|
-
const g =
|
|
103
|
+
const g = requirementGap(r, cfg, probes)
|
|
103
104
|
if (g) gaps.push({ requirement: r, optional: Boolean("optional" in r && r.optional), ...g })
|
|
104
105
|
}
|
|
105
106
|
const state = gaps.some((g) => !g.optional) ? "needs_setup" : gaps.length ? "partial" : "ready"
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs"
|
|
2
|
+
import path from "node:path"
|
|
3
|
+
|
|
4
|
+
import type { McpTool } from "./tools.ts"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Reports the agent writes from what it found (release status, open defects, pipeline health): a Markdown file to
|
|
8
|
+
* edit or paste, and the same report as a page to open or share. The chat gets the summary and the links.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** "Release status: all projects" → "release-status-all-projects". */
|
|
12
|
+
export function reportSlug(title: string): string {
|
|
13
|
+
return (
|
|
14
|
+
title
|
|
15
|
+
.toLowerCase()
|
|
16
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
17
|
+
.slice(0, 40)
|
|
18
|
+
.replace(/^-+|-+$/g, "") || "report"
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const escapeHtml = (s: string) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """)
|
|
23
|
+
|
|
24
|
+
/** The report as a page: the Markdown rendered, with raw HTML in it shown as text so a report can never run script. */
|
|
25
|
+
export function reportHtml(title: string, markdown: string, written: Date): string {
|
|
26
|
+
const safe = markdown.replace(/<(?=[A-Za-z/!?])/g, "<")
|
|
27
|
+
const body = Bun.markdown.html(safe)
|
|
28
|
+
return `<!doctype html>
|
|
29
|
+
<html lang="en">
|
|
30
|
+
<head>
|
|
31
|
+
<meta charset="utf-8">
|
|
32
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
33
|
+
<title>${escapeHtml(title)}</title>
|
|
34
|
+
<style>
|
|
35
|
+
:root { --bg: #ffffff; --text: #1f2328; --muted: #59636e; --border: #d1d9e0; --accent: #0969da; --panel: #f6f8fa; }
|
|
36
|
+
@media (prefers-color-scheme: dark) { :root { --bg: #0d1117; --text: #e6edf3; --muted: #8b949e; --border: #30363d; --accent: #4ea1ff; --panel: #161b22; } }
|
|
37
|
+
* { box-sizing: border-box; }
|
|
38
|
+
body { margin: 0; background: var(--bg); color: var(--text); font: 15px/1.6 -apple-system, "Segoe UI", Roboto, sans-serif; }
|
|
39
|
+
main { max-width: 960px; margin: 0 auto; padding: 32px 16px 64px; }
|
|
40
|
+
header { border-bottom: 1px solid var(--border); padding-bottom: 12px; margin-bottom: 24px; }
|
|
41
|
+
header p { margin: 4px 0 0; color: var(--muted); font-size: 13px; }
|
|
42
|
+
h1 { font-size: 28px; line-height: 1.25; margin: 0; }
|
|
43
|
+
h2 { font-size: 20px; margin: 32px 0 8px; padding-bottom: 4px; border-bottom: 1px solid var(--border); }
|
|
44
|
+
h3 { font-size: 16px; margin: 24px 0 8px; }
|
|
45
|
+
a { color: var(--accent); }
|
|
46
|
+
code { background: var(--panel); border-radius: 4px; padding: 1px 4px; font-size: 13px; }
|
|
47
|
+
pre { background: var(--panel); border: 1px solid var(--border); border-radius: 6px; padding: 12px; overflow-x: auto; }
|
|
48
|
+
pre code { background: none; padding: 0; }
|
|
49
|
+
table { border-collapse: collapse; width: 100%; margin: 12px 0; display: block; overflow-x: auto; }
|
|
50
|
+
th, td { border: 1px solid var(--border); padding: 6px 10px; text-align: left; vertical-align: top; }
|
|
51
|
+
th { background: var(--panel); }
|
|
52
|
+
blockquote { margin: 12px 0; padding: 4px 12px; border-left: 4px solid var(--border); color: var(--muted); }
|
|
53
|
+
li { margin: 2px 0; }
|
|
54
|
+
</style>
|
|
55
|
+
</head>
|
|
56
|
+
<body>
|
|
57
|
+
<main>
|
|
58
|
+
<header>
|
|
59
|
+
<h1>${escapeHtml(title)}</h1>
|
|
60
|
+
<p>Written by ForgeQE on ${escapeHtml(written.toLocaleString())}</p>
|
|
61
|
+
</header>
|
|
62
|
+
${body}
|
|
63
|
+
</main>
|
|
64
|
+
</body>
|
|
65
|
+
</html>
|
|
66
|
+
`
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export const REPORT_TOOLS: McpTool[] = [
|
|
70
|
+
{
|
|
71
|
+
name: "write_report",
|
|
72
|
+
description:
|
|
73
|
+
'Save a report the user asks for ("create a release report", "write up the open defects", "give me a report I can share") as a Markdown file and an HTML page in the reports folder. Gather the facts with your other tools first, then pass the whole report as Markdown: a one-paragraph summary first, then ## sections, tables for per-item status (one row per project, case, or build), and links to builds, work items, and pull requests. Do not invent data you did not read. The user is shown the report paths as links, so reply with three to five lines of summary only: do not repeat the paths or paste the report.',
|
|
74
|
+
inputSchema: {
|
|
75
|
+
type: "object",
|
|
76
|
+
properties: {
|
|
77
|
+
title: { type: "string", description: "The report's title, e.g. Release status: all projects, 9 October 2026" },
|
|
78
|
+
markdown: { type: "string", description: "The report body in Markdown, without the title (it is added as the heading)" },
|
|
79
|
+
},
|
|
80
|
+
required: ["title", "markdown"],
|
|
81
|
+
},
|
|
82
|
+
async run(args, ctx) {
|
|
83
|
+
const title = String(args.title || "Report").trim()
|
|
84
|
+
const markdown = String(args.markdown || "").trim()
|
|
85
|
+
if (!markdown) throw new Error("The report is empty: pass its body as markdown.")
|
|
86
|
+
const written = new Date()
|
|
87
|
+
const stamp = written.toISOString().replace(/[-:]/g, "").replace("T", "-").slice(0, 15)
|
|
88
|
+
// Beside the run reports, so the shell links it and outDir publishing (notify.report_url) serves it too.
|
|
89
|
+
const dir = path.resolve(ctx.config.export.outDir, `${reportSlug(title)}-${stamp}`)
|
|
90
|
+
mkdirSync(dir, { recursive: true })
|
|
91
|
+
const md = path.join(dir, "report.md")
|
|
92
|
+
const html = path.join(dir, "report.html")
|
|
93
|
+
writeFileSync(md, `# ${title}\n\n${markdown}\n`)
|
|
94
|
+
writeFileSync(html, reportHtml(title, markdown, written))
|
|
95
|
+
const show = (p: string) => path.relative(process.cwd(), p) || p
|
|
96
|
+
ctx.emit?.({ type: "report", title, html, markdown: md })
|
|
97
|
+
ctx.emit?.({ type: "card", card: { status: "ok", title: `Report: ${title}`, body: [`Page ${show(html)}`, `Markdown ${show(md)}`] } })
|
|
98
|
+
return { html: show(html), markdown: show(md) }
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
]
|
package/src/mcp/tools.ts
CHANGED
|
@@ -29,6 +29,7 @@ import { EXPLORE_TOOLS } from "./exploretools.ts"
|
|
|
29
29
|
import { QUALITY_TOOLS } from "./qualitytools.ts"
|
|
30
30
|
import { CAPABILITY_TOOLS } from "./captools.ts"
|
|
31
31
|
import { NOTIFY_TOOLS } from "./notifytools.ts"
|
|
32
|
+
import { REPORT_TOOLS } from "./reporttools.ts"
|
|
32
33
|
import { capabilityIndex } from "../capabilities/render.ts"
|
|
33
34
|
import { domainNotes } from "../domain.ts"
|
|
34
35
|
import { readNetwork } from "../api/traffic.ts"
|
|
@@ -95,6 +96,8 @@ export type ToolEvent =
|
|
|
95
96
|
| { type: "code-done"; result?: CodeResult; error?: string; ms: number }
|
|
96
97
|
/** A tool's result to show as a panel (a test written, tests healed, a monitoring round). */
|
|
97
98
|
| { type: "card"; card: Card }
|
|
99
|
+
/** write_report saved a report: its page and its Markdown. */
|
|
100
|
+
| { type: "report"; title: string; html: string; markdown: string }
|
|
98
101
|
|
|
99
102
|
export type ToolContext = {
|
|
100
103
|
config: AppConfig
|
|
@@ -722,6 +725,7 @@ export const TOOLS: McpTool[] = [
|
|
|
722
725
|
...QUALITY_TOOLS,
|
|
723
726
|
...CAPABILITY_TOOLS,
|
|
724
727
|
...NOTIFY_TOOLS,
|
|
728
|
+
...REPORT_TOOLS,
|
|
725
729
|
]
|
|
726
730
|
|
|
727
731
|
/** The setup the agent should know about: where it works, which systems are configured, and the defaults. */
|