ralph-lisa-loop 0.3.0 → 0.3.9
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/README.md +51 -17
- package/dist/cli.js +20 -8
- package/dist/commands.d.ts +8 -0
- package/dist/commands.js +206 -64
- package/dist/policy.d.ts +6 -3
- package/dist/policy.js +7 -14
- package/dist/state.d.ts +13 -0
- package/dist/state.js +74 -12
- package/package.json +2 -1
- package/templates/roles/lisa.md +55 -18
- package/templates/roles/ralph.md +37 -18
- package/dist/test/cli.test.d.ts +0 -1
- package/dist/test/cli.test.js +0 -594
- package/dist/test/policy.test.d.ts +0 -1
- package/dist/test/policy.test.js +0 -130
- package/dist/test/state.test.d.ts +0 -1
- package/dist/test/state.test.js +0 -82
- package/dist/test/watcher.test.d.ts +0 -12
- package/dist/test/watcher.test.js +0 -247
package/dist/state.js
CHANGED
|
@@ -38,6 +38,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
38
38
|
})();
|
|
39
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
40
|
exports.VALID_TAGS = exports.ARCHIVE_DIR = exports.STATE_DIR = void 0;
|
|
41
|
+
exports.findProjectRoot = findProjectRoot;
|
|
42
|
+
exports.resetProjectRootCache = resetProjectRootCache;
|
|
41
43
|
exports.stateDir = stateDir;
|
|
42
44
|
exports.checkSession = checkSession;
|
|
43
45
|
exports.readFile = readFile;
|
|
@@ -61,11 +63,71 @@ exports.STATE_DIR = ".dual-agent";
|
|
|
61
63
|
exports.ARCHIVE_DIR = ".dual-agent-archive";
|
|
62
64
|
exports.VALID_TAGS = "PLAN|RESEARCH|CODE|FIX|PASS|NEEDS_WORK|CHALLENGE|DISCUSS|QUESTION|CONSENSUS";
|
|
63
65
|
const TAG_RE = new RegExp(`^\\[(${exports.VALID_TAGS})\\]`);
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Walk up from startDir to find the nearest directory containing .dual-agent/.
|
|
68
|
+
* Similar to how git finds .git/ from any subdirectory.
|
|
69
|
+
* Result is cached per process invocation for efficiency.
|
|
70
|
+
*/
|
|
71
|
+
/**
|
|
72
|
+
* Cache keyed by resolved startDir to avoid returning wrong root
|
|
73
|
+
* when called with different directories in the same process.
|
|
74
|
+
*/
|
|
75
|
+
let _cachedStartDir;
|
|
76
|
+
let _cachedProjectRoot;
|
|
77
|
+
function findProjectRoot(startDir = process.cwd()) {
|
|
78
|
+
const resolved = path.resolve(startDir);
|
|
79
|
+
// Cache hit: same startDir as last call
|
|
80
|
+
if (_cachedStartDir === resolved && _cachedProjectRoot !== undefined) {
|
|
81
|
+
if (_cachedProjectRoot === null)
|
|
82
|
+
return null;
|
|
83
|
+
// Validate cached root still exists
|
|
84
|
+
if (fs.existsSync(path.join(_cachedProjectRoot, exports.STATE_DIR))) {
|
|
85
|
+
return _cachedProjectRoot;
|
|
86
|
+
}
|
|
87
|
+
// Invalidate stale cache
|
|
88
|
+
_cachedStartDir = undefined;
|
|
89
|
+
_cachedProjectRoot = undefined;
|
|
90
|
+
}
|
|
91
|
+
let dir = resolved;
|
|
92
|
+
while (true) {
|
|
93
|
+
if (fs.existsSync(path.join(dir, exports.STATE_DIR))) {
|
|
94
|
+
_cachedStartDir = resolved;
|
|
95
|
+
_cachedProjectRoot = dir;
|
|
96
|
+
return dir;
|
|
97
|
+
}
|
|
98
|
+
const parent = path.dirname(dir);
|
|
99
|
+
if (parent === dir)
|
|
100
|
+
break; // reached filesystem root
|
|
101
|
+
dir = parent;
|
|
102
|
+
}
|
|
103
|
+
_cachedStartDir = resolved;
|
|
104
|
+
_cachedProjectRoot = null;
|
|
105
|
+
return null;
|
|
66
106
|
}
|
|
67
|
-
|
|
68
|
-
|
|
107
|
+
/**
|
|
108
|
+
* Reset the cached project root. Used in tests.
|
|
109
|
+
*/
|
|
110
|
+
function resetProjectRootCache() {
|
|
111
|
+
_cachedStartDir = undefined;
|
|
112
|
+
_cachedProjectRoot = undefined;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get the .dual-agent/ state directory path.
|
|
116
|
+
* When projectDir is explicitly given, uses that path directly.
|
|
117
|
+
* When omitted, searches upward from CWD to find .dual-agent/ (like git).
|
|
118
|
+
*/
|
|
119
|
+
function stateDir(projectDir) {
|
|
120
|
+
if (projectDir !== undefined) {
|
|
121
|
+
return path.join(projectDir, exports.STATE_DIR);
|
|
122
|
+
}
|
|
123
|
+
const root = findProjectRoot();
|
|
124
|
+
return path.join(root || process.cwd(), exports.STATE_DIR);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Check that a session exists. Searches upward from CWD when no explicit dir given.
|
|
128
|
+
*/
|
|
129
|
+
function checkSession(projectDir) {
|
|
130
|
+
const dir = projectDir !== undefined ? stateDir(projectDir) : stateDir();
|
|
69
131
|
if (!fs.existsSync(dir)) {
|
|
70
132
|
console.error('Error: Session not initialized. Run: ralph-lisa init "task description"');
|
|
71
133
|
process.exit(1);
|
|
@@ -87,22 +149,22 @@ function appendFile(filePath, content) {
|
|
|
87
149
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
88
150
|
fs.appendFileSync(filePath, content, "utf-8");
|
|
89
151
|
}
|
|
90
|
-
function getTurn(projectDir
|
|
152
|
+
function getTurn(projectDir) {
|
|
91
153
|
return readFile(path.join(stateDir(projectDir), "turn.txt")) || "ralph";
|
|
92
154
|
}
|
|
93
|
-
function setTurn(turn, projectDir
|
|
155
|
+
function setTurn(turn, projectDir) {
|
|
94
156
|
writeFile(path.join(stateDir(projectDir), "turn.txt"), turn);
|
|
95
157
|
}
|
|
96
|
-
function getRound(projectDir
|
|
158
|
+
function getRound(projectDir) {
|
|
97
159
|
return readFile(path.join(stateDir(projectDir), "round.txt")) || "?";
|
|
98
160
|
}
|
|
99
|
-
function setRound(round, projectDir
|
|
161
|
+
function setRound(round, projectDir) {
|
|
100
162
|
writeFile(path.join(stateDir(projectDir), "round.txt"), String(round));
|
|
101
163
|
}
|
|
102
|
-
function getStep(projectDir
|
|
164
|
+
function getStep(projectDir) {
|
|
103
165
|
return readFile(path.join(stateDir(projectDir), "step.txt")) || "?";
|
|
104
166
|
}
|
|
105
|
-
function setStep(step, projectDir
|
|
167
|
+
function setStep(step, projectDir) {
|
|
106
168
|
writeFile(path.join(stateDir(projectDir), "step.txt"), step);
|
|
107
169
|
}
|
|
108
170
|
function extractTag(content) {
|
|
@@ -124,7 +186,7 @@ function timeShort() {
|
|
|
124
186
|
const pad = (n) => String(n).padStart(2, "0");
|
|
125
187
|
return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
|
126
188
|
}
|
|
127
|
-
function appendHistory(role, content, projectDir
|
|
189
|
+
function appendHistory(role, content, projectDir) {
|
|
128
190
|
const tag = extractTag(content);
|
|
129
191
|
const summary = extractSummary(content);
|
|
130
192
|
const round = getRound(projectDir);
|
|
@@ -142,7 +204,7 @@ ${content}
|
|
|
142
204
|
`;
|
|
143
205
|
appendFile(path.join(stateDir(projectDir), "history.md"), entry);
|
|
144
206
|
}
|
|
145
|
-
function updateLastAction(role, content, projectDir
|
|
207
|
+
function updateLastAction(role, content, projectDir) {
|
|
146
208
|
const tag = extractTag(content);
|
|
147
209
|
const summary = extractSummary(content);
|
|
148
210
|
const ts = timeShort();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ralph-lisa-loop",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
4
4
|
"description": "Turn-based dual-agent collaboration: Ralph codes, Lisa reviews, consensus required.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"ralph-lisa": "dist/cli.js"
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
},
|
|
14
14
|
"files": [
|
|
15
15
|
"dist/",
|
|
16
|
+
"!dist/test/",
|
|
16
17
|
"templates/"
|
|
17
18
|
],
|
|
18
19
|
"keywords": [
|
package/templates/roles/lisa.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
You work with Ralph (lead developer) in a turn-based collaboration.
|
|
5
5
|
|
|
6
|
-
##
|
|
6
|
+
## AUTO-START: Do This Immediately
|
|
7
7
|
|
|
8
8
|
**Every time the user messages you (even just "continue" or "go"), run these commands:**
|
|
9
9
|
|
|
@@ -20,7 +20,7 @@ Then based on result:
|
|
|
20
20
|
|
|
21
21
|
**Do NOT wait for user to tell you to check. Check automatically.**
|
|
22
22
|
|
|
23
|
-
##
|
|
23
|
+
## CRITICAL: Turn-Based Rules
|
|
24
24
|
|
|
25
25
|
- Output `lisa` → You can review
|
|
26
26
|
- Output `ralph` → STOP immediately, tell user "Waiting for Ralph"
|
|
@@ -29,13 +29,15 @@ Then based on result:
|
|
|
29
29
|
|
|
30
30
|
## How to Submit
|
|
31
31
|
|
|
32
|
-
When your review is ready:
|
|
32
|
+
When your review is ready, **always use `--file`** for safe submission (avoids shell escaping issues with `[]`, backticks, `$`, nested quotes):
|
|
33
33
|
```bash
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
# 1. Write review to a file (e.g., .dual-agent/submit.md)
|
|
35
|
+
# 2. Submit from file
|
|
36
|
+
ralph-lisa submit-lisa --file .dual-agent/submit.md
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
+
Inline mode (`ralph-lisa submit-lisa "[TAG] ..."`) is deprecated — it breaks on special characters. Use `--file` or `--stdin` instead.
|
|
40
|
+
|
|
39
41
|
This automatically passes the turn to Ralph. Then you MUST STOP.
|
|
40
42
|
|
|
41
43
|
## Tags You Can Use
|
|
@@ -54,37 +56,72 @@ This automatically passes the turn to Ralph. Then you MUST STOP.
|
|
|
54
56
|
```
|
|
55
57
|
1. ralph-lisa whose-turn → Check turn
|
|
56
58
|
2. (If lisa) Read Ralph's work: ralph-lisa read work.md
|
|
57
|
-
3. Review
|
|
58
|
-
4.
|
|
59
|
-
5.
|
|
60
|
-
6.
|
|
61
|
-
7.
|
|
59
|
+
3. Review following the behavior spec below
|
|
60
|
+
4. Write review to .dual-agent/submit.md
|
|
61
|
+
5. ralph-lisa submit-lisa --file .dual-agent/submit.md
|
|
62
|
+
6. STOP and wait for Ralph
|
|
63
|
+
7. ralph-lisa whose-turn → Check again
|
|
64
|
+
8. Repeat
|
|
62
65
|
```
|
|
63
66
|
|
|
64
67
|
## Available Commands
|
|
65
68
|
|
|
66
69
|
```bash
|
|
67
70
|
ralph-lisa whose-turn # Check whose turn
|
|
68
|
-
ralph-lisa submit-lisa
|
|
71
|
+
ralph-lisa submit-lisa --file .dual-agent/submit.md # Submit and pass turn
|
|
69
72
|
ralph-lisa status # See current status
|
|
70
73
|
ralph-lisa read work.md # Read Ralph's work
|
|
74
|
+
ralph-lisa recap # Context recovery summary
|
|
71
75
|
ralph-lisa history # View full history
|
|
72
76
|
```
|
|
73
77
|
|
|
74
|
-
##
|
|
78
|
+
## Goal Guardian (Direction Check)
|
|
79
|
+
|
|
80
|
+
**Before every review**, check task alignment:
|
|
81
|
+
1. Read task.md: `ralph-lisa read task.md`
|
|
82
|
+
2. Compare Ralph's work direction with the task goal
|
|
83
|
+
3. If misaligned: return [NEEDS_WORK] with "Direction misalignment" before reviewing code details
|
|
84
|
+
4. If aligned: proceed with normal code review
|
|
85
|
+
|
|
86
|
+
This is your PRIMARY responsibility — catching direction drift early saves more time than catching code bugs.
|
|
87
|
+
|
|
88
|
+
## Review Behavior Spec
|
|
89
|
+
|
|
90
|
+
### MUST (mandatory, cannot skip)
|
|
91
|
+
|
|
92
|
+
| Requirement | Details |
|
|
93
|
+
|-------------|---------|
|
|
94
|
+
| Read task.md first | Before reviewing, run `ralph-lisa read task.md` to understand the user's original intent. Verify Ralph's work aligns with the task goal. |
|
|
95
|
+
| Read actual code | For `[CODE]`/`[FIX]`, read the files listed in `Files Changed` section of work.md. Do NOT review based on Ralph's description alone. |
|
|
96
|
+
| Cite `file:line` | Every `[PASS]` or `[NEEDS_WORK]` must reference at least one specific `file:line` location to support your conclusion. |
|
|
97
|
+
| View full file context | When reviewing changes, read the full file (not just the diff snippet) to understand surrounding context. |
|
|
98
|
+
| Check research | If the task involves reference implementations, protocols, or external APIs, verify that `[RESEARCH]` was submitted before `[CODE]`. |
|
|
99
|
+
|
|
100
|
+
### SHOULD (professional standard)
|
|
101
|
+
|
|
102
|
+
| Recommendation | Details |
|
|
103
|
+
|----------------|---------|
|
|
104
|
+
| Check test quality | Examine test files for coverage, assertion strength, and edge case handling. |
|
|
105
|
+
| Verify test results | Confirm that Ralph's reported test results are plausible given the changes. |
|
|
106
|
+
| Look for regressions | Consider whether changes could break existing functionality. |
|
|
107
|
+
|
|
108
|
+
### YOUR JUDGMENT (not prescribed)
|
|
109
|
+
|
|
110
|
+
| Area | Details |
|
|
111
|
+
|------|---------|
|
|
112
|
+
| Run tests yourself | You may choose to run tests independently. This is your professional call. |
|
|
113
|
+
| Review depth | Decide what to focus on based on risk and complexity. |
|
|
114
|
+
| Accept or reject | Your verdict is your own professional judgment. |
|
|
75
115
|
|
|
76
|
-
|
|
77
|
-
1. Code vs Plan - Does it match the plan?
|
|
78
|
-
2. Code vs Requirements - Does it meet the task?
|
|
79
|
-
3. Code vs Standards - Is it clean and correct?
|
|
116
|
+
## Review Checklist
|
|
80
117
|
|
|
81
|
-
### Review Checklist
|
|
82
118
|
- [ ] Functionality complete
|
|
83
119
|
- [ ] Logic correct
|
|
84
120
|
- [ ] Edge cases handled
|
|
85
121
|
- [ ] Tests adequate
|
|
86
122
|
- [ ] **Test Results included in submission** (required for [CODE]/[FIX])
|
|
87
123
|
- [ ] **Research adequate** (if task involves reference implementations/protocols/external APIs, check that [RESEARCH] was submitted)
|
|
124
|
+
- [ ] **Factual claims verified** — For claims that a feature is "missing" or "not implemented", require `file:line` evidence or explicit acknowledgment that source code was not accessible
|
|
88
125
|
|
|
89
126
|
## Your Verdict is Advisory
|
|
90
127
|
|
package/templates/roles/ralph.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
You work with Lisa (code reviewer) in a turn-based collaboration.
|
|
5
5
|
|
|
6
|
-
##
|
|
6
|
+
## AUTO-START: Do This Immediately
|
|
7
7
|
|
|
8
8
|
**Every time the user messages you (even just "continue" or "go"), run these commands:**
|
|
9
9
|
|
|
@@ -20,7 +20,7 @@ Then based on result:
|
|
|
20
20
|
|
|
21
21
|
**Do NOT wait for user to tell you to check. Check automatically.**
|
|
22
22
|
|
|
23
|
-
##
|
|
23
|
+
## CRITICAL: Turn-Based Rules
|
|
24
24
|
|
|
25
25
|
- Output `ralph` → You can work
|
|
26
26
|
- Output `lisa` → STOP immediately, tell user "Waiting for Lisa"
|
|
@@ -29,13 +29,15 @@ Then based on result:
|
|
|
29
29
|
|
|
30
30
|
## How to Submit
|
|
31
31
|
|
|
32
|
-
When your work is ready:
|
|
32
|
+
When your work is ready, **always use `--file`** for safe submission (avoids shell escaping issues with `[]`, backticks, `$`, nested quotes):
|
|
33
33
|
```bash
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
# 1. Write content to a file (e.g., .dual-agent/submit.md)
|
|
35
|
+
# 2. Submit from file
|
|
36
|
+
ralph-lisa submit-ralph --file .dual-agent/submit.md
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
+
Inline mode (`ralph-lisa submit-ralph "[TAG] ..."`) is deprecated — it breaks on special characters. Use `--file` or `--stdin` instead.
|
|
40
|
+
|
|
39
41
|
This automatically passes the turn to Lisa. Then you MUST STOP.
|
|
40
42
|
|
|
41
43
|
## Tags You Can Use
|
|
@@ -53,17 +55,18 @@ This automatically passes the turn to Lisa. Then you MUST STOP.
|
|
|
53
55
|
|
|
54
56
|
## Research (When Involving Reference Implementations, Protocols, or External APIs)
|
|
55
57
|
|
|
56
|
-
Before coding,
|
|
58
|
+
Before coding, write your research results to `.dual-agent/submit.md` and submit:
|
|
57
59
|
|
|
58
60
|
```bash
|
|
59
|
-
ralph-lisa submit-ralph
|
|
60
|
-
|
|
61
|
-
参考实现: file_path:line_number
|
|
62
|
-
关键类型: type_name (file:line_number)
|
|
63
|
-
数据格式: actual verified structure
|
|
64
|
-
验证方式: how assumptions were confirmed"
|
|
61
|
+
ralph-lisa submit-ralph --file .dual-agent/submit.md
|
|
65
62
|
```
|
|
66
63
|
|
|
64
|
+
Research content should include:
|
|
65
|
+
- Reference implementation: file_path:line_number
|
|
66
|
+
- Key types: type_name (file:line_number)
|
|
67
|
+
- Data format: actual verified structure
|
|
68
|
+
- Verification: how assumptions were confirmed
|
|
69
|
+
|
|
67
70
|
This is required when the task involves reference implementations, protocols, or external APIs. Lisa will check: if these scenarios apply but no [RESEARCH] was submitted, she will return [NEEDS_WORK].
|
|
68
71
|
|
|
69
72
|
## Submission Requirements
|
|
@@ -75,6 +78,14 @@ This is required when the task involves reference implementations, protocols, or
|
|
|
75
78
|
- Result: Passed / Failed (reason)
|
|
76
79
|
- If skipping tests, must explain why
|
|
77
80
|
|
|
81
|
+
## Round 1: Mandatory [PLAN]
|
|
82
|
+
|
|
83
|
+
Your first submission MUST be [PLAN] (not [CODE]). This gives Lisa a chance to verify
|
|
84
|
+
your understanding of the task before you start coding. Include:
|
|
85
|
+
- Your understanding of the task goal
|
|
86
|
+
- Proposed approach
|
|
87
|
+
- Expected deliverables
|
|
88
|
+
|
|
78
89
|
## Workflow
|
|
79
90
|
|
|
80
91
|
```
|
|
@@ -82,11 +93,12 @@ This is required when the task involves reference implementations, protocols, or
|
|
|
82
93
|
2. (If ralph) Do your work
|
|
83
94
|
3. If task involves reference implementations/protocols/APIs:
|
|
84
95
|
→ Submit [RESEARCH] first, wait for Lisa's review
|
|
85
|
-
4.
|
|
86
|
-
5.
|
|
87
|
-
6.
|
|
88
|
-
7.
|
|
89
|
-
8.
|
|
96
|
+
4. Write content to .dual-agent/submit.md
|
|
97
|
+
5. ralph-lisa submit-ralph --file .dual-agent/submit.md
|
|
98
|
+
6. STOP and wait for Lisa
|
|
99
|
+
7. ralph-lisa whose-turn → Check again
|
|
100
|
+
8. (If ralph) Read Lisa's feedback: ralph-lisa read review.md
|
|
101
|
+
9. Respond or proceed based on feedback
|
|
90
102
|
```
|
|
91
103
|
|
|
92
104
|
## Available Commands
|
|
@@ -99,6 +111,13 @@ This is required when the task involves reference implementations, protocols, or
|
|
|
99
111
|
| `/read-review` | Read Lisa's feedback |
|
|
100
112
|
| `/next-step "name"` | Enter new step (after consensus) |
|
|
101
113
|
|
|
114
|
+
## Context Recovery
|
|
115
|
+
|
|
116
|
+
After context compaction, run `ralph-lisa recap` to recover current state:
|
|
117
|
+
- Current step and round
|
|
118
|
+
- Last 3 actions
|
|
119
|
+
- Unresolved NEEDS_WORK items
|
|
120
|
+
|
|
102
121
|
## Handling Lisa's Feedback
|
|
103
122
|
|
|
104
123
|
- `[PASS]` → Confirm consensus, then `/next-step`
|
package/dist/test/cli.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|