ralphctl 0.2.5 → 0.3.1

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 (55) hide show
  1. package/dist/add-CIM72NE3.mjs +18 -0
  2. package/dist/add-GX7P7XTT.mjs +16 -0
  3. package/dist/bootstrap-FMHG6DRY.mjs +11 -0
  4. package/dist/chunk-3QBEBKMZ.mjs +103 -0
  5. package/dist/{chunk-EDJX7TT6.mjs → chunk-57UWLHRH.mjs} +22 -2
  6. package/dist/chunk-747KW2RW.mjs +24 -0
  7. package/dist/chunk-7JLZQICD.mjs +228 -0
  8. package/dist/{chunk-7TG3EAQ2.mjs → chunk-CFUVE2BP.mjs} +1 -5
  9. package/dist/chunk-CSC4TBJB.mjs +5546 -0
  10. package/dist/{chunk-IB6OCKZW.mjs → chunk-CTP2A436.mjs} +60 -55
  11. package/dist/{chunk-UBPZHHCD.mjs → chunk-D2YGPLIV.mjs} +84 -41
  12. package/dist/chunk-EPDR6VO5.mjs +5109 -0
  13. package/dist/{chunk-QBXHAXHI.mjs → chunk-FKMKOWLA.mjs} +154 -208
  14. package/dist/{chunk-OEUJDSHY.mjs → chunk-IWXBJD2D.mjs} +1 -1
  15. package/dist/chunk-JOQO4HMM.mjs +269 -0
  16. package/dist/{chunk-EUNAUHC3.mjs → chunk-NUYQK5MN.mjs} +80 -29
  17. package/dist/{chunk-JRFOUFD3.mjs → chunk-YCDUVPRT.mjs} +32 -52
  18. package/dist/cli.mjs +171 -3996
  19. package/dist/create-7WFSCMP4.mjs +15 -0
  20. package/dist/{handle-TA4MYNQJ.mjs → handle-BBAZJ44Y.mjs} +2 -2
  21. package/dist/mount-U7QXVB5Q.mjs +6804 -0
  22. package/dist/{project-YONEJICR.mjs → project-2IE7VWDB.mjs} +9 -5
  23. package/dist/prompts/harness-context.md +3 -3
  24. package/dist/prompts/ideate-auto.md +8 -10
  25. package/dist/prompts/ideate.md +3 -2
  26. package/dist/prompts/plan-auto.md +12 -12
  27. package/dist/prompts/plan-common.md +47 -19
  28. package/dist/prompts/plan-interactive.md +8 -8
  29. package/dist/prompts/signals-evaluation.md +1 -1
  30. package/dist/prompts/sprint-feedback.md +48 -0
  31. package/dist/prompts/task-evaluation-resume.md +12 -5
  32. package/dist/prompts/task-evaluation.md +37 -33
  33. package/dist/prompts/task-execution.md +33 -24
  34. package/dist/prompts/ticket-refine.md +6 -5
  35. package/dist/prompts/validation-checklist.md +10 -10
  36. package/dist/{resolver-RXEY6EJE.mjs → resolver-EOE5WUMV.mjs} +5 -5
  37. package/dist/{sprint-FGLWYWKX.mjs → sprint-OGOFEJJH.mjs} +7 -9
  38. package/dist/start-WG7VMEB2.mjs +17 -0
  39. package/package.json +15 -13
  40. package/dist/add-3T225IX5.mjs +0 -16
  41. package/dist/add-6A5432U2.mjs +0 -16
  42. package/dist/chunk-742XQ7FL.mjs +0 -551
  43. package/dist/chunk-7LZ6GOGN.mjs +0 -53
  44. package/dist/chunk-CSICORGV.mjs +0 -4333
  45. package/dist/chunk-DUU5346E.mjs +0 -59
  46. package/dist/create-MYGOWO2F.mjs +0 -12
  47. package/dist/multiline-OHSNFCRG.mjs +0 -40
  48. package/dist/wizard-XZ7OGBCJ.mjs +0 -193
  49. package/schemas/config.schema.json +0 -30
  50. package/schemas/ideate-output.schema.json +0 -22
  51. package/schemas/projects.schema.json +0 -58
  52. package/schemas/requirements-output.schema.json +0 -24
  53. package/schemas/sprint.schema.json +0 -109
  54. package/schemas/task-import.schema.json +0 -56
  55. package/schemas/tasks.schema.json +0 -98
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ addSingleTicketInteractive,
4
+ ticketAddCommand
5
+ } from "./chunk-7JLZQICD.mjs";
6
+ import "./chunk-NUYQK5MN.mjs";
7
+ import "./chunk-JOQO4HMM.mjs";
8
+ import "./chunk-CFUVE2BP.mjs";
9
+ import "./chunk-747KW2RW.mjs";
10
+ import "./chunk-YCDUVPRT.mjs";
11
+ import "./chunk-FKMKOWLA.mjs";
12
+ import "./chunk-IWXBJD2D.mjs";
13
+ import "./chunk-CTP2A436.mjs";
14
+ import "./chunk-57UWLHRH.mjs";
15
+ export {
16
+ addSingleTicketInteractive,
17
+ ticketAddCommand
18
+ };
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ addCheckScriptToRepository,
4
+ projectAddCommand
5
+ } from "./chunk-D2YGPLIV.mjs";
6
+ import "./chunk-NUYQK5MN.mjs";
7
+ import "./chunk-CFUVE2BP.mjs";
8
+ import "./chunk-747KW2RW.mjs";
9
+ import "./chunk-FKMKOWLA.mjs";
10
+ import "./chunk-IWXBJD2D.mjs";
11
+ import "./chunk-CTP2A436.mjs";
12
+ import "./chunk-57UWLHRH.mjs";
13
+ export {
14
+ addCheckScriptToRepository,
15
+ projectAddCommand
16
+ };
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ getPrompt,
4
+ getSharedDeps,
5
+ setSharedDeps
6
+ } from "./chunk-747KW2RW.mjs";
7
+ export {
8
+ getPrompt,
9
+ getSharedDeps,
10
+ setSharedDeps
11
+ };
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ listProjects
4
+ } from "./chunk-NUYQK5MN.mjs";
5
+ import {
6
+ EXIT_ERROR,
7
+ exitWithCode
8
+ } from "./chunk-CFUVE2BP.mjs";
9
+ import {
10
+ getPrompt
11
+ } from "./chunk-747KW2RW.mjs";
12
+ import {
13
+ createSprint,
14
+ setCurrentSprint
15
+ } from "./chunk-YCDUVPRT.mjs";
16
+ import {
17
+ emoji,
18
+ field,
19
+ formatSprintStatus,
20
+ icons,
21
+ showError,
22
+ showNextStep,
23
+ showRandomQuote,
24
+ showSuccess
25
+ } from "./chunk-FKMKOWLA.mjs";
26
+
27
+ // src/integration/cli/commands/sprint/create.ts
28
+ async function sprintCreateCommand(options = {}) {
29
+ const projects = await listProjects();
30
+ if (projects.length === 0) {
31
+ showError("No projects configured.");
32
+ showNextStep("ralphctl project add", "add a project first");
33
+ if (options.interactive === false) exitWithCode(EXIT_ERROR);
34
+ return;
35
+ }
36
+ let projectId;
37
+ const projectFlag = options.project?.trim();
38
+ if (projectFlag) {
39
+ const match = projects.find((p) => p.name === projectFlag || p.id === projectFlag);
40
+ if (!match) {
41
+ showError(`Project not found: ${projectFlag}`);
42
+ if (options.interactive === false) exitWithCode(EXIT_ERROR);
43
+ return;
44
+ }
45
+ projectId = match.id;
46
+ } else if (options.interactive === false) {
47
+ showError("--project is required in non-interactive mode");
48
+ exitWithCode(EXIT_ERROR);
49
+ } else if (projects.length === 1 && projects[0]) {
50
+ projectId = projects[0].id;
51
+ } else {
52
+ projectId = await getPrompt().select({
53
+ message: `${icons.project} Project:`,
54
+ choices: projects.map((p) => ({ label: p.displayName, value: p.id, description: p.description }))
55
+ });
56
+ }
57
+ if (!projectId) {
58
+ showError("No project selected.");
59
+ return;
60
+ }
61
+ const pickedProject = projects.find((p) => p.id === projectId);
62
+ let name;
63
+ if (options.interactive === false) {
64
+ const trimmed = options.name?.trim();
65
+ name = trimmed && trimmed.length > 0 ? trimmed : void 0;
66
+ } else {
67
+ const inputName = await getPrompt().input({
68
+ message: `${icons.sprint} Sprint name (optional):`,
69
+ default: options.name?.trim()
70
+ });
71
+ const trimmed = inputName.trim();
72
+ name = trimmed.length > 0 ? trimmed : void 0;
73
+ }
74
+ const sprint = await createSprint({ projectId, name });
75
+ let setAsCurrent = true;
76
+ if (options.interactive) {
77
+ setAsCurrent = await getPrompt().confirm({
78
+ message: `${emoji.donut} Set as current sprint?`,
79
+ default: true
80
+ });
81
+ }
82
+ if (setAsCurrent) {
83
+ await setCurrentSprint(sprint.id);
84
+ }
85
+ showSuccess("Sprint created!", [
86
+ ["ID", sprint.id],
87
+ ["Name", sprint.name],
88
+ ["Project", pickedProject ? `${pickedProject.displayName} (${pickedProject.name})` : projectId],
89
+ ["Status", formatSprintStatus(sprint.status)]
90
+ ]);
91
+ showRandomQuote();
92
+ if (setAsCurrent) {
93
+ console.log(field("Current", "Yes (this sprint is now active target)"));
94
+ showNextStep("ralphctl ticket add", "add tickets to this sprint");
95
+ } else {
96
+ console.log(field("Current", "No"));
97
+ showNextStep(`ralphctl sprint current ${sprint.id}`, "set as current later");
98
+ }
99
+ }
100
+
101
+ export {
102
+ sprintCreateCommand
103
+ };
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // src/errors.ts
3
+ // src/domain/errors.ts
4
4
  var DomainError = class extends Error {
5
5
  cause;
6
6
  constructor(message, cause) {
@@ -127,6 +127,24 @@ var DependencyCycleError = class extends DomainError {
127
127
  var IssueFetchError = class extends DomainError {
128
128
  code = "ISSUE_FETCH_ERROR";
129
129
  };
130
+ var StepError = class extends DomainError {
131
+ code = "STEP_ERROR";
132
+ stepName;
133
+ constructor(message, stepName, cause) {
134
+ super(message, cause);
135
+ this.stepName = stepName;
136
+ }
137
+ };
138
+ var BranchPreflightError = class extends DomainError {
139
+ code = "BRANCH_PREFLIGHT_ERROR";
140
+ projectPath;
141
+ expectedBranch;
142
+ constructor(projectPath, expectedBranch, cause) {
143
+ super(`Branch verification failed: expected '${expectedBranch}' in ${projectPath}`, cause);
144
+ this.projectPath = projectPath;
145
+ this.expectedBranch = expectedBranch;
146
+ }
147
+ };
130
148
 
131
149
  export {
132
150
  DomainError,
@@ -144,5 +162,7 @@ export {
144
162
  SprintStatusError,
145
163
  NoCurrentSprintError,
146
164
  DependencyCycleError,
147
- IssueFetchError
165
+ IssueFetchError,
166
+ StepError,
167
+ BranchPreflightError
148
168
  };
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/integration/bootstrap.ts
4
+ var _shared = null;
5
+ function getSharedDeps() {
6
+ if (!_shared) {
7
+ throw new Error(
8
+ "SharedDeps not initialised \u2014 the application entrypoint must call setSharedDeps() before any CLI command runs."
9
+ );
10
+ }
11
+ return _shared;
12
+ }
13
+ function setSharedDeps(deps) {
14
+ _shared = deps;
15
+ }
16
+ function getPrompt() {
17
+ return getSharedDeps().prompt;
18
+ }
19
+
20
+ export {
21
+ getSharedDeps,
22
+ setSharedDeps,
23
+ getPrompt
24
+ };
@@ -0,0 +1,228 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ getProjectById
4
+ } from "./chunk-NUYQK5MN.mjs";
5
+ import {
6
+ addTicket,
7
+ fetchIssueFromUrl,
8
+ truncate
9
+ } from "./chunk-JOQO4HMM.mjs";
10
+ import {
11
+ EXIT_ERROR,
12
+ exitWithCode
13
+ } from "./chunk-CFUVE2BP.mjs";
14
+ import {
15
+ getPrompt
16
+ } from "./chunk-747KW2RW.mjs";
17
+ import {
18
+ getCurrentSprintOrThrow
19
+ } from "./chunk-YCDUVPRT.mjs";
20
+ import {
21
+ createSpinner,
22
+ emoji,
23
+ error,
24
+ field,
25
+ fieldMultiline,
26
+ icons,
27
+ log,
28
+ renderCard,
29
+ showError,
30
+ showSuccess,
31
+ showWarning
32
+ } from "./chunk-FKMKOWLA.mjs";
33
+ import {
34
+ ensureError,
35
+ wrapAsync
36
+ } from "./chunk-IWXBJD2D.mjs";
37
+ import {
38
+ IOError,
39
+ SprintStatusError
40
+ } from "./chunk-57UWLHRH.mjs";
41
+
42
+ // src/integration/cli/commands/ticket/add.ts
43
+ import { Result as Result2 } from "typescript-result";
44
+
45
+ // src/integration/ui/prompts/editor-input.ts
46
+ import { Result } from "typescript-result";
47
+ async function editorInput(options) {
48
+ try {
49
+ const result = await getPrompt().editor({
50
+ message: options.message,
51
+ default: options.default,
52
+ kind: "markdown"
53
+ });
54
+ if (result === null) {
55
+ return Result.error(new IOError("Editor cancelled"));
56
+ }
57
+ return Result.ok(result);
58
+ } catch (err) {
59
+ return Result.error(
60
+ new IOError(
61
+ `Editor failed: ${err instanceof Error ? err.message : String(err)}`,
62
+ err instanceof Error ? err : void 0
63
+ )
64
+ );
65
+ }
66
+ }
67
+
68
+ // src/integration/cli/commands/ticket/add.ts
69
+ function tryFetchIssue(url) {
70
+ const spinner = createSpinner("Fetching issue data...");
71
+ spinner.start();
72
+ const fetchR = Result2.try(() => fetchIssueFromUrl(url));
73
+ if (!fetchR.ok) {
74
+ spinner.fail("Could not fetch issue data");
75
+ showWarning(fetchR.error.message);
76
+ log.newline();
77
+ return void 0;
78
+ }
79
+ const data = fetchR.value;
80
+ if (!data) {
81
+ spinner.stop();
82
+ return void 0;
83
+ }
84
+ spinner.succeed("Issue data fetched");
85
+ log.newline();
86
+ const bodyPreview = truncate(data.body, 200);
87
+ const cardLines = [`Title: ${data.title}`, "", bodyPreview];
88
+ if (data.comments.length > 0) {
89
+ cardLines.push("", `${String(data.comments.length)} comment(s)`);
90
+ }
91
+ console.log(renderCard(`${icons.info} Fetched Issue`, cardLines));
92
+ log.newline();
93
+ return data;
94
+ }
95
+ function validateUrl(url) {
96
+ try {
97
+ new URL(url);
98
+ return true;
99
+ } catch {
100
+ return false;
101
+ }
102
+ }
103
+ async function addSingleTicketNonInteractive(options) {
104
+ const errors = [];
105
+ const trimmedTitle = options.title?.trim();
106
+ if (!trimmedTitle) {
107
+ errors.push("--title is required");
108
+ }
109
+ if (options.link && !validateUrl(options.link)) {
110
+ errors.push("--link must be a valid URL");
111
+ }
112
+ if (errors.length > 0 || !trimmedTitle) {
113
+ showError("Validation failed");
114
+ for (const e of errors) {
115
+ log.item(error(e));
116
+ }
117
+ log.newline();
118
+ exitWithCode(EXIT_ERROR);
119
+ }
120
+ const title = trimmedTitle;
121
+ const trimmedDesc = options.description?.trim();
122
+ const description = trimmedDesc === "" ? void 0 : trimmedDesc;
123
+ const trimmedLink = options.link?.trim();
124
+ const link = trimmedLink === "" ? void 0 : trimmedLink;
125
+ const addR = await wrapAsync(() => addTicket({ title, description, link }), ensureError);
126
+ if (!addR.ok) {
127
+ handleTicketError(addR.error);
128
+ return;
129
+ }
130
+ await showTicketResult(addR.value);
131
+ }
132
+ async function addSingleTicketInteractive(options) {
133
+ const link = await getPrompt().input({
134
+ message: `${icons.info} Issue link (optional):`,
135
+ default: options.link?.trim(),
136
+ validate: (v) => {
137
+ if (!v) return true;
138
+ return validateUrl(v) ? true : "Invalid URL format";
139
+ }
140
+ });
141
+ const trimmedLink = link.trim();
142
+ const normalizedLink = trimmedLink === "" ? void 0 : trimmedLink;
143
+ let prefill;
144
+ if (normalizedLink) {
145
+ prefill = tryFetchIssue(normalizedLink);
146
+ }
147
+ let title = await getPrompt().input({
148
+ message: `${icons.ticket} Title:`,
149
+ default: prefill?.title ?? options.title?.trim(),
150
+ validate: (v) => v.trim().length > 0 ? true : "Title is required"
151
+ });
152
+ const descR = await editorInput({
153
+ message: "Description (recommended):",
154
+ default: prefill?.body ?? options.description?.trim()
155
+ });
156
+ if (!descR.ok) {
157
+ showError(`Editor input failed: ${descR.error.message}`);
158
+ return null;
159
+ }
160
+ const description = descR.value;
161
+ title = title.trim();
162
+ const trimmedDescription = description.trim();
163
+ const normalizedDescription = trimmedDescription === "" ? void 0 : trimmedDescription;
164
+ const addR = await wrapAsync(
165
+ () => addTicket({ title, description: normalizedDescription, link: normalizedLink }),
166
+ ensureError
167
+ );
168
+ if (!addR.ok) {
169
+ handleTicketError(addR.error);
170
+ return null;
171
+ }
172
+ await showTicketResult(addR.value);
173
+ return addR.value;
174
+ }
175
+ async function showTicketResult(ticket) {
176
+ const sprintR = await wrapAsync(() => getCurrentSprintOrThrow(), ensureError);
177
+ const projectLabel = sprintR.ok ? await wrapAsync(() => getProjectById(sprintR.value.projectId), ensureError).then(
178
+ (r) => r.ok ? `${r.value.displayName} (${r.value.name})` : sprintR.value.projectId
179
+ ) : "unknown";
180
+ showSuccess("Ticket added!", [
181
+ ["ID", ticket.id],
182
+ ["Title", ticket.title],
183
+ ["Project", projectLabel]
184
+ ]);
185
+ if (ticket.description) {
186
+ console.log(fieldMultiline("Description", ticket.description));
187
+ }
188
+ if (ticket.link) {
189
+ console.log(field("Link", ticket.link));
190
+ }
191
+ console.log("");
192
+ }
193
+ function handleTicketError(err) {
194
+ if (err instanceof SprintStatusError) {
195
+ showError(err.message);
196
+ } else if (err instanceof Error && err.message.includes("does not exist")) {
197
+ showError(err.message);
198
+ } else {
199
+ throw err;
200
+ }
201
+ }
202
+ async function ticketAddCommand(options = {}) {
203
+ if (options.interactive === false) {
204
+ await addSingleTicketNonInteractive(options);
205
+ return;
206
+ }
207
+ let count = 0;
208
+ while (true) {
209
+ const ticket = await addSingleTicketInteractive(options);
210
+ if (ticket) {
211
+ count++;
212
+ log.dim(`${String(count)} ticket(s) added in this session`);
213
+ } else {
214
+ break;
215
+ }
216
+ const another = await getPrompt().confirm({
217
+ message: `${emoji.donut} Add another ticket?`,
218
+ default: true
219
+ });
220
+ if (!another) break;
221
+ }
222
+ }
223
+
224
+ export {
225
+ editorInput,
226
+ addSingleTicketInteractive,
227
+ ticketAddCommand
228
+ };
@@ -1,20 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // src/utils/exit-codes.ts
4
- var EXIT_SUCCESS = 0;
3
+ // src/domain/exit-codes.ts
5
4
  var EXIT_ERROR = 1;
6
5
  var EXIT_NO_TASKS = 2;
7
- var EXIT_ALL_BLOCKED = 3;
8
6
  var EXIT_INTERRUPTED = 130;
9
7
  function exitWithCode(code) {
10
8
  process.exit(code);
11
9
  }
12
10
 
13
11
  export {
14
- EXIT_SUCCESS,
15
12
  EXIT_ERROR,
16
13
  EXIT_NO_TASKS,
17
- EXIT_ALL_BLOCKED,
18
14
  EXIT_INTERRUPTED,
19
15
  exitWithCode
20
16
  };