hippocamp 0.2.8 → 0.2.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.
|
@@ -106,14 +106,14 @@ jobs:
|
|
|
106
106
|
--target-chars "$HIPPOCAMP_DREAM_TARGET_CHARS" \
|
|
107
107
|
> "/tmp/hippocamp-dream-${project}.json"
|
|
108
108
|
|
|
109
|
-
|
|
109
|
+
git add -- "projects/${project}/current_state.md" "projects/${project}/open_threads.md"
|
|
110
|
+
if git diff --cached --quiet; then
|
|
110
111
|
echo "No Dream diff for ${project}"
|
|
111
112
|
git checkout main
|
|
112
113
|
git reset --hard origin/main
|
|
113
114
|
continue
|
|
114
115
|
fi
|
|
115
116
|
|
|
116
|
-
git add "projects/${project}/current_state.md" "projects/${project}/open_threads.md"
|
|
117
117
|
git commit -m "Dream update ${project} memory"
|
|
118
118
|
git push --force-with-lease origin "$branch"
|
|
119
119
|
|
|
@@ -113,12 +113,12 @@ while IFS= read -r project; do
|
|
|
113
113
|
continue
|
|
114
114
|
fi
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
git add -- "projects/${project}/current_state.md" "projects/${project}/open_threads.md"
|
|
117
|
+
if git diff --cached --quiet; then
|
|
117
118
|
echo "No Dream diff for ${project}"
|
|
118
119
|
continue
|
|
119
120
|
fi
|
|
120
121
|
|
|
121
|
-
git add "projects/${project}/current_state.md" "projects/${project}/open_threads.md"
|
|
122
122
|
git commit -m "Dream update ${project} memory"
|
|
123
123
|
|
|
124
124
|
if git ls-remote --exit-code --heads origin "refs/heads/${branch}" >/dev/null 2>&1; then
|
package/docs/dream.md
CHANGED
|
@@ -17,6 +17,8 @@ Recent events use at most half of the evidence budget. The remaining budget supp
|
|
|
17
17
|
|
|
18
18
|
Dream promotes clear decisions, explicit corrections, and reusable project lessons into `current_state.md`, with source references. It keeps remaining actions in `open_threads.md`, preserves unresolved blockers, and removes completed actions only when evidence supports it. A merged PR does not prove its deployment or follow-up work is done. Uncertain lessons remain in events for normal search.
|
|
19
19
|
|
|
20
|
+
Projects with indexed events can start without curated summaries. Dream creates the two files, and the scheduled runners include these new files in the project's PR.
|
|
21
|
+
|
|
20
22
|
Corrections apply across both files: a shipped feature should not remain an implementation task, while unverified deployment stays open. Extra compaction passes must keep source paths and timestamps for retained knowledge and aim below the size limit to leave room for length estimates. Dream writes the review comment itself; the model does not set review progress.
|
|
21
23
|
|
|
22
24
|
The snapshot may grow within `--target-chars` when new evidence adds useful knowledge. If it exceeds the target, Dream compacts the complete result again. It never crops a wake-up file. After three passes, it fails without writing either file or advancing the event comment if the snapshot still does not fit. A project below the threshold with no new indexed evidence is skipped without a model call.
|
package/package.json
CHANGED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
const assert = require("node:assert/strict");
|
|
2
|
+
const { execFile } = require("node:child_process");
|
|
3
|
+
const fs = require("node:fs/promises");
|
|
4
|
+
const os = require("node:os");
|
|
5
|
+
const path = require("node:path");
|
|
6
|
+
const { promisify } = require("node:util");
|
|
7
|
+
const test = require("node:test");
|
|
8
|
+
const memory = require("../scripts/hippocamp-memory.cjs");
|
|
9
|
+
|
|
10
|
+
const exec = promisify(execFile);
|
|
11
|
+
|
|
12
|
+
test("Dream runner publishes first summaries and skips an unchanged repeat", async (t) => {
|
|
13
|
+
const root = await fs.mkdtemp(path.join(os.tmpdir(), "hippocamp-runner-test-"));
|
|
14
|
+
const seed = path.join(root, "seed");
|
|
15
|
+
const remote = path.join(root, "remote.git");
|
|
16
|
+
const bin = path.join(root, "bin");
|
|
17
|
+
const calls = path.join(root, "prs");
|
|
18
|
+
const preload = path.join(root, "model.cjs");
|
|
19
|
+
const previousRoot = process.env.HIPPOCAMP_GLOBAL_ROOT;
|
|
20
|
+
t.after(async () => {
|
|
21
|
+
if (previousRoot === undefined) delete process.env.HIPPOCAMP_GLOBAL_ROOT;
|
|
22
|
+
else process.env.HIPPOCAMP_GLOBAL_ROOT = previousRoot;
|
|
23
|
+
await fs.rm(root, { recursive: true, force: true });
|
|
24
|
+
});
|
|
25
|
+
await fs.mkdir(seed);
|
|
26
|
+
await fs.mkdir(bin);
|
|
27
|
+
process.env.HIPPOCAMP_GLOBAL_ROOT = seed;
|
|
28
|
+
await memory.appendEvent({ projectRoot: "/tmp/new-project", scope: "project", sync: false, title: "Confirmed decision", keywords: ["constraint"], content: "Keep production access read-only." });
|
|
29
|
+
const env = {
|
|
30
|
+
...process.env,
|
|
31
|
+
PATH: `${bin}${path.delimiter}${process.env.PATH}`,
|
|
32
|
+
GIT_CONFIG_GLOBAL: path.join(root, "gitconfig"),
|
|
33
|
+
GIT_CONFIG_NOSYSTEM: "1",
|
|
34
|
+
GITHUB_TOKEN: "fixture",
|
|
35
|
+
LAGOON_REPOSITORY: "fixture/lagoon",
|
|
36
|
+
MANIFEST_API_KEY: "fixture",
|
|
37
|
+
MANIFEST_BASE_URL: "https://model.invalid",
|
|
38
|
+
HIPPOCAMP_DREAM_AUTO_MERGE: "false",
|
|
39
|
+
NODE_OPTIONS: `--require=${preload}`,
|
|
40
|
+
FIXTURE_REMOTE: remote,
|
|
41
|
+
FIXTURE_CALLS: calls,
|
|
42
|
+
};
|
|
43
|
+
await fs.writeFile(env.GIT_CONFIG_GLOBAL, "[user]\nname = Fixture\nemail = fixture@localhost\n");
|
|
44
|
+
await fs.writeFile(preload, `
|
|
45
|
+
global.fetch = async () => {
|
|
46
|
+
const fs = require("node:fs");
|
|
47
|
+
const path = require("node:path");
|
|
48
|
+
fs.writeFileSync(path.join(process.env.HIPPOCAMP_GLOBAL_ROOT, "unrelated.md"), "Do not publish this file");
|
|
49
|
+
return { ok: true, status: 200, text: async () => JSON.stringify({ output_text: JSON.stringify({
|
|
50
|
+
current_state_md: "# Current State\\n\\n- Keep production access read-only.",
|
|
51
|
+
open_threads_md: "# Open Threads\\n\\n- Verify deployment."
|
|
52
|
+
}) }) };
|
|
53
|
+
};
|
|
54
|
+
`);
|
|
55
|
+
await fs.writeFile(path.join(bin, "gh"), `#!${process.execPath}
|
|
56
|
+
const fs = require("node:fs");
|
|
57
|
+
const { execFileSync } = require("node:child_process");
|
|
58
|
+
const args = process.argv.slice(2);
|
|
59
|
+
if (args[0] === "auth") process.exit(0);
|
|
60
|
+
if (args[0] === "repo" && args[1] === "clone") {
|
|
61
|
+
execFileSync("git", ["clone", process.env.FIXTURE_REMOTE, args[3]], { stdio: "inherit" });
|
|
62
|
+
} else if (args[0] === "pr" && args[1] === "list") {
|
|
63
|
+
if (fs.existsSync(process.env.FIXTURE_CALLS)) console.log("1");
|
|
64
|
+
} else if (args[0] === "pr" && args[1] === "create") {
|
|
65
|
+
fs.appendFileSync(process.env.FIXTURE_CALLS, "created\\n");
|
|
66
|
+
} else {
|
|
67
|
+
throw new Error("Unexpected gh operation: " + args.join(" "));
|
|
68
|
+
}
|
|
69
|
+
`, { mode: 0o755 });
|
|
70
|
+
const git = (args, cwd = seed) => exec("git", args, { cwd, env });
|
|
71
|
+
await git(["init", "-b", "main"]);
|
|
72
|
+
await git(["add", "."]);
|
|
73
|
+
await git(["commit", "-m", "Seed indexed evidence without curated files"]);
|
|
74
|
+
const before = (await git(["rev-parse", "HEAD"])).stdout.trim();
|
|
75
|
+
await git(["clone", "--bare", seed, remote]);
|
|
76
|
+
const runner = path.resolve(__dirname, "../assets/railway/run-dream.sh");
|
|
77
|
+
await exec("bash", [runner], { env });
|
|
78
|
+
const changed = (await git(["diff", "--name-only", before, "refs/heads/dream/new-project"], remote)).stdout.trim().split("\n");
|
|
79
|
+
assert.deepEqual(changed, ["projects/new-project/current_state.md", "projects/new-project/open_threads.md"]);
|
|
80
|
+
assert.match((await git(["show", "dream/new-project:projects/new-project/current_state.md"], remote)).stdout, /hippocamp-dream-through:/);
|
|
81
|
+
assert.equal(await fs.readFile(calls, "utf8"), "created\n");
|
|
82
|
+
// Simulate accepting the reviewed PR, then repeat against the same evidence.
|
|
83
|
+
await git(["update-ref", "refs/heads/main", "refs/heads/dream/new-project"], remote);
|
|
84
|
+
await exec("bash", [runner], { env });
|
|
85
|
+
assert.equal(await fs.readFile(calls, "utf8"), "created\n");
|
|
86
|
+
});
|