ralph-research 0.1.2 → 0.1.4

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 (138) hide show
  1. package/README.md +132 -101
  2. package/dist/adapters/fs/json-file-research-project-defaults-store.d.ts +8 -0
  3. package/dist/adapters/fs/json-file-research-project-defaults-store.js +30 -0
  4. package/dist/adapters/fs/json-file-research-project-defaults-store.js.map +1 -0
  5. package/dist/adapters/fs/json-file-research-session-repository.d.ts +24 -0
  6. package/dist/adapters/fs/json-file-research-session-repository.js +199 -0
  7. package/dist/adapters/fs/json-file-research-session-repository.js.map +1 -0
  8. package/dist/adapters/fs/lockfile.js +142 -57
  9. package/dist/adapters/fs/lockfile.js.map +1 -1
  10. package/dist/adapters/fs/manifest-loader.js +8 -1
  11. package/dist/adapters/fs/manifest-loader.js.map +1 -1
  12. package/dist/adapters/proposer/codex-cli-proposer.d.ts +16 -0
  13. package/dist/adapters/proposer/codex-cli-proposer.js +106 -0
  14. package/dist/adapters/proposer/codex-cli-proposer.js.map +1 -0
  15. package/dist/adapters/proposer/codex-cli-session-driver.d.ts +64 -0
  16. package/dist/adapters/proposer/codex-cli-session-driver.js +182 -0
  17. package/dist/adapters/proposer/codex-cli-session-driver.js.map +1 -0
  18. package/dist/adapters/proposer/codex-cli-session-manager.d.ts +79 -0
  19. package/dist/adapters/proposer/codex-cli-session-manager.js +248 -0
  20. package/dist/adapters/proposer/codex-cli-session-manager.js.map +1 -0
  21. package/dist/adapters/proposer/codex-cli-session-outcome-extractor.d.ts +3 -0
  22. package/dist/adapters/proposer/codex-cli-session-outcome-extractor.js +94 -0
  23. package/dist/adapters/proposer/codex-cli-session-outcome-extractor.js.map +1 -0
  24. package/dist/adapters/proposer/proposer-factory.d.ts +22 -0
  25. package/dist/adapters/proposer/proposer-factory.js +19 -0
  26. package/dist/adapters/proposer/proposer-factory.js.map +1 -0
  27. package/dist/app/services/codex-cli-session-lifecycle-service.d.ts +116 -0
  28. package/dist/app/services/codex-cli-session-lifecycle-service.js +186 -0
  29. package/dist/app/services/codex-cli-session-lifecycle-service.js.map +1 -0
  30. package/dist/app/services/manual-decision-service.js +20 -9
  31. package/dist/app/services/manual-decision-service.js.map +1 -1
  32. package/dist/app/services/project-state-service.js +5 -3
  33. package/dist/app/services/project-state-service.js.map +1 -1
  34. package/dist/app/services/research-project-defaults-service.d.ts +18 -0
  35. package/dist/app/services/research-project-defaults-service.js +175 -0
  36. package/dist/app/services/research-project-defaults-service.js.map +1 -0
  37. package/dist/app/services/research-session-draft-service.d.ts +121 -0
  38. package/dist/app/services/research-session-draft-service.js +846 -0
  39. package/dist/app/services/research-session-draft-service.js.map +1 -0
  40. package/dist/app/services/research-session-entry-flow-summary-mapper.d.ts +12 -0
  41. package/dist/app/services/research-session-entry-flow-summary-mapper.js +33 -0
  42. package/dist/app/services/research-session-entry-flow-summary-mapper.js.map +1 -0
  43. package/dist/app/services/research-session-interactive-service.d.ts +35 -0
  44. package/dist/app/services/research-session-interactive-service.js +295 -0
  45. package/dist/app/services/research-session-interactive-service.js.map +1 -0
  46. package/dist/app/services/research-session-launch-service.d.ts +46 -0
  47. package/dist/app/services/research-session-launch-service.js +389 -0
  48. package/dist/app/services/research-session-launch-service.js.map +1 -0
  49. package/dist/app/services/research-session-orchestrator-service.d.ts +140 -0
  50. package/dist/app/services/research-session-orchestrator-service.js +614 -0
  51. package/dist/app/services/research-session-orchestrator-service.js.map +1 -0
  52. package/dist/app/services/research-session-recovery-service.d.ts +30 -0
  53. package/dist/app/services/research-session-recovery-service.js +110 -0
  54. package/dist/app/services/research-session-recovery-service.js.map +1 -0
  55. package/dist/app/services/research-session-wizard-controller.d.ts +51 -0
  56. package/dist/app/services/research-session-wizard-controller.js +220 -0
  57. package/dist/app/services/research-session-wizard-controller.js.map +1 -0
  58. package/dist/app/services/run-cycle-service.d.ts +2 -0
  59. package/dist/app/services/run-cycle-service.js +8 -6
  60. package/dist/app/services/run-cycle-service.js.map +1 -1
  61. package/dist/app/services/run-loop-service.js +11 -3
  62. package/dist/app/services/run-loop-service.js.map +1 -1
  63. package/dist/cli/commands/inspect.js +2 -0
  64. package/dist/cli/commands/inspect.js.map +1 -1
  65. package/dist/cli/commands/launch.d.ts +16 -0
  66. package/dist/cli/commands/launch.js +68 -0
  67. package/dist/cli/commands/launch.js.map +1 -0
  68. package/dist/cli/commands/proposer-display.d.ts +2 -0
  69. package/dist/cli/commands/proposer-display.js +18 -0
  70. package/dist/cli/commands/proposer-display.js.map +1 -0
  71. package/dist/cli/commands/resume.d.ts +14 -0
  72. package/dist/cli/commands/resume.js +134 -0
  73. package/dist/cli/commands/resume.js.map +1 -0
  74. package/dist/cli/commands/run.d.ts +2 -2
  75. package/dist/cli/commands/run.js +15 -4
  76. package/dist/cli/commands/run.js.map +1 -1
  77. package/dist/cli/commands/status.js +4 -0
  78. package/dist/cli/commands/status.js.map +1 -1
  79. package/dist/cli/main.js +2 -29
  80. package/dist/cli/main.js.map +1 -1
  81. package/dist/cli/program.d.ts +15 -0
  82. package/dist/cli/program.js +54 -0
  83. package/dist/cli/program.js.map +1 -0
  84. package/dist/cli/tui/research-session-shell.d.ts +22 -0
  85. package/dist/cli/tui/research-session-shell.js +719 -0
  86. package/dist/cli/tui/research-session-shell.js.map +1 -0
  87. package/dist/core/engine/cycle-runner.d.ts +4 -0
  88. package/dist/core/engine/cycle-runner.js +15 -9
  89. package/dist/core/engine/cycle-runner.js.map +1 -1
  90. package/dist/core/manifest/admission.d.ts +1 -0
  91. package/dist/core/manifest/admission.js +50 -0
  92. package/dist/core/manifest/admission.js.map +1 -1
  93. package/dist/core/manifest/defaults.d.ts +21 -0
  94. package/dist/core/manifest/defaults.js +21 -0
  95. package/dist/core/manifest/defaults.js.map +1 -1
  96. package/dist/core/manifest/schema.d.ts +170 -0
  97. package/dist/core/manifest/schema.js +21 -1
  98. package/dist/core/manifest/schema.js.map +1 -1
  99. package/dist/core/model/codex-cli-cycle-session.d.ts +4 -0
  100. package/dist/core/model/codex-cli-cycle-session.js +2 -0
  101. package/dist/core/model/codex-cli-cycle-session.js.map +1 -0
  102. package/dist/core/model/codex-cli-session-lifecycle.d.ts +131 -0
  103. package/dist/core/model/codex-cli-session-lifecycle.js +237 -0
  104. package/dist/core/model/codex-cli-session-lifecycle.js.map +1 -0
  105. package/dist/core/model/codex-cli-session-outcome.d.ts +121 -0
  106. package/dist/core/model/codex-cli-session-outcome.js +70 -0
  107. package/dist/core/model/codex-cli-session-outcome.js.map +1 -0
  108. package/dist/core/model/research-project-defaults.d.ts +48 -0
  109. package/dist/core/model/research-project-defaults.js +46 -0
  110. package/dist/core/model/research-project-defaults.js.map +1 -0
  111. package/dist/core/model/research-session.d.ts +1143 -0
  112. package/dist/core/model/research-session.js +689 -0
  113. package/dist/core/model/research-session.js.map +1 -0
  114. package/dist/core/model/run-record.d.ts +56 -6
  115. package/dist/core/model/run-record.js +28 -0
  116. package/dist/core/model/run-record.js.map +1 -1
  117. package/dist/core/ports/research-project-defaults-store.d.ts +5 -0
  118. package/dist/core/ports/research-project-defaults-store.js +2 -0
  119. package/dist/core/ports/research-project-defaults-store.js.map +1 -0
  120. package/dist/core/ports/research-session-repository.d.ts +25 -0
  121. package/dist/core/ports/research-session-repository.js +2 -0
  122. package/dist/core/ports/research-session-repository.js.map +1 -0
  123. package/dist/core/state/frontier-materializer.d.ts +2 -0
  124. package/dist/core/state/frontier-materializer.js +11 -2
  125. package/dist/core/state/frontier-materializer.js.map +1 -1
  126. package/dist/core/state/research-session-recovery-classifier.d.ts +24 -0
  127. package/dist/core/state/research-session-recovery-classifier.js +236 -0
  128. package/dist/core/state/research-session-recovery-classifier.js.map +1 -0
  129. package/dist/core/state/research-session-resume-candidate.d.ts +8 -0
  130. package/dist/core/state/research-session-resume-candidate.js +62 -0
  131. package/dist/core/state/research-session-resume-candidate.js.map +1 -0
  132. package/dist/core/state/research-session-state-machine.d.ts +62 -0
  133. package/dist/core/state/research-session-state-machine.js +443 -0
  134. package/dist/core/state/research-session-state-machine.js.map +1 -0
  135. package/dist/mcp/server.d.ts +4 -0
  136. package/dist/mcp/server.js +192 -1
  137. package/dist/mcp/server.js.map +1 -1
  138. package/package.json +1 -1
package/README.md CHANGED
@@ -1,45 +1,117 @@
1
1
  # ralph-research
2
2
 
3
- Local-first runtime for recursive research improvement.
3
+ [![CI](https://github.com/coyaSONG/ralph-research/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/coyaSONG/ralph-research/actions/workflows/ci.yml)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D24-339933?logo=node.js&logoColor=white)](package.json)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-3178c6?logo=typescript&logoColor=white)](tsconfig.json)
4
7
 
5
- `ralph-research` runs a bounded improvement loop over a real artifact:
8
+ Local-first runtime for recursive research improvement over real artifacts.
6
9
 
7
- 1. define a metric
10
+ `ralph-research` ships an actual CLI and stdio MCP server that run a bounded loop:
11
+
12
+ 1. load a manifest
8
13
  2. generate one candidate change
9
- 3. evaluate it
10
- 4. keep only verified improvements
14
+ 3. evaluate it with trusted signals
15
+ 4. persist the run, decision, and frontier state
16
+ 5. promote only verified improvements
17
+
18
+ The current product bar is reliability, not breadth. The bundled success path is the `writing` template, while the runtime itself is manifest-driven and reusable for other local workflows.
19
+
20
+ ## Trust Signals
21
+
22
+ - Actual shipped surfaces: CLI binary `rrx` and stdio MCP server
23
+ - Development verification commands: `npm test`, `npm run typecheck`, `npm run build`
24
+ - Persisted runtime evidence: runs, decisions, frontier, and lock metadata
25
+ - Recovery semantics are enforced by code and persisted state, not described only in prompts
26
+ - Supported onboarding path is intentionally narrower than the full manifest surface
27
+
28
+ ## What It Is
29
+
30
+ - A Node/TypeScript runtime with a real CLI: `rrx`
31
+ - A stdio MCP server backed by the same service layer as the CLI
32
+ - A Git-aware candidate execution loop with persisted run, decision, and frontier state
33
+ - A local-first system designed to be resumed, inspected, and trusted after interruptions
11
34
 
12
- The v0.1 focus is a writing workflow that is runnable in under five minutes on a local machine.
35
+ ## What It Is Not
13
36
 
14
- ## Quickstart
37
+ - Not a no-config autonomous agent for arbitrary domains out of the box
38
+ - Not a hosted service
39
+ - Not a prompt-only protocol with undocumented runtime behavior
40
+ - Not broader than the shipped contract: one bundled template (`writing`) and three MCP tools
15
41
 
16
- ### Zero-config demo
42
+ ## Quick Decision Guide
43
+
44
+ | If you want to... | Use |
45
+ | --- | --- |
46
+ | Check whether a repo is runnable | `rrx validate` then `rrx doctor` |
47
+ | Materialize the bundled example project | `rrx init --template writing` |
48
+ | Run a disposable end-to-end demo | `rrx demo writing` |
49
+ | Launch the v1 goal-driven orchestrator | `rrx "improve the holdout top-3 model"` |
50
+ | Launch the v1 goal-driven orchestrator explicitly | `rrx launch "improve the holdout top-3 model"` |
51
+ | Resume a persisted TUI research session | `rrx resume latest` |
52
+ | Execute one cycle | `rrx run --json` |
53
+ | Resume the latest recoverable run | `rrx run` |
54
+ | Force a fresh run id | `rrx run --fresh` |
55
+ | Inspect runtime and recovery state | `rrx status --json` |
56
+ | Inspect why one run was accepted or rejected | `rrx inspect <runId> --json` |
57
+ | Review the current accepted frontier | `rrx frontier --json` |
58
+ | Serve the same contract over MCP stdio | `rrx serve-mcp --stdio` |
59
+
60
+ ## Five-Minute Start
61
+
62
+ ### Option A: disposable demo
17
63
 
18
64
  ```bash
19
65
  npx ralph-research demo writing
20
66
  ```
21
67
 
22
- This creates a temporary writing repo, runs one accepted cycle, and prints the path plus the run id. The v0.1 demo supports the bundled `writing` template only.
68
+ This creates a temporary Git repo, runs one accepted cycle, and prints the temp path plus the run id.
23
69
 
24
- ### Template flow
70
+ ### Option B: initialize a local repo
25
71
 
26
72
  ```bash
27
73
  npx ralph-research init --template writing
74
+ npx ralph-research doctor
28
75
  npx ralph-research run --json
29
- npx ralph-research run --until-target --until-no-improve 3 --json
76
+ npx ralph-research status --json
30
77
  npx ralph-research inspect run-0001 --json
31
78
  ```
32
79
 
33
- This path is the v0.1 success bar: `init -> run -> inspect` should work quickly and produce an acceptance reason you can inspect. The bundled template set is currently `writing` only.
80
+ This is the current truth contract for the bundled template: `init -> run -> inspect` should succeed quickly on a local machine.
34
81
 
35
- ## Core Concepts
82
+ `rrx "goal"` now creates or refreshes the launch draft session and drops into the v1 TUI shell. Initial launch does not start an autonomous research cycle until the shell tells it to continue.
83
+
84
+ When you submit the review step, the shell materializes a real research session and hands control to the selected agent runtime. Once that interactive run returns, `launch-draft` is removed. The remaining persisted session is the only runtime record you need to inspect or resume.
36
85
 
37
- - `Manifest`: `ralph.yaml` defines the research program.
38
- - `Metric`: how candidate quality is measured.
39
- - `Frontier`: the currently accepted best candidate set.
40
- - `Ratchet`: the acceptance policy that decides whether the frontier advances.
41
- - `Proposer`: how a bounded candidate change is generated.
42
- - `Judge`: how qualitative outputs are compared when numeric metrics are not enough.
86
+ Resume semantics are intentionally narrow:
87
+
88
+ - `rrx resume <sessionId>` only works for sessions that ended after a completed cycle checkpoint
89
+ - interrupted sessions are resumable because the runtime has durable evidence for the next cycle boundary
90
+ - a clean agent exit without `goal_achieved` or a completed checkpoint is treated as terminal and is not resumable
91
+
92
+ ## Runtime Model
93
+
94
+ The runtime is manifest-driven. `ralph.yaml` defines the project, proposer, experiment, metrics, ratchet, and storage root. The service layer then:
95
+
96
+ - loads and validates the manifest
97
+ - acquires a durable lock
98
+ - classifies recovery against the latest persisted run
99
+ - executes or resumes a candidate
100
+ - writes run, decision, and frontier state under the storage root
101
+
102
+ See [docs/operation-model.md](docs/operation-model.md) for the full lifecycle and recovery model.
103
+
104
+ ## Current Scope
105
+
106
+ - Bundled template: `writing`
107
+ - Default template metric: local command metric, no API key required
108
+ - Optional judge path: pairwise LLM judge packs
109
+ - MCP tools:
110
+ - `run_research_cycle`
111
+ - `get_research_status`
112
+ - `get_frontier`
113
+
114
+ The runtime supports broader manifests than the bundled template demonstrates, but the shipped onboarding path is intentionally narrow until those flows are equally reliable.
43
115
 
44
116
  ## Writing Template
45
117
 
@@ -49,19 +121,51 @@ The bundled writing template is self-contained:
49
121
  - `scripts/propose.mjs`: bounded rewrite
50
122
  - `scripts/experiment.mjs`: output materialization
51
123
  - `scripts/metric.mjs`: local heuristic metric
52
- - `prompts/judge.md`: pairwise judge prompt you can upgrade to later
124
+ - `prompts/judge.md`: pairwise judge prompt starter
125
+
126
+ `templates/writing/ralph.yaml` uses a local command metric by default, so the first run works without model credentials.
127
+
128
+ ## Progressive Runs
129
+
130
+ `rrx run` executes one cycle by default and auto-resumes the latest recoverable run when one exists.
53
131
 
54
- The default template uses a local command metric so the first run does not require API keys. When you are ready, replace the numeric metric with an `llm_judge` extractor and use the included pairwise prompt as a starting point.
132
+ Progressive stop modes are opt-in:
133
+
134
+ - `--fresh`: start a new `runId` instead of auto-resuming the latest recoverable run
135
+ - `--until-target`: keep iterating until `manifest.stopping.target` is met
136
+ - `--until-no-improve N`: stop after `N` consecutive cycles without frontier improvement
137
+ - `--cycles N` with a progressive flag: treat `N` as a max-cycle cap instead of an exact count
138
+
139
+ The bundled `writing` template ships with `stopping.target` commented out, so enable that block in `ralph.yaml` before using `--until-target`.
140
+
141
+ ```bash
142
+ npx ralph-research run --until-target --until-no-improve 3 --json
143
+ ```
144
+
145
+ ## More Docs
146
+
147
+ - [docs/operation-model.md](docs/operation-model.md): lifecycle, persisted state, recovery classes
148
+ - [docs/playbook.md](docs/playbook.md): situation-to-command operator guide
149
+ - [docs/examples.md](docs/examples.md): quickstart and manifest examples pulled from shipped templates and fixtures
150
+ - [docs/examples-catalog.md](docs/examples-catalog.md): broader scenario catalog grounded in shipped templates and test fixtures
151
+ - [docs/comparison.md](docs/comparison.md): why this runtime is narrower and more stateful than prompt-only loop systems
152
+ - [docs/faq.md](docs/faq.md): common runtime, recovery, and inspection questions
153
+ - [docs/knowledge/INDEX.md](docs/knowledge/INDEX.md): project knowledge log
55
154
 
56
155
  ## CLI
57
156
 
58
157
  ```text
158
+ rrx "improve the holdout top-3 model"
159
+ rrx launch "improve the holdout top-3 model"
160
+ rrx resume latest
59
161
  rrx validate
60
162
  rrx doctor
61
163
  rrx init --template writing
62
164
  rrx demo writing
63
165
  rrx run
166
+ rrx run --fresh
64
167
  rrx run --until-target
168
+ rrx run --until-no-improve 3
65
169
  rrx run --until-target --until-no-improve 3
66
170
  rrx status
67
171
  rrx frontier
@@ -71,87 +175,14 @@ rrx reject <runId>
71
175
  rrx serve-mcp --stdio
72
176
  ```
73
177
 
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
-
140
- ## MCP
141
-
142
- The bundled MCP server currently supports stdio transport and exposes three thin tools backed by the same service layer as the CLI:
143
-
144
- - `run_research_cycle`
145
- - `get_research_status`
146
- - `get_frontier`
147
-
148
- ## Design Principles
178
+ ## Core Concepts
149
179
 
150
- - local-first execution
151
- - bounded changes
152
- - recoverable state transitions
153
- - trusted signal before automation
154
- - inspectable accept/reject decisions
180
+ - `Manifest`: `ralph.yaml` defines the research program
181
+ - `Metric`: how candidate quality is measured
182
+ - `Frontier`: the currently accepted best candidate set
183
+ - `Ratchet`: the acceptance policy that decides whether the frontier advances
184
+ - `Proposer`: how a bounded candidate change is generated
185
+ - `Judge`: how qualitative outputs are compared when numeric metrics are not enough
155
186
 
156
187
  ## Development
157
188
 
@@ -0,0 +1,8 @@
1
+ import { type ResearchProjectDefaultsRecord } from "../../core/model/research-project-defaults.js";
2
+ import type { ResearchProjectDefaultsStore } from "../../core/ports/research-project-defaults-store.js";
3
+ export declare class JsonFileResearchProjectDefaultsStore implements ResearchProjectDefaultsStore {
4
+ private readonly filePath;
5
+ constructor(filePath: string);
6
+ save(record: ResearchProjectDefaultsRecord): Promise<void>;
7
+ load(): Promise<ResearchProjectDefaultsRecord | null>;
8
+ }
@@ -0,0 +1,30 @@
1
+ import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
2
+ import { dirname, resolve } from "node:path";
3
+ import { researchProjectDefaultsRecordSchema, } from "../../core/model/research-project-defaults.js";
4
+ import { isMissingFileError } from "../../shared/fs-errors.js";
5
+ export class JsonFileResearchProjectDefaultsStore {
6
+ filePath;
7
+ constructor(filePath) {
8
+ this.filePath = resolve(filePath);
9
+ }
10
+ async save(record) {
11
+ const parsed = researchProjectDefaultsRecordSchema.parse(record);
12
+ const tempPath = `${this.filePath}.tmp-${process.pid}-${Date.now()}`;
13
+ await mkdir(dirname(this.filePath), { recursive: true });
14
+ await writeFile(tempPath, `${JSON.stringify(parsed, null, 2)}\n`, "utf8");
15
+ await rename(tempPath, this.filePath);
16
+ }
17
+ async load() {
18
+ try {
19
+ const raw = await readFile(this.filePath, "utf8");
20
+ return researchProjectDefaultsRecordSchema.parse(JSON.parse(raw));
21
+ }
22
+ catch (error) {
23
+ if (isMissingFileError(error)) {
24
+ return null;
25
+ }
26
+ throw error;
27
+ }
28
+ }
29
+ }
30
+ //# sourceMappingURL=json-file-research-project-defaults-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-file-research-project-defaults-store.js","sourceRoot":"","sources":["../../../src/adapters/fs/json-file-research-project-defaults-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,EACL,mCAAmC,GAEpC,MAAM,+CAA+C,CAAC;AAEvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,MAAM,OAAO,oCAAoC;IAC9B,QAAQ,CAAS;IAElC,YAAmB,QAAgB;QACjC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,MAAqC;QACrD,MAAM,MAAM,GAAG,mCAAmC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACjE,MAAM,QAAQ,GAAG,GAAG,IAAI,CAAC,QAAQ,QAAQ,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QAErE,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,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,QAAQ,CAAC,CAAC;IACxC,CAAC;IAEM,KAAK,CAAC,IAAI;QACf,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YAClD,OAAO,mCAAmC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QACpE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC9B,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,24 @@
1
+ import { type ResearchSessionMetadata, type ResearchSessionRecord } from "../../core/model/research-session.js";
2
+ import type { PersistedResearchSessionBundle, ResearchSessionQuery, ResearchSessionRepository } from "../../core/ports/research-session-repository.js";
3
+ export declare class JsonFileResearchSessionRepository implements ResearchSessionRepository {
4
+ private readonly sessionsRoot;
5
+ constructor(sessionsRoot: string);
6
+ saveSession(record: ResearchSessionRecord): Promise<void>;
7
+ loadSession(sessionId: string): Promise<ResearchSessionRecord | null>;
8
+ deleteSession(sessionId: string): Promise<void>;
9
+ loadSessionMetadata(sessionId: string): Promise<ResearchSessionMetadata | null>;
10
+ loadPersistedSession(sessionId: string): Promise<PersistedResearchSessionBundle | null>;
11
+ querySessions(query?: ResearchSessionQuery): Promise<ResearchSessionRecord[]>;
12
+ querySessionMetadata(query?: ResearchSessionQuery): Promise<ResearchSessionMetadata[]>;
13
+ private loadAllSessions;
14
+ private loadAllSessionMetadata;
15
+ private listSessionDirectories;
16
+ private getPath;
17
+ private getLifecyclePath;
18
+ private getSessionsRoot;
19
+ private readSessionRecord;
20
+ private readSessionMetadata;
21
+ private readLifecycleRecord;
22
+ private assertDirectoryMatchesSession;
23
+ private assertLifecycleMatchesSession;
24
+ }
@@ -0,0 +1,199 @@
1
+ import { mkdir, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
2
+ import { dirname, join, resolve } from "node:path";
3
+ import { parseCodexCliSessionLifecycleRecord, } from "../../core/model/codex-cli-session-lifecycle.js";
4
+ import { parsePersistedResearchSessionMetadata, researchSessionRecordSchema, } from "../../core/model/research-session.js";
5
+ import { isMissingFileError } from "../../shared/fs-errors.js";
6
+ export class JsonFileResearchSessionRepository {
7
+ sessionsRoot;
8
+ constructor(sessionsRoot) {
9
+ this.sessionsRoot = resolve(sessionsRoot);
10
+ }
11
+ async saveSession(record) {
12
+ const parsed = researchSessionRecordSchema.parse(record);
13
+ const path = this.getPath(parsed.sessionId);
14
+ const tempPath = `${path}.tmp-${process.pid}-${Date.now()}`;
15
+ await mkdir(dirname(path), { recursive: true });
16
+ await writeFile(tempPath, `${JSON.stringify(parsed, null, 2)}\n`, "utf8");
17
+ await rename(tempPath, path);
18
+ }
19
+ async loadSession(sessionId) {
20
+ return this.readSessionRecord(sessionId);
21
+ }
22
+ async deleteSession(sessionId) {
23
+ const path = join(this.getSessionsRoot(), sessionId);
24
+ await rm(path, { recursive: true, force: true });
25
+ }
26
+ async loadSessionMetadata(sessionId) {
27
+ return this.readSessionMetadata(sessionId);
28
+ }
29
+ async loadPersistedSession(sessionId) {
30
+ const session = await this.readSessionRecord(sessionId);
31
+ if (!session) {
32
+ return null;
33
+ }
34
+ const lifecyclePath = this.getLifecyclePath(sessionId);
35
+ const lifecycle = await this.readLifecycleRecord(sessionId);
36
+ return {
37
+ session,
38
+ lifecycle,
39
+ codexSessionReference: lifecycle
40
+ ? {
41
+ codexSessionId: lifecycle.identity.codexSessionId,
42
+ lifecyclePath,
43
+ }
44
+ : null,
45
+ };
46
+ }
47
+ async querySessions(query = {}) {
48
+ const records = await this.loadAllSessions();
49
+ const filtered = records.filter((record) => {
50
+ if (query.workingDirectory && record.workingDirectory !== query.workingDirectory) {
51
+ return false;
52
+ }
53
+ if (query.statuses && !query.statuses.includes(record.status)) {
54
+ return false;
55
+ }
56
+ return true;
57
+ });
58
+ if (query.limit === undefined) {
59
+ return filtered;
60
+ }
61
+ return filtered.slice(0, query.limit);
62
+ }
63
+ async querySessionMetadata(query = {}) {
64
+ const records = await this.loadAllSessionMetadata();
65
+ const filtered = records.filter((record) => {
66
+ if (query.workingDirectory && record.workingDirectory !== query.workingDirectory) {
67
+ return false;
68
+ }
69
+ if (query.statuses && !query.statuses.includes(record.status)) {
70
+ return false;
71
+ }
72
+ return true;
73
+ });
74
+ if (query.limit === undefined) {
75
+ return filtered;
76
+ }
77
+ return filtered.slice(0, query.limit);
78
+ }
79
+ async loadAllSessions() {
80
+ const directories = await this.listSessionDirectories();
81
+ const records = [];
82
+ for (const directoryName of directories) {
83
+ const record = await this.readSessionRecord(directoryName);
84
+ if (!record) {
85
+ continue;
86
+ }
87
+ this.assertDirectoryMatchesSession(record, directoryName);
88
+ records.push(record);
89
+ }
90
+ return records.sort((left, right) => left.sessionId.localeCompare(right.sessionId));
91
+ }
92
+ async loadAllSessionMetadata() {
93
+ const directories = await this.listSessionDirectories();
94
+ const records = [];
95
+ for (const directoryName of directories) {
96
+ const record = await this.readSessionMetadata(directoryName);
97
+ if (!record) {
98
+ continue;
99
+ }
100
+ this.assertDirectoryMatchesSession(record, directoryName);
101
+ records.push(record);
102
+ }
103
+ return records.sort((left, right) => left.sessionId.localeCompare(right.sessionId));
104
+ }
105
+ async listSessionDirectories() {
106
+ try {
107
+ const entries = await readdir(this.getSessionsRoot(), { withFileTypes: true });
108
+ const directories = [];
109
+ for (const entry of entries) {
110
+ if (!entry.isDirectory()) {
111
+ continue;
112
+ }
113
+ const path = join(this.getSessionsRoot(), entry.name, "session.json");
114
+ const fileStats = await stat(path).catch((error) => {
115
+ if (isMissingFileError(error)) {
116
+ return null;
117
+ }
118
+ throw error;
119
+ });
120
+ if (!fileStats?.isFile()) {
121
+ continue;
122
+ }
123
+ directories.push(entry.name);
124
+ }
125
+ return directories.sort((left, right) => left.localeCompare(right));
126
+ }
127
+ catch (error) {
128
+ if (isMissingFileError(error)) {
129
+ return [];
130
+ }
131
+ throw error;
132
+ }
133
+ }
134
+ getPath(sessionId) {
135
+ return join(this.getSessionsRoot(), sessionId, "session.json");
136
+ }
137
+ getLifecyclePath(sessionId) {
138
+ return join(this.getSessionsRoot(), sessionId, "codex-session.json");
139
+ }
140
+ getSessionsRoot() {
141
+ return this.sessionsRoot;
142
+ }
143
+ async readSessionRecord(sessionId) {
144
+ const path = this.getPath(sessionId);
145
+ try {
146
+ const raw = await readFile(path, "utf8");
147
+ const record = researchSessionRecordSchema.parse(JSON.parse(raw));
148
+ this.assertDirectoryMatchesSession(record, sessionId);
149
+ return record;
150
+ }
151
+ catch (error) {
152
+ if (isMissingFileError(error)) {
153
+ return null;
154
+ }
155
+ throw error;
156
+ }
157
+ }
158
+ async readSessionMetadata(sessionId) {
159
+ const path = this.getPath(sessionId);
160
+ try {
161
+ const raw = await readFile(path, "utf8");
162
+ const record = parsePersistedResearchSessionMetadata(JSON.parse(raw));
163
+ this.assertDirectoryMatchesSession(record, sessionId);
164
+ return record;
165
+ }
166
+ catch (error) {
167
+ if (isMissingFileError(error)) {
168
+ return null;
169
+ }
170
+ throw error;
171
+ }
172
+ }
173
+ async readLifecycleRecord(sessionId) {
174
+ const path = this.getLifecyclePath(sessionId);
175
+ try {
176
+ const raw = await readFile(path, "utf8");
177
+ const record = parseCodexCliSessionLifecycleRecord(raw);
178
+ this.assertLifecycleMatchesSession(record, sessionId);
179
+ return record;
180
+ }
181
+ catch (error) {
182
+ if (isMissingFileError(error)) {
183
+ return null;
184
+ }
185
+ throw error;
186
+ }
187
+ }
188
+ assertDirectoryMatchesSession(record, directoryName) {
189
+ if (record.sessionId !== directoryName) {
190
+ throw new Error(`Research session directory name "${directoryName}" must match record sessionId "${record.sessionId}"`);
191
+ }
192
+ }
193
+ assertLifecycleMatchesSession(record, directoryName) {
194
+ if (record.sessionId !== directoryName) {
195
+ throw new Error(`Research session directory name "${directoryName}" must match lifecycle sessionId "${record.sessionId}"`);
196
+ }
197
+ }
198
+ }
199
+ //# sourceMappingURL=json-file-research-session-repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-file-research-session-repository.js","sourceRoot":"","sources":["../../../src/adapters/fs/json-file-research-session-repository.ts"],"names":[],"mappings":"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"}