clairo 2.0.0 → 2.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/dist/cli.js +414 -53
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -19,8 +19,8 @@ import { useCallback, useEffect as useEffect2, useMemo, useState as useState2 }
|
|
|
19
19
|
// src/lib/duckEvents.ts
|
|
20
20
|
var listeners = /* @__PURE__ */ new Set();
|
|
21
21
|
var duckEvents = {
|
|
22
|
-
emit: (event) => {
|
|
23
|
-
listeners.forEach((fn) => fn(event));
|
|
22
|
+
emit: (event, payload) => {
|
|
23
|
+
listeners.forEach((fn) => fn(event, payload));
|
|
24
24
|
},
|
|
25
25
|
subscribe: (fn) => {
|
|
26
26
|
listeners.add(fn);
|
|
@@ -579,6 +579,16 @@ function usePullRequests() {
|
|
|
579
579
|
if (result.success) {
|
|
580
580
|
setPrDetails(result.data);
|
|
581
581
|
setErrors((prev) => ({ ...prev, details: void 0 }));
|
|
582
|
+
const payload = { prNumber: result.data.number, prTitle: result.data.title };
|
|
583
|
+
if (result.data.state === "MERGED") {
|
|
584
|
+
duckEvents.emit("pr:merged", payload);
|
|
585
|
+
} else if (result.data.reviewDecision === "APPROVED") {
|
|
586
|
+
duckEvents.emit("pr:approved", payload);
|
|
587
|
+
} else if (result.data.reviewDecision === "CHANGES_REQUESTED") {
|
|
588
|
+
duckEvents.emit("pr:changes-requested", payload);
|
|
589
|
+
} else if (result.data.reviews.length > 0) {
|
|
590
|
+
duckEvents.emit("pr:reviewed", payload);
|
|
591
|
+
}
|
|
582
592
|
} else {
|
|
583
593
|
setErrors((prev) => ({ ...prev, details: result.error }));
|
|
584
594
|
}
|
|
@@ -1007,7 +1017,10 @@ async function applyTransition(auth, ticketKey, transitionId) {
|
|
|
1007
1017
|
return { success: true, data: null };
|
|
1008
1018
|
}
|
|
1009
1019
|
async function getIssueDetail(auth, issueKey) {
|
|
1010
|
-
const result = await jiraFetch(
|
|
1020
|
+
const result = await jiraFetch(
|
|
1021
|
+
auth,
|
|
1022
|
+
`/issue/${issueKey}?fields=summary,status,description,assignee,reporter,comment`
|
|
1023
|
+
);
|
|
1011
1024
|
if (!result.ok) {
|
|
1012
1025
|
if (result.status === 401 || result.status === 403) {
|
|
1013
1026
|
return { success: false, error: "Authentication failed", errorType: "auth_error" };
|
|
@@ -1933,7 +1946,7 @@ function useJiraTickets() {
|
|
|
1933
1946
|
const newTickets = getLinkedTickets(repoPath, currentBranch);
|
|
1934
1947
|
setTickets(newTickets);
|
|
1935
1948
|
setJiraState("has_tickets");
|
|
1936
|
-
duckEvents.emit("jira:linked");
|
|
1949
|
+
duckEvents.emit("jira:linked", { ticketKey: result.data.key });
|
|
1937
1950
|
setLoading((prev) => ({ ...prev, link: false }));
|
|
1938
1951
|
return true;
|
|
1939
1952
|
},
|
|
@@ -2140,55 +2153,405 @@ function useListNavigation({
|
|
|
2140
2153
|
|
|
2141
2154
|
// src/hooks/useRubberDuck.ts
|
|
2142
2155
|
import { useCallback as useCallback7, useEffect as useEffect7, useState as useState9 } from "react";
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
"
|
|
2156
|
+
|
|
2157
|
+
// src/constants/duck.ts
|
|
2158
|
+
var MOTIVATIONAL = [
|
|
2159
|
+
"I believe in you!",
|
|
2160
|
+
"You've got this!",
|
|
2161
|
+
"One commit at a time.",
|
|
2162
|
+
"Progress, not perfection.",
|
|
2163
|
+
"Every bug fixed is a victory.",
|
|
2164
|
+
"Ship it when it feels right.",
|
|
2165
|
+
"You're closer than you think.",
|
|
2166
|
+
"The tests will pass. Eventually.",
|
|
2167
|
+
"Future you will thank present you.",
|
|
2168
|
+
"Debugging builds character.",
|
|
2169
|
+
"Trust the process. And the compiler.",
|
|
2170
|
+
"Small steps, big impact."
|
|
2171
|
+
];
|
|
2172
|
+
var SARCASTIC = [
|
|
2147
2173
|
"It's always DNS.",
|
|
2148
|
-
"Did you check the logs?",
|
|
2149
|
-
"Maybe add a console.log?",
|
|
2150
|
-
"Is it plugged in?",
|
|
2151
2174
|
"Works on my machine.",
|
|
2152
|
-
"Have you tried reading the error message?",
|
|
2153
|
-
"I believe in you!",
|
|
2154
|
-
"It's probably a race condition.",
|
|
2155
|
-
"Have you tried turning it off and on again?",
|
|
2156
|
-
"Are you sure it compiled?",
|
|
2157
2175
|
"It's not a bug, it's a feature.",
|
|
2176
|
+
"Have you tried turning it off and on again?",
|
|
2177
|
+
"Maybe the real bug was the friends we made along the way.",
|
|
2178
|
+
"Ah yes, the classic off-by-one error. Or is it off-by-two?",
|
|
2179
|
+
"git blame says it was you.",
|
|
2180
|
+
"404: Solution not found. Just kidding, you'll get it.",
|
|
2181
|
+
"Ah yes, undefined is not a function. Classic.",
|
|
2182
|
+
"I'm sure the tests pass locally.",
|
|
2183
|
+
"Looks like a skill issue.",
|
|
2184
|
+
"This is what Stack Overflow was made for.",
|
|
2185
|
+
"Surely this won't break prod.",
|
|
2186
|
+
"git push --force and pray.",
|
|
2187
|
+
"Ah, another meeting that could have been a Slack message.",
|
|
2188
|
+
"The deadline was yesterday. No pressure."
|
|
2189
|
+
];
|
|
2190
|
+
var TECHNICAL = [
|
|
2191
|
+
"Did you check the logs?",
|
|
2192
|
+
"Maybe add a console.log?",
|
|
2158
2193
|
"Did you clear the cache?",
|
|
2159
2194
|
"Try deleting node_modules.",
|
|
2195
|
+
"Are you sure it compiled?",
|
|
2196
|
+
"Have you tried reading the error message?",
|
|
2197
|
+
"It's probably a race condition.",
|
|
2198
|
+
"Is it plugged in?",
|
|
2199
|
+
"Have you checked the network tab?",
|
|
2200
|
+
"Maybe it needs a type assertion.",
|
|
2201
|
+
"Sounds like a missing await.",
|
|
2202
|
+
"Is that dependency up to date?",
|
|
2203
|
+
"Try adding a .catch() to that promise.",
|
|
2204
|
+
"Check if it works in an incognito tab.",
|
|
2205
|
+
"Did you remember to save the file?",
|
|
2206
|
+
"Is the environment variable set?",
|
|
2207
|
+
"Have you tried a fresh git clone?",
|
|
2208
|
+
"Maybe it's a circular dependency.",
|
|
2209
|
+
"Check the types. Always check the types."
|
|
2210
|
+
];
|
|
2211
|
+
var QUACKS = [
|
|
2212
|
+
"Quack.",
|
|
2213
|
+
"Quack quack quack.",
|
|
2160
2214
|
"That's quackers!",
|
|
2215
|
+
"*supportive quacking*",
|
|
2161
2216
|
"Rubber duck debugging, activate!",
|
|
2162
|
-
"
|
|
2217
|
+
"Have you tried explaining it out loud?",
|
|
2218
|
+
"*listens intently*",
|
|
2219
|
+
"*nods in duck*",
|
|
2220
|
+
"*quacks thoughtfully*",
|
|
2221
|
+
"*tilts head*",
|
|
2222
|
+
"Tell me more about this bug...",
|
|
2223
|
+
"*floats beside you*",
|
|
2224
|
+
"*waddles encouragingly*",
|
|
2225
|
+
"Quack? Quack.",
|
|
2226
|
+
"*preens feathers while you think*",
|
|
2227
|
+
"I'm all ears. Well, I'm all beak.",
|
|
2228
|
+
"*splashes in your terminal*",
|
|
2229
|
+
"Go on, I quack \u2014 I mean, I listen.",
|
|
2230
|
+
"*adjusts tiny rubber duck glasses*"
|
|
2163
2231
|
];
|
|
2232
|
+
var DUCK_MESSAGES = [...MOTIVATIONAL, ...SARCASTIC, ...TECHNICAL, ...QUACKS];
|
|
2164
2233
|
var REACTION_MESSAGES = {
|
|
2165
|
-
"pr:merged": [
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2234
|
+
"pr:merged": [
|
|
2235
|
+
"Quack! It shipped!",
|
|
2236
|
+
"Merged! Time to celebrate.",
|
|
2237
|
+
"To production we go!",
|
|
2238
|
+
"Another one bites the dust.",
|
|
2239
|
+
"Merge commit secured.",
|
|
2240
|
+
"*celebratory quacking*",
|
|
2241
|
+
"The green button has been pressed!",
|
|
2242
|
+
"One less branch in the world.",
|
|
2243
|
+
"*does a little victory waddle*",
|
|
2244
|
+
"And just like that, it was done.",
|
|
2245
|
+
"git branch -d, you served us well.",
|
|
2246
|
+
"Main just got a little better.",
|
|
2247
|
+
"*throws confetti feathers*",
|
|
2248
|
+
"That's what I call a clean merge.",
|
|
2249
|
+
"The CI gods have smiled upon us.",
|
|
2250
|
+
"Deployed and unbothered.",
|
|
2251
|
+
{ template: "PR #{prNumber} merged! Ship it!", requires: ["prNumber"] },
|
|
2252
|
+
{ template: "{prTitle} is live!", requires: ["prTitle"] },
|
|
2253
|
+
{ template: "PR #{prNumber} is now part of history.", requires: ["prNumber"] },
|
|
2254
|
+
{ template: "#{prNumber} has entered the chat (and main).", requires: ["prNumber"] },
|
|
2255
|
+
{ template: "Farewell, #{prNumber}. You were a good branch.", requires: ["prNumber"] },
|
|
2256
|
+
{ template: '"{prTitle}" \u2014 merged and deployed.', requires: ["prTitle"] },
|
|
2257
|
+
{ template: "#{prNumber}: from draft to main. What a journey.", requires: ["prNumber"] },
|
|
2258
|
+
{ template: "RIP #{prNumber}'s branch. Long live main.", requires: ["prNumber"] },
|
|
2259
|
+
{ template: '"{prTitle}" is in the books.', requires: ["prTitle"] },
|
|
2260
|
+
{ template: "#{prNumber} just graduated to production.", requires: ["prNumber"] }
|
|
2261
|
+
],
|
|
2262
|
+
"pr:opened": [
|
|
2263
|
+
"A new PR! Exciting!",
|
|
2264
|
+
"Time for review!",
|
|
2265
|
+
"Fresh code incoming!",
|
|
2266
|
+
"PR opened! Now we wait...",
|
|
2267
|
+
"Let's hope CI passes.",
|
|
2268
|
+
"*optimistic quacking*",
|
|
2269
|
+
"Into the review queue it goes!",
|
|
2270
|
+
"Bold move. I like it.",
|
|
2271
|
+
"And so it begins...",
|
|
2272
|
+
"*quacks in anticipation*",
|
|
2273
|
+
"The diff looks great from here.",
|
|
2274
|
+
"Reviewers, assemble!",
|
|
2275
|
+
"Don't forget to self-review first.",
|
|
2276
|
+
"May your CI be green and your conflicts few.",
|
|
2277
|
+
"*refreshes PR page nervously*",
|
|
2278
|
+
"The hardest part is waiting for reviews.",
|
|
2279
|
+
{ template: "PR #{prNumber} is out there!", requires: ["prNumber"] },
|
|
2280
|
+
{ template: '"{prTitle}" \u2014 sounds promising!', requires: ["prTitle"] },
|
|
2281
|
+
{ template: "#{prNumber} is ready for eyeballs.", requires: ["prNumber"] },
|
|
2282
|
+
{ template: "#{prNumber} just dropped. Reviews welcome.", requires: ["prNumber"] },
|
|
2283
|
+
{ template: '"{prTitle}" \u2014 I would approve that.', requires: ["prTitle"] },
|
|
2284
|
+
{ template: "#{prNumber} has entered the arena.", requires: ["prNumber"] },
|
|
2285
|
+
{ template: '"{prTitle}" \u2014 the diff speaks for itself.', requires: ["prTitle"] },
|
|
2286
|
+
{ template: "Good luck, #{prNumber}. You're gonna need it.", requires: ["prNumber"] },
|
|
2287
|
+
{ template: '"{prTitle}": chapter one.', requires: ["prTitle"] },
|
|
2288
|
+
{ template: "#{prNumber} is seeking approval. Aren't we all?", requires: ["prNumber"] }
|
|
2289
|
+
],
|
|
2290
|
+
"pr:reviewed": [
|
|
2291
|
+
"Feedback time!",
|
|
2292
|
+
"Reviews are in!",
|
|
2293
|
+
"*attentive quacking*",
|
|
2294
|
+
"Someone looked at your code!",
|
|
2295
|
+
"The verdict is in...",
|
|
2296
|
+
"Review received. Deep breaths.",
|
|
2297
|
+
"A fresh pair of eyes!",
|
|
2298
|
+
"*peeks at the comments*",
|
|
2299
|
+
"Code review: the great equalizer.",
|
|
2300
|
+
"Opinions incoming!",
|
|
2301
|
+
"At least someone is reading your code.",
|
|
2302
|
+
"*braces for impact*",
|
|
2303
|
+
"Comments are just spicy suggestions.",
|
|
2304
|
+
"Time to read between the lines.",
|
|
2305
|
+
"Let's see what they think...",
|
|
2306
|
+
{ template: "#{prNumber} has been reviewed!", requires: ["prNumber"] },
|
|
2307
|
+
{ template: 'Someone has opinions about "{prTitle}".', requires: ["prTitle"] },
|
|
2308
|
+
{ template: "#{prNumber} caught someone's attention.", requires: ["prNumber"] },
|
|
2309
|
+
{ template: 'Eyes on "{prTitle}".', requires: ["prTitle"] },
|
|
2310
|
+
{ template: "#{prNumber}: reviewed. The suspense builds.", requires: ["prNumber"] },
|
|
2311
|
+
{ template: '"{prTitle}" is under the microscope.', requires: ["prTitle"] },
|
|
2312
|
+
{ template: "#{prNumber} got some feedback. Brace yourself.", requires: ["prNumber"] }
|
|
2313
|
+
],
|
|
2314
|
+
"pr:approved": [
|
|
2315
|
+
"Approved!",
|
|
2316
|
+
"LGTM!",
|
|
2317
|
+
"Ship it!",
|
|
2318
|
+
"Green across the board!",
|
|
2319
|
+
"*excited quacking*",
|
|
2320
|
+
"The stamp of approval!",
|
|
2321
|
+
"You earned that checkmark.",
|
|
2322
|
+
"*quacks with pride*",
|
|
2323
|
+
"Merge when ready, captain.",
|
|
2324
|
+
"No notes. Literally.",
|
|
2325
|
+
"They couldn't find a single nit. Impressive.",
|
|
2326
|
+
"*standing ovation quacking*",
|
|
2327
|
+
"The approver has spoken.",
|
|
2328
|
+
"All systems go.",
|
|
2329
|
+
"Permission to merge, granted.",
|
|
2330
|
+
"Clean code wins again.",
|
|
2331
|
+
{ template: "PR #{prNumber} approved!", requires: ["prNumber"] },
|
|
2332
|
+
{ template: "#{prNumber} got the green light!", requires: ["prNumber"] },
|
|
2333
|
+
{ template: '"{prTitle}" has been blessed.', requires: ["prTitle"] },
|
|
2334
|
+
{ template: "#{prNumber}: approved. Go time.", requires: ["prNumber"] },
|
|
2335
|
+
{ template: '"{prTitle}" passed the vibe check.', requires: ["prTitle"] },
|
|
2336
|
+
{ template: "#{prNumber} is merge-ready. Your move.", requires: ["prNumber"] },
|
|
2337
|
+
{ template: '"{prTitle}": approved. No objections.', requires: ["prTitle"] },
|
|
2338
|
+
{ template: "#{prNumber} cleared for takeoff.", requires: ["prNumber"] },
|
|
2339
|
+
{ template: "#{prNumber}: zero nits. A rare achievement.", requires: ["prNumber"] }
|
|
2340
|
+
],
|
|
2341
|
+
"pr:changes-requested": [
|
|
2342
|
+
"Some changes needed...",
|
|
2343
|
+
"Back to the drawing board!",
|
|
2344
|
+
"Iterate iterate!",
|
|
2345
|
+
"Feedback is a gift. A slightly annoying gift.",
|
|
2346
|
+
"Almost there. Almost.",
|
|
2347
|
+
"*encouraging quack*",
|
|
2348
|
+
"It's not a rejection, it's a suggestion.",
|
|
2349
|
+
"Round two. Ding ding!",
|
|
2350
|
+
"*passes you a tissue*",
|
|
2351
|
+
"They're just nits. Probably.",
|
|
2352
|
+
"You'll get 'em next push.",
|
|
2353
|
+
"Every great PR has a revision arc.",
|
|
2354
|
+
"They're helping you write better code. That's the story.",
|
|
2355
|
+
"*quacks supportively*",
|
|
2356
|
+
"Nothing a force push can't fix. (Don't actually.)",
|
|
2357
|
+
"The best code is rewritten code. Or something.",
|
|
2358
|
+
"Take a breath. Then address the comments.",
|
|
2359
|
+
{ template: "PR #{prNumber} needs some love.", requires: ["prNumber"] },
|
|
2360
|
+
{ template: "#{prNumber} is almost there \u2014 just a few tweaks.", requires: ["prNumber"] },
|
|
2361
|
+
{ template: '"{prTitle}" needs another pass.', requires: ["prTitle"] },
|
|
2362
|
+
{ template: "#{prNumber}: so close, yet so far.", requires: ["prNumber"] },
|
|
2363
|
+
{ template: "#{prNumber} got sent back. It happens to the best of us.", requires: ["prNumber"] },
|
|
2364
|
+
{ template: '"{prTitle}" has notes. Address them and come back stronger.', requires: ["prTitle"] },
|
|
2365
|
+
{ template: "#{prNumber}: revision requested. You know the drill.", requires: ["prNumber"] },
|
|
2366
|
+
{ template: '"{prTitle}" \u2014 round two incoming.', requires: ["prTitle"] },
|
|
2367
|
+
{ template: "#{prNumber} will be even better after this.", requires: ["prNumber"] }
|
|
2368
|
+
],
|
|
2369
|
+
error: [
|
|
2370
|
+
"Uh oh...",
|
|
2371
|
+
"There there...",
|
|
2372
|
+
"*concerned quacking*",
|
|
2373
|
+
"Quack... not good.",
|
|
2374
|
+
"Errors happen. That's what undo is for.",
|
|
2375
|
+
"Have you tried quacking at it?",
|
|
2376
|
+
"It's fine. Everything's fine.",
|
|
2377
|
+
"*pats you with wing*",
|
|
2378
|
+
"This too shall pass.",
|
|
2379
|
+
"Even senior devs get errors. It's fine.",
|
|
2380
|
+
"*hides behind your monitor*",
|
|
2381
|
+
"That was... unexpected.",
|
|
2382
|
+
"The stack trace knows what happened. You'll figure it out.",
|
|
2383
|
+
"If at first you fail, try try again.",
|
|
2384
|
+
"*nervous quacking*",
|
|
2385
|
+
"Look on the bright side: at least it failed loudly.",
|
|
2386
|
+
"I've seen worse. I think.",
|
|
2387
|
+
"Error is just another word for learning opportunity.",
|
|
2388
|
+
"*puts on hard hat*",
|
|
2389
|
+
"That's a feature request from the error gods.",
|
|
2390
|
+
"Have you considered that maybe the error is right?",
|
|
2391
|
+
"Errors are just the code being honest with you.",
|
|
2392
|
+
"*offers you a rubber duck*",
|
|
2393
|
+
"At least it errored before production. ...Right?"
|
|
2394
|
+
],
|
|
2395
|
+
"jira:transition": [
|
|
2396
|
+
"Ticket moving!",
|
|
2397
|
+
"Progress!",
|
|
2398
|
+
"Workflow in motion!",
|
|
2399
|
+
"Status updated!",
|
|
2400
|
+
"*productive quacking*",
|
|
2401
|
+
"The board looks better already.",
|
|
2402
|
+
"Kanban dreams coming true.",
|
|
2403
|
+
"*drags ticket across the board*",
|
|
2404
|
+
"One column closer to done.",
|
|
2405
|
+
"The sprint board thanks you.",
|
|
2406
|
+
"Velocity: increasing.",
|
|
2407
|
+
"Your scrum master would be proud.",
|
|
2408
|
+
"*updates the burndown chart mentally*",
|
|
2409
|
+
"Flow state: achieved.",
|
|
2410
|
+
"The backlog trembles.",
|
|
2411
|
+
{ template: "{ticketKey} \u2192 {status}!", requires: ["ticketKey", "status"] },
|
|
2412
|
+
{ template: "{ticketKey} is moving along!", requires: ["ticketKey"] },
|
|
2413
|
+
{ template: "{ticketKey} leveled up to {status}.", requires: ["ticketKey", "status"] },
|
|
2414
|
+
{ template: "{ticketKey} has places to be.", requires: ["ticketKey"] },
|
|
2415
|
+
{ template: "{ticketKey}: {status}. Onward!", requires: ["ticketKey", "status"] },
|
|
2416
|
+
{ template: "{ticketKey} just moved to {status}. Progress!", requires: ["ticketKey", "status"] },
|
|
2417
|
+
{ template: "{ticketKey} is now {status}. The board rejoices.", requires: ["ticketKey", "status"] },
|
|
2418
|
+
{ template: "{ticketKey}: status updated. Your standup just got easier.", requires: ["ticketKey"] },
|
|
2419
|
+
{ template: "{ticketKey} changed lanes to {status}.", requires: ["ticketKey", "status"] },
|
|
2420
|
+
{ template: "{ticketKey} is on the move!", requires: ["ticketKey"] }
|
|
2421
|
+
],
|
|
2422
|
+
"jira:linked": [
|
|
2423
|
+
"Ticket linked!",
|
|
2424
|
+
"Jira connection made!",
|
|
2425
|
+
"Tracking enabled!",
|
|
2426
|
+
"Code meets ticket!",
|
|
2427
|
+
"Traceability achieved.",
|
|
2428
|
+
"*organized quacking*",
|
|
2429
|
+
"Branch and ticket, sitting in a tree.",
|
|
2430
|
+
"Connected the dots!",
|
|
2431
|
+
"*files everything neatly*",
|
|
2432
|
+
"Your PM will be proud.",
|
|
2433
|
+
"Context: preserved.",
|
|
2434
|
+
"Now you can prove you did the work.",
|
|
2435
|
+
"Audit trail established.",
|
|
2436
|
+
"The code has a story now.",
|
|
2437
|
+
{ template: "{ticketKey} linked to this branch!", requires: ["ticketKey"] },
|
|
2438
|
+
{ template: "{ticketKey} now has a home.", requires: ["ticketKey"] },
|
|
2439
|
+
{ template: "{ticketKey} and this branch are besties now.", requires: ["ticketKey"] },
|
|
2440
|
+
{ template: "{ticketKey}: tracked and accounted for.", requires: ["ticketKey"] },
|
|
2441
|
+
{ template: "{ticketKey} is now part of the story.", requires: ["ticketKey"] },
|
|
2442
|
+
{ template: "{ticketKey} linked. Your commits have meaning now.", requires: ["ticketKey"] },
|
|
2443
|
+
{ template: "{ticketKey}: connected. No more mystery commits.", requires: ["ticketKey"] }
|
|
2444
|
+
],
|
|
2445
|
+
"jira:configured": [
|
|
2446
|
+
"Jira ready!",
|
|
2447
|
+
"Integration complete!",
|
|
2448
|
+
"Connected to Jira!",
|
|
2449
|
+
"The pipeline is flowing!",
|
|
2450
|
+
"*impressed quacking*",
|
|
2451
|
+
"Jira and terminal, together at last.",
|
|
2452
|
+
"Setup complete. Time to be productive.",
|
|
2453
|
+
"*quacks approvingly*",
|
|
2454
|
+
"The tools are connected. The workflow is whole.",
|
|
2455
|
+
"Now the real fun begins.",
|
|
2456
|
+
"Terminal + Jira = unstoppable.",
|
|
2457
|
+
"One less browser tab needed.",
|
|
2458
|
+
"You just leveled up your workflow.",
|
|
2459
|
+
"*nods in DevOps*"
|
|
2460
|
+
],
|
|
2461
|
+
"jira:assigned": [
|
|
2462
|
+
"Assigned!",
|
|
2463
|
+
"On it!",
|
|
2464
|
+
"Claimed!",
|
|
2465
|
+
"It's yours now!",
|
|
2466
|
+
"*dutiful quacking*",
|
|
2467
|
+
"Ownership established.",
|
|
2468
|
+
"Responsibility accepted.",
|
|
2469
|
+
"*salutes*",
|
|
2470
|
+
"A ticket has found its champion.",
|
|
2471
|
+
"Challenge accepted.",
|
|
2472
|
+
"With great tickets comes great responsibility.",
|
|
2473
|
+
"The chosen one.",
|
|
2474
|
+
"*pins ticket to your desk*",
|
|
2475
|
+
"It's dangerous to go alone \u2014 take this ticket.",
|
|
2476
|
+
{ template: "{ticketKey} assigned to {assignee}!", requires: ["ticketKey", "assignee"] },
|
|
2477
|
+
{ template: "{ticketKey} has an owner now!", requires: ["ticketKey"] },
|
|
2478
|
+
{ template: "{assignee} is on the case!", requires: ["assignee"] },
|
|
2479
|
+
{ template: "{assignee} accepted the quest: {ticketKey}.", requires: ["ticketKey", "assignee"] },
|
|
2480
|
+
{ template: "{ticketKey} found its person.", requires: ["ticketKey"] },
|
|
2481
|
+
{ template: "{assignee} picked up {ticketKey}. Bold.", requires: ["ticketKey", "assignee"] },
|
|
2482
|
+
{ template: "{ticketKey} \u2192 {assignee}. Good luck!", requires: ["ticketKey", "assignee"] },
|
|
2483
|
+
{ template: "{assignee} volunteered as tribute for {ticketKey}.", requires: ["ticketKey", "assignee"] },
|
|
2484
|
+
{ template: "{ticketKey} is in {assignee}'s hands now.", requires: ["ticketKey", "assignee"] },
|
|
2485
|
+
{ template: "{assignee}: you own {ticketKey}. No takebacks.", requires: ["ticketKey", "assignee"] }
|
|
2486
|
+
],
|
|
2487
|
+
"jira:unassigned": [
|
|
2488
|
+
"Unassigned!",
|
|
2489
|
+
"Free agent!",
|
|
2490
|
+
"Released!",
|
|
2491
|
+
"Back to the pool.",
|
|
2492
|
+
"*liberated quacking*",
|
|
2493
|
+
"Ticket is up for grabs.",
|
|
2494
|
+
"Back to the backlog wilderness.",
|
|
2495
|
+
"*waves goodbye*",
|
|
2496
|
+
"An orphan ticket in the wild.",
|
|
2497
|
+
"Someone will pick it up. Probably.",
|
|
2498
|
+
"Into the void it goes.",
|
|
2499
|
+
"Not my ticket, not my problem.",
|
|
2500
|
+
"*whistles innocently*",
|
|
2501
|
+
"Free as a bird. Well, a duck.",
|
|
2502
|
+
{ template: "{ticketKey} is unassigned.", requires: ["ticketKey"] },
|
|
2503
|
+
{ template: "{ticketKey} needs a new hero.", requires: ["ticketKey"] },
|
|
2504
|
+
{ template: "{ticketKey} is looking for a volunteer.", requires: ["ticketKey"] },
|
|
2505
|
+
{ template: "Who wants {ticketKey}? Anyone?", requires: ["ticketKey"] },
|
|
2506
|
+
{ template: "{ticketKey} has been released into the wild.", requires: ["ticketKey"] },
|
|
2507
|
+
{ template: "{ticketKey}: abandoned. *sad quack*", requires: ["ticketKey"] },
|
|
2508
|
+
{ template: "{ticketKey} is available. First come, first served.", requires: ["ticketKey"] },
|
|
2509
|
+
{ template: "{ticketKey} is free. Like a duck on a pond.", requires: ["ticketKey"] }
|
|
2510
|
+
]
|
|
2176
2511
|
};
|
|
2512
|
+
function fillTemplate(template, payload) {
|
|
2513
|
+
return template.replace(/\{(\w+)\}/g, (_, key) => {
|
|
2514
|
+
const val = payload[key];
|
|
2515
|
+
return val !== void 0 ? String(val) : `{${key}}`;
|
|
2516
|
+
});
|
|
2517
|
+
}
|
|
2518
|
+
function pickReactionMessage(event, payload) {
|
|
2519
|
+
const entries = REACTION_MESSAGES[event];
|
|
2520
|
+
const candidates = [];
|
|
2521
|
+
for (const entry of entries) {
|
|
2522
|
+
if (typeof entry === "string") {
|
|
2523
|
+
candidates.push(entry);
|
|
2524
|
+
} else if (payload && entry.requires.every((k) => payload[k] !== void 0)) {
|
|
2525
|
+
candidates.push(fillTemplate(entry.template, payload));
|
|
2526
|
+
}
|
|
2527
|
+
}
|
|
2528
|
+
return candidates[Math.floor(Math.random() * candidates.length)];
|
|
2529
|
+
}
|
|
2530
|
+
|
|
2531
|
+
// src/hooks/useRubberDuck.ts
|
|
2177
2532
|
function useRubberDuck() {
|
|
2178
|
-
const [state, setState] = useState9({
|
|
2179
|
-
|
|
2180
|
-
|
|
2533
|
+
const [state, setState] = useState9(() => {
|
|
2534
|
+
const config = loadConfig();
|
|
2535
|
+
return {
|
|
2536
|
+
visible: config.duckVisible ?? false,
|
|
2537
|
+
message: DUCK_MESSAGES[Math.floor(Math.random() * DUCK_MESSAGES.length)]
|
|
2538
|
+
};
|
|
2181
2539
|
});
|
|
2182
2540
|
const getRandomMessage = useCallback7(() => {
|
|
2183
2541
|
const index = Math.floor(Math.random() * DUCK_MESSAGES.length);
|
|
2184
2542
|
return DUCK_MESSAGES[index];
|
|
2185
2543
|
}, []);
|
|
2186
2544
|
const toggleDuck = useCallback7(() => {
|
|
2187
|
-
setState((prev) =>
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2545
|
+
setState((prev) => {
|
|
2546
|
+
const newVisible = !prev.visible;
|
|
2547
|
+
const config = loadConfig();
|
|
2548
|
+
saveConfig({ ...config, duckVisible: newVisible });
|
|
2549
|
+
return {
|
|
2550
|
+
...prev,
|
|
2551
|
+
visible: newVisible,
|
|
2552
|
+
message: newVisible ? getRandomMessage() : prev.message
|
|
2553
|
+
};
|
|
2554
|
+
});
|
|
2192
2555
|
}, [getRandomMessage]);
|
|
2193
2556
|
const quack = useCallback7(() => {
|
|
2194
2557
|
if (state.visible) {
|
|
@@ -2198,20 +2561,16 @@ function useRubberDuck() {
|
|
|
2198
2561
|
}));
|
|
2199
2562
|
}
|
|
2200
2563
|
}, [state.visible, getRandomMessage]);
|
|
2201
|
-
const getReactionMessage = useCallback7((event) => {
|
|
2202
|
-
const messages = REACTION_MESSAGES[event];
|
|
2203
|
-
return messages[Math.floor(Math.random() * messages.length)];
|
|
2204
|
-
}, []);
|
|
2205
2564
|
useEffect7(() => {
|
|
2206
|
-
const unsubscribe = duckEvents.subscribe((event) => {
|
|
2565
|
+
const unsubscribe = duckEvents.subscribe((event, payload) => {
|
|
2207
2566
|
setState((prev) => ({
|
|
2208
2567
|
...prev,
|
|
2209
2568
|
visible: true,
|
|
2210
|
-
message:
|
|
2569
|
+
message: pickReactionMessage(event, payload)
|
|
2211
2570
|
}));
|
|
2212
2571
|
});
|
|
2213
2572
|
return unsubscribe;
|
|
2214
|
-
}, [
|
|
2573
|
+
}, []);
|
|
2215
2574
|
return {
|
|
2216
2575
|
visible: state.visible,
|
|
2217
2576
|
message: state.message,
|
|
@@ -2496,7 +2855,7 @@ ${body}`;
|
|
|
2496
2855
|
var _a;
|
|
2497
2856
|
const ticketKeys = repoPath && branch ? getLinkedTickets(repoPath, branch).map((t) => t.key) : [];
|
|
2498
2857
|
logPRCreated(newPR.number, newPR.title, ticketKeys);
|
|
2499
|
-
duckEvents.emit("pr:opened");
|
|
2858
|
+
duckEvents.emit("pr:opened", { prNumber: newPR.number, prTitle: newPR.title });
|
|
2500
2859
|
(_a = onLogUpdatedRef.current) == null ? void 0 : _a.call(onLogUpdatedRef);
|
|
2501
2860
|
}
|
|
2502
2861
|
});
|
|
@@ -2532,7 +2891,7 @@ ${body}`;
|
|
|
2532
2891
|
var _a;
|
|
2533
2892
|
const tickets = repoPath && branch ? getLinkedTickets(repoPath, branch).map((t) => t.key) : [];
|
|
2534
2893
|
logPRCreated(newPR.number, newPR.title, tickets);
|
|
2535
|
-
duckEvents.emit("pr:opened");
|
|
2894
|
+
duckEvents.emit("pr:opened", { prNumber: newPR.number, prTitle: newPR.title });
|
|
2536
2895
|
(_a = onLogUpdatedRef.current) == null ? void 0 : _a.call(onLogUpdatedRef);
|
|
2537
2896
|
}
|
|
2538
2897
|
});
|
|
@@ -2771,7 +3130,7 @@ function JiraIssueDetailView({
|
|
|
2771
3130
|
onIssueUpdated,
|
|
2772
3131
|
onLogUpdated
|
|
2773
3132
|
}) {
|
|
2774
|
-
var _a;
|
|
3133
|
+
var _a, _b;
|
|
2775
3134
|
const scrollRef = useRef6(null);
|
|
2776
3135
|
const [detail, setDetail] = useState13(null);
|
|
2777
3136
|
const [loading, setLoading] = useState13(true);
|
|
@@ -2817,7 +3176,7 @@ function JiraIssueDetailView({
|
|
|
2817
3176
|
const oldStatus = (detail == null ? void 0 : detail.fields.status.name) ?? "Unknown";
|
|
2818
3177
|
setDetail((prev) => prev ? { ...prev, fields: { ...prev.fields, status: { name: newStatus } } } : prev);
|
|
2819
3178
|
onIssueUpdated(issueKey, { status: newStatus });
|
|
2820
|
-
duckEvents.emit("jira:transition");
|
|
3179
|
+
duckEvents.emit("jira:transition", { ticketKey: issueKey, status: newStatus });
|
|
2821
3180
|
logJiraStatusChanged(issueKey, issueSummary, oldStatus, newStatus);
|
|
2822
3181
|
onLogUpdated == null ? void 0 : onLogUpdated();
|
|
2823
3182
|
} else {
|
|
@@ -2835,7 +3194,7 @@ function JiraIssueDetailView({
|
|
|
2835
3194
|
const assignee = { accountId: myAccountId, displayName: myDisplayName };
|
|
2836
3195
|
setDetail((prev) => prev ? { ...prev, fields: { ...prev.fields, assignee } } : prev);
|
|
2837
3196
|
onIssueUpdated(issueKey, { assignee });
|
|
2838
|
-
duckEvents.emit("jira:assigned");
|
|
3197
|
+
duckEvents.emit("jira:assigned", { ticketKey: issueKey, assignee: myDisplayName });
|
|
2839
3198
|
logJiraAssigneeChanged(issueKey, issueSummary, "assigned", myDisplayName);
|
|
2840
3199
|
onLogUpdated == null ? void 0 : onLogUpdated();
|
|
2841
3200
|
} else {
|
|
@@ -2851,7 +3210,7 @@ function JiraIssueDetailView({
|
|
|
2851
3210
|
if (result.success) {
|
|
2852
3211
|
setDetail((prev) => prev ? { ...prev, fields: { ...prev.fields, assignee: null } } : prev);
|
|
2853
3212
|
onIssueUpdated(issueKey, { assignee: null });
|
|
2854
|
-
duckEvents.emit("jira:unassigned");
|
|
3213
|
+
duckEvents.emit("jira:unassigned", { ticketKey: issueKey });
|
|
2855
3214
|
logJiraAssigneeChanged(issueKey, issueSummary, "unassigned");
|
|
2856
3215
|
onLogUpdated == null ? void 0 : onLogUpdated();
|
|
2857
3216
|
} else {
|
|
@@ -2862,7 +3221,7 @@ function JiraIssueDetailView({
|
|
|
2862
3221
|
};
|
|
2863
3222
|
useInput7(
|
|
2864
3223
|
(input, key) => {
|
|
2865
|
-
var _a2,
|
|
3224
|
+
var _a2, _b2;
|
|
2866
3225
|
if (mode === "transitions") {
|
|
2867
3226
|
if (key.escape) {
|
|
2868
3227
|
setMode("normal");
|
|
@@ -2877,7 +3236,7 @@ function JiraIssueDetailView({
|
|
|
2877
3236
|
(_a2 = scrollRef.current) == null ? void 0 : _a2.scrollBy(-1);
|
|
2878
3237
|
}
|
|
2879
3238
|
if (key.downArrow || input === "j") {
|
|
2880
|
-
(
|
|
3239
|
+
(_b2 = scrollRef.current) == null ? void 0 : _b2.scrollBy(1);
|
|
2881
3240
|
}
|
|
2882
3241
|
if (input === "o") {
|
|
2883
3242
|
open3(getIssueUrl()).catch(() => {
|
|
@@ -2921,7 +3280,9 @@ function JiraIssueDetailView({
|
|
|
2921
3280
|
/* @__PURE__ */ jsx9(Text8, { dimColor: true, children: "Status:" }),
|
|
2922
3281
|
/* @__PURE__ */ jsx9(Text8, { color: statusColor, children: detail.fields.status.name }),
|
|
2923
3282
|
/* @__PURE__ */ jsx9(Text8, { dimColor: true, children: "Assignee:" }),
|
|
2924
|
-
/* @__PURE__ */ jsx9(Text8, { children: ((_a = detail.fields.assignee) == null ? void 0 : _a.displayName) ?? "Unassigned" })
|
|
3283
|
+
/* @__PURE__ */ jsx9(Text8, { children: ((_a = detail.fields.assignee) == null ? void 0 : _a.displayName) ?? "Unassigned" }),
|
|
3284
|
+
/* @__PURE__ */ jsx9(Text8, { dimColor: true, children: "Reporter:" }),
|
|
3285
|
+
/* @__PURE__ */ jsx9(Text8, { children: ((_b = detail.fields.reporter) == null ? void 0 : _b.displayName) ?? "Unknown" })
|
|
2925
3286
|
] }),
|
|
2926
3287
|
/* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Divider, {}) }),
|
|
2927
3288
|
/* @__PURE__ */ jsxs8(Box9, { marginTop: 1, flexDirection: "column", children: [
|
|
@@ -3665,7 +4026,7 @@ function ChangeStatusModal({ repoPath, ticketKey, currentStatus, onComplete, onC
|
|
|
3665
4026
|
if (result.success) {
|
|
3666
4027
|
const transition = transitions.find((t) => t.id === item.value);
|
|
3667
4028
|
const newStatus = (transition == null ? void 0 : transition.to.name) ?? item.label;
|
|
3668
|
-
duckEvents.emit("jira:transition");
|
|
4029
|
+
duckEvents.emit("jira:transition", { ticketKey, status: newStatus });
|
|
3669
4030
|
onComplete(newStatus);
|
|
3670
4031
|
} else {
|
|
3671
4032
|
setError(result.error);
|