@astrosheep/pi-context 0.23.0 → 0.23.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/src/dream/cli.js +1 -1
- package/dist/test/dream.test.js +23 -3
- package/package.json +1 -1
- package/playbook.md +2 -2
- package/src/dream/cli.ts +1 -1
package/dist/src/dream/cli.js
CHANGED
|
@@ -17,7 +17,7 @@ function args(argv) { const out = {}; for (let i = 0; i < argv.length; i++) {
|
|
|
17
17
|
out[a.slice(2)] = argv[++i] ?? "";
|
|
18
18
|
} return out; }
|
|
19
19
|
function packageRoot() {
|
|
20
|
-
let dir = dirname(
|
|
20
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
21
21
|
while (true) {
|
|
22
22
|
if (existsSync(join(dir, "package.json")))
|
|
23
23
|
return dir;
|
package/dist/test/dream.test.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import test from "node:test";
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
|
-
import { execFile, execFileSync } from "node:child_process";
|
|
4
|
-
import { existsSync, linkSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, symlinkSync, unlinkSync, utimesSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { execFile, execFileSync, spawnSync } from "node:child_process";
|
|
4
|
+
import { cpSync, existsSync, linkSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, symlinkSync, unlinkSync, utimesSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { mkdtempSync } from "node:fs";
|
|
6
6
|
import { tmpdir } from "node:os";
|
|
7
7
|
import { join } from "node:path";
|
|
@@ -225,14 +225,34 @@ test("dreamer session has exactly the jailed file-tool allowlist", async () => {
|
|
|
225
225
|
session.dispose();
|
|
226
226
|
}
|
|
227
227
|
});
|
|
228
|
-
test("playbook describes plain files and the
|
|
228
|
+
test("playbook describes plain files, retained frontmatter, and the read-only session WAL", () => {
|
|
229
229
|
const playbook = readFileSync(join(process.cwd(), "playbook.md"), "utf8");
|
|
230
230
|
assert.equal(playbook.includes("notes_"), false);
|
|
231
231
|
for (const field of ["origin", "status", "stale", "created_at", "updated_at", "last_accessed", "access_count"])
|
|
232
232
|
assert.match(playbook, new RegExp(`^${field}:`, "m"));
|
|
233
233
|
assert.equal(/^scope:/m.test(playbook), false, "scope is derived from the address rather than persisted");
|
|
234
|
+
assert.match(playbook, /`pi\/session\/\*\*` is a live agent's write-ahead log/);
|
|
235
|
+
assert.match(playbook, /never write or edit anything there/);
|
|
236
|
+
assert.match(playbook, /Session notes remain untouched even when promoted/);
|
|
234
237
|
assert.match(playbook, /Nothing is physically deleted/);
|
|
235
238
|
});
|
|
239
|
+
test("CLI finds its package root when the installed file URL contains spaces", () => {
|
|
240
|
+
const install = mkdtempSync(join(tmpdir(), "dream install "));
|
|
241
|
+
const home = fixture();
|
|
242
|
+
try {
|
|
243
|
+
cpSync(join(process.cwd(), "dist/src"), join(install, "dist/src"), { recursive: true });
|
|
244
|
+
symlinkSync(join(process.cwd(), "node_modules"), join(install, "node_modules"), process.platform === "win32" ? "junction" : "dir");
|
|
245
|
+
cpSync(join(process.cwd(), "playbook.md"), join(install, "playbook.md"));
|
|
246
|
+
writeFileSync(join(install, "package.json"), JSON.stringify({ type: "module" }));
|
|
247
|
+
const result = spawnSync(process.execPath, [join(install, "dist/src/dream/cli.js"), "--notes-home", home, "--force", "--dreamer", "definitely-not-a-real-model"], { encoding: "utf8" });
|
|
248
|
+
assert.equal(result.status, 1, result.stderr);
|
|
249
|
+
assert.doesNotMatch(result.stderr, /could not locate installed package root/);
|
|
250
|
+
assert.match(result.stderr, /definitely-not-a-real-model/);
|
|
251
|
+
}
|
|
252
|
+
finally {
|
|
253
|
+
rmSync(install, { recursive: true, force: true });
|
|
254
|
+
}
|
|
255
|
+
});
|
|
236
256
|
test("provider errors are reported with partial writes instead of parsing a response", async () => {
|
|
237
257
|
const factory = scriptedSession((handler) => {
|
|
238
258
|
handler({ type: "tool_execution_start", toolName: "write", args: { path: "global/partial.md", content: "half" } });
|
package/package.json
CHANGED
package/playbook.md
CHANGED
|
@@ -24,9 +24,9 @@ access_count: 0
|
|
|
24
24
|
2. **Merge threshold.** Supersede another note only when all three hold: same topic (name it in the survivor's body), same kind of note (checkpoint/design/log…), and the survivor is strictly newer or strictly more specific. Otherwise keep both and record the open conflict in the survivor.
|
|
25
25
|
3. **Size budget.** Keep every note under ~200 lines / ~8KB. Oversized notes get split by topic with a one-line cross-link in each (`see also: @home/<vpath>`). Checkpoints may exceed the budget — trim prose, never facts.
|
|
26
26
|
4. **Keep the maps.** Each home's `MAP.md` maps that home's durable notes: one line per entry — its address and a short gist in your own words, never a mechanical body slice. Project notes go on `@project/MAP.md`, cross-project knowledge on `@personal/MAP.md`; session notes are never mapped — the pocket covers them. When a note is promoted across homes, move its line to the destination map; when a note goes stale, drop its line. Maps obey the same size budget as any note.
|
|
27
|
-
5. **Jurisdiction.**
|
|
27
|
+
5. **Jurisdiction.** Read the whole store, including every session home, to extract durable knowledge. `pi/session/**` is a live agent's write-ahead log: never write or edit anything there, including frontmatter or stale markers. Promote useful facts by writing to project or personal instead. Other notes are never physically deleted and every run is bracketed by git commits, so the human gate can audit and revert whatever you touch. Group your report by home so the gate can see what moved. In writable homes: map entry lines are yours to maintain, but prose that carries rules or guidance is not — flag it in your report instead of rewriting it.
|
|
28
28
|
6. **Leave stable notes alone.** Change notes to incorporate new evidence, resolve verified errors, merge genuine duplicates, or split oversized files—not merely to shorten or rephrase them. Preserve facts, conditions, exceptions, and uncertainty. No change is a valid outcome.
|
|
29
29
|
|
|
30
|
-
Read the files and merge genuinely duplicate notes by editing the survivor, then set `stale: true` in the absorbed note's frontmatter. Nothing is physically deleted; stale notes remain readable. Promote durable cross-project knowledge by writing or editing at `@personal/<vpath>`. Keep notes compact and preserve useful provenance in the body.
|
|
30
|
+
Read the files and merge genuinely duplicate notes in writable homes by editing the survivor, then set `stale: true` in the absorbed note's frontmatter if it is writable. Session notes remain untouched even when promoted; record their source in the destination. Nothing is physically deleted; stale notes remain readable. Promote durable cross-project knowledge by writing or editing at `@personal/<vpath>`. Keep notes compact and preserve useful provenance in the body.
|
|
31
31
|
|
|
32
32
|
Do not write skill ideas as files. Put skill ideas and unresolved questions in your final assistant message as proposals for the human. Your final message should be a concise report of what you inspected, changed, and left unresolved. If you made no file writes, say so.
|
package/src/dream/cli.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { notesRoot } from "../notes/paths.js";
|
|
|
12
12
|
|
|
13
13
|
function args(argv: string[]) { const out: Record<string, string | boolean> = {}; for (let i=0;i<argv.length;i++) { const a=argv[i]!; if (a === "--force" || a === "--help") out[a.slice(2)] = true; else if (a.startsWith("--")) out[a.slice(2)] = argv[++i] ?? ""; } return out; }
|
|
14
14
|
function packageRoot(): string {
|
|
15
|
-
let dir = dirname(
|
|
15
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
16
16
|
while (true) { if (existsSync(join(dir, "package.json"))) return dir; const parent = dirname(dir); if (parent === dir) throw new Error("could not locate installed package root"); dir = parent; }
|
|
17
17
|
}
|
|
18
18
|
|