@lebronj/pi-suite 0.1.5 → 0.1.7
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 +3 -3
- package/package.json +1 -1
- package/scripts/bootstrap.sh +52 -18
- package/skills/pi-skill/SKILL.md +2 -2
- package/vendor/pi-memory/README.md +2 -2
- package/vendor/pi-memory/src/evolution/config.ts +4 -3
- package/vendor/pi-memory/src/evolution/git.ts +22 -7
- package/vendor/pi-memory/src/evolution/index.ts +1 -1
- package/vendor/pi-memory/src/index.ts +1 -0
- package/vendor/pi-memory/test/evolution.test.ts +13 -1
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ pi install npm:pi-subagents
|
|
|
15
15
|
Or use the bootstrap script to install Pi, configure the team OpenAI-compatible endpoint, install this suite, and set up Bun + qmd for memory search:
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
curl -fsSL https://registry.npmjs.org/@lebronj/pi-suite/-/pi-suite-0.1.
|
|
18
|
+
curl -fsSL https://registry.npmjs.org/@lebronj/pi-suite/-/pi-suite-0.1.7.tgz | tar -xzO package/scripts/bootstrap.sh | bash
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
## What Is Included
|
|
@@ -41,7 +41,7 @@ Debug-only extensions are intentionally excluded:
|
|
|
41
41
|
|
|
42
42
|
## Team Model Setup
|
|
43
43
|
|
|
44
|
-
The bootstrap script asks for an API key and writes:
|
|
44
|
+
The bootstrap script can be run with `curl | bash`: it reads the API key from the terminal instead of stdin. It asks for an API key and writes:
|
|
45
45
|
|
|
46
46
|
- Provider: OpenAI-compatible `openai`
|
|
47
47
|
- Base URL: `https://claude-code.club/openai/v1`
|
|
@@ -79,7 +79,7 @@ Useful commands:
|
|
|
79
79
|
/memory-version-push
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
Memory evolution is local-only by default and does not configure a shared remote. If a user wants backup sync, set `PI_EVOLUTION_REMOTE` to their own private repo before bootstrap/setup, or add a personal remote later with `git -C ~/.pi/agent/evolution remote add origin <url>`. Set `PI_EVOLUTION_AUTO_PUSH=1` only if automatic remote sync is desired.
|
|
83
83
|
|
|
84
84
|
## Goal Mode
|
|
85
85
|
|
package/package.json
CHANGED
package/scripts/bootstrap.sh
CHANGED
|
@@ -10,21 +10,39 @@ if ! command -v npm >/dev/null 2>&1; then
|
|
|
10
10
|
exit 1
|
|
11
11
|
fi
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
fi
|
|
23
|
-
printf "\n" >&2
|
|
13
|
+
prompt_secret() {
|
|
14
|
+
local prompt="$1"
|
|
15
|
+
local var_name="$2"
|
|
16
|
+
local value=""
|
|
17
|
+
local stty_state=""
|
|
18
|
+
|
|
19
|
+
if [ ! -t 0 ] && [ ! -r /dev/tty ]; then
|
|
20
|
+
echo "$prompt is required. Re-run from a terminal or set $var_name in the environment." >&2
|
|
21
|
+
return 1
|
|
22
|
+
fi
|
|
24
23
|
|
|
24
|
+
printf "%s: " "$prompt" >/dev/tty
|
|
25
|
+
if command -v stty >/dev/null 2>&1; then
|
|
26
|
+
stty_state=$(stty -g </dev/tty 2>/dev/null || true)
|
|
27
|
+
stty -echo </dev/tty 2>/dev/null || true
|
|
28
|
+
fi
|
|
29
|
+
IFS= read -r value </dev/tty
|
|
30
|
+
if [ -n "$stty_state" ]; then
|
|
31
|
+
stty "$stty_state" </dev/tty 2>/dev/null || true
|
|
32
|
+
fi
|
|
33
|
+
printf "\n" >/dev/tty
|
|
34
|
+
|
|
35
|
+
if [ -z "$value" ]; then
|
|
36
|
+
echo "$prompt is required." >&2
|
|
37
|
+
return 1
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
printf -v "$var_name" '%s' "$value"
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
TEAM_API_KEY="${TEAM_API_KEY:-}"
|
|
25
44
|
if [ -z "$TEAM_API_KEY" ]; then
|
|
26
|
-
|
|
27
|
-
exit 1
|
|
45
|
+
prompt_secret "OpenAI-compatible API key" TEAM_API_KEY
|
|
28
46
|
fi
|
|
29
47
|
|
|
30
48
|
echo "Installing Pi CLI..."
|
|
@@ -95,7 +113,8 @@ WORKSPACE_DIR="${PI_WORKSPACE_DIR:-$PWD}"
|
|
|
95
113
|
WORKSPACE_PI_DIR="$WORKSPACE_DIR/.pi"
|
|
96
114
|
MEMORY_DIR="$AGENT_DIR/memory"
|
|
97
115
|
EVOLUTION_DIR="${PI_EVOLUTION_DIR:-$AGENT_DIR/evolution}"
|
|
98
|
-
EVOLUTION_REMOTE="${PI_EVOLUTION_REMOTE:-
|
|
116
|
+
EVOLUTION_REMOTE="${PI_EVOLUTION_REMOTE:-}"
|
|
117
|
+
LEGACY_SHARED_EVOLUTION_REMOTE="https://github.com/LRM-Teams/pi-evolution.git"
|
|
99
118
|
EVOLUTION_BRANCH="${PI_EVOLUTION_BRANCH:-main}"
|
|
100
119
|
SUITE_SKILLS_DIR="${PI_SUITE_SKILLS_DIR:-$AGENT_DIR/npm/node_modules/@lebronj/pi-suite/skills}"
|
|
101
120
|
|
|
@@ -122,17 +141,32 @@ setup_evolution_repo() {
|
|
|
122
141
|
fi
|
|
123
142
|
if [ ! -e "$EVOLUTION_DIR" ]; then
|
|
124
143
|
mkdir -p "$(dirname "$EVOLUTION_DIR")"
|
|
125
|
-
if
|
|
144
|
+
if [ -n "$EVOLUTION_REMOTE" ]; then
|
|
145
|
+
if ! git clone --branch "$EVOLUTION_BRANCH" "$EVOLUTION_REMOTE" "$EVOLUTION_DIR"; then
|
|
146
|
+
mkdir -p "$EVOLUTION_DIR"
|
|
147
|
+
git -C "$EVOLUTION_DIR" init -b "$EVOLUTION_BRANCH" 2>/dev/null || git -C "$EVOLUTION_DIR" init
|
|
148
|
+
git -C "$EVOLUTION_DIR" checkout -B "$EVOLUTION_BRANCH" >/dev/null 2>&1 || true
|
|
149
|
+
git -C "$EVOLUTION_DIR" remote add origin "$EVOLUTION_REMOTE" 2>/dev/null || true
|
|
150
|
+
fi
|
|
151
|
+
else
|
|
126
152
|
mkdir -p "$EVOLUTION_DIR"
|
|
127
153
|
git -C "$EVOLUTION_DIR" init -b "$EVOLUTION_BRANCH" 2>/dev/null || git -C "$EVOLUTION_DIR" init
|
|
128
154
|
git -C "$EVOLUTION_DIR" checkout -B "$EVOLUTION_BRANCH" >/dev/null 2>&1 || true
|
|
129
|
-
|
|
155
|
+
fi
|
|
156
|
+
elif [ -z "$EVOLUTION_REMOTE" ]; then
|
|
157
|
+
current_remote=$(git -C "$EVOLUTION_DIR" remote get-url origin 2>/dev/null || true)
|
|
158
|
+
if [ "$current_remote" = "$LEGACY_SHARED_EVOLUTION_REMOTE" ]; then
|
|
159
|
+
git -C "$EVOLUTION_DIR" remote remove origin 2>/dev/null || true
|
|
130
160
|
fi
|
|
131
161
|
fi
|
|
132
162
|
mkdir -p "$EVOLUTION_DIR/memory" "$EVOLUTION_DIR/skill-drafts" "$EVOLUTION_DIR/snapshots" "$EVOLUTION_DIR/manifests"
|
|
133
163
|
echo "Memory evolution repo ready: $EVOLUTION_DIR"
|
|
134
|
-
|
|
135
|
-
|
|
164
|
+
if [ -n "$EVOLUTION_REMOTE" ]; then
|
|
165
|
+
echo "Remote: $EVOLUTION_REMOTE"
|
|
166
|
+
echo "Auto push remains off by default. Use /memory-version-push or PI_EVOLUTION_AUTO_PUSH=1."
|
|
167
|
+
else
|
|
168
|
+
echo "Remote: none (local-only by default). Set PI_EVOLUTION_REMOTE to a personal private repo if you want backup sync."
|
|
169
|
+
fi
|
|
136
170
|
}
|
|
137
171
|
|
|
138
172
|
setup_evolution_repo
|
package/skills/pi-skill/SKILL.md
CHANGED
|
@@ -82,7 +82,7 @@ Memory versioning:
|
|
|
82
82
|
|
|
83
83
|
- Runtime memory remains authoritative at `~/.pi/agent/memory`; disabled skill drafts remain authoritative at `~/.pi/agent/skill-drafts`.
|
|
84
84
|
- Versioning mirror and snapshots live at `~/.pi/agent/evolution` by default.
|
|
85
|
-
-
|
|
85
|
+
- No remote is configured by default; memory evolution stays local per user/machine unless the user adds a personal private remote.
|
|
86
86
|
- Automatic local snapshot + commit is enabled by default; automatic push is disabled unless `PI_EVOLUTION_AUTO_PUSH=1`.
|
|
87
87
|
- Snapshots run before mutating memory tools, curator runs, learning approve/reject, session summaries/handoffs, compact handoffs, restore, and external curator `run-once`.
|
|
88
88
|
- Slash commands: `/memory-version-status`, `/memory-version-snapshot [reason]`, `/memory-version-list`, `/memory-version-restore <snapshot-id> [memory|skill-drafts|all]`, `/memory-version-push`.
|
|
@@ -121,7 +121,7 @@ Useful memory environment variables:
|
|
|
121
121
|
- `PI_MEMORY_CURATOR_STARTUP_HINT=0`: hide the disabled-curator startup hint.
|
|
122
122
|
- `PI_EVOLUTION_ENABLED=0`: disable snapshot + git versioning.
|
|
123
123
|
- `PI_EVOLUTION_DIR`: override evolution repo directory; default `~/.pi/agent/evolution`.
|
|
124
|
-
- `PI_EVOLUTION_REMOTE`:
|
|
124
|
+
- `PI_EVOLUTION_REMOTE`: optional personal private Git remote; unset by default.
|
|
125
125
|
- `PI_EVOLUTION_BRANCH`: override branch; default `main`.
|
|
126
126
|
- `PI_EVOLUTION_AUTO_COMMIT=0`: disable automatic local commits.
|
|
127
127
|
- `PI_EVOLUTION_AUTO_PUSH=1`: push automatically after commits.
|
|
@@ -208,7 +208,7 @@ Tools and slash commands:
|
|
|
208
208
|
|
|
209
209
|
Restore always creates a pre-restore snapshot first, then restores the selected target, syncs the mirror, and commits `memory: restore snapshot <id>`.
|
|
210
210
|
|
|
211
|
-
|
|
211
|
+
No remote is configured by default. This keeps each user's memory evolution local to their machine and avoids writing personal memory into a shared team repo. If remote backup is desired, set `PI_EVOLUTION_REMOTE` to a personal private repo before setup, or add `origin` manually later. Auto commit is on; auto push is off unless `PI_EVOLUTION_AUTO_PUSH=1` is set. Any remote should be private because memory contents are committed in plaintext, including any secret accidentally written to memory.
|
|
212
212
|
|
|
213
213
|
## External Curator Service
|
|
214
214
|
|
|
@@ -249,7 +249,7 @@ The controller uses a systemd user timer when available and falls back to cron.
|
|
|
249
249
|
| `PI_MEMORY_AUTO_APPROVE_SKILL_DRAFTS` | `1`, `true`, `yes`, `on` | unset | YOLO mode for creating newly proposed disabled skill drafts |
|
|
250
250
|
| `PI_EVOLUTION_ENABLED` | `0`, `1`, `true`, `false` | `1` | Enable snapshot + git versioning |
|
|
251
251
|
| `PI_EVOLUTION_DIR` | path | `~/.pi/agent/evolution` | Local evolution repo directory |
|
|
252
|
-
| `PI_EVOLUTION_REMOTE` | URL |
|
|
252
|
+
| `PI_EVOLUTION_REMOTE` | URL | unset | Optional personal private Git remote for manual/optional push |
|
|
253
253
|
| `PI_EVOLUTION_BRANCH` | branch | `main` | Local branch used for init/clone |
|
|
254
254
|
| `PI_EVOLUTION_AUTO_COMMIT` | `0`, `1`, `true`, `false` | `1` | Commit sync/snapshot changes automatically |
|
|
255
255
|
| `PI_EVOLUTION_AUTO_PUSH` | `0`, `1`, `true`, `false` | `0` | Push after commits automatically |
|
|
@@ -5,7 +5,7 @@ export interface EvolutionConfig {
|
|
|
5
5
|
autoCommit: boolean;
|
|
6
6
|
autoPush: boolean;
|
|
7
7
|
repoDir: string;
|
|
8
|
-
remote: string;
|
|
8
|
+
remote: string | null;
|
|
9
9
|
branch: string;
|
|
10
10
|
memoryDir: string;
|
|
11
11
|
skillDraftsDir: string;
|
|
@@ -27,7 +27,8 @@ type EvolutionEnv = Partial<
|
|
|
27
27
|
>
|
|
28
28
|
>;
|
|
29
29
|
|
|
30
|
-
export const DEFAULT_EVOLUTION_REMOTE = "
|
|
30
|
+
export const DEFAULT_EVOLUTION_REMOTE = "";
|
|
31
|
+
export const LEGACY_SHARED_EVOLUTION_REMOTE = "https://github.com/LRM-Teams/pi-evolution.git";
|
|
31
32
|
export const DEFAULT_EVOLUTION_BRANCH = "main";
|
|
32
33
|
|
|
33
34
|
function homeDir(env: EvolutionEnv): string {
|
|
@@ -55,7 +56,7 @@ export function resolveEvolutionConfig(memoryDir: string, env: EvolutionEnv = pr
|
|
|
55
56
|
autoCommit: truthy(env.PI_EVOLUTION_AUTO_COMMIT, true),
|
|
56
57
|
autoPush: truthy(env.PI_EVOLUTION_AUTO_PUSH, false),
|
|
57
58
|
repoDir: path.resolve(expandHome(env.PI_EVOLUTION_DIR || path.join(agentDir, "evolution"), env)),
|
|
58
|
-
remote: env.PI_EVOLUTION_REMOTE ||
|
|
59
|
+
remote: env.PI_EVOLUTION_REMOTE?.trim() || null,
|
|
59
60
|
branch: env.PI_EVOLUTION_BRANCH || DEFAULT_EVOLUTION_BRANCH,
|
|
60
61
|
memoryDir,
|
|
61
62
|
skillDraftsDir: path.join(agentDir, "skill-drafts"),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
-
import type
|
|
4
|
+
import { LEGACY_SHARED_EVOLUTION_REMOTE, type EvolutionConfig } from "./config.ts";
|
|
5
5
|
import { pathExists } from "./file-utils.ts";
|
|
6
6
|
|
|
7
7
|
export interface GitStatus {
|
|
@@ -56,14 +56,21 @@ export function ensureEvolutionRepo(config: EvolutionConfig): void {
|
|
|
56
56
|
}
|
|
57
57
|
if (!pathExists(config.repoDir)) {
|
|
58
58
|
fs.mkdirSync(path.dirname(config.repoDir), { recursive: true });
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
if (config.remote) {
|
|
60
|
+
try {
|
|
61
|
+
execFileSync("git", ["clone", "--branch", config.branch, config.remote, config.repoDir], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
|
|
62
|
+
} catch {
|
|
63
|
+
fs.mkdirSync(config.repoDir, { recursive: true });
|
|
64
|
+
runGit(config.repoDir, ["init", "-b", config.branch], { allowFailure: true });
|
|
65
|
+
if (!isGitRepo(config.repoDir)) runGit(config.repoDir, ["init"]);
|
|
66
|
+
runGit(config.repoDir, ["checkout", "-B", config.branch]);
|
|
67
|
+
runGit(config.repoDir, ["remote", "add", "origin", config.remote], { allowFailure: true });
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
62
70
|
fs.mkdirSync(config.repoDir, { recursive: true });
|
|
63
71
|
runGit(config.repoDir, ["init", "-b", config.branch], { allowFailure: true });
|
|
64
72
|
if (!isGitRepo(config.repoDir)) runGit(config.repoDir, ["init"]);
|
|
65
73
|
runGit(config.repoDir, ["checkout", "-B", config.branch]);
|
|
66
|
-
runGit(config.repoDir, ["remote", "add", "origin", config.remote], { allowFailure: true });
|
|
67
74
|
}
|
|
68
75
|
} else if (!isGitRepo(config.repoDir)) {
|
|
69
76
|
fs.mkdirSync(config.repoDir, { recursive: true });
|
|
@@ -73,8 +80,12 @@ export function ensureEvolutionRepo(config: EvolutionConfig): void {
|
|
|
73
80
|
}
|
|
74
81
|
|
|
75
82
|
const remote = runGit(config.repoDir, ["remote", "get-url", "origin"], { allowFailure: true });
|
|
76
|
-
if (
|
|
77
|
-
|
|
83
|
+
if (config.remote) {
|
|
84
|
+
if (!remote) runGit(config.repoDir, ["remote", "add", "origin", config.remote]);
|
|
85
|
+
else if (remote !== config.remote) runGit(config.repoDir, ["remote", "set-url", "origin", config.remote]);
|
|
86
|
+
} else if (remote === LEGACY_SHARED_EVOLUTION_REMOTE) {
|
|
87
|
+
runGit(config.repoDir, ["remote", "remove", "origin"], { allowFailure: true });
|
|
88
|
+
}
|
|
78
89
|
|
|
79
90
|
const branch = runGit(config.repoDir, ["branch", "--show-current"], { allowFailure: true });
|
|
80
91
|
if (!branch) runGit(config.repoDir, ["checkout", "-B", config.branch]);
|
|
@@ -127,6 +138,10 @@ export function commitEvolutionChanges(config: EvolutionConfig, message: string)
|
|
|
127
138
|
|
|
128
139
|
export function pushEvolution(config: EvolutionConfig): string {
|
|
129
140
|
ensureEvolutionRepo(config);
|
|
141
|
+
const remote = runGit(config.repoDir, ["remote", "get-url", "origin"], { allowFailure: true });
|
|
142
|
+
if (!remote) {
|
|
143
|
+
return "No evolution remote configured. Add a personal private remote with `git -C ~/.pi/agent/evolution remote add origin <url>` or set PI_EVOLUTION_REMOTE before setup.";
|
|
144
|
+
}
|
|
130
145
|
const branch = runGit(config.repoDir, ["branch", "--show-current"], { allowFailure: true }) || config.branch;
|
|
131
146
|
return runGit(config.repoDir, ["push", "-u", "origin", branch]);
|
|
132
147
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { DEFAULT_EVOLUTION_BRANCH, DEFAULT_EVOLUTION_REMOTE, resolveEvolutionConfig, type EvolutionConfig } from "./config.ts";
|
|
1
|
+
export { DEFAULT_EVOLUTION_BRANCH, DEFAULT_EVOLUTION_REMOTE, LEGACY_SHARED_EVOLUTION_REMOTE, resolveEvolutionConfig, type EvolutionConfig } from "./config.ts";
|
|
2
2
|
export { commitEvolutionChanges, ensureEvolutionRepo, getEvolutionGitStatus, pushEvolution, type GitCommitResult, type GitStatus } from "./git.ts";
|
|
3
3
|
export { buildManifest, createSnapshotId, listManifests, readManifest, writeManifest, type EvolutionManifest } from "./manifest.ts";
|
|
4
4
|
export { restoreEvolutionSnapshot, type RestoreResult, type RestoreTarget } from "./restore.ts";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
2
3
|
import { existsSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
4
|
import { tmpdir } from "node:os";
|
|
4
5
|
import { join } from "node:path";
|
|
@@ -6,6 +7,7 @@ import { test } from "node:test";
|
|
|
6
7
|
import {
|
|
7
8
|
createEvolutionSnapshot,
|
|
8
9
|
getEvolutionGitStatus,
|
|
10
|
+
LEGACY_SHARED_EVOLUTION_REMOTE,
|
|
9
11
|
listManifests,
|
|
10
12
|
resolveEvolutionConfig,
|
|
11
13
|
restoreEvolutionSnapshot,
|
|
@@ -24,7 +26,6 @@ function testConfig() {
|
|
|
24
26
|
repoDir,
|
|
25
27
|
config: resolveEvolutionConfig(memoryDir, {
|
|
26
28
|
PI_EVOLUTION_DIR: repoDir,
|
|
27
|
-
PI_EVOLUTION_REMOTE: "https://example.invalid/pi-evolution.git",
|
|
28
29
|
PI_EVOLUTION_AUTO_PUSH: "0",
|
|
29
30
|
HOME: root,
|
|
30
31
|
}),
|
|
@@ -50,6 +51,17 @@ test("creates snapshot, manifest, current mirrors, and git commit", () => {
|
|
|
50
51
|
assert.match(getEvolutionGitStatus(config).lastCommit || "", /memory: test snapshot/);
|
|
51
52
|
});
|
|
52
53
|
|
|
54
|
+
test("local-only config removes the legacy shared team remote", () => {
|
|
55
|
+
const { config, repoDir } = testConfig();
|
|
56
|
+
mkdirSync(repoDir, { recursive: true });
|
|
57
|
+
execFileSync("git", ["init", "-b", "main"], { cwd: repoDir, stdio: "ignore" });
|
|
58
|
+
execFileSync("git", ["remote", "add", "origin", LEGACY_SHARED_EVOLUTION_REMOTE], { cwd: repoDir, stdio: "ignore" });
|
|
59
|
+
|
|
60
|
+
createEvolutionSnapshot(config, { reason: "local migration", trigger: "test", commitMessage: "memory: local migration" });
|
|
61
|
+
|
|
62
|
+
assert.equal(getEvolutionGitStatus(config).remote, null);
|
|
63
|
+
});
|
|
64
|
+
|
|
53
65
|
test("sync does not create empty commits when nothing changed", () => {
|
|
54
66
|
const { memoryDir, config } = testConfig();
|
|
55
67
|
mkdirSync(memoryDir, { recursive: true });
|