@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/dist/cli.js
ADDED
|
@@ -0,0 +1,671 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
3
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
4
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
5
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
return path;
|
|
9
|
+
};
|
|
10
|
+
import fs from "node:fs";
|
|
11
|
+
import os from "node:os";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import { parseArgs } from "node:util";
|
|
14
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
15
|
+
import { probeMemoryStoreAdapter, refineryReviewSchemaVersion, validateMemoryStoreAdapter, } from "./core/adapter.js";
|
|
16
|
+
import { asRefineryError, RefineryError, serializeRefineryError, } from "./core/errors.js";
|
|
17
|
+
import { inspectReviewRun } from "./core/artifacts.js";
|
|
18
|
+
import { resolveRefineryPaths } from "./core/paths.js";
|
|
19
|
+
import { parseReviewIntent } from "./core/intents.js";
|
|
20
|
+
import {} from "./core/review.js";
|
|
21
|
+
import { createCodexMemoryAdapter, resolveCodexMemoryHome } from "./adapters/codex-memory.js";
|
|
22
|
+
import { runCoralReview, startCoralConsoleRun } from "./coral/review-conductor.js";
|
|
23
|
+
import { parseReviewTopology } from "./coral/topology.js";
|
|
24
|
+
const HELP = `refinery — Codex-first memory review CLI
|
|
25
|
+
|
|
26
|
+
USAGE
|
|
27
|
+
refinery init [--home <dir>] [--codex-home <dir>] [--skip-codex-skill] [--force] [--json]
|
|
28
|
+
refinery doctor [--memory-home <dir>] [--json]
|
|
29
|
+
refinery version [--json]
|
|
30
|
+
refinery review [--project <dir>] [--memory-home <dir>] [--intent <intent>] [--request <text>] [--home <dir>] [--run-id <id>] [--output-dir <dir>] [--sink-url <url>] [--sink-timeout-ms <ms>] [--json]
|
|
31
|
+
refinery console run [--project <dir>] [--memory-home <dir>] [--intent <intent>] [--request <text>] [--run-id <id>] [--coral-url <url>] [--json]
|
|
32
|
+
refinery dev fixture memory-proposal [--json]
|
|
33
|
+
refinery trial inspect --run-dir <dir> [--json]
|
|
34
|
+
|
|
35
|
+
Refinery reads bounded Codex memory files, runs a dry-run Coral-coordinated review, and emits proposal artifacts.
|
|
36
|
+
It does not approve, apply, or write durable memory. Runtime state defaults to ~/.refinery/runs/by-project/<project-key>.
|
|
37
|
+
Run init once to create ~/.refinery and install the bundled $refinery Codex skill.
|
|
38
|
+
Use console run for local Coral Console trials that seed a live session without writing run artifacts.`;
|
|
39
|
+
function stableJson(value) {
|
|
40
|
+
return JSON.stringify(value, null, 2) + "\n";
|
|
41
|
+
}
|
|
42
|
+
function packageRoot() {
|
|
43
|
+
return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
44
|
+
}
|
|
45
|
+
function bundledCodexSkillDir() {
|
|
46
|
+
return path.join(packageRoot(), "skills", "refinery");
|
|
47
|
+
}
|
|
48
|
+
function bundledCodexSkillPath() {
|
|
49
|
+
return path.join(bundledCodexSkillDir(), "SKILL.md");
|
|
50
|
+
}
|
|
51
|
+
function resolveCodexHome(codexHome, env = process.env) {
|
|
52
|
+
return path.resolve(codexHome ?? env.CODEX_HOME ?? path.join(os.homedir(), ".codex"));
|
|
53
|
+
}
|
|
54
|
+
function installedCodexSkillPath(codexHome) {
|
|
55
|
+
return path.join(resolveCodexHome(codexHome), "skills", "refinery", "SKILL.md");
|
|
56
|
+
}
|
|
57
|
+
function copyDirectory(src, dest) {
|
|
58
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
59
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
60
|
+
const sourcePath = path.join(src, entry.name);
|
|
61
|
+
const destPath = path.join(dest, entry.name);
|
|
62
|
+
if (entry.isDirectory()) {
|
|
63
|
+
copyDirectory(sourcePath, destPath);
|
|
64
|
+
}
|
|
65
|
+
else if (entry.isFile()) {
|
|
66
|
+
fs.copyFileSync(sourcePath, destPath);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function defaultRunId(prefix = "review") {
|
|
71
|
+
return `${prefix}-${new Date().toISOString().replace(/[:.]/g, "-")}`;
|
|
72
|
+
}
|
|
73
|
+
async function loadSink(spec) {
|
|
74
|
+
const resolved = path.resolve(spec);
|
|
75
|
+
let mod;
|
|
76
|
+
try {
|
|
77
|
+
mod = await import(__rewriteRelativeImportExtension(pathToFileURL(resolved).href));
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
throw new RefineryError("SINK_LOAD_FAILED", error instanceof Error ? error.message : String(error), { phase: "sink" });
|
|
81
|
+
}
|
|
82
|
+
const sink = mod.sink ?? mod.default;
|
|
83
|
+
if (!sink || typeof sink !== "object" || !("url" in sink) || typeof sink.url !== "string") {
|
|
84
|
+
throw new RefineryError("SINK_LOAD_FAILED", "sink module must export { sink: { url, headers? } } or default { url, headers? }", { phase: "sink" });
|
|
85
|
+
}
|
|
86
|
+
return sink;
|
|
87
|
+
}
|
|
88
|
+
function parseOptionArgs(args, options) {
|
|
89
|
+
try {
|
|
90
|
+
return parseArgs({
|
|
91
|
+
args,
|
|
92
|
+
options,
|
|
93
|
+
allowPositionals: false,
|
|
94
|
+
}).values;
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
throw new RefineryError("INVALID_OPTION", error instanceof Error ? error.message : String(error), { phase: "args" });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function parsePositiveIntegerOption(value, label) {
|
|
101
|
+
if (value === undefined)
|
|
102
|
+
return undefined;
|
|
103
|
+
if (typeof value !== "string" || !/^[0-9]+$/.test(value)) {
|
|
104
|
+
throw new RefineryError("INVALID_OPTION", `${label} must be a positive integer.`, { phase: "args" });
|
|
105
|
+
}
|
|
106
|
+
const parsed = Number(value);
|
|
107
|
+
if (!Number.isSafeInteger(parsed) || parsed <= 0) {
|
|
108
|
+
throw new RefineryError("INVALID_OPTION", `${label} must be a positive integer.`, { phase: "args" });
|
|
109
|
+
}
|
|
110
|
+
return parsed;
|
|
111
|
+
}
|
|
112
|
+
function validateRunId(runId) {
|
|
113
|
+
if (!runId ||
|
|
114
|
+
runId.includes("/") ||
|
|
115
|
+
runId.includes("\\") ||
|
|
116
|
+
runId.includes("..") ||
|
|
117
|
+
!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(runId)) {
|
|
118
|
+
throw new RefineryError("INVALID_OPTION", "--run-id must be path-safe: non-empty, no slashes, no dot-dot, and only alphanumerics, dot, underscore, or dash.", { phase: "args", runId });
|
|
119
|
+
}
|
|
120
|
+
return runId;
|
|
121
|
+
}
|
|
122
|
+
function ensureRunDirInside(outputDir, runId) {
|
|
123
|
+
const resolvedOutput = path.resolve(outputDir);
|
|
124
|
+
const resolvedRun = path.resolve(resolvedOutput, runId);
|
|
125
|
+
const relative = path.relative(resolvedOutput, resolvedRun);
|
|
126
|
+
if (relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
127
|
+
throw new RefineryError("INVALID_OPTION", "--run-id must not escape the output directory.", {
|
|
128
|
+
phase: "args",
|
|
129
|
+
runId,
|
|
130
|
+
runDir: resolvedRun,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function inferCommand(argv) {
|
|
135
|
+
if (argv[0] === "trial" && argv[1] === "inspect")
|
|
136
|
+
return "trial inspect";
|
|
137
|
+
if (argv[0] === "console" && argv[1] === "run")
|
|
138
|
+
return "console run";
|
|
139
|
+
if (argv[0] === "dev" && argv[1] === "fixture")
|
|
140
|
+
return "dev fixture";
|
|
141
|
+
return argv[0] ?? "unknown";
|
|
142
|
+
}
|
|
143
|
+
function wantsJson(argv) {
|
|
144
|
+
return argv.includes("--json");
|
|
145
|
+
}
|
|
146
|
+
function writeJsonFailure(argv, error) {
|
|
147
|
+
const refined = asRefineryError(error, { code: "CLI_ERROR", phase: "cli" });
|
|
148
|
+
const output = {
|
|
149
|
+
ok: false,
|
|
150
|
+
command: inferCommand(argv),
|
|
151
|
+
error: serializeRefineryError(refined),
|
|
152
|
+
...(refined.runId ? { runId: refined.runId } : {}),
|
|
153
|
+
...(refined.runDir ? { runDir: refined.runDir } : {}),
|
|
154
|
+
};
|
|
155
|
+
process.stdout.write(stableJson(output));
|
|
156
|
+
}
|
|
157
|
+
function installCodexSkill(options = {}) {
|
|
158
|
+
const installPath = installedCodexSkillPath(options.codexHome);
|
|
159
|
+
if (options.skip) {
|
|
160
|
+
return { requested: false, action: "skipped", path: installPath };
|
|
161
|
+
}
|
|
162
|
+
const sourceDir = bundledCodexSkillDir();
|
|
163
|
+
if (!fs.existsSync(bundledCodexSkillPath())) {
|
|
164
|
+
throw new RefineryError("SKILL_BUNDLE_NOT_FOUND", `Bundled Codex skill not found: ${sourceDir}`, {
|
|
165
|
+
phase: "init",
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
const destDir = path.dirname(installPath);
|
|
169
|
+
if (fs.existsSync(installPath) && !options.force) {
|
|
170
|
+
return { requested: true, action: "preserved", path: installPath };
|
|
171
|
+
}
|
|
172
|
+
const action = fs.existsSync(installPath) ? "overwritten" : "installed";
|
|
173
|
+
if (options.force && fs.existsSync(destDir)) {
|
|
174
|
+
fs.rmSync(destDir, { recursive: true, force: true });
|
|
175
|
+
}
|
|
176
|
+
copyDirectory(sourceDir, destDir);
|
|
177
|
+
return { requested: true, action, path: installPath };
|
|
178
|
+
}
|
|
179
|
+
async function cmdInit(rest) {
|
|
180
|
+
const values = parseOptionArgs(rest, {
|
|
181
|
+
home: { type: "string" },
|
|
182
|
+
"codex-home": { type: "string" },
|
|
183
|
+
"skip-codex-skill": { type: "boolean", default: false },
|
|
184
|
+
force: { type: "boolean", default: false },
|
|
185
|
+
json: { type: "boolean", default: false },
|
|
186
|
+
});
|
|
187
|
+
const paths = resolveRefineryPaths({
|
|
188
|
+
home: typeof values.home === "string" ? values.home : undefined,
|
|
189
|
+
cwd: process.cwd(),
|
|
190
|
+
});
|
|
191
|
+
const dirs = [
|
|
192
|
+
paths.configDir,
|
|
193
|
+
paths.credentialsDir,
|
|
194
|
+
path.join(paths.runsRootDir, "by-project"),
|
|
195
|
+
paths.runsDir,
|
|
196
|
+
];
|
|
197
|
+
const createdDirs = [];
|
|
198
|
+
for (const dir of dirs) {
|
|
199
|
+
if (!fs.existsSync(dir))
|
|
200
|
+
createdDirs.push(dir);
|
|
201
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
202
|
+
}
|
|
203
|
+
const codexSkill = installCodexSkill({
|
|
204
|
+
codexHome: typeof values["codex-home"] === "string" ? values["codex-home"] : undefined,
|
|
205
|
+
force: Boolean(values.force),
|
|
206
|
+
skip: Boolean(values["skip-codex-skill"]),
|
|
207
|
+
});
|
|
208
|
+
const memoryHome = resolveCodexMemoryHome();
|
|
209
|
+
process.stdout.write(stableJson({
|
|
210
|
+
ok: true,
|
|
211
|
+
command: "init",
|
|
212
|
+
home: paths.home,
|
|
213
|
+
createdDirs,
|
|
214
|
+
codexSkill,
|
|
215
|
+
doctor: {
|
|
216
|
+
memoryHome,
|
|
217
|
+
memoryHomeExists: fs.existsSync(memoryHome),
|
|
218
|
+
bundledCodexSkill: {
|
|
219
|
+
path: bundledCodexSkillPath(),
|
|
220
|
+
exists: fs.existsSync(bundledCodexSkillPath()),
|
|
221
|
+
},
|
|
222
|
+
installedCodexSkill: {
|
|
223
|
+
path: codexSkill.path,
|
|
224
|
+
exists: fs.existsSync(codexSkill.path),
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
}));
|
|
228
|
+
return 0;
|
|
229
|
+
}
|
|
230
|
+
function isMainModule() {
|
|
231
|
+
if (!process.argv[1])
|
|
232
|
+
return false;
|
|
233
|
+
try {
|
|
234
|
+
return fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(process.argv[1]);
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
return import.meta.url === pathToFileURL(process.argv[1]).href;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
async function cmdDoctor(rest) {
|
|
241
|
+
const values = parseOptionArgs(rest, {
|
|
242
|
+
"memory-home": { type: "string" },
|
|
243
|
+
json: { type: "boolean", default: false },
|
|
244
|
+
});
|
|
245
|
+
const memoryHome = resolveCodexMemoryHome(typeof values["memory-home"] === "string" ? values["memory-home"] : undefined);
|
|
246
|
+
const adapter = createCodexMemoryAdapter({ memoryHome });
|
|
247
|
+
const validation = validateMemoryStoreAdapter(adapter);
|
|
248
|
+
if (!validation.valid) {
|
|
249
|
+
process.stdout.write(stableJson({
|
|
250
|
+
ok: false,
|
|
251
|
+
command: "doctor",
|
|
252
|
+
memoryHome,
|
|
253
|
+
memoryHomeSafe: path.basename(memoryHome) === "memories",
|
|
254
|
+
memoryHomeExists: false,
|
|
255
|
+
authRequired: false,
|
|
256
|
+
error: {
|
|
257
|
+
code: "ADAPTER_INVALID",
|
|
258
|
+
message: validation.errors.join("; "),
|
|
259
|
+
phase: "adapter",
|
|
260
|
+
details: validation.errors,
|
|
261
|
+
},
|
|
262
|
+
}));
|
|
263
|
+
return 1;
|
|
264
|
+
}
|
|
265
|
+
const probe = await probeMemoryStoreAdapter(adapter, { scope: "project", limit: 3 });
|
|
266
|
+
const refineryPaths = resolveRefineryPaths();
|
|
267
|
+
const installedSkillPath = installedCodexSkillPath();
|
|
268
|
+
const output = {
|
|
269
|
+
ok: probe.valid,
|
|
270
|
+
command: "doctor",
|
|
271
|
+
memoryHome,
|
|
272
|
+
memoryHomeSafe: path.basename(memoryHome) === "memories",
|
|
273
|
+
memoryHomeExists: true,
|
|
274
|
+
authRequired: false,
|
|
275
|
+
adapter: { name: adapter.name },
|
|
276
|
+
sourceCount: probe.sourceCount,
|
|
277
|
+
activeMemoryCount: probe.activeMemoryCount,
|
|
278
|
+
refineryHome: {
|
|
279
|
+
home: refineryPaths.home,
|
|
280
|
+
exists: fs.existsSync(refineryPaths.home),
|
|
281
|
+
},
|
|
282
|
+
bundledCodexSkill: {
|
|
283
|
+
path: bundledCodexSkillPath(),
|
|
284
|
+
exists: fs.existsSync(bundledCodexSkillPath()),
|
|
285
|
+
},
|
|
286
|
+
installedCodexSkill: {
|
|
287
|
+
path: installedSkillPath,
|
|
288
|
+
exists: fs.existsSync(installedSkillPath),
|
|
289
|
+
},
|
|
290
|
+
errors: probe.errors,
|
|
291
|
+
};
|
|
292
|
+
if (!probe.valid) {
|
|
293
|
+
process.stdout.write(stableJson({
|
|
294
|
+
...output,
|
|
295
|
+
error: {
|
|
296
|
+
code: "DOCTOR_FAILED",
|
|
297
|
+
message: probe.errors.join("; "),
|
|
298
|
+
phase: "doctor",
|
|
299
|
+
details: probe.errors,
|
|
300
|
+
},
|
|
301
|
+
}));
|
|
302
|
+
return 1;
|
|
303
|
+
}
|
|
304
|
+
process.stdout.write(stableJson(output));
|
|
305
|
+
return 0;
|
|
306
|
+
}
|
|
307
|
+
function packageMetadata() {
|
|
308
|
+
const packagePath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "package.json");
|
|
309
|
+
const parsed = JSON.parse(fs.readFileSync(packagePath, "utf8"));
|
|
310
|
+
return {
|
|
311
|
+
name: parsed.name ?? "refinery",
|
|
312
|
+
version: parsed.version ?? "0.0.0",
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
async function cmdVersion(rest) {
|
|
316
|
+
parseOptionArgs(rest, {
|
|
317
|
+
json: { type: "boolean", default: false },
|
|
318
|
+
});
|
|
319
|
+
process.stdout.write(stableJson({
|
|
320
|
+
ok: true,
|
|
321
|
+
command: "version",
|
|
322
|
+
...packageMetadata(),
|
|
323
|
+
}));
|
|
324
|
+
return 0;
|
|
325
|
+
}
|
|
326
|
+
async function cmdTrial(rest) {
|
|
327
|
+
const sub = rest[0];
|
|
328
|
+
if (sub !== "inspect")
|
|
329
|
+
throw new RefineryError("INVALID_OPTION", "Unknown trial command. Use: refinery trial inspect", { phase: "args" });
|
|
330
|
+
const values = parseOptionArgs(rest.slice(1), {
|
|
331
|
+
"run-dir": { type: "string" },
|
|
332
|
+
json: { type: "boolean", default: false },
|
|
333
|
+
});
|
|
334
|
+
if (!values["run-dir"] || typeof values["run-dir"] !== "string") {
|
|
335
|
+
throw new RefineryError("INVALID_OPTION", "trial inspect requires --run-dir <dir>", { phase: "args" });
|
|
336
|
+
}
|
|
337
|
+
const result = inspectReviewRun(values["run-dir"]);
|
|
338
|
+
process.stdout.write(stableJson(result));
|
|
339
|
+
return 0;
|
|
340
|
+
}
|
|
341
|
+
function memoryProposalFixture() {
|
|
342
|
+
const runId = "fixture-memory-proposal";
|
|
343
|
+
const proposal = {
|
|
344
|
+
schemaVersion: refineryReviewSchemaVersion,
|
|
345
|
+
id: `proposal:${runId}:1`,
|
|
346
|
+
action: "update",
|
|
347
|
+
lifecycle: "proposed",
|
|
348
|
+
intent: "update-candidates",
|
|
349
|
+
memoryType: "preference",
|
|
350
|
+
scope: "project",
|
|
351
|
+
body: "Prefer live Refinery review for memory-update proposals; use fixture mode only when the user explicitly asks for mock, fixture, deterministic, or no-Coral behavior.",
|
|
352
|
+
confidence: 0.91,
|
|
353
|
+
rationale: "This preserves the production path as the default while giving local sessions a deterministic way to rehearse skill and CLI behavior.",
|
|
354
|
+
sourceRefs: [
|
|
355
|
+
{
|
|
356
|
+
source_id: "skill:$refinery",
|
|
357
|
+
source_path: "$refinery",
|
|
358
|
+
kind: "companion-skill",
|
|
359
|
+
},
|
|
360
|
+
],
|
|
361
|
+
targetMemoryId: null,
|
|
362
|
+
updateReason: "Clarifies the expected agent workflow for Refinery memory review usage tests.",
|
|
363
|
+
};
|
|
364
|
+
return {
|
|
365
|
+
ok: true,
|
|
366
|
+
schemaVersion: refineryReviewSchemaVersion,
|
|
367
|
+
command: "review",
|
|
368
|
+
mode: "fixture",
|
|
369
|
+
fixture: "memory-proposal",
|
|
370
|
+
adapter: { name: "fixture" },
|
|
371
|
+
scope: "project",
|
|
372
|
+
dryRun: true,
|
|
373
|
+
writesAttempted: false,
|
|
374
|
+
runId,
|
|
375
|
+
runDir: null,
|
|
376
|
+
counts: {
|
|
377
|
+
sources: 1,
|
|
378
|
+
activeMemories: 1,
|
|
379
|
+
proposals: 1,
|
|
380
|
+
rejected: 0,
|
|
381
|
+
},
|
|
382
|
+
proposals: [proposal],
|
|
383
|
+
rejected: [],
|
|
384
|
+
evidenceReview: {
|
|
385
|
+
findings: [
|
|
386
|
+
{
|
|
387
|
+
relation: "refinement",
|
|
388
|
+
rationale: "Fixture output is intentionally review-shaped but does not inspect real memory.",
|
|
389
|
+
confidence: 0.94,
|
|
390
|
+
},
|
|
391
|
+
],
|
|
392
|
+
},
|
|
393
|
+
metadata: {
|
|
394
|
+
schemaVersion: refineryReviewSchemaVersion,
|
|
395
|
+
runId,
|
|
396
|
+
adapter: "fixture",
|
|
397
|
+
scope: "project",
|
|
398
|
+
dryRun: true,
|
|
399
|
+
mode: "fixture",
|
|
400
|
+
createdAt: "fixture",
|
|
401
|
+
writesAttempted: false,
|
|
402
|
+
sinkUrl: null,
|
|
403
|
+
runtime: { kind: "fixture", coral: false },
|
|
404
|
+
specialistOrder: ["fixture"],
|
|
405
|
+
sourceLimit: 1,
|
|
406
|
+
sourceCharLimit: null,
|
|
407
|
+
intent: "update-candidates",
|
|
408
|
+
request: "Mock fixture memory update proposal.",
|
|
409
|
+
},
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
async function cmdDev(rest) {
|
|
413
|
+
const sub = rest[0];
|
|
414
|
+
const fixture = rest[1];
|
|
415
|
+
if (sub !== "fixture" || fixture !== "memory-proposal") {
|
|
416
|
+
throw new RefineryError("INVALID_OPTION", "Unknown dev command. Use: refinery dev fixture memory-proposal", { phase: "args" });
|
|
417
|
+
}
|
|
418
|
+
parseOptionArgs(rest.slice(2), {
|
|
419
|
+
json: { type: "boolean", default: false },
|
|
420
|
+
});
|
|
421
|
+
process.stdout.write(stableJson(memoryProposalFixture()));
|
|
422
|
+
return 0;
|
|
423
|
+
}
|
|
424
|
+
async function waitForConsoleShutdown(session) {
|
|
425
|
+
const managedProcess = session.managedProcess;
|
|
426
|
+
if (!managedProcess)
|
|
427
|
+
return;
|
|
428
|
+
await new Promise((resolve, reject) => {
|
|
429
|
+
let finished = false;
|
|
430
|
+
const cleanup = () => {
|
|
431
|
+
process.off("SIGINT", shutdown);
|
|
432
|
+
process.off("SIGTERM", shutdown);
|
|
433
|
+
managedProcess.off("exit", exited);
|
|
434
|
+
};
|
|
435
|
+
const finish = () => {
|
|
436
|
+
if (finished)
|
|
437
|
+
return;
|
|
438
|
+
finished = true;
|
|
439
|
+
cleanup();
|
|
440
|
+
resolve();
|
|
441
|
+
};
|
|
442
|
+
const fail = (error) => {
|
|
443
|
+
if (finished)
|
|
444
|
+
return;
|
|
445
|
+
finished = true;
|
|
446
|
+
cleanup();
|
|
447
|
+
reject(error);
|
|
448
|
+
};
|
|
449
|
+
const shutdown = () => {
|
|
450
|
+
session.close().then(finish, fail);
|
|
451
|
+
};
|
|
452
|
+
const exited = () => {
|
|
453
|
+
finish();
|
|
454
|
+
};
|
|
455
|
+
process.once("SIGINT", shutdown);
|
|
456
|
+
process.once("SIGTERM", shutdown);
|
|
457
|
+
managedProcess.once("exit", exited);
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
async function cmdConsole(rest) {
|
|
461
|
+
const sub = rest[0];
|
|
462
|
+
if (sub !== "run") {
|
|
463
|
+
throw new RefineryError("INVALID_OPTION", "Unknown console command. Use: refinery console run", { phase: "args" });
|
|
464
|
+
}
|
|
465
|
+
const values = parseOptionArgs(rest.slice(1), {
|
|
466
|
+
project: { type: "string" },
|
|
467
|
+
intent: { type: "string" },
|
|
468
|
+
request: { type: "string" },
|
|
469
|
+
scope: { type: "string", default: "project" },
|
|
470
|
+
"memory-home": { type: "string" },
|
|
471
|
+
"run-id": { type: "string" },
|
|
472
|
+
"source-limit": { type: "string" },
|
|
473
|
+
"source-char-limit": { type: "string" },
|
|
474
|
+
"coral-url": { type: "string" },
|
|
475
|
+
"coral-auth-key": { type: "string" },
|
|
476
|
+
"coral-config": { type: "string" },
|
|
477
|
+
"coral-namespace": { type: "string" },
|
|
478
|
+
"coral-session-id": { type: "string" },
|
|
479
|
+
"coral-thread-id": { type: "string" },
|
|
480
|
+
"coral-package": { type: "string" },
|
|
481
|
+
"coral-timeout-ms": { type: "string" },
|
|
482
|
+
"coral-no-start": { type: "boolean", default: false },
|
|
483
|
+
"coral-no-teardown": { type: "boolean", default: false },
|
|
484
|
+
"exit-after-seed": { type: "boolean", default: false },
|
|
485
|
+
topology: { type: "string", default: "debate-critique" },
|
|
486
|
+
json: { type: "boolean", default: false },
|
|
487
|
+
});
|
|
488
|
+
const runId = validateRunId(typeof values["run-id"] === "string" ? values["run-id"] : defaultRunId("console"));
|
|
489
|
+
const intent = parseReviewIntent(values.intent);
|
|
490
|
+
const request = typeof values.request === "string" && values.request.trim() ? values.request.trim() : null;
|
|
491
|
+
const sourceLimit = parsePositiveIntegerOption(values["source-limit"], "--source-limit");
|
|
492
|
+
const sourceCharLimit = parsePositiveIntegerOption(values["source-char-limit"], "--source-char-limit");
|
|
493
|
+
const coralTimeoutMs = parsePositiveIntegerOption(values["coral-timeout-ms"], "--coral-timeout-ms");
|
|
494
|
+
const topology = parseReviewTopology(values.topology);
|
|
495
|
+
if (typeof values["coral-thread-id"] === "string" && typeof values["coral-session-id"] !== "string") {
|
|
496
|
+
throw new RefineryError("INVALID_OPTION", "--coral-thread-id requires --coral-session-id", { phase: "args" });
|
|
497
|
+
}
|
|
498
|
+
const project = path.resolve(typeof values.project === "string" ? values.project : process.cwd());
|
|
499
|
+
const adapter = createCodexMemoryAdapter({
|
|
500
|
+
memoryHome: typeof values["memory-home"] === "string" ? values["memory-home"] : undefined,
|
|
501
|
+
});
|
|
502
|
+
const validation = validateMemoryStoreAdapter(adapter);
|
|
503
|
+
if (!validation.valid) {
|
|
504
|
+
throw new RefineryError("ADAPTER_INVALID", validation.errors.join("; "), {
|
|
505
|
+
phase: "adapter",
|
|
506
|
+
details: validation.errors,
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
const session = await startCoralConsoleRun({
|
|
510
|
+
adapter,
|
|
511
|
+
project,
|
|
512
|
+
source: "codex-memory",
|
|
513
|
+
target: "codex-memory",
|
|
514
|
+
scope: String(values.scope ?? "project"),
|
|
515
|
+
runId,
|
|
516
|
+
intent,
|
|
517
|
+
request,
|
|
518
|
+
sourceLimit,
|
|
519
|
+
sourceCharLimit,
|
|
520
|
+
coral: {
|
|
521
|
+
apiUrl: typeof values["coral-url"] === "string" ? values["coral-url"] : undefined,
|
|
522
|
+
authKey: typeof values["coral-auth-key"] === "string" ? values["coral-auth-key"] : undefined,
|
|
523
|
+
configPath: typeof values["coral-config"] === "string" ? values["coral-config"] : undefined,
|
|
524
|
+
namespace: typeof values["coral-namespace"] === "string" ? values["coral-namespace"] : undefined,
|
|
525
|
+
sessionId: typeof values["coral-session-id"] === "string" ? values["coral-session-id"] : undefined,
|
|
526
|
+
threadId: typeof values["coral-thread-id"] === "string" ? values["coral-thread-id"] : undefined,
|
|
527
|
+
coralPackage: typeof values["coral-package"] === "string" ? values["coral-package"] : undefined,
|
|
528
|
+
timeoutMs: coralTimeoutMs,
|
|
529
|
+
topology,
|
|
530
|
+
startServer: typeof values["coral-url"] === "string" ? false : !values["coral-no-start"],
|
|
531
|
+
noTeardown: Boolean(values["coral-no-teardown"]),
|
|
532
|
+
},
|
|
533
|
+
});
|
|
534
|
+
process.stdout.write(stableJson(session.result));
|
|
535
|
+
if (Boolean(values["exit-after-seed"])) {
|
|
536
|
+
await session.close();
|
|
537
|
+
return 0;
|
|
538
|
+
}
|
|
539
|
+
if (session.managedServerStarted)
|
|
540
|
+
await waitForConsoleShutdown(session);
|
|
541
|
+
return 0;
|
|
542
|
+
}
|
|
543
|
+
async function cmdReview(rest) {
|
|
544
|
+
const values = parseOptionArgs(rest, {
|
|
545
|
+
project: { type: "string" },
|
|
546
|
+
intent: { type: "string" },
|
|
547
|
+
request: { type: "string" },
|
|
548
|
+
scope: { type: "string", default: "project" },
|
|
549
|
+
home: { type: "string" },
|
|
550
|
+
"memory-home": { type: "string" },
|
|
551
|
+
"run-id": { type: "string" },
|
|
552
|
+
"output-dir": { type: "string" },
|
|
553
|
+
sink: { type: "string" },
|
|
554
|
+
"sink-url": { type: "string" },
|
|
555
|
+
"sink-timeout-ms": { type: "string" },
|
|
556
|
+
"source-limit": { type: "string" },
|
|
557
|
+
"source-char-limit": { type: "string" },
|
|
558
|
+
"coral-url": { type: "string" },
|
|
559
|
+
"coral-auth-key": { type: "string" },
|
|
560
|
+
"coral-config": { type: "string" },
|
|
561
|
+
"coral-namespace": { type: "string" },
|
|
562
|
+
"coral-session-id": { type: "string" },
|
|
563
|
+
"coral-thread-id": { type: "string" },
|
|
564
|
+
"coral-package": { type: "string" },
|
|
565
|
+
"coral-timeout-ms": { type: "string" },
|
|
566
|
+
"coral-no-start": { type: "boolean", default: false },
|
|
567
|
+
"coral-no-teardown": { type: "boolean", default: false },
|
|
568
|
+
topology: { type: "string" },
|
|
569
|
+
json: { type: "boolean", default: false },
|
|
570
|
+
});
|
|
571
|
+
const runId = validateRunId(typeof values["run-id"] === "string" ? values["run-id"] : defaultRunId());
|
|
572
|
+
const intent = parseReviewIntent(values.intent);
|
|
573
|
+
const request = typeof values.request === "string" && values.request.trim() ? values.request.trim() : null;
|
|
574
|
+
const sourceLimit = parsePositiveIntegerOption(values["source-limit"], "--source-limit");
|
|
575
|
+
const sourceCharLimit = parsePositiveIntegerOption(values["source-char-limit"], "--source-char-limit");
|
|
576
|
+
const sinkTimeoutMs = parsePositiveIntegerOption(values["sink-timeout-ms"], "--sink-timeout-ms");
|
|
577
|
+
const coralTimeoutMs = parsePositiveIntegerOption(values["coral-timeout-ms"], "--coral-timeout-ms");
|
|
578
|
+
const topology = parseReviewTopology(values.topology);
|
|
579
|
+
const project = path.resolve(typeof values.project === "string" ? values.project : process.cwd());
|
|
580
|
+
const paths = resolveRefineryPaths({
|
|
581
|
+
home: typeof values.home === "string" ? values.home : undefined,
|
|
582
|
+
cwd: project,
|
|
583
|
+
});
|
|
584
|
+
const outputDir = typeof values["output-dir"] === "string" ? path.resolve(values["output-dir"]) : paths.runsDir;
|
|
585
|
+
ensureRunDirInside(outputDir, runId);
|
|
586
|
+
const loadedSink = typeof values.sink === "string"
|
|
587
|
+
? await loadSink(values.sink)
|
|
588
|
+
: typeof values["sink-url"] === "string"
|
|
589
|
+
? { url: values["sink-url"] }
|
|
590
|
+
: undefined;
|
|
591
|
+
const sink = loadedSink && sinkTimeoutMs ? { ...loadedSink, timeoutMs: sinkTimeoutMs } : loadedSink;
|
|
592
|
+
if (typeof values["coral-thread-id"] === "string" && typeof values["coral-session-id"] !== "string") {
|
|
593
|
+
throw new RefineryError("INVALID_OPTION", "--coral-thread-id requires --coral-session-id", { phase: "args" });
|
|
594
|
+
}
|
|
595
|
+
const adapter = createCodexMemoryAdapter({
|
|
596
|
+
memoryHome: typeof values["memory-home"] === "string" ? values["memory-home"] : undefined,
|
|
597
|
+
});
|
|
598
|
+
const validation = validateMemoryStoreAdapter(adapter);
|
|
599
|
+
if (!validation.valid) {
|
|
600
|
+
throw new RefineryError("ADAPTER_INVALID", validation.errors.join("; "), {
|
|
601
|
+
phase: "adapter",
|
|
602
|
+
details: validation.errors,
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
const result = await runCoralReview({
|
|
606
|
+
adapter,
|
|
607
|
+
project,
|
|
608
|
+
source: "codex-memory",
|
|
609
|
+
target: "codex-memory",
|
|
610
|
+
scope: String(values.scope ?? "project"),
|
|
611
|
+
runId,
|
|
612
|
+
outputDir,
|
|
613
|
+
intent,
|
|
614
|
+
request,
|
|
615
|
+
sink,
|
|
616
|
+
sourceLimit,
|
|
617
|
+
sourceCharLimit,
|
|
618
|
+
coral: {
|
|
619
|
+
apiUrl: typeof values["coral-url"] === "string" ? values["coral-url"] : undefined,
|
|
620
|
+
authKey: typeof values["coral-auth-key"] === "string" ? values["coral-auth-key"] : undefined,
|
|
621
|
+
configPath: typeof values["coral-config"] === "string" ? values["coral-config"] : undefined,
|
|
622
|
+
namespace: typeof values["coral-namespace"] === "string" ? values["coral-namespace"] : undefined,
|
|
623
|
+
sessionId: typeof values["coral-session-id"] === "string" ? values["coral-session-id"] : undefined,
|
|
624
|
+
threadId: typeof values["coral-thread-id"] === "string" ? values["coral-thread-id"] : undefined,
|
|
625
|
+
coralPackage: typeof values["coral-package"] === "string" ? values["coral-package"] : undefined,
|
|
626
|
+
timeoutMs: coralTimeoutMs,
|
|
627
|
+
topology,
|
|
628
|
+
startServer: typeof values["coral-url"] === "string" ? false : !values["coral-no-start"],
|
|
629
|
+
noTeardown: Boolean(values["coral-no-teardown"]),
|
|
630
|
+
},
|
|
631
|
+
});
|
|
632
|
+
process.stdout.write(stableJson(result));
|
|
633
|
+
return 0;
|
|
634
|
+
}
|
|
635
|
+
export async function main(argv = process.argv.slice(2)) {
|
|
636
|
+
const command = argv[0];
|
|
637
|
+
if (!command || command === "--help" || command === "-h") {
|
|
638
|
+
process.stdout.write(HELP + "\n");
|
|
639
|
+
return 0;
|
|
640
|
+
}
|
|
641
|
+
if (command === "doctor")
|
|
642
|
+
return cmdDoctor(argv.slice(1));
|
|
643
|
+
if (command === "init")
|
|
644
|
+
return cmdInit(argv.slice(1));
|
|
645
|
+
if (command === "version")
|
|
646
|
+
return cmdVersion(argv.slice(1));
|
|
647
|
+
if (command === "trial")
|
|
648
|
+
return cmdTrial(argv.slice(1));
|
|
649
|
+
if (command === "console")
|
|
650
|
+
return cmdConsole(argv.slice(1));
|
|
651
|
+
if (command === "dev")
|
|
652
|
+
return cmdDev(argv.slice(1));
|
|
653
|
+
if (command === "review")
|
|
654
|
+
return cmdReview(argv.slice(1));
|
|
655
|
+
throw new RefineryError("INVALID_OPTION", `Unknown command: ${command}`, { phase: "args" });
|
|
656
|
+
}
|
|
657
|
+
if (isMainModule()) {
|
|
658
|
+
const argv = process.argv.slice(2);
|
|
659
|
+
main(argv).then((code) => {
|
|
660
|
+
process.exitCode = code;
|
|
661
|
+
}, (error) => {
|
|
662
|
+
if (wantsJson(argv)) {
|
|
663
|
+
writeJsonFailure(argv, error);
|
|
664
|
+
}
|
|
665
|
+
else {
|
|
666
|
+
process.stderr.write(`${error.message}\n`);
|
|
667
|
+
}
|
|
668
|
+
process.exitCode = 1;
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
//# sourceMappingURL=cli.js.map
|