mirror of
https://github.com/luckyyzh/pi-agent-integrated.git
synced 2026-10-03 02:59:35 +00:00
fix: make qmd memory search opt-in (#6)
Co-authored-by: luckyyzh <luckyyzh@users.noreply.github.com>
This commit is contained in:
@@ -13,6 +13,12 @@ ANTHROPIC_API_KEY=
|
||||
OPENAI_API_KEY=
|
||||
GEMINI_API_KEY=
|
||||
|
||||
# pi-memory runs in lightweight Markdown-only mode by default. This keeps
|
||||
# durable facts, daily logs, scratchpad, and recovery without qmd/model downloads.
|
||||
# Set both values below only after installing and configuring qmd yourself.
|
||||
# PI_MEMORY_NO_SEARCH=0
|
||||
# PI_MEMORY_QMD_UPDATE=background
|
||||
|
||||
# Optional: move mutable runtime data while retaining the same isolation model.
|
||||
# PI_AGENT_DATA_DIR=D:\path\to\pi-agent-data
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ data/workspaces/default/ 默认工作目录
|
||||
| `pi-mcp-adapter@2.15.0` | 用一个紧凑代理工具接入 MCP | 模型使用 `mcp` 搜索并调用 MCP;`/mcp` 查看状态。外部宿主配置发现默认关闭 |
|
||||
| `@playwright/mcp@0.0.78` | 真实网页导航、点击、表单、快照和截图 | 通过 MCP 按需启动,空闲 5 分钟退出;使用无痕 Headless 系统 Edge |
|
||||
| `pi-lens@3.8.73` | LSP、AST、符号检索和项目诊断 | 模型按需激活代码智能工具;可用 `/lens-health`、`/lens-tools`、`/lens-map` 检查 |
|
||||
| `pi-memory@0.4.0` | Markdown 长期记忆、日志、临时工作区和恢复记录 | 模型按需使用 memory 工具;文件位于 `data/agent/memory/`,默认不启用向量索引 |
|
||||
| `pi-memory@0.4.0` | Markdown 长期记忆、日志、临时工作区和恢复记录 | 默认轻量模式保留读写、状态和恢复工具,但不注册依赖 qmd 的 `memory_search`;文件位于 `data/agent/memory/` |
|
||||
| `pi-subagents@0.37.2` | 创建研究、规划或执行子代理 | 简单任务不委派,跨模块或可并行复杂任务自动判断;也可使用 `/run`、`/parallel` |
|
||||
| `pi-smart-fetch@0.3.17` | 抓取单个或批量 URL 内容 | 模型按需使用 `web_fetch` / `batch_web_fetch`,也提供给研究子代理 |
|
||||
| `@ayulab/pi-rewind@0.4.6` | 每轮前后创建代码检查点 | `/rewind` 恢复代码、会话或两者;`/checkpoint` 管理存储。自动恢复文件默认关闭 |
|
||||
@@ -127,6 +127,19 @@ data/workspaces/default/ 默认工作目录
|
||||
|
||||
Playwright 不下载独立 Chromium。首次 `setup` 只缓存 MCP 的 Node.js 包;浏览器执行使用系统 Edge。
|
||||
|
||||
#### 记忆模式
|
||||
|
||||
默认设置 `PI_MEMORY_NO_SEARCH=1` 和 `PI_MEMORY_QMD_UPDATE=off`。这不会削弱 Markdown 记忆、每日日志、scratchpad 或恢复记录,但会跳过 qmd 探测、安装提示和 `memory_search` 工具,因此全新安装不会自动下载 qmd 的本地模型。集成补丁会在 `setup` 以及每次启动前自动检查并重放,受管插件重装后无需手工修改。
|
||||
|
||||
如果确实需要跨全部记忆文件的关键词、语义或深度搜索,请先自行安装并配置 qmd,然后在 `.env` 中设置:
|
||||
|
||||
```dotenv
|
||||
PI_MEMORY_NO_SEARCH=0
|
||||
PI_MEMORY_QMD_UPDATE=background
|
||||
```
|
||||
|
||||
随后运行 `npm run memory:configure` 或直接重启应用。qmd 及其模型不随本仓库分发。
|
||||
|
||||
### Profile、迁移和自定义扩展
|
||||
|
||||
只创建缺失的项目 Profile 文件:
|
||||
@@ -151,6 +164,7 @@ npm run profile:migrate -- --from D:\old-pi\agent --skills-from D:\old-skills
|
||||
```powershell
|
||||
npm run setup # 完整安装、构建和 Profile 插件校验
|
||||
npm run profile:packages # 安装缺失或版本不匹配的受管插件
|
||||
npm run memory:configure # 重新应用受管 pi-memory 轻量集成
|
||||
npm run dev # 127.0.0.1:30141 开发服务
|
||||
npm run restart # Windows:停止本项目旧开发进程并重新启动
|
||||
npm run dev:lan # 局域网监听;仅在可信网络使用
|
||||
@@ -296,7 +310,7 @@ Versions are pinned in `config/settings.default.json` and `config/mcp.default.js
|
||||
| `pi-mcp-adapter@2.15.0` | Compact MCP proxy | The model searches and invokes MCP through `mcp`; `/mcp` shows status. Host-config discovery is off |
|
||||
| `@playwright/mcp@0.0.78` | Real navigation, clicks, forms, snapshots, screenshots | Starts on demand, exits after five idle minutes, uses isolated headless system Edge |
|
||||
| `pi-lens@3.8.73` | LSP, AST, symbols, project diagnostics | The model activates code intelligence on demand; inspect with `/lens-health`, `/lens-tools`, `/lens-map` |
|
||||
| `pi-memory@0.4.0` | Markdown durable facts, logs, scratchpad, recovery | The model uses memory tools on demand; files live under `data/agent/memory/`; vector indexing is off by default |
|
||||
| `pi-memory@0.4.0` | Markdown durable facts, logs, scratchpad, recovery | Lightweight mode retains read/write, status, and recovery tools but does not register qmd-dependent `memory_search`; files live under `data/agent/memory/` |
|
||||
| `pi-subagents@0.37.2` | Research, planning, execution subagents | Simple tasks stay local; complex or parallel work may delegate automatically; `/run` and `/parallel` remain available |
|
||||
| `pi-smart-fetch@0.3.17` | Single and batched URL retrieval | Provides `web_fetch` and `batch_web_fetch` to the main and research agents |
|
||||
| `@ayulab/pi-rewind@0.4.6` | Per-turn code checkpoints | `/rewind` restores code, conversation, or both; `/checkpoint` manages storage. Automatic file restore is off |
|
||||
@@ -306,6 +320,19 @@ Versions are pinned in `config/settings.default.json` and `config/mcp.default.js
|
||||
|
||||
Playwright never downloads a standalone Chromium in this project. Setup caches only its Node package; browser execution uses system Edge.
|
||||
|
||||
#### Memory modes
|
||||
|
||||
The managed launcher defaults to `PI_MEMORY_NO_SEARCH=1` and `PI_MEMORY_QMD_UPDATE=off`. Markdown memory, daily logs, scratchpad, and recovery stay available, while qmd detection, its installation notice, and the `memory_search` tool are skipped. A deterministic integration patch is checked during setup and before every launch, so reinstalling managed packages needs no manual repair.
|
||||
|
||||
To opt into keyword, semantic, or deep search across every memory file, install and configure qmd separately, then add the following to `.env`:
|
||||
|
||||
```dotenv
|
||||
PI_MEMORY_NO_SEARCH=0
|
||||
PI_MEMORY_QMD_UPDATE=background
|
||||
```
|
||||
|
||||
Run `npm run memory:configure` or restart the application afterward. qmd and its local models are not bundled with this repository.
|
||||
|
||||
### Profile, migration, and extension
|
||||
|
||||
```powershell
|
||||
@@ -323,6 +350,7 @@ Migration copies without deleting source data and removes absolute resource path
|
||||
```powershell
|
||||
npm run setup # Full install, build, and managed-profile validation
|
||||
npm run profile:packages # Install missing or version-mismatched managed plugins
|
||||
npm run memory:configure # Reapply the managed pi-memory lightweight integration
|
||||
npm run dev # Development server on 127.0.0.1:30141
|
||||
npm run restart # Windows: stop this project's old dev process and restart
|
||||
npm run dev:lan # Listen on the LAN; trusted networks only
|
||||
|
||||
+2
-1
@@ -12,6 +12,7 @@
|
||||
"setup": "node scripts/setup.mjs",
|
||||
"profile:init": "node scripts/init-profile.mjs",
|
||||
"profile:packages": "node scripts/install-managed-packages.mjs",
|
||||
"memory:configure": "node scripts/configure-pi-memory.mjs",
|
||||
"profile:migrate": "node scripts/migrate-profile.mjs",
|
||||
"check": "node scripts/check-integration.mjs",
|
||||
"check:profile": "node scripts/check-managed-profile.mjs",
|
||||
@@ -31,7 +32,7 @@
|
||||
"storage:clean": "node scripts/storage-maintenance.mjs clean",
|
||||
"typecheck": "node pi-web/node_modules/typescript/bin/tsc --noEmit -p pi-web/tsconfig.json",
|
||||
"lint": "npm --prefix pi-web run lint",
|
||||
"test:managed": "node --test scripts/migrate-profile.test.mjs scripts/storage-maintenance.test.mjs pi-web/lib/app-runtime.test.mjs pi-web/lib/project-trust.test.mjs pi-web/lib/searxng-extension.test.mjs pi-web/lib/skill-lock.test.mjs pi-web/lib/skill-updates.test.mjs"
|
||||
"test:managed": "node --test scripts/configure-pi-memory.test.mjs scripts/migrate-profile.test.mjs scripts/storage-maintenance.test.mjs pi-web/lib/app-runtime.test.mjs pi-web/lib/project-trust.test.mjs pi-web/lib/searxng-extension.test.mjs pi-web/lib/skill-lock.test.mjs pi-web/lib/skill-updates.test.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.19.0"
|
||||
|
||||
@@ -49,6 +49,12 @@ const missing = [
|
||||
...requiredTools.filter((name) => !tools.has(name)).map((name) => `tool:${name}`),
|
||||
...requiredCommands.filter((name) => !commands.has(name)).map((name) => `command:/${name}`),
|
||||
];
|
||||
if (process.env.PI_MEMORY_NO_SEARCH === "1" && tools.has("memory_search")) {
|
||||
missing.push("unexpected tool:memory_search in lightweight memory mode");
|
||||
}
|
||||
if (process.env.PI_MEMORY_NO_SEARCH !== "1" && !tools.has("memory_search")) {
|
||||
missing.push("tool:memory_search");
|
||||
}
|
||||
|
||||
if (missing.length > 0) {
|
||||
console.error(`Managed Pi profile is incomplete: ${missing.join(", ")}`);
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
||||
import { join, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { agentDir as defaultAgentDir } from "./profile.mjs";
|
||||
|
||||
const supportedVersion = "0.4.0";
|
||||
|
||||
function replaceOnce(source, before, after, label) {
|
||||
if (source.includes(after)) return source;
|
||||
|
||||
const first = source.indexOf(before);
|
||||
const last = source.lastIndexOf(before);
|
||||
if (first < 0 || first !== last) {
|
||||
throw new Error(`Cannot apply pi-memory lightweight patch: ${label}`);
|
||||
}
|
||||
return source.slice(0, first) + after + source.slice(first + before.length);
|
||||
}
|
||||
|
||||
export function patchPiMemorySource(input) {
|
||||
let source = input.replaceAll("\r\n", "\n");
|
||||
|
||||
source = replaceOnce(
|
||||
source,
|
||||
`\t\tqmdAvailable = await detectQmd();
|
||||
\t\tif (!qmdAvailable) {
|
||||
\t\t\tif (ctx.hasUI) {
|
||||
\t\t\t\tctx.ui.notify(qmdInstallInstructions(), "info");
|
||||
\t\t\t}
|
||||
\t\t\trefreshMemorySnapshot("session_start");
|
||||
\t\t\treturn;
|
||||
\t\t}`,
|
||||
`\t\tconst searchEnabled = process.env.PI_MEMORY_NO_SEARCH !== "1";
|
||||
\t\tqmdAvailable = searchEnabled ? await detectQmd() : false;
|
||||
\t\tif (!qmdAvailable) {
|
||||
\t\t\tif (ctx.hasUI && searchEnabled) {
|
||||
\t\t\t\tctx.ui.notify(qmdInstallInstructions(), "info");
|
||||
\t\t\t}
|
||||
\t\t\trefreshMemorySnapshot("session_start");
|
||||
\t\t\treturn;
|
||||
\t\t}`,
|
||||
"session-start qmd probe",
|
||||
);
|
||||
|
||||
source = replaceOnce(
|
||||
source,
|
||||
`\t\t\tsnapshotCaveat =
|
||||
\t\t\t\t\`Snapshot \${snapshotReason} at \${snapshotTakenAt}. \` +
|
||||
\t\t\t\t"Use memory_read / memory_search for the authoritative latest state; " +
|
||||
\t\t\t\t"recent writes may also be visible in tool-call history.";`,
|
||||
`\t\t\tsnapshotCaveat =
|
||||
\t\t\t\t\`Snapshot \${snapshotReason} at \${snapshotTakenAt}. \` +
|
||||
\t\t\t\t(process.env.PI_MEMORY_NO_SEARCH === "1"
|
||||
\t\t\t\t\t? "Use memory_read for the authoritative latest state; "
|
||||
\t\t\t\t\t: "Use memory_read / memory_search for the authoritative latest state; ") +
|
||||
\t\t\t\t"recent writes may also be visible in tool-call history.";`,
|
||||
"snapshot search guidance",
|
||||
);
|
||||
|
||||
source = replaceOnce(
|
||||
source,
|
||||
`\t\t\t"- Things to fix later or keep in mind \\u2192 scratchpad tool",
|
||||
\t\t\t"- Use memory_search to find past context across all memory files (keyword, semantic, or deep search).",
|
||||
\t\t\t"- Use #tags (e.g. #decision, #preference) and [[links]] (e.g. [[auth-strategy]]) in memory content to improve future search recall.",
|
||||
\t\t\t'- If someone says "remember this," write it immediately.',`,
|
||||
`\t\t\t"- Things to fix later or keep in mind \\u2192 scratchpad tool",
|
||||
\t\t\t...(process.env.PI_MEMORY_NO_SEARCH === "1"
|
||||
\t\t\t\t? []
|
||||
\t\t\t\t: [
|
||||
\t\t\t\t\t\t"- Use memory_search to find past context across all memory files (keyword, semantic, or deep search).",
|
||||
\t\t\t\t\t\t"- Use #tags (e.g. #decision, #preference) and [[links]] (e.g. [[auth-strategy]]) in memory content to improve future search recall.",
|
||||
\t\t\t\t\t]),
|
||||
\t\t\t'- If someone says "remember this," write it immediately.',`,
|
||||
"memory prompt search guidance",
|
||||
);
|
||||
|
||||
source = replaceOnce(
|
||||
source,
|
||||
`\t// --- memory_search tool ---
|
||||
\tpi.registerTool({`,
|
||||
`\t// --- memory_search tool (optional in lightweight mode) ---
|
||||
\tif (process.env.PI_MEMORY_NO_SEARCH !== "1") {
|
||||
\t\tpi.registerTool({`,
|
||||
"memory_search registration start",
|
||||
);
|
||||
|
||||
source = replaceOnce(
|
||||
source,
|
||||
`\t\t\t\t\tisError: true,
|
||||
\t\t\t\t\tdetails: {},
|
||||
\t\t\t\t};
|
||||
\t\t\t}
|
||||
\t\t},
|
||||
\t});
|
||||
|
||||
\t// --- memory_status tool (doctor) ---`,
|
||||
`\t\t\t\t\tisError: true,
|
||||
\t\t\t\t\tdetails: {},
|
||||
\t\t\t\t};
|
||||
\t\t\t}
|
||||
\t\t\t},
|
||||
\t\t});
|
||||
\t}
|
||||
|
||||
\t// --- memory_status tool (doctor) ---`,
|
||||
"memory_search registration end",
|
||||
);
|
||||
|
||||
source = replaceOnce(
|
||||
source,
|
||||
`\t\t\tconst qmdOk = qmdAvailable || (await detectQmd());`,
|
||||
`\t\t\tconst searchEnabled = process.env.PI_MEMORY_NO_SEARCH !== "1";
|
||||
\t\t\tconst qmdOk = searchEnabled && (qmdAvailable || (await detectQmd()));`,
|
||||
"memory status qmd probe",
|
||||
);
|
||||
|
||||
source = replaceOnce(
|
||||
source,
|
||||
`\t\t\t\t"## Search (qmd)",
|
||||
\t\t\t\t\`- qmd available: \${mark(qmdOk)}\`,
|
||||
\t\t\t];
|
||||
|
||||
\t\t\tif (qmdOk) {`,
|
||||
`\t\t\t\t"## Search (qmd)",
|
||||
\t\t\t\tsearchEnabled
|
||||
\t\t\t\t\t? \`- qmd available: \${mark(qmdOk)}\`
|
||||
\t\t\t\t\t: "- Disabled by PI_MEMORY_NO_SEARCH=1 (lightweight mode)",
|
||||
\t\t\t];
|
||||
|
||||
\t\t\tif (!searchEnabled) {
|
||||
\t\t\t\t// Core Markdown memory remains fully available in lightweight mode.
|
||||
\t\t\t} else if (qmdOk) {`,
|
||||
"memory status lightweight result",
|
||||
);
|
||||
|
||||
source = replaceOnce(
|
||||
source,
|
||||
`\t\t\t\t\`- PI_MEMORY_QMD_UPDATE: \${getQmdUpdateMode()}\`,
|
||||
\t\t\t\t\`- PI_MEMORY_DIR: \${process.env.PI_MEMORY_DIR ? "set" : "default"}\`,`,
|
||||
`\t\t\t\t\`- PI_MEMORY_NO_SEARCH: \${process.env.PI_MEMORY_NO_SEARCH ?? "0"}\`,
|
||||
\t\t\t\t\`- PI_MEMORY_QMD_UPDATE: \${getQmdUpdateMode()}\`,
|
||||
\t\t\t\t\`- PI_MEMORY_DIR: \${process.env.PI_MEMORY_DIR ? "set" : "default"}\`,`,
|
||||
"memory status configuration",
|
||||
);
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
export function isPiMemoryLiteConfigured(source) {
|
||||
return (
|
||||
source.includes('qmdAvailable = searchEnabled ? await detectQmd() : false;') &&
|
||||
source.includes('if (process.env.PI_MEMORY_NO_SEARCH !== "1") {\n\t\tpi.registerTool({') &&
|
||||
source.includes("Disabled by PI_MEMORY_NO_SEARCH=1 (lightweight mode)")
|
||||
);
|
||||
}
|
||||
|
||||
export function configurePiMemory({ agentDir = defaultAgentDir, quiet = false } = {}) {
|
||||
const packageDir = join(agentDir, "npm", "node_modules", "pi-memory");
|
||||
const packageJsonPath = join(packageDir, "package.json");
|
||||
const sourcePath = join(packageDir, "index.ts");
|
||||
|
||||
if (!existsSync(packageJsonPath) || !existsSync(sourcePath)) {
|
||||
return { status: "missing", sourcePath };
|
||||
}
|
||||
|
||||
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
||||
if (packageJson.version !== supportedVersion) {
|
||||
throw new Error(
|
||||
`Unsupported pi-memory version ${packageJson.version ?? "unknown"}; expected ${supportedVersion}.`,
|
||||
);
|
||||
}
|
||||
|
||||
const source = readFileSync(sourcePath, "utf8");
|
||||
const patched = patchPiMemorySource(source);
|
||||
if (patched === source) {
|
||||
if (!quiet) console.log("pi-memory lightweight integration ready.");
|
||||
return { status: "ready", sourcePath };
|
||||
}
|
||||
|
||||
writeFileSync(sourcePath, patched, "utf8");
|
||||
if (!quiet) console.log("Configured pi-memory lightweight integration.");
|
||||
return { status: "patched", sourcePath };
|
||||
}
|
||||
|
||||
const invokedPath = process.argv[1] ? resolve(process.argv[1]) : "";
|
||||
if (invokedPath === fileURLToPath(import.meta.url)) {
|
||||
const result = configurePiMemory();
|
||||
if (result.status === "missing") {
|
||||
console.error("pi-memory is not installed. Run npm run setup first.");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { existsSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import test from "node:test";
|
||||
import {
|
||||
configurePiMemory,
|
||||
isPiMemoryLiteConfigured,
|
||||
patchPiMemorySource,
|
||||
} from "./configure-pi-memory.mjs";
|
||||
import { agentDir, managedEnvironment } from "./profile.mjs";
|
||||
|
||||
test("managed profile defaults pi-memory to lightweight mode", () => {
|
||||
const defaultEnvironment = managedEnvironment({ ...process.env, PI_MEMORY_NO_SEARCH: undefined });
|
||||
const searchEnvironment = managedEnvironment({ ...process.env, PI_MEMORY_NO_SEARCH: "0" });
|
||||
|
||||
assert.equal(defaultEnvironment.PI_MEMORY_NO_SEARCH, "1");
|
||||
assert.equal(searchEnvironment.PI_MEMORY_NO_SEARCH, "0");
|
||||
});
|
||||
|
||||
test("installed pi-memory integration is patched and idempotent", (context) => {
|
||||
const sourcePath = join(agentDir, "npm", "node_modules", "pi-memory", "index.ts");
|
||||
if (!existsSync(sourcePath)) {
|
||||
context.skip("managed pi-memory is not installed; npm run setup installs it before CI tests");
|
||||
return;
|
||||
}
|
||||
|
||||
configurePiMemory({ quiet: true });
|
||||
const source = readFileSync(sourcePath, "utf8");
|
||||
assert.equal(isPiMemoryLiteConfigured(source), true);
|
||||
assert.equal(patchPiMemorySource(source), source);
|
||||
});
|
||||
|
||||
test("integration rejects an unreviewed pi-memory version", () => {
|
||||
const temporaryAgentDir = mkdtempSync(join(tmpdir(), "pi-memory-version-"));
|
||||
const packageDir = join(temporaryAgentDir, "npm", "node_modules", "pi-memory");
|
||||
mkdirSync(packageDir, { recursive: true });
|
||||
writeFileSync(join(packageDir, "package.json"), JSON.stringify({ version: "9.9.9" }), "utf8");
|
||||
writeFileSync(join(packageDir, "index.ts"), "export default function () {}\n", "utf8");
|
||||
|
||||
assert.throws(
|
||||
() => configurePiMemory({ agentDir: temporaryAgentDir, quiet: true }),
|
||||
/Unsupported pi-memory version 9\.9\.9/,
|
||||
);
|
||||
});
|
||||
@@ -1,6 +1,7 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { configurePiMemory } from "./configure-pi-memory.mjs";
|
||||
import { agentDir, managedEnvironment, rootDir } from "./profile.mjs";
|
||||
|
||||
const settings = JSON.parse(
|
||||
@@ -46,3 +47,5 @@ for (const source of packages) {
|
||||
if (result.error) throw result.error;
|
||||
if (result.status !== 0) process.exit(result.status ?? 1);
|
||||
}
|
||||
|
||||
configurePiMemory({ agentDir });
|
||||
|
||||
@@ -124,6 +124,7 @@ export function managedEnvironment(baseEnv = process.env) {
|
||||
USERPROFILE: homeDir,
|
||||
PI_MEMORY_DIR: baseEnv.PI_MEMORY_DIR?.trim() || memoryDir,
|
||||
PI_MEMORY_SNAPSHOT: baseEnv.PI_MEMORY_SNAPSHOT?.trim() || "stable",
|
||||
PI_MEMORY_NO_SEARCH: baseEnv.PI_MEMORY_NO_SEARCH?.trim() || "1",
|
||||
PI_MEMORY_QMD_UPDATE: baseEnv.PI_MEMORY_QMD_UPDATE?.trim() || "off",
|
||||
PI_RETRY_STALL_TIMEOUT_MS: baseEnv.PI_RETRY_STALL_TIMEOUT_MS?.trim() || "180000",
|
||||
npm_config_cache: baseEnv.npm_config_cache?.trim() || join(dataDir, "cache", "npm"),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { spawn } from "node:child_process";
|
||||
import { join } from "node:path";
|
||||
import { configurePiMemory } from "./configure-pi-memory.mjs";
|
||||
import { managedEnvironment, rootDir } from "./profile.mjs";
|
||||
import {
|
||||
isLocalPortListening,
|
||||
@@ -21,6 +22,10 @@ if (!npmCliPath) {
|
||||
}
|
||||
|
||||
const childEnvironment = managedEnvironment();
|
||||
const memoryConfiguration = configurePiMemory({ quiet: true });
|
||||
if (memoryConfiguration.status === "missing") {
|
||||
console.warn("[memory] pi-memory is not installed; run npm run setup to enable managed memory");
|
||||
}
|
||||
if (await isLocalPortListening(30141)) {
|
||||
console.log("[storage] skipped automatic maintenance because Pi Web is already running");
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user