@lebronj/pi-suite 0.1.16 → 0.1.18
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 +13 -4
- package/extensions/goal-mode.ts +261 -33
- package/package.json +1 -1
- package/skills/pi-skill/SKILL.md +32 -7
- package/vendor/pi-memory/README.md +87 -56
- package/vendor/pi-memory/index.ts +522 -310
- package/vendor/pi-memory/package.json +1 -1
- package/vendor/pi-memory/src/cli.ts +56 -32
- package/vendor/pi-memory/src/evolution/config.ts +8 -2
- package/vendor/pi-memory/src/governance/share-candidates.ts +72 -0
- package/vendor/pi-memory/src/index.ts +68 -25
- package/vendor/pi-memory/src/learning/review-compact.ts +36 -0
- package/vendor/pi-memory/src/learning/review-summary.ts +81 -0
- package/vendor/pi-memory/src/manager/local-curator-manager.ts +146 -0
- package/vendor/pi-memory/src/paths/resolve-roots.ts +155 -0
- package/vendor/pi-memory/src/profile/generator.ts +45 -0
- package/vendor/pi-memory/src/service-controller.ts +156 -84
- package/vendor/pi-memory/src/skills/lifecycle.ts +205 -0
- package/vendor/pi-memory/src/sync/connector.ts +146 -0
- package/vendor/pi-memory/src/sync/downflow.ts +54 -0
- package/vendor/pi-memory/src/sync/feedback.ts +30 -0
- package/vendor/pi-memory/src/sync/queue.ts +40 -0
- package/vendor/pi-memory/src/sync/schemas.ts +44 -0
- package/vendor/pi-memory/src/sync/sensitivity.ts +18 -0
- package/vendor/pi-memory/test/manager-service.test.ts +17 -0
- package/vendor/pi-memory/test/resolve-roots.test.ts +63 -0
- package/vendor/pi-memory/test/review-summary.test.ts +36 -0
- package/vendor/pi-memory/test/skill-lifecycle.test.ts +75 -0
- package/vendor/pi-memory/test/sync-local-loop.test.ts +101 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { test } from "node:test";
|
|
6
|
+
import {
|
|
7
|
+
disableMemorySkill,
|
|
8
|
+
enableMemorySkill,
|
|
9
|
+
ensureAgentRoot,
|
|
10
|
+
formatEnabledSkillsForPrompt,
|
|
11
|
+
listMemorySkills,
|
|
12
|
+
receiveDelivery,
|
|
13
|
+
} from "../src/index.ts";
|
|
14
|
+
|
|
15
|
+
function agentEnv() {
|
|
16
|
+
const root = mkdtempSync(join(tmpdir(), "pi-memory-skill-life-"));
|
|
17
|
+
const agentRoot = join(root, "workspace_1", ".pi", "agents", "agent_a");
|
|
18
|
+
const env = {
|
|
19
|
+
HOME: root,
|
|
20
|
+
PI_AGENT_ROOT: agentRoot,
|
|
21
|
+
MULTICA_WORKSPACE_ID: "workspace_1",
|
|
22
|
+
MULTICA_AGENT_ID: "agent_a",
|
|
23
|
+
};
|
|
24
|
+
ensureAgentRoot(env);
|
|
25
|
+
return { root, agentRoot, env };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function writeSkill(path: string, name: string) {
|
|
29
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
30
|
+
writeFileSync(path, `---\nname: ${name}\ndescription: Use ${name}.\n---\n# ${name}\n`, "utf-8");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
test("enables and disables a draft skill without deleting the draft", () => {
|
|
34
|
+
const { agentRoot, env } = agentEnv();
|
|
35
|
+
const draftDir = join(agentRoot, "skills", "drafts", "draft-one");
|
|
36
|
+
writeSkill(join(draftDir, "SKILL.md"), "draft-one");
|
|
37
|
+
|
|
38
|
+
let skills = listMemorySkills(env);
|
|
39
|
+
assert.equal(skills.drafts.length, 1);
|
|
40
|
+
assert.equal(skills.enabled.length, 0);
|
|
41
|
+
|
|
42
|
+
const enabled = enableMemorySkill("draft:draft-one", { env });
|
|
43
|
+
assert.equal(enabled.enabled.name, "draft-one");
|
|
44
|
+
assert.equal(existsSync(join(agentRoot, "skills", "enabled", "draft-one", "SKILL.md")), true);
|
|
45
|
+
assert.equal(existsSync(join(agentRoot, "skills", "drafts", "draft-one", "SKILL.md")), true);
|
|
46
|
+
assert.match(readFileSync(join(agentRoot, "memory", "audit", "skill-lifecycle.jsonl"), "utf-8"), /"action":"enable"/);
|
|
47
|
+
|
|
48
|
+
const prompt = formatEnabledSkillsForPrompt(env);
|
|
49
|
+
assert.match(prompt, /<available_skills>/);
|
|
50
|
+
assert.match(prompt, /draft-one/);
|
|
51
|
+
assert.match(prompt, /skills\/enabled\/draft-one\/SKILL.md/);
|
|
52
|
+
|
|
53
|
+
const disabled = disableMemorySkill("draft-one", env);
|
|
54
|
+
assert.equal(disabled.removed, true);
|
|
55
|
+
skills = listMemorySkills(env);
|
|
56
|
+
assert.equal(skills.enabled.length, 0);
|
|
57
|
+
assert.equal(skills.drafts.length, 1);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("enables a generated skill delivery by generated id", () => {
|
|
61
|
+
const { agentRoot, env } = agentEnv();
|
|
62
|
+
receiveDelivery({
|
|
63
|
+
id: "delivery_1",
|
|
64
|
+
shared_unit_id: "unit_skill_1",
|
|
65
|
+
unit_type: "skill",
|
|
66
|
+
content: "---\nname: shared-demo\ndescription: Use for tests.\n---\n# Shared Demo\n",
|
|
67
|
+
}, env);
|
|
68
|
+
|
|
69
|
+
const enabled = enableMemorySkill("generated:unit_skill_1", { env });
|
|
70
|
+
assert.equal(enabled.source.kind, "generated");
|
|
71
|
+
assert.equal(enabled.enabled.name, "shared-demo");
|
|
72
|
+
assert.equal(existsSync(join(agentRoot, "skills", "enabled", "shared-demo", ".pi-skill-enabled.json")), true);
|
|
73
|
+
const manifest = readFileSync(join(agentRoot, "skills", "enabled", "shared-demo", ".pi-skill-enabled.json"), "utf-8");
|
|
74
|
+
assert.match(manifest, /generated:unit_skill_1/);
|
|
75
|
+
});
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { existsSync, mkdtempSync, readFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { test } from "node:test";
|
|
6
|
+
import {
|
|
7
|
+
appendEvolutionCandidate,
|
|
8
|
+
appendFeedbackEvent,
|
|
9
|
+
buildFeedbackEvent,
|
|
10
|
+
compactProcessedReviewEntries,
|
|
11
|
+
ensureAgentRoot,
|
|
12
|
+
receiveDelivery,
|
|
13
|
+
} from "../src/index.ts";
|
|
14
|
+
|
|
15
|
+
function agentEnv() {
|
|
16
|
+
const root = mkdtempSync(join(tmpdir(), "pi-memory-loop-"));
|
|
17
|
+
const agentRoot = join(root, "workspace_1", ".pi", "agents", "agent_a");
|
|
18
|
+
const env = {
|
|
19
|
+
HOME: root,
|
|
20
|
+
PI_AGENT_ROOT: agentRoot,
|
|
21
|
+
MULTICA_WORKSPACE_ID: "workspace_1",
|
|
22
|
+
MULTICA_AGENT_ID: "agent_a",
|
|
23
|
+
MULTICA_RUN_ID: "run_1",
|
|
24
|
+
};
|
|
25
|
+
ensureAgentRoot(env);
|
|
26
|
+
return { root, agentRoot, env };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
test("sync queue writes share candidates and blocks secret-like payloads", () => {
|
|
30
|
+
const { agentRoot, env } = agentEnv();
|
|
31
|
+
const result = appendEvolutionCandidate({
|
|
32
|
+
type: "memory",
|
|
33
|
+
content: "Prefer LSP rename for cross-file refactors.",
|
|
34
|
+
tags: ["coding", "lsp"],
|
|
35
|
+
source: "local_curator",
|
|
36
|
+
suggested_scope: "workspace",
|
|
37
|
+
status: "candidate",
|
|
38
|
+
}, env);
|
|
39
|
+
assert.equal(result.appended, true);
|
|
40
|
+
assert.equal(existsSync(join(agentRoot, "sync_queue", "memory-candidates.jsonl")), true);
|
|
41
|
+
assert.throws(() => appendEvolutionCandidate({
|
|
42
|
+
type: "memory",
|
|
43
|
+
content: "api_key=sk_test_secret_should_not_upload_123456789",
|
|
44
|
+
tags: ["secret"],
|
|
45
|
+
source: "local_curator",
|
|
46
|
+
suggested_scope: "workspace",
|
|
47
|
+
status: "candidate",
|
|
48
|
+
}, env), /secret-like content/);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("downflow receive writes only inbox/cache/generated locations", () => {
|
|
52
|
+
const { agentRoot, env } = agentEnv();
|
|
53
|
+
const memoryResult = receiveDelivery({
|
|
54
|
+
id: "delivery_1",
|
|
55
|
+
shared_unit_id: "unit_memory_1",
|
|
56
|
+
unit_type: "memory",
|
|
57
|
+
content: "Shared memory that matches coding tasks.",
|
|
58
|
+
tags: ["coding"],
|
|
59
|
+
}, env);
|
|
60
|
+
assert.equal(memoryResult.accepted, true);
|
|
61
|
+
assert.equal(existsSync(join(agentRoot, "inbox", "memory", "unit_memory_1.json")), true);
|
|
62
|
+
assert.equal(existsSync(join(agentRoot, "shared-cache", "memory", "unit_memory_1.json")), true);
|
|
63
|
+
assert.equal(readFileSync(join(agentRoot, "memory", "MEMORY.md"), "utf-8"), "");
|
|
64
|
+
|
|
65
|
+
const skillResult = receiveDelivery({
|
|
66
|
+
id: "delivery_2",
|
|
67
|
+
shared_unit_id: "unit_skill_1",
|
|
68
|
+
unit_type: "skill",
|
|
69
|
+
content: "---\nname: shared-demo\ndescription: Use for tests.\n---\n# Shared Demo\n",
|
|
70
|
+
}, env);
|
|
71
|
+
assert.equal(skillResult.accepted, true);
|
|
72
|
+
assert.equal(existsSync(join(agentRoot, "inbox", "skills", "unit_skill_1", "SKILL.md")), true);
|
|
73
|
+
assert.equal(existsSync(join(agentRoot, "skills", "generated", "unit_skill_1", "SKILL.md")), true);
|
|
74
|
+
assert.equal(existsSync(join(agentRoot, "skills", "enabled", "unit_skill_1", "SKILL.md")), false);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("feedback queue appends scoped feedback events", () => {
|
|
78
|
+
const { agentRoot, env } = agentEnv();
|
|
79
|
+
const event = buildFeedbackEvent({
|
|
80
|
+
shared_unit_id: "unit_memory_1",
|
|
81
|
+
unit_type: "memory",
|
|
82
|
+
event: "used",
|
|
83
|
+
outcome: "success",
|
|
84
|
+
}, env);
|
|
85
|
+
appendFeedbackEvent(event, env);
|
|
86
|
+
const feedback = readFileSync(join(agentRoot, "feedback", "feedback.jsonl"), "utf-8");
|
|
87
|
+
assert.match(feedback, /"workspace_id":"workspace_1"/);
|
|
88
|
+
assert.match(feedback, /"agent_id":"agent_a"/);
|
|
89
|
+
assert.match(feedback, /"run_id":"run_1"/);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("review compact removes old processed entries but keeps pending proposals", () => {
|
|
93
|
+
const review = [
|
|
94
|
+
`[type:review status:approved id:mem_old kind:memory_promotion approved_at:2026-01-01T00:00:00.000Z]\nOld approved`,
|
|
95
|
+
`[type:review status:proposed id:mem_pending kind:memory_promotion]\nPending`,
|
|
96
|
+
].join("\n§\n");
|
|
97
|
+
const result = compactProcessedReviewEntries(review, { now: new Date("2026-03-01T00:00:00.000Z"), compactDays: 30 });
|
|
98
|
+
assert.equal(result.removed, 1);
|
|
99
|
+
assert.equal(result.activeEntries.length, 1);
|
|
100
|
+
assert.match(result.activeEntries[0], /mem_pending/);
|
|
101
|
+
});
|