tau-coding-agent 0.1.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.
- package/LICENSE +21 -0
- package/README.md +42 -0
- package/extensions/answer.ts +601 -0
- package/extensions/branch-term.ts +405 -0
- package/extensions/btw.ts +444 -0
- package/extensions/ghostty.ts +301 -0
- package/extensions/git-diff-stats.ts +277 -0
- package/extensions/git-pr-status.ts +286 -0
- package/extensions/insights.ts +2367 -0
- package/extensions/interlude.ts +144 -0
- package/extensions/loop.ts +529 -0
- package/extensions/memory.ts +1889 -0
- package/extensions/notify.ts +161 -0
- package/extensions/openai-fast.ts +227 -0
- package/extensions/openai-verbosity.ts +223 -0
- package/extensions/review.ts +4347 -0
- package/extensions/sandbox/index.ts +2578 -0
- package/extensions/usage/anthropic.ts +198 -0
- package/extensions/usage/github-copilot.ts +204 -0
- package/extensions/usage/google-gemini-cli.ts +232 -0
- package/extensions/usage/index.ts +2310 -0
- package/extensions/usage/minimax.ts +208 -0
- package/extensions/usage/openai-codex.ts +180 -0
- package/extensions/usage/openrouter.ts +168 -0
- package/extensions/usage/providers.ts +26 -0
- package/extensions/usage/shared.ts +156 -0
- package/extensions/usage/types.ts +53 -0
- package/extensions/usage/zai.ts +186 -0
- package/extensions/websearch/README.md +68 -0
- package/extensions/websearch/browser/chromium.ts +330 -0
- package/extensions/websearch/browser/discovery.ts +75 -0
- package/extensions/websearch/browser/firefox.ts +150 -0
- package/extensions/websearch/browser/sqlite.ts +38 -0
- package/extensions/websearch/config.ts +76 -0
- package/extensions/websearch/index.ts +312 -0
- package/extensions/websearch/normalize.ts +155 -0
- package/extensions/websearch/providers/anthropic.pi.ts +139 -0
- package/extensions/websearch/providers/gemini.browser.ts +185 -0
- package/extensions/websearch/providers/gemini.pi.ts +108 -0
- package/extensions/websearch/providers/openai-codex.browser.ts +77 -0
- package/extensions/websearch/providers/openai-codex.pi.ts +49 -0
- package/extensions/websearch/providers/openai-codex.shared.ts +123 -0
- package/extensions/websearch/providers/pi-model.shared.ts +86 -0
- package/extensions/websearch/providers/search-prompt.shared.ts +17 -0
- package/extensions/websearch/providers/shared.ts +76 -0
- package/extensions/websearch/types.ts +52 -0
- package/extensions/worktree.ts +2223 -0
- package/package.json +72 -0
- package/skills/browser-tools/SKILL.md +253 -0
- package/skills/browser-tools/scripts/browser-content.js +100 -0
- package/skills/browser-tools/scripts/browser-cookies.js +33 -0
- package/skills/browser-tools/scripts/browser-dismiss-cookies.js +455 -0
- package/skills/browser-tools/scripts/browser-eval.js +75 -0
- package/skills/browser-tools/scripts/browser-logs-tail.js +89 -0
- package/skills/browser-tools/scripts/browser-nav.js +28 -0
- package/skills/browser-tools/scripts/browser-net-summary.js +115 -0
- package/skills/browser-tools/scripts/browser-pick.js +133 -0
- package/skills/browser-tools/scripts/browser-screenshot.js +18 -0
- package/skills/browser-tools/scripts/browser-start.js +281 -0
- package/skills/browser-tools/scripts/browser-watch.js +321 -0
- package/skills/browser-tools/scripts/utils.js +60 -0
- package/skills/git-clean-history/SKILL.md +45 -0
- package/skills/git-commit/SKILL.md +55 -0
- package/skills/oracle/SKILL.md +64 -0
- package/skills/oracle/scripts/oracle +249 -0
- package/skills/oracle/scripts/oracle-bundle +227 -0
- package/skills/sentry/SKILL.md +198 -0
- package/skills/sentry/lib/auth.js +99 -0
- package/skills/sentry/scripts/fetch-event.js +325 -0
- package/skills/sentry/scripts/fetch-issue.js +368 -0
- package/skills/sentry/scripts/list-issues.js +245 -0
- package/skills/sentry/scripts/search-events.js +291 -0
- package/skills/sentry/scripts/search-logs.js +234 -0
- package/skills/update-changelog/SKILL.md +135 -0
- package/skills/web-design/SKILL.md +117 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from "fs";
|
|
2
|
+
import { homedir } from "os";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
|
|
5
|
+
export const SENTRY_API_BASE = "https://sentry.io/api/0";
|
|
6
|
+
|
|
7
|
+
// Cache for project slug -> ID resolution
|
|
8
|
+
const projectIdCache = new Map();
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Get auth token from ~/.sentryclirc
|
|
12
|
+
* @returns {string} The auth token
|
|
13
|
+
*/
|
|
14
|
+
export function getAuthToken() {
|
|
15
|
+
const rcPath = join(homedir(), ".sentryclirc");
|
|
16
|
+
if (!existsSync(rcPath)) {
|
|
17
|
+
console.error("Error: ~/.sentryclirc not found");
|
|
18
|
+
console.error("Provide a Sentry auth token via ~/.sentryclirc (user-managed).");
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const content = readFileSync(rcPath, "utf-8");
|
|
23
|
+
const match = content.match(/token\s*=\s*(.+)/);
|
|
24
|
+
if (!match) {
|
|
25
|
+
console.error("Error: No token found in ~/.sentryclirc");
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
return match[1].trim();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Fetch JSON from a Sentry API endpoint
|
|
33
|
+
* @param {string} url - The full URL to fetch
|
|
34
|
+
* @param {string} token - The auth token
|
|
35
|
+
* @returns {Promise<any>} The parsed JSON response
|
|
36
|
+
*/
|
|
37
|
+
export async function fetchJson(url, token) {
|
|
38
|
+
const res = await fetch(url, {
|
|
39
|
+
headers: {
|
|
40
|
+
Authorization: `Bearer ${token}`,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (!res.ok) {
|
|
45
|
+
const text = await res.text();
|
|
46
|
+
throw new Error(`API error ${res.status}: ${text}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return res.json();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Format a timestamp for display
|
|
54
|
+
* @param {string|number} ts - Timestamp (ISO string or unix)
|
|
55
|
+
* @returns {string} Formatted timestamp
|
|
56
|
+
*/
|
|
57
|
+
export function formatTimestamp(ts) {
|
|
58
|
+
if (!ts) return "N/A";
|
|
59
|
+
try {
|
|
60
|
+
const date = new Date(ts);
|
|
61
|
+
if (isNaN(date.getTime())) return ts;
|
|
62
|
+
return date.toLocaleString();
|
|
63
|
+
} catch {
|
|
64
|
+
return ts;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Resolve a project slug to its numeric ID.
|
|
70
|
+
* If the input is already a numeric ID, returns it as-is.
|
|
71
|
+
* @param {string} org - Organization slug
|
|
72
|
+
* @param {string} project - Project slug or numeric ID
|
|
73
|
+
* @param {string} token - Auth token
|
|
74
|
+
* @returns {Promise<string>} The numeric project ID
|
|
75
|
+
*/
|
|
76
|
+
export async function resolveProjectId(org, project, token) {
|
|
77
|
+
// If already numeric, return as-is
|
|
78
|
+
if (/^\d+$/.test(project)) {
|
|
79
|
+
return project;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Check cache
|
|
83
|
+
const cacheKey = `${org}/${project}`;
|
|
84
|
+
if (projectIdCache.has(cacheKey)) {
|
|
85
|
+
return projectIdCache.get(cacheKey);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Fetch project details to get the ID
|
|
89
|
+
const url = `${SENTRY_API_BASE}/projects/${encodeURIComponent(org)}/${encodeURIComponent(project)}/`;
|
|
90
|
+
const data = await fetchJson(url, token);
|
|
91
|
+
|
|
92
|
+
if (!data || !data.id) {
|
|
93
|
+
throw new Error(`Project '${project}' not found in organization '${org}'`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const id = String(data.id);
|
|
97
|
+
projectIdCache.set(cacheKey, id);
|
|
98
|
+
return id;
|
|
99
|
+
}
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { SENTRY_API_BASE, getAuthToken, fetchJson, formatTimestamp } from "../lib/auth.js";
|
|
4
|
+
|
|
5
|
+
const HELP = `Usage: fetch-event.js <event-id> [options]
|
|
6
|
+
|
|
7
|
+
Fetch a specific event by ID with full details.
|
|
8
|
+
|
|
9
|
+
Arguments:
|
|
10
|
+
event-id The event ID to fetch
|
|
11
|
+
|
|
12
|
+
Options:
|
|
13
|
+
--org, -o <org> Organization slug (required)
|
|
14
|
+
--project, -p <project> Project slug (required)
|
|
15
|
+
--json Output raw JSON
|
|
16
|
+
--breadcrumbs, -b Show all breadcrumbs (default: last 30)
|
|
17
|
+
--spans Show span tree (for transactions)
|
|
18
|
+
-h, --help Show this help
|
|
19
|
+
|
|
20
|
+
Examples:
|
|
21
|
+
# Fetch an event
|
|
22
|
+
fetch-event.js 571076d9728248739cecac2c9e96a24c --org myorg --project backend
|
|
23
|
+
|
|
24
|
+
# Get full breadcrumb history
|
|
25
|
+
fetch-event.js abc123 --org myorg --project backend --breadcrumbs
|
|
26
|
+
|
|
27
|
+
# Show spans for a transaction
|
|
28
|
+
fetch-event.js abc123 --org myorg --project backend --spans
|
|
29
|
+
|
|
30
|
+
# Get raw JSON for further analysis
|
|
31
|
+
fetch-event.js abc123 --org myorg --project backend --json
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
function parseArgs(args) {
|
|
35
|
+
const options = {
|
|
36
|
+
eventId: null,
|
|
37
|
+
org: null,
|
|
38
|
+
project: null,
|
|
39
|
+
json: false,
|
|
40
|
+
allBreadcrumbs: false,
|
|
41
|
+
showSpans: false,
|
|
42
|
+
help: false,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
for (let i = 0; i < args.length; i++) {
|
|
46
|
+
const arg = args[i];
|
|
47
|
+
|
|
48
|
+
switch (arg) {
|
|
49
|
+
case "--help":
|
|
50
|
+
case "-h":
|
|
51
|
+
options.help = true;
|
|
52
|
+
break;
|
|
53
|
+
case "--json":
|
|
54
|
+
options.json = true;
|
|
55
|
+
break;
|
|
56
|
+
case "--org":
|
|
57
|
+
case "-o":
|
|
58
|
+
options.org = args[++i];
|
|
59
|
+
break;
|
|
60
|
+
case "--project":
|
|
61
|
+
case "-p":
|
|
62
|
+
options.project = args[++i];
|
|
63
|
+
break;
|
|
64
|
+
case "--breadcrumbs":
|
|
65
|
+
case "-b":
|
|
66
|
+
options.allBreadcrumbs = true;
|
|
67
|
+
break;
|
|
68
|
+
case "--spans":
|
|
69
|
+
options.showSpans = true;
|
|
70
|
+
break;
|
|
71
|
+
default:
|
|
72
|
+
if (!arg.startsWith("-") && !options.eventId) {
|
|
73
|
+
options.eventId = arg;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return options;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function formatStacktrace(frames, { maxFrames = 20, showContext = true } = {}) {
|
|
82
|
+
if (!frames || frames.length === 0) return " (no frames)";
|
|
83
|
+
|
|
84
|
+
const reversed = frames.slice().reverse();
|
|
85
|
+
const appFrames = reversed.filter((f) => f.inApp !== false);
|
|
86
|
+
const framesToShow = appFrames.length > 0 ? appFrames : reversed;
|
|
87
|
+
|
|
88
|
+
return framesToShow
|
|
89
|
+
.slice(0, maxFrames)
|
|
90
|
+
.map((f, i) => {
|
|
91
|
+
const file = f.filename || f.absPath || f.module || "unknown";
|
|
92
|
+
const func = f.function || "(anonymous)";
|
|
93
|
+
const line = f.lineNo || f.lineno;
|
|
94
|
+
const col = f.colNo || f.colno;
|
|
95
|
+
const loc = line ? `:${line}${col ? `:${col}` : ""}` : "";
|
|
96
|
+
|
|
97
|
+
let out = ` ${i + 1}. ${file}${loc}\n → ${func}`;
|
|
98
|
+
|
|
99
|
+
if (showContext && f.context_line) {
|
|
100
|
+
out += `\n | ${f.context_line.trim()}`;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return out;
|
|
104
|
+
})
|
|
105
|
+
.join("\n\n");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function formatBreadcrumb(crumb) {
|
|
109
|
+
let ts = "??:??:??";
|
|
110
|
+
if (crumb.timestamp) {
|
|
111
|
+
try {
|
|
112
|
+
const date =
|
|
113
|
+
typeof crumb.timestamp === "number"
|
|
114
|
+
? new Date(crumb.timestamp * 1000)
|
|
115
|
+
: new Date(crumb.timestamp);
|
|
116
|
+
if (!isNaN(date.getTime())) {
|
|
117
|
+
ts = date.toISOString().slice(11, 19);
|
|
118
|
+
}
|
|
119
|
+
} catch {}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const cat = crumb.category || crumb.type || "?";
|
|
123
|
+
const level = crumb.level && crumb.level !== "info" ? `[${crumb.level}] ` : "";
|
|
124
|
+
let msg = crumb.message || "";
|
|
125
|
+
|
|
126
|
+
if (!msg && crumb.data) {
|
|
127
|
+
if (crumb.data.url) msg = crumb.data.url;
|
|
128
|
+
else if (crumb.data.method) msg = `${crumb.data.method} ${crumb.data.url || ""}`;
|
|
129
|
+
else if (typeof crumb.data === "object") msg = JSON.stringify(crumb.data);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return ` [${ts}] ${level}${cat}: ${msg}`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function formatSpan(span, indent = 0) {
|
|
136
|
+
const prefix = " ".repeat(indent);
|
|
137
|
+
const op = span.op || "?";
|
|
138
|
+
const desc = span.description || "(no description)";
|
|
139
|
+
const status = span.status || "?";
|
|
140
|
+
const duration = span.exclusive_time ? `${span.exclusive_time.toFixed(1)}ms` : "?";
|
|
141
|
+
|
|
142
|
+
return `${prefix}[${op}] ${desc}\n${prefix} status: ${status} | duration: ${duration}`;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function formatEvent(event, options) {
|
|
146
|
+
const lines = [];
|
|
147
|
+
|
|
148
|
+
lines.push(`# Event: ${event.eventID || event.id}`);
|
|
149
|
+
lines.push("");
|
|
150
|
+
lines.push(`**Timestamp:** ${formatTimestamp(event.dateCreated || event.timestamp)}`);
|
|
151
|
+
lines.push(`**Project:** ${event.projectSlug || event.projectID || "?"}`);
|
|
152
|
+
|
|
153
|
+
if (event.title) {
|
|
154
|
+
lines.push(`**Title:** ${event.title}`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (event.message) {
|
|
158
|
+
lines.push(`**Message:** ${event.message}`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Tags
|
|
162
|
+
if (event.tags && event.tags.length > 0) {
|
|
163
|
+
lines.push("");
|
|
164
|
+
lines.push("## Tags");
|
|
165
|
+
for (const tag of event.tags) {
|
|
166
|
+
lines.push(`- **${tag.key}:** ${tag.value}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Contexts
|
|
171
|
+
if (event.contexts) {
|
|
172
|
+
const ctx = event.contexts;
|
|
173
|
+
const contextLines = [];
|
|
174
|
+
|
|
175
|
+
if (ctx.runtime) {
|
|
176
|
+
contextLines.push(`- **Runtime:** ${ctx.runtime.name || "?"} ${ctx.runtime.version || ""}`);
|
|
177
|
+
}
|
|
178
|
+
if (ctx.browser) {
|
|
179
|
+
contextLines.push(`- **Browser:** ${ctx.browser.name || "?"} ${ctx.browser.version || ""}`);
|
|
180
|
+
}
|
|
181
|
+
if (ctx.os) {
|
|
182
|
+
contextLines.push(`- **OS:** ${ctx.os.name || "?"} ${ctx.os.version || ""}`);
|
|
183
|
+
}
|
|
184
|
+
if (ctx.device && ctx.device.family) {
|
|
185
|
+
contextLines.push(`- **Device:** ${ctx.device.family}`);
|
|
186
|
+
}
|
|
187
|
+
if (ctx.trace) {
|
|
188
|
+
contextLines.push(`- **Trace ID:** ${ctx.trace.trace_id || "?"}`);
|
|
189
|
+
contextLines.push(`- **Span ID:** ${ctx.trace.span_id || "?"}`);
|
|
190
|
+
if (ctx.trace.op) {
|
|
191
|
+
contextLines.push(`- **Operation:** ${ctx.trace.op}`);
|
|
192
|
+
}
|
|
193
|
+
if (ctx.trace.status) {
|
|
194
|
+
contextLines.push(`- **Status:** ${ctx.trace.status}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (contextLines.length > 0) {
|
|
199
|
+
lines.push("");
|
|
200
|
+
lines.push("## Context");
|
|
201
|
+
lines.push(...contextLines);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Process entries
|
|
206
|
+
if (event.entries) {
|
|
207
|
+
// Request
|
|
208
|
+
for (const entry of event.entries) {
|
|
209
|
+
if (entry.type === "request" && entry.data) {
|
|
210
|
+
const req = entry.data;
|
|
211
|
+
lines.push("");
|
|
212
|
+
lines.push("## Request");
|
|
213
|
+
if (req.method && req.url) {
|
|
214
|
+
lines.push(`**${req.method}** ${req.url}`);
|
|
215
|
+
}
|
|
216
|
+
if (req.headers && req.headers.length > 0) {
|
|
217
|
+
const importantHeaders = ["User-Agent", "Content-Type", "Host"];
|
|
218
|
+
const headers = req.headers.filter(([k]) => importantHeaders.includes(k));
|
|
219
|
+
if (headers.length > 0) {
|
|
220
|
+
for (const [k, v] of headers) {
|
|
221
|
+
lines.push(` ${k}: ${v}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Exceptions
|
|
229
|
+
for (const entry of event.entries) {
|
|
230
|
+
if (entry.type === "exception" && entry.data?.values) {
|
|
231
|
+
lines.push("");
|
|
232
|
+
lines.push("## Exception");
|
|
233
|
+
for (const exc of entry.data.values) {
|
|
234
|
+
lines.push("");
|
|
235
|
+
lines.push(`**${exc.type || "Error"}:** ${exc.value || "(no message)"}`);
|
|
236
|
+
if (exc.stacktrace?.frames) {
|
|
237
|
+
lines.push("");
|
|
238
|
+
lines.push(formatStacktrace(exc.stacktrace.frames));
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Breadcrumbs
|
|
245
|
+
for (const entry of event.entries) {
|
|
246
|
+
if (entry.type === "breadcrumbs" && entry.data?.values) {
|
|
247
|
+
const crumbs = options.allBreadcrumbs ? entry.data.values : entry.data.values.slice(-30);
|
|
248
|
+
|
|
249
|
+
if (crumbs.length > 0) {
|
|
250
|
+
lines.push("");
|
|
251
|
+
lines.push(
|
|
252
|
+
`## Breadcrumbs (${crumbs.length}${options.allBreadcrumbs ? "" : " most recent"})`,
|
|
253
|
+
);
|
|
254
|
+
for (const c of crumbs) {
|
|
255
|
+
lines.push(formatBreadcrumb(c));
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Spans (for transactions)
|
|
262
|
+
if (options.showSpans) {
|
|
263
|
+
for (const entry of event.entries) {
|
|
264
|
+
if (entry.type === "spans" && entry.data) {
|
|
265
|
+
lines.push("");
|
|
266
|
+
lines.push("## Spans");
|
|
267
|
+
const spans = Array.isArray(entry.data) ? entry.data : [entry.data];
|
|
268
|
+
for (const span of spans.slice(0, 50)) {
|
|
269
|
+
lines.push(formatSpan(span));
|
|
270
|
+
lines.push("");
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return lines.join("\n");
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
async function main() {
|
|
281
|
+
const args = process.argv.slice(2);
|
|
282
|
+
const options = parseArgs(args);
|
|
283
|
+
|
|
284
|
+
if (options.help) {
|
|
285
|
+
console.log(HELP);
|
|
286
|
+
process.exit(0);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (!options.eventId) {
|
|
290
|
+
console.error("Error: event-id is required");
|
|
291
|
+
console.error("Run with --help for usage information");
|
|
292
|
+
process.exit(1);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (!options.org) {
|
|
296
|
+
console.error("Error: --org is required");
|
|
297
|
+
console.error("Run with --help for usage information");
|
|
298
|
+
process.exit(1);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (!options.project) {
|
|
302
|
+
console.error("Error: --project is required");
|
|
303
|
+
console.error("Run with --help for usage information");
|
|
304
|
+
process.exit(1);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const token = getAuthToken();
|
|
308
|
+
|
|
309
|
+
const url = `${SENTRY_API_BASE}/projects/${encodeURIComponent(options.org)}/${encodeURIComponent(options.project)}/events/${encodeURIComponent(options.eventId)}/`;
|
|
310
|
+
|
|
311
|
+
try {
|
|
312
|
+
const event = await fetchJson(url, token);
|
|
313
|
+
|
|
314
|
+
if (options.json) {
|
|
315
|
+
console.log(JSON.stringify(event, null, 2));
|
|
316
|
+
} else {
|
|
317
|
+
console.log(formatEvent(event, options));
|
|
318
|
+
}
|
|
319
|
+
} catch (err) {
|
|
320
|
+
console.error("Error:", err.message);
|
|
321
|
+
process.exit(1);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
main();
|