ralphy-spec 0.1.1 → 0.2.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 (176) hide show
  1. package/README.ja.md +74 -130
  2. package/README.ko.md +74 -130
  3. package/README.md +75 -133
  4. package/README.zh.md +74 -130
  5. package/bin/ralphy-spec.js +0 -0
  6. package/dist/cli/checkpoint.d.ts +3 -0
  7. package/dist/cli/checkpoint.d.ts.map +1 -0
  8. package/dist/cli/checkpoint.js +23 -0
  9. package/dist/cli/checkpoint.js.map +1 -0
  10. package/dist/cli/init.d.ts +3 -0
  11. package/dist/cli/init.d.ts.map +1 -0
  12. package/dist/cli/init.js +66 -0
  13. package/dist/cli/init.js.map +1 -0
  14. package/dist/cli/report.d.ts +3 -0
  15. package/dist/cli/report.d.ts.map +1 -0
  16. package/dist/cli/report.js +53 -0
  17. package/dist/cli/report.js.map +1 -0
  18. package/dist/cli/run.d.ts +3 -0
  19. package/dist/cli/run.d.ts.map +1 -0
  20. package/dist/cli/run.js +79 -0
  21. package/dist/cli/run.js.map +1 -0
  22. package/dist/cli/status.d.ts +3 -0
  23. package/dist/cli/status.d.ts.map +1 -0
  24. package/dist/cli/status.js +45 -0
  25. package/dist/cli/status.js.map +1 -0
  26. package/dist/cli/tail.d.ts +3 -0
  27. package/dist/cli/tail.d.ts.map +1 -0
  28. package/dist/cli/tail.js +46 -0
  29. package/dist/cli/tail.js.map +1 -0
  30. package/dist/cli/update.d.ts +3 -0
  31. package/dist/cli/update.d.ts.map +1 -0
  32. package/dist/cli/update.js +62 -0
  33. package/dist/cli/update.js.map +1 -0
  34. package/dist/cli/validate.d.ts +3 -0
  35. package/dist/cli/validate.d.ts.map +1 -0
  36. package/dist/cli/validate.js +83 -0
  37. package/dist/cli/validate.js.map +1 -0
  38. package/dist/core/backends/claude-code.d.ts +17 -0
  39. package/dist/core/backends/claude-code.d.ts.map +1 -0
  40. package/dist/core/backends/claude-code.js +75 -0
  41. package/dist/core/backends/claude-code.js.map +1 -0
  42. package/dist/core/backends/cursor.d.ts +17 -0
  43. package/dist/core/backends/cursor.d.ts.map +1 -0
  44. package/dist/core/backends/cursor.js +75 -0
  45. package/dist/core/backends/cursor.js.map +1 -0
  46. package/dist/core/backends/noop.d.ts +10 -0
  47. package/dist/core/backends/noop.d.ts.map +1 -0
  48. package/dist/core/backends/noop.js +17 -0
  49. package/dist/core/backends/noop.js.map +1 -0
  50. package/dist/core/backends/opencode.d.ts +16 -0
  51. package/dist/core/backends/opencode.d.ts.map +1 -0
  52. package/dist/core/backends/opencode.js +73 -0
  53. package/dist/core/backends/opencode.js.map +1 -0
  54. package/dist/core/backends/types.d.ts +21 -0
  55. package/dist/core/backends/types.d.ts.map +1 -0
  56. package/dist/core/backends/types.js +3 -0
  57. package/dist/core/backends/types.js.map +1 -0
  58. package/dist/core/budgets/manager.d.ts +21 -0
  59. package/dist/core/budgets/manager.d.ts.map +1 -0
  60. package/dist/core/budgets/manager.js +48 -0
  61. package/dist/core/budgets/manager.js.map +1 -0
  62. package/dist/core/budgets/state.d.ts +25 -0
  63. package/dist/core/budgets/state.d.ts.map +1 -0
  64. package/dist/core/budgets/state.js +33 -0
  65. package/dist/core/budgets/state.js.map +1 -0
  66. package/dist/core/budgets/tiers.d.ts +32 -0
  67. package/dist/core/budgets/tiers.d.ts.map +1 -0
  68. package/dist/core/budgets/tiers.js +67 -0
  69. package/dist/core/budgets/tiers.js.map +1 -0
  70. package/dist/core/engine/context-pack.d.ts +12 -0
  71. package/dist/core/engine/context-pack.d.ts.map +1 -0
  72. package/dist/core/engine/context-pack.js +45 -0
  73. package/dist/core/engine/context-pack.js.map +1 -0
  74. package/dist/core/engine/loop.d.ts +28 -0
  75. package/dist/core/engine/loop.d.ts.map +1 -0
  76. package/dist/core/engine/loop.js +366 -0
  77. package/dist/core/engine/loop.js.map +1 -0
  78. package/dist/core/engine/phases.d.ts +2 -0
  79. package/dist/core/engine/phases.d.ts.map +1 -0
  80. package/dist/core/engine/phases.js +3 -0
  81. package/dist/core/engine/phases.js.map +1 -0
  82. package/dist/core/engine/repair.d.ts +6 -0
  83. package/dist/core/engine/repair.d.ts.map +1 -0
  84. package/dist/core/engine/repair.js +23 -0
  85. package/dist/core/engine/repair.js.map +1 -0
  86. package/dist/core/folders.d.ts +26 -0
  87. package/dist/core/folders.d.ts.map +1 -0
  88. package/dist/core/folders.js +58 -0
  89. package/dist/core/folders.js.map +1 -0
  90. package/dist/core/memory/ledger.d.ts +13 -0
  91. package/dist/core/memory/ledger.d.ts.map +1 -0
  92. package/dist/core/memory/ledger.js +24 -0
  93. package/dist/core/memory/ledger.js.map +1 -0
  94. package/dist/core/memory/persistence.d.ts +45 -0
  95. package/dist/core/memory/persistence.d.ts.map +1 -0
  96. package/dist/core/memory/persistence.js +162 -0
  97. package/dist/core/memory/persistence.js.map +1 -0
  98. package/dist/core/reporting/spend.d.ts +40 -0
  99. package/dist/core/reporting/spend.d.ts.map +1 -0
  100. package/dist/core/reporting/spend.js +157 -0
  101. package/dist/core/reporting/spend.js.map +1 -0
  102. package/dist/core/spec/dag.d.ts +7 -0
  103. package/dist/core/spec/dag.d.ts.map +1 -0
  104. package/dist/core/spec/dag.js +65 -0
  105. package/dist/core/spec/dag.js.map +1 -0
  106. package/dist/core/spec/file-contract.d.ts +13 -0
  107. package/dist/core/spec/file-contract.d.ts.map +1 -0
  108. package/dist/core/spec/file-contract.js +29 -0
  109. package/dist/core/spec/file-contract.js.map +1 -0
  110. package/dist/core/spec/loader.d.ts +8 -0
  111. package/dist/core/spec/loader.d.ts.map +1 -0
  112. package/dist/core/spec/loader.js +51 -0
  113. package/dist/core/spec/loader.js.map +1 -0
  114. package/dist/core/spec/schemas.d.ts +278 -0
  115. package/dist/core/spec/schemas.d.ts.map +1 -0
  116. package/dist/core/spec/schemas.js +207 -0
  117. package/dist/core/spec/schemas.js.map +1 -0
  118. package/dist/core/spec/types.d.ts +71 -0
  119. package/dist/core/spec/types.d.ts.map +1 -0
  120. package/dist/core/spec/types.js +3 -0
  121. package/dist/core/spec/types.js.map +1 -0
  122. package/dist/core/validators/parsers/eslint.d.ts +3 -0
  123. package/dist/core/validators/parsers/eslint.d.ts.map +1 -0
  124. package/dist/core/validators/parsers/eslint.js +35 -0
  125. package/dist/core/validators/parsers/eslint.js.map +1 -0
  126. package/dist/core/validators/parsers/jest.d.ts +3 -0
  127. package/dist/core/validators/parsers/jest.d.ts.map +1 -0
  128. package/dist/core/validators/parsers/jest.js +16 -0
  129. package/dist/core/validators/parsers/jest.js.map +1 -0
  130. package/dist/core/validators/parsers/tsc.d.ts +3 -0
  131. package/dist/core/validators/parsers/tsc.d.ts.map +1 -0
  132. package/dist/core/validators/parsers/tsc.js +32 -0
  133. package/dist/core/validators/parsers/tsc.js.map +1 -0
  134. package/dist/core/validators/runner.d.ts +8 -0
  135. package/dist/core/validators/runner.d.ts.map +1 -0
  136. package/dist/core/validators/runner.js +85 -0
  137. package/dist/core/validators/runner.js.map +1 -0
  138. package/dist/core/validators/signatures.d.ts +3 -0
  139. package/dist/core/validators/signatures.d.ts.map +1 -0
  140. package/dist/core/validators/signatures.js +10 -0
  141. package/dist/core/validators/signatures.js.map +1 -0
  142. package/dist/core/validators/types.d.ts +27 -0
  143. package/dist/core/validators/types.d.ts.map +1 -0
  144. package/dist/core/validators/types.js +3 -0
  145. package/dist/core/validators/types.js.map +1 -0
  146. package/dist/core/workspace/contract-enforcer.d.ts +54 -0
  147. package/dist/core/workspace/contract-enforcer.d.ts.map +1 -0
  148. package/dist/core/workspace/contract-enforcer.js +128 -0
  149. package/dist/core/workspace/contract-enforcer.js.map +1 -0
  150. package/dist/core/workspace/manager.d.ts +28 -0
  151. package/dist/core/workspace/manager.d.ts.map +1 -0
  152. package/dist/core/workspace/manager.js +3 -0
  153. package/dist/core/workspace/manager.js.map +1 -0
  154. package/dist/core/workspace/merge.d.ts +38 -0
  155. package/dist/core/workspace/merge.d.ts.map +1 -0
  156. package/dist/core/workspace/merge.js +92 -0
  157. package/dist/core/workspace/merge.js.map +1 -0
  158. package/dist/core/workspace/patch-mode.d.ts +22 -0
  159. package/dist/core/workspace/patch-mode.d.ts.map +1 -0
  160. package/dist/core/workspace/patch-mode.js +91 -0
  161. package/dist/core/workspace/patch-mode.js.map +1 -0
  162. package/dist/core/workspace/worktree-mode.d.ts +28 -0
  163. package/dist/core/workspace/worktree-mode.d.ts.map +1 -0
  164. package/dist/core/workspace/worktree-mode.js +156 -0
  165. package/dist/core/workspace/worktree-mode.js.map +1 -0
  166. package/dist/index.js +14 -4
  167. package/dist/index.js.map +1 -1
  168. package/dist/templates/shared/openspec-tasks-template.md +23 -3
  169. package/dist/templates/shared/project-template.yml +232 -0
  170. package/dist/utils/installer.d.ts.map +1 -1
  171. package/dist/utils/installer.js +31 -1
  172. package/dist/utils/installer.js.map +1 -1
  173. package/dist/utils/validator.d.ts.map +1 -1
  174. package/dist/utils/validator.js +10 -0
  175. package/dist/utils/validator.js.map +1 -1
  176. package/package.json +11 -4
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.PatchModeWorkspace = void 0;
7
+ exports.getPatchWorkspaceRoot = getPatchWorkspaceRoot;
8
+ const execa_1 = require("execa");
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ const file_contract_1 = require("../spec/file-contract");
11
+ class PatchModeWorkspace {
12
+ repoRoot;
13
+ mode = "patch";
14
+ stateByTask = new Map();
15
+ constructor(repoRoot) {
16
+ this.repoRoot = repoRoot;
17
+ }
18
+ async prepare(taskId) {
19
+ const snapshotCommit = await this.git(["rev-parse", "HEAD"]);
20
+ this.stateByTask.set(taskId, { snapshotCommit });
21
+ return { taskId, workingDir: this.repoRoot };
22
+ }
23
+ getWorkingDir(_taskId) {
24
+ return this.repoRoot;
25
+ }
26
+ async getChangedFiles(_taskId) {
27
+ // name-status gives: A/M/D/R... <path> ...
28
+ const out = await this.git(["diff", "--name-status"]);
29
+ const lines = out
30
+ .split("\n")
31
+ .map((l) => l.trim())
32
+ .filter(Boolean);
33
+ const changed = [];
34
+ for (const line of lines) {
35
+ const parts = line.split(/\s+/);
36
+ const status = parts[0] ?? "";
37
+ const file = parts[1] ?? "";
38
+ if (!file)
39
+ continue;
40
+ changed.push({ file, isNew: status.startsWith("A") });
41
+ }
42
+ return changed;
43
+ }
44
+ async enforceContract(taskId, contract) {
45
+ const changedFiles = await this.getChangedFiles(taskId);
46
+ const violations = (0, file_contract_1.evaluateFileContract)({ changedFiles, contract });
47
+ if (violations.length) {
48
+ await this.revert(taskId);
49
+ }
50
+ return violations;
51
+ }
52
+ async checkpoint(taskId, message) {
53
+ // Best effort: commit all changes. If nothing to commit, return HEAD.
54
+ await this.git(["add", "-A"]);
55
+ const commitMsg = `[ralphy-spec] ${taskId}: ${message}`;
56
+ try {
57
+ await this.git(["commit", "-m", commitMsg]);
58
+ }
59
+ catch {
60
+ // likely "nothing to commit"
61
+ }
62
+ const ref = await this.git(["rev-parse", "HEAD"]);
63
+ return { ref };
64
+ }
65
+ async merge(_taskId) {
66
+ // Patch mode executes on main; merge is no-op.
67
+ }
68
+ async revert(taskId) {
69
+ const state = this.stateByTask.get(taskId);
70
+ if (!state)
71
+ return;
72
+ // Hard revert to snapshot; also remove untracked files.
73
+ await this.git(["reset", "--hard", state.snapshotCommit]);
74
+ await this.git(["clean", "-fd"]);
75
+ }
76
+ async cleanup(_taskId) {
77
+ // No-op for patch mode.
78
+ }
79
+ async git(args) {
80
+ const res = await (0, execa_1.execa)("git", args, {
81
+ cwd: this.repoRoot,
82
+ stdio: "pipe",
83
+ });
84
+ return res.stdout.trim();
85
+ }
86
+ }
87
+ exports.PatchModeWorkspace = PatchModeWorkspace;
88
+ function getPatchWorkspaceRoot(repoRoot) {
89
+ return node_path_1.default.resolve(repoRoot);
90
+ }
91
+ //# sourceMappingURL=patch-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch-mode.js","sourceRoot":"","sources":["../../../src/core/workspace/patch-mode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { FileContract } from "../spec/types";
2
+ import type { CheckpointRef, ContractViolation, WorkspaceContext, WorkspaceManager } from "./manager";
3
+ /**
4
+ * WorktreeModeWorkspace uses git worktrees for task isolation.
5
+ *
6
+ * Each task runs in its own worktree branch, providing complete isolation
7
+ * from the main working directory. Changes are merged back on success.
8
+ */
9
+ export declare class WorktreeModeWorkspace implements WorkspaceManager {
10
+ private readonly repoRoot;
11
+ mode: "worktree";
12
+ private readonly stateByTask;
13
+ private readonly worktreeBase;
14
+ constructor(repoRoot: string);
15
+ prepare(taskId: string): Promise<WorkspaceContext>;
16
+ getWorkingDir(taskId: string): string;
17
+ getChangedFiles(taskId: string): Promise<Array<{
18
+ file: string;
19
+ isNew: boolean;
20
+ }>>;
21
+ enforceContract(taskId: string, contract: FileContract): Promise<ContractViolation[]>;
22
+ checkpoint(taskId: string, message: string): Promise<CheckpointRef>;
23
+ merge(taskId: string): Promise<void>;
24
+ revert(taskId: string): Promise<void>;
25
+ cleanup(taskId: string): Promise<void>;
26
+ private git;
27
+ }
28
+ //# sourceMappingURL=worktree-mode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree-mode.d.ts","sourceRoot":"","sources":["../../../src/core/workspace/worktree-mode.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,KAAK,EACV,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EACjB,MAAM,WAAW,CAAC;AAQnB;;;;;GAKG;AACH,qBAAa,qBAAsB,YAAW,gBAAgB;IAKhD,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAJrC,IAAI,EAAE,UAAU,CAAc;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoC;IAChE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAET,QAAQ,EAAE,MAAM;IAIvC,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAoCxD,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAK/B,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IA2BjF,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAYrF,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAoBnE,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBpC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASrC,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAiB9B,GAAG;CAalB"}
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.WorktreeModeWorkspace = void 0;
7
+ const execa_1 = require("execa");
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const promises_1 = __importDefault(require("node:fs/promises"));
10
+ const file_contract_1 = require("../spec/file-contract");
11
+ /**
12
+ * WorktreeModeWorkspace uses git worktrees for task isolation.
13
+ *
14
+ * Each task runs in its own worktree branch, providing complete isolation
15
+ * from the main working directory. Changes are merged back on success.
16
+ */
17
+ class WorktreeModeWorkspace {
18
+ repoRoot;
19
+ mode = "worktree";
20
+ stateByTask = new Map();
21
+ worktreeBase;
22
+ constructor(repoRoot) {
23
+ this.repoRoot = repoRoot;
24
+ this.worktreeBase = node_path_1.default.join(repoRoot, ".ralphy", "worktrees");
25
+ }
26
+ async prepare(taskId) {
27
+ // Ensure worktree base directory exists
28
+ await promises_1.default.mkdir(this.worktreeBase, { recursive: true });
29
+ // Get current HEAD as base
30
+ const baseCommit = await this.git(["rev-parse", "HEAD"], this.repoRoot);
31
+ // Create a unique branch name for this task
32
+ const branchName = `ralphy/${taskId}/${Date.now()}`;
33
+ const worktreePath = node_path_1.default.join(this.worktreeBase, taskId.replace(/[^a-zA-Z0-9-_]/g, "_"));
34
+ // Clean up existing worktree if present
35
+ try {
36
+ await promises_1.default.rm(worktreePath, { recursive: true, force: true });
37
+ }
38
+ catch {
39
+ // Ignore if doesn't exist
40
+ }
41
+ // Remove stale worktree entry if any
42
+ try {
43
+ await this.git(["worktree", "remove", "--force", worktreePath], this.repoRoot);
44
+ }
45
+ catch {
46
+ // Ignore if doesn't exist
47
+ }
48
+ // Create new worktree with a new branch
49
+ await this.git(["worktree", "add", "-b", branchName, worktreePath, baseCommit], this.repoRoot);
50
+ this.stateByTask.set(taskId, { worktreePath, branchName, baseCommit });
51
+ return { taskId, workingDir: worktreePath };
52
+ }
53
+ getWorkingDir(taskId) {
54
+ const state = this.stateByTask.get(taskId);
55
+ return state?.worktreePath ?? this.repoRoot;
56
+ }
57
+ async getChangedFiles(taskId) {
58
+ const state = this.stateByTask.get(taskId);
59
+ if (!state)
60
+ return [];
61
+ // Get changes compared to base commit
62
+ const out = await this.git(["diff", "--name-status", state.baseCommit], state.worktreePath);
63
+ const lines = out
64
+ .split("\n")
65
+ .map((l) => l.trim())
66
+ .filter(Boolean);
67
+ const changed = [];
68
+ for (const line of lines) {
69
+ const parts = line.split(/\s+/);
70
+ const status = parts[0] ?? "";
71
+ const file = parts[1] ?? "";
72
+ if (!file)
73
+ continue;
74
+ changed.push({ file, isNew: status.startsWith("A") });
75
+ }
76
+ return changed;
77
+ }
78
+ async enforceContract(taskId, contract) {
79
+ const changedFiles = await this.getChangedFiles(taskId);
80
+ const violations = (0, file_contract_1.evaluateFileContract)({ changedFiles, contract });
81
+ if (violations.length) {
82
+ // Revert the worktree to base state
83
+ await this.revert(taskId);
84
+ }
85
+ return violations;
86
+ }
87
+ async checkpoint(taskId, message) {
88
+ const state = this.stateByTask.get(taskId);
89
+ if (!state) {
90
+ throw new Error(`No worktree state for task ${taskId}`);
91
+ }
92
+ // Stage and commit all changes in worktree
93
+ await this.git(["add", "-A"], state.worktreePath);
94
+ const commitMsg = `[ralphy-spec] ${taskId}: ${message}`;
95
+ try {
96
+ await this.git(["commit", "-m", commitMsg], state.worktreePath);
97
+ }
98
+ catch {
99
+ // Likely nothing to commit
100
+ }
101
+ const ref = await this.git(["rev-parse", "HEAD"], state.worktreePath);
102
+ return { ref };
103
+ }
104
+ async merge(taskId) {
105
+ const state = this.stateByTask.get(taskId);
106
+ if (!state)
107
+ return;
108
+ // Get the current branch in main repo
109
+ const currentBranch = await this.git(["rev-parse", "--abbrev-ref", "HEAD"], this.repoRoot);
110
+ // Merge the task branch back using --squash for clean history
111
+ try {
112
+ await this.git(["merge", "--squash", state.branchName], this.repoRoot);
113
+ await this.git(["commit", "-m", `[ralphy-spec] Merge task ${taskId}`], this.repoRoot);
114
+ }
115
+ catch (err) {
116
+ // If merge fails, user may need to resolve manually
117
+ throw new Error(`Failed to merge task ${taskId}: ${err?.message ?? String(err)}. Manual resolution may be required.`);
118
+ }
119
+ }
120
+ async revert(taskId) {
121
+ const state = this.stateByTask.get(taskId);
122
+ if (!state)
123
+ return;
124
+ // Hard reset worktree to base commit
125
+ await this.git(["reset", "--hard", state.baseCommit], state.worktreePath);
126
+ await this.git(["clean", "-fd"], state.worktreePath);
127
+ }
128
+ async cleanup(taskId) {
129
+ const state = this.stateByTask.get(taskId);
130
+ if (!state)
131
+ return;
132
+ try {
133
+ // Remove the worktree
134
+ await this.git(["worktree", "remove", "--force", state.worktreePath], this.repoRoot);
135
+ // Delete the branch
136
+ await this.git(["branch", "-D", state.branchName], this.repoRoot);
137
+ }
138
+ catch {
139
+ // Best effort cleanup
140
+ }
141
+ this.stateByTask.delete(taskId);
142
+ }
143
+ async git(args, cwd) {
144
+ const res = await (0, execa_1.execa)("git", args, {
145
+ cwd,
146
+ stdio: "pipe",
147
+ reject: false,
148
+ });
149
+ if (res.exitCode !== 0 && res.stderr) {
150
+ throw new Error(`git ${args.join(" ")} failed: ${res.stderr}`);
151
+ }
152
+ return res.stdout.trim();
153
+ }
154
+ }
155
+ exports.WorktreeModeWorkspace = WorktreeModeWorkspace;
156
+ //# sourceMappingURL=worktree-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree-mode.js","sourceRoot":"","sources":["../../../src/core/workspace/worktree-mode.ts"],"names":[],"mappings":";;;;;;AAAA,iCAA8B;AAC9B,0DAA6B;AAC7B,gEAAkC;AAElC,yDAA6D;AAc7D;;;;;GAKG;AACH,MAAa,qBAAqB;IAKH;IAJ7B,IAAI,GAAe,UAAU,CAAC;IACb,WAAW,GAAG,IAAI,GAAG,EAAyB,CAAC;IAC/C,YAAY,CAAS;IAEtC,YAA6B,QAAgB;QAAhB,aAAQ,GAAR,QAAQ,CAAQ;QAC3C,IAAI,CAAC,YAAY,GAAG,mBAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAc;QAC1B,wCAAwC;QACxC,MAAM,kBAAE,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEvD,2BAA2B;QAC3B,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAExE,4CAA4C;QAC5C,MAAM,UAAU,GAAG,UAAU,MAAM,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QACpD,MAAM,YAAY,GAAG,mBAAI,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC,CAAC;QAE1F,wCAAwC;QACxC,IAAI,CAAC;YACH,MAAM,kBAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,CAAC;QAAC,MAAM,CAAC;YACP,0BAA0B;QAC5B,CAAC;QAED,qCAAqC;QACrC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjF,CAAC;QAAC,MAAM,CAAC;YACP,0BAA0B;QAC5B,CAAC;QAED,wCAAwC;QACxC,MAAM,IAAI,CAAC,GAAG,CACZ,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,CAAC,EAC/D,IAAI,CAAC,QAAQ,CACd,CAAC;QAEF,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC;QAEvE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC;IAC9C,CAAC;IAED,aAAa,CAAC,MAAc;QAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC3C,OAAO,KAAK,EAAE,YAAY,IAAI,IAAI,CAAC,QAAQ,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,MAAc;QAClC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,CAAC;QAEtB,sCAAsC;QACtC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,CACxB,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,CAAC,UAAU,CAAC,EAC3C,KAAK,CAAC,YAAY,CACnB,CAAC;QAEF,MAAM,KAAK,GAAG,GAAG;aACd,KAAK,CAAC,IAAI,CAAC;aACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACpB,MAAM,CAAC,OAAO,CAAC,CAAC;QAEnB,MAAM,OAAO,GAA4C,EAAE,CAAC;QAC5D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAChC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC9B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC5B,IAAI,CAAC,IAAI;gBAAE,SAAS;YACpB,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACxD,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,MAAc,EAAE,QAAsB;QAC1D,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QACxD,MAAM,UAAU,GAAG,IAAA,oCAAoB,EAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC,CAAC;QAEpE,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;YACtB,oCAAoC;YACpC,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;QAED,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,MAAc,EAAE,OAAe;QAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,8BAA8B,MAAM,EAAE,CAAC,CAAC;QAC1D,CAAC;QAED,2CAA2C;QAC3C,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;QAElD,MAAM,SAAS,GAAG,iBAAiB,MAAM,KAAK,OAAO,EAAE,CAAC;QACxD,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;QAClE,CAAC;QAAC,MAAM,CAAC;YACP,2BAA2B;QAC7B,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;QACtE,OAAO,EAAE,GAAG,EAAE,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,MAAc;QACxB,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK;YAAE,OAAO;QAEnB,sCAAsC;QACtC,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,GAAG,CAClC,CAAC,WAAW,EAAE,cAAc,EAAE,MAAM,CAAC,EACrC,IAAI,CAAC,QAAQ,CACd,CAAC;QAEF,8DAA8D;QAC9D,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;YACvE,MAAM,IAAI,CAAC,GAAG,CACZ,CAAC,QAAQ,EAAE,IAAI,EAAE,4BAA4B,MAAM,EAAE,CAAC,EACtD,IAAI,CAAC,QAAQ,CACd,CAAC;QACJ,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,oDAAoD;YACpD,MAAM,IAAI,KAAK,CACb,wBAAwB,MAAM,KAAK,GAAG,EAAE,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,sCAAsC,CACrG,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,MAAc;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK;YAAE,OAAO;QAEnB,qCAAqC;QACrC,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;QAC1E,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAc;QAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK;YAAE,OAAO;QAEnB,IAAI,CAAC;YACH,sBAAsB;YACtB,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,CAAC,YAAY,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;YAErF,oBAAoB;YACpB,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpE,CAAC;QAAC,MAAM,CAAC;YACP,sBAAsB;QACxB,CAAC;QAED,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC;IAEO,KAAK,CAAC,GAAG,CAAC,IAAc,EAAE,GAAW;QAC3C,MAAM,GAAG,GAAG,MAAM,IAAA,aAAK,EAAC,KAAK,EAAE,IAAI,EAAE;YACnC,GAAG;YACH,KAAK,EAAE,MAAM;YACb,MAAM,EAAE,KAAK;SACd,CAAC,CAAC;QAEH,IAAI,GAAG,CAAC,QAAQ,KAAK,CAAC,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QACjE,CAAC;QAED,OAAO,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IAC3B,CAAC;CACF;AA7KD,sDA6KC"}
package/dist/index.js CHANGED
@@ -1,18 +1,28 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const commander_1 = require("commander");
4
- const init_1 = require("./commands/init");
5
- const validate_1 = require("./commands/validate");
6
- const update_1 = require("./commands/update");
4
+ const init_1 = require("./cli/init");
5
+ const validate_1 = require("./cli/validate");
6
+ const update_1 = require("./cli/update");
7
+ const run_1 = require("./cli/run");
8
+ const status_1 = require("./cli/status");
9
+ const report_1 = require("./cli/report");
10
+ const tail_1 = require("./cli/tail");
11
+ const checkpoint_1 = require("./cli/checkpoint");
7
12
  function buildProgram() {
8
13
  const program = new commander_1.Command();
9
14
  program
10
15
  .name("ralphy-spec")
11
16
  .description("One-command setup for Ralph loop + OpenSpec workflows across Cursor, OpenCode, and Claude Code.")
12
- .version("0.1.1");
17
+ .version("0.1.2");
13
18
  (0, init_1.registerInitCommand)(program);
14
19
  (0, validate_1.registerValidateCommand)(program);
15
20
  (0, update_1.registerUpdateCommand)(program);
21
+ (0, run_1.registerRunCommand)(program);
22
+ (0, status_1.registerStatusCommand)(program);
23
+ (0, report_1.registerReportCommand)(program);
24
+ (0, tail_1.registerTailCommand)(program);
25
+ (0, checkpoint_1.registerCheckpointCommand)(program);
16
26
  return program;
17
27
  }
18
28
  async function main() {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAA,yCAAoC;AACpC,0CAAsD;AACtD,kDAA8D;AAC9D,8CAA0D;AAE1D,SAAS,YAAY;IACnB,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,aAAa,CAAC;SACnB,WAAW,CACV,iGAAiG,CAClG;SACA,OAAO,CAAC,OAAO,CAAC,CAAC;IAEpB,IAAA,0BAAmB,EAAC,OAAO,CAAC,CAAC;IAC7B,IAAA,kCAAuB,EAAC,OAAO,CAAC,CAAC;IACjC,IAAA,8BAAqB,EAAC,OAAO,CAAC,CAAC;IAE/B,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC;IAC/B,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,mEAAmE;AACnE,IAAI,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAA,yCAAoC;AACpC,qCAAiD;AACjD,6CAAyD;AACzD,yCAAqD;AACrD,mCAA+C;AAC/C,yCAAqD;AACrD,yCAAqD;AACrD,qCAAiD;AACjD,iDAA6D;AAE7D,SAAS,YAAY;IACnB,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,aAAa,CAAC;SACnB,WAAW,CACV,iGAAiG,CAClG;SACA,OAAO,CAAC,OAAO,CAAC,CAAC;IAEpB,IAAA,0BAAmB,EAAC,OAAO,CAAC,CAAC;IAC7B,IAAA,kCAAuB,EAAC,OAAO,CAAC,CAAC;IACjC,IAAA,8BAAqB,EAAC,OAAO,CAAC,CAAC;IAC/B,IAAA,wBAAkB,EAAC,OAAO,CAAC,CAAC;IAC5B,IAAA,8BAAqB,EAAC,OAAO,CAAC,CAAC;IAC/B,IAAA,8BAAqB,EAAC,OAAO,CAAC,CAAC;IAC/B,IAAA,0BAAmB,EAAC,OAAO,CAAC,CAAC;IAC7B,IAAA,sCAAyB,EAAC,OAAO,CAAC,CAAC;IAEnC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC;IAC/B,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,mEAAmE;AACnE,IAAI,EAAE,CAAC"}
@@ -3,11 +3,15 @@
3
3
  Use this structure for `openspec/changes/<change-name>/tasks.md`.
4
4
 
5
5
  ## 1. Planning / Scaffolding
6
- - [ ] 1.1 Confirm scope and affected modules
6
+ - [ ] 1.1 Confirm scope, non-goals, and impacted modules
7
+ - Acceptance criteria:
8
+ - GIVEN the current `openspec/specs/` baseline
9
+ - WHEN this change is implemented
10
+ - THEN only the intended domains are affected
7
11
  - Test plan: N/A
8
12
 
9
13
  ## 2. Implementation
10
- - [ ] 2.1 Implement feature behavior
14
+ - [ ] 2.1 Implement feature behavior (spec-driven)
11
15
  - Acceptance criteria:
12
16
  - GIVEN ...
13
17
  - WHEN ...
@@ -16,13 +20,29 @@ Use this structure for `openspec/changes/<change-name>/tasks.md`.
16
20
  - Run: `npm test`
17
21
  - Assert: ...
18
22
 
23
+ ## 3. Validators / Budgets (v2+)
24
+ - [ ] 3.1 Define or update validators used by this change
25
+ - Notes:
26
+ - Validators are the ground truth (deterministic pass/fail)
27
+ - Prefer: `npm run typecheck`, `npm test`, `npm run lint`
28
+ - Test plan:
29
+ - Run the validator commands locally/CI
30
+
31
+ - [ ] 3.2 If the change introduces budgeted execution (v2.1+), document expected behavior
32
+ - Notes:
33
+ - Optimal → Warning → Hard tier expectations
34
+ - WARNING tier should shrink context + enforce repair-only constraints
35
+ - HARD tier should stop safely (no silent retries)
36
+ - Test plan:
37
+ - Run a small demo task that crosses WARNING tier and confirm behaviors
38
+
19
39
  ## 3. Validation
20
40
  - [ ] 3.1 Add/adjust tests to cover all scenarios
21
41
  - Test plan:
22
42
  - Run: `npm test`
23
43
 
24
44
  ## 4. Documentation / Archive
25
- - [ ] 4.1 Update specs and archive change
45
+ - [ ] 4.1 Update OpenSpec docs/spec deltas (if needed) and archive change
26
46
  - Test plan:
27
47
  - Run: `npm test`
28
48
 
@@ -0,0 +1,232 @@
1
+ # ralphy-spec Project Configuration
2
+ # Generated by: ralphy-spec init
3
+ # Version: 2.1 (Budget Intelligence + Sprint Semantics)
4
+
5
+ version: "1.1"
6
+
7
+ project:
8
+ name: "my-project"
9
+ repoRoot: "."
10
+ language: "ts"
11
+ packageManager: "npm" # user-defined: npm | pnpm | yarn | bun
12
+
13
+ defaults:
14
+ backend: "cursor"
15
+ workspaceMode: "patch" # "worktree" | "patch"
16
+ checkpointMode: "commit" # "commit" | "patch"
17
+ validators:
18
+ - typecheck
19
+ - test
20
+ - lint
21
+
22
+ # Artifacts (IDE-friendly human interface)
23
+ # NOTE: These are defaults; users can override or disable.
24
+ artifacts:
25
+ enabled: true
26
+ rootDir: "ralphy-spec" # default; can be overridden via CLI: --artifact-dir
27
+ statusIcons: "emoji" # "emoji" | "ascii" | "none"
28
+
29
+ # Run-level budgets (hard limits for entire run)
30
+ budgets:
31
+ run:
32
+ money_usd: 20 # Max USD per run
33
+ tokens: 2000000 # Max tokens per run
34
+ wall_time_minutes: 90 # Max wall clock time
35
+ max_iterations_total: 80 # Max total iterations across all tasks
36
+
37
+ limits:
38
+ max_parallel_tasks: 1 # Concurrent tasks (v1: always 1)
39
+ max_parallel_validators: 2 # Concurrent validators
40
+ command_timeout_seconds: 900
41
+
42
+ # Sprint size defaults (applied when task has sprint.size but no explicit budget)
43
+ # Users can override per-task
44
+ sprint_defaults:
45
+ XS:
46
+ optimal: { usd: 0.20, tokens: 15000, time_minutes: 3 }
47
+ warning: { usd: 0.35, tokens: 25000, time_minutes: 5 }
48
+ hard: { usd: 0.50, tokens: 40000, time_minutes: 8, max_iterations: 3 }
49
+ S:
50
+ optimal: { usd: 0.50, tokens: 40000, time_minutes: 5 }
51
+ warning: { usd: 0.80, tokens: 65000, time_minutes: 8 }
52
+ hard: { usd: 1.20, tokens: 100000, time_minutes: 12, max_iterations: 5 }
53
+ M:
54
+ optimal: { usd: 1.20, tokens: 80000, time_minutes: 10 }
55
+ warning: { usd: 2.00, tokens: 150000, time_minutes: 15 }
56
+ hard: { usd: 3.00, tokens: 250000, time_minutes: 20, max_iterations: 8 }
57
+ L:
58
+ optimal: { usd: 2.50, tokens: 150000, time_minutes: 20 }
59
+ warning: { usd: 4.00, tokens: 280000, time_minutes: 35 }
60
+ hard: { usd: 6.00, tokens: 450000, time_minutes: 50, max_iterations: 12 }
61
+ XL:
62
+ optimal: { usd: 5.00, tokens: 300000, time_minutes: 40 }
63
+ warning: { usd: 8.00, tokens: 550000, time_minutes: 70 }
64
+ hard: { usd: 12.00, tokens: 900000, time_minutes: 100, max_iterations: 20 }
65
+
66
+ backends:
67
+ cursor:
68
+ command: "cursor"
69
+ modelTiers:
70
+ default: { hint: "balanced" }
71
+ cheap: { hint: "cheap" }
72
+ strong: { hint: "strong" }
73
+ opencode:
74
+ command: "opencode"
75
+ modelTiers:
76
+ default: {}
77
+ cheap: {}
78
+ claude_code:
79
+ command: "claude"
80
+ modelTiers:
81
+ default: {}
82
+
83
+ validators:
84
+ - id: "typecheck"
85
+ # Avoid hard-coding package manager. Choose commands that match your repo.
86
+ run: "npm run typecheck"
87
+ timeout_seconds: 600
88
+ parser: "tsc"
89
+ - id: "test"
90
+ run: "npm test"
91
+ timeout_seconds: 900
92
+ parser: "jest"
93
+ - id: "lint"
94
+ run: "npm run lint"
95
+ timeout_seconds: 600
96
+ parser: "eslint"
97
+
98
+ # Tasks - define your implementation tasks here
99
+ tasks: []
100
+
101
+ # ============================================================
102
+ # TASK EXAMPLES (uncomment and modify as needed)
103
+ # ============================================================
104
+
105
+ # Example 1: Simple fix (XS sprint, uses defaults)
106
+ # - id: "fix-typo-001"
107
+ # title: "Fix typo in error message"
108
+ # goal: "Correct spelling in validation error"
109
+ #
110
+ # sprint:
111
+ # size: XS # Uses XS defaults: $0.20 optimal, 3 max iter
112
+ # intent: "fix" # No refactoring allowed
113
+ #
114
+ # files_contract:
115
+ # allowed: ["src/utils/validation.ts"]
116
+ # forbidden: []
117
+ # allow_new_files: false
118
+ #
119
+ # acceptance:
120
+ # - id: "acc-1"
121
+ # text: "Error message spelled correctly"
122
+ # type: "behavior"
123
+
124
+ # Example 2: Feature (M sprint with custom budget)
125
+ # - id: "auth-001"
126
+ # title: "JWT middleware"
127
+ # goal: "Add JWT auth middleware for API routes"
128
+ #
129
+ # sprint:
130
+ # size: M
131
+ # intent: "feature" # Limited refactoring allowed
132
+ #
133
+ # budget: # Optional: override sprint defaults
134
+ # optimal:
135
+ # usd: 1.2
136
+ # tokens: 80000
137
+ # time_minutes: 10
138
+ # warning:
139
+ # usd: 2.0
140
+ # tokens: 150000
141
+ # time_minutes: 15
142
+ # hard:
143
+ # usd: 3.0
144
+ # tokens: 250000
145
+ # time_minutes: 20
146
+ # max_iterations: 8
147
+ #
148
+ # files_contract:
149
+ # allowed:
150
+ # - "src/middleware/**"
151
+ # - "src/api/**"
152
+ # forbidden:
153
+ # - "src/db/**"
154
+ # allow_new_files: true
155
+ #
156
+ # context:
157
+ # docs: ["README.md"]
158
+ # files: ["src/api/index.ts"]
159
+ #
160
+ # acceptance:
161
+ # - id: "acc-1"
162
+ # text: "Requests without token return 401"
163
+ # type: "behavior"
164
+ # - id: "acc-2"
165
+ # text: "Valid tokens allow access"
166
+ # type: "behavior"
167
+ # - id: "acc-3"
168
+ # text: "Unit tests added"
169
+ # type: "evidence"
170
+ # evidence:
171
+ # must_include_files: ["src/**/__tests__/**"]
172
+ #
173
+ # validators: ["typecheck", "test", "lint"]
174
+ # done_policy:
175
+ # require_all_validators_pass: true
176
+ # require_acceptance_evidence: true
177
+
178
+ # Example 3: Large refactor (L sprint)
179
+ # - id: "refactor-db-001"
180
+ # title: "Migrate to Prisma"
181
+ # goal: "Replace raw SQL with Prisma ORM"
182
+ # deps: ["auth-001"] # Depends on auth task
183
+ #
184
+ # sprint:
185
+ # size: L
186
+ # intent: "refactor" # Full refactoring allowed
187
+ #
188
+ # files_contract:
189
+ # allowed:
190
+ # - "src/db/**"
191
+ # - "prisma/**"
192
+ # forbidden:
193
+ # - "src/api/**" # Don't touch API layer
194
+ # allow_new_files: true
195
+ #
196
+ # acceptance:
197
+ # - id: "acc-1"
198
+ # text: "All database queries use Prisma"
199
+ # type: "behavior"
200
+ # - id: "acc-2"
201
+ # text: "Existing tests pass"
202
+ # type: "evidence"
203
+
204
+ # ============================================================
205
+ # BUDGET TIERS EXPLAINED
206
+ # ============================================================
207
+ #
208
+ # OPTIMAL: Expected cost for correct completion
209
+ # - Agent operates normally with full context
210
+ # - All features enabled (self-review, planning)
211
+ #
212
+ # WARNING: Still acceptable but attention needed
213
+ # - Context shrink: fewer files, only failing tests
214
+ # - Repair-only mode: "fix only, no refactor"
215
+ # - Optional calls disabled
216
+ # - STATUS.md shows pressure signals
217
+ #
218
+ # HARD: Must stop immediately
219
+ # - Task marked as BLOCKED
220
+ # - Workspace preserved for debugging
221
+ # - Failure summary written
222
+ # - No silent retries
223
+ #
224
+ # ============================================================
225
+ # SPRINT SIZES GUIDE
226
+ # ============================================================
227
+ #
228
+ # XS: Single file fix, typo, simple config change
229
+ # S: Small function, add a test, minor refactor
230
+ # M: Feature slice, new endpoint, component
231
+ # L: Multi-file feature, significant change
232
+ # XL: Infrastructure, major refactor, migration
@@ -1 +1 @@
1
- {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../src/utils/installer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAgBvC,wBAAsB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAyB9E;AAED,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GACvB,OAAO,CAAC,IAAI,CAAC,CA+Df"}
1
+ {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../src/utils/installer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAiBvC,wBAAsB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsD9E;AAED,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GACvB,OAAO,CAAC,IAAI,CAAC,CA+Df"}