ralphctl 0.1.2 → 0.1.4
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/{add-HGJCLWED.mjs → add-7LBVENXM.mjs} +6 -4
- package/dist/{add-MRGCS3US.mjs → add-DVEYDCTR.mjs} +6 -4
- package/dist/{chunk-NTWO2LXB.mjs → chunk-7LZ6GOGN.mjs} +13 -12
- package/dist/{chunk-JON4GCLR.mjs → chunk-DZ6HHTM5.mjs} +1 -1
- package/dist/chunk-EDJX7TT6.mjs +148 -0
- package/dist/{chunk-MNMQC36F.mjs → chunk-F2MMCTB5.mjs} +71 -77
- package/dist/{chunk-EKMZZRWI.mjs → chunk-LFDW6MWF.mjs} +65 -70
- package/dist/{chunk-LOR7QBXX.mjs → chunk-M7JV6MKD.mjs} +270 -349
- package/dist/chunk-OEUJDSHY.mjs +27 -0
- package/dist/{chunk-WGHJI3OI.mjs → chunk-PDI6HBZ7.mjs} +32 -37
- package/dist/{chunk-6PYTKGB5.mjs → chunk-W3TY22IS.mjs} +45 -39
- package/dist/{chunk-MRKOFVTM.mjs → chunk-YIB7QYU4.mjs} +102 -100
- package/dist/cli.mjs +761 -739
- package/dist/create-MQ4OHZAX.mjs +12 -0
- package/dist/{handle-UG5M2OON.mjs → handle-K2AZLTKU.mjs} +1 -1
- package/dist/{project-NT3L4FTB.mjs → project-Q4LKML42.mjs} +6 -4
- package/dist/{resolver-WSFWKACM.mjs → resolver-NH34HTB6.mjs} +27 -17
- package/dist/{sprint-4VHDLGFN.mjs → sprint-UHYXSEBJ.mjs} +8 -5
- package/dist/{wizard-LRELAN2J.mjs → wizard-MCDDXLGE.mjs} +45 -48
- package/package.json +2 -1
- package/dist/create-MG7E7PLQ.mjs +0 -10
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
import {
|
|
3
3
|
addSingleTicketInteractive,
|
|
4
4
|
ticketAddCommand
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-F2MMCTB5.mjs";
|
|
6
6
|
import "./chunk-7TG3EAQ2.mjs";
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-PDI6HBZ7.mjs";
|
|
8
|
+
import "./chunk-LFDW6MWF.mjs";
|
|
9
|
+
import "./chunk-OEUJDSHY.mjs";
|
|
10
|
+
import "./chunk-W3TY22IS.mjs";
|
|
11
|
+
import "./chunk-EDJX7TT6.mjs";
|
|
10
12
|
import "./chunk-QBXHAXHI.mjs";
|
|
11
13
|
export {
|
|
12
14
|
addSingleTicketInteractive,
|
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
import {
|
|
3
3
|
addCheckScriptToRepository,
|
|
4
4
|
projectAddCommand
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-YIB7QYU4.mjs";
|
|
6
|
+
import "./chunk-7LZ6GOGN.mjs";
|
|
7
7
|
import "./chunk-7TG3EAQ2.mjs";
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-PDI6HBZ7.mjs";
|
|
9
|
+
import "./chunk-OEUJDSHY.mjs";
|
|
10
|
+
import "./chunk-W3TY22IS.mjs";
|
|
11
|
+
import "./chunk-EDJX7TT6.mjs";
|
|
10
12
|
import "./chunk-QBXHAXHI.mjs";
|
|
11
13
|
export {
|
|
12
14
|
addCheckScriptToRepository,
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
ensureError,
|
|
4
|
+
wrapAsync
|
|
5
|
+
} from "./chunk-OEUJDSHY.mjs";
|
|
2
6
|
|
|
3
7
|
// src/interactive/escapable.ts
|
|
4
8
|
import readline from "readline";
|
|
@@ -32,19 +36,16 @@ async function escapableSelect(config, options) {
|
|
|
32
36
|
}
|
|
33
37
|
};
|
|
34
38
|
process.stdin.on("keypress", onKeypress);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
throw err;
|
|
45
|
-
} finally {
|
|
46
|
-
process.stdin.removeListener("keypress", onKeypress);
|
|
39
|
+
const r = await wrapAsync(
|
|
40
|
+
() => select(withEscapeHint(config, options?.escLabel ?? "back"), { signal: controller.signal }),
|
|
41
|
+
ensureError
|
|
42
|
+
);
|
|
43
|
+
process.stdin.removeListener("keypress", onKeypress);
|
|
44
|
+
if (!r.ok) {
|
|
45
|
+
if (r.error.name === "AbortPromptError") return null;
|
|
46
|
+
throw r.error;
|
|
47
47
|
}
|
|
48
|
+
return r.value;
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
export {
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/errors.ts
|
|
4
|
+
var DomainError = class extends Error {
|
|
5
|
+
cause;
|
|
6
|
+
constructor(message, cause) {
|
|
7
|
+
super(message, cause ? { cause } : void 0);
|
|
8
|
+
this.name = this.constructor.name;
|
|
9
|
+
this.cause = cause;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
var IOError = class extends DomainError {
|
|
13
|
+
code = "IO_ERROR";
|
|
14
|
+
};
|
|
15
|
+
var StorageError = class extends DomainError {
|
|
16
|
+
code = "STORAGE_ERROR";
|
|
17
|
+
};
|
|
18
|
+
var LockError = class extends DomainError {
|
|
19
|
+
code = "LOCK_ERROR";
|
|
20
|
+
lockPath;
|
|
21
|
+
constructor(message, lockPath, cause) {
|
|
22
|
+
super(message, cause);
|
|
23
|
+
this.lockPath = lockPath;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var ParseError = class extends DomainError {
|
|
27
|
+
code = "PARSE_ERROR";
|
|
28
|
+
};
|
|
29
|
+
var ValidationError = class extends DomainError {
|
|
30
|
+
code = "VALIDATION_ERROR";
|
|
31
|
+
path;
|
|
32
|
+
constructor(message, path, cause) {
|
|
33
|
+
super(message, cause);
|
|
34
|
+
this.path = path;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
function detectSpawnRateLimit(stderr) {
|
|
38
|
+
const patterns = [/rate.?limit/i, /\b429\b/, /too many requests/i, /overloaded/i, /\b529\b/];
|
|
39
|
+
const isRateLimited = patterns.some((p) => p.test(stderr));
|
|
40
|
+
if (!isRateLimited) return { rateLimited: false, retryAfterMs: null };
|
|
41
|
+
const retryMatch = /retry.?after:?\s*(\d+)/i.exec(stderr);
|
|
42
|
+
const retryAfterMs = retryMatch?.[1] ? parseInt(retryMatch[1], 10) * 1e3 : null;
|
|
43
|
+
return { rateLimited: true, retryAfterMs };
|
|
44
|
+
}
|
|
45
|
+
var SpawnError = class extends DomainError {
|
|
46
|
+
code = "SPAWN_ERROR";
|
|
47
|
+
stderr;
|
|
48
|
+
exitCode;
|
|
49
|
+
rateLimited;
|
|
50
|
+
retryAfterMs;
|
|
51
|
+
sessionId;
|
|
52
|
+
constructor(message, stderr, exitCode, sessionId, cause) {
|
|
53
|
+
super(message, cause);
|
|
54
|
+
this.stderr = stderr;
|
|
55
|
+
this.exitCode = exitCode;
|
|
56
|
+
this.sessionId = sessionId ?? null;
|
|
57
|
+
const rl = detectSpawnRateLimit(stderr);
|
|
58
|
+
this.rateLimited = rl.rateLimited;
|
|
59
|
+
this.retryAfterMs = rl.retryAfterMs;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var SprintNotFoundError = class extends DomainError {
|
|
63
|
+
code = "SPRINT_NOT_FOUND";
|
|
64
|
+
sprintId;
|
|
65
|
+
constructor(sprintId) {
|
|
66
|
+
super(`Sprint not found: ${sprintId}`);
|
|
67
|
+
this.sprintId = sprintId;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
var TaskNotFoundError = class extends DomainError {
|
|
71
|
+
code = "TASK_NOT_FOUND";
|
|
72
|
+
taskId;
|
|
73
|
+
constructor(taskId) {
|
|
74
|
+
super(`Task not found: ${taskId}`);
|
|
75
|
+
this.taskId = taskId;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
var TicketNotFoundError = class extends DomainError {
|
|
79
|
+
code = "TICKET_NOT_FOUND";
|
|
80
|
+
ticketId;
|
|
81
|
+
constructor(ticketId) {
|
|
82
|
+
super(`Ticket not found: ${ticketId}`);
|
|
83
|
+
this.ticketId = ticketId;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
var ProjectNotFoundError = class extends DomainError {
|
|
87
|
+
code = "PROJECT_NOT_FOUND";
|
|
88
|
+
projectName;
|
|
89
|
+
constructor(projectName) {
|
|
90
|
+
super(`Project not found: ${projectName}`);
|
|
91
|
+
this.projectName = projectName;
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
var ProjectExistsError = class extends DomainError {
|
|
95
|
+
code = "PROJECT_EXISTS";
|
|
96
|
+
projectName;
|
|
97
|
+
constructor(projectName) {
|
|
98
|
+
super(`Project already exists: ${projectName}`);
|
|
99
|
+
this.projectName = projectName;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
var StatusError = class extends DomainError {
|
|
103
|
+
code = "STATUS_ERROR";
|
|
104
|
+
};
|
|
105
|
+
var SprintStatusError = class extends StatusError {
|
|
106
|
+
currentStatus;
|
|
107
|
+
operation;
|
|
108
|
+
constructor(message, currentStatus, operation) {
|
|
109
|
+
super(message);
|
|
110
|
+
this.currentStatus = currentStatus;
|
|
111
|
+
this.operation = operation;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
var NoCurrentSprintError = class extends StatusError {
|
|
115
|
+
constructor() {
|
|
116
|
+
super("No sprint specified and no current sprint set.");
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
var DependencyCycleError = class extends DomainError {
|
|
120
|
+
code = "DEPENDENCY_CYCLE";
|
|
121
|
+
cycle;
|
|
122
|
+
constructor(cycle) {
|
|
123
|
+
super(`Dependency cycle detected: ${cycle.join(" \u2192 ")}`);
|
|
124
|
+
this.cycle = cycle;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
var IssueFetchError = class extends DomainError {
|
|
128
|
+
code = "ISSUE_FETCH_ERROR";
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export {
|
|
132
|
+
DomainError,
|
|
133
|
+
IOError,
|
|
134
|
+
StorageError,
|
|
135
|
+
LockError,
|
|
136
|
+
ParseError,
|
|
137
|
+
ValidationError,
|
|
138
|
+
SpawnError,
|
|
139
|
+
SprintNotFoundError,
|
|
140
|
+
TaskNotFoundError,
|
|
141
|
+
TicketNotFoundError,
|
|
142
|
+
ProjectNotFoundError,
|
|
143
|
+
ProjectExistsError,
|
|
144
|
+
SprintStatusError,
|
|
145
|
+
NoCurrentSprintError,
|
|
146
|
+
DependencyCycleError,
|
|
147
|
+
IssueFetchError
|
|
148
|
+
};
|
|
@@ -4,25 +4,33 @@ import {
|
|
|
4
4
|
exitWithCode
|
|
5
5
|
} from "./chunk-7TG3EAQ2.mjs";
|
|
6
6
|
import {
|
|
7
|
-
ProjectNotFoundError,
|
|
8
|
-
getProject,
|
|
9
7
|
listProjects,
|
|
10
8
|
projectExists
|
|
11
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-PDI6HBZ7.mjs";
|
|
12
10
|
import {
|
|
13
|
-
SprintStatusError,
|
|
14
11
|
assertSprintStatus,
|
|
15
12
|
generateUuid8,
|
|
16
13
|
getEditor,
|
|
17
14
|
resolveSprintId,
|
|
18
15
|
setEditor
|
|
19
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-LFDW6MWF.mjs";
|
|
17
|
+
import {
|
|
18
|
+
ensureError,
|
|
19
|
+
unwrapOrThrow,
|
|
20
|
+
wrapAsync
|
|
21
|
+
} from "./chunk-OEUJDSHY.mjs";
|
|
20
22
|
import {
|
|
21
23
|
SprintSchema,
|
|
22
24
|
getSprintFilePath,
|
|
23
25
|
readValidatedJson,
|
|
24
26
|
writeValidatedJson
|
|
25
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-W3TY22IS.mjs";
|
|
28
|
+
import {
|
|
29
|
+
IOError,
|
|
30
|
+
IssueFetchError,
|
|
31
|
+
SprintStatusError,
|
|
32
|
+
TicketNotFoundError
|
|
33
|
+
} from "./chunk-EDJX7TT6.mjs";
|
|
26
34
|
import {
|
|
27
35
|
createSpinner,
|
|
28
36
|
emoji,
|
|
@@ -41,9 +49,11 @@ import {
|
|
|
41
49
|
|
|
42
50
|
// src/commands/ticket/add.ts
|
|
43
51
|
import { confirm, input, select as select2 } from "@inquirer/prompts";
|
|
52
|
+
import { Result as Result3 } from "typescript-result";
|
|
44
53
|
|
|
45
54
|
// src/utils/editor-input.ts
|
|
46
55
|
import { editor } from "@inquirer/prompts";
|
|
56
|
+
import { Result } from "typescript-result";
|
|
47
57
|
|
|
48
58
|
// src/utils/editor.ts
|
|
49
59
|
import { select } from "@inquirer/prompts";
|
|
@@ -77,7 +87,8 @@ async function resolveEditor() {
|
|
|
77
87
|
async function editorInput(options) {
|
|
78
88
|
if (!process.stdin.isTTY) {
|
|
79
89
|
const { multilineInput } = await import("./multiline-OHSNFCRG.mjs");
|
|
80
|
-
|
|
90
|
+
const value = await multilineInput({ message: options.message, default: options.default });
|
|
91
|
+
return Result.ok(value);
|
|
81
92
|
}
|
|
82
93
|
const editorCmd = await resolveEditor();
|
|
83
94
|
const prevVisual = process.env["VISUAL"];
|
|
@@ -88,7 +99,14 @@ async function editorInput(options) {
|
|
|
88
99
|
default: options.default,
|
|
89
100
|
postfix: ".md"
|
|
90
101
|
});
|
|
91
|
-
return result.trim();
|
|
102
|
+
return Result.ok(result.trim());
|
|
103
|
+
} catch (err) {
|
|
104
|
+
return Result.error(
|
|
105
|
+
new IOError(
|
|
106
|
+
`Editor failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
107
|
+
err instanceof Error ? err : void 0
|
|
108
|
+
)
|
|
109
|
+
);
|
|
92
110
|
} finally {
|
|
93
111
|
if (prevVisual === void 0) delete process.env["VISUAL"];
|
|
94
112
|
else process.env["VISUAL"] = prevVisual;
|
|
@@ -96,33 +114,21 @@ async function editorInput(options) {
|
|
|
96
114
|
}
|
|
97
115
|
|
|
98
116
|
// src/store/ticket.ts
|
|
99
|
-
var TicketNotFoundError = class extends Error {
|
|
100
|
-
ticketId;
|
|
101
|
-
constructor(ticketId) {
|
|
102
|
-
super(`Ticket not found: ${ticketId}`);
|
|
103
|
-
this.name = "TicketNotFoundError";
|
|
104
|
-
this.ticketId = ticketId;
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
117
|
async function getSprintData(sprintId) {
|
|
108
118
|
const id = await resolveSprintId(sprintId);
|
|
109
|
-
|
|
119
|
+
const result = await readValidatedJson(getSprintFilePath(id), SprintSchema);
|
|
120
|
+
if (!result.ok) throw result.error;
|
|
121
|
+
return result.value;
|
|
110
122
|
}
|
|
111
123
|
async function saveSprintData(sprint) {
|
|
112
|
-
await writeValidatedJson(getSprintFilePath(sprint.id), sprint, SprintSchema);
|
|
124
|
+
const result = await writeValidatedJson(getSprintFilePath(sprint.id), sprint, SprintSchema);
|
|
125
|
+
if (!result.ok) throw result.error;
|
|
113
126
|
}
|
|
114
127
|
async function addTicket(input2, sprintId) {
|
|
115
128
|
const sprint = await getSprintData(sprintId);
|
|
116
129
|
assertSprintStatus(sprint, ["draft"], "add tickets");
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
} catch (err) {
|
|
120
|
-
if (err instanceof ProjectNotFoundError) {
|
|
121
|
-
throw new Error(`Project '${input2.projectName}' does not exist. Add it first with 'ralphctl project add'.`, {
|
|
122
|
-
cause: err
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
throw err;
|
|
130
|
+
if (!await projectExists(input2.projectName)) {
|
|
131
|
+
throw new Error(`Project '${input2.projectName}' does not exist. Add it first with 'ralphctl project add'.`);
|
|
126
132
|
}
|
|
127
133
|
const ticket = {
|
|
128
134
|
id: generateUuid8(),
|
|
@@ -205,6 +211,7 @@ function formatTicketId(ticket) {
|
|
|
205
211
|
|
|
206
212
|
// src/utils/issue-fetch.ts
|
|
207
213
|
import { spawnSync } from "child_process";
|
|
214
|
+
import { Result as Result2 } from "typescript-result";
|
|
208
215
|
var MAX_COMMENTS = 20;
|
|
209
216
|
function parseIssueUrl(url) {
|
|
210
217
|
let parsed;
|
|
@@ -241,7 +248,7 @@ function parseIssueUrl(url) {
|
|
|
241
248
|
}
|
|
242
249
|
return null;
|
|
243
250
|
}
|
|
244
|
-
function
|
|
251
|
+
function fetchGitHubIssueResult(parsed) {
|
|
245
252
|
const result = spawnSync(
|
|
246
253
|
"gh",
|
|
247
254
|
[
|
|
@@ -257,7 +264,7 @@ function fetchGitHubIssue(parsed) {
|
|
|
257
264
|
);
|
|
258
265
|
if (result.status !== 0) {
|
|
259
266
|
const stderr = result.stderr.trim();
|
|
260
|
-
|
|
267
|
+
return Result2.error(new IssueFetchError(`gh issue view failed: ${stderr || "unknown error"}`));
|
|
261
268
|
}
|
|
262
269
|
const data = JSON.parse(result.stdout);
|
|
263
270
|
const comments = (data.comments ?? []).slice(-MAX_COMMENTS).map((c) => ({
|
|
@@ -265,14 +272,14 @@ function fetchGitHubIssue(parsed) {
|
|
|
265
272
|
createdAt: c.createdAt ?? "",
|
|
266
273
|
body: c.body ?? ""
|
|
267
274
|
}));
|
|
268
|
-
return {
|
|
275
|
+
return Result2.ok({
|
|
269
276
|
title: data.title ?? "",
|
|
270
277
|
body: data.body ?? "",
|
|
271
278
|
comments,
|
|
272
279
|
url: `https://${parsed.hostname}/${parsed.owner}/${parsed.repo}/issues/${String(parsed.number)}`
|
|
273
|
-
};
|
|
280
|
+
});
|
|
274
281
|
}
|
|
275
|
-
function
|
|
282
|
+
function fetchGitLabIssueResult(parsed) {
|
|
276
283
|
const result = spawnSync(
|
|
277
284
|
"glab",
|
|
278
285
|
["issue", "view", String(parsed.number), "--repo", `${parsed.owner}/${parsed.repo}`, "--output", "json"],
|
|
@@ -280,7 +287,7 @@ function fetchGitLabIssue(parsed) {
|
|
|
280
287
|
);
|
|
281
288
|
if (result.status !== 0) {
|
|
282
289
|
const stderr = result.stderr.trim();
|
|
283
|
-
|
|
290
|
+
return Result2.error(new IssueFetchError(`glab issue view failed: ${stderr || "unknown error"}`));
|
|
284
291
|
}
|
|
285
292
|
const data = JSON.parse(result.stdout);
|
|
286
293
|
const notesResult = spawnSync(
|
|
@@ -300,18 +307,21 @@ function fetchGitLabIssue(parsed) {
|
|
|
300
307
|
} catch {
|
|
301
308
|
}
|
|
302
309
|
}
|
|
303
|
-
return {
|
|
310
|
+
return Result2.ok({
|
|
304
311
|
title: data.title ?? "",
|
|
305
312
|
body: data.description ?? "",
|
|
306
313
|
comments,
|
|
307
314
|
url: `https://${parsed.hostname}/${parsed.owner}/${parsed.repo}/-/issues/${String(parsed.number)}`
|
|
308
|
-
};
|
|
315
|
+
});
|
|
309
316
|
}
|
|
310
|
-
function
|
|
317
|
+
function fetchIssueResult(parsed) {
|
|
311
318
|
if (parsed.host === "github") {
|
|
312
|
-
return
|
|
319
|
+
return fetchGitHubIssueResult(parsed);
|
|
313
320
|
}
|
|
314
|
-
return
|
|
321
|
+
return fetchGitLabIssueResult(parsed);
|
|
322
|
+
}
|
|
323
|
+
function fetchIssue(parsed) {
|
|
324
|
+
return unwrapOrThrow(fetchIssueResult(parsed));
|
|
315
325
|
}
|
|
316
326
|
function fetchIssueFromUrl(url) {
|
|
317
327
|
const parsed = parseIssueUrl(url);
|
|
@@ -346,30 +356,19 @@ function formatIssueContext(data) {
|
|
|
346
356
|
}
|
|
347
357
|
return lines.join("\n");
|
|
348
358
|
}
|
|
349
|
-
var IssueFetchError = class extends Error {
|
|
350
|
-
constructor(message) {
|
|
351
|
-
super(message);
|
|
352
|
-
this.name = "IssueFetchError";
|
|
353
|
-
}
|
|
354
|
-
};
|
|
355
359
|
|
|
356
360
|
// src/commands/ticket/add.ts
|
|
357
361
|
function tryFetchIssue(url) {
|
|
358
362
|
const spinner = createSpinner("Fetching issue data...");
|
|
359
363
|
spinner.start();
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
data = fetchIssueFromUrl(url);
|
|
363
|
-
} catch (err) {
|
|
364
|
+
const fetchR = Result3.try(() => fetchIssueFromUrl(url));
|
|
365
|
+
if (!fetchR.ok) {
|
|
364
366
|
spinner.fail("Could not fetch issue data");
|
|
365
|
-
|
|
366
|
-
showWarning(err.message);
|
|
367
|
-
} else if (err instanceof Error) {
|
|
368
|
-
showWarning(err.message);
|
|
369
|
-
}
|
|
367
|
+
showWarning(fetchR.error.message);
|
|
370
368
|
log.newline();
|
|
371
369
|
return void 0;
|
|
372
370
|
}
|
|
371
|
+
const data = fetchR.value;
|
|
373
372
|
if (!data) {
|
|
374
373
|
spinner.stop();
|
|
375
374
|
return void 0;
|
|
@@ -422,17 +421,12 @@ async function addSingleTicketNonInteractive(options) {
|
|
|
422
421
|
const trimmedLink = options.link?.trim();
|
|
423
422
|
const link = trimmedLink === "" ? void 0 : trimmedLink;
|
|
424
423
|
const projectName = trimmedProject;
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
link,
|
|
430
|
-
projectName
|
|
431
|
-
});
|
|
432
|
-
showTicketResult(ticket);
|
|
433
|
-
} catch (err) {
|
|
434
|
-
handleTicketError(err);
|
|
424
|
+
const addR = await wrapAsync(() => addTicket({ title, description, link, projectName }), ensureError);
|
|
425
|
+
if (!addR.ok) {
|
|
426
|
+
handleTicketError(addR.error);
|
|
427
|
+
return;
|
|
435
428
|
}
|
|
429
|
+
showTicketResult(addR.value);
|
|
436
430
|
}
|
|
437
431
|
async function addSingleTicketInteractive(options) {
|
|
438
432
|
const projects = await listProjects();
|
|
@@ -467,26 +461,28 @@ async function addSingleTicketInteractive(options) {
|
|
|
467
461
|
default: prefill?.title ?? options.title?.trim(),
|
|
468
462
|
validate: (v) => v.trim().length > 0 ? true : "Title is required"
|
|
469
463
|
});
|
|
470
|
-
const
|
|
464
|
+
const descR = await editorInput({
|
|
471
465
|
message: "Description (recommended):",
|
|
472
466
|
default: prefill?.body ?? options.description?.trim()
|
|
473
467
|
});
|
|
468
|
+
if (!descR.ok) {
|
|
469
|
+
showError(`Editor input failed: ${descR.error.message}`);
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
472
|
+
const description = descR.value;
|
|
474
473
|
title = title.trim();
|
|
475
474
|
const trimmedDescription = description.trim();
|
|
476
475
|
const normalizedDescription = trimmedDescription === "" ? void 0 : trimmedDescription;
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
});
|
|
484
|
-
showTicketResult(ticket);
|
|
485
|
-
return ticket;
|
|
486
|
-
} catch (err) {
|
|
487
|
-
handleTicketError(err);
|
|
476
|
+
const addR = await wrapAsync(
|
|
477
|
+
() => addTicket({ title, description: normalizedDescription, link: normalizedLink, projectName }),
|
|
478
|
+
ensureError
|
|
479
|
+
);
|
|
480
|
+
if (!addR.ok) {
|
|
481
|
+
handleTicketError(addR.error);
|
|
488
482
|
return null;
|
|
489
483
|
}
|
|
484
|
+
showTicketResult(addR.value);
|
|
485
|
+
return addR.value;
|
|
490
486
|
}
|
|
491
487
|
function showTicketResult(ticket) {
|
|
492
488
|
showSuccess("Ticket added!", [
|
|
@@ -536,7 +532,6 @@ async function ticketAddCommand(options = {}) {
|
|
|
536
532
|
}
|
|
537
533
|
|
|
538
534
|
export {
|
|
539
|
-
TicketNotFoundError,
|
|
540
535
|
addTicket,
|
|
541
536
|
updateTicket,
|
|
542
537
|
removeTicket,
|
|
@@ -550,7 +545,6 @@ export {
|
|
|
550
545
|
editorInput,
|
|
551
546
|
fetchIssueFromUrl,
|
|
552
547
|
formatIssueContext,
|
|
553
|
-
IssueFetchError,
|
|
554
548
|
addSingleTicketInteractive,
|
|
555
549
|
ticketAddCommand
|
|
556
550
|
};
|