@klaudworks/rmr 1.0.0 → 1.0.1
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/dist/index.js +90 -15
- package/examples/workflows/feature-dev/workflow.yaml +0 -11
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10921,23 +10921,31 @@ class CompletionCommand extends BaseCommand {
|
|
|
10921
10921
|
}
|
|
10922
10922
|
|
|
10923
10923
|
// src/lib/run-state.ts
|
|
10924
|
-
import { readFile, writeFile } from "node:fs/promises";
|
|
10924
|
+
import { appendFile, readFile, writeFile } from "node:fs/promises";
|
|
10925
10925
|
import { resolve as resolve3 } from "node:path";
|
|
10926
10926
|
function pad(input) {
|
|
10927
10927
|
return String(input).padStart(2, "0");
|
|
10928
10928
|
}
|
|
10929
10929
|
function generateRunId(now = new Date) {
|
|
10930
|
-
const yyyy = now.
|
|
10931
|
-
const mm = pad(now.
|
|
10932
|
-
const dd = pad(now.
|
|
10933
|
-
const hh = pad(now.
|
|
10934
|
-
const min = pad(now.
|
|
10935
|
-
const sec = pad(now.
|
|
10936
|
-
return `${yyyy}${mm}${dd}-${hh}${min}${sec}
|
|
10930
|
+
const yyyy = now.getFullYear();
|
|
10931
|
+
const mm = pad(now.getMonth() + 1);
|
|
10932
|
+
const dd = pad(now.getDate());
|
|
10933
|
+
const hh = pad(now.getHours());
|
|
10934
|
+
const min = pad(now.getMinutes());
|
|
10935
|
+
const sec = pad(now.getSeconds());
|
|
10936
|
+
return `${yyyy}${mm}${dd}-${hh}${min}${sec}`;
|
|
10937
10937
|
}
|
|
10938
10938
|
function runFilePath(config, runId) {
|
|
10939
10939
|
return resolve3(config.runsDir, `${runId}.json`);
|
|
10940
10940
|
}
|
|
10941
|
+
function runLogPath(config, runId) {
|
|
10942
|
+
return resolve3(config.runsDir, `${runId}.log`);
|
|
10943
|
+
}
|
|
10944
|
+
async function appendToRunLog(config, runId, content) {
|
|
10945
|
+
const path = runLogPath(config, runId);
|
|
10946
|
+
await appendFile(path, content, "utf8");
|
|
10947
|
+
return path;
|
|
10948
|
+
}
|
|
10941
10949
|
function createInitialRunState(options) {
|
|
10942
10950
|
const firstStep = options.workflow.steps[0];
|
|
10943
10951
|
if (!firstStep) {
|
|
@@ -11219,7 +11227,7 @@ var adapters = {
|
|
|
11219
11227
|
},
|
|
11220
11228
|
createStreamParser: createOpenCodeStreamParser,
|
|
11221
11229
|
resumeTemplate(sessionId) {
|
|
11222
|
-
return `opencode
|
|
11230
|
+
return `opencode --session ${sessionId}`;
|
|
11223
11231
|
}
|
|
11224
11232
|
},
|
|
11225
11233
|
codex: {
|
|
@@ -11236,7 +11244,7 @@ var adapters = {
|
|
|
11236
11244
|
},
|
|
11237
11245
|
createStreamParser: createCodexStreamParser,
|
|
11238
11246
|
resumeTemplate(sessionId) {
|
|
11239
|
-
return `codex
|
|
11247
|
+
return `codex resume ${sessionId}`;
|
|
11240
11248
|
}
|
|
11241
11249
|
},
|
|
11242
11250
|
copilot: {
|
|
@@ -11472,6 +11480,19 @@ function applyOutputToContext(context, stepId, values) {
|
|
|
11472
11480
|
context[`${stepId}.${key}`] = value;
|
|
11473
11481
|
}
|
|
11474
11482
|
}
|
|
11483
|
+
function formatStepLogEntry(params) {
|
|
11484
|
+
const separator = `${"=".repeat(80)}
|
|
11485
|
+
`;
|
|
11486
|
+
const output = params.combinedOutput.length > 0 ? params.combinedOutput.endsWith(`
|
|
11487
|
+
`) ? params.combinedOutput : `${params.combinedOutput}
|
|
11488
|
+
` : `
|
|
11489
|
+
`;
|
|
11490
|
+
return `${separator}STEP: ${params.stepId} (step ${params.stepNumber}) | Started: ${params.startedAt}
|
|
11491
|
+
` + `${separator}` + `${output}
|
|
11492
|
+
` + `${separator}STEP: ${params.stepId} (step ${params.stepNumber}) | Completed: ${params.completedAt} | Status: ${params.status}
|
|
11493
|
+
` + `${separator}
|
|
11494
|
+
`;
|
|
11495
|
+
}
|
|
11475
11496
|
async function runWorkflow(config, workflow, runState, options) {
|
|
11476
11497
|
if (options.overrides?.stepId) {
|
|
11477
11498
|
runState.current_step = options.overrides.stepId;
|
|
@@ -11516,6 +11537,15 @@ Note: ${injectedHint}` : resolvedPrompt;
|
|
|
11516
11537
|
runState.last_harness.session_id = result.sessionId;
|
|
11517
11538
|
}
|
|
11518
11539
|
if (result.exitCode !== 0) {
|
|
11540
|
+
const completedAt = new Date().toISOString();
|
|
11541
|
+
await appendToRunLog(config, runState.run_id, formatStepLogEntry({
|
|
11542
|
+
stepId: step.id,
|
|
11543
|
+
stepNumber,
|
|
11544
|
+
startedAt: stepStartedAt,
|
|
11545
|
+
completedAt,
|
|
11546
|
+
status: "paused",
|
|
11547
|
+
combinedOutput: result.combinedOutput
|
|
11548
|
+
}));
|
|
11519
11549
|
await pauseRun(config, runState, harnessExitReason({
|
|
11520
11550
|
stepId: step.id,
|
|
11521
11551
|
harness,
|
|
@@ -11527,6 +11557,15 @@ Note: ${injectedHint}` : resolvedPrompt;
|
|
|
11527
11557
|
return runState;
|
|
11528
11558
|
}
|
|
11529
11559
|
if (result.combinedOutput.includes(HUMAN_SENTINEL)) {
|
|
11560
|
+
const completedAt = new Date().toISOString();
|
|
11561
|
+
await appendToRunLog(config, runState.run_id, formatStepLogEntry({
|
|
11562
|
+
stepId: step.id,
|
|
11563
|
+
stepNumber,
|
|
11564
|
+
startedAt: stepStartedAt,
|
|
11565
|
+
completedAt,
|
|
11566
|
+
status: "paused",
|
|
11567
|
+
combinedOutput: result.combinedOutput
|
|
11568
|
+
}));
|
|
11530
11569
|
await pauseRun(config, runState, `HUMAN_INTERVENTION_REQUIRED at step "${step.id}".`, harness, runState.last_harness.session_id);
|
|
11531
11570
|
return runState;
|
|
11532
11571
|
}
|
|
@@ -11536,6 +11575,15 @@ Note: ${injectedHint}` : resolvedPrompt;
|
|
|
11536
11575
|
validateRequiredOutputKeys(stepOutput, step.requires.outputs);
|
|
11537
11576
|
} catch (error) {
|
|
11538
11577
|
const message = error instanceof Error ? error.message : "Failed to parse step output.";
|
|
11578
|
+
const completedAt = new Date().toISOString();
|
|
11579
|
+
await appendToRunLog(config, runState.run_id, formatStepLogEntry({
|
|
11580
|
+
stepId: step.id,
|
|
11581
|
+
stepNumber,
|
|
11582
|
+
startedAt: stepStartedAt,
|
|
11583
|
+
completedAt,
|
|
11584
|
+
status: "paused",
|
|
11585
|
+
combinedOutput: result.combinedOutput
|
|
11586
|
+
}));
|
|
11539
11587
|
await pauseRun(config, runState, message, harness, runState.last_harness.session_id);
|
|
11540
11588
|
return runState;
|
|
11541
11589
|
}
|
|
@@ -11543,19 +11591,46 @@ Note: ${injectedHint}` : resolvedPrompt;
|
|
|
11543
11591
|
applyOutputToContext(runState.context, step.id, stepOutput.values);
|
|
11544
11592
|
const nextState = stepOutput.next_state ?? step.next_step;
|
|
11545
11593
|
if (!isValidTarget(workflow, nextState)) {
|
|
11594
|
+
const completedAt = new Date().toISOString();
|
|
11595
|
+
await appendToRunLog(config, runState.run_id, formatStepLogEntry({
|
|
11596
|
+
stepId: step.id,
|
|
11597
|
+
stepNumber,
|
|
11598
|
+
startedAt: stepStartedAt,
|
|
11599
|
+
completedAt,
|
|
11600
|
+
status: "paused",
|
|
11601
|
+
combinedOutput: result.combinedOutput
|
|
11602
|
+
}));
|
|
11546
11603
|
await pauseRun(config, runState, `Invalid next_state "${nextState}" at step "${step.id}".`, harness, runState.last_harness.session_id);
|
|
11547
11604
|
return runState;
|
|
11548
11605
|
}
|
|
11549
11606
|
if (nextState === "human_intervention") {
|
|
11607
|
+
const completedAt = new Date().toISOString();
|
|
11608
|
+
await appendToRunLog(config, runState.run_id, formatStepLogEntry({
|
|
11609
|
+
stepId: step.id,
|
|
11610
|
+
stepNumber,
|
|
11611
|
+
startedAt: stepStartedAt,
|
|
11612
|
+
completedAt,
|
|
11613
|
+
status: "paused",
|
|
11614
|
+
combinedOutput: result.combinedOutput
|
|
11615
|
+
}));
|
|
11550
11616
|
await pauseRun(config, runState, `Step "${step.id}" requested human intervention.`, harness, runState.last_harness.session_id);
|
|
11551
11617
|
return runState;
|
|
11552
11618
|
}
|
|
11619
|
+
const stepCompletedAt = new Date().toISOString();
|
|
11620
|
+
await appendToRunLog(config, runState.run_id, formatStepLogEntry({
|
|
11621
|
+
stepId: step.id,
|
|
11622
|
+
stepNumber,
|
|
11623
|
+
startedAt: stepStartedAt,
|
|
11624
|
+
completedAt: stepCompletedAt,
|
|
11625
|
+
status: "success",
|
|
11626
|
+
combinedOutput: result.combinedOutput
|
|
11627
|
+
}));
|
|
11553
11628
|
const stepExecution = {
|
|
11554
11629
|
step_number: stepNumber,
|
|
11555
11630
|
step_id: step.id,
|
|
11556
11631
|
session_id: runState.last_harness?.session_id ?? null,
|
|
11557
11632
|
started_at: stepStartedAt,
|
|
11558
|
-
completed_at:
|
|
11633
|
+
completed_at: stepCompletedAt
|
|
11559
11634
|
};
|
|
11560
11635
|
runState.step_history.push(stepExecution);
|
|
11561
11636
|
stepNumber++;
|
|
@@ -11839,15 +11914,15 @@ class ContinueCommand extends BaseCommand {
|
|
|
11839
11914
|
description: "Resume a previously created run by run id.",
|
|
11840
11915
|
details: "Loads `.rmr/runs/<run-id>.json` and continues orchestration from the stored step unless overridden. If a harness session id exists (or is provided), rmr attempts harness resume first.",
|
|
11841
11916
|
examples: [
|
|
11842
|
-
["Resume a paused run", "$0 continue 20260316-
|
|
11843
|
-
["Resume from a specific step", "$0 continue 20260316-
|
|
11917
|
+
["Resume a paused run", "$0 continue 20260316-153210"],
|
|
11918
|
+
["Resume from a specific step", "$0 continue 20260316-153210 --step verify"],
|
|
11844
11919
|
[
|
|
11845
11920
|
"Resume with a hint",
|
|
11846
|
-
'$0 continue 20260316-
|
|
11921
|
+
'$0 continue 20260316-153210 --hint "Plan mode only: read and propose changes, do not edit files."'
|
|
11847
11922
|
],
|
|
11848
11923
|
[
|
|
11849
11924
|
"Force session override",
|
|
11850
|
-
"$0 continue 20260316-
|
|
11925
|
+
"$0 continue 20260316-153210 --session-id abc123"
|
|
11851
11926
|
]
|
|
11852
11927
|
]
|
|
11853
11928
|
});
|
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
# Feature development workflow for rmr.
|
|
2
|
-
# Three steps: plan (research + plan), implement, verify (review).
|
|
3
|
-
# The verify step can loop back to implement or escalate to human intervention.
|
|
4
|
-
#
|
|
5
|
-
# Prompt files are co-located with this workflow in the same folder.
|
|
6
|
-
# Template variables reference step outputs: {{step_id.key}}
|
|
7
|
-
#
|
|
8
|
-
# Routing is controlled by <rmr:next_state> in agent output.
|
|
9
|
-
# The planner can reject a task by setting next_state=done.
|
|
10
|
-
# The reviewer can request changes by setting next_state=implement.
|
|
11
|
-
|
|
12
1
|
id: feature-dev
|
|
13
2
|
name: Feature Development
|
|
14
3
|
harness: claude
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@klaudworks/rex",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@klaudworks/rex",
|
|
9
|
-
"version": "1.0.
|
|
9
|
+
"version": "1.0.1",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"clipanion": "^4.0.0-rc.4",
|
|
12
12
|
"yaml": "^2.8.2"
|