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,162 @@
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.PersistenceLayer = void 0;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
9
+ const folders_1 = require("../folders");
10
+ const schemaSql = `
11
+ CREATE TABLE IF NOT EXISTS runs (
12
+ id TEXT PRIMARY KEY,
13
+ status TEXT NOT NULL,
14
+ started_at TEXT NOT NULL,
15
+ finished_at TEXT,
16
+ repo_root TEXT NOT NULL,
17
+ backend_id TEXT,
18
+ workspace_mode TEXT
19
+ );
20
+
21
+ CREATE TABLE IF NOT EXISTS tasks (
22
+ run_id TEXT NOT NULL,
23
+ task_id TEXT NOT NULL,
24
+ status TEXT NOT NULL,
25
+ phase TEXT,
26
+ iteration INTEGER NOT NULL DEFAULT 0,
27
+ started_at TEXT,
28
+ finished_at TEXT,
29
+ last_error TEXT,
30
+ PRIMARY KEY (run_id, task_id)
31
+ );
32
+
33
+ CREATE TABLE IF NOT EXISTS ledger (
34
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
35
+ run_id TEXT NOT NULL,
36
+ task_id TEXT,
37
+ ts TEXT NOT NULL,
38
+ kind TEXT NOT NULL,
39
+ message TEXT NOT NULL,
40
+ data_json TEXT
41
+ );
42
+
43
+ CREATE TABLE IF NOT EXISTS issues (
44
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
45
+ run_id TEXT NOT NULL,
46
+ task_id TEXT NOT NULL,
47
+ signature TEXT,
48
+ kind TEXT NOT NULL,
49
+ file TEXT,
50
+ line INTEGER,
51
+ message TEXT NOT NULL,
52
+ raw_json TEXT,
53
+ ts TEXT NOT NULL
54
+ );
55
+
56
+ CREATE TABLE IF NOT EXISTS checkpoints (
57
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
58
+ run_id TEXT NOT NULL,
59
+ task_id TEXT NOT NULL,
60
+ ts TEXT NOT NULL,
61
+ ref TEXT NOT NULL,
62
+ message TEXT NOT NULL
63
+ );
64
+ `;
65
+ class PersistenceLayer {
66
+ db;
67
+ constructor(dbPath) {
68
+ this.db = new better_sqlite3_1.default(dbPath);
69
+ this.db.pragma("journal_mode = WAL");
70
+ this.db.exec(schemaSql);
71
+ }
72
+ static async openForRepo(repoRoot) {
73
+ await (0, folders_1.migrateLegacyIfNeeded)(repoRoot);
74
+ const ralphyDir = await (0, folders_1.ensureRalphyFolders)(repoRoot);
75
+ const dbPath = node_path_1.default.join(ralphyDir, folders_1.FILES.db);
76
+ return new PersistenceLayer(dbPath);
77
+ }
78
+ close() {
79
+ this.db.close();
80
+ }
81
+ createRun(args) {
82
+ this.db
83
+ .prepare(`INSERT INTO runs (id, status, started_at, repo_root, backend_id, workspace_mode)
84
+ VALUES (@runId, 'active', @ts, @repoRoot, @backendId, @workspaceMode)`)
85
+ .run({
86
+ runId: args.runId,
87
+ ts: new Date().toISOString(),
88
+ repoRoot: args.repoRoot,
89
+ backendId: args.backendId ?? null,
90
+ workspaceMode: args.workspaceMode ?? null,
91
+ });
92
+ }
93
+ finishRun(args) {
94
+ this.db
95
+ .prepare(`UPDATE runs
96
+ SET status=@status, finished_at=@ts
97
+ WHERE id=@runId`)
98
+ .run({ runId: args.runId, status: args.status, ts: new Date().toISOString() });
99
+ }
100
+ upsertTaskState(args) {
101
+ this.db
102
+ .prepare(`INSERT INTO tasks (run_id, task_id, status, phase, iteration, started_at, last_error)
103
+ VALUES (@runId, @taskId, @status, @phase, @iteration, @startedAt, @lastError)
104
+ ON CONFLICT(run_id, task_id) DO UPDATE SET
105
+ status=excluded.status,
106
+ phase=excluded.phase,
107
+ iteration=excluded.iteration,
108
+ last_error=excluded.last_error`)
109
+ .run({
110
+ runId: args.runId,
111
+ taskId: args.taskId,
112
+ status: args.status,
113
+ phase: args.phase ?? null,
114
+ iteration: args.iteration ?? 0,
115
+ startedAt: new Date().toISOString(),
116
+ lastError: args.lastError ?? null,
117
+ });
118
+ }
119
+ appendLedger(event) {
120
+ this.db
121
+ .prepare(`INSERT INTO ledger (run_id, task_id, ts, kind, message, data_json)
122
+ VALUES (@runId, @taskId, @ts, @kind, @message, @dataJson)`)
123
+ .run({
124
+ runId: event.runId,
125
+ taskId: event.taskId ?? null,
126
+ ts: event.ts,
127
+ kind: event.kind,
128
+ message: event.message,
129
+ dataJson: event.data ? JSON.stringify(event.data) : null,
130
+ });
131
+ }
132
+ listLedger(args) {
133
+ const rows = this.db
134
+ .prepare(`SELECT run_id as runId, task_id as taskId, ts, kind, message, data_json as dataJson
135
+ FROM ledger
136
+ WHERE run_id=@runId
137
+ ORDER BY id DESC
138
+ LIMIT @limit`)
139
+ .all({ runId: args.runId, limit: args.limit ?? 50 });
140
+ return rows
141
+ .reverse()
142
+ .map((r) => ({
143
+ runId: r.runId,
144
+ taskId: r.taskId ?? undefined,
145
+ ts: r.ts,
146
+ kind: r.kind,
147
+ message: r.message,
148
+ data: r.dataJson ? JSON.parse(r.dataJson) : undefined,
149
+ }));
150
+ }
151
+ getLatestRun() {
152
+ const row = this.db
153
+ .prepare(`SELECT id as runId, status, started_at as startedAt
154
+ FROM runs
155
+ ORDER BY started_at DESC
156
+ LIMIT 1`)
157
+ .get();
158
+ return row ? row : null;
159
+ }
160
+ }
161
+ exports.PersistenceLayer = PersistenceLayer;
162
+ //# sourceMappingURL=persistence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistence.js","sourceRoot":"","sources":["../../../src/core/memory/persistence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import type { BudgetUsage } from "../budgets/state";
2
+ export type SpendEntry = {
3
+ taskId: string;
4
+ backendId?: string;
5
+ phase?: string;
6
+ usd: number;
7
+ tokens: number;
8
+ wallTimeMs: number;
9
+ iterations: number;
10
+ };
11
+ export type SpendBreakdown = {
12
+ total: BudgetUsage;
13
+ byTask: Map<string, BudgetUsage>;
14
+ byBackend: Map<string, BudgetUsage>;
15
+ byPhase: Map<string, BudgetUsage>;
16
+ entries: SpendEntry[];
17
+ };
18
+ /**
19
+ * Aggregate spend data from ledger events.
20
+ *
21
+ * This processes ledger events to build a breakdown of spending
22
+ * by task, backend, and phase.
23
+ */
24
+ export declare function aggregateSpend(events: SpendEntry[]): SpendBreakdown;
25
+ /**
26
+ * Format spend breakdown as markdown report.
27
+ */
28
+ export declare function formatSpendReport(breakdown: SpendBreakdown): string;
29
+ /**
30
+ * Create spend entries from ledger events.
31
+ *
32
+ * This function parses ledger events and extracts spend information
33
+ * from events with kind="iteration_complete" or similar.
34
+ */
35
+ export declare function extractSpendFromLedger(ledgerEvents: Array<{
36
+ taskId?: string;
37
+ kind: string;
38
+ data?: unknown;
39
+ }>): SpendEntry[];
40
+ //# sourceMappingURL=spend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spend.d.ts","sourceRoot":"","sources":["../../../src/core/reporting/spend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,WAAW,CAAC;IACnB,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACjC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAClC,OAAO,EAAE,UAAU,EAAE,CAAC;CACvB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,cAAc,CA0DnE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,cAAc,GAAG,MAAM,CA+DnE;AAYD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,KAAK,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC,GACD,UAAU,EAAE,CA+Bd"}
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.aggregateSpend = aggregateSpend;
4
+ exports.formatSpendReport = formatSpendReport;
5
+ exports.extractSpendFromLedger = extractSpendFromLedger;
6
+ /**
7
+ * Aggregate spend data from ledger events.
8
+ *
9
+ * This processes ledger events to build a breakdown of spending
10
+ * by task, backend, and phase.
11
+ */
12
+ function aggregateSpend(events) {
13
+ const total = { usd: 0, tokens: 0, wallTimeMs: 0, iterations: 0 };
14
+ const byTask = new Map();
15
+ const byBackend = new Map();
16
+ const byPhase = new Map();
17
+ for (const entry of events) {
18
+ // Accumulate total
19
+ total.usd += entry.usd;
20
+ total.tokens += entry.tokens;
21
+ total.wallTimeMs += entry.wallTimeMs;
22
+ total.iterations += entry.iterations;
23
+ // By task
24
+ const taskUsage = byTask.get(entry.taskId) ?? {
25
+ usd: 0,
26
+ tokens: 0,
27
+ wallTimeMs: 0,
28
+ iterations: 0,
29
+ };
30
+ taskUsage.usd += entry.usd;
31
+ taskUsage.tokens += entry.tokens;
32
+ taskUsage.wallTimeMs += entry.wallTimeMs;
33
+ taskUsage.iterations += entry.iterations;
34
+ byTask.set(entry.taskId, taskUsage);
35
+ // By backend (if present)
36
+ if (entry.backendId) {
37
+ const backendUsage = byBackend.get(entry.backendId) ?? {
38
+ usd: 0,
39
+ tokens: 0,
40
+ wallTimeMs: 0,
41
+ iterations: 0,
42
+ };
43
+ backendUsage.usd += entry.usd;
44
+ backendUsage.tokens += entry.tokens;
45
+ backendUsage.wallTimeMs += entry.wallTimeMs;
46
+ backendUsage.iterations += entry.iterations;
47
+ byBackend.set(entry.backendId, backendUsage);
48
+ }
49
+ // By phase (if present)
50
+ if (entry.phase) {
51
+ const phaseUsage = byPhase.get(entry.phase) ?? {
52
+ usd: 0,
53
+ tokens: 0,
54
+ wallTimeMs: 0,
55
+ iterations: 0,
56
+ };
57
+ phaseUsage.usd += entry.usd;
58
+ phaseUsage.tokens += entry.tokens;
59
+ phaseUsage.wallTimeMs += entry.wallTimeMs;
60
+ phaseUsage.iterations += entry.iterations;
61
+ byPhase.set(entry.phase, phaseUsage);
62
+ }
63
+ }
64
+ return { total, byTask, byBackend, byPhase, entries: events };
65
+ }
66
+ /**
67
+ * Format spend breakdown as markdown report.
68
+ */
69
+ function formatSpendReport(breakdown) {
70
+ const lines = [];
71
+ lines.push(`# Spend Breakdown Report`);
72
+ lines.push(``);
73
+ // Total
74
+ lines.push(`## Summary`);
75
+ lines.push(``);
76
+ lines.push(`| Metric | Value |`);
77
+ lines.push(`|--------|-------|`);
78
+ lines.push(`| Total USD | $${breakdown.total.usd.toFixed(4)} |`);
79
+ lines.push(`| Total Tokens | ${breakdown.total.tokens.toLocaleString()} |`);
80
+ lines.push(`| Wall Time | ${formatDuration(breakdown.total.wallTimeMs)} |`);
81
+ lines.push(`| Iterations | ${breakdown.total.iterations} |`);
82
+ lines.push(``);
83
+ // By Task
84
+ if (breakdown.byTask.size > 0) {
85
+ lines.push(`## By Task`);
86
+ lines.push(``);
87
+ lines.push(`| Task | USD | Tokens | Time | Iterations |`);
88
+ lines.push(`|------|-----|--------|------|------------|`);
89
+ for (const [taskId, usage] of breakdown.byTask.entries()) {
90
+ lines.push(`| ${taskId} | $${usage.usd.toFixed(4)} | ${usage.tokens.toLocaleString()} | ${formatDuration(usage.wallTimeMs)} | ${usage.iterations} |`);
91
+ }
92
+ lines.push(``);
93
+ }
94
+ // By Backend
95
+ if (breakdown.byBackend.size > 0) {
96
+ lines.push(`## By Backend`);
97
+ lines.push(``);
98
+ lines.push(`| Backend | USD | Tokens | Time | Iterations |`);
99
+ lines.push(`|---------|-----|--------|------|------------|`);
100
+ for (const [backendId, usage] of breakdown.byBackend.entries()) {
101
+ lines.push(`| ${backendId} | $${usage.usd.toFixed(4)} | ${usage.tokens.toLocaleString()} | ${formatDuration(usage.wallTimeMs)} | ${usage.iterations} |`);
102
+ }
103
+ lines.push(``);
104
+ }
105
+ // By Phase
106
+ if (breakdown.byPhase.size > 0) {
107
+ lines.push(`## By Phase`);
108
+ lines.push(``);
109
+ lines.push(`| Phase | USD | Tokens | Time | Iterations |`);
110
+ lines.push(`|-------|-----|--------|------|------------|`);
111
+ for (const [phase, usage] of breakdown.byPhase.entries()) {
112
+ lines.push(`| ${phase} | $${usage.usd.toFixed(4)} | ${usage.tokens.toLocaleString()} | ${formatDuration(usage.wallTimeMs)} | ${usage.iterations} |`);
113
+ }
114
+ lines.push(``);
115
+ }
116
+ return lines.join("\n");
117
+ }
118
+ /**
119
+ * Format duration in human-readable form.
120
+ */
121
+ function formatDuration(ms) {
122
+ if (ms < 1000)
123
+ return `${ms}ms`;
124
+ if (ms < 60_000)
125
+ return `${(ms / 1000).toFixed(1)}s`;
126
+ if (ms < 3600_000)
127
+ return `${(ms / 60_000).toFixed(1)}m`;
128
+ return `${(ms / 3600_000).toFixed(1)}h`;
129
+ }
130
+ /**
131
+ * Create spend entries from ledger events.
132
+ *
133
+ * This function parses ledger events and extracts spend information
134
+ * from events with kind="iteration_complete" or similar.
135
+ */
136
+ function extractSpendFromLedger(ledgerEvents) {
137
+ const entries = [];
138
+ for (const event of ledgerEvents) {
139
+ // Look for events that contain spend data
140
+ if (event.kind === "iteration_complete" || event.kind === "backend_usage") {
141
+ const data = event.data;
142
+ if (data && event.taskId) {
143
+ entries.push({
144
+ taskId: event.taskId,
145
+ backendId: data.backendId,
146
+ phase: data.phase,
147
+ usd: data.usd ?? 0,
148
+ tokens: data.tokens ?? 0,
149
+ wallTimeMs: data.wallTimeMs ?? 0,
150
+ iterations: 1,
151
+ });
152
+ }
153
+ }
154
+ }
155
+ return entries;
156
+ }
157
+ //# sourceMappingURL=spend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spend.js","sourceRoot":"","sources":["../../../src/core/reporting/spend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { TaskSpec } from "./types";
2
+ export type TaskGraph = {
3
+ tasksById: Map<string, TaskSpec>;
4
+ order: string[];
5
+ };
6
+ export declare function buildTaskDAG(tasks: TaskSpec[]): TaskGraph;
7
+ //# sourceMappingURL=dag.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dag.d.ts","sourceRoot":"","sources":["../../../src/core/spec/dag.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,MAAM,MAAM,SAAS,GAAG;IACtB,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACjC,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC;AAEF,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,SAAS,CAiEzD"}
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildTaskDAG = buildTaskDAG;
4
+ function buildTaskDAG(tasks) {
5
+ const tasksById = new Map();
6
+ for (const t of tasks) {
7
+ if (tasksById.has(t.id)) {
8
+ throw new Error(`Duplicate task id: ${t.id}`);
9
+ }
10
+ tasksById.set(t.id, t);
11
+ }
12
+ const indeg = new Map();
13
+ const adj = new Map();
14
+ for (const id of tasksById.keys()) {
15
+ indeg.set(id, 0);
16
+ adj.set(id, new Set());
17
+ }
18
+ for (const t of tasks) {
19
+ const deps = t.deps ?? [];
20
+ for (const dep of deps) {
21
+ if (!tasksById.has(dep)) {
22
+ throw new Error(`Task ${t.id} depends on missing task ${dep}`);
23
+ }
24
+ adj.get(dep).add(t.id);
25
+ indeg.set(t.id, (indeg.get(t.id) ?? 0) + 1);
26
+ }
27
+ }
28
+ const queue = [];
29
+ for (const [id, d] of indeg.entries()) {
30
+ if (d === 0)
31
+ queue.push(id);
32
+ }
33
+ // Prefer higher priority first (stable-ish by id)
34
+ queue.sort((a, b) => {
35
+ const pa = tasksById.get(a)?.priority ?? 0;
36
+ const pb = tasksById.get(b)?.priority ?? 0;
37
+ if (pa !== pb)
38
+ return pb - pa;
39
+ return a.localeCompare(b);
40
+ });
41
+ const order = [];
42
+ while (queue.length) {
43
+ const id = queue.shift();
44
+ order.push(id);
45
+ for (const next of adj.get(id) ?? []) {
46
+ indeg.set(next, (indeg.get(next) ?? 0) - 1);
47
+ if (indeg.get(next) === 0) {
48
+ queue.push(next);
49
+ queue.sort((a, b) => {
50
+ const pa = tasksById.get(a)?.priority ?? 0;
51
+ const pb = tasksById.get(b)?.priority ?? 0;
52
+ if (pa !== pb)
53
+ return pb - pa;
54
+ return a.localeCompare(b);
55
+ });
56
+ }
57
+ }
58
+ }
59
+ if (order.length !== tasksById.size) {
60
+ const remaining = [...tasksById.keys()].filter((id) => !order.includes(id));
61
+ throw new Error(`Cycle detected in task dependencies. Remaining: ${remaining.join(", ")}`);
62
+ }
63
+ return { tasksById, order };
64
+ }
65
+ //# sourceMappingURL=dag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dag.js","sourceRoot":"","sources":["../../../src/core/spec/dag.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { FileContract } from "./types";
2
+ export type ContractViolation = {
3
+ file: string;
4
+ reason: "forbidden" | "not_allowed" | "new_file_disallowed";
5
+ };
6
+ export declare function evaluateFileContract(args: {
7
+ changedFiles: Array<{
8
+ file: string;
9
+ isNew: boolean;
10
+ }>;
11
+ contract: FileContract;
12
+ }): ContractViolation[];
13
+ //# sourceMappingURL=file-contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-contract.d.ts","sourceRoot":"","sources":["../../../src/core/spec/file-contract.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,GAAG,aAAa,GAAG,qBAAqB,CAAC;CAC7D,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,YAAY,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACtD,QAAQ,EAAE,YAAY,CAAC;CACxB,GAAG,iBAAiB,EAAE,CA6BtB"}
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.evaluateFileContract = evaluateFileContract;
4
+ const minimatch_1 = require("minimatch");
5
+ function evaluateFileContract(args) {
6
+ const { changedFiles, contract } = args;
7
+ const allowed = contract.allowed ?? [];
8
+ const forbidden = contract.forbidden ?? [];
9
+ const allowNewFiles = contract.allowNewFiles ?? true;
10
+ const violations = [];
11
+ for (const { file, isNew } of changedFiles) {
12
+ if (isNew && !allowNewFiles) {
13
+ violations.push({ file, reason: "new_file_disallowed" });
14
+ continue;
15
+ }
16
+ if (forbidden.some((pat) => (0, minimatch_1.minimatch)(file, pat, { dot: true }))) {
17
+ violations.push({ file, reason: "forbidden" });
18
+ continue;
19
+ }
20
+ if (allowed.length) {
21
+ const ok = allowed.some((pat) => (0, minimatch_1.minimatch)(file, pat, { dot: true }));
22
+ if (!ok) {
23
+ violations.push({ file, reason: "not_allowed" });
24
+ }
25
+ }
26
+ }
27
+ return violations;
28
+ }
29
+ //# sourceMappingURL=file-contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-contract.js","sourceRoot":"","sources":["../../../src/core/spec/file-contract.ts"],"names":[],"mappings":";;AAQA,oDAgCC;AAxCD,yCAAsC;AAQtC,SAAgB,oBAAoB,CAAC,IAGpC;IACC,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IAExC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,IAAI,EAAE,CAAC;IACvC,MAAM,SAAS,GAAG,QAAQ,CAAC,SAAS,IAAI,EAAE,CAAC;IAC3C,MAAM,aAAa,GAAG,QAAQ,CAAC,aAAa,IAAI,IAAI,CAAC;IAErD,MAAM,UAAU,GAAwB,EAAE,CAAC;IAE3C,KAAK,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,YAAY,EAAE,CAAC;QAC3C,IAAI,KAAK,IAAI,CAAC,aAAa,EAAE,CAAC;YAC5B,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC,CAAC;YACzD,SAAS;QACX,CAAC;QAED,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAA,qBAAS,EAAC,IAAI,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;YACjE,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;YAC/C,SAAS;QACX,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAA,qBAAS,EAAC,IAAI,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YACtE,IAAI,CAAC,EAAE,EAAE,CAAC;gBACR,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { ProjectSpec } from "./types";
2
+ export declare class SpecLoader {
3
+ private readonly repoRoot;
4
+ constructor(repoRoot: string);
5
+ loadProjectSpec(): Promise<ProjectSpec>;
6
+ private readFirstExisting;
7
+ }
8
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/core/spec/loader.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,qBAAa,UAAU;IACT,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,MAAM;IAEvC,eAAe,IAAI,OAAO,CAAC,WAAW,CAAC;YAqB/B,iBAAiB;CAiBhC"}
@@ -0,0 +1,51 @@
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.SpecLoader = void 0;
7
+ const promises_1 = __importDefault(require("node:fs/promises"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const yaml_1 = __importDefault(require("yaml"));
10
+ const zod_1 = require("zod");
11
+ const schemas_1 = require("./schemas");
12
+ class SpecLoader {
13
+ repoRoot;
14
+ constructor(repoRoot) {
15
+ this.repoRoot = repoRoot;
16
+ }
17
+ async loadProjectSpec() {
18
+ const ymlPath = node_path_1.default.join(this.repoRoot, "openspec", "project.yml");
19
+ const jsonPath = node_path_1.default.join(this.repoRoot, "openspec", "project.json");
20
+ const rawText = await this.readFirstExisting([ymlPath, jsonPath]);
21
+ const raw = rawText.kind === "yml" ? yaml_1.default.parse(rawText.text) : JSON.parse(rawText.text);
22
+ try {
23
+ return schemas_1.projectSpecSchema.parse(raw);
24
+ }
25
+ catch (err) {
26
+ if (err instanceof zod_1.ZodError) {
27
+ const pretty = err.issues
28
+ .map((i) => `- ${i.path.join(".") || "(root)"}: ${i.message}`)
29
+ .join("\n");
30
+ throw new Error(`Invalid OpenSpec project spec:\n${pretty}`);
31
+ }
32
+ throw err;
33
+ }
34
+ }
35
+ async readFirstExisting(candidates) {
36
+ for (const p of candidates) {
37
+ try {
38
+ const text = await promises_1.default.readFile(p, "utf8");
39
+ return { kind: p.endsWith(".json") ? "json" : "yml", path: p, text };
40
+ }
41
+ catch {
42
+ // continue
43
+ }
44
+ }
45
+ throw new Error(`Missing OpenSpec project file. Expected one of:\n${candidates
46
+ .map((p) => `- ${p}`)
47
+ .join("\n")}`);
48
+ }
49
+ }
50
+ exports.SpecLoader = SpecLoader;
51
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/core/spec/loader.ts"],"names":[],"mappings":";;;;;;AAAA,gEAAkC;AAClC,0DAA6B;AAC7B,gDAAwB;AACxB,6BAA+B;AAC/B,uCAA8C;AAG9C,MAAa,UAAU;IACQ;IAA7B,YAA6B,QAAgB;QAAhB,aAAQ,GAAR,QAAQ,CAAQ;IAAG,CAAC;IAEjD,KAAK,CAAC,eAAe;QACnB,MAAM,OAAO,GAAG,mBAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC;QACpE,MAAM,QAAQ,GAAG,mBAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC;QAEtE,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;QAClE,MAAM,GAAG,GACP,OAAO,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,cAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAE/E,IAAI,CAAC;YACH,OAAO,2BAAiB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,cAAQ,EAAE,CAAC;gBAC5B,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM;qBACtB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;qBAC7D,IAAI,CAAC,IAAI,CAAC,CAAC;gBACd,MAAM,IAAI,KAAK,CAAC,mCAAmC,MAAM,EAAE,CAAC,CAAC;YAC/D,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAC7B,UAAoB;QAEpB,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,kBAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;gBAC1C,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC;YACvE,CAAC;YAAC,MAAM,CAAC;gBACP,WAAW;YACb,CAAC;QACH,CAAC;QACD,MAAM,IAAI,KAAK,CACb,oDAAoD,UAAU;aAC3D,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;aACpB,IAAI,CAAC,IAAI,CAAC,EAAE,CAChB,CAAC;IACJ,CAAC;CACF;AAzCD,gCAyCC"}