ralph-research 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +69 -0
  2. package/dist/adapters/extractor/command-extractor.js +46 -4
  3. package/dist/adapters/extractor/command-extractor.js.map +1 -1
  4. package/dist/adapters/fs/json-file-frontier-store.js +4 -2
  5. package/dist/adapters/fs/json-file-frontier-store.js.map +1 -1
  6. package/dist/adapters/fs/lockfile.d.ts +21 -1
  7. package/dist/adapters/fs/lockfile.js +65 -11
  8. package/dist/adapters/fs/lockfile.js.map +1 -1
  9. package/dist/adapters/fs/manifest-loader.d.ts +5 -1
  10. package/dist/adapters/fs/manifest-loader.js +15 -2
  11. package/dist/adapters/fs/manifest-loader.js.map +1 -1
  12. package/dist/adapters/git/git-client.d.ts +2 -0
  13. package/dist/adapters/git/git-client.js +19 -0
  14. package/dist/adapters/git/git-client.js.map +1 -1
  15. package/dist/app/services/manual-decision-service.js +76 -25
  16. package/dist/app/services/manual-decision-service.js.map +1 -1
  17. package/dist/app/services/project-state-service.d.ts +26 -1
  18. package/dist/app/services/project-state-service.js +172 -14
  19. package/dist/app/services/project-state-service.js.map +1 -1
  20. package/dist/app/services/run-admission-service.d.ts +20 -0
  21. package/dist/app/services/run-admission-service.js +30 -0
  22. package/dist/app/services/run-admission-service.js.map +1 -0
  23. package/dist/app/services/run-cycle-service.d.ts +5 -4
  24. package/dist/app/services/run-cycle-service.js +175 -14
  25. package/dist/app/services/run-cycle-service.js.map +1 -1
  26. package/dist/app/services/run-loop-service.d.ts +21 -0
  27. package/dist/app/services/run-loop-service.js +155 -0
  28. package/dist/app/services/run-loop-service.js.map +1 -0
  29. package/dist/cli/commands/demo.js +1 -0
  30. package/dist/cli/commands/demo.js.map +1 -1
  31. package/dist/cli/commands/doctor.d.ts +8 -0
  32. package/dist/cli/commands/doctor.js +59 -0
  33. package/dist/cli/commands/doctor.js.map +1 -0
  34. package/dist/cli/commands/init.js +1 -0
  35. package/dist/cli/commands/init.js.map +1 -1
  36. package/dist/cli/commands/inspect.js +4 -0
  37. package/dist/cli/commands/inspect.js.map +1 -1
  38. package/dist/cli/commands/run.d.ts +3 -1
  39. package/dist/cli/commands/run.js +31 -28
  40. package/dist/cli/commands/run.js.map +1 -1
  41. package/dist/cli/commands/status.js +35 -4
  42. package/dist/cli/commands/status.js.map +1 -1
  43. package/dist/cli/commands/validate.js +21 -18
  44. package/dist/cli/commands/validate.js.map +1 -1
  45. package/dist/cli/main.js +3 -10
  46. package/dist/cli/main.js.map +1 -1
  47. package/dist/core/engine/cycle-runner.d.ts +2 -0
  48. package/dist/core/engine/cycle-runner.js +504 -34
  49. package/dist/core/engine/cycle-runner.js.map +1 -1
  50. package/dist/core/engine/promotion-artifact.d.ts +23 -0
  51. package/dist/core/engine/promotion-artifact.js +58 -0
  52. package/dist/core/engine/promotion-artifact.js.map +1 -0
  53. package/dist/core/engine/workspace-manager.d.ts +10 -1
  54. package/dist/core/engine/workspace-manager.js +70 -3
  55. package/dist/core/engine/workspace-manager.js.map +1 -1
  56. package/dist/core/manifest/admission.d.ts +16 -0
  57. package/dist/core/manifest/admission.js +64 -0
  58. package/dist/core/manifest/admission.js.map +1 -0
  59. package/dist/core/manifest/schema.d.ts +47 -0
  60. package/dist/core/manifest/schema.js +18 -1
  61. package/dist/core/manifest/schema.js.map +1 -1
  62. package/dist/core/model/decision-record.d.ts +4 -0
  63. package/dist/core/model/decision-record.js +6 -0
  64. package/dist/core/model/decision-record.js.map +1 -1
  65. package/dist/core/model/metric-diagnostics.d.ts +7 -0
  66. package/dist/core/model/metric-diagnostics.js +51 -0
  67. package/dist/core/model/metric-diagnostics.js.map +1 -0
  68. package/dist/core/model/run-record.d.ts +6 -0
  69. package/dist/core/model/run-record.js +4 -0
  70. package/dist/core/model/run-record.js.map +1 -1
  71. package/dist/core/state/frontier-materializer.d.ts +12 -0
  72. package/dist/core/state/frontier-materializer.js +74 -0
  73. package/dist/core/state/frontier-materializer.js.map +1 -0
  74. package/dist/core/state/frontier-semantics.d.ts +12 -0
  75. package/dist/core/state/frontier-semantics.js +26 -0
  76. package/dist/core/state/frontier-semantics.js.map +1 -0
  77. package/dist/core/state/ratchet-engine.js +29 -21
  78. package/dist/core/state/ratchet-engine.js.map +1 -1
  79. package/dist/core/state/recovery-classifier.d.ts +17 -0
  80. package/dist/core/state/recovery-classifier.js +150 -0
  81. package/dist/core/state/recovery-classifier.js.map +1 -0
  82. package/dist/core/state/run-state-machine.js +33 -23
  83. package/dist/core/state/run-state-machine.js.map +1 -1
  84. package/dist/core/state/stopping-target.d.ts +14 -0
  85. package/dist/core/state/stopping-target.js +67 -0
  86. package/dist/core/state/stopping-target.js.map +1 -0
  87. package/dist/mcp/server.js +17 -23
  88. package/dist/mcp/server.js.map +1 -1
  89. package/package.json +2 -2
  90. package/templates/writing/ralph.yaml +7 -0
package/README.md CHANGED
@@ -26,6 +26,7 @@ This creates a temporary writing repo, runs one accepted cycle, and prints the p
26
26
  ```bash
27
27
  npx ralph-research init --template writing
28
28
  npx ralph-research run --json
29
+ npx ralph-research run --until-target --until-no-improve 3 --json
29
30
  npx ralph-research inspect run-0001 --json
30
31
  ```
31
32
 
@@ -60,6 +61,8 @@ rrx doctor
60
61
  rrx init --template writing
61
62
  rrx demo writing
62
63
  rrx run
64
+ rrx run --until-target
65
+ rrx run --until-target --until-no-improve 3
63
66
  rrx status
64
67
  rrx frontier
65
68
  rrx inspect <runId>
@@ -68,6 +71,72 @@ rrx reject <runId>
68
71
  rrx serve-mcp --stdio
69
72
  ```
70
73
 
74
+ `rrx run --cycles N` still executes a finite loop. Progressive modes are opt-in:
75
+
76
+ - `--until-target`: keep iterating until `manifest.stopping.target` is satisfied
77
+ - `--until-no-improve N`: stop after `N` consecutive cycles without a frontier improvement
78
+ - `--cycles N` with a progressive flag: treat `N` as a max-cycle cap instead of an exact count
79
+
80
+ `rrx status` now reports both the persisted latest run snapshot and the runtime view derived from the lock heartbeat, so `running (alive)` is distinguished from `stale (resumable)` and the output includes heartbeat and last-progress timestamps when available.
81
+
82
+ ## Stopping Targets
83
+
84
+ Use `stopping.target` when the workflow contract is "keep going until metric X reaches threshold Y":
85
+
86
+ ```yaml
87
+ metrics:
88
+ catalog:
89
+ - id: exact_rate
90
+ kind: numeric
91
+ direction: maximize
92
+ extractor:
93
+ type: command
94
+ command: "python scripts/metric.py"
95
+ parser: plain_number
96
+
97
+ frontier:
98
+ strategy: single_best
99
+ primaryMetric: exact_rate
100
+
101
+ ratchet:
102
+ type: epsilon_improve
103
+ metric: exact_rate
104
+ epsilon: 0
105
+
106
+ stopping:
107
+ target:
108
+ metric: exact_rate
109
+ op: ">="
110
+ value: 0.8
111
+ ```
112
+
113
+ ## Metric Diagnostics
114
+
115
+ If a metric script can explain why a candidate was zeroed or downgraded, prefer JSON output plus `parser: json_path` so the reason survives into `run`, `decision`, and `inspect` output:
116
+
117
+ ```yaml
118
+ metrics:
119
+ catalog:
120
+ - id: exact_rate
121
+ kind: numeric
122
+ direction: maximize
123
+ extractor:
124
+ type: command
125
+ command: "python scripts/metric.py"
126
+ parser: json_path
127
+ valuePath: $.value
128
+ ```
129
+
130
+ ```json
131
+ {
132
+ "value": 0,
133
+ "metricId": "overfit_safe_exact_rate",
134
+ "reasons": ["all_missing_features", "normalized_order_leak"]
135
+ }
136
+ ```
137
+
138
+ When `project.workspace=git`, rrx now warns if proposer, experiment, or metric command files are dirty in the working tree, because detached candidate worktrees only see committed baseline content.
139
+
71
140
  ## MCP
72
141
 
73
142
  The bundled MCP server currently supports stdio transport and exposes three thin tools backed by the same service layer as the CLI:
@@ -12,23 +12,29 @@ export async function extractCommandMetric(config, input) {
12
12
  if (result.exitCode !== 0) {
13
13
  throw new Error(`command metric extractor failed with exit code ${result.exitCode}: ${result.stderr || result.stdout}`);
14
14
  }
15
+ const parsedMetric = parseMetricValue(result.stdout, config);
15
16
  return {
16
17
  metricId: input.metricId,
17
18
  direction: input.direction,
18
- value: parseMetricValue(result.stdout, config),
19
+ value: parsedMetric.value,
19
20
  details: {
20
21
  parser: config.parser,
21
22
  command: config.command,
22
23
  cwd,
24
+ ...(parsedMetric.details ? parsedMetric.details : {}),
23
25
  },
24
26
  };
25
27
  }
26
28
  function parseMetricValue(stdout, config) {
27
29
  switch (config.parser) {
28
30
  case "plain_number":
29
- return parseNumericValue(stdout.trim(), "plain_number");
31
+ return {
32
+ value: parseNumericValue(stdout.trim(), "plain_number"),
33
+ };
30
34
  case "regex":
31
- return parseRegexValue(stdout, config.pattern);
35
+ return {
36
+ value: parseRegexValue(stdout, config.pattern),
37
+ };
32
38
  case "json_path":
33
39
  return parseJsonPathValue(stdout, config.valuePath);
34
40
  }
@@ -50,7 +56,11 @@ function parseJsonPathValue(stdout, valuePath) {
50
56
  }
51
57
  const json = JSON.parse(stdout);
52
58
  const value = readJsonPath(json, valuePath);
53
- return parseNumericValue(value, "json_path");
59
+ const details = extractJsonMetricDetails(json);
60
+ return {
61
+ value: parseNumericValue(value, "json_path"),
62
+ ...(Object.keys(details).length > 0 ? { details } : {}),
63
+ };
54
64
  }
55
65
  function readJsonPath(root, path) {
56
66
  if (!path.startsWith("$")) {
@@ -90,4 +100,36 @@ function parseNumericValue(value, parserName) {
90
100
  }
91
101
  return numericValue;
92
102
  }
103
+ function extractJsonMetricDetails(root) {
104
+ if (!root || typeof root !== "object" || Array.isArray(root)) {
105
+ return {};
106
+ }
107
+ const record = root;
108
+ const details = {};
109
+ if (typeof record.reason === "string") {
110
+ details.reason = record.reason;
111
+ }
112
+ if (Array.isArray(record.reasons)) {
113
+ details.reasons = record.reasons.filter((entry) => typeof entry === "string");
114
+ }
115
+ if (typeof record.metricId === "string") {
116
+ details.sourceMetricId = record.metricId;
117
+ }
118
+ if (typeof record.sourceMetricId === "string") {
119
+ details.sourceMetricId = record.sourceMetricId;
120
+ }
121
+ if (Array.isArray(record.invalidReasons)) {
122
+ details.invalidReasons = record.invalidReasons.filter((entry) => typeof entry === "string");
123
+ }
124
+ if (Array.isArray(record.flags)) {
125
+ details.flags = record.flags.filter((entry) => typeof entry === "string");
126
+ }
127
+ if (Array.isArray(record.diagnostics)) {
128
+ details.diagnostics = record.diagnostics.filter((entry) => typeof entry === "string");
129
+ }
130
+ if (record.details && typeof record.details === "object" && !Array.isArray(record.details)) {
131
+ Object.assign(details, record.details);
132
+ }
133
+ return details;
134
+ }
93
135
  //# sourceMappingURL=command-extractor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"command-extractor.js","sourceRoot":"","sources":["../../../src/adapters/extractor/command-extractor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"command-extractor.js","sourceRoot":"","sources":["../../../src/adapters/extractor/command-extractor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAYrC,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAAoC,EACpC,KAAgC;IAEhC,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IACjG,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,OAAO,EAAE;QAChD,GAAG;QACH,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,EAAE;QACpD,MAAM,EAAE,KAAK;QACb,KAAK,EAAE,IAAI;QACX,OAAO,EAAE,MAAM,CAAC,UAAU,GAAG,KAAK;KACnC,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,kDAAkD,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1H,CAAC;IAED,MAAM,YAAY,GAAG,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE7D,OAAO;QACL,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,KAAK,EAAE,YAAY,CAAC,KAAK;QACzB,OAAO,EAAE;YACP,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,GAAG;YACH,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;SACtD;KACF,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CACvB,MAAc,EACd,MAAoC;IAKpC,QAAQ,MAAM,CAAC,MAAM,EAAE,CAAC;QACtB,KAAK,cAAc;YACjB,OAAO;gBACL,KAAK,EAAE,iBAAiB,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,cAAc,CAAC;aACxD,CAAC;QACJ,KAAK,OAAO;YACV,OAAO;gBACL,KAAK,EAAE,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC;aAC/C,CAAC;QACJ,KAAK,WAAW;YACd,OAAO,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IACxD,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,MAAc,EAAE,OAAgB;IACvD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;IACrF,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACpD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,sCAAsC,OAAO,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;IAC9D,OAAO,iBAAiB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,kBAAkB,CACzB,MAAc,EACd,SAAkB;IAKlB,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAC;IAC3F,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAY,CAAC;IAC3C,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,wBAAwB,CAAC,IAAI,CAAC,CAAC;IAE/C,OAAO;QACL,KAAK,EAAE,iBAAiB,CAAC,KAAK,EAAE,WAAW,CAAC;QAC5C,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACxD,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,IAAa,EAAE,IAAY;IAC/C,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,MAAM,GAAG,IAAI;SAChB,KAAK,CAAC,CAAC,CAAC;SACR,OAAO,CAAC,YAAY,EAAE,KAAK,CAAC;SAC5B,KAAK,CAAC,GAAG,CAAC;SACV,MAAM,CAAC,OAAO,CAAC,CAAC;IAEnB,IAAI,OAAO,GAAY,IAAI,CAAC;IAC5B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,YAAY,IAAI,mCAAmC,KAAK,EAAE,CAAC,CAAC;QAC9E,CAAC;QAED,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACzC,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;YACzB,SAAS;QACX,CAAC;QAED,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAChC,OAAO,GAAI,OAAmC,CAAC,KAAK,CAAC,CAAC;YACtD,SAAS;QACX,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,YAAY,IAAI,qDAAqD,KAAK,EAAE,CAAC,CAAC;IAChG,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAc,EAAE,UAAkB;IAC3D,MAAM,YAAY,GAChB,OAAO,KAAK,KAAK,QAAQ;QACvB,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ;YACzB,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YACjC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;IAEnB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,GAAG,UAAU,4CAA4C,CAAC,CAAC;IAC7E,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,SAAS,wBAAwB,CAAC,IAAa;IAC7C,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7D,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,MAAM,GAAG,IAA+B,CAAC;IAC/C,MAAM,OAAO,GAA4B,EAAE,CAAC;IAE5C,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QACtC,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IACjC,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QAClC,OAAO,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC;IACjG,CAAC;IACD,IAAI,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,CAAC,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC;IAC3C,CAAC;IACD,IAAI,OAAO,MAAM,CAAC,cAAc,KAAK,QAAQ,EAAE,CAAC;QAC9C,OAAO,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC;IACjD,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC;QACzC,OAAO,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC;IAC/G,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC;IAC7F,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;QACtC,OAAO,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC;IACzG,CAAC;IACD,IAAI,MAAM,CAAC,OAAO,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3F,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -1,4 +1,4 @@
1
- import { mkdir, readFile, writeFile } from "node:fs/promises";
1
+ import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
2
2
  import { dirname, resolve } from "node:path";
3
3
  import { frontierEntrySchema } from "../../core/model/frontier-entry.js";
4
4
  import { isMissingFileError } from "../../shared/fs-errors.js";
@@ -10,8 +10,10 @@ export class JsonFileFrontierStore {
10
10
  }
11
11
  async save(entries) {
12
12
  const parsed = frontierSnapshotSchema.parse(entries);
13
+ const tempPath = `${this.path}.tmp-${process.pid}`;
13
14
  await mkdir(dirname(this.path), { recursive: true });
14
- await writeFile(this.path, `${JSON.stringify(parsed, null, 2)}\n`, "utf8");
15
+ await writeFile(tempPath, `${JSON.stringify(parsed, null, 2)}\n`, "utf8");
16
+ await rename(tempPath, this.path);
15
17
  }
16
18
  async load() {
17
19
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"json-file-frontier-store.js","sourceRoot":"","sources":["../../../src/adapters/fs/json-file-frontier-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,EAAE,mBAAmB,EAAsB,MAAM,oCAAoC,CAAC;AAE7F,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,MAAM,sBAAsB,GAAG,mBAAmB,CAAC,KAAK,EAAE,CAAC;AAE3D,MAAM,OAAO,qBAAqB;IACf,IAAI,CAAS;IAE9B,YAAmB,IAAY;QAC7B,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,OAAwB;QACxC,MAAM,MAAM,GAAG,sBAAsB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrD,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC7E,CAAC;IAEM,KAAK,CAAC,IAAI;QACf,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC9C,OAAO,sBAAsB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC9B,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"json-file-frontier-store.js","sourceRoot":"","sources":["../../../src/adapters/fs/json-file-frontier-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,EAAE,mBAAmB,EAAsB,MAAM,oCAAoC,CAAC;AAE7F,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,MAAM,sBAAsB,GAAG,mBAAmB,CAAC,KAAK,EAAE,CAAC;AAE3D,MAAM,OAAO,qBAAqB;IACf,IAAI,CAAS;IAE9B,YAAmB,IAAY;QAC7B,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,OAAwB;QACxC,MAAM,MAAM,GAAG,sBAAsB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrD,MAAM,QAAQ,GAAG,GAAG,IAAI,CAAC,IAAI,QAAQ,OAAO,CAAC,GAAG,EAAE,CAAC;QACnD,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,MAAM,SAAS,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC1E,MAAM,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IAEM,KAAK,CAAC,IAAI;QACf,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC9C,OAAO,sBAAsB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC9B,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF"}
@@ -5,20 +5,40 @@ declare const lockfileMetadataSchema: z.ZodObject<{
5
5
  createdAt: z.ZodString;
6
6
  updatedAt: z.ZodString;
7
7
  ttlMs: z.ZodNumber;
8
+ graceMs: z.ZodDefault<z.ZodNumber>;
9
+ owner: z.ZodOptional<z.ZodObject<{
10
+ runId: z.ZodOptional<z.ZodString>;
11
+ operation: z.ZodOptional<z.ZodString>;
12
+ }, z.core.$strip>>;
8
13
  }, z.core.$strip>;
9
14
  export type LockfileMetadata = z.infer<typeof lockfileMetadataSchema>;
10
15
  export interface AcquireLockOptions {
11
16
  ttlMs?: number;
17
+ graceMs?: number;
18
+ owner?: LockfileMetadata["owner"];
12
19
  }
13
20
  export interface LockHandle {
14
21
  path: string;
15
22
  metadata: LockfileMetadata;
16
23
  }
24
+ export interface LockRuntimeState {
25
+ metadata: LockfileMetadata;
26
+ processAlive: boolean;
27
+ stale: boolean;
28
+ heartbeatAgeMs: number;
29
+ }
17
30
  export declare class LockAcquisitionError extends Error {
18
- constructor(message: string);
31
+ readonly metadata: LockfileMetadata | undefined;
32
+ readonly heartbeatAgeMs: number | undefined;
33
+ constructor(message: string, options?: {
34
+ metadata?: LockfileMetadata;
35
+ heartbeatAgeMs?: number;
36
+ });
19
37
  }
20
38
  export declare function acquireLock(path: string, options?: AcquireLockOptions): Promise<LockHandle>;
39
+ export declare function renewLock(path: string, token: string): Promise<LockfileMetadata>;
21
40
  export declare function releaseLock(path: string, token?: string): Promise<void>;
22
41
  export declare function isStaleLock(path: string): Promise<boolean>;
42
+ export declare function inspectLock(path: string): Promise<LockRuntimeState | null>;
23
43
  export declare function readLockMetadata(path: string): Promise<LockfileMetadata | null>;
24
44
  export {};
@@ -3,30 +3,45 @@ import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
3
3
  import { dirname, resolve } from "node:path";
4
4
  import { z } from "zod";
5
5
  import { isMissingFileError } from "../../shared/fs-errors.js";
6
+ const DEFAULT_LOCK_TTL_MS = 5 * 60 * 1000;
7
+ const DEFAULT_LOCK_GRACE_MS = 30 * 1000;
8
+ const lockOwnerSchema = z.object({
9
+ runId: z.string().min(1).optional(),
10
+ operation: z.string().min(1).optional(),
11
+ });
6
12
  const lockfileMetadataSchema = z.object({
7
13
  pid: z.number().int().positive(),
8
14
  token: z.string().min(1),
9
15
  createdAt: z.string().datetime(),
10
16
  updatedAt: z.string().datetime(),
11
17
  ttlMs: z.number().int().positive(),
18
+ graceMs: z.number().int().nonnegative().default(DEFAULT_LOCK_GRACE_MS),
19
+ owner: lockOwnerSchema.optional(),
12
20
  });
13
21
  export class LockAcquisitionError extends Error {
14
- constructor(message) {
22
+ metadata;
23
+ heartbeatAgeMs;
24
+ constructor(message, options = {}) {
15
25
  super(message);
16
26
  this.name = "LockAcquisitionError";
27
+ this.metadata = options.metadata;
28
+ this.heartbeatAgeMs = options.heartbeatAgeMs;
17
29
  }
18
30
  }
19
- const DEFAULT_LOCK_TTL_MS = 5 * 60 * 1000;
20
31
  export async function acquireLock(path, options = {}) {
21
32
  const resolvedPath = resolve(path);
22
33
  const ttlMs = options.ttlMs ?? DEFAULT_LOCK_TTL_MS;
34
+ const graceMs = options.graceMs ?? DEFAULT_LOCK_GRACE_MS;
23
35
  await mkdir(dirname(resolvedPath), { recursive: true });
36
+ const now = new Date().toISOString();
24
37
  const metadata = {
25
38
  pid: process.pid,
26
39
  token: randomUUID(),
27
- createdAt: new Date().toISOString(),
28
- updatedAt: new Date().toISOString(),
40
+ createdAt: now,
41
+ updatedAt: now,
29
42
  ttlMs,
43
+ graceMs,
44
+ ...(options.owner ? { owner: options.owner } : {}),
30
45
  };
31
46
  try {
32
47
  await writeFile(resolvedPath, `${JSON.stringify(metadata, null, 2)}\n`, {
@@ -40,9 +55,20 @@ export async function acquireLock(path, options = {}) {
40
55
  throw error;
41
56
  }
42
57
  }
58
+ const existing = await readLockMetadata(resolvedPath);
43
59
  const stale = await isStaleLock(resolvedPath);
44
60
  if (!stale) {
45
- throw new LockAcquisitionError(`Active lock already exists at ${resolvedPath}`);
61
+ const heartbeatAgeMs = existing ? Date.now() - Date.parse(existing.updatedAt) : undefined;
62
+ const details = [
63
+ `Active lock already exists at ${resolvedPath}`,
64
+ existing ? `pid=${existing.pid}` : null,
65
+ existing?.owner?.runId ? `runId=${existing.owner.runId}` : null,
66
+ heartbeatAgeMs === undefined ? null : `heartbeatAgeMs=${heartbeatAgeMs}`,
67
+ ].filter(Boolean).join(" ");
68
+ throw new LockAcquisitionError(details, {
69
+ ...(existing ? { metadata: existing } : {}),
70
+ ...(heartbeatAgeMs === undefined ? {} : { heartbeatAgeMs }),
71
+ });
46
72
  }
47
73
  await rm(resolvedPath, { force: true });
48
74
  await writeFile(resolvedPath, `${JSON.stringify(metadata, null, 2)}\n`, {
@@ -51,6 +77,24 @@ export async function acquireLock(path, options = {}) {
51
77
  });
52
78
  return { path: resolvedPath, metadata };
53
79
  }
80
+ export async function renewLock(path, token) {
81
+ const resolvedPath = resolve(path);
82
+ const metadata = await readLockMetadata(resolvedPath);
83
+ if (!metadata) {
84
+ throw new LockAcquisitionError(`Refusing to renew lock at ${resolvedPath}: lock is missing`);
85
+ }
86
+ if (metadata.token !== token) {
87
+ throw new LockAcquisitionError(`Refusing to renew lock at ${resolvedPath}: token mismatch`, {
88
+ metadata,
89
+ });
90
+ }
91
+ const updated = {
92
+ ...metadata,
93
+ updatedAt: new Date().toISOString(),
94
+ };
95
+ await writeFile(resolvedPath, `${JSON.stringify(updated, null, 2)}\n`, "utf8");
96
+ return updated;
97
+ }
54
98
  export async function releaseLock(path, token) {
55
99
  const resolvedPath = resolve(path);
56
100
  const metadata = await readLockMetadata(resolvedPath);
@@ -63,15 +107,25 @@ export async function releaseLock(path, token) {
63
107
  await rm(resolvedPath, { force: true });
64
108
  }
65
109
  export async function isStaleLock(path) {
66
- const metadata = await readLockMetadata(path);
67
- if (!metadata) {
110
+ const runtime = await inspectLock(path);
111
+ if (!runtime) {
68
112
  return false;
69
113
  }
70
- const ageMs = Date.now() - Date.parse(metadata.updatedAt);
71
- if (ageMs > metadata.ttlMs) {
72
- return true;
114
+ return runtime.stale;
115
+ }
116
+ export async function inspectLock(path) {
117
+ const metadata = await readLockMetadata(path);
118
+ if (!metadata) {
119
+ return null;
73
120
  }
74
- return !isProcessAlive(metadata.pid);
121
+ const heartbeatAgeMs = Date.now() - Date.parse(metadata.updatedAt);
122
+ const processAlive = isProcessAlive(metadata.pid);
123
+ return {
124
+ metadata,
125
+ processAlive,
126
+ stale: heartbeatAgeMs > metadata.ttlMs + metadata.graceMs || !processAlive,
127
+ heartbeatAgeMs,
128
+ };
75
129
  }
76
130
  export async function readLockMetadata(path) {
77
131
  const resolvedPath = resolve(path);
@@ -1 +1 @@
1
- {"version":3,"file":"lockfile.js","sourceRoot":"","sources":["../../../src/adapters/fs/lockfile.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lockfile.js","sourceRoot":"","sources":["../../../src/adapters/fs/lockfile.ts"],"names":[],"mappings":"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"}
@@ -2,9 +2,13 @@ import { type RalphManifest } from "../../core/manifest/schema.js";
2
2
  export interface LoadedManifest {
3
3
  path: string;
4
4
  manifest: RalphManifest;
5
+ resolvedBaselineRef: string;
5
6
  }
6
7
  export declare class ManifestLoadError extends Error {
7
8
  readonly causeValue?: unknown;
8
9
  constructor(message: string, causeValue?: unknown);
9
10
  }
10
- export declare function loadManifestFromFile(path?: string): Promise<LoadedManifest>;
11
+ export interface LoadManifestOptions {
12
+ repoRoot?: string;
13
+ }
14
+ export declare function loadManifestFromFile(path?: string, options?: LoadManifestOptions): Promise<LoadedManifest>;
@@ -2,6 +2,7 @@ import { readFile } from "node:fs/promises";
2
2
  import { resolve } from "node:path";
3
3
  import { parse } from "yaml";
4
4
  import { ZodError } from "zod";
5
+ import { compileManifestAdmission } from "../../core/manifest/admission.js";
5
6
  import { DEFAULT_MANIFEST_FILENAME, RalphManifestSchema } from "../../core/manifest/schema.js";
6
7
  export class ManifestLoadError extends Error {
7
8
  causeValue;
@@ -11,7 +12,7 @@ export class ManifestLoadError extends Error {
11
12
  this.causeValue = causeValue;
12
13
  }
13
14
  }
14
- export async function loadManifestFromFile(path = DEFAULT_MANIFEST_FILENAME) {
15
+ export async function loadManifestFromFile(path = DEFAULT_MANIFEST_FILENAME, options = {}) {
15
16
  const resolvedPath = resolve(path);
16
17
  let rawText;
17
18
  try {
@@ -28,12 +29,24 @@ export async function loadManifestFromFile(path = DEFAULT_MANIFEST_FILENAME) {
28
29
  throw new ManifestLoadError(`Failed to parse YAML from ${resolvedPath}`, error);
29
30
  }
30
31
  try {
32
+ const manifest = RalphManifestSchema.parse(parsedYaml);
33
+ const admission = await compileManifestAdmission(manifest, options);
34
+ if (!admission.executable) {
35
+ throw new ManifestLoadError(`Manifest admission failed for ${resolvedPath}`, {
36
+ executable: false,
37
+ issues: admission.issues,
38
+ });
39
+ }
31
40
  return {
32
41
  path: resolvedPath,
33
- manifest: RalphManifestSchema.parse(parsedYaml),
42
+ manifest,
43
+ resolvedBaselineRef: admission.resolvedBaselineRef,
34
44
  };
35
45
  }
36
46
  catch (error) {
47
+ if (error instanceof ManifestLoadError) {
48
+ throw error;
49
+ }
37
50
  if (error instanceof ZodError) {
38
51
  throw new ManifestLoadError(`Manifest validation failed for ${resolvedPath}`, error.flatten());
39
52
  }
@@ -1 +1 @@
1
- {"version":3,"file":"manifest-loader.js","sourceRoot":"","sources":["../../../src/adapters/fs/manifest-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAE/B,OAAO,EAAE,yBAAyB,EAAE,mBAAmB,EAAsB,MAAM,+BAA+B,CAAC;AAOnH,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1B,UAAU,CAAW;IAErC,YAAmB,OAAe,EAAE,UAAoB;QACtD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,IAAI,GAAG,yBAAyB;IACzE,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnC,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,iBAAiB,CAAC,8BAA8B,YAAY,EAAE,EAAE,KAAK,CAAC,CAAC;IACnF,CAAC;IAED,IAAI,UAAmB,CAAC;IACxB,IAAI,CAAC;QACH,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,iBAAiB,CAAC,6BAA6B,YAAY,EAAE,EAAE,KAAK,CAAC,CAAC;IAClF,CAAC;IAED,IAAI,CAAC;QACH,OAAO;YACL,IAAI,EAAE,YAAY;YAClB,QAAQ,EAAE,mBAAmB,CAAC,KAAK,CAAC,UAAU,CAAC;SAChD,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;YAC9B,MAAM,IAAI,iBAAiB,CAAC,kCAAkC,YAAY,EAAE,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACjG,CAAC;QAED,MAAM,IAAI,iBAAiB,CAAC,kCAAkC,YAAY,EAAE,EAAE,KAAK,CAAC,CAAC;IACvF,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"manifest-loader.js","sourceRoot":"","sources":["../../../src/adapters/fs/manifest-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAE/B,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,yBAAyB,EAAE,mBAAmB,EAAsB,MAAM,+BAA+B,CAAC;AAQnH,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1B,UAAU,CAAW;IAErC,YAAmB,OAAe,EAAE,UAAoB;QACtD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;CACF;AAMD,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAAI,GAAG,yBAAyB,EAChC,UAA+B,EAAE;IAEjC,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnC,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,iBAAiB,CAAC,8BAA8B,YAAY,EAAE,EAAE,KAAK,CAAC,CAAC;IACnF,CAAC;IAED,IAAI,UAAmB,CAAC;IACxB,IAAI,CAAC;QACH,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,iBAAiB,CAAC,6BAA6B,YAAY,EAAE,EAAE,KAAK,CAAC,CAAC;IAClF,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,mBAAmB,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACvD,MAAM,SAAS,GAAG,MAAM,wBAAwB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAEpE,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC;YAC1B,MAAM,IAAI,iBAAiB,CAAC,iCAAiC,YAAY,EAAE,EAAE;gBAC3E,UAAU,EAAE,KAAK;gBACjB,MAAM,EAAE,SAAS,CAAC,MAAM;aACzB,CAAC,CAAC;QACL,CAAC;QAED,OAAO;YACL,IAAI,EAAE,YAAY;YAClB,QAAQ;YACR,mBAAmB,EAAE,SAAS,CAAC,mBAAmB;SACnD,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,iBAAiB,EAAE,CAAC;YACvC,MAAM,KAAK,CAAC;QACd,CAAC;QAED,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;YAC9B,MAAM,IAAI,iBAAiB,CAAC,kCAAkC,YAAY,EAAE,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACjG,CAAC;QAED,MAAM,IAAI,iBAAiB,CAAC,kCAAkC,YAAY,EAAE,EAAE,KAAK,CAAC,CAAC;IACvF,CAAC;AACH,CAAC"}
@@ -6,4 +6,6 @@ export declare class GitClient {
6
6
  constructor(repoRoot: string);
7
7
  stageAndCommitPaths(paths: string[], message: string): Promise<CommitResult>;
8
8
  getHeadSha(): Promise<string>;
9
+ applyPatchIfNeeded(patchPath: string): Promise<"applied" | "already_applied">;
10
+ private canApplyPatch;
9
11
  }
@@ -19,5 +19,24 @@ export class GitClient {
19
19
  const { stdout } = await execa("git", ["-C", this.repoRoot, "rev-parse", "HEAD"]);
20
20
  return stdout.trim();
21
21
  }
22
+ async applyPatchIfNeeded(patchPath) {
23
+ if (await this.canApplyPatch(["apply", "--check", "--3way", "--index", "-p2", patchPath])) {
24
+ await execa("git", ["-C", this.repoRoot, "apply", "--3way", "--index", "-p2", patchPath]);
25
+ return "applied";
26
+ }
27
+ if (await this.canApplyPatch(["apply", "--check", "--reverse", "--index", "-p2", patchPath])) {
28
+ return "already_applied";
29
+ }
30
+ throw new Error(`repository state diverged from durable promotion patch ${patchPath}`);
31
+ }
32
+ async canApplyPatch(args) {
33
+ try {
34
+ await execa("git", ["-C", this.repoRoot, ...args]);
35
+ return true;
36
+ }
37
+ catch {
38
+ return false;
39
+ }
40
+ }
22
41
  }
23
42
  //# sourceMappingURL=git-client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"git-client.js","sourceRoot":"","sources":["../../../src/adapters/git/git-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAM9B,MAAM,OAAO,SAAS;IACH,QAAQ,CAAS;IAElC,YAAmB,QAAgB;QACjC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAEM,KAAK,CAAC,mBAAmB,CAAC,KAAe,EAAE,OAAe;QAC/D,MAAM,WAAW,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACnF,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;QACpF,CAAC;QAED,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,WAAW,CAAC,CAAC,CAAC;QAC7E,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QACnE,OAAO;YACL,SAAS,EAAE,MAAM,IAAI,CAAC,UAAU,EAAE;SACnC,CAAC;IACJ,CAAC;IAEM,KAAK,CAAC,UAAU;QACrB,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;QAClF,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;IACvB,CAAC;CACF"}
1
+ {"version":3,"file":"git-client.js","sourceRoot":"","sources":["../../../src/adapters/git/git-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAM9B,MAAM,OAAO,SAAS;IACH,QAAQ,CAAS;IAElC,YAAmB,QAAgB;QACjC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAEM,KAAK,CAAC,mBAAmB,CAAC,KAAe,EAAE,OAAe;QAC/D,MAAM,WAAW,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACnF,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;QACpF,CAAC;QAED,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,WAAW,CAAC,CAAC,CAAC;QAC7E,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QACnE,OAAO;YACL,SAAS,EAAE,MAAM,IAAI,CAAC,UAAU,EAAE;SACnC,CAAC;IACJ,CAAC;IAEM,KAAK,CAAC,UAAU;QACrB,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;QAClF,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;IACvB,CAAC;IAEM,KAAK,CAAC,kBAAkB,CAAC,SAAiB;QAC/C,IAAI,MAAM,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC;YAC1F,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;YAC1F,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,IAAI,MAAM,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC;YAC7F,OAAO,iBAAiB,CAAC;QAC3B,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,0DAA0D,SAAS,EAAE,CAAC,CAAC;IACzF,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,IAAc;QACxC,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;YACnD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF"}