@itsshadowai/refinery 0.1.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.
- package/LICENSE +21 -0
- package/README.md +228 -0
- package/coral/agents/claim-scout/coral-agent.toml +23 -0
- package/coral/agents/decision-synthesizer/coral-agent.toml +23 -0
- package/coral/agents/evidence-auditor/coral-agent.toml +23 -0
- package/coral/agents/memory-cartographer/coral-agent.toml +23 -0
- package/coral/agents/proposal-editor/coral-agent.toml +23 -0
- package/coral/agents/run-worker.sh +19 -0
- package/coral/refinery-config.toml +16 -0
- package/dist/adapters/codex-memory.d.ts +6 -0
- package/dist/adapters/codex-memory.js +264 -0
- package/dist/adapters/codex-memory.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +671 -0
- package/dist/cli.js.map +1 -0
- package/dist/coral/client.d.ts +107 -0
- package/dist/coral/client.js +214 -0
- package/dist/coral/client.js.map +1 -0
- package/dist/coral/definitions.d.ts +25 -0
- package/dist/coral/definitions.js +53 -0
- package/dist/coral/definitions.js.map +1 -0
- package/dist/coral/mcp.d.ts +17 -0
- package/dist/coral/mcp.js +71 -0
- package/dist/coral/mcp.js.map +1 -0
- package/dist/coral/review-conductor.d.ts +120 -0
- package/dist/coral/review-conductor.js +1290 -0
- package/dist/coral/review-conductor.js.map +1 -0
- package/dist/coral/smoke.d.ts +1 -0
- package/dist/coral/smoke.js +265 -0
- package/dist/coral/smoke.js.map +1 -0
- package/dist/coral/topology.d.ts +5 -0
- package/dist/coral/topology.js +15 -0
- package/dist/coral/topology.js.map +1 -0
- package/dist/coral/worker.d.ts +34 -0
- package/dist/coral/worker.js +671 -0
- package/dist/coral/worker.js.map +1 -0
- package/dist/core/adapter.d.ts +93 -0
- package/dist/core/adapter.js +112 -0
- package/dist/core/adapter.js.map +1 -0
- package/dist/core/artifacts.d.ts +93 -0
- package/dist/core/artifacts.js +200 -0
- package/dist/core/artifacts.js.map +1 -0
- package/dist/core/deliberation.d.ts +89 -0
- package/dist/core/deliberation.js +385 -0
- package/dist/core/deliberation.js.map +1 -0
- package/dist/core/errors.d.ts +26 -0
- package/dist/core/errors.js +50 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/intents.d.ts +5 -0
- package/dist/core/intents.js +34 -0
- package/dist/core/intents.js.map +1 -0
- package/dist/core/live-review.d.ts +93 -0
- package/dist/core/live-review.js +269 -0
- package/dist/core/live-review.js.map +1 -0
- package/dist/core/model-client.d.ts +19 -0
- package/dist/core/model-client.js +45 -0
- package/dist/core/model-client.js.map +1 -0
- package/dist/core/paths.d.ts +16 -0
- package/dist/core/paths.js +43 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/review.d.ts +93 -0
- package/dist/core/review.js +102 -0
- package/dist/core/review.js.map +1 -0
- package/dist/core/specialists/claim-scout.d.ts +2 -0
- package/dist/core/specialists/claim-scout.js +26 -0
- package/dist/core/specialists/claim-scout.js.map +1 -0
- package/dist/core/specialists/decision-synthesizer.d.ts +2 -0
- package/dist/core/specialists/decision-synthesizer.js +35 -0
- package/dist/core/specialists/decision-synthesizer.js.map +1 -0
- package/dist/core/specialists/evidence-auditor.d.ts +2 -0
- package/dist/core/specialists/evidence-auditor.js +35 -0
- package/dist/core/specialists/evidence-auditor.js.map +1 -0
- package/dist/core/specialists/harness.d.ts +2 -0
- package/dist/core/specialists/harness.js +13 -0
- package/dist/core/specialists/harness.js.map +1 -0
- package/dist/core/specialists/index.d.ts +8 -0
- package/dist/core/specialists/index.js +8 -0
- package/dist/core/specialists/index.js.map +1 -0
- package/dist/core/specialists/memory-cartographer.d.ts +2 -0
- package/dist/core/specialists/memory-cartographer.js +33 -0
- package/dist/core/specialists/memory-cartographer.js.map +1 -0
- package/dist/core/specialists/prompt.d.ts +3 -0
- package/dist/core/specialists/prompt.js +25 -0
- package/dist/core/specialists/prompt.js.map +1 -0
- package/dist/core/specialists/proposal-editor.d.ts +2 -0
- package/dist/core/specialists/proposal-editor.js +37 -0
- package/dist/core/specialists/proposal-editor.js.map +1 -0
- package/dist/core/specialists/types.d.ts +20 -0
- package/dist/core/specialists/types.js +2 -0
- package/dist/core/specialists/types.js.map +1 -0
- package/dist/env.d.ts +11 -0
- package/dist/env.js +53 -0
- package/dist/env.js.map +1 -0
- package/dist/mcp.d.ts +9 -0
- package/dist/mcp.js +147 -0
- package/dist/mcp.js.map +1 -0
- package/package.json +50 -0
- package/skills/refinery/SKILL.md +117 -0
- package/skills/refinery/agents/openai.yaml +4 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Shadow AI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# refinery
|
|
2
|
+
|
|
3
|
+
Refinery is a Codex-first memory review CLI. It reads bounded Codex memory
|
|
4
|
+
files, runs a dry-run Coral-coordinated specialist review, and emits proposal
|
|
5
|
+
artifacts that a coding agent or host app can inspect before applying changes
|
|
6
|
+
elsewhere.
|
|
7
|
+
|
|
8
|
+
Refinery does not approve proposals, apply edits, or own durable memory truth.
|
|
9
|
+
For the first useful version, Codex memories are the only built-in memory
|
|
10
|
+
surface.
|
|
11
|
+
|
|
12
|
+
## Requirements
|
|
13
|
+
|
|
14
|
+
- Node.js >= 22.
|
|
15
|
+
- Codex memories enabled and available under `~/.codex/memories`, or another
|
|
16
|
+
explicitly provided directory named `memories`.
|
|
17
|
+
- Model credentials for live review, usually `OPENROUTER_API_KEY` or
|
|
18
|
+
`MODEL_API_KEY`.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install -g @itsshadowai/refinery
|
|
24
|
+
refinery init --json
|
|
25
|
+
refinery doctor --json
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`refinery init` creates global Refinery state under `~/.refinery` and installs
|
|
29
|
+
the bundled `$refinery` Codex skill into `${CODEX_HOME:-~/.codex}/skills/refinery`.
|
|
30
|
+
It preserves an existing installed skill unless `--force` is passed.
|
|
31
|
+
|
|
32
|
+
## Commands
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Verify the local Codex memory source is readable.
|
|
36
|
+
refinery doctor --json
|
|
37
|
+
|
|
38
|
+
# Verify the installed CLI version.
|
|
39
|
+
refinery version --json
|
|
40
|
+
|
|
41
|
+
# Verify a non-default Codex memory directory.
|
|
42
|
+
refinery doctor --memory-home /path/to/memories --json
|
|
43
|
+
|
|
44
|
+
# Run a dry-run stale-memory audit over Codex memories.
|
|
45
|
+
refinery review \
|
|
46
|
+
--project . \
|
|
47
|
+
--intent stale-audit \
|
|
48
|
+
--request "Find Codex memories that may be stale after recent repo moves." \
|
|
49
|
+
--json
|
|
50
|
+
|
|
51
|
+
# Seed a live Coral Console debate/critique session without writing run artifacts.
|
|
52
|
+
refinery console run \
|
|
53
|
+
--project . \
|
|
54
|
+
--intent stale-audit \
|
|
55
|
+
--json
|
|
56
|
+
|
|
57
|
+
# Inspect an existing run without invoking Coral or a model.
|
|
58
|
+
refinery trial inspect --run-dir ~/.refinery/runs/by-project/<project-key>/<run-id> --json
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The CLI always emits structured JSON for these commands. Failures use
|
|
62
|
+
`ok: false` with `error.code`, `error.message`, and `error.phase` when known.
|
|
63
|
+
Secrets are not emitted.
|
|
64
|
+
|
|
65
|
+
## Memory Source
|
|
66
|
+
|
|
67
|
+
The built-in Codex memory reader is intentionally bounded. It accepts only a
|
|
68
|
+
directory named `memories`, normally `~/.codex/memories`, and does not crawl all
|
|
69
|
+
of `~/.codex`.
|
|
70
|
+
|
|
71
|
+
Indexed files:
|
|
72
|
+
|
|
73
|
+
- `MEMORY.md`
|
|
74
|
+
- `memory_summary.md`
|
|
75
|
+
- `rollout_summaries/*.md`
|
|
76
|
+
- `extensions/ad_hoc/**/*.md`
|
|
77
|
+
|
|
78
|
+
Records use opaque IDs such as `codex-source:<hash>` and
|
|
79
|
+
`codex-memory:<hash>`. Proposal targets should use those opaque IDs rather than
|
|
80
|
+
database IDs or file offsets.
|
|
81
|
+
|
|
82
|
+
## Review
|
|
83
|
+
|
|
84
|
+
`refinery review` is dry-run only. It starts or targets Coral, creates bounded
|
|
85
|
+
proposal and critique threads, runs the five Refinery specialists, writes a run
|
|
86
|
+
directory, and returns proposed memory-maintenance actions.
|
|
87
|
+
|
|
88
|
+
The default workflow is debate/critique. Claim Scout extracts candidate memory
|
|
89
|
+
claims, Memory Cartographer maps nearby active memories, Evidence Auditor checks
|
|
90
|
+
support and provenance, Proposal Editor turns surviving claims into typed
|
|
91
|
+
proposal packets, and Decision Synthesizer resolves challenges into final
|
|
92
|
+
proposals, rejected candidates, and unresolved questions. Each specialist
|
|
93
|
+
message is persisted under that step's `messages/` artifact directory.
|
|
94
|
+
|
|
95
|
+
Supported review intents:
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
general-review
|
|
99
|
+
stale-audit
|
|
100
|
+
forget-candidates
|
|
101
|
+
update-candidates
|
|
102
|
+
conflict-audit
|
|
103
|
+
scope-audit
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Proposal actions:
|
|
107
|
+
|
|
108
|
+
```text
|
|
109
|
+
create, update, supersede, merge, archive, retag, quarantine,
|
|
110
|
+
promote, demote, ttl_update, contradiction_review
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Proposal lifecycle states:
|
|
114
|
+
|
|
115
|
+
```text
|
|
116
|
+
proposed, needs_review, accepted, rejected, deferred,
|
|
117
|
+
applied_externally, superseded, archived_for_audit
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
New proposals default to `lifecycle: "proposed"`. Applying or rejecting them is
|
|
121
|
+
owned by the caller.
|
|
122
|
+
|
|
123
|
+
## Trial Artifacts
|
|
124
|
+
|
|
125
|
+
Runtime state is globally organized by default:
|
|
126
|
+
|
|
127
|
+
```text
|
|
128
|
+
~/.refinery/
|
|
129
|
+
config/
|
|
130
|
+
credentials/
|
|
131
|
+
runs/
|
|
132
|
+
by-project/
|
|
133
|
+
<project-key>/
|
|
134
|
+
<run-id>/
|
|
135
|
+
input.json
|
|
136
|
+
manifest.json
|
|
137
|
+
metadata.json
|
|
138
|
+
proposals.json
|
|
139
|
+
rejected.json
|
|
140
|
+
claims.json
|
|
141
|
+
challenge-ledger.json
|
|
142
|
+
deliberation.json
|
|
143
|
+
review.json
|
|
144
|
+
coral.json
|
|
145
|
+
transcript.json
|
|
146
|
+
steps/
|
|
147
|
+
claim-scout/{input.json,output.raw.md,output.parsed.json}
|
|
148
|
+
memory-cartographer/{input.json,output.raw.md,output.parsed.json}
|
|
149
|
+
evidence-auditor/{input.json,output.raw.md,output.parsed.json}
|
|
150
|
+
proposal-editor/{input.json,output.raw.md,output.parsed.json}
|
|
151
|
+
decision-synthesizer/{input.json,output.raw.md,output.parsed.json}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Failed reviews that reach a run directory write `status.json`, failed
|
|
155
|
+
`review.json`, and any available step error artifacts. Use `trial inspect` for a
|
|
156
|
+
stable summary instead of scraping file paths.
|
|
157
|
+
|
|
158
|
+
Use `--home ./.refinery` only when you intentionally want project-local
|
|
159
|
+
Refinery state. The default keeps run artifacts and future credentials/config
|
|
160
|
+
global while grouping runs by project key.
|
|
161
|
+
|
|
162
|
+
## Coral Runtime
|
|
163
|
+
|
|
164
|
+
The default runtime is Coral. Refinery owns local executable agent manifests
|
|
165
|
+
under `coral/agents/*` and a repo-local config at `coral/refinery-config.toml`.
|
|
166
|
+
The CLI can also attach to an existing Coral server:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
refinery review \
|
|
170
|
+
--coral-url http://localhost:5555 \
|
|
171
|
+
--coral-no-start \
|
|
172
|
+
--json
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Caller-owned Coral sessions and threads are not torn down by Refinery.
|
|
176
|
+
|
|
177
|
+
## Console Mode
|
|
178
|
+
|
|
179
|
+
`refinery console run` is a local development command for Coral Console
|
|
180
|
+
inspection. It reads the bounded Codex memory source, starts Coral when
|
|
181
|
+
`--coral-url` is not provided, creates a session and thread set, seeds the
|
|
182
|
+
default debate/critique workflow, prints the console URL and session
|
|
183
|
+
identifiers, and does not write run artifacts.
|
|
184
|
+
|
|
185
|
+
The default console topology is `debate-critique`. When Refinery starts the
|
|
186
|
+
Coral server, the command stays in the foreground so the Console remains
|
|
187
|
+
available until interrupted.
|
|
188
|
+
|
|
189
|
+
## Development
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
npm test
|
|
193
|
+
npm run build
|
|
194
|
+
npm link
|
|
195
|
+
refinery version --json
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
The test suite covers the Codex memory adapter, Codex-first CLI contract, Coral
|
|
199
|
+
worker/conductor helpers, artifact inspection, model client, intents, MCP
|
|
200
|
+
specialist prompt tools, and specialist contracts.
|
|
201
|
+
|
|
202
|
+
### Codex Skill
|
|
203
|
+
|
|
204
|
+
Use one Codex skill for Refinery memory work:
|
|
205
|
+
|
|
206
|
+
```text
|
|
207
|
+
$refinery
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Example prompt:
|
|
211
|
+
|
|
212
|
+
```text
|
|
213
|
+
Use $refinery to inspect the current project Codex memories with intent update-candidates, source-limit 1, source-char-limit 2500, and summarize the proposed edits.
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
The companion skill should be installed once in the Codex global skill root:
|
|
217
|
+
|
|
218
|
+
```text
|
|
219
|
+
~/.codex/skills/refinery/SKILL.md
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Do not keep repo-local alternate copies of the Refinery skill; they create
|
|
223
|
+
duplicate suggestions and teach agents old invocation names. `$refinery`
|
|
224
|
+
defaults to live `refinery review`. For deterministic rehearsal only:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
refinery dev fixture memory-proposal --json
|
|
228
|
+
```
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
edition = 4
|
|
2
|
+
|
|
3
|
+
[agent]
|
|
4
|
+
name = "refinery-claim-scout"
|
|
5
|
+
version = "0.1.0"
|
|
6
|
+
description = "Refinery Claim Scout specialist as a Coral executable agent."
|
|
7
|
+
summary = "Claim Scout extracts candidate memory claims from source evidence."
|
|
8
|
+
readme = "Executable Refinery specialist. Worker owns Coral wait/send and maps to src/core/specialists/claim-scout."
|
|
9
|
+
|
|
10
|
+
[agent.license]
|
|
11
|
+
type = "spdx"
|
|
12
|
+
expression = "MIT"
|
|
13
|
+
|
|
14
|
+
[options]
|
|
15
|
+
MODEL_NAME = { type = "string", default = "deepseek/deepseek-v4-pro" }
|
|
16
|
+
MODEL_BASE_URL = { type = "string", default = "https://openrouter.ai/api/v1" }
|
|
17
|
+
REASONING_EFFORT = { type = "string", default = "low" }
|
|
18
|
+
REFINERY_CORAL_MAX_TURNS = { type = "string", default = "1" }
|
|
19
|
+
|
|
20
|
+
[runtimes.executable]
|
|
21
|
+
path = "../run-worker.sh"
|
|
22
|
+
arguments = ["--specialist", "claim-scout"]
|
|
23
|
+
transport = "streamable_http"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
edition = 4
|
|
2
|
+
|
|
3
|
+
[agent]
|
|
4
|
+
name = "refinery-decision-synthesizer"
|
|
5
|
+
version = "0.1.0"
|
|
6
|
+
description = "Refinery Decision Synthesizer specialist as a Coral executable agent."
|
|
7
|
+
summary = "Decision Synthesizer resolves challenges into final proposed edits, rejected candidates, and unresolved questions."
|
|
8
|
+
readme = "Executable Refinery specialist. Worker owns Coral wait/send and maps to src/core/specialists/decision-synthesizer."
|
|
9
|
+
|
|
10
|
+
[agent.license]
|
|
11
|
+
type = "spdx"
|
|
12
|
+
expression = "MIT"
|
|
13
|
+
|
|
14
|
+
[options]
|
|
15
|
+
MODEL_NAME = { type = "string", default = "deepseek/deepseek-v4-pro" }
|
|
16
|
+
MODEL_BASE_URL = { type = "string", default = "https://openrouter.ai/api/v1" }
|
|
17
|
+
REASONING_EFFORT = { type = "string", default = "low" }
|
|
18
|
+
REFINERY_CORAL_MAX_TURNS = { type = "string", default = "1" }
|
|
19
|
+
|
|
20
|
+
[runtimes.executable]
|
|
21
|
+
path = "../run-worker.sh"
|
|
22
|
+
arguments = ["--specialist", "decision-synthesizer"]
|
|
23
|
+
transport = "streamable_http"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
edition = 4
|
|
2
|
+
|
|
3
|
+
[agent]
|
|
4
|
+
name = "refinery-evidence-auditor"
|
|
5
|
+
version = "0.1.0"
|
|
6
|
+
description = "Refinery Evidence Auditor specialist as a Coral executable agent."
|
|
7
|
+
summary = "Evidence Auditor checks support, provenance, truncation, lineage, and write risk."
|
|
8
|
+
readme = "Executable Refinery specialist. Worker owns Coral wait/send and maps to src/core/specialists/evidence-auditor."
|
|
9
|
+
|
|
10
|
+
[agent.license]
|
|
11
|
+
type = "spdx"
|
|
12
|
+
expression = "MIT"
|
|
13
|
+
|
|
14
|
+
[options]
|
|
15
|
+
MODEL_NAME = { type = "string", default = "deepseek/deepseek-v4-pro" }
|
|
16
|
+
MODEL_BASE_URL = { type = "string", default = "https://openrouter.ai/api/v1" }
|
|
17
|
+
REASONING_EFFORT = { type = "string", default = "low" }
|
|
18
|
+
REFINERY_CORAL_MAX_TURNS = { type = "string", default = "1" }
|
|
19
|
+
|
|
20
|
+
[runtimes.executable]
|
|
21
|
+
path = "../run-worker.sh"
|
|
22
|
+
arguments = ["--specialist", "evidence-auditor"]
|
|
23
|
+
transport = "streamable_http"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
edition = 4
|
|
2
|
+
|
|
3
|
+
[agent]
|
|
4
|
+
name = "refinery-memory-cartographer"
|
|
5
|
+
version = "0.1.0"
|
|
6
|
+
description = "Refinery Memory Cartographer specialist as a Coral executable agent."
|
|
7
|
+
summary = "Memory Cartographer maps nearby memories, duplicates, conflicts, and supersession targets."
|
|
8
|
+
readme = "Executable Refinery specialist. Worker owns Coral wait/send and maps to src/core/specialists/memory-cartographer."
|
|
9
|
+
|
|
10
|
+
[agent.license]
|
|
11
|
+
type = "spdx"
|
|
12
|
+
expression = "MIT"
|
|
13
|
+
|
|
14
|
+
[options]
|
|
15
|
+
MODEL_NAME = { type = "string", default = "deepseek/deepseek-v4-pro" }
|
|
16
|
+
MODEL_BASE_URL = { type = "string", default = "https://openrouter.ai/api/v1" }
|
|
17
|
+
REASONING_EFFORT = { type = "string", default = "low" }
|
|
18
|
+
REFINERY_CORAL_MAX_TURNS = { type = "string", default = "1" }
|
|
19
|
+
|
|
20
|
+
[runtimes.executable]
|
|
21
|
+
path = "../run-worker.sh"
|
|
22
|
+
arguments = ["--specialist", "memory-cartographer"]
|
|
23
|
+
transport = "streamable_http"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
edition = 4
|
|
2
|
+
|
|
3
|
+
[agent]
|
|
4
|
+
name = "refinery-proposal-editor"
|
|
5
|
+
version = "0.1.0"
|
|
6
|
+
description = "Refinery Proposal Editor specialist as a Coral executable agent."
|
|
7
|
+
summary = "Proposal Editor turns surviving claims into typed memory proposal packets."
|
|
8
|
+
readme = "Executable Refinery specialist. Worker owns Coral wait/send and maps to src/core/specialists/proposal-editor."
|
|
9
|
+
|
|
10
|
+
[agent.license]
|
|
11
|
+
type = "spdx"
|
|
12
|
+
expression = "MIT"
|
|
13
|
+
|
|
14
|
+
[options]
|
|
15
|
+
MODEL_NAME = { type = "string", default = "deepseek/deepseek-v4-pro" }
|
|
16
|
+
MODEL_BASE_URL = { type = "string", default = "https://openrouter.ai/api/v1" }
|
|
17
|
+
REASONING_EFFORT = { type = "string", default = "low" }
|
|
18
|
+
REFINERY_CORAL_MAX_TURNS = { type = "string", default = "1" }
|
|
19
|
+
|
|
20
|
+
[runtimes.executable]
|
|
21
|
+
path = "../run-worker.sh"
|
|
22
|
+
arguments = ["--specialist", "proposal-editor"]
|
|
23
|
+
transport = "streamable_http"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
|
6
|
+
|
|
7
|
+
if [[ -n "${REFINERY_NODE_BIN:-}" ]]; then
|
|
8
|
+
NODE_BIN="${REFINERY_NODE_BIN}"
|
|
9
|
+
elif [[ -x "${HOME}/.nvm/versions/node/v24.10.0/bin/node" ]]; then
|
|
10
|
+
NODE_BIN="${HOME}/.nvm/versions/node/v24.10.0/bin/node"
|
|
11
|
+
else
|
|
12
|
+
NODE_BIN="node"
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
cd "${REPO_ROOT}"
|
|
16
|
+
if [[ -f "${REPO_ROOT}/dist/coral/worker.js" ]]; then
|
|
17
|
+
exec "${NODE_BIN}" dist/coral/worker.js "$@"
|
|
18
|
+
fi
|
|
19
|
+
exec "${NODE_BIN}" src/coral/worker.ts "$@"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
[network]
|
|
2
|
+
bind_address = "127.0.0.1"
|
|
3
|
+
external_address = "127.0.0.1"
|
|
4
|
+
bind_port = 5555
|
|
5
|
+
allow_any_host = true
|
|
6
|
+
|
|
7
|
+
[auth]
|
|
8
|
+
keys = ["refinery-dev"]
|
|
9
|
+
|
|
10
|
+
[registry]
|
|
11
|
+
include_coral_home_agents = false
|
|
12
|
+
include_debug_agents = false
|
|
13
|
+
export_debug_agents = false
|
|
14
|
+
watch_local_agents = true
|
|
15
|
+
local_agent_rescan_timer = "10s"
|
|
16
|
+
local_agents = ["/Users/bambozlor/Lab/Research-Desk/refinery/coral/agents/*"]
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { MemoryStoreAdapter } from "../core/adapter.ts";
|
|
2
|
+
export interface CodexMemoryAdapterOptions {
|
|
3
|
+
memoryHome?: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function resolveCodexMemoryHome(memoryHome?: string): string;
|
|
6
|
+
export declare function createCodexMemoryAdapter(options?: CodexMemoryAdapterOptions): MemoryStoreAdapter;
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { RefineryError } from "../core/errors.js";
|
|
6
|
+
export function resolveCodexMemoryHome(memoryHome) {
|
|
7
|
+
return path.resolve(memoryHome ?? path.join(os.homedir(), ".codex", "memories"));
|
|
8
|
+
}
|
|
9
|
+
function hashId(prefix, parts) {
|
|
10
|
+
const hash = crypto.createHash("sha256");
|
|
11
|
+
for (const part of parts)
|
|
12
|
+
hash.update(part).update("\0");
|
|
13
|
+
return `${prefix}:${hash.digest("hex").slice(0, 16)}`;
|
|
14
|
+
}
|
|
15
|
+
function compactText(text, max = 4000) {
|
|
16
|
+
const compact = text.replace(/\s+/g, " ").trim();
|
|
17
|
+
if (compact.length <= max)
|
|
18
|
+
return compact;
|
|
19
|
+
return `${compact.slice(0, max - 3).trimEnd()}...`;
|
|
20
|
+
}
|
|
21
|
+
function assertSafeMemoryHome(memoryHome) {
|
|
22
|
+
if (path.basename(memoryHome) !== "memories") {
|
|
23
|
+
throw new RefineryError("CODEX_MEMORY_HOME_UNSAFE", "memoryHome must point to a directory named memories, such as ~/.codex/memories.", { phase: "adapter", details: { memoryHome } });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function ensureMemoryHome(memoryHome) {
|
|
27
|
+
if (!fs.existsSync(memoryHome) || !fs.statSync(memoryHome).isDirectory()) {
|
|
28
|
+
throw new RefineryError("CODEX_MEMORY_HOME_NOT_FOUND", `Codex memory home does not exist: ${memoryHome}`, { phase: "adapter", details: { memoryHome } });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function readIfExists(memoryHome, relPath) {
|
|
32
|
+
const absPath = path.join(memoryHome, relPath);
|
|
33
|
+
if (!fs.existsSync(absPath) || !fs.statSync(absPath).isFile())
|
|
34
|
+
return null;
|
|
35
|
+
return toDocument(memoryHome, absPath);
|
|
36
|
+
}
|
|
37
|
+
function walkMarkdown(dir) {
|
|
38
|
+
if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory())
|
|
39
|
+
return [];
|
|
40
|
+
const out = [];
|
|
41
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
42
|
+
const abs = path.join(dir, entry.name);
|
|
43
|
+
if (entry.isDirectory()) {
|
|
44
|
+
out.push(...walkMarkdown(abs));
|
|
45
|
+
}
|
|
46
|
+
else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
47
|
+
out.push(abs);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return out.sort();
|
|
51
|
+
}
|
|
52
|
+
function originKindForRelPath(relPath) {
|
|
53
|
+
if (relPath === "MEMORY.md")
|
|
54
|
+
return "memory-index";
|
|
55
|
+
if (relPath === "memory_summary.md")
|
|
56
|
+
return "memory-summary";
|
|
57
|
+
if (relPath === "raw_memories.md")
|
|
58
|
+
return "raw-memory";
|
|
59
|
+
if (relPath === "phase2_workspace_diff.md")
|
|
60
|
+
return "workspace-diff";
|
|
61
|
+
if (relPath.startsWith("rollout_summaries/"))
|
|
62
|
+
return "rollout-summary";
|
|
63
|
+
if (relPath.startsWith("extensions/ad_hoc/"))
|
|
64
|
+
return "ad-hoc-note";
|
|
65
|
+
return "other";
|
|
66
|
+
}
|
|
67
|
+
function sourceKindForOrigin(originKind) {
|
|
68
|
+
switch (originKind) {
|
|
69
|
+
case "memory-index":
|
|
70
|
+
return "codex-memory-index";
|
|
71
|
+
case "memory-summary":
|
|
72
|
+
return "codex-memory-summary";
|
|
73
|
+
case "rollout-summary":
|
|
74
|
+
return "codex-rollout-summary";
|
|
75
|
+
case "ad-hoc-note":
|
|
76
|
+
return "codex-ad-hoc-note";
|
|
77
|
+
case "raw-memory":
|
|
78
|
+
return "codex-raw-memory";
|
|
79
|
+
case "workspace-diff":
|
|
80
|
+
return "codex-workspace-diff";
|
|
81
|
+
case "other":
|
|
82
|
+
return "codex-memory-document";
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function firstMetadataValue(text, field) {
|
|
86
|
+
const match = text.match(new RegExp(`^${field}:\\s*(.+)$`, "m"));
|
|
87
|
+
return match ? match[1].trim() : null;
|
|
88
|
+
}
|
|
89
|
+
function parseRolloutListMetadata(text) {
|
|
90
|
+
const match = text.match(/\(([^)]*thread_id=[^)]+)\)/);
|
|
91
|
+
if (!match)
|
|
92
|
+
return {};
|
|
93
|
+
const body = match[1];
|
|
94
|
+
const metadata = {};
|
|
95
|
+
for (const part of body.split(/,\s*/)) {
|
|
96
|
+
const eq = part.indexOf("=");
|
|
97
|
+
if (eq <= 0)
|
|
98
|
+
continue;
|
|
99
|
+
const key = part.slice(0, eq).trim();
|
|
100
|
+
const value = part.slice(eq + 1).trim();
|
|
101
|
+
if (key === "thread_id")
|
|
102
|
+
metadata.threadId = value;
|
|
103
|
+
else if (key === "updated_at")
|
|
104
|
+
metadata.updatedAt = value;
|
|
105
|
+
else if (key === "rollout_path")
|
|
106
|
+
metadata.rolloutPath = value;
|
|
107
|
+
else if (key === "cwd")
|
|
108
|
+
metadata.cwd = value;
|
|
109
|
+
else
|
|
110
|
+
metadata[key] = value;
|
|
111
|
+
}
|
|
112
|
+
return metadata;
|
|
113
|
+
}
|
|
114
|
+
function metadataFor(relPath, text, originKind) {
|
|
115
|
+
const metadata = {
|
|
116
|
+
originKind,
|
|
117
|
+
relPath,
|
|
118
|
+
};
|
|
119
|
+
if (originKind === "rollout-summary") {
|
|
120
|
+
metadata.threadId = firstMetadataValue(text, "thread_id");
|
|
121
|
+
metadata.updatedAt = firstMetadataValue(text, "updated_at");
|
|
122
|
+
metadata.rolloutPath = firstMetadataValue(text, "rollout_path");
|
|
123
|
+
metadata.cwd = firstMetadataValue(text, "cwd");
|
|
124
|
+
}
|
|
125
|
+
Object.assign(metadata, parseRolloutListMetadata(text));
|
|
126
|
+
return Object.fromEntries(Object.entries(metadata).filter(([, value]) => value !== null && value !== undefined));
|
|
127
|
+
}
|
|
128
|
+
function toDocument(memoryHome, absPath) {
|
|
129
|
+
const relPath = path.relative(memoryHome, absPath).split(path.sep).join("/");
|
|
130
|
+
const text = fs.readFileSync(absPath, "utf8");
|
|
131
|
+
const originKind = originKindForRelPath(relPath);
|
|
132
|
+
return {
|
|
133
|
+
relPath,
|
|
134
|
+
absPath,
|
|
135
|
+
text,
|
|
136
|
+
originKind,
|
|
137
|
+
sourceKind: sourceKindForOrigin(originKind),
|
|
138
|
+
metadata: metadataFor(relPath, text, originKind),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function loadDocuments(memoryHome) {
|
|
142
|
+
assertSafeMemoryHome(memoryHome);
|
|
143
|
+
ensureMemoryHome(memoryHome);
|
|
144
|
+
const docs = [];
|
|
145
|
+
for (const relPath of ["MEMORY.md", "memory_summary.md", "raw_memories.md", "phase2_workspace_diff.md"]) {
|
|
146
|
+
const doc = readIfExists(memoryHome, relPath);
|
|
147
|
+
if (doc)
|
|
148
|
+
docs.push(doc);
|
|
149
|
+
}
|
|
150
|
+
for (const abs of walkMarkdown(path.join(memoryHome, "rollout_summaries")))
|
|
151
|
+
docs.push(toDocument(memoryHome, abs));
|
|
152
|
+
for (const abs of walkMarkdown(path.join(memoryHome, "extensions/ad_hoc")))
|
|
153
|
+
docs.push(toDocument(memoryHome, abs));
|
|
154
|
+
return docs;
|
|
155
|
+
}
|
|
156
|
+
function documentToSource(doc) {
|
|
157
|
+
return {
|
|
158
|
+
id: hashId("codex-source", [doc.relPath, doc.text]),
|
|
159
|
+
kind: doc.sourceKind,
|
|
160
|
+
path: doc.relPath,
|
|
161
|
+
text: compactText(doc.text, 8000),
|
|
162
|
+
refs: [{ source_path: doc.relPath, origin_kind: doc.originKind }],
|
|
163
|
+
metadata: doc.metadata,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function headingForLine(lines, lineIndex) {
|
|
167
|
+
for (let i = lineIndex; i >= 0; i -= 1) {
|
|
168
|
+
const match = lines[i].match(/^#{1,6}\s+(.+)$/);
|
|
169
|
+
if (match)
|
|
170
|
+
return match[1].trim();
|
|
171
|
+
}
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
function inferMemoryType(originKind, heading, body) {
|
|
175
|
+
const text = `${heading ?? ""} ${body}`.toLowerCase();
|
|
176
|
+
if (text.includes("preference") || text.includes("when the user") || text.includes("should "))
|
|
177
|
+
return "operational";
|
|
178
|
+
if (text.includes("failure") || text.includes("fix:") || text.includes("symptom:"))
|
|
179
|
+
return "procedural";
|
|
180
|
+
if (originKind === "ad-hoc-note")
|
|
181
|
+
return "semantic";
|
|
182
|
+
return "semantic";
|
|
183
|
+
}
|
|
184
|
+
function documentToMemories(doc) {
|
|
185
|
+
const lines = doc.text.split(/\r?\n/);
|
|
186
|
+
const records = [];
|
|
187
|
+
lines.forEach((line, index) => {
|
|
188
|
+
const bullet = line.match(/^\s*-\s+(.+)$/);
|
|
189
|
+
if (!bullet)
|
|
190
|
+
return;
|
|
191
|
+
const body = bullet[1].trim();
|
|
192
|
+
if (!body)
|
|
193
|
+
return;
|
|
194
|
+
const heading = headingForLine(lines, index);
|
|
195
|
+
records.push({
|
|
196
|
+
id: hashId("codex-memory", [doc.relPath, String(index + 1), body]),
|
|
197
|
+
type: inferMemoryType(doc.originKind, heading, body),
|
|
198
|
+
scope: "project",
|
|
199
|
+
status: "active",
|
|
200
|
+
body,
|
|
201
|
+
confidence: null,
|
|
202
|
+
provenance: {
|
|
203
|
+
originKind: doc.originKind,
|
|
204
|
+
sourcePath: doc.relPath,
|
|
205
|
+
heading,
|
|
206
|
+
line: index + 1,
|
|
207
|
+
threadId: typeof doc.metadata.threadId === "string" ? doc.metadata.threadId : null,
|
|
208
|
+
updatedAt: typeof doc.metadata.updatedAt === "string" ? doc.metadata.updatedAt : null,
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
if (records.length === 0 && doc.originKind === "ad-hoc-note" && doc.text.trim()) {
|
|
213
|
+
records.push({
|
|
214
|
+
id: hashId("codex-memory", [doc.relPath, doc.text]),
|
|
215
|
+
type: "semantic",
|
|
216
|
+
scope: "project",
|
|
217
|
+
status: "active",
|
|
218
|
+
body: compactText(doc.text, 1600),
|
|
219
|
+
confidence: null,
|
|
220
|
+
provenance: {
|
|
221
|
+
originKind: doc.originKind,
|
|
222
|
+
sourcePath: doc.relPath,
|
|
223
|
+
heading: null,
|
|
224
|
+
line: 1,
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
return records;
|
|
229
|
+
}
|
|
230
|
+
function filterByQuery(items, query) {
|
|
231
|
+
const q = query.toLowerCase();
|
|
232
|
+
return items.filter((item) => [item.body, item.text, item.path].some((value) => typeof value === "string" && value.toLowerCase().includes(q)));
|
|
233
|
+
}
|
|
234
|
+
function limitItems(items, limit) {
|
|
235
|
+
return typeof limit === "number" && Number.isFinite(limit) && limit > 0 ? items.slice(0, limit) : items;
|
|
236
|
+
}
|
|
237
|
+
export function createCodexMemoryAdapter(options = {}) {
|
|
238
|
+
const memoryHome = resolveCodexMemoryHome(options.memoryHome);
|
|
239
|
+
assertSafeMemoryHome(memoryHome);
|
|
240
|
+
const readSources = () => loadDocuments(memoryHome).map(documentToSource);
|
|
241
|
+
const readMemories = () => loadDocuments(memoryHome).flatMap(documentToMemories);
|
|
242
|
+
return {
|
|
243
|
+
name: "codex-memory",
|
|
244
|
+
async listSourceEvidence(input) {
|
|
245
|
+
return limitItems(readSources(), input.limit);
|
|
246
|
+
},
|
|
247
|
+
async searchSourceEvidence(input) {
|
|
248
|
+
return limitItems(filterByQuery(readSources(), input.query), input.limit);
|
|
249
|
+
},
|
|
250
|
+
async getSourceEvidence(input) {
|
|
251
|
+
return readSources().find((source) => source.id === input.id) ?? null;
|
|
252
|
+
},
|
|
253
|
+
async listActiveMemories(input) {
|
|
254
|
+
return limitItems(readMemories(), input.limit);
|
|
255
|
+
},
|
|
256
|
+
async searchActiveMemories(input) {
|
|
257
|
+
return limitItems(filterByQuery(readMemories(), input.query), input.limit);
|
|
258
|
+
},
|
|
259
|
+
async getActiveMemory(input) {
|
|
260
|
+
return readMemories().find((memory) => memory.id === input.id) ?? null;
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
//# sourceMappingURL=codex-memory.js.map
|