ralphctl 0.2.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/add-GX7P7XTT.mjs +16 -0
  2. package/dist/add-JGUOR4Z5.mjs +18 -0
  3. package/dist/bootstrap-FMHG6DRY.mjs +11 -0
  4. package/dist/chunk-3QBEBKMZ.mjs +103 -0
  5. package/dist/chunk-4GHVNKLV.mjs +5088 -0
  6. package/dist/{chunk-EDJX7TT6.mjs → chunk-57UWLHRH.mjs} +22 -2
  7. package/dist/chunk-747KW2RW.mjs +24 -0
  8. package/dist/chunk-CDOPLXFK.mjs +5485 -0
  9. package/dist/{chunk-7TG3EAQ2.mjs → chunk-CFUVE2BP.mjs} +1 -5
  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-QBXHAXHI.mjs → chunk-FKMKOWLA.mjs} +154 -208
  13. package/dist/chunk-HL4ZMHCQ.mjs +261 -0
  14. package/dist/{chunk-OEUJDSHY.mjs → chunk-IWXBJD2D.mjs} +1 -1
  15. package/dist/chunk-JXMHLW42.mjs +227 -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 +168 -3995
  19. package/dist/create-7WFSCMP4.mjs +15 -0
  20. package/dist/{handle-TA4MYNQJ.mjs → handle-BBAZJ44Y.mjs} +2 -2
  21. package/dist/mount-XZPBDRPZ.mjs +6751 -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 +24 -15
  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 +7 -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-MMWC7QLI.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
@@ -1,59 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- createSprint,
4
- setCurrentSprint
5
- } from "./chunk-JRFOUFD3.mjs";
6
- import {
7
- emoji,
8
- field,
9
- formatSprintStatus,
10
- icons,
11
- showNextStep,
12
- showRandomQuote,
13
- showSuccess
14
- } from "./chunk-QBXHAXHI.mjs";
15
-
16
- // src/commands/sprint/create.ts
17
- import { confirm, input } from "@inquirer/prompts";
18
- async function sprintCreateCommand(options = {}) {
19
- let name;
20
- if (options.interactive === false) {
21
- const trimmed = options.name?.trim();
22
- name = trimmed && trimmed.length > 0 ? trimmed : void 0;
23
- } else {
24
- const inputName = await input({
25
- message: `${icons.sprint} Sprint name (optional):`,
26
- default: options.name?.trim()
27
- });
28
- const trimmed = inputName.trim();
29
- name = trimmed.length > 0 ? trimmed : void 0;
30
- }
31
- const sprint = await createSprint(name);
32
- let setAsCurrent = true;
33
- if (options.interactive) {
34
- setAsCurrent = await confirm({
35
- message: `${emoji.donut} Set as current sprint?`,
36
- default: true
37
- });
38
- }
39
- if (setAsCurrent) {
40
- await setCurrentSprint(sprint.id);
41
- }
42
- showSuccess("Sprint created!", [
43
- ["ID", sprint.id],
44
- ["Name", sprint.name],
45
- ["Status", formatSprintStatus(sprint.status)]
46
- ]);
47
- showRandomQuote();
48
- if (setAsCurrent) {
49
- console.log(field("Current", "Yes (this sprint is now active target)"));
50
- showNextStep("ralphctl ticket add --project <name>", "add tickets to this sprint");
51
- } else {
52
- console.log(field("Current", "No"));
53
- showNextStep(`ralphctl sprint current ${sprint.id}`, "set as current later");
54
- }
55
- }
56
-
57
- export {
58
- sprintCreateCommand
59
- };
@@ -1,12 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- sprintCreateCommand
4
- } from "./chunk-DUU5346E.mjs";
5
- import "./chunk-JRFOUFD3.mjs";
6
- import "./chunk-OEUJDSHY.mjs";
7
- import "./chunk-IB6OCKZW.mjs";
8
- import "./chunk-EDJX7TT6.mjs";
9
- import "./chunk-QBXHAXHI.mjs";
10
- export {
11
- sprintCreateCommand
12
- };
@@ -1,40 +0,0 @@
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
- };
@@ -1,193 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- sprintPlanCommand,
4
- sprintRefineCommand,
5
- sprintStartCommand
6
- } from "./chunk-CSICORGV.mjs";
7
- import "./chunk-7LZ6GOGN.mjs";
8
- import {
9
- sprintCreateCommand
10
- } from "./chunk-DUU5346E.mjs";
11
- import {
12
- addSingleTicketInteractive
13
- } from "./chunk-742XQ7FL.mjs";
14
- import "./chunk-7TG3EAQ2.mjs";
15
- import "./chunk-EUNAUHC3.mjs";
16
- import {
17
- getCurrentSprint,
18
- getSprint
19
- } from "./chunk-JRFOUFD3.mjs";
20
- import {
21
- ensureError,
22
- wrapAsync
23
- } from "./chunk-OEUJDSHY.mjs";
24
- import "./chunk-IB6OCKZW.mjs";
25
- import "./chunk-EDJX7TT6.mjs";
26
- import {
27
- colors,
28
- emoji,
29
- icons,
30
- log,
31
- printHeader,
32
- printSeparator,
33
- progressBar,
34
- showSuccess,
35
- showWarning
36
- } from "./chunk-QBXHAXHI.mjs";
37
-
38
- // src/interactive/wizard.ts
39
- import { confirm } from "@inquirer/prompts";
40
- var TOTAL_STEPS = 5;
41
- function showStepProgress(step, title) {
42
- const bar = progressBar(step - 1, TOTAL_STEPS, { width: 10, showPercent: false });
43
- log.newline();
44
- printSeparator();
45
- console.log(` ${colors.highlight(`Step ${String(step)} of ${String(TOTAL_STEPS)}`)} ${bar} ${title}`);
46
- log.newline();
47
- }
48
- async function runWizard() {
49
- const r = await wrapAsync(async () => {
50
- printHeader("Sprint Setup Wizard", emoji.donut);
51
- log.dim("This wizard will guide you through setting up a new sprint.");
52
- log.dim("You can skip optional steps along the way.");
53
- log.newline();
54
- showStepProgress(1, "Create Sprint");
55
- const createResult = await wrapAsync(() => sprintCreateCommand({ interactive: true }), ensureError);
56
- if (!createResult.ok) {
57
- log.error(`Sprint creation failed: ${createResult.error.message}`);
58
- log.newline();
59
- showWarning("Cannot continue without a sprint. Wizard aborted.");
60
- return;
61
- }
62
- const sprintId = await getCurrentSprint();
63
- if (!sprintId) {
64
- showWarning("No current sprint set. Wizard aborted.");
65
- return;
66
- }
67
- showStepProgress(2, "Add Tickets");
68
- let ticketCount = 0;
69
- let addMore = true;
70
- while (addMore) {
71
- const ticketResult = await wrapAsync(() => addSingleTicketInteractive({}), ensureError);
72
- if (ticketResult.ok) {
73
- if (ticketResult.value) {
74
- ticketCount++;
75
- } else {
76
- break;
77
- }
78
- } else {
79
- log.error(`Failed to add ticket: ${ticketResult.error.message}`);
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
- const refineResult = await wrapAsync(() => sprintRefineCommand([]), ensureError);
101
- if (!refineResult.ok) {
102
- log.error(`Refinement failed: ${refineResult.error.message}`);
103
- log.dim("You can refine later with: ralphctl sprint refine");
104
- }
105
- } else {
106
- log.dim("Skipped. You can refine later with: ralphctl sprint refine");
107
- }
108
- }
109
- showStepProgress(4, "Plan Tasks");
110
- let canPlan = false;
111
- const sprintCheckResult = await wrapAsync(() => getSprint(sprintId), ensureError);
112
- if (sprintCheckResult.ok) {
113
- const sprint = sprintCheckResult.value;
114
- const hasTickets = sprint.tickets.length > 0;
115
- const allApproved = hasTickets && sprint.tickets.every((t) => t.requirementStatus === "approved");
116
- canPlan = allApproved;
117
- if (!hasTickets) {
118
- log.dim("Skipped -- no tickets to plan.");
119
- } else if (!allApproved) {
120
- log.dim("Skipped -- not all requirements are approved yet.");
121
- log.dim("Refine first with: ralphctl sprint refine");
122
- }
123
- } else {
124
- log.dim("Skipped -- could not read sprint state.");
125
- }
126
- if (canPlan) {
127
- const shouldPlan = await confirm({
128
- message: `${emoji.donut} Generate tasks now?`,
129
- default: true
130
- });
131
- if (shouldPlan) {
132
- const planResult = await wrapAsync(() => sprintPlanCommand([]), ensureError);
133
- if (!planResult.ok) {
134
- log.error(`Planning failed: ${planResult.error.message}`);
135
- log.dim("You can plan later with: ralphctl sprint plan");
136
- }
137
- } else {
138
- log.dim("Skipped. You can plan later with: ralphctl sprint plan");
139
- }
140
- }
141
- showStepProgress(5, "Start Execution");
142
- const shouldStart = await confirm({
143
- message: `${emoji.donut} Start execution now?`,
144
- default: false
145
- });
146
- if (shouldStart) {
147
- const startResult = await wrapAsync(
148
- // Note: sprintStartCommand may call process.exit() on completion
149
- () => sprintStartCommand([]),
150
- ensureError
151
- );
152
- if (!startResult.ok) {
153
- log.error(`Execution failed: ${startResult.error.message}`);
154
- }
155
- return;
156
- }
157
- log.newline();
158
- printSeparator();
159
- showSuccess("Wizard complete!");
160
- log.newline();
161
- const summaryResult = await wrapAsync(() => getSprint(sprintId), ensureError);
162
- if (summaryResult.ok) {
163
- const sprint = summaryResult.value;
164
- log.info(`Sprint "${sprint.name}" is ready.`);
165
- log.item(`${icons.ticket} ${String(sprint.tickets.length)} ticket(s)`);
166
- const approvedCount = sprint.tickets.filter((t) => t.requirementStatus === "approved").length;
167
- if (sprint.tickets.length > 0) {
168
- log.item(`${icons.success} ${String(approvedCount)}/${String(sprint.tickets.length)} requirements approved`);
169
- }
170
- }
171
- log.newline();
172
- log.dim("Next steps:");
173
- if (ticketCount === 0) {
174
- log.item("ralphctl ticket add --project <name>");
175
- }
176
- log.item("ralphctl sprint refine");
177
- log.item("ralphctl sprint plan");
178
- log.item("ralphctl sprint start");
179
- log.newline();
180
- }, ensureError);
181
- if (!r.ok) {
182
- if (r.error.name === "ExitPromptError") {
183
- log.newline();
184
- showWarning("Wizard cancelled");
185
- log.newline();
186
- return;
187
- }
188
- throw r.error;
189
- }
190
- }
191
- export {
192
- runWizard
193
- };
@@ -1,30 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "config.schema.json",
4
- "title": "Config",
5
- "description": "RalphCTL configuration",
6
- "type": "object",
7
- "properties": {
8
- "currentSprint": {
9
- "type": ["string", "null"],
10
- "default": null,
11
- "description": "Current sprint ID (which sprint CLI commands target)"
12
- },
13
- "aiProvider": {
14
- "type": ["string", "null"],
15
- "enum": ["claude", "copilot", null],
16
- "default": null,
17
- "description": "AI provider to use for code generation (claude or copilot)"
18
- },
19
- "editor": {
20
- "type": ["string", "null"],
21
- "default": null,
22
- "description": "Editor command for editing files (e.g., 'subl -w', 'code --wait', 'vim')"
23
- },
24
- "evaluationIterations": {
25
- "type": "integer",
26
- "minimum": 0,
27
- "description": "Number of evaluation iterations (0 = disabled, default fallback: 1)"
28
- }
29
- }
30
- }
@@ -1,22 +0,0 @@
1
- {
2
- "$schema": "http://json-schema.org/draft-07/schema#",
3
- "title": "Ideate Output Schema",
4
- "description": "Combined requirements and tasks from sprint ideate command",
5
- "type": "object",
6
- "required": ["requirements", "tasks"],
7
- "properties": {
8
- "requirements": {
9
- "type": "string",
10
- "minLength": 1,
11
- "description": "Refined requirements in markdown format"
12
- },
13
- "tasks": {
14
- "type": "array",
15
- "description": "Array of implementation tasks",
16
- "items": {
17
- "$ref": "task-import.schema.json#/definitions/ImportTask"
18
- }
19
- }
20
- },
21
- "additionalProperties": false
22
- }
@@ -1,58 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "projects.schema.json",
4
- "title": "Projects",
5
- "description": "Array of project definitions",
6
- "type": "array",
7
- "items": {
8
- "type": "object",
9
- "required": ["name", "displayName", "repositories"],
10
- "properties": {
11
- "name": {
12
- "type": "string",
13
- "pattern": "^[a-z0-9-]+$",
14
- "minLength": 1,
15
- "description": "Project slug (lowercase, numbers, hyphens only)"
16
- },
17
- "displayName": {
18
- "type": "string",
19
- "minLength": 1,
20
- "description": "Human-readable project name"
21
- },
22
- "repositories": {
23
- "type": "array",
24
- "minItems": 1,
25
- "description": "Array of repositories for this project",
26
- "items": {
27
- "type": "object",
28
- "required": ["name", "path"],
29
- "properties": {
30
- "name": {
31
- "type": "string",
32
- "minLength": 1,
33
- "description": "Repository name (auto-derived from path basename)"
34
- },
35
- "path": {
36
- "type": "string",
37
- "minLength": 1,
38
- "description": "Absolute path to the repository"
39
- },
40
- "checkScript": {
41
- "type": "string",
42
- "description": "Idempotent check command that bootstraps and verifies the environment (e.g., pnpm install && pnpm typecheck && pnpm lint && pnpm test)"
43
- },
44
- "checkTimeout": {
45
- "type": "number",
46
- "exclusiveMinimum": 0,
47
- "description": "Per-repo timeout in milliseconds for check script execution (overrides RALPHCTL_SETUP_TIMEOUT_MS)"
48
- }
49
- }
50
- }
51
- },
52
- "description": {
53
- "type": "string",
54
- "description": "Optional project description"
55
- }
56
- }
57
- }
58
- }
@@ -1,24 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "requirements-output.schema.json",
4
- "title": "Requirements Output",
5
- "description": "Schema for refined requirements output from ralphctl sprint refine",
6
- "type": "array",
7
- "items": {
8
- "type": "object",
9
- "required": ["ref", "requirements"],
10
- "additionalProperties": false,
11
- "properties": {
12
- "ref": {
13
- "type": "string",
14
- "minLength": 1,
15
- "description": "Reference to the ticket - either internal ID, external ID, or exact title"
16
- },
17
- "requirements": {
18
- "type": "string",
19
- "minLength": 1,
20
- "description": "Refined requirements in markdown format - should include problem statement, requirements, acceptance criteria, scope, and constraints"
21
- }
22
- }
23
- }
24
- }
@@ -1,109 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "sprint.schema.json",
4
- "title": "Sprint",
5
- "description": "Sprint metadata and tickets",
6
- "type": "object",
7
- "required": ["id", "name", "status", "createdAt"],
8
- "properties": {
9
- "id": {
10
- "type": "string",
11
- "pattern": "^\\d{8}-\\d{6}-[a-z0-9-]+$",
12
- "description": "Sprint ID in format YYYYMMDD-HHmmss-<slug> (lexicographically sortable)"
13
- },
14
- "name": {
15
- "type": "string",
16
- "minLength": 1,
17
- "description": "Human-readable sprint name"
18
- },
19
- "status": {
20
- "type": "string",
21
- "enum": ["draft", "active", "closed"],
22
- "default": "draft",
23
- "description": "Sprint status (one-way: draft → active → closed)"
24
- },
25
- "createdAt": {
26
- "type": "string",
27
- "format": "date-time",
28
- "description": "ISO 8601 timestamp when sprint was created"
29
- },
30
- "activatedAt": {
31
- "type": ["string", "null"],
32
- "format": "date-time",
33
- "default": null,
34
- "description": "ISO 8601 timestamp when sprint was activated"
35
- },
36
- "closedAt": {
37
- "type": ["string", "null"],
38
- "format": "date-time",
39
- "default": null,
40
- "description": "ISO 8601 timestamp when sprint was closed"
41
- },
42
- "checkRanAt": {
43
- "type": "object",
44
- "default": {},
45
- "description": "Map of projectPath → ISO 8601 timestamp recording when check script last ran (per sprint lifecycle)",
46
- "additionalProperties": {
47
- "type": "string",
48
- "format": "date-time"
49
- }
50
- },
51
- "branch": {
52
- "type": ["string", "null"],
53
- "default": null,
54
- "description": "Branch name used for sprint execution. When set, all repos checkout this branch before task execution."
55
- },
56
- "tickets": {
57
- "type": "array",
58
- "default": [],
59
- "description": "Tickets to be planned into tasks",
60
- "items": {
61
- "type": "object",
62
- "required": ["id", "title", "projectName"],
63
- "properties": {
64
- "id": {
65
- "type": "string",
66
- "minLength": 1,
67
- "description": "Internal ticket ID (uuid8, auto-generated)"
68
- },
69
- "title": {
70
- "type": "string",
71
- "minLength": 1,
72
- "description": "Short summary of the work"
73
- },
74
- "description": {
75
- "type": "string",
76
- "description": "Detailed description of requirements, acceptance criteria, context"
77
- },
78
- "link": {
79
- "type": "string",
80
- "format": "uri",
81
- "description": "URL to external issue tracker"
82
- },
83
- "projectName": {
84
- "type": "string",
85
- "minLength": 1,
86
- "description": "Reference to project name (from projects.json)"
87
- },
88
- "requirementStatus": {
89
- "type": "string",
90
- "enum": ["pending", "approved"],
91
- "default": "pending",
92
- "description": "Status of requirement refinement"
93
- },
94
- "affectedRepositories": {
95
- "type": "array",
96
- "items": {
97
- "type": "string"
98
- },
99
- "description": "Repository paths selected during planning"
100
- },
101
- "requirements": {
102
- "type": "string",
103
- "description": "Refined requirements (set during sprint refine)"
104
- }
105
- }
106
- }
107
- }
108
- }
109
- }
@@ -1,56 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "task-import.schema.json",
4
- "title": "Task Import",
5
- "description": "Schema for importing tasks via ralphctl task import or scope plan",
6
- "type": "array",
7
- "items": {
8
- "type": "object",
9
- "required": ["name", "projectPath"],
10
- "properties": {
11
- "name": {
12
- "type": "string",
13
- "minLength": 1,
14
- "description": "Task name - concise, actionable description"
15
- },
16
- "description": {
17
- "type": "string",
18
- "description": "Detailed description of what the task accomplishes"
19
- },
20
- "steps": {
21
- "type": "array",
22
- "description": "Implementation steps - specific, actionable items",
23
- "items": {
24
- "type": "string"
25
- }
26
- },
27
- "verificationCriteria": {
28
- "type": "array",
29
- "description": "Definition-of-done checks used to evaluate task completion",
30
- "items": {
31
- "type": "string"
32
- }
33
- },
34
- "ticketId": {
35
- "type": "string",
36
- "description": "Reference to parent ticket ID (e.g., TICKET-001)"
37
- },
38
- "id": {
39
- "type": "string",
40
- "description": "Local ID for referencing this task in blockedBy (e.g., '1', 'auth-setup'). Converted to real ID on import."
41
- },
42
- "blockedBy": {
43
- "type": "array",
44
- "description": "IDs of tasks that must complete first. Reference tasks by their 'id' field.",
45
- "items": {
46
- "type": "string"
47
- }
48
- },
49
- "projectPath": {
50
- "type": "string",
51
- "minLength": 1,
52
- "description": "Absolute path to the repository where this task should execute. Must be one of the project's paths."
53
- }
54
- }
55
- }
56
- }