mitsupi 1.0.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 (77) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +95 -0
  3. package/TODO.md +11 -0
  4. package/commands/handoff.md +100 -0
  5. package/commands/make-release.md +75 -0
  6. package/commands/pickup.md +30 -0
  7. package/commands/update-changelog.md +78 -0
  8. package/package.json +22 -0
  9. package/pi-extensions/answer.ts +527 -0
  10. package/pi-extensions/codex-tuning.ts +632 -0
  11. package/pi-extensions/commit.ts +248 -0
  12. package/pi-extensions/cwd-history.ts +237 -0
  13. package/pi-extensions/issues.ts +548 -0
  14. package/pi-extensions/loop.ts +446 -0
  15. package/pi-extensions/qna.ts +167 -0
  16. package/pi-extensions/reveal.ts +689 -0
  17. package/pi-extensions/review.ts +807 -0
  18. package/pi-themes/armin.json +81 -0
  19. package/pi-themes/nightowl.json +82 -0
  20. package/skills/anachb/SKILL.md +183 -0
  21. package/skills/anachb/departures.sh +79 -0
  22. package/skills/anachb/disruptions.sh +53 -0
  23. package/skills/anachb/route.sh +87 -0
  24. package/skills/anachb/search.sh +43 -0
  25. package/skills/ghidra/SKILL.md +254 -0
  26. package/skills/ghidra/scripts/find-ghidra.sh +54 -0
  27. package/skills/ghidra/scripts/ghidra-analyze.sh +239 -0
  28. package/skills/ghidra/scripts/ghidra_scripts/ExportAll.java +278 -0
  29. package/skills/ghidra/scripts/ghidra_scripts/ExportCalls.java +148 -0
  30. package/skills/ghidra/scripts/ghidra_scripts/ExportDecompiled.java +84 -0
  31. package/skills/ghidra/scripts/ghidra_scripts/ExportFunctions.java +114 -0
  32. package/skills/ghidra/scripts/ghidra_scripts/ExportStrings.java +123 -0
  33. package/skills/ghidra/scripts/ghidra_scripts/ExportSymbols.java +135 -0
  34. package/skills/github/SKILL.md +47 -0
  35. package/skills/improve-skill/SKILL.md +155 -0
  36. package/skills/improve-skill/scripts/extract-session.js +349 -0
  37. package/skills/oebb-scotty/SKILL.md +429 -0
  38. package/skills/oebb-scotty/arrivals.sh +83 -0
  39. package/skills/oebb-scotty/departures.sh +83 -0
  40. package/skills/oebb-scotty/disruptions.sh +33 -0
  41. package/skills/oebb-scotty/search-station.sh +36 -0
  42. package/skills/oebb-scotty/trip.sh +119 -0
  43. package/skills/openscad/SKILL.md +232 -0
  44. package/skills/openscad/examples/parametric_box.scad +92 -0
  45. package/skills/openscad/examples/phone_stand.scad +95 -0
  46. package/skills/openscad/tools/common.sh +50 -0
  47. package/skills/openscad/tools/export-stl.sh +56 -0
  48. package/skills/openscad/tools/extract-params.sh +147 -0
  49. package/skills/openscad/tools/multi-preview.sh +68 -0
  50. package/skills/openscad/tools/preview.sh +74 -0
  51. package/skills/openscad/tools/render-with-params.sh +91 -0
  52. package/skills/openscad/tools/validate.sh +46 -0
  53. package/skills/pi-share/SKILL.md +105 -0
  54. package/skills/pi-share/fetch-session.mjs +322 -0
  55. package/skills/sentry/SKILL.md +239 -0
  56. package/skills/sentry/lib/auth.js +99 -0
  57. package/skills/sentry/scripts/fetch-event.js +329 -0
  58. package/skills/sentry/scripts/fetch-issue.js +356 -0
  59. package/skills/sentry/scripts/list-issues.js +239 -0
  60. package/skills/sentry/scripts/search-events.js +291 -0
  61. package/skills/sentry/scripts/search-logs.js +240 -0
  62. package/skills/tmux/SKILL.md +105 -0
  63. package/skills/tmux/scripts/find-sessions.sh +112 -0
  64. package/skills/tmux/scripts/wait-for-text.sh +83 -0
  65. package/skills/web-browser/SKILL.md +91 -0
  66. package/skills/web-browser/scripts/cdp.js +210 -0
  67. package/skills/web-browser/scripts/dismiss-cookies.js +373 -0
  68. package/skills/web-browser/scripts/eval.js +68 -0
  69. package/skills/web-browser/scripts/logs-tail.js +69 -0
  70. package/skills/web-browser/scripts/nav.js +65 -0
  71. package/skills/web-browser/scripts/net-summary.js +94 -0
  72. package/skills/web-browser/scripts/package-lock.json +33 -0
  73. package/skills/web-browser/scripts/package.json +6 -0
  74. package/skills/web-browser/scripts/pick.js +165 -0
  75. package/skills/web-browser/scripts/screenshot.js +52 -0
  76. package/skills/web-browser/scripts/start.js +80 -0
  77. package/skills/web-browser/scripts/watch.js +266 -0
@@ -0,0 +1,239 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { SENTRY_API_BASE, getAuthToken, fetchJson, formatTimestamp, resolveProjectId } from "../lib/auth.js";
4
+
5
+ const HELP = `Usage: list-issues.js [options]
6
+
7
+ List and search issues in Sentry.
8
+
9
+ Options:
10
+ --org, -o <org> Organization slug (required)
11
+ --project, -p <project> Project slug (can be repeated for multiple projects)
12
+ --query, -q <query> Search query (Sentry issue search syntax)
13
+ --status <status> Filter by status (unresolved, resolved, ignored)
14
+ --level <level> Filter by level (error, warning, info, fatal)
15
+ --period, -t <period> Time period (default: 14d, e.g., 24h, 7d, 14d)
16
+ --limit, -n <n> Max results (default: 25)
17
+ --sort <sort> Sort order (date, new, priority, freq, user)
18
+ --json Output raw JSON
19
+ -h, --help Show this help
20
+
21
+ Query Syntax:
22
+ is:unresolved Unresolved issues only
23
+ is:resolved Resolved issues only
24
+ is:ignored Ignored issues only
25
+ is:assigned Assigned to someone
26
+ is:unassigned Not assigned
27
+ assigned:me Assigned to current user
28
+ level:error Error level only
29
+ firstSeen:+7d First seen more than 7 days ago
30
+ lastSeen:-24h Last seen within 24 hours
31
+ event.timestamp:>=2025-12-23 Events since date
32
+ times_seen:>100 Seen more than 100 times
33
+ user.email:*@example.com User email pattern
34
+ has:user Has user context
35
+ error.handled:0 Unhandled errors
36
+
37
+ Sort Options:
38
+ date - Last seen (default)
39
+ new - First seen (newest first)
40
+ priority - Priority score
41
+ freq - Frequency (events per time)
42
+ user - Users affected
43
+
44
+ Examples:
45
+ # List unresolved errors
46
+ list-issues.js --org myorg --project backend --status unresolved
47
+
48
+ # Find recent high-priority issues
49
+ list-issues.js --org myorg --query "is:unresolved lastSeen:-24h" --sort priority
50
+
51
+ # Search for specific error type
52
+ list-issues.js --org myorg --query "AI_NoOutputGeneratedError"
53
+
54
+ # Find issues first seen in a date range
55
+ list-issues.js --org myorg --query "firstSeen:>=2025-12-23 firstSeen:<=2025-12-24"
56
+
57
+ # Find issues with many events
58
+ list-issues.js --org myorg --query "times_seen:>50" --sort freq
59
+ `;
60
+
61
+ function parseArgs(args) {
62
+ const options = {
63
+ org: null,
64
+ projects: [],
65
+ query: null,
66
+ status: null,
67
+ level: null,
68
+ period: "14d",
69
+ limit: 25,
70
+ sort: null,
71
+ json: false,
72
+ help: false,
73
+ };
74
+
75
+ for (let i = 0; i < args.length; i++) {
76
+ const arg = args[i];
77
+
78
+ switch (arg) {
79
+ case "--help":
80
+ case "-h":
81
+ options.help = true;
82
+ break;
83
+ case "--json":
84
+ options.json = true;
85
+ break;
86
+ case "--org":
87
+ case "-o":
88
+ options.org = args[++i];
89
+ break;
90
+ case "--project":
91
+ case "-p":
92
+ options.projects.push(args[++i]);
93
+ break;
94
+ case "--query":
95
+ case "-q":
96
+ options.query = args[++i];
97
+ break;
98
+ case "--status":
99
+ options.status = args[++i];
100
+ break;
101
+ case "--level":
102
+ options.level = args[++i];
103
+ break;
104
+ case "--period":
105
+ case "-t":
106
+ options.period = args[++i];
107
+ break;
108
+ case "--limit":
109
+ case "-n":
110
+ options.limit = parseInt(args[++i], 10);
111
+ break;
112
+ case "--sort":
113
+ options.sort = args[++i];
114
+ break;
115
+ }
116
+ }
117
+
118
+ return options;
119
+ }
120
+
121
+ function formatIssue(issue) {
122
+ const lines = [];
123
+
124
+ const id = issue.shortId || issue.id;
125
+ const title = issue.title || "(no title)";
126
+ const level = issue.level || "?";
127
+ const status = issue.status || "?";
128
+ const count = issue.count || 0;
129
+ const userCount = issue.userCount || 0;
130
+ const firstSeen = formatTimestamp(issue.firstSeen);
131
+ const lastSeen = formatTimestamp(issue.lastSeen);
132
+ const project = issue.project?.slug || "?";
133
+ const culprit = issue.culprit || "";
134
+ const permalink = issue.permalink || "";
135
+
136
+ lines.push(`[${id}] ${title}`);
137
+ lines.push(` level: ${level} | status: ${status} | project: ${project}`);
138
+ lines.push(` events: ${count} | users: ${userCount}`);
139
+ lines.push(` first: ${firstSeen} | last: ${lastSeen}`);
140
+
141
+ if (culprit) {
142
+ lines.push(` culprit: ${culprit}`);
143
+ }
144
+
145
+ if (permalink) {
146
+ lines.push(` url: ${permalink}`);
147
+ }
148
+
149
+ return lines.join("\n");
150
+ }
151
+
152
+ function formatOutput(issues) {
153
+ if (!issues || issues.length === 0) {
154
+ return "No issues found matching your query.";
155
+ }
156
+
157
+ const lines = [];
158
+ lines.push(`Found ${issues.length} issues:\n`);
159
+
160
+ for (const issue of issues) {
161
+ lines.push(formatIssue(issue));
162
+ lines.push("");
163
+ }
164
+
165
+ return lines.join("\n").trimEnd();
166
+ }
167
+
168
+ async function main() {
169
+ const args = process.argv.slice(2);
170
+ const options = parseArgs(args);
171
+
172
+ if (options.help) {
173
+ console.log(HELP);
174
+ process.exit(0);
175
+ }
176
+
177
+ if (!options.org) {
178
+ console.error("Error: --org is required");
179
+ console.error("Run with --help for usage information");
180
+ process.exit(1);
181
+ }
182
+
183
+ const token = getAuthToken();
184
+
185
+ // Build query parameters
186
+ const params = new URLSearchParams();
187
+
188
+ if (options.period) {
189
+ params.set("statsPeriod", options.period);
190
+ }
191
+
192
+ params.set("limit", Math.min(options.limit, 100).toString());
193
+
194
+ // Build search query
195
+ const queryParts = [];
196
+
197
+ if (options.query) {
198
+ queryParts.push(options.query);
199
+ }
200
+
201
+ if (options.status) {
202
+ queryParts.push(`is:${options.status}`);
203
+ }
204
+
205
+ if (options.level) {
206
+ queryParts.push(`level:${options.level}`);
207
+ }
208
+
209
+ if (queryParts.length > 0) {
210
+ params.set("query", queryParts.join(" "));
211
+ }
212
+
213
+ if (options.sort) {
214
+ params.set("sort", options.sort);
215
+ }
216
+
217
+ // Build URL - always use org endpoint with resolved project IDs
218
+ // This handles both slugs and numeric IDs uniformly
219
+ for (const project of options.projects) {
220
+ const projectId = await resolveProjectId(options.org, project, token);
221
+ params.append("project", projectId);
222
+ }
223
+ const url = `${SENTRY_API_BASE}/organizations/${encodeURIComponent(options.org)}/issues/?${params.toString()}`;
224
+
225
+ try {
226
+ const data = await fetchJson(url, token);
227
+
228
+ if (options.json) {
229
+ console.log(JSON.stringify(data, null, 2));
230
+ } else {
231
+ console.log(formatOutput(data));
232
+ }
233
+ } catch (err) {
234
+ console.error("Error:", err.message);
235
+ process.exit(1);
236
+ }
237
+ }
238
+
239
+ main();
@@ -0,0 +1,291 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { SENTRY_API_BASE, getAuthToken, fetchJson, formatTimestamp, resolveProjectId } from "../lib/auth.js";
4
+
5
+ const HELP = `Usage: search-events.js [options]
6
+
7
+ Search for events (transactions, errors) in Sentry Discover.
8
+
9
+ Options:
10
+ --org, -o <org> Organization slug (required)
11
+ --project, -p <project> Project slug or ID
12
+ --query, -q <query> Search query (Discover syntax)
13
+ --period, -t <period> Time period (default: 24h, e.g., 1h, 7d, 14d)
14
+ --start <datetime> Start time (ISO 8601, e.g., 2025-12-23T15:00:00)
15
+ --end <datetime> End time (ISO 8601)
16
+ --transaction <name> Filter by transaction name
17
+ --tag <key:value> Filter by tag (can be repeated)
18
+ --level <level> Filter by level (error, warning, info)
19
+ --limit, -n <n> Max results (default: 25, max: 100)
20
+ --fields <fields> Comma-separated fields to include
21
+ --json Output raw JSON
22
+ -h, --help Show this help
23
+
24
+ Common Fields:
25
+ id, title, timestamp, transaction, message, level, environment,
26
+ user.email, user.id, tags[key], http.method, http.url
27
+
28
+ Query Syntax (Discover):
29
+ transaction:process-* Match transaction names with wildcards
30
+ level:error Filter by log level
31
+ user.email:foo@bar.com Filter by user email
32
+ environment:production Filter by environment
33
+ has:stack.filename Events with stack traces
34
+ !has:user Events without user
35
+
36
+ Date Range Examples:
37
+ --period 7d Last 7 days
38
+ --start 2025-12-23T15:00:00 From specific time to now
39
+ --start 2025-12-23T15:00:00 --end 2025-12-23T18:00:00 Specific range
40
+
41
+ Examples:
42
+ # Find all transactions for a transaction name
43
+ search-events.js --org myorg --project backend --transaction process-incoming-email
44
+
45
+ # Find errors in the last 7 days
46
+ search-events.js --org myorg --query "level:error" --period 7d
47
+
48
+ # Find events around a specific time
49
+ search-events.js --org myorg --start 2025-12-23T15:00:00 --end 2025-12-23T17:00:00
50
+
51
+ # Search with a specific tag
52
+ search-events.js --org myorg --tag thread_id:th_abc123
53
+
54
+ # Get more fields
55
+ search-events.js --org myorg --fields "id,title,timestamp,user.email"
56
+ `;
57
+
58
+ function parseArgs(args) {
59
+ const options = {
60
+ org: null,
61
+ project: null,
62
+ query: null,
63
+ period: null,
64
+ start: null,
65
+ end: null,
66
+ transaction: null,
67
+ tags: [],
68
+ level: null,
69
+ limit: 25,
70
+ fields: ["id", "title", "timestamp", "transaction", "message"],
71
+ json: false,
72
+ help: false,
73
+ };
74
+
75
+ for (let i = 0; i < args.length; i++) {
76
+ const arg = args[i];
77
+
78
+ switch (arg) {
79
+ case "--help":
80
+ case "-h":
81
+ options.help = true;
82
+ break;
83
+ case "--json":
84
+ options.json = true;
85
+ break;
86
+ case "--org":
87
+ case "-o":
88
+ options.org = args[++i];
89
+ break;
90
+ case "--project":
91
+ case "-p":
92
+ options.project = args[++i];
93
+ break;
94
+ case "--query":
95
+ case "-q":
96
+ options.query = args[++i];
97
+ break;
98
+ case "--period":
99
+ case "-t":
100
+ options.period = args[++i];
101
+ break;
102
+ case "--start":
103
+ options.start = args[++i];
104
+ break;
105
+ case "--end":
106
+ options.end = args[++i];
107
+ break;
108
+ case "--transaction":
109
+ options.transaction = args[++i];
110
+ break;
111
+ case "--tag":
112
+ options.tags.push(args[++i]);
113
+ break;
114
+ case "--level":
115
+ options.level = args[++i];
116
+ break;
117
+ case "--limit":
118
+ case "-n":
119
+ options.limit = parseInt(args[++i], 10);
120
+ break;
121
+ case "--fields":
122
+ options.fields = args[++i].split(",").map((f) => f.trim());
123
+ break;
124
+ }
125
+ }
126
+
127
+ // Default to 24h if no time range specified
128
+ if (!options.period && !options.start) {
129
+ options.period = "24h";
130
+ }
131
+
132
+ return options;
133
+ }
134
+
135
+ function formatEvent(event, fields) {
136
+ const lines = [];
137
+
138
+ const id = event.id || event["event.type"] || "?";
139
+ const ts = event.timestamp || "N/A";
140
+ const title = event.title || event.transaction || event.message || "(no title)";
141
+ const transaction = event.transaction || "";
142
+
143
+ // Format timestamp
144
+ let displayTs = ts;
145
+ try {
146
+ const date = new Date(ts);
147
+ if (!isNaN(date.getTime())) {
148
+ displayTs = date.toISOString().replace("T", " ").slice(0, 19);
149
+ }
150
+ } catch {}
151
+
152
+ lines.push(`[${displayTs}] ${title}`);
153
+
154
+ if (transaction && transaction !== title) {
155
+ lines.push(` transaction: ${transaction}`);
156
+ }
157
+
158
+ if (event.message && event.message !== title) {
159
+ lines.push(` message: ${event.message}`);
160
+ }
161
+
162
+ // Show any extra fields the user requested
163
+ for (const field of fields) {
164
+ if (["id", "title", "timestamp", "transaction", "message"].includes(field)) continue;
165
+ const value = event[field];
166
+ if (value !== undefined && value !== null && value !== "") {
167
+ lines.push(` ${field}: ${value}`);
168
+ }
169
+ }
170
+
171
+ lines.push(` id: ${id}`);
172
+
173
+ return lines.join("\n");
174
+ }
175
+
176
+ function formatOutput(data, fields) {
177
+ if (!data.data || data.data.length === 0) {
178
+ return "No events found matching your query.";
179
+ }
180
+
181
+ const lines = [];
182
+ lines.push(`Found ${data.data.length} events:\n`);
183
+
184
+ for (const event of data.data) {
185
+ lines.push(formatEvent(event, fields));
186
+ lines.push("");
187
+ }
188
+
189
+ return lines.join("\n").trimEnd();
190
+ }
191
+
192
+ async function main() {
193
+ const args = process.argv.slice(2);
194
+ const options = parseArgs(args);
195
+
196
+ if (options.help) {
197
+ console.log(HELP);
198
+ process.exit(0);
199
+ }
200
+
201
+ if (!options.org) {
202
+ console.error("Error: --org is required");
203
+ console.error("Run with --help for usage information");
204
+ process.exit(1);
205
+ }
206
+
207
+ const token = getAuthToken();
208
+
209
+ // Build query parameters
210
+ const params = new URLSearchParams();
211
+ params.set("dataset", "discover");
212
+
213
+ // Time range
214
+ if (options.start) {
215
+ params.set("start", options.start);
216
+ if (options.end) {
217
+ params.set("end", options.end);
218
+ } else {
219
+ // If only start, use current time as end
220
+ params.set("end", new Date().toISOString());
221
+ }
222
+ } else if (options.period) {
223
+ params.set("statsPeriod", options.period);
224
+ }
225
+
226
+ params.set("per_page", Math.min(options.limit, 100).toString());
227
+ params.set("sort", "-timestamp");
228
+
229
+ // Add fields
230
+ for (const field of options.fields) {
231
+ params.append("field", field);
232
+ }
233
+
234
+ // Always include project.name for context
235
+ if (!options.fields.includes("project.name")) {
236
+ params.append("field", "project.name");
237
+ }
238
+
239
+ // Build search query
240
+ const queryParts = [];
241
+
242
+ if (options.project) {
243
+ const projectId = await resolveProjectId(options.org, options.project, token);
244
+ params.set("project", projectId);
245
+ }
246
+
247
+ if (options.query) {
248
+ queryParts.push(options.query);
249
+ }
250
+
251
+ if (options.transaction) {
252
+ queryParts.push(`transaction:${options.transaction}`);
253
+ }
254
+
255
+ if (options.level) {
256
+ queryParts.push(`level:${options.level}`);
257
+ }
258
+
259
+ for (const tag of options.tags) {
260
+ // Handle tags[key]:value format
261
+ if (tag.includes(":")) {
262
+ const [key, value] = tag.split(":", 2);
263
+ if (key.startsWith("tags[")) {
264
+ queryParts.push(`${key}:${value}`);
265
+ } else {
266
+ queryParts.push(`tags[${key}]:${value}`);
267
+ }
268
+ }
269
+ }
270
+
271
+ if (queryParts.length > 0) {
272
+ params.set("query", queryParts.join(" "));
273
+ }
274
+
275
+ const url = `${SENTRY_API_BASE}/organizations/${encodeURIComponent(options.org)}/events/?${params.toString()}`;
276
+
277
+ try {
278
+ const data = await fetchJson(url, token);
279
+
280
+ if (options.json) {
281
+ console.log(JSON.stringify(data, null, 2));
282
+ } else {
283
+ console.log(formatOutput(data, options.fields));
284
+ }
285
+ } catch (err) {
286
+ console.error("Error:", err.message);
287
+ process.exit(1);
288
+ }
289
+ }
290
+
291
+ main();