psyclaw 0.26.1 → 0.26.3
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 +7 -5
- package/dist/src/adapters/pi/extension.d.ts +1 -1
- package/dist/src/adapters/pi/extension.js +98 -5
- package/dist/src/adapters/pi/extension.js.map +1 -1
- package/dist/src/chat.js +21 -0
- package/dist/src/chat.js.map +1 -1
- package/dist/src/project/jsonl.js +15 -3
- package/dist/src/project/jsonl.js.map +1 -1
- package/dist/src/setup.d.ts +9 -0
- package/dist/src/setup.js +190 -28
- package/dist/src/setup.js.map +1 -1
- package/dist/src/style/cli-ui.js +2 -2
- package/dist/src/style/cli-ui.js.map +1 -1
- package/dist/src/wizard.d.ts +1 -1
- package/dist/src/wizard.js +40 -9
- package/dist/src/wizard.js.map +1 -1
- package/package.json +1 -1
- package/scripts/rebrand-pi.mjs +92 -70
package/scripts/rebrand-pi.mjs
CHANGED
|
@@ -8,13 +8,16 @@
|
|
|
8
8
|
* 3. 3D 侧影电路方块字 (3D Isometric Shadow Block: ██████╗)
|
|
9
9
|
* 4. 学术罗马衬线体 (Academic Roman Serif: ╔══╗)
|
|
10
10
|
*
|
|
11
|
-
*
|
|
11
|
+
* Pets are opt-in via /pet and only render when the terminal is wide enough.
|
|
12
12
|
*/
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
13
|
+
import { execFile } from "node:child_process";
|
|
14
|
+
import { readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
15
|
+
import { randomUUID } from "node:crypto";
|
|
16
|
+
import { basename, dirname, join } from "node:path";
|
|
15
17
|
import { fileURLToPath } from "node:url";
|
|
16
18
|
|
|
17
19
|
const NAME = "PsyClaw";
|
|
20
|
+
const LOCKED_PI_VERSION = "0.84.1";
|
|
18
21
|
// Retain the predecessor Pi profile so existing models, themes, packages, and
|
|
19
22
|
// skills survive the product rename. PsyClaw's project data remains separate.
|
|
20
23
|
const CONFIG_DIR = `.psy${"pi"}`;
|
|
@@ -54,7 +57,6 @@ const AURORA_STOPS = ["#38bdf8", "#60a5fa", "#818cf8", "#a855f7", "#ec4899", "#2
|
|
|
54
57
|
// Colors
|
|
55
58
|
const WHITE = "\\x1b[1m\\x1b[38;2;255;255;255m";
|
|
56
59
|
const GLASSES = "\\x1b[1m\\x1b[38;2;56;189;248m";
|
|
57
|
-
const ZZZ = "\\x1b[38;2;168;85;247m";
|
|
58
60
|
const GOLD = "\\x1b[38;2;251;191;36m";
|
|
59
61
|
const RESET = "\\x1b[0m";
|
|
60
62
|
|
|
@@ -62,37 +64,6 @@ const RESET = "\\x1b[0m";
|
|
|
62
64
|
const PUP_SCHOLAR_TOP = `${WHITE}( ᐡ ${RESET}${GLASSES}⌐■-■${RESET}${WHITE} ᐡ )${RESET} ${GOLD}✨${RESET}`;
|
|
63
65
|
const PUP_SCHOLAR_BOT = `${WHITE}c( づ 📜 づ )${RESET}`;
|
|
64
66
|
|
|
65
|
-
const PUP_SLEEP_TOP = `${ZZZ}z z Z${RESET}`;
|
|
66
|
-
const PUP_SLEEP_BOT = `${WHITE}( ᐡ ${RESET}${GLASSES}⌐■-■${RESET}${WHITE} ᐡ )${RESET} ${ZZZ}💤${RESET}`;
|
|
67
|
-
|
|
68
|
-
const PUP_SCHOLAR_5ROW = [
|
|
69
|
-
` ${WHITE}/ᐢ⑅ᐢ/ ${RESET} ${GOLD}✨${RESET}`,
|
|
70
|
-
` ${WHITE}( ${RESET}${GLASSES}⌐■-■${RESET}${WHITE} )${RESET} `,
|
|
71
|
-
` c${WHITE}(づ 📜 づ${RESET}`,
|
|
72
|
-
` ${WHITE}( " " )${RESET}`,
|
|
73
|
-
` ${WHITE}∪-----∪${RESET} `,
|
|
74
|
-
];
|
|
75
|
-
|
|
76
|
-
const PUP_SLEEPING_5ROW = [
|
|
77
|
-
` ${ZZZ}z z Z${RESET} `,
|
|
78
|
-
` ${WHITE}/ᐢ⑅ᐢ/ ${RESET}${ZZZ}💤${RESET} `,
|
|
79
|
-
` ${WHITE}( ${RESET}${GLASSES}⌐■-■${RESET}${WHITE} )~${RESET} `,
|
|
80
|
-
`${WHITE}c( - ᴥ - )づ${RESET}`,
|
|
81
|
-
` ${WHITE}(______)'${RESET} `,
|
|
82
|
-
];
|
|
83
|
-
|
|
84
|
-
const PUP_SCHOLAR_3ROW = [
|
|
85
|
-
` ${WHITE}/ᐢ⑅ᐢ/ ${RESET} ${GOLD}✨${RESET}`,
|
|
86
|
-
` ${WHITE}( ${RESET}${GLASSES}⌐■-■${RESET}${WHITE} )${RESET} `,
|
|
87
|
-
` c${WHITE}(づ 📜 づ${RESET}`,
|
|
88
|
-
];
|
|
89
|
-
|
|
90
|
-
const PUP_SLEEPING_3ROW = [
|
|
91
|
-
` ${ZZZ}z z Z${RESET} `,
|
|
92
|
-
` ${WHITE}/ᐢ⑅ᐢ/ ${RESET}${ZZZ}💤${RESET} `,
|
|
93
|
-
` ${WHITE}( ${RESET}${GLASSES}⌐■-■${RESET}${WHITE} )~${RESET} `,
|
|
94
|
-
];
|
|
95
|
-
|
|
96
67
|
// 1. 紧凑型对称衬线 I 方块字 (2-Row Compact)
|
|
97
68
|
const FONT_2ROW_ROW0 = "█▀█ █▀▀ █ █ █▀▀ █ █▀█ █ █";
|
|
98
69
|
const FONT_2ROW_ROW1 = "█▀▀ ▄██ █ █▄▄ █▄▄ ▄█▀ █▀█";
|
|
@@ -109,7 +80,13 @@ const FONT_SLANT_CLASSIC = [
|
|
|
109
80
|
];
|
|
110
81
|
|
|
111
82
|
// 3. 3D 侧影电路方块 (3D Isometric Shadow Block - 5-Row)
|
|
112
|
-
const FONT_3D_BLOCK =
|
|
83
|
+
const FONT_3D_BLOCK = [
|
|
84
|
+
" ██████╗ ███████╗██╗ ██╗ ██████╗██╗ █████╗ ██╗ ██╗",
|
|
85
|
+
" ██╔══██╗██╔════╝╚██╗ ██╔╝██╔════╝██║ ██╔══██╗██║ ██║",
|
|
86
|
+
" ██████╔╝███████╗ ╚████╔╝ ██║ ██║ ███████║██║ █╗ ██║",
|
|
87
|
+
" ██╔═══╝ ╚════██║ ╚██╔╝ ██║ ██║ ██╔══██║██║███╗██║",
|
|
88
|
+
" ██║ ███████║ ██║ ╚██████╗███████╗██║ ██║╚███╔███╔╝",
|
|
89
|
+
];
|
|
113
90
|
|
|
114
91
|
// 4. 学术罗马衬线体 (Academic Roman Serif - 3-Row)
|
|
115
92
|
const FONT_SERIF = [
|
|
@@ -129,46 +106,57 @@ function buildCustomVariant(fontLines, dogLines = []) {
|
|
|
129
106
|
return `[\n${rows.join(",\n")}\n ]`;
|
|
130
107
|
}
|
|
131
108
|
|
|
132
|
-
//
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
\` \\x1b[1m${
|
|
109
|
+
// Every default variant is pet-free. Pet variants are selected only when
|
|
110
|
+
// PSYCLAW_PET=1 and the complete row fits the current terminal.
|
|
111
|
+
const VAR_COMPACT = `[
|
|
112
|
+
\` \\x1b[1m${GRAD_2ROW_0}\\x1b[0m \\x1b[38;2;148;163;184mv\${process.env.PSYCLAW_VERSION ?? this.version}\\x1b[0m\`,
|
|
113
|
+
\` \\x1b[1m${GRAD_2ROW_1}\\x1b[0m\`
|
|
136
114
|
]`;
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
\` \\x1b[1m${
|
|
140
|
-
\` \\x1b[1m${GRAD_2ROW_1}\\x1b[0m \\x1b[38;2;148;163;184mEvidence-Grounded Social-Science Research Agent\\x1b[0m ${PUP_SLEEP_BOT}\`
|
|
115
|
+
const VAR_COMPACT_PET = `[
|
|
116
|
+
\` \\x1b[1m${GRAD_2ROW_0}\\x1b[0m ${PUP_SCHOLAR_TOP}\`,
|
|
117
|
+
\` \\x1b[1m${GRAD_2ROW_1}\\x1b[0m ${PUP_SCHOLAR_BOT}\`
|
|
141
118
|
]`;
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
const
|
|
145
|
-
const VAR_3D_BLOCK_SCHOLAR = buildCustomVariant(FONT_3D_BLOCK, PUP_SCHOLAR_5ROW);
|
|
146
|
-
const VAR_3D_BLOCK_SLEEP = buildCustomVariant(FONT_3D_BLOCK, PUP_SLEEPING_5ROW);
|
|
147
|
-
const VAR_SERIF_SCHOLAR = buildCustomVariant(FONT_SERIF, PUP_SCHOLAR_3ROW);
|
|
148
|
-
const VAR_SERIF_SLEEP = buildCustomVariant(FONT_SERIF, PUP_SLEEPING_3ROW);
|
|
149
|
-
const VAR_SLANT_CLASSIC_NARROW = buildCustomVariant(FONT_SLANT_CLASSIC);
|
|
150
|
-
const VAR_SERIF_NARROW = buildCustomVariant(FONT_SERIF);
|
|
151
|
-
|
|
119
|
+
const VAR_SLANT_CLASSIC = buildCustomVariant(FONT_SLANT_CLASSIC);
|
|
120
|
+
const VAR_3D_BLOCK = buildCustomVariant(FONT_3D_BLOCK);
|
|
121
|
+
const VAR_SERIF = buildCustomVariant(FONT_SERIF);
|
|
152
122
|
const GRAD_PIPELINE = "\\x1b[38;2;45;212;191m• Pipeline :\\x1b[0m \\x1b[1m\\x1b[38;2;56;189;248mintake\\x1b[0m \\x1b[38;2;99;102;241m➔\\x1b[0m \\x1b[1m\\x1b[38;2;129;140;248mcapture\\x1b[0m \\x1b[38;2;168;85;247m➔\\x1b[0m \\x1b[1m\\x1b[38;2;168;85;247mcitation-audit\\x1b[0m \\x1b[38;2;236;72;153m➔\\x1b[0m \\x1b[1m\\x1b[38;2;45;212;191mbrief\\x1b[0m";
|
|
153
123
|
const GRAD_PROTOCOL = "\\x1b[38;2;45;212;191m• Protocol :\\x1b[0m \\x1b[1m\\x1b[38;2;52;211;153m✔ 2+ Source Cross-Check\\x1b[0m \\x1b[38;2;100;116;139m·\\x1b[0m \\x1b[1m\\x1b[38;2;45;212;191m✔ SHA-256 Provenance Ledger\\x1b[0m";
|
|
154
124
|
const GRAD_WORKBENCH = "\\x1b[38;2;45;212;191m• Workbench :\\x1b[0m \\x1b[1m\\x1b[38;2;56;189;248mhttp://127.0.0.1:3721\\x1b[0m \\x1b[38;2;168;85;247m(Interactive Panel Active)\\x1b[0m";
|
|
155
125
|
|
|
156
|
-
const PSYCLAW_DYNAMIC_BANNER = `const
|
|
157
|
-
${
|
|
158
|
-
${VAR_SLANT_CLASSIC_SCHOLAR}, ${VAR_SLANT_CLASSIC_SLEEP},
|
|
159
|
-
${VAR_3D_BLOCK_SCHOLAR}, ${VAR_3D_BLOCK_SLEEP},
|
|
160
|
-
${VAR_SERIF_SCHOLAR}, ${VAR_SERIF_SLEEP},
|
|
126
|
+
const PSYCLAW_DYNAMIC_BANNER = `const bannerCandidates = [
|
|
127
|
+
${VAR_COMPACT}, ${VAR_SLANT_CLASSIC}, ${VAR_3D_BLOCK}, ${VAR_SERIF},
|
|
161
128
|
];
|
|
162
|
-
const
|
|
163
|
-
const
|
|
164
|
-
const
|
|
129
|
+
const compactBanner = ${VAR_COMPACT};
|
|
130
|
+
const petBanner = ${VAR_COMPACT_PET};
|
|
131
|
+
const terminalColumns = process.stdout.columns ?? 80;
|
|
132
|
+
const ansiPattern = /\\x1b\\[[0-9;]*m/g;
|
|
133
|
+
const cellWidth = (text) => Array.from(text.replace(ansiPattern, "")).reduce((width, char) => {
|
|
134
|
+
const code = char.codePointAt(0) ?? 0;
|
|
135
|
+
const wide = code >= 0x1100 && (code <= 0x115f || code === 0x2329 || code === 0x232a ||
|
|
136
|
+
(code >= 0x2e80 && code <= 0xa4cf) || (code >= 0xac00 && code <= 0xd7a3) ||
|
|
137
|
+
(code >= 0xf900 && code <= 0xfaff) || (code >= 0xfe10 && code <= 0xfe6f) ||
|
|
138
|
+
(code >= 0xff00 && code <= 0xff60) || (code >= 0x1f300 && code <= 0x1faff));
|
|
139
|
+
return width + (wide ? 2 : 1);
|
|
140
|
+
}, 0);
|
|
141
|
+
const bannerWidth = (rows) => Math.max(...rows.map(cellWidth));
|
|
142
|
+
const fittingBanners = bannerCandidates.filter((rows) => bannerWidth(rows) <= terminalColumns - 4);
|
|
143
|
+
const tinyBanner = [terminalColumns >= 22
|
|
144
|
+
? \` ψ PsyClaw v\${process.env.PSYCLAW_VERSION ?? this.version}\`
|
|
145
|
+
: " PsyClaw"];
|
|
146
|
+
const defaultPool = fittingBanners.length > 0 ? fittingBanners : [tinyBanner];
|
|
147
|
+
const chosenBanner = process.env.PSYCLAW_PET === "1" && bannerWidth(petBanner) <= terminalColumns - 4
|
|
148
|
+
? petBanner
|
|
149
|
+
: defaultPool[Math.floor(Math.random() * defaultPool.length)];
|
|
150
|
+
const detailLines = terminalColumns >= 86 ? [
|
|
151
|
+
\` ${GRAD_PIPELINE}\`,
|
|
152
|
+
\` ${GRAD_PROTOCOL}\`,
|
|
153
|
+
] : [];
|
|
154
|
+
if (terminalColumns >= 76) detailLines.push(\` ${GRAD_WORKBENCH}\`);
|
|
165
155
|
const logo = [
|
|
166
156
|
"",
|
|
167
157
|
...chosenBanner,
|
|
168
158
|
"",
|
|
169
|
-
|
|
170
|
-
\` ${GRAD_PROTOCOL}\`,
|
|
171
|
-
\` ${GRAD_WORKBENCH}\`,
|
|
159
|
+
...detailLines,
|
|
172
160
|
"",
|
|
173
161
|
].join("\\n");`;
|
|
174
162
|
|
|
@@ -230,6 +218,9 @@ const MODE_PATCHES = [
|
|
|
230
218
|
|
|
231
219
|
async function patchPackageJson(pkgPath) {
|
|
232
220
|
const pkg = JSON.parse(await readFile(pkgPath, "utf8"));
|
|
221
|
+
if (pkg.version !== LOCKED_PI_VERSION) {
|
|
222
|
+
throw new Error(`Unsupported Pi runtime ${String(pkg.version)}; expected ${LOCKED_PI_VERSION}`);
|
|
223
|
+
}
|
|
233
224
|
const existing = pkg.piConfig && typeof pkg.piConfig === "object" && !Array.isArray(pkg.piConfig)
|
|
234
225
|
? pkg.piConfig
|
|
235
226
|
: {};
|
|
@@ -237,20 +228,51 @@ async function patchPackageJson(pkgPath) {
|
|
|
237
228
|
return { applied: false };
|
|
238
229
|
}
|
|
239
230
|
pkg.piConfig = { ...existing, name: NAME, configDir: CONFIG_DIR };
|
|
240
|
-
await
|
|
231
|
+
await atomicReplace(pkgPath, `${JSON.stringify(pkg, null, "\t")}\n`);
|
|
241
232
|
return { applied: true };
|
|
242
233
|
}
|
|
243
234
|
|
|
235
|
+
async function atomicReplace(path, content, checkJavaScript = false) {
|
|
236
|
+
const suffix = `${process.pid}.${randomUUID()}`;
|
|
237
|
+
const temporary = join(dirname(path), `.${basename(path)}.${suffix}.tmp${checkJavaScript ? ".mjs" : ""}`);
|
|
238
|
+
const backup = join(dirname(path), `.${basename(path)}.${suffix}.bak`);
|
|
239
|
+
let backedUp = false;
|
|
240
|
+
await writeFile(temporary, content, { encoding: "utf8", flag: "wx" });
|
|
241
|
+
try {
|
|
242
|
+
if (checkJavaScript) {
|
|
243
|
+
await new Promise((resolve, reject) => {
|
|
244
|
+
execFile(process.execPath, ["--check", temporary], { windowsHide: true }, (error) => error ? reject(error) : resolve());
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
try { await rename(temporary, path); }
|
|
248
|
+
catch (error) {
|
|
249
|
+
if (!new Set(["EEXIST", "EPERM", "EACCES"]).has(error?.code)) throw error;
|
|
250
|
+
await rename(path, backup);
|
|
251
|
+
backedUp = true;
|
|
252
|
+
try { await rename(temporary, path); }
|
|
253
|
+
catch (replaceError) {
|
|
254
|
+
await rename(backup, path).catch(() => undefined);
|
|
255
|
+
throw replaceError;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
} finally {
|
|
259
|
+
await rm(temporary, { force: true }).catch(() => undefined);
|
|
260
|
+
if (backedUp) await rm(backup, { force: true }).catch(() => undefined);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
244
264
|
async function applyModePatches(modePath) {
|
|
245
265
|
let content = await readFile(modePath, "utf8");
|
|
246
266
|
const applied = [];
|
|
247
267
|
|
|
248
268
|
// Replace the entire generated block. The greedy range also repairs a module
|
|
249
269
|
// that a previous build appended to, instead of declaring the banner twice.
|
|
250
|
-
const dynamicBannerRegex = /(?:const (?:wideBannerVariants|BANNER_VARIANTS)[\s\S]
|
|
251
|
-
const
|
|
270
|
+
const dynamicBannerRegex = /(?:const (?:bannerCandidates|wideBannerVariants|BANNER_VARIANTS)[\s\S]*?const logo = \[[\s\S]*?\]\.join\("\\n"\);|const logo = (?:`[\s\S]*?`|\[[\s\S]*?\]\.join\("\\n"\)|theme\.bold[^;]*);)/g;
|
|
271
|
+
const matches = [...content.matchAll(dynamicBannerRegex)];
|
|
272
|
+
if (matches.length !== 1) throw new Error(`Expected exactly one Pi startup banner, found ${matches.length}`);
|
|
273
|
+
const currentMatch = matches[0];
|
|
252
274
|
if (currentMatch && currentMatch[0] !== PSYCLAW_DYNAMIC_BANNER) {
|
|
253
|
-
content = content.
|
|
275
|
+
content = `${content.slice(0, currentMatch.index)}${PSYCLAW_DYNAMIC_BANNER}${content.slice(currentMatch.index + currentMatch[0].length)}`;
|
|
254
276
|
applied.push("const logo = ... [Updated Curated 4-Style psyclaw Banner Rotation Pool]");
|
|
255
277
|
}
|
|
256
278
|
|
|
@@ -262,7 +284,7 @@ async function applyModePatches(modePath) {
|
|
|
262
284
|
}
|
|
263
285
|
}
|
|
264
286
|
if (applied.length > 0) {
|
|
265
|
-
await
|
|
287
|
+
await atomicReplace(modePath, content, true);
|
|
266
288
|
}
|
|
267
289
|
return applied;
|
|
268
290
|
}
|