@sentry/warden 0.35.1 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/dist/cli/args.d.ts +12 -0
  2. package/dist/cli/args.d.ts.map +1 -1
  3. package/dist/cli/args.js +14 -0
  4. package/dist/cli/args.js.map +1 -1
  5. package/dist/cli/commands/init.js +2 -2
  6. package/dist/cli/commands/init.js.map +1 -1
  7. package/dist/cli/help.d.ts.map +1 -1
  8. package/dist/cli/help.js +16 -0
  9. package/dist/cli/help.js.map +1 -1
  10. package/dist/cli/main.d.ts +4 -2
  11. package/dist/cli/main.d.ts.map +1 -1
  12. package/dist/cli/main.js +34 -13
  13. package/dist/cli/main.js.map +1 -1
  14. package/dist/cli/output/jsonl-schema-gen.d.ts.map +1 -1
  15. package/dist/cli/output/jsonl-schema-gen.js +3 -1
  16. package/dist/cli/output/jsonl-schema-gen.js.map +1 -1
  17. package/dist/cli/output/jsonl.d.ts +54 -0
  18. package/dist/cli/output/jsonl.d.ts.map +1 -1
  19. package/dist/cli/output/jsonl.js +6 -1
  20. package/dist/cli/output/jsonl.js.map +1 -1
  21. package/dist/cli/output/tasks.d.ts.map +1 -1
  22. package/dist/cli/output/tasks.js +7 -0
  23. package/dist/cli/output/tasks.js.map +1 -1
  24. package/dist/config/loader.d.ts +2 -2
  25. package/dist/config/loader.d.ts.map +1 -1
  26. package/dist/config/loader.js +3 -3
  27. package/dist/config/loader.js.map +1 -1
  28. package/dist/config/schema.d.ts +5 -5
  29. package/dist/config/schema.d.ts.map +1 -1
  30. package/dist/config/schema.js +3 -3
  31. package/dist/config/schema.js.map +1 -1
  32. package/dist/index.d.ts +4 -4
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +2 -2
  35. package/dist/index.js.map +1 -1
  36. package/dist/sdk/analyze.d.ts.map +1 -1
  37. package/dist/sdk/analyze.js +139 -10
  38. package/dist/sdk/analyze.js.map +1 -1
  39. package/dist/sdk/auth.d.ts +5 -4
  40. package/dist/sdk/auth.d.ts.map +1 -1
  41. package/dist/sdk/auth.js +9 -7
  42. package/dist/sdk/auth.js.map +1 -1
  43. package/dist/sdk/circuit-breaker.js +3 -3
  44. package/dist/sdk/circuit-breaker.js.map +1 -1
  45. package/dist/sdk/errors.d.ts +8 -0
  46. package/dist/sdk/errors.d.ts.map +1 -1
  47. package/dist/sdk/errors.js +44 -1
  48. package/dist/sdk/errors.js.map +1 -1
  49. package/dist/sdk/haiku.d.ts.map +1 -1
  50. package/dist/sdk/haiku.js +21 -12
  51. package/dist/sdk/haiku.js.map +1 -1
  52. package/dist/sdk/otel.d.ts +15 -0
  53. package/dist/sdk/otel.d.ts.map +1 -1
  54. package/dist/sdk/otel.js +50 -6
  55. package/dist/sdk/otel.js.map +1 -1
  56. package/dist/sdk/post-process.d.ts +2 -2
  57. package/dist/sdk/post-process.d.ts.map +1 -1
  58. package/dist/sdk/post-process.js +1 -1
  59. package/dist/sdk/post-process.js.map +1 -1
  60. package/dist/sdk/runtimes/claude.d.ts.map +1 -1
  61. package/dist/sdk/runtimes/claude.js +45 -35
  62. package/dist/sdk/runtimes/claude.js.map +1 -1
  63. package/dist/sdk/runtimes/pi.d.ts.map +1 -1
  64. package/dist/sdk/runtimes/pi.js +90 -6
  65. package/dist/sdk/runtimes/pi.js.map +1 -1
  66. package/dist/sdk/runtimes/types.d.ts +2 -2
  67. package/dist/sdk/runtimes/types.d.ts.map +1 -1
  68. package/dist/sdk/types.d.ts +12 -4
  69. package/dist/sdk/types.d.ts.map +1 -1
  70. package/dist/sdk/verify.d.ts +2 -2
  71. package/dist/sdk/verify.d.ts.map +1 -1
  72. package/dist/sdk/verify.js +1 -1
  73. package/dist/sdk/verify.js.map +1 -1
  74. package/dist/sentry-trace.d.ts +29 -0
  75. package/dist/sentry-trace.d.ts.map +1 -0
  76. package/dist/sentry-trace.js +154 -0
  77. package/dist/sentry-trace.js.map +1 -0
  78. package/dist/sentry.d.ts.map +1 -1
  79. package/dist/sentry.js +56 -0
  80. package/dist/sentry.js.map +1 -1
  81. package/dist/types/index.d.ts +72 -0
  82. package/dist/types/index.d.ts.map +1 -1
  83. package/dist/types/index.js +37 -0
  84. package/dist/types/index.js.map +1 -1
  85. package/package.json +1 -1
  86. package/skills/warden/SKILL.md +0 -76
  87. package/skills/warden/SOURCES.md +0 -39
  88. package/skills/warden/SPEC.md +0 -112
  89. package/skills/warden/references/cli-reference.md +0 -149
  90. package/skills/warden/references/config-schema.md +0 -141
  91. package/skills/warden/references/configuration.md +0 -143
  92. package/skills/warden/references/creating-skills.md +0 -87
  93. package/skills/warden-sweep/SKILL.md +0 -78
  94. package/skills/warden-sweep/SOURCES.md +0 -43
  95. package/skills/warden-sweep/SPEC.md +0 -126
  96. package/skills/warden-sweep/references/issue-phase.md +0 -24
  97. package/skills/warden-sweep/references/organize-phase.md +0 -31
  98. package/skills/warden-sweep/references/patch-phase.md +0 -142
  99. package/skills/warden-sweep/references/patch-prompt.md +0 -72
  100. package/skills/warden-sweep/references/resume-and-artifacts.md +0 -51
  101. package/skills/warden-sweep/references/scan-phase.md +0 -46
  102. package/skills/warden-sweep/references/script-interfaces.md +0 -127
  103. package/skills/warden-sweep/references/verify-phase.md +0 -69
  104. package/skills/warden-sweep/references/verify-prompt.md +0 -25
  105. package/skills/warden-sweep/scripts/_utils.py +0 -99
  106. package/skills/warden-sweep/scripts/create_issue.py +0 -189
  107. package/skills/warden-sweep/scripts/extract_findings.py +0 -219
  108. package/skills/warden-sweep/scripts/find_reviewers.py +0 -114
  109. package/skills/warden-sweep/scripts/generate_report.py +0 -266
  110. package/skills/warden-sweep/scripts/index_prs.py +0 -187
  111. package/skills/warden-sweep/scripts/organize.py +0 -422
  112. package/skills/warden-sweep/scripts/scan.py +0 -584
@@ -1,127 +0,0 @@
1
- # Script Interfaces
2
-
3
- Use this reference before running Warden Sweep scripts. Run scripts from the repository root and pass the host skill-root path.
4
-
5
- ## Contents
6
-
7
- - `scan.py`
8
- - `index_prs.py`
9
- - `create_issue.py`
10
- - `organize.py`
11
- - `extract_findings.py`
12
- - `generate_report.py`
13
- - `find_reviewers.py`
14
-
15
- ## `scripts/scan.py`
16
-
17
- Runs setup and scan in one call: generates a run ID, creates the sweep directory, checks dependencies, creates the `warden` label, enumerates files, runs Warden per file, writes `scan-index.jsonl`, and extracts findings.
18
-
19
- ```bash
20
- uv run <skill-root>/scripts/scan.py [file ...]
21
- uv run <skill-root>/scripts/scan.py --sweep-dir .warden/sweeps/<run-id>
22
- ```
23
-
24
- Stdout JSON:
25
-
26
- ```json
27
- {
28
- "runId": "abc123",
29
- "sweepDir": ".warden/sweeps/abc123",
30
- "filesScanned": 10,
31
- "filesTimedOut": 0,
32
- "filesErrored": 0,
33
- "totalFindings": 3,
34
- "findings": []
35
- }
36
- ```
37
-
38
- Exit codes: `0` success, `1` fatal error, `2` partial scan.
39
-
40
- ## `scripts/index_prs.py`
41
-
42
- Fetches open Warden-labeled PRs, builds a file-to-PR dedup index, and caches diffs for overlapping PRs.
43
-
44
- ```bash
45
- uv run <skill-root>/scripts/index_prs.py <sweep-dir>
46
- ```
47
-
48
- Stdout JSON includes `fileIndex`. Side effects:
49
-
50
- - writes `data/existing-prs.json`
51
- - writes `data/pr-diffs/<number>.diff` for overlapping PRs
52
-
53
- ## `scripts/create_issue.py`
54
-
55
- Creates a GitHub tracking issue summarizing verified sweep results.
56
-
57
- ```bash
58
- uv run <skill-root>/scripts/create_issue.py <sweep-dir>
59
- ```
60
-
61
- Stdout JSON:
62
-
63
- ```json
64
- {
65
- "issueUrl": "https://github.com/owner/repo/issues/123",
66
- "issueNumber": 123
67
- }
68
- ```
69
-
70
- Idempotent: skips creation when `issueUrl` already exists in the manifest.
71
-
72
- ## `scripts/organize.py`
73
-
74
- Tags security findings, labels security PRs, updates finding reports with PR links, posts final results to the tracking issue, generates the summary report, and finalizes the manifest.
75
-
76
- ```bash
77
- uv run <skill-root>/scripts/organize.py <sweep-dir>
78
- ```
79
-
80
- Stdout JSON includes final sweep counts and report paths. Side effects:
81
-
82
- - creates `security/index.jsonl`
83
- - copies security finding reports to `security/`
84
- - creates or reuses the `security` GitHub label
85
- - labels security PRs
86
- - appends PR links to `findings/*.md`
87
- - writes `summary.md` and `data/report.json`
88
- - updates `phases.organize` in `data/manifest.json`
89
-
90
- ## `scripts/extract_findings.py`
91
-
92
- Parses Warden JSONL log files and extracts normalized findings. Usually called by `scan.py`.
93
-
94
- ```bash
95
- uv run <skill-root>/scripts/extract_findings.py <log-path-or-directory> -o <output.jsonl>
96
- ```
97
-
98
- Writes one normalized finding per line to `<output.jsonl>`.
99
-
100
- ## `scripts/generate_report.py`
101
-
102
- Builds `summary.md` and `report.json` from sweep data. Usually called by `organize.py`.
103
-
104
- ```bash
105
- uv run <skill-root>/scripts/generate_report.py <sweep-dir>
106
- ```
107
-
108
- Side effects:
109
-
110
- - writes `<sweep-dir>/summary.md`
111
- - writes `<sweep-dir>/data/report.json`
112
-
113
- ## `scripts/find_reviewers.py`
114
-
115
- Finds the top two git contributors for a file from the last 12 months.
116
-
117
- ```bash
118
- uv run <skill-root>/scripts/find_reviewers.py <file-path>
119
- ```
120
-
121
- Stdout JSON:
122
-
123
- ```json
124
- {
125
- "reviewers": ["user1", "user2"]
126
- }
127
- ```
@@ -1,69 +0,0 @@
1
- # Verify Phase
2
-
3
- Deep-trace every finding before patching. This phase qualifies true issues and rejects false positives.
4
-
5
- ## Input
6
-
7
- Read findings from:
8
-
9
- ```text
10
- <sweep-dir>/data/all-findings.jsonl
11
- ```
12
-
13
- ## Process
14
-
15
- For each finding:
16
-
17
- 1. If `data/verify/<finding-id>.json` exists, skip it.
18
- 2. Launch verification work using the host agent's task/delegation mechanism when available. Process findings in parallel batches up to 8 if the host supports parallel work.
19
- 3. Read `references/verify-prompt.md` and substitute the finding values into the `${...}` placeholders.
20
- 4. Parse the returned JSON.
21
- 5. Write the raw result to `data/verify/<finding-id>.json`.
22
- 6. Append verified findings to `data/verified.jsonl`.
23
- 7. Append rejected findings to `data/rejected.jsonl`.
24
- 8. For verified findings, generate `findings/<finding-id>.md`.
25
-
26
- If the host does not support delegated tasks, run the same verification prompt serially.
27
-
28
- ## Verified Finding Report
29
-
30
- ````markdown
31
- # ${TITLE}
32
-
33
- **ID**: ${FINDING_ID} | **Severity**: ${SEVERITY} | **Confidence**: ${CONFIDENCE}
34
- **Skill**: ${SKILL} | **File**: ${FILE_PATH}:${START_LINE}
35
-
36
- ## Description
37
- ${DESCRIPTION}
38
-
39
- ## Verification
40
- **Verdict**: Verified (${VERIFICATION_CONFIDENCE})
41
- **Reasoning**: ${REASONING}
42
- **Code trace**: ${TRACE_NOTES}
43
-
44
- ## Suggested Fix
45
- ${FIX_DESCRIPTION}
46
- ```diff
47
- ${FIX_DIFF}
48
- ```
49
- ````
50
-
51
- Update the manifest: set `phases.verify` to `"complete"`.
52
-
53
- ## Report Template
54
-
55
- ```markdown
56
- ## Verification Complete
57
-
58
- **{verified}** verified, **{rejected}** rejected.
59
-
60
- ### Verified Findings
61
-
62
- | # | Severity | Confidence | File | Title | Reasoning |
63
- |---|----------|------------|------|-------|-----------|
64
- | 1 | **HIGH** | high | `src/db/query.ts:42` | SQL injection in query builder | User input flows directly into... |
65
-
66
- ### Rejected ({rejected_count})
67
-
68
- - `{findingId}` {file}: {reasoning}
69
- ```
@@ -1,25 +0,0 @@
1
- Verify a code analysis finding. Determine if this is a TRUE issue or a FALSE POSITIVE.
2
- Do NOT write or edit any files. Research only.
3
-
4
- ## Finding
5
- - Title: ${TITLE}
6
- - Severity: ${SEVERITY} | Confidence: ${CONFIDENCE}
7
- - Skill: ${SKILL}
8
- - Location: ${FILE_PATH}:${START_LINE}-${END_LINE}
9
- - Description: ${DESCRIPTION}
10
- - Verification hint: ${VERIFICATION}
11
-
12
- ## Instructions
13
- 1. Read the file at the reported location. Examine at least 50 lines of surrounding context.
14
- 2. Trace data flow to/from the flagged code using Grep/Glob.
15
- 3. Check if the issue is mitigated elsewhere (guards, validation, try/catch upstream).
16
- 4. Check if the issue is actually reachable in practice.
17
-
18
- Return your verdict as JSON:
19
- {
20
- "findingId": "${FINDING_ID}",
21
- "verdict": "verified" or "rejected",
22
- "confidence": "high" or "medium" or "low",
23
- "reasoning": "2-3 sentence explanation",
24
- "traceNotes": "What code paths you examined"
25
- }
@@ -1,99 +0,0 @@
1
- """Shared utilities for warden-sweep scripts."""
2
- from __future__ import annotations
3
-
4
- import json
5
- import os
6
- import subprocess
7
- from typing import Any
8
-
9
-
10
- def run_cmd(
11
- args: list[str], timeout: int = 30, cwd: str | None = None
12
- ) -> subprocess.CompletedProcess[str]:
13
- """Run a command and return the result."""
14
- return subprocess.run(
15
- args,
16
- capture_output=True,
17
- text=True,
18
- timeout=timeout,
19
- cwd=cwd,
20
- )
21
-
22
-
23
- def run_cmd_stdout(
24
- args: list[str], timeout: int = 30, cwd: str | None = None
25
- ) -> str | None:
26
- """Run a command and return stripped stdout, or None on failure."""
27
- try:
28
- result = run_cmd(args, timeout=timeout, cwd=cwd)
29
- return result.stdout.strip() if result.returncode == 0 else None
30
- except (subprocess.TimeoutExpired, FileNotFoundError):
31
- return None
32
-
33
-
34
- def read_json(path: str) -> dict[str, Any] | None:
35
- """Read a JSON file and return parsed object, or None on failure."""
36
- if not os.path.exists(path):
37
- return None
38
- try:
39
- with open(path) as f:
40
- return json.load(f)
41
- except (json.JSONDecodeError, OSError):
42
- return None
43
-
44
-
45
- def write_json(path: str, data: dict[str, Any]) -> None:
46
- """Write a dict to a JSON file with trailing newline."""
47
- with open(path, "w") as f:
48
- json.dump(data, f, indent=2)
49
- f.write("\n")
50
-
51
-
52
- def read_jsonl(path: str) -> list[dict[str, Any]]:
53
- """Read a JSONL file and return list of parsed objects."""
54
- entries: list[dict[str, Any]] = []
55
- if not os.path.exists(path):
56
- return entries
57
- with open(path) as f:
58
- for line in f:
59
- line = line.strip()
60
- if not line:
61
- continue
62
- try:
63
- entries.append(json.loads(line))
64
- except json.JSONDecodeError:
65
- continue
66
- return entries
67
-
68
-
69
- def severity_badge(severity: str) -> str:
70
- """Return a markdown-friendly severity indicator."""
71
- badges = {
72
- "critical": "**CRITICAL**",
73
- "high": "**HIGH**",
74
- "medium": "MEDIUM",
75
- "low": "LOW",
76
- "info": "info",
77
- }
78
- return badges.get(severity, severity)
79
-
80
-
81
- def pr_number_from_url(pr_url: str) -> str:
82
- """Extract the PR or issue number from a GitHub URL's last path segment."""
83
- return pr_url.rstrip("/").split("/")[-1]
84
-
85
-
86
- def ensure_github_label(name: str, color: str, description: str) -> None:
87
- """Create a GitHub label if it doesn't exist (idempotent)."""
88
- try:
89
- subprocess.run(
90
- [
91
- "gh", "label", "create", name,
92
- "--color", color,
93
- "--description", description,
94
- ],
95
- capture_output=True,
96
- timeout=15,
97
- )
98
- except (subprocess.TimeoutExpired, FileNotFoundError):
99
- pass
@@ -1,189 +0,0 @@
1
- #!/usr/bin/env python3
2
- # /// script
3
- # requires-python = ">=3.9"
4
- # ///
5
- """
6
- Warden Sweep: Create tracking issue.
7
-
8
- Creates a GitHub issue summarizing the sweep results after verification
9
- but before patching. Gives every PR a parent to reference and gives
10
- reviewers a single place to see the full picture.
11
-
12
- Usage:
13
- uv run create_issue.py <sweep-dir>
14
-
15
- Stdout: JSON with issueUrl and issueNumber
16
- Stderr: Progress lines
17
-
18
- Idempotent: if issueUrl already exists in manifest, skips creation.
19
- """
20
- from __future__ import annotations
21
-
22
- import argparse
23
- import json
24
- import os
25
- import subprocess
26
- import sys
27
- from typing import Any
28
-
29
- sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
30
- from _utils import ( # noqa: E402
31
- ensure_github_label,
32
- pr_number_from_url,
33
- read_json,
34
- read_jsonl,
35
- severity_badge,
36
- write_json,
37
- )
38
-
39
-
40
- def build_issue_body(
41
- run_id: str,
42
- scan_index: list[dict[str, Any]],
43
- all_findings: list[dict[str, Any]],
44
- verified: list[dict[str, Any]],
45
- rejected: list[dict[str, Any]],
46
- ) -> str:
47
- """Build the GitHub issue body markdown."""
48
- files_scanned = sum(1 for e in scan_index if e.get("status") == "complete")
49
- files_timed_out = sum(
50
- 1 for e in scan_index
51
- if e.get("status") == "error" and e.get("error") == "timeout"
52
- )
53
- files_errored = sum(
54
- 1 for e in scan_index
55
- if e.get("status") == "error" and e.get("error") != "timeout"
56
- )
57
-
58
- # Collect unique skills from scan index
59
- skills: set[str] = set()
60
- for entry in scan_index:
61
- for skill in entry.get("skills", []):
62
- skills.add(skill)
63
-
64
- lines = [
65
- f"## Warden Sweep `{run_id}`",
66
- "",
67
- "| Metric | Count |",
68
- "|--------|-------|",
69
- f"| Files scanned | {files_scanned} |",
70
- f"| Files timed out | {files_timed_out} |",
71
- f"| Files errored | {files_errored} |",
72
- f"| Total findings | {len(all_findings)} |",
73
- f"| Verified | {len(verified)} |",
74
- f"| Rejected | {len(rejected)} |",
75
- "",
76
- ]
77
-
78
- if verified:
79
- lines.append("### Verified Findings")
80
- lines.append("")
81
- lines.append("| Severity | Skill | File | Title |")
82
- lines.append("|----------|-------|------|-------|")
83
- for f in verified:
84
- sev = severity_badge(f.get("severity", "info"))
85
- skill = f.get("skill", "")
86
- file_path = f.get("file", "")
87
- start_line = f.get("startLine")
88
- location = f"{file_path}:{start_line}" if start_line else file_path
89
- title = f.get("title", "")
90
- lines.append(f"| {sev} | {skill} | `{location}` | {title} |")
91
- lines.append("")
92
-
93
- if skills:
94
- lines.append("### Skills Run")
95
- lines.append("")
96
- lines.append(", ".join(sorted(skills)))
97
- lines.append("")
98
-
99
- lines.append("> Generated by Warden Sweep. PRs referencing this issue will appear below.")
100
-
101
- return "\n".join(lines) + "\n"
102
-
103
-
104
- def create_github_issue(title: str, body: str) -> dict[str, Any]:
105
- """Create a GitHub issue with the warden label. Returns issueUrl and issueNumber."""
106
- ensure_github_label("warden", "5319E7", "Automated fix from Warden Sweep")
107
-
108
- result = subprocess.run(
109
- [
110
- "gh", "issue", "create",
111
- "--label", "warden",
112
- "--title", title,
113
- "--body", body,
114
- ],
115
- capture_output=True,
116
- text=True,
117
- timeout=30,
118
- )
119
-
120
- if result.returncode != 0:
121
- raise RuntimeError(f"gh issue create failed: {result.stderr.strip()}")
122
-
123
- issue_url = result.stdout.strip()
124
- try:
125
- issue_number = int(pr_number_from_url(issue_url))
126
- except (ValueError, IndexError):
127
- raise RuntimeError(f"Could not parse issue number from gh output: {issue_url}")
128
-
129
- return {"issueUrl": issue_url, "issueNumber": issue_number}
130
-
131
-
132
- def main() -> None:
133
- parser = argparse.ArgumentParser(
134
- description="Warden Sweep: Create tracking issue"
135
- )
136
- parser.add_argument("sweep_dir", help="Path to the sweep directory")
137
- args = parser.parse_args()
138
-
139
- sweep_dir = args.sweep_dir
140
- data_dir = os.path.join(sweep_dir, "data")
141
- manifest_path = os.path.join(data_dir, "manifest.json")
142
-
143
- if not os.path.isdir(sweep_dir):
144
- print(
145
- json.dumps({"error": f"Sweep directory not found: {sweep_dir}"}),
146
- file=sys.stdout,
147
- )
148
- sys.exit(1)
149
-
150
- manifest = read_json(manifest_path) or {}
151
-
152
- # Idempotency: if issue already exists, return existing values
153
- if manifest.get("issueUrl"):
154
- output = {
155
- "issueUrl": manifest["issueUrl"],
156
- "issueNumber": manifest.get("issueNumber", 0),
157
- }
158
- print(json.dumps(output))
159
- return
160
-
161
- run_id = manifest.get("runId", "unknown")
162
-
163
- # Read sweep data
164
- scan_index = read_jsonl(os.path.join(data_dir, "scan-index.jsonl"))
165
- all_findings = read_jsonl(os.path.join(data_dir, "all-findings.jsonl"))
166
- verified = read_jsonl(os.path.join(data_dir, "verified.jsonl"))
167
- rejected = read_jsonl(os.path.join(data_dir, "rejected.jsonl"))
168
-
169
- files_scanned = sum(1 for e in scan_index if e.get("status") == "complete")
170
-
171
- # Build issue
172
- title = f"Warden Sweep {run_id}: {len(verified)} findings across {files_scanned} files"
173
- body = build_issue_body(run_id, scan_index, all_findings, verified, rejected)
174
-
175
- print("Creating tracking issue...", file=sys.stderr)
176
- result = create_github_issue(title, body)
177
- print(f"Created issue: {result['issueUrl']}", file=sys.stderr)
178
-
179
- # Write issueUrl and issueNumber to manifest
180
- manifest["issueUrl"] = result["issueUrl"]
181
- manifest["issueNumber"] = result["issueNumber"]
182
- manifest.setdefault("phases", {})["issue"] = "complete"
183
- write_json(manifest_path, manifest)
184
-
185
- print(json.dumps(result))
186
-
187
-
188
- if __name__ == "__main__":
189
- main()