mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-27 09:21:35 +07:00
polish report drafting guidance
This commit is contained in:
@@ -46,6 +46,7 @@ Use this skill only for `openclaw/openclaw`.
|
||||
- Show the full sanitized draft before asking to submit.
|
||||
- Ask permission in plain English before adding `--submit`.
|
||||
- Only after approval, use `--submit` for public bug or feature issues.
|
||||
- If submission succeeds, include the created GitHub issue URL in the final reply to the user.
|
||||
|
||||
## Do Not
|
||||
|
||||
@@ -99,7 +100,8 @@ Use this skill only for `openclaw/openclaw`.
|
||||
10. After showing the draft, ask in plain English: `If this draft looks right, I can submit it to GitHub now.`
|
||||
11. Do not mention CLI flags like `--submit` in the user-facing approval question.
|
||||
12. Only if the user clearly approves, rerun or continue with `--submit` for public bug or feature issues.
|
||||
13. For security, keep the report private and route the user to `security@openclaw.ai`.
|
||||
13. If the issue is created successfully, include the created GitHub URL in the final reply.
|
||||
14. For security, keep the report private and route the user to `security@openclaw.ai`.
|
||||
|
||||
## Common Commands
|
||||
|
||||
@@ -131,6 +133,8 @@ Use `--additional-information` for details that do not fit neatly into `--repro`
|
||||
|
||||
Prefer deriving these from the conversation when they are already clear instead of asking the user to restate them.
|
||||
|
||||
When passing multiline text into the CLI as a single quoted argument, encode line breaks as literal `\n` so `openclaw report` can render them back as real line breaks in the final issue body.
|
||||
|
||||
## Private Security Reports
|
||||
|
||||
If the request is a security issue:
|
||||
@@ -179,7 +183,7 @@ I need a few bug-report details: what steps reproduce it, what you expected, wha
|
||||
If those fields are not already clear from the diagnosis session, ask for them. Otherwise infer them and run:
|
||||
|
||||
```bash
|
||||
openclaw report bug --summary "Gateway times out behind mitmproxy" --repro "..." --expected "..." --actual "..." --impact "..." --probe gateway
|
||||
openclaw report bug --summary "Gateway times out behind mitmproxy" --repro "1. Start gateway\n2. Send request\n3. Observe timeout" --expected "..." --actual "..." --impact "..." --probe gateway
|
||||
```
|
||||
|
||||
Then show the draft itself, not internal report metadata. Only add `--submit` after explicit approval.
|
||||
@@ -190,6 +194,8 @@ After showing the draft, ask:
|
||||
If this draft looks right, I can submit it to GitHub now.
|
||||
```
|
||||
|
||||
If submission succeeds, include the created issue URL in the final reply.
|
||||
|
||||
### Example: regression bug with loose extra context
|
||||
|
||||
User says: `This worked last week, but after updating it started timing out.`
|
||||
@@ -206,7 +212,7 @@ I need the repro steps, expected behavior, actual behavior, and impact. I can al
|
||||
If the missing facts are not already clear from the conversation or diagnosis session, ask for them. Otherwise infer them and run:
|
||||
|
||||
```bash
|
||||
openclaw report bug --summary "Regression after update" --repro "..." --expected "..." --actual "..." --impact "..." --previous-version "2026.3.14" --additional-information "Worked last week; now every call times out behind the same proxy setup." --probe model
|
||||
openclaw report bug --summary "Regression after update" --repro "1. Start gateway\n2. Send request\n3. Observe failure" --expected "..." --actual "..." --impact "..." --previous-version "2026.3.14" --additional-information "Worked last week; now every call times out behind the same proxy setup." --probe model
|
||||
```
|
||||
|
||||
Then show the draft and ask:
|
||||
@@ -215,6 +221,8 @@ Then show the draft and ask:
|
||||
If this draft looks right, I can submit it to GitHub now.
|
||||
```
|
||||
|
||||
If submission succeeds, include the created issue URL in the final reply.
|
||||
|
||||
### Example: feature request
|
||||
|
||||
User says: `Please add a way to export a report draft without submitting it.`
|
||||
@@ -231,6 +239,8 @@ Then show the draft and ask:
|
||||
If this draft looks right, I can submit it to GitHub now.
|
||||
```
|
||||
|
||||
If submission succeeds, include the created issue URL in the final reply.
|
||||
|
||||
### Example: private security report
|
||||
|
||||
User says: `I found a token leak in logs.`
|
||||
|
||||
@@ -202,6 +202,22 @@ describe("reportCommand", () => {
|
||||
expect(payload.submissionEligible).toBe(false);
|
||||
});
|
||||
|
||||
it("renders literal escaped newline sequences as real line breaks in report sections", async () => {
|
||||
const payload = await buildReportPayload({
|
||||
kind: "bug",
|
||||
options: {
|
||||
summary: "Gateway timeout",
|
||||
repro: "1. Start gateway\\n2. Send request\\n3. Observe failure",
|
||||
expected: "Model responds",
|
||||
actual: "Timeout",
|
||||
impact: "Blocks requests",
|
||||
},
|
||||
});
|
||||
|
||||
expect(payload.body).toContain("1. Start gateway\n2. Send request\n3. Observe failure");
|
||||
expect(payload.body).not.toContain("\\n2. Send request");
|
||||
});
|
||||
|
||||
it("writes markdown output that matches the generated body", async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-report-test-"));
|
||||
const outputPath = path.join(tmpDir, "bug.md");
|
||||
@@ -446,6 +462,25 @@ describe("reportCommand", () => {
|
||||
expect(payload.submission.url).toBe("https://github.com/openclaw/openclaw/issues/999");
|
||||
});
|
||||
|
||||
it("prints the created issue url in human output after successful submission", async () => {
|
||||
await reportCommand({
|
||||
kind: "bug",
|
||||
options: {
|
||||
summary: "Gateway timeout",
|
||||
repro: "1. Start gateway",
|
||||
expected: "Model responds",
|
||||
actual: "Timeout",
|
||||
impact: "Blocks requests",
|
||||
submit: true,
|
||||
yes: true,
|
||||
nonInteractive: true,
|
||||
},
|
||||
runtime,
|
||||
});
|
||||
|
||||
expect(runtime.log).toHaveBeenCalledWith("Created: https://github.com/openclaw/openclaw/issues/999");
|
||||
});
|
||||
|
||||
it("keeps draft generation working when config and secret resolution degrade", async () => {
|
||||
readBestEffortConfig.mockRejectedValueOnce(new Error("config missing"));
|
||||
resolveCommandSecretRefsViaGateway.mockRejectedValueOnce(new Error("secret refs unavailable"));
|
||||
|
||||
@@ -137,8 +137,15 @@ export type ReportPayload = {
|
||||
const PUBLIC_REPO = "openclaw/openclaw";
|
||||
const REPORT_GENERATED_NOTE = "_Generated via `openclaw report`._";
|
||||
|
||||
function normalizeEscapedMultilineText(value: string | undefined): string | undefined {
|
||||
if (value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
return value.replace(/\\r\\n/g, "\n").replace(/\\n/g, "\n").replace(/\r\n/g, "\n");
|
||||
}
|
||||
|
||||
function sanitizeWhitespace(value: string | undefined): string | undefined {
|
||||
const trimmed = value?.trim();
|
||||
const trimmed = normalizeEscapedMultilineText(value)?.trim();
|
||||
return trimmed ? trimmed : undefined;
|
||||
}
|
||||
|
||||
@@ -165,8 +172,9 @@ export function sanitizeReportText(value: string | undefined): {
|
||||
if (!value) {
|
||||
return { text: "", redactionsApplied: [] };
|
||||
}
|
||||
const redactions = detectRedactions(value);
|
||||
let text = redactSecrets(value);
|
||||
const normalized = normalizeEscapedMultilineText(value) ?? "";
|
||||
const redactions = detectRedactions(normalized);
|
||||
let text = redactSecrets(normalized);
|
||||
text = text.replace(/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, "[email-redacted]");
|
||||
text = text.replace(/\b(?:\+?1[-.\s]?)?(?:\(?\d{3}\)?[-.\s]?){2}\d{4}\b/g, "[phone-redacted]");
|
||||
text = text.replace(/\/Users\/[^/\s]+/g, "/Users/user");
|
||||
|
||||
Reference in New Issue
Block a user