ralphctl 0.1.0 → 0.1.2

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 (130) hide show
  1. package/README.md +58 -24
  2. package/dist/add-HGJCLWED.mjs +14 -0
  3. package/dist/add-MRGCS3US.mjs +14 -0
  4. package/dist/chunk-6PYTKGB5.mjs +316 -0
  5. package/dist/chunk-7TG3EAQ2.mjs +20 -0
  6. package/dist/chunk-EKMZZRWI.mjs +521 -0
  7. package/dist/chunk-JON4GCLR.mjs +59 -0
  8. package/dist/chunk-LOR7QBXX.mjs +3683 -0
  9. package/dist/chunk-MNMQC36F.mjs +556 -0
  10. package/dist/chunk-MRKOFVTM.mjs +537 -0
  11. package/dist/chunk-NTWO2LXB.mjs +52 -0
  12. package/dist/chunk-QBXHAXHI.mjs +562 -0
  13. package/dist/chunk-WGHJI3OI.mjs +214 -0
  14. package/dist/cli.mjs +4245 -0
  15. package/dist/create-MG7E7PLQ.mjs +10 -0
  16. package/dist/handle-UG5M2OON.mjs +22 -0
  17. package/dist/multiline-OHSNFCRG.mjs +40 -0
  18. package/dist/project-NT3L4FTB.mjs +28 -0
  19. package/dist/resolver-WSFWKACM.mjs +153 -0
  20. package/dist/sprint-4VHDLGFN.mjs +37 -0
  21. package/dist/wizard-LRELAN2J.mjs +196 -0
  22. package/package.json +19 -28
  23. package/CHANGELOG.md +0 -94
  24. package/bin/ralphctl +0 -13
  25. package/src/ai/executor.ts +0 -973
  26. package/src/ai/lifecycle.ts +0 -45
  27. package/src/ai/parser.ts +0 -40
  28. package/src/ai/permissions.ts +0 -207
  29. package/src/ai/process-manager.ts +0 -248
  30. package/src/ai/prompts/index.ts +0 -89
  31. package/src/ai/rate-limiter.ts +0 -89
  32. package/src/ai/runner.ts +0 -478
  33. package/src/ai/session.ts +0 -319
  34. package/src/ai/task-context.ts +0 -270
  35. package/src/cli-metadata.ts +0 -7
  36. package/src/cli.ts +0 -65
  37. package/src/commands/completion/index.ts +0 -33
  38. package/src/commands/config/config.ts +0 -58
  39. package/src/commands/config/index.ts +0 -33
  40. package/src/commands/dashboard/dashboard.ts +0 -5
  41. package/src/commands/dashboard/index.ts +0 -6
  42. package/src/commands/doctor/doctor.ts +0 -271
  43. package/src/commands/doctor/index.ts +0 -25
  44. package/src/commands/progress/index.ts +0 -25
  45. package/src/commands/progress/log.ts +0 -64
  46. package/src/commands/progress/show.ts +0 -14
  47. package/src/commands/project/add.ts +0 -336
  48. package/src/commands/project/index.ts +0 -104
  49. package/src/commands/project/list.ts +0 -31
  50. package/src/commands/project/remove.ts +0 -43
  51. package/src/commands/project/repo.ts +0 -118
  52. package/src/commands/project/show.ts +0 -49
  53. package/src/commands/sprint/close.ts +0 -180
  54. package/src/commands/sprint/context.ts +0 -109
  55. package/src/commands/sprint/create.ts +0 -60
  56. package/src/commands/sprint/current.ts +0 -75
  57. package/src/commands/sprint/delete.ts +0 -72
  58. package/src/commands/sprint/health.ts +0 -229
  59. package/src/commands/sprint/ideate.ts +0 -496
  60. package/src/commands/sprint/index.ts +0 -226
  61. package/src/commands/sprint/list.ts +0 -86
  62. package/src/commands/sprint/plan-utils.ts +0 -207
  63. package/src/commands/sprint/plan.ts +0 -549
  64. package/src/commands/sprint/refine.ts +0 -359
  65. package/src/commands/sprint/requirements.ts +0 -58
  66. package/src/commands/sprint/show.ts +0 -140
  67. package/src/commands/sprint/start.ts +0 -119
  68. package/src/commands/sprint/switch.ts +0 -20
  69. package/src/commands/task/add.ts +0 -316
  70. package/src/commands/task/import.ts +0 -150
  71. package/src/commands/task/index.ts +0 -123
  72. package/src/commands/task/list.ts +0 -145
  73. package/src/commands/task/next.ts +0 -45
  74. package/src/commands/task/remove.ts +0 -47
  75. package/src/commands/task/reorder.ts +0 -45
  76. package/src/commands/task/show.ts +0 -111
  77. package/src/commands/task/status.ts +0 -99
  78. package/src/commands/ticket/add.ts +0 -265
  79. package/src/commands/ticket/edit.ts +0 -166
  80. package/src/commands/ticket/index.ts +0 -114
  81. package/src/commands/ticket/list.ts +0 -128
  82. package/src/commands/ticket/refine-utils.ts +0 -89
  83. package/src/commands/ticket/refine.ts +0 -268
  84. package/src/commands/ticket/remove.ts +0 -48
  85. package/src/commands/ticket/show.ts +0 -74
  86. package/src/completion/handle.ts +0 -30
  87. package/src/completion/resolver.ts +0 -241
  88. package/src/interactive/dashboard.ts +0 -268
  89. package/src/interactive/escapable.ts +0 -81
  90. package/src/interactive/file-browser.ts +0 -153
  91. package/src/interactive/index.ts +0 -429
  92. package/src/interactive/menu.ts +0 -403
  93. package/src/interactive/selectors.ts +0 -273
  94. package/src/interactive/wizard.ts +0 -221
  95. package/src/providers/claude.ts +0 -53
  96. package/src/providers/copilot.ts +0 -86
  97. package/src/providers/index.ts +0 -43
  98. package/src/providers/types.ts +0 -85
  99. package/src/schemas/index.ts +0 -130
  100. package/src/store/config.ts +0 -74
  101. package/src/store/progress.ts +0 -230
  102. package/src/store/project.ts +0 -276
  103. package/src/store/sprint.ts +0 -229
  104. package/src/store/task.ts +0 -443
  105. package/src/store/ticket.ts +0 -178
  106. package/src/theme/index.ts +0 -215
  107. package/src/theme/ui.ts +0 -872
  108. package/src/utils/detect-scripts.ts +0 -247
  109. package/src/utils/editor-input.ts +0 -41
  110. package/src/utils/editor.ts +0 -37
  111. package/src/utils/exit-codes.ts +0 -27
  112. package/src/utils/file-lock.ts +0 -135
  113. package/src/utils/git.ts +0 -185
  114. package/src/utils/ids.ts +0 -37
  115. package/src/utils/issue-fetch.ts +0 -244
  116. package/src/utils/json-extract.ts +0 -62
  117. package/src/utils/multiline.ts +0 -61
  118. package/src/utils/path-selector.ts +0 -236
  119. package/src/utils/paths.ts +0 -108
  120. package/src/utils/provider.ts +0 -34
  121. package/src/utils/requirements-export.ts +0 -63
  122. package/src/utils/storage.ts +0 -107
  123. package/tsconfig.json +0 -25
  124. /package/{src/ai → dist}/prompts/ideate-auto.md +0 -0
  125. /package/{src/ai → dist}/prompts/ideate.md +0 -0
  126. /package/{src/ai → dist}/prompts/plan-auto.md +0 -0
  127. /package/{src/ai → dist}/prompts/plan-common.md +0 -0
  128. /package/{src/ai → dist}/prompts/plan-interactive.md +0 -0
  129. /package/{src/ai → dist}/prompts/task-execution.md +0 -0
  130. /package/{src/ai → dist}/prompts/ticket-refine.md +0 -0
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ sprintCreateCommand
4
+ } from "./chunk-JON4GCLR.mjs";
5
+ import "./chunk-EKMZZRWI.mjs";
6
+ import "./chunk-6PYTKGB5.mjs";
7
+ import "./chunk-QBXHAXHI.mjs";
8
+ export {
9
+ sprintCreateCommand
10
+ };
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/completion/handle.ts
4
+ async function handleCompletionRequest(program) {
5
+ const env = process.env;
6
+ if (!env["COMP_CWORD"] || !env["COMP_POINT"] || !env["COMP_LINE"]) {
7
+ return false;
8
+ }
9
+ const tabtab = (await import("tabtab")).default;
10
+ const { resolveCompletions } = await import("./resolver-WSFWKACM.mjs");
11
+ const tabEnv = tabtab.parseEnv(env);
12
+ const completions = await resolveCompletions(program, {
13
+ line: tabEnv.line,
14
+ last: tabEnv.last,
15
+ prev: tabEnv.prev
16
+ });
17
+ tabtab.log(completions);
18
+ return true;
19
+ }
20
+ export {
21
+ handleCompletionRequest
22
+ };
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ icons,
4
+ muted
5
+ } from "./chunk-QBXHAXHI.mjs";
6
+
7
+ // src/utils/multiline.ts
8
+ import * as readline from "readline";
9
+ async function multilineInput(options) {
10
+ const { message, default: defaultValue, hint = "Ctrl+D to finish" } = options;
11
+ console.log(`${icons.edit} ${message} ${muted(`(${hint})`)}`);
12
+ if (defaultValue) {
13
+ console.log(muted(" Default:"));
14
+ for (const line of defaultValue.split("\n")) {
15
+ console.log(muted(` ${line}`));
16
+ }
17
+ console.log("");
18
+ }
19
+ const lines = [];
20
+ const rl = readline.createInterface({
21
+ input: process.stdin,
22
+ output: process.stdout,
23
+ terminal: process.stdin.isTTY
24
+ });
25
+ return new Promise((resolve) => {
26
+ rl.on("line", (line) => {
27
+ lines.push(line);
28
+ });
29
+ rl.on("close", () => {
30
+ console.log("");
31
+ while (lines.length > 0 && lines.at(-1)?.trim() === "") {
32
+ lines.pop();
33
+ }
34
+ resolve(lines.join("\n"));
35
+ });
36
+ });
37
+ }
38
+ export {
39
+ multilineInput
40
+ };
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ProjectExistsError,
4
+ ProjectNotFoundError,
5
+ addProjectRepo,
6
+ createProject,
7
+ getProject,
8
+ getProjectRepos,
9
+ listProjects,
10
+ projectExists,
11
+ removeProject,
12
+ removeProjectRepo,
13
+ updateProject
14
+ } from "./chunk-WGHJI3OI.mjs";
15
+ import "./chunk-6PYTKGB5.mjs";
16
+ export {
17
+ ProjectExistsError,
18
+ ProjectNotFoundError,
19
+ addProjectRepo,
20
+ createProject,
21
+ getProject,
22
+ getProjectRepos,
23
+ listProjects,
24
+ projectExists,
25
+ removeProject,
26
+ removeProjectRepo,
27
+ updateProject
28
+ };
@@ -0,0 +1,153 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/completion/resolver.ts
4
+ var dynamicResolvers = {
5
+ "--project": async () => {
6
+ try {
7
+ const { listProjects } = await import("./project-NT3L4FTB.mjs");
8
+ const projects = await listProjects();
9
+ return projects.map((p) => ({ name: p.name, description: p.displayName }));
10
+ } catch {
11
+ return [];
12
+ }
13
+ },
14
+ "--status": () => {
15
+ return Promise.resolve([
16
+ { name: "draft", description: "Draft sprints" },
17
+ { name: "active", description: "Active sprints" },
18
+ { name: "closed", description: "Closed sprints" },
19
+ { name: "todo", description: "Todo tasks" },
20
+ { name: "in_progress", description: "In-progress tasks" },
21
+ { name: "done", description: "Done tasks" },
22
+ { name: "pending", description: "Pending requirements" },
23
+ { name: "approved", description: "Approved requirements" }
24
+ ]);
25
+ }
26
+ };
27
+ var configKeyCompletions = [
28
+ { name: "provider", description: "AI provider (claude or copilot)" },
29
+ { name: "editor", description: "External editor for multiline input" }
30
+ ];
31
+ var configValueCompletions = {
32
+ provider: [
33
+ { name: "claude", description: "Claude Code CLI" },
34
+ { name: "copilot", description: "GitHub Copilot CLI" }
35
+ ]
36
+ };
37
+ async function getSprintCompletions() {
38
+ try {
39
+ const { listSprints } = await import("./sprint-4VHDLGFN.mjs");
40
+ const sprints = await listSprints();
41
+ return sprints.map((s) => ({
42
+ name: s.id,
43
+ description: `${s.name} (${s.status})`
44
+ }));
45
+ } catch {
46
+ return [];
47
+ }
48
+ }
49
+ function getSubcommands(cmd) {
50
+ return cmd.commands.map((sub) => ({
51
+ name: sub.name(),
52
+ description: sub.description()
53
+ }));
54
+ }
55
+ function getOptions(cmd) {
56
+ const items = [];
57
+ for (const opt of cmd.options) {
58
+ const flag = opt.long ?? opt.short;
59
+ if (flag) {
60
+ items.push({ name: flag, description: opt.description });
61
+ }
62
+ }
63
+ return items;
64
+ }
65
+ function findSubcommand(cmd, name) {
66
+ return cmd.commands.find((sub) => sub.name() === name);
67
+ }
68
+ function optionExpectsValue(cmd, flag) {
69
+ const opt = cmd.options.find((o) => o.long === flag || o.short === flag);
70
+ if (!opt) return false;
71
+ return opt.required || opt.optional;
72
+ }
73
+ function parseWords(line) {
74
+ return line.trim().split(/\s+/).slice(1);
75
+ }
76
+ async function resolveCompletions(program, ctx) {
77
+ const words = parseWords(ctx.line);
78
+ let currentCmd = program;
79
+ let wordIndex = 0;
80
+ while (wordIndex < words.length) {
81
+ const word = words[wordIndex];
82
+ if (!word) break;
83
+ if (word.startsWith("-")) {
84
+ wordIndex++;
85
+ if (optionExpectsValue(currentCmd, word) && wordIndex < words.length) {
86
+ wordIndex++;
87
+ }
88
+ continue;
89
+ }
90
+ const sub = findSubcommand(currentCmd, word);
91
+ if (sub) {
92
+ currentCmd = sub;
93
+ wordIndex++;
94
+ } else {
95
+ break;
96
+ }
97
+ }
98
+ const cmdPath = getCommandPath(currentCmd);
99
+ if (cmdPath === "config set") {
100
+ return resolveConfigSetCompletions(words, ctx);
101
+ }
102
+ if (ctx.prev.startsWith("-")) {
103
+ const resolver = dynamicResolvers[ctx.prev];
104
+ if (resolver) {
105
+ return resolver();
106
+ }
107
+ if (optionExpectsValue(currentCmd, ctx.prev)) {
108
+ return [];
109
+ }
110
+ }
111
+ if (ctx.last.startsWith("-")) {
112
+ return getOptions(currentCmd);
113
+ }
114
+ const subs = getSubcommands(currentCmd);
115
+ if (subs.length > 0) {
116
+ return subs;
117
+ }
118
+ if (cmdPath.startsWith("sprint ") && acceptsPositionalArg(currentCmd)) {
119
+ return getSprintCompletions();
120
+ }
121
+ return [];
122
+ }
123
+ function getCommandPath(cmd) {
124
+ const parts = [];
125
+ let current = cmd;
126
+ while (current?.parent) {
127
+ parts.unshift(current.name());
128
+ current = current.parent;
129
+ }
130
+ return parts.join(" ");
131
+ }
132
+ function acceptsPositionalArg(cmd) {
133
+ return cmd.registeredArguments.length > 0;
134
+ }
135
+ function resolveConfigSetCompletions(words, ctx) {
136
+ const setIndex = words.indexOf("set");
137
+ if (setIndex === -1) {
138
+ return Promise.resolve(configKeyCompletions);
139
+ }
140
+ const argsAfterSet = words.slice(setIndex + 1).filter((w) => !w.startsWith("-"));
141
+ if (argsAfterSet.length === 0) {
142
+ return Promise.resolve(configKeyCompletions);
143
+ }
144
+ if (argsAfterSet.length === 1 && ctx.last !== "") {
145
+ return Promise.resolve(configKeyCompletions);
146
+ }
147
+ const key = argsAfterSet[0];
148
+ const values = key ? configValueCompletions[key] : void 0;
149
+ return Promise.resolve(values ?? []);
150
+ }
151
+ export {
152
+ resolveCompletions
153
+ };
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ NoCurrentSprintError,
4
+ SprintNotFoundError,
5
+ SprintStatusError,
6
+ activateSprint,
7
+ assertSprintStatus,
8
+ closeSprint,
9
+ createSprint,
10
+ deleteSprint,
11
+ findActiveSprint,
12
+ getActiveSprintOrThrow,
13
+ getCurrentSprintOrThrow,
14
+ getSprint,
15
+ listSprints,
16
+ resolveSprintId,
17
+ saveSprint
18
+ } from "./chunk-EKMZZRWI.mjs";
19
+ import "./chunk-6PYTKGB5.mjs";
20
+ import "./chunk-QBXHAXHI.mjs";
21
+ export {
22
+ NoCurrentSprintError,
23
+ SprintNotFoundError,
24
+ SprintStatusError,
25
+ activateSprint,
26
+ assertSprintStatus,
27
+ closeSprint,
28
+ createSprint,
29
+ deleteSprint,
30
+ findActiveSprint,
31
+ getActiveSprintOrThrow,
32
+ getCurrentSprintOrThrow,
33
+ getSprint,
34
+ listSprints,
35
+ resolveSprintId,
36
+ saveSprint
37
+ };
@@ -0,0 +1,196 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ sprintPlanCommand,
4
+ sprintRefineCommand,
5
+ sprintStartCommand
6
+ } from "./chunk-LOR7QBXX.mjs";
7
+ import "./chunk-NTWO2LXB.mjs";
8
+ import {
9
+ sprintCreateCommand
10
+ } from "./chunk-JON4GCLR.mjs";
11
+ import {
12
+ addSingleTicketInteractive
13
+ } from "./chunk-MNMQC36F.mjs";
14
+ import "./chunk-7TG3EAQ2.mjs";
15
+ import "./chunk-WGHJI3OI.mjs";
16
+ import {
17
+ getCurrentSprint,
18
+ getSprint
19
+ } from "./chunk-EKMZZRWI.mjs";
20
+ import "./chunk-6PYTKGB5.mjs";
21
+ import {
22
+ colors,
23
+ emoji,
24
+ icons,
25
+ log,
26
+ printHeader,
27
+ printSeparator,
28
+ progressBar,
29
+ showSuccess,
30
+ showWarning
31
+ } from "./chunk-QBXHAXHI.mjs";
32
+
33
+ // src/interactive/wizard.ts
34
+ import { confirm } from "@inquirer/prompts";
35
+ var TOTAL_STEPS = 5;
36
+ function showStepProgress(step, title) {
37
+ const bar = progressBar(step - 1, TOTAL_STEPS, { width: 10, showPercent: false });
38
+ log.newline();
39
+ printSeparator();
40
+ console.log(` ${colors.highlight(`Step ${String(step)} of ${String(TOTAL_STEPS)}`)} ${bar} ${title}`);
41
+ log.newline();
42
+ }
43
+ async function runWizard() {
44
+ try {
45
+ printHeader("Sprint Setup Wizard", emoji.donut);
46
+ log.dim("This wizard will guide you through setting up a new sprint.");
47
+ log.dim("You can skip optional steps along the way.");
48
+ log.newline();
49
+ showStepProgress(1, "Create Sprint");
50
+ try {
51
+ await sprintCreateCommand({ interactive: true });
52
+ } catch (err) {
53
+ if (err instanceof Error) {
54
+ log.error(`Sprint creation failed: ${err.message}`);
55
+ }
56
+ log.newline();
57
+ showWarning("Cannot continue without a sprint. Wizard aborted.");
58
+ return;
59
+ }
60
+ const sprintId = await getCurrentSprint();
61
+ if (!sprintId) {
62
+ showWarning("No current sprint set. Wizard aborted.");
63
+ return;
64
+ }
65
+ showStepProgress(2, "Add Tickets");
66
+ let ticketCount = 0;
67
+ let addMore = true;
68
+ while (addMore) {
69
+ try {
70
+ const ticket = await addSingleTicketInteractive({});
71
+ if (ticket) {
72
+ ticketCount++;
73
+ } else {
74
+ break;
75
+ }
76
+ } catch (err) {
77
+ if (err instanceof Error) {
78
+ log.error(`Failed to add ticket: ${err.message}`);
79
+ }
80
+ }
81
+ log.newline();
82
+ addMore = await confirm({
83
+ message: `${emoji.donut} Add another ticket?`,
84
+ default: true
85
+ });
86
+ }
87
+ if (ticketCount === 0) {
88
+ log.newline();
89
+ showWarning("No tickets added. You can add them later with: ralphctl ticket add");
90
+ }
91
+ showStepProgress(3, "Refine Requirements");
92
+ if (ticketCount === 0) {
93
+ log.dim("Skipped -- no tickets to refine.");
94
+ } else {
95
+ const shouldRefine = await confirm({
96
+ message: `${emoji.donut} Refine requirements now?`,
97
+ default: true
98
+ });
99
+ if (shouldRefine) {
100
+ try {
101
+ await sprintRefineCommand([]);
102
+ } catch (err) {
103
+ if (err instanceof Error) {
104
+ log.error(`Refinement failed: ${err.message}`);
105
+ }
106
+ log.dim("You can refine later with: ralphctl sprint refine");
107
+ }
108
+ } else {
109
+ log.dim("Skipped. You can refine later with: ralphctl sprint refine");
110
+ }
111
+ }
112
+ showStepProgress(4, "Plan Tasks");
113
+ let canPlan = false;
114
+ try {
115
+ const sprint = await getSprint(sprintId);
116
+ const hasTickets = sprint.tickets.length > 0;
117
+ const allApproved = hasTickets && sprint.tickets.every((t) => t.requirementStatus === "approved");
118
+ canPlan = allApproved;
119
+ if (!hasTickets) {
120
+ log.dim("Skipped -- no tickets to plan.");
121
+ } else if (!allApproved) {
122
+ log.dim("Skipped -- not all requirements are approved yet.");
123
+ log.dim("Refine first with: ralphctl sprint refine");
124
+ }
125
+ } catch {
126
+ log.dim("Skipped -- could not read sprint state.");
127
+ }
128
+ if (canPlan) {
129
+ const shouldPlan = await confirm({
130
+ message: `${emoji.donut} Generate tasks now?`,
131
+ default: true
132
+ });
133
+ if (shouldPlan) {
134
+ try {
135
+ await sprintPlanCommand([]);
136
+ } catch (err) {
137
+ if (err instanceof Error) {
138
+ log.error(`Planning failed: ${err.message}`);
139
+ }
140
+ log.dim("You can plan later with: ralphctl sprint plan");
141
+ }
142
+ } else {
143
+ log.dim("Skipped. You can plan later with: ralphctl sprint plan");
144
+ }
145
+ }
146
+ showStepProgress(5, "Start Execution");
147
+ const shouldStart = await confirm({
148
+ message: `${emoji.donut} Start execution now?`,
149
+ default: false
150
+ });
151
+ if (shouldStart) {
152
+ try {
153
+ await sprintStartCommand([]);
154
+ } catch (err) {
155
+ if (err instanceof Error) {
156
+ log.error(`Execution failed: ${err.message}`);
157
+ }
158
+ }
159
+ return;
160
+ }
161
+ log.newline();
162
+ printSeparator();
163
+ showSuccess("Wizard complete!");
164
+ log.newline();
165
+ try {
166
+ const sprint = await getSprint(sprintId);
167
+ log.info(`Sprint "${sprint.name}" is ready.`);
168
+ log.item(`${icons.ticket} ${String(sprint.tickets.length)} ticket(s)`);
169
+ const approvedCount = sprint.tickets.filter((t) => t.requirementStatus === "approved").length;
170
+ if (sprint.tickets.length > 0) {
171
+ log.item(`${icons.success} ${String(approvedCount)}/${String(sprint.tickets.length)} requirements approved`);
172
+ }
173
+ } catch {
174
+ }
175
+ log.newline();
176
+ log.dim("Next steps:");
177
+ if (ticketCount === 0) {
178
+ log.item("ralphctl ticket add --project <name>");
179
+ }
180
+ log.item("ralphctl sprint refine");
181
+ log.item("ralphctl sprint plan");
182
+ log.item("ralphctl sprint start");
183
+ log.newline();
184
+ } catch (err) {
185
+ if (err.name === "ExitPromptError") {
186
+ log.newline();
187
+ showWarning("Wizard cancelled");
188
+ log.newline();
189
+ return;
190
+ }
191
+ throw err;
192
+ }
193
+ }
194
+ export {
195
+ runWizard
196
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ralphctl",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Sprint and task management CLI for AI-assisted coding",
5
5
  "homepage": "https://github.com/lukas-grigis/ralphctl",
6
6
  "type": "module",
@@ -24,37 +24,15 @@
24
24
  "developer-tools"
25
25
  ],
26
26
  "bin": {
27
- "ralphctl": "./bin/ralphctl"
27
+ "ralphctl": "./dist/cli.mjs"
28
28
  },
29
29
  "files": [
30
- "bin/",
31
- "src/",
32
- "!src/**/*.test.ts",
33
- "!src/test-utils/",
34
- "!src/integration/",
35
- "schemas/",
36
- "tsconfig.json",
37
- "README.md",
38
- "LICENSE",
39
- "CHANGELOG.md"
30
+ "dist/",
31
+ "schemas/"
40
32
  ],
41
33
  "publishConfig": {
42
34
  "access": "public"
43
35
  },
44
- "scripts": {
45
- "build": "tsc --noEmit",
46
- "dev": "tsx src/cli.ts",
47
- "lint": "eslint .",
48
- "lint:fix": "eslint . --fix",
49
- "format": "prettier --write .",
50
- "format:check": "prettier --check .",
51
- "typecheck": "tsc --noEmit",
52
- "test": "vitest run",
53
- "test:watch": "vitest",
54
- "test:coverage": "vitest run --coverage",
55
- "prepare": "husky"
56
- },
57
- "packageManager": "pnpm@10.29.3",
58
36
  "engines": {
59
37
  "node": ">=24.0.0"
60
38
  },
@@ -65,7 +43,6 @@
65
43
  "gradient-string": "^3.0.0",
66
44
  "ora": "^9.3.0",
67
45
  "tabtab": "^3.0.2",
68
- "tsx": "^4.21.0",
69
46
  "zod": "^4.3.6"
70
47
  },
71
48
  "devDependencies": {
@@ -78,6 +55,8 @@
78
55
  "husky": "^9.1.7",
79
56
  "lint-staged": "^16.3.1",
80
57
  "prettier": "^3.8.1",
58
+ "tsup": "^8.5.1",
59
+ "tsx": "^4.21.0",
81
60
  "typescript": "^5.9.3",
82
61
  "typescript-eslint": "^8.56.1",
83
62
  "vitest": "^4.0.18"
@@ -88,5 +67,17 @@
88
67
  "prettier --write"
89
68
  ],
90
69
  "*.{md,json,yml,yaml}": "prettier --write"
70
+ },
71
+ "scripts": {
72
+ "build": "tsup && mkdir -p dist/prompts && cp src/ai/prompts/*.md dist/prompts/",
73
+ "dev": "tsx src/cli.ts",
74
+ "lint": "eslint .",
75
+ "lint:fix": "eslint . --fix",
76
+ "format": "prettier --write .",
77
+ "format:check": "prettier --check .",
78
+ "typecheck": "tsc --noEmit",
79
+ "test": "vitest run",
80
+ "test:watch": "vitest",
81
+ "test:coverage": "vitest run --coverage"
91
82
  }
92
- }
83
+ }
package/CHANGELOG.md DELETED
@@ -1,94 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to RalphCTL will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/), and this project adheres to [Semantic Versioning](https://semver.org/).
6
-
7
- ## [0.1.0] - 2026-03-07
8
-
9
- ### Added
10
-
11
- - **npm publishing** — `ralphctl` is now available via `npm install -g ralphctl`
12
- - Release pipeline publishes to npm and creates GitHub Releases with changelog-based notes
13
-
14
- ### Changed
15
-
16
- - Streamlined README for end-user onboarding with `npm install -g` as primary install method
17
- - Added release process documentation to CONTRIBUTING.md
18
- - Version bumped to 0.1.0 for first public npm release
19
-
20
- ## [0.0.3] - 2026-03-06
21
-
22
- ### Changed
23
-
24
- - Normalized git author identity across commit history
25
- - Updated package metadata for open-source release (description, homepage, private flag)
26
- - Moved `tsx` from devDependencies to dependencies (runtime requirement for `bin/ralphctl`)
27
- - Fixed stale path references in SECURITY.md, CONTRIBUTING.md, and agent memory files
28
- - Fixed changelog compare link in release workflow to include `v` prefix
29
- - Corrected documentation table descriptions in README.md
30
- - Cleaned up stale `dist/` build artifacts
31
- - Edited documentation for public release
32
-
33
- ## [0.0.2] - 2026-03-03
34
-
35
- ### Added
36
-
37
- - **Doctor command** — `ralphctl doctor` checks Node.js version, git, AI provider binary, data directory, project repos, and current sprint health
38
- - **Shell tab-completion** — `ralphctl completion install` for bash, zsh, and fish via tabtab
39
- - **Branch management** — `sprint start` prompts for branch strategy (keep current, auto, custom); `--branch` and `--branch-name` flags; pre-flight verification; `sprint close --create-pr` creates PRs
40
- - **Provider abstraction** — `config set provider claude|copilot` with adapter layer; experimental Copilot CLI support with headless execution and session ID capture
41
- - **Draft re-plan** — running `sprint plan` on a draft with existing tasks passes all tickets + tasks as AI context for atomic replacement
42
- - **Check script model** — single idempotent `checkScript` per repo replaces old `setupScript`/`verifyScript`; runs at sprint start and as a post-task gate
43
- - **Lifecycle hooks** — `runLifecycleHook()` abstraction in `src/ai/lifecycle.ts` with `RALPHCTL_LIFECYCLE_EVENT` env var
44
- - **Ecosystem detection** — `EcosystemDetector[]` registry (node, python, go, rust, gradle, maven, makefile) for check script suggestions during project setup
45
- - **Sprint health** — duplicate task order and pending requirements diagnostics; branch consistency checks across repos
46
- - **Interactive mode** — Escape key navigation, styled section titles, flat workflow section, provider config in REPL, refined/planned counts in status header, guards for unrefined/unplanned tickets
47
- - **Inline multiline editor** — replaced with `@inquirer/editor` and configurable editor settings via `config set editor`
48
- - **CI/CD** — GitHub Actions pipeline with lint, typecheck, test, format check; Dependabot; automated GitHub Release pipeline
49
- - **Schema sync tests** — JSON schema ↔ Zod schema validation
50
-
51
- ### Changed
52
-
53
- - Renamed `claude` module to `ai` for provider-agnostic naming
54
- - Replaced tsup build with bash wrapper approach for CLI outside repo root
55
- - Default data directory changed to `~/.ralphctl` (was `ralphctl-data/`)
56
- - Separated repo root from data directory with smart `RALPHCTL_ROOT` handling
57
- - Removed `externalId` field and `--id`/`--editor` CLI flags from ticket command
58
- - Documentation restructured — moved to `.claude/docs/`, slimmed CLAUDE.md from 613 to 160 lines with skill-based reference material
59
- - Replaced raw color functions with theme helpers across all commands
60
- - Improved card rendering and terminal width awareness
61
-
62
- ### Fixed
63
-
64
- - Sanitize session IDs and harden file operations against path traversal
65
- - Fixed pre-flight execution checks for security and correctness
66
- - Preserve error cause in re-thrown errors
67
- - Thread provider through `checkTaskPermissions()`
68
- - Branch management error handling and retry logic
69
- - Interactive mode duplicate quote, closed sprint status header, and dashboard duplication
70
- - ANSI code handling in CLI test field extraction
71
- - Removed redundant file reads in interactive menu context loading
72
-
73
- ### Dependencies
74
-
75
- - Bumped `zod` from 3.x to 4.x
76
- - Bumped `@inquirer/prompts` from 7.x to 8.x
77
- - Bumped `@types/node`, `globals`, `ora`, `typescript-eslint`, and other dev dependencies
78
-
79
- ## [0.0.1] - 2026-02-15
80
-
81
- ### Added
82
-
83
- - **Project management** — register multi-repo projects with named paths
84
- - **Sprint lifecycle** — create, activate, close sprints with state machine enforcement (draft -> active -> closed)
85
- - **Ticket tracking** — add work items linked to projects, with optional external IDs
86
- - **Two-phase planning** — refine requirements (WHAT) then generate tasks (HOW) with human approval gates
87
- - **Task dependencies** — `blockedBy` references with topological sort and cycle detection
88
- - **Task execution** — headless, watch, session, and interactive modes via Claude CLI
89
- - **Parallel execution** — one task per repo concurrently, with rate limit backoff and session resume
90
- - **Interactive menu mode** — context-aware REPL with persistent status header and Quick Start wizard
91
- - **Sprint health checks** — diagnose blockers, stale tasks, and missing dependencies
92
- - **Requirements export** — markdown export of refined requirements
93
- - **Progress logging** — append-only timestamped progress log per sprint
94
- - **Ralph Wiggum personality** — themed UI with donut spinners, random quotes, and gradient banner
package/bin/ralphctl DELETED
@@ -1,13 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Resolve symlinks so this works via npm link / pnpm link --global
3
- SOURCE="${BASH_SOURCE[0]}"
4
- while [ -L "$SOURCE" ]; do
5
- DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)"
6
- SOURCE="$(readlink "$SOURCE")"
7
- [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
8
- done
9
- SCRIPT_DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)"
10
- REPO_DIR="$SCRIPT_DIR/.."
11
-
12
- export TSX_TSCONFIG_PATH="$REPO_DIR/tsconfig.json"
13
- exec node --import tsx "$REPO_DIR/src/cli.ts" "$@"