@pi-unipi/unipi 2.4.2 → 2.5.0
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/CHANGELOG.md +25 -0
- package/package.json +23 -22
- package/packages/ask-user/package.json +2 -2
- package/packages/autocomplete/package.json +1 -1
- package/packages/btw/package.json +2 -2
- package/packages/cocoindex/package.json +2 -2
- package/packages/compactor/package.json +3 -3
- package/packages/core/package.json +1 -1
- package/packages/core/sandbox.ts +7 -6
- package/packages/footer/package.json +2 -2
- package/packages/image/package.json +2 -2
- package/packages/info-screen/package.json +2 -2
- package/packages/input-shortcuts/package.json +2 -2
- package/packages/kanboard/package.json +2 -2
- package/packages/mcp/README.md +9 -0
- package/packages/mcp/package.json +5 -2
- package/packages/mcp/src/bridge/registry.ts +244 -137
- package/packages/mcp/src/bridge/translator.ts +77 -9
- package/packages/mcp/src/index.ts +43 -67
- package/packages/mcp/src/tui/settings-overlay.ts +3 -9
- package/packages/memory/README.md +15 -11
- package/packages/memory/bridge/mempalace_bridge.py +636 -0
- package/packages/memory/mempalace.ts +169 -18
- package/packages/memory/package.json +3 -3
- package/packages/memory/storage.ts +27 -10
- package/packages/milestone/README.md +11 -3
- package/packages/milestone/hooks.ts +103 -29
- package/packages/milestone/index.ts +1 -1
- package/packages/milestone/package.json +5 -2
- package/packages/notify/package.json +2 -2
- package/packages/ralph/package.json +3 -3
- package/packages/subagents/package.json +1 -1
- package/packages/unipi/bundled.js +693 -408
- package/packages/updater/package.json +2 -2
- package/packages/utility/package.json +2 -2
- package/packages/web-api/package.json +2 -2
- package/packages/workflow/README.md +8 -0
- package/packages/workflow/commands.ts +16 -26
- package/packages/workflow/index.ts +165 -85
- package/packages/workflow/package.json +5 -2
|
@@ -868,12 +868,40 @@ var init_core = __esm({
|
|
|
868
868
|
|
|
869
869
|
// packages/memory/mempalace.ts
|
|
870
870
|
import { spawnSync, spawn } from "node:child_process";
|
|
871
|
+
import { createHash } from "node:crypto";
|
|
872
|
+
import { createRequire } from "node:module";
|
|
871
873
|
import * as fs4 from "node:fs";
|
|
872
874
|
import * as path4 from "node:path";
|
|
873
875
|
import * as os from "node:os";
|
|
874
876
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
875
|
-
function
|
|
876
|
-
|
|
877
|
+
function isReadableFile(candidate) {
|
|
878
|
+
try {
|
|
879
|
+
return fs4.statSync(candidate).isFile() && fs4.accessSync(candidate, fs4.constants.R_OK) === void 0;
|
|
880
|
+
} catch {
|
|
881
|
+
return false;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
function resolveMempalaceBridgePath(moduleUrl = import.meta.url) {
|
|
885
|
+
const moduleDir = path4.dirname(fileURLToPath3(moduleUrl));
|
|
886
|
+
const candidates = [];
|
|
887
|
+
if (process.env.UNIPI_MEMPALACE_BRIDGE) {
|
|
888
|
+
candidates.push(path4.resolve(process.env.UNIPI_MEMPALACE_BRIDGE));
|
|
889
|
+
}
|
|
890
|
+
candidates.push(
|
|
891
|
+
path4.join(moduleDir, "bridge", "mempalace_bridge.py"),
|
|
892
|
+
path4.join(moduleDir, "..", "memory", "bridge", "mempalace_bridge.py")
|
|
893
|
+
);
|
|
894
|
+
try {
|
|
895
|
+
const require2 = createRequire(moduleUrl);
|
|
896
|
+
const memoryPackage = require2.resolve("@pi-unipi/memory/package.json");
|
|
897
|
+
candidates.push(path4.join(path4.dirname(memoryPackage), "bridge", "mempalace_bridge.py"));
|
|
898
|
+
} catch {
|
|
899
|
+
}
|
|
900
|
+
return candidates.find(isReadableFile) ?? null;
|
|
901
|
+
}
|
|
902
|
+
function getBridgePath() {
|
|
903
|
+
if (cachedBridgePath === void 0) cachedBridgePath = resolveMempalaceBridgePath();
|
|
904
|
+
return cachedBridgePath;
|
|
877
905
|
}
|
|
878
906
|
function which(bin) {
|
|
879
907
|
try {
|
|
@@ -973,17 +1001,71 @@ function invalidatePingVerified() {
|
|
|
973
1001
|
} catch {
|
|
974
1002
|
}
|
|
975
1003
|
}
|
|
976
|
-
function
|
|
977
|
-
|
|
1004
|
+
function getMemorySourceFingerprint(sourceDir = path4.join(os.homedir(), ".unipi", "memory")) {
|
|
1005
|
+
const hash = createHash("sha256");
|
|
1006
|
+
if (!fs4.existsSync(sourceDir)) return hash.update("missing").digest("hex");
|
|
1007
|
+
const visit = (dir) => {
|
|
1008
|
+
let entries;
|
|
1009
|
+
try {
|
|
1010
|
+
entries = fs4.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
1011
|
+
} catch {
|
|
1012
|
+
hash.update(`unreadable:${dir}`);
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
for (const entry of entries) {
|
|
1016
|
+
if (entry.name.startsWith(".")) continue;
|
|
1017
|
+
const full = path4.join(dir, entry.name);
|
|
1018
|
+
if (entry.isDirectory()) {
|
|
1019
|
+
visit(full);
|
|
1020
|
+
continue;
|
|
1021
|
+
}
|
|
1022
|
+
if (!entry.isFile() || entry.name !== "memory.db" && !entry.name.endsWith(".md")) continue;
|
|
1023
|
+
try {
|
|
1024
|
+
const stat = fs4.statSync(full);
|
|
1025
|
+
hash.update(`${path4.relative(sourceDir, full)}\0${stat.size}\0${stat.mtimeMs}
|
|
1026
|
+
`);
|
|
1027
|
+
} catch {
|
|
1028
|
+
hash.update(`unreadable:${path4.relative(sourceDir, full)}
|
|
1029
|
+
`);
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
};
|
|
1033
|
+
visit(sourceDir);
|
|
1034
|
+
return hash.digest("hex");
|
|
1035
|
+
}
|
|
1036
|
+
function readMigrationState(flagPath = MIGRATED_FLAG) {
|
|
1037
|
+
try {
|
|
1038
|
+
const parsed = JSON.parse(fs4.readFileSync(flagPath, "utf-8"));
|
|
1039
|
+
if (parsed?.version !== MIGRATION_STATE_VERSION || typeof parsed.completedAt !== "string" || typeof parsed.sourceFingerprint !== "string" || !parsed.result || parsed.result.failed !== 0 || parsed.result.verified !== parsed.result.discovered) return null;
|
|
1040
|
+
return parsed;
|
|
1041
|
+
} catch {
|
|
1042
|
+
return null;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
function isMigrated(sourceFingerprint = getMemorySourceFingerprint(), flagPath = MIGRATED_FLAG) {
|
|
1046
|
+
return readMigrationState(flagPath)?.sourceFingerprint === sourceFingerprint;
|
|
978
1047
|
}
|
|
979
|
-
function markMigrated() {
|
|
1048
|
+
function markMigrated(sourceFingerprint, result, flagPath = MIGRATED_FLAG) {
|
|
1049
|
+
if (result.failed !== 0 || result.verified !== result.discovered) return false;
|
|
980
1050
|
try {
|
|
981
|
-
fs4.mkdirSync(path4.dirname(
|
|
982
|
-
|
|
1051
|
+
fs4.mkdirSync(path4.dirname(flagPath), { recursive: true });
|
|
1052
|
+
const state = {
|
|
1053
|
+
version: MIGRATION_STATE_VERSION,
|
|
1054
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1055
|
+
sourceFingerprint,
|
|
1056
|
+
result
|
|
1057
|
+
};
|
|
1058
|
+
const temp = `${flagPath}.${process.pid}.tmp`;
|
|
1059
|
+
fs4.writeFileSync(temp, JSON.stringify(state, null, 2), "utf-8");
|
|
1060
|
+
fs4.renameSync(temp, flagPath);
|
|
1061
|
+
return true;
|
|
983
1062
|
} catch {
|
|
1063
|
+
return false;
|
|
984
1064
|
}
|
|
985
1065
|
}
|
|
986
|
-
function runBridge(install, palace, cmd, args = {}) {
|
|
1066
|
+
function runBridge(install, palace, cmd, args = {}, timeoutMs = 6e4) {
|
|
1067
|
+
const bridgePath = getBridgePath();
|
|
1068
|
+
if (!bridgePath) return null;
|
|
987
1069
|
let argsJson;
|
|
988
1070
|
try {
|
|
989
1071
|
argsJson = JSON.stringify(args);
|
|
@@ -992,9 +1074,9 @@ function runBridge(install, palace, cmd, args = {}) {
|
|
|
992
1074
|
}
|
|
993
1075
|
let res;
|
|
994
1076
|
try {
|
|
995
|
-
res = spawnSync(install.python, [
|
|
1077
|
+
res = spawnSync(install.python, [bridgePath, palace, cmd, argsJson], {
|
|
996
1078
|
encoding: "utf-8",
|
|
997
|
-
timeout:
|
|
1079
|
+
timeout: timeoutMs,
|
|
998
1080
|
maxBuffer: 64 * 1024 * 1024
|
|
999
1081
|
});
|
|
1000
1082
|
} catch {
|
|
@@ -1013,22 +1095,27 @@ function runBridge(install, palace, cmd, args = {}) {
|
|
|
1013
1095
|
return null;
|
|
1014
1096
|
}
|
|
1015
1097
|
}
|
|
1016
|
-
function runBridgeAsync(install, palace, cmd, args = {}) {
|
|
1017
|
-
return new Promise((
|
|
1098
|
+
function runBridgeAsync(install, palace, cmd, args = {}, timeoutMs = 6e4) {
|
|
1099
|
+
return new Promise((resolve14) => {
|
|
1100
|
+
const bridgePath = getBridgePath();
|
|
1101
|
+
if (!bridgePath) {
|
|
1102
|
+
resolve14(null);
|
|
1103
|
+
return;
|
|
1104
|
+
}
|
|
1018
1105
|
let argsJson;
|
|
1019
1106
|
try {
|
|
1020
1107
|
argsJson = JSON.stringify(args);
|
|
1021
1108
|
} catch {
|
|
1022
|
-
|
|
1109
|
+
resolve14(null);
|
|
1023
1110
|
return;
|
|
1024
1111
|
}
|
|
1025
1112
|
let child;
|
|
1026
1113
|
try {
|
|
1027
|
-
child = spawn(install.python, [
|
|
1114
|
+
child = spawn(install.python, [bridgePath, palace, cmd, argsJson], {
|
|
1028
1115
|
stdio: ["ignore", "pipe", "ignore"]
|
|
1029
1116
|
});
|
|
1030
1117
|
} catch {
|
|
1031
|
-
|
|
1118
|
+
resolve14(null);
|
|
1032
1119
|
return;
|
|
1033
1120
|
}
|
|
1034
1121
|
let out = "";
|
|
@@ -1037,7 +1124,7 @@ function runBridgeAsync(install, palace, cmd, args = {}) {
|
|
|
1037
1124
|
if (settled) return;
|
|
1038
1125
|
settled = true;
|
|
1039
1126
|
clearTimeout(timer);
|
|
1040
|
-
|
|
1127
|
+
resolve14(value);
|
|
1041
1128
|
};
|
|
1042
1129
|
const timer = setTimeout(() => {
|
|
1043
1130
|
try {
|
|
@@ -1045,7 +1132,7 @@ function runBridgeAsync(install, palace, cmd, args = {}) {
|
|
|
1045
1132
|
} catch {
|
|
1046
1133
|
}
|
|
1047
1134
|
finish(null);
|
|
1048
|
-
},
|
|
1135
|
+
}, timeoutMs);
|
|
1049
1136
|
timer.unref?.();
|
|
1050
1137
|
child.stdout?.setEncoding("utf-8");
|
|
1051
1138
|
child.stdout?.on("data", (chunk) => {
|
|
@@ -1065,7 +1152,7 @@ function runBridgeAsync(install, palace, cmd, args = {}) {
|
|
|
1065
1152
|
});
|
|
1066
1153
|
});
|
|
1067
1154
|
}
|
|
1068
|
-
var DEFAULT_PALACE, INSTALL_FLAG, MIGRATED_FLAG, PING_VERIFIED_FLAG, PING_VERIFIED_TTL_MS,
|
|
1155
|
+
var DEFAULT_PALACE, INSTALL_FLAG, MIGRATED_FLAG, PING_VERIFIED_FLAG, PING_VERIFIED_TTL_MS, MIGRATION_STATE_VERSION, cachedBridgePath;
|
|
1069
1156
|
var init_mempalace = __esm({
|
|
1070
1157
|
"packages/memory/mempalace.ts"() {
|
|
1071
1158
|
"use strict";
|
|
@@ -1074,7 +1161,7 @@ var init_mempalace = __esm({
|
|
|
1074
1161
|
MIGRATED_FLAG = path4.join(os.homedir(), ".unipi", "memory", ".mempalace-migrated");
|
|
1075
1162
|
PING_VERIFIED_FLAG = path4.join(os.homedir(), ".unipi", "memory", ".mempalace-ping-verified");
|
|
1076
1163
|
PING_VERIFIED_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
1077
|
-
|
|
1164
|
+
MIGRATION_STATE_VERSION = 2;
|
|
1078
1165
|
}
|
|
1079
1166
|
});
|
|
1080
1167
|
|
|
@@ -1174,7 +1261,7 @@ function parseMemoryContent(content) {
|
|
|
1174
1261
|
const [, frontmatterStr, body] = match;
|
|
1175
1262
|
const frontmatter = yaml.load(frontmatterStr);
|
|
1176
1263
|
return {
|
|
1177
|
-
id: "",
|
|
1264
|
+
id: frontmatter.id || "",
|
|
1178
1265
|
title: frontmatter.title,
|
|
1179
1266
|
content: body.trim(),
|
|
1180
1267
|
tags: frontmatter.tags || [],
|
|
@@ -1186,6 +1273,7 @@ function parseMemoryContent(content) {
|
|
|
1186
1273
|
}
|
|
1187
1274
|
function writeMemoryFile(filePath, record) {
|
|
1188
1275
|
const frontmatter = {
|
|
1276
|
+
id: record.id,
|
|
1189
1277
|
title: record.title,
|
|
1190
1278
|
tags: record.tags,
|
|
1191
1279
|
project: record.project,
|
|
@@ -1405,12 +1493,15 @@ var init_storage = __esm({
|
|
|
1405
1493
|
}
|
|
1406
1494
|
this.mempalaceInstall = install;
|
|
1407
1495
|
this.backend = "mempalace";
|
|
1408
|
-
|
|
1496
|
+
const sourceFingerprint = getMemorySourceFingerprint(getMemoryBaseDir());
|
|
1497
|
+
if (!isMigrated(sourceFingerprint)) {
|
|
1409
1498
|
try {
|
|
1410
|
-
runBridge(install, this.palacePath, "migrate", {
|
|
1499
|
+
const result = runBridge(install, this.palacePath, "migrate", {
|
|
1411
1500
|
source_dir: getMemoryBaseDir()
|
|
1412
|
-
});
|
|
1413
|
-
|
|
1501
|
+
}, 15 * 6e4);
|
|
1502
|
+
if (result && result.failed === 0 && result.verified === result.discovered) {
|
|
1503
|
+
markMigrated(sourceFingerprint, result);
|
|
1504
|
+
}
|
|
1414
1505
|
} catch {
|
|
1415
1506
|
}
|
|
1416
1507
|
}
|
|
@@ -1597,7 +1688,7 @@ ${record.content}
|
|
|
1597
1688
|
const filePath = path5.join(this.scopeDir, file);
|
|
1598
1689
|
const record = parseMemoryFile(filePath);
|
|
1599
1690
|
if (!record) continue;
|
|
1600
|
-
const id = record.title.toLowerCase().replace(/[^a-z0-9]+/g, "_");
|
|
1691
|
+
const id = record.id || record.title.toLowerCase().replace(/[^a-z0-9]+/g, "_");
|
|
1601
1692
|
if (existingIds.has(id)) continue;
|
|
1602
1693
|
try {
|
|
1603
1694
|
record.id = id;
|
|
@@ -2239,8 +2330,8 @@ var init_embedding = __esm({
|
|
|
2239
2330
|
});
|
|
2240
2331
|
|
|
2241
2332
|
// packages/info-screen/usage-parser.ts
|
|
2242
|
-
import { readdirSync as
|
|
2243
|
-
import { join as join9, dirname as
|
|
2333
|
+
import { readdirSync as readdirSync5, readFileSync as readFileSync8, statSync as statSync5, existsSync as existsSync9, mkdirSync as mkdirSync7, writeFileSync as writeFileSync8, renameSync as renameSync3, openSync, readSync, closeSync } from "node:fs";
|
|
2334
|
+
import { join as join9, dirname as dirname9 } from "node:path";
|
|
2244
2335
|
import { homedir as homedir5 } from "node:os";
|
|
2245
2336
|
function getCachePath() {
|
|
2246
2337
|
const base = process.env.UNIPI_DIR || join9(homedir5(), ".unipi");
|
|
@@ -2262,10 +2353,10 @@ function readCache() {
|
|
|
2262
2353
|
function writeCache(cache) {
|
|
2263
2354
|
try {
|
|
2264
2355
|
const path28 = getCachePath();
|
|
2265
|
-
mkdirSync7(
|
|
2356
|
+
mkdirSync7(dirname9(path28), { recursive: true });
|
|
2266
2357
|
const tmp = `${path28}.${process.pid}.tmp`;
|
|
2267
2358
|
writeFileSync8(tmp, JSON.stringify(cache), "utf-8");
|
|
2268
|
-
|
|
2359
|
+
renameSync3(tmp, path28);
|
|
2269
2360
|
} catch {
|
|
2270
2361
|
}
|
|
2271
2362
|
}
|
|
@@ -2361,7 +2452,7 @@ function extractRecords(filePath, modelIndex, models) {
|
|
|
2361
2452
|
}
|
|
2362
2453
|
function collectSessionFiles(dir, files) {
|
|
2363
2454
|
try {
|
|
2364
|
-
const entries =
|
|
2455
|
+
const entries = readdirSync5(dir, { withFileTypes: true });
|
|
2365
2456
|
for (const entry of entries) {
|
|
2366
2457
|
const entryPath = join9(dir, entry.name);
|
|
2367
2458
|
if (entry.isDirectory()) {
|
|
@@ -2375,7 +2466,7 @@ function collectSessionFiles(dir, files) {
|
|
|
2375
2466
|
}
|
|
2376
2467
|
async function parseUsageStatsAsync() {
|
|
2377
2468
|
const yielder = async () => {
|
|
2378
|
-
await new Promise((
|
|
2469
|
+
await new Promise((resolve14) => setImmediate(resolve14));
|
|
2379
2470
|
};
|
|
2380
2471
|
const { stats, pending } = collectStats(yielder);
|
|
2381
2472
|
if (pending) await pending;
|
|
@@ -2411,7 +2502,7 @@ function collectStats(yielder) {
|
|
|
2411
2502
|
let mtimeMs = 0;
|
|
2412
2503
|
let size = 0;
|
|
2413
2504
|
try {
|
|
2414
|
-
const st =
|
|
2505
|
+
const st = statSync5(filePath);
|
|
2415
2506
|
mtimeMs = st.mtimeMs;
|
|
2416
2507
|
size = st.size;
|
|
2417
2508
|
} catch {
|
|
@@ -2592,19 +2683,19 @@ __export(env_exports, {
|
|
|
2592
2683
|
formatEnvironmentInfo: () => formatEnvironmentInfo,
|
|
2593
2684
|
getEnvironmentInfo: () => getEnvironmentInfo
|
|
2594
2685
|
});
|
|
2595
|
-
import { existsSync as existsSync18, readdirSync as
|
|
2596
|
-
import { join as join18, resolve as
|
|
2686
|
+
import { existsSync as existsSync18, readdirSync as readdirSync11 } from "node:fs";
|
|
2687
|
+
import { join as join18, resolve as resolve6 } from "node:path";
|
|
2597
2688
|
import { homedir as homedir14 } from "node:os";
|
|
2598
2689
|
function getEnvironmentInfo() {
|
|
2599
2690
|
const unipiModules = [];
|
|
2600
2691
|
const configPaths = [];
|
|
2601
2692
|
const extensionPaths = [];
|
|
2602
2693
|
try {
|
|
2603
|
-
const nodeModules =
|
|
2694
|
+
const nodeModules = resolve6(process.cwd(), "node_modules");
|
|
2604
2695
|
if (existsSync18(nodeModules)) {
|
|
2605
2696
|
const scopePath = join18(nodeModules, "@pi-unipi");
|
|
2606
2697
|
if (existsSync18(scopePath)) {
|
|
2607
|
-
for (const entry of
|
|
2698
|
+
for (const entry of readdirSync11(scopePath)) {
|
|
2608
2699
|
if (entry.startsWith(".")) continue;
|
|
2609
2700
|
const pkgPath = join18(scopePath, entry, "package.json");
|
|
2610
2701
|
if (existsSync18(pkgPath)) {
|
|
@@ -2616,7 +2707,7 @@ function getEnvironmentInfo() {
|
|
|
2616
2707
|
} catch {
|
|
2617
2708
|
}
|
|
2618
2709
|
const globalConfig = join18(homedir14(), ".unipi", "config");
|
|
2619
|
-
const projectConfig =
|
|
2710
|
+
const projectConfig = resolve6(process.cwd(), ".unipi", "config");
|
|
2620
2711
|
if (existsSync18(globalConfig)) {
|
|
2621
2712
|
configPaths.push(globalConfig);
|
|
2622
2713
|
}
|
|
@@ -3863,7 +3954,7 @@ var init_schema = __esm({
|
|
|
3863
3954
|
// packages/compactor/src/config/manager.ts
|
|
3864
3955
|
import { existsSync as existsSync31, mkdirSync as mkdirSync19, readFileSync as readFileSync29, writeFileSync as writeFileSync23 } from "node:fs";
|
|
3865
3956
|
import { homedir as homedir20 } from "node:os";
|
|
3866
|
-
import { dirname as
|
|
3957
|
+
import { dirname as dirname24, join as join32 } from "node:path";
|
|
3867
3958
|
function projectConfigPath(cwd) {
|
|
3868
3959
|
return join32(cwd, ".unipi", "config", "compactor.json");
|
|
3869
3960
|
}
|
|
@@ -3900,7 +3991,7 @@ function loadConfig4(cwd) {
|
|
|
3900
3991
|
function saveConfig3(config, opts) {
|
|
3901
3992
|
try {
|
|
3902
3993
|
const targetPath = opts?.perProject && opts?.cwd ? projectConfigPath(opts.cwd) : COMPACTOR_CONFIG_PATH;
|
|
3903
|
-
const dir =
|
|
3994
|
+
const dir = dirname24(targetPath);
|
|
3904
3995
|
if (!existsSync31(dir)) mkdirSync19(dir, { recursive: true });
|
|
3905
3996
|
writeFileSync23(targetPath, `${JSON.stringify(config, null, 2)}
|
|
3906
3997
|
`);
|
|
@@ -3935,7 +4026,7 @@ function migrateConfig(partial) {
|
|
|
3935
4026
|
}
|
|
3936
4027
|
function scaffoldConfig() {
|
|
3937
4028
|
try {
|
|
3938
|
-
const dir =
|
|
4029
|
+
const dir = dirname24(COMPACTOR_CONFIG_PATH);
|
|
3939
4030
|
if (!existsSync31(dir)) mkdirSync19(dir, { recursive: true });
|
|
3940
4031
|
if (!existsSync31(COMPACTOR_CONFIG_PATH)) {
|
|
3941
4032
|
writeFileSync23(COMPACTOR_CONFIG_PATH, `${JSON.stringify(DEFAULT_COMPACTOR_CONFIG, null, 2)}
|
|
@@ -5452,9 +5543,9 @@ var init_snapshot = __esm({
|
|
|
5452
5543
|
});
|
|
5453
5544
|
|
|
5454
5545
|
// packages/compactor/src/config/presets.ts
|
|
5455
|
-
import { createHash as
|
|
5546
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
5456
5547
|
function presetHash(config) {
|
|
5457
|
-
return
|
|
5548
|
+
return createHash4("sha256").update(JSON.stringify(config)).digest("hex");
|
|
5458
5549
|
}
|
|
5459
5550
|
function configsEqual(a, b) {
|
|
5460
5551
|
const aHash = presetHash(a);
|
|
@@ -6309,7 +6400,7 @@ __export(evaluator_exports, {
|
|
|
6309
6400
|
splitChainedCommands: () => splitChainedCommands
|
|
6310
6401
|
});
|
|
6311
6402
|
import { realpathSync as realpathSync2, existsSync as existsSync37, readFileSync as readFileSync32 } from "node:fs";
|
|
6312
|
-
import { resolve as
|
|
6403
|
+
import { resolve as resolve12, join as join36 } from "node:path";
|
|
6313
6404
|
import { homedir as homedir22 } from "node:os";
|
|
6314
6405
|
function loadProjectPermissions(cwd, basePolicy) {
|
|
6315
6406
|
const settingsPath = join36(cwd, ".pi", "settings.json");
|
|
@@ -6381,7 +6472,7 @@ function splitChainedCommands(command) {
|
|
|
6381
6472
|
return commands;
|
|
6382
6473
|
}
|
|
6383
6474
|
function evaluateFilePath(filePath, policy, cwd = process.cwd()) {
|
|
6384
|
-
const resolved =
|
|
6475
|
+
const resolved = resolve12(cwd, filePath);
|
|
6385
6476
|
try {
|
|
6386
6477
|
const real = realpathSync2(resolved);
|
|
6387
6478
|
const home = homedir22();
|
|
@@ -6551,6 +6642,9 @@ var init_thinking_label = __esm({
|
|
|
6551
6642
|
init_core();
|
|
6552
6643
|
import { dirname as dirname2 } from "node:path";
|
|
6553
6644
|
import { fileURLToPath } from "node:url";
|
|
6645
|
+
import {
|
|
6646
|
+
buildSessionContext
|
|
6647
|
+
} from "@earendil-works/pi-coding-agent";
|
|
6554
6648
|
|
|
6555
6649
|
// packages/workflow/commands.ts
|
|
6556
6650
|
init_core();
|
|
@@ -6824,15 +6918,10 @@ function registerWorkflowCommands(pi, options) {
|
|
|
6824
6918
|
fullCommand: `/${fullCommand}`,
|
|
6825
6919
|
args: args?.trim() ?? ""
|
|
6826
6920
|
};
|
|
6827
|
-
if (!options.
|
|
6921
|
+
if (!options.activateSandbox(workflowEvent)) {
|
|
6828
6922
|
if (ctx.hasUI) ctx.ui.notify("Another UniPi workflow is still active", "warning");
|
|
6829
6923
|
return;
|
|
6830
6924
|
}
|
|
6831
|
-
const currentTools = options.getActiveTools();
|
|
6832
|
-
options.saveTools(currentTools);
|
|
6833
|
-
const sandboxTools = getToolsForCommand(cmd.name, currentTools);
|
|
6834
|
-
const sandboxLevel = getSandboxLevel(cmd.name);
|
|
6835
|
-
options.setActiveTools([...sandboxTools], sandboxLevel);
|
|
6836
6925
|
let skillContent = "";
|
|
6837
6926
|
try {
|
|
6838
6927
|
const skillPath = join3(
|
|
@@ -6861,7 +6950,12 @@ Arguments: ${args.trim()}`;
|
|
|
6861
6950
|
${skillContent}
|
|
6862
6951
|
</skill_content>`;
|
|
6863
6952
|
}
|
|
6864
|
-
|
|
6953
|
+
try {
|
|
6954
|
+
pi.sendUserMessage(message, { deliverAs: "followUp" });
|
|
6955
|
+
} catch (error) {
|
|
6956
|
+
options.abortWorkflow();
|
|
6957
|
+
throw error;
|
|
6958
|
+
}
|
|
6865
6959
|
if (ctx.hasUI) {
|
|
6866
6960
|
ctx.ui.notify(`Running /${fullCommand}`, "info");
|
|
6867
6961
|
const ralphStatus = options.isRalphDetected() ? "\u2713 rl" : "\u25CB rl";
|
|
@@ -6929,90 +7023,147 @@ var WorkflowLifecycle = class {
|
|
|
6929
7023
|
|
|
6930
7024
|
// packages/workflow/index.ts
|
|
6931
7025
|
var VERSION = getPackageVersion(dirname2(fileURLToPath(import.meta.url)));
|
|
6932
|
-
var
|
|
6933
|
-
|
|
6934
|
-
|
|
6935
|
-
|
|
6936
|
-
|
|
7026
|
+
var WORKFLOW_SANDBOX_SNAPSHOT_TYPE = "unipi-workflow-sandbox-snapshot";
|
|
7027
|
+
function sandboxRestrictions(level) {
|
|
7028
|
+
const common = [
|
|
7029
|
+
"Do not attempt to call tools blocked by name.",
|
|
7030
|
+
"If the user requests an action that requires a blocked tool, explain that the workflow sandbox does not allow it."
|
|
7031
|
+
];
|
|
7032
|
+
if (level === "brainstorm") {
|
|
7033
|
+
return [
|
|
7034
|
+
"The write tool is restricted to .unipi/docs/specs/ only.",
|
|
7035
|
+
"Use bash only for specific setup operations such as git init or mkdir; use grep, find, and ls for discovery instead of bash.",
|
|
7036
|
+
...common
|
|
7037
|
+
];
|
|
7038
|
+
}
|
|
7039
|
+
if (level === "write_unipi") {
|
|
7040
|
+
return [
|
|
7041
|
+
"The write tool is restricted to .unipi/docs/ only (specs and plans).",
|
|
7042
|
+
"Use grep, find, and ls for file discovery instead of guessing filenames.",
|
|
7043
|
+
"Bash is blocked; use read, write, edit, grep, find, and ls only.",
|
|
7044
|
+
...common
|
|
7045
|
+
];
|
|
7046
|
+
}
|
|
7047
|
+
return common;
|
|
7048
|
+
}
|
|
7049
|
+
function formatActiveSandboxSnapshot(command, level) {
|
|
7050
|
+
const blocked = getBlockedToolsForLevel(level);
|
|
7051
|
+
const blockedLine = blocked.length > 0 ? blocked.join(", ") : "none";
|
|
7052
|
+
return [
|
|
7053
|
+
"# UniPi Workflow Sandbox Snapshot",
|
|
7054
|
+
"This snapshot supersedes all prior UniPi workflow sandbox snapshots; use only this snapshot for workflow sandbox status and restrictions.",
|
|
7055
|
+
"Status: active",
|
|
7056
|
+
`Workflow: /unipi:${command}`,
|
|
7057
|
+
`Sandbox level: ${level}`,
|
|
7058
|
+
`Blocked tool names: ${blockedLine}`,
|
|
7059
|
+
"Pi's provider tool schemas and tool order remain unchanged. Calls to blocked tool names are rejected by the workflow sandbox.",
|
|
7060
|
+
["Restrictions:", ...sandboxRestrictions(level).map((restriction) => `- ${restriction}`)].join("\n")
|
|
7061
|
+
].join("\n\n");
|
|
7062
|
+
}
|
|
7063
|
+
function formatInactiveSandboxSnapshot() {
|
|
7064
|
+
return [
|
|
7065
|
+
"# UniPi Workflow Sandbox Snapshot",
|
|
7066
|
+
"This snapshot supersedes all prior UniPi workflow sandbox snapshots; use only this snapshot for workflow sandbox status and restrictions.",
|
|
7067
|
+
"Status: inactive",
|
|
7068
|
+
"No UniPi workflow sandbox is active. Prior workflow sandbox restrictions no longer apply."
|
|
7069
|
+
].join("\n\n");
|
|
7070
|
+
}
|
|
7071
|
+
function latestEffectiveSandboxSnapshot(branch) {
|
|
7072
|
+
const messages = buildSessionContext(branch).messages;
|
|
7073
|
+
for (let index = messages.length - 1; index >= 0; index--) {
|
|
7074
|
+
const message = messages[index];
|
|
7075
|
+
if (message.role === "custom" && message.customType === WORKFLOW_SANDBOX_SNAPSHOT_TYPE) {
|
|
7076
|
+
return {
|
|
7077
|
+
content: message.content,
|
|
7078
|
+
details: message.details
|
|
7079
|
+
};
|
|
7080
|
+
}
|
|
7081
|
+
}
|
|
7082
|
+
return void 0;
|
|
7083
|
+
}
|
|
7084
|
+
function latestHistoricalSandboxSnapshot(branch) {
|
|
7085
|
+
for (let index = branch.length - 1; index >= 0; index--) {
|
|
7086
|
+
const entry = branch[index];
|
|
7087
|
+
if (entry.type === "custom_message" && entry.customType === WORKFLOW_SANDBOX_SNAPSHOT_TYPE) {
|
|
7088
|
+
return {
|
|
7089
|
+
content: entry.content,
|
|
7090
|
+
details: entry.details
|
|
7091
|
+
};
|
|
7092
|
+
}
|
|
7093
|
+
}
|
|
7094
|
+
return void 0;
|
|
7095
|
+
}
|
|
7096
|
+
function isActiveSnapshot(snapshot) {
|
|
7097
|
+
if (typeof snapshot.details?.active === "boolean") return snapshot.details.active;
|
|
7098
|
+
return typeof snapshot.content === "string" && snapshot.content.includes("Status: active");
|
|
7099
|
+
}
|
|
6937
7100
|
function workflow_default(pi) {
|
|
6938
7101
|
const workflowLifecycle = new WorkflowLifecycle();
|
|
7102
|
+
let ralphDetected = false;
|
|
7103
|
+
let sandboxCommand = null;
|
|
6939
7104
|
registerWorkflowCommands(pi, {
|
|
6940
7105
|
isRalphDetected: () => ralphDetected,
|
|
6941
|
-
|
|
6942
|
-
setActiveTools: (tools, level) => {
|
|
6943
|
-
pi.setActiveTools(tools);
|
|
6944
|
-
sandboxActive = true;
|
|
6945
|
-
currentSandboxLevel = level;
|
|
6946
|
-
currentSandboxTools = tools;
|
|
6947
|
-
},
|
|
6948
|
-
saveTools: (tools) => {
|
|
6949
|
-
savedTools = tools;
|
|
6950
|
-
},
|
|
6951
|
-
startWorkflow: (event) => {
|
|
7106
|
+
activateSandbox: (event) => {
|
|
6952
7107
|
if (!workflowLifecycle.start(event)) return false;
|
|
7108
|
+
sandboxCommand = event.command;
|
|
6953
7109
|
emitEvent(pi, UNIPI_EVENTS.WORKFLOW_START, event);
|
|
6954
7110
|
return true;
|
|
7111
|
+
},
|
|
7112
|
+
abortWorkflow: () => {
|
|
7113
|
+
sandboxCommand = null;
|
|
7114
|
+
workflowLifecycle.reset();
|
|
6955
7115
|
}
|
|
6956
7116
|
});
|
|
6957
7117
|
pi.on("tool_call", async (event, _ctx) => {
|
|
6958
|
-
if (!
|
|
6959
|
-
const
|
|
6960
|
-
if (!
|
|
7118
|
+
if (!sandboxCommand) return;
|
|
7119
|
+
const level = getSandboxLevel(sandboxCommand);
|
|
7120
|
+
if (!isToolAllowed(level, event.toolName)) {
|
|
7121
|
+
const blocked = getBlockedToolsForLevel(level);
|
|
6961
7122
|
return {
|
|
6962
7123
|
block: true,
|
|
6963
|
-
reason: `Tool "${event.toolName}" is not allowed in ${
|
|
7124
|
+
reason: `Tool "${event.toolName}" is not allowed in ${level} sandbox. Blocked: ${blocked.join(", ")}`
|
|
6964
7125
|
};
|
|
6965
7126
|
}
|
|
6966
7127
|
});
|
|
6967
|
-
pi.on("before_agent_start", async (
|
|
6968
|
-
|
|
6969
|
-
const
|
|
6970
|
-
const
|
|
6971
|
-
|
|
6972
|
-
|
|
6973
|
-
|
|
6974
|
-
|
|
6975
|
-
<sandbox>
|
|
6976
|
-
Sandbox mode: ${currentSandboxLevel}.
|
|
6977
|
-
Available tools: ${allowed.join(", ")}.${blockedLine}`;
|
|
6978
|
-
if (currentSandboxLevel === "brainstorm") {
|
|
6979
|
-
return {
|
|
6980
|
-
systemPrompt: event.systemPrompt + base + `
|
|
6981
|
-
The write tool is available but restricted to .unipi/docs/specs/ only.
|
|
6982
|
-
bash is available ONLY for specific setup use case (e.g., git init, mkdir). Do NOT use bash for reading files or listing directories \u2014 use grep, find, ls instead.
|
|
6983
|
-
Do NOT attempt to call blocked tools. Do NOT output tool call XML for them.
|
|
6984
|
-
If the user requests an action that requires a blocked tool, respond that you do not have access.
|
|
6985
|
-
</sandbox>`
|
|
6986
|
-
};
|
|
6987
|
-
}
|
|
6988
|
-
if (currentSandboxLevel === "write_unipi") {
|
|
7128
|
+
pi.on("before_agent_start", async (_event, ctx) => {
|
|
7129
|
+
const branch = ctx.sessionManager.getBranch();
|
|
7130
|
+
const latest = latestEffectiveSandboxSnapshot(branch);
|
|
7131
|
+
const historical = latestHistoricalSandboxSnapshot(branch);
|
|
7132
|
+
if (sandboxCommand) {
|
|
7133
|
+
const level = getSandboxLevel(sandboxCommand);
|
|
7134
|
+
const content = formatActiveSandboxSnapshot(sandboxCommand, level);
|
|
7135
|
+
if (latest?.content === content) return void 0;
|
|
6989
7136
|
return {
|
|
6990
|
-
|
|
6991
|
-
|
|
6992
|
-
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
|
|
7137
|
+
message: {
|
|
7138
|
+
customType: WORKFLOW_SANDBOX_SNAPSHOT_TYPE,
|
|
7139
|
+
content,
|
|
7140
|
+
display: false,
|
|
7141
|
+
details: {
|
|
7142
|
+
active: true,
|
|
7143
|
+
command: sandboxCommand,
|
|
7144
|
+
level
|
|
7145
|
+
}
|
|
7146
|
+
}
|
|
6997
7147
|
};
|
|
6998
7148
|
}
|
|
7149
|
+
const prior = latest ?? historical;
|
|
7150
|
+
if (!prior || !isActiveSnapshot(prior)) return void 0;
|
|
6999
7151
|
return {
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7152
|
+
message: {
|
|
7153
|
+
customType: WORKFLOW_SANDBOX_SNAPSHOT_TYPE,
|
|
7154
|
+
content: formatInactiveSandboxSnapshot(),
|
|
7155
|
+
display: false,
|
|
7156
|
+
details: {
|
|
7157
|
+
active: false
|
|
7158
|
+
}
|
|
7159
|
+
}
|
|
7004
7160
|
};
|
|
7005
7161
|
});
|
|
7006
7162
|
pi.on("agent_end", async (event, _ctx) => {
|
|
7007
|
-
if (sandboxActive && savedTools) {
|
|
7008
|
-
pi.setActiveTools(savedTools);
|
|
7009
|
-
savedTools = null;
|
|
7010
|
-
sandboxActive = false;
|
|
7011
|
-
currentSandboxLevel = null;
|
|
7012
|
-
currentSandboxTools = null;
|
|
7013
|
-
}
|
|
7014
7163
|
const completedWorkflow = workflowLifecycle.complete(event.messages);
|
|
7015
|
-
if (completedWorkflow)
|
|
7164
|
+
if (!completedWorkflow) return;
|
|
7165
|
+
sandboxCommand = null;
|
|
7166
|
+
emitEvent(pi, UNIPI_EVENTS.WORKFLOW_END, completedWorkflow);
|
|
7016
7167
|
});
|
|
7017
7168
|
pi.on("session_start", async (_event, ctx) => {
|
|
7018
7169
|
initUnipiDirs();
|
|
@@ -7025,7 +7176,7 @@ If the user requires an action that requires a blocked tool, respond that you do
|
|
|
7025
7176
|
if (!ralphDetected) {
|
|
7026
7177
|
try {
|
|
7027
7178
|
const allTools = pi.getAllTools();
|
|
7028
|
-
ralphDetected = allTools.some((
|
|
7179
|
+
ralphDetected = allTools.some((tool) => tool.name === "ralph_start");
|
|
7029
7180
|
} catch {
|
|
7030
7181
|
}
|
|
7031
7182
|
}
|
|
@@ -7036,14 +7187,11 @@ If the user requires an action that requires a blocked tool, respond that you do
|
|
|
7036
7187
|
});
|
|
7037
7188
|
pi.events.on(UNIPI_EVENTS.MODULE_READY, (data) => {
|
|
7038
7189
|
const event = data;
|
|
7039
|
-
if (event?.name === MODULES.RALPH)
|
|
7040
|
-
ralphDetected = true;
|
|
7041
|
-
}
|
|
7190
|
+
if (event?.name === MODULES.RALPH) ralphDetected = true;
|
|
7042
7191
|
});
|
|
7043
7192
|
pi.on("session_shutdown", async () => {
|
|
7044
7193
|
ralphDetected = false;
|
|
7045
|
-
|
|
7046
|
-
sandboxActive = false;
|
|
7194
|
+
sandboxCommand = null;
|
|
7047
7195
|
workflowLifecycle.reset();
|
|
7048
7196
|
});
|
|
7049
7197
|
}
|
|
@@ -7922,7 +8070,7 @@ function handleNuke(rest, ctx, pi) {
|
|
|
7922
8070
|
// packages/memory/index.ts
|
|
7923
8071
|
init_core();
|
|
7924
8072
|
init_storage();
|
|
7925
|
-
import { dirname as
|
|
8073
|
+
import { dirname as dirname7 } from "node:path";
|
|
7926
8074
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
7927
8075
|
|
|
7928
8076
|
// packages/memory/tools.ts
|
|
@@ -8630,7 +8778,7 @@ init_settings();
|
|
|
8630
8778
|
function getInfoRegistry2() {
|
|
8631
8779
|
return globalThis.__unipi_info_registry;
|
|
8632
8780
|
}
|
|
8633
|
-
var VERSION3 = getPackageVersion(
|
|
8781
|
+
var VERSION3 = getPackageVersion(dirname7(fileURLToPath4(import.meta.url)));
|
|
8634
8782
|
var projectStorage = null;
|
|
8635
8783
|
var orphanSyncPending = false;
|
|
8636
8784
|
function ensureOrphanSync(storage) {
|
|
@@ -8852,12 +9000,12 @@ function memory_default(pi) {
|
|
|
8852
9000
|
|
|
8853
9001
|
// packages/info-screen/index.ts
|
|
8854
9002
|
init_core();
|
|
8855
|
-
import { dirname as
|
|
9003
|
+
import { dirname as dirname10 } from "node:path";
|
|
8856
9004
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
8857
9005
|
|
|
8858
9006
|
// packages/info-screen/config.ts
|
|
8859
9007
|
import { readFileSync as readFileSync7, writeFileSync as writeFileSync7, existsSync as existsSync8, mkdirSync as mkdirSync6 } from "node:fs";
|
|
8860
|
-
import { join as join8, dirname as
|
|
9008
|
+
import { join as join8, dirname as dirname8 } from "node:path";
|
|
8861
9009
|
import { homedir as homedir4 } from "node:os";
|
|
8862
9010
|
|
|
8863
9011
|
// packages/info-screen/types.ts
|
|
@@ -8886,7 +9034,7 @@ function readSettingsFile() {
|
|
|
8886
9034
|
}
|
|
8887
9035
|
}
|
|
8888
9036
|
function writeSettingsFile(data) {
|
|
8889
|
-
const dir =
|
|
9037
|
+
const dir = dirname8(SETTINGS_PATH);
|
|
8890
9038
|
if (!existsSync8(dir)) {
|
|
8891
9039
|
mkdirSync6(dir, { recursive: true });
|
|
8892
9040
|
}
|
|
@@ -9187,7 +9335,7 @@ if (!globalThis.__unipi_info_registry) {
|
|
|
9187
9335
|
|
|
9188
9336
|
// packages/info-screen/core-groups.ts
|
|
9189
9337
|
init_core();
|
|
9190
|
-
import { readFileSync as readFileSync9, readdirSync as
|
|
9338
|
+
import { readFileSync as readFileSync9, readdirSync as readdirSync6, existsSync as existsSync10 } from "node:fs";
|
|
9191
9339
|
import { join as join10 } from "node:path";
|
|
9192
9340
|
import { homedir as homedir6 } from "node:os";
|
|
9193
9341
|
init_usage_parser();
|
|
@@ -9248,7 +9396,7 @@ function discoverExtensions() {
|
|
|
9248
9396
|
for (const dir of extensionDirs) {
|
|
9249
9397
|
if (!existsSync10(dir)) continue;
|
|
9250
9398
|
try {
|
|
9251
|
-
const entries =
|
|
9399
|
+
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
9252
9400
|
for (const entry of entries) {
|
|
9253
9401
|
const name = entry.name;
|
|
9254
9402
|
if (counted.has(name)) continue;
|
|
@@ -9322,7 +9470,7 @@ function discoverSkills() {
|
|
|
9322
9470
|
for (const dir of skillDirs) {
|
|
9323
9471
|
if (!existsSync10(dir)) continue;
|
|
9324
9472
|
try {
|
|
9325
|
-
const entries =
|
|
9473
|
+
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
9326
9474
|
for (const entry of entries) {
|
|
9327
9475
|
if (!entry.isDirectory()) continue;
|
|
9328
9476
|
const name = entry.name;
|
|
@@ -10433,7 +10581,7 @@ var SettingsOverlay = class _SettingsOverlay {
|
|
|
10433
10581
|
};
|
|
10434
10582
|
|
|
10435
10583
|
// packages/info-screen/index.ts
|
|
10436
|
-
var VERSION4 = getPackageVersion(
|
|
10584
|
+
var VERSION4 = getPackageVersion(dirname10(fileURLToPath5(import.meta.url)));
|
|
10437
10585
|
function info_screen_default(pi) {
|
|
10438
10586
|
setPiApi(pi);
|
|
10439
10587
|
registerCoreGroups();
|
|
@@ -10576,7 +10724,7 @@ function info_screen_default(pi) {
|
|
|
10576
10724
|
import { defineTool } from "@earendil-works/pi-coding-agent";
|
|
10577
10725
|
import { Text } from "@earendil-works/pi-tui";
|
|
10578
10726
|
import { Type as Type3 } from "typebox";
|
|
10579
|
-
import { existsSync as existsSync13, readdirSync as
|
|
10727
|
+
import { existsSync as existsSync13, readdirSync as readdirSync8 } from "node:fs";
|
|
10580
10728
|
import { join as join13 } from "node:path";
|
|
10581
10729
|
import { homedir as homedir9 } from "node:os";
|
|
10582
10730
|
|
|
@@ -10815,14 +10963,14 @@ ${agentPrompt}`;
|
|
|
10815
10963
|
init_model_resolver();
|
|
10816
10964
|
|
|
10817
10965
|
// packages/subagents/src/custom-agents.ts
|
|
10818
|
-
import { existsSync as existsSync11, readdirSync as
|
|
10966
|
+
import { existsSync as existsSync11, readdirSync as readdirSync7, readFileSync as readFileSync10, renameSync as renameSync4 } from "node:fs";
|
|
10819
10967
|
import { join as join11 } from "node:path";
|
|
10820
10968
|
import { homedir as homedir7 } from "node:os";
|
|
10821
10969
|
import { parseFrontmatter } from "@earendil-works/pi-coding-agent";
|
|
10822
10970
|
function backupCorrupted(filePath) {
|
|
10823
10971
|
const backupPath = filePath + ".bak";
|
|
10824
10972
|
try {
|
|
10825
|
-
|
|
10973
|
+
renameSync4(filePath, backupPath);
|
|
10826
10974
|
} catch {
|
|
10827
10975
|
}
|
|
10828
10976
|
}
|
|
@@ -10871,7 +11019,7 @@ function loadCustomAgents(cwd) {
|
|
|
10871
11019
|
const agents = /* @__PURE__ */ new Map();
|
|
10872
11020
|
const globalDir = getGlobalAgentsDir();
|
|
10873
11021
|
if (existsSync11(globalDir)) {
|
|
10874
|
-
const files =
|
|
11022
|
+
const files = readdirSync7(globalDir).filter((f) => f.endsWith(".md"));
|
|
10875
11023
|
for (const file of files) {
|
|
10876
11024
|
const agent = loadAgentFromFile(join11(globalDir, file), "global");
|
|
10877
11025
|
if (agent) {
|
|
@@ -10881,7 +11029,7 @@ function loadCustomAgents(cwd) {
|
|
|
10881
11029
|
}
|
|
10882
11030
|
const projectDir = getProjectAgentsDir(cwd);
|
|
10883
11031
|
if (existsSync11(projectDir)) {
|
|
10884
|
-
const files =
|
|
11032
|
+
const files = readdirSync7(projectDir).filter((f) => f.endsWith(".md"));
|
|
10885
11033
|
for (const file of files) {
|
|
10886
11034
|
const agent = loadAgentFromFile(join11(projectDir, file), "project");
|
|
10887
11035
|
if (agent) {
|
|
@@ -10908,17 +11056,17 @@ var FileLock = class {
|
|
|
10908
11056
|
*/
|
|
10909
11057
|
async acquire(filePath, agentId) {
|
|
10910
11058
|
while (this.locks.has(filePath)) {
|
|
10911
|
-
await new Promise((
|
|
11059
|
+
await new Promise((resolve14) => {
|
|
10912
11060
|
const queue = this.queues.get(filePath) ?? [];
|
|
10913
|
-
queue.push(
|
|
11061
|
+
queue.push(resolve14);
|
|
10914
11062
|
this.queues.set(filePath, queue);
|
|
10915
11063
|
});
|
|
10916
11064
|
}
|
|
10917
11065
|
let releaseFn;
|
|
10918
|
-
const promise = new Promise((
|
|
11066
|
+
const promise = new Promise((resolve14) => {
|
|
10919
11067
|
releaseFn = () => {
|
|
10920
11068
|
this.locks.delete(filePath);
|
|
10921
|
-
|
|
11069
|
+
resolve14();
|
|
10922
11070
|
const queue = this.queues.get(filePath);
|
|
10923
11071
|
if (queue && queue.length > 0) {
|
|
10924
11072
|
const next = queue.shift();
|
|
@@ -11236,7 +11384,7 @@ var AgentManager = class {
|
|
|
11236
11384
|
};
|
|
11237
11385
|
|
|
11238
11386
|
// packages/subagents/src/config.ts
|
|
11239
|
-
import { existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync11, renameSync as
|
|
11387
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync11, renameSync as renameSync5, writeFileSync as writeFileSync9 } from "node:fs";
|
|
11240
11388
|
import { join as join12 } from "node:path";
|
|
11241
11389
|
import { homedir as homedir8 } from "node:os";
|
|
11242
11390
|
var DEFAULT_CONFIG2 = {
|
|
@@ -11261,7 +11409,7 @@ function ensureDirExists(dirPath) {
|
|
|
11261
11409
|
function writeConfigAtomic(filePath, config) {
|
|
11262
11410
|
const tmpPath = filePath + ".tmp";
|
|
11263
11411
|
writeFileSync9(tmpPath, JSON.stringify(config, null, 2), "utf-8");
|
|
11264
|
-
|
|
11412
|
+
renameSync5(tmpPath, filePath);
|
|
11265
11413
|
}
|
|
11266
11414
|
function loadConfigFromPath(filePath) {
|
|
11267
11415
|
if (!existsSync12(filePath)) return null;
|
|
@@ -11277,7 +11425,7 @@ function loadConfigFromPath(filePath) {
|
|
|
11277
11425
|
function repairCorrupted(filePath) {
|
|
11278
11426
|
const backupPath = filePath + ".bak";
|
|
11279
11427
|
try {
|
|
11280
|
-
|
|
11428
|
+
renameSync5(filePath, backupPath);
|
|
11281
11429
|
} catch {
|
|
11282
11430
|
}
|
|
11283
11431
|
writeConfigAtomic(filePath, DEFAULT_CONFIG2);
|
|
@@ -12096,7 +12244,7 @@ function src_default(pi) {
|
|
|
12096
12244
|
for (const dir of [globalAgentsDir, workspaceAgentsDir]) {
|
|
12097
12245
|
try {
|
|
12098
12246
|
if (existsSync13(dir)) {
|
|
12099
|
-
for (const file of
|
|
12247
|
+
for (const file of readdirSync8(dir)) {
|
|
12100
12248
|
if (file.endsWith(".md") && !customTypes.includes(file.replace(".md", ""))) {
|
|
12101
12249
|
customTypes.push(file.replace(".md", ""));
|
|
12102
12250
|
}
|
|
@@ -12542,7 +12690,7 @@ Description: ${record.description}
|
|
|
12542
12690
|
// packages/btw/extensions/btw.ts
|
|
12543
12691
|
init_core();
|
|
12544
12692
|
import {
|
|
12545
|
-
buildSessionContext,
|
|
12693
|
+
buildSessionContext as buildSessionContext2,
|
|
12546
12694
|
createAgentSession as createAgentSession2,
|
|
12547
12695
|
createExtensionRuntime,
|
|
12548
12696
|
SessionManager as SessionManager2
|
|
@@ -12628,7 +12776,7 @@ function buildBtwSeedState(ctx, thread, mode) {
|
|
|
12628
12776
|
if (mode === "contextual") {
|
|
12629
12777
|
try {
|
|
12630
12778
|
messages.push(
|
|
12631
|
-
...
|
|
12779
|
+
...buildSessionContext2(ctx.sessionManager.getEntries(), ctx.sessionManager.getLeafId()).messages.filter(
|
|
12632
12780
|
(message) => !isVisibleBtwMessage(message)
|
|
12633
12781
|
)
|
|
12634
12782
|
);
|
|
@@ -14031,7 +14179,7 @@ ${summary}`;
|
|
|
14031
14179
|
|
|
14032
14180
|
// packages/web-api/src/index.ts
|
|
14033
14181
|
init_core();
|
|
14034
|
-
import { dirname as
|
|
14182
|
+
import { dirname as dirname11 } from "node:path";
|
|
14035
14183
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
14036
14184
|
|
|
14037
14185
|
// packages/web-api/src/tools.ts
|
|
@@ -16701,7 +16849,7 @@ var llmSummarizeProvider = {
|
|
|
16701
16849
|
registry.register(llmSummarizeProvider);
|
|
16702
16850
|
|
|
16703
16851
|
// packages/web-api/src/index.ts
|
|
16704
|
-
var VERSION5 = getPackageVersion(
|
|
16852
|
+
var VERSION5 = getPackageVersion(dirname11(fileURLToPath6(import.meta.url)));
|
|
16705
16853
|
function getInfoRegistry4() {
|
|
16706
16854
|
return globalThis.__unipi_info_registry;
|
|
16707
16855
|
}
|
|
@@ -16773,14 +16921,14 @@ function src_default2(pi) {
|
|
|
16773
16921
|
|
|
16774
16922
|
// packages/utility/src/index.ts
|
|
16775
16923
|
init_core();
|
|
16776
|
-
import { dirname as
|
|
16924
|
+
import { dirname as dirname14 } from "node:path";
|
|
16777
16925
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
16778
16926
|
|
|
16779
16927
|
// packages/utility/src/commands.ts
|
|
16780
16928
|
init_core();
|
|
16781
16929
|
|
|
16782
16930
|
// packages/utility/src/lifecycle/cleanup.ts
|
|
16783
|
-
import { existsSync as existsSync16, statSync as
|
|
16931
|
+
import { existsSync as existsSync16, statSync as statSync8, readdirSync as readdirSync10, unlinkSync as unlinkSync5, rmdirSync } from "node:fs";
|
|
16784
16932
|
import { join as join16 } from "node:path";
|
|
16785
16933
|
import { homedir as homedir12, tmpdir } from "node:os";
|
|
16786
16934
|
var DEFAULTS = {
|
|
@@ -16797,7 +16945,7 @@ function expandHome(path28) {
|
|
|
16797
16945
|
}
|
|
16798
16946
|
function isStale(path28, maxAgeDays) {
|
|
16799
16947
|
try {
|
|
16800
|
-
const stats =
|
|
16948
|
+
const stats = statSync8(path28);
|
|
16801
16949
|
const ageMs = Date.now() - stats.mtime.getTime();
|
|
16802
16950
|
return ageMs > maxAgeDays * 24 * 60 * 60 * 1e3;
|
|
16803
16951
|
} catch {
|
|
@@ -16809,7 +16957,7 @@ function hasWalLock(dbPath) {
|
|
|
16809
16957
|
const shmPath = dbPath + "-shm";
|
|
16810
16958
|
if (existsSync16(walPath)) {
|
|
16811
16959
|
try {
|
|
16812
|
-
const walStats =
|
|
16960
|
+
const walStats = statSync8(walPath);
|
|
16813
16961
|
const ageMs = Date.now() - walStats.mtime.getTime();
|
|
16814
16962
|
return ageMs > 5 * 60 * 1e3;
|
|
16815
16963
|
} catch {
|
|
@@ -16830,14 +16978,14 @@ function cleanDbs(options) {
|
|
|
16830
16978
|
const scanDir = (dir) => {
|
|
16831
16979
|
let entries;
|
|
16832
16980
|
try {
|
|
16833
|
-
entries =
|
|
16981
|
+
entries = readdirSync10(dir);
|
|
16834
16982
|
} catch {
|
|
16835
16983
|
return;
|
|
16836
16984
|
}
|
|
16837
16985
|
for (const entry of entries) {
|
|
16838
16986
|
const fullPath = join16(dir, entry);
|
|
16839
16987
|
try {
|
|
16840
|
-
const stats =
|
|
16988
|
+
const stats = statSync8(fullPath);
|
|
16841
16989
|
if (stats.isDirectory()) {
|
|
16842
16990
|
scanDir(fullPath);
|
|
16843
16991
|
continue;
|
|
@@ -16853,7 +17001,7 @@ function cleanDbs(options) {
|
|
|
16853
17001
|
const companion = fullPath + suffix;
|
|
16854
17002
|
if (existsSync16(companion)) {
|
|
16855
17003
|
unlinkSync5(companion);
|
|
16856
|
-
result.bytesFreed +=
|
|
17004
|
+
result.bytesFreed += statSync8(companion).size;
|
|
16857
17005
|
}
|
|
16858
17006
|
}
|
|
16859
17007
|
result.removed++;
|
|
@@ -16882,7 +17030,7 @@ function cleanTemps(options) {
|
|
|
16882
17030
|
const tmpDir = tmpdir();
|
|
16883
17031
|
let entries;
|
|
16884
17032
|
try {
|
|
16885
|
-
entries =
|
|
17033
|
+
entries = readdirSync10(tmpDir);
|
|
16886
17034
|
} catch {
|
|
16887
17035
|
return result;
|
|
16888
17036
|
}
|
|
@@ -16890,7 +17038,7 @@ function cleanTemps(options) {
|
|
|
16890
17038
|
if (!patterns.some((p) => p.test(entry))) continue;
|
|
16891
17039
|
const fullPath = join16(tmpDir, entry);
|
|
16892
17040
|
try {
|
|
16893
|
-
const stats =
|
|
17041
|
+
const stats = statSync8(fullPath);
|
|
16894
17042
|
if (!stats.isFile()) continue;
|
|
16895
17043
|
if (isStale(fullPath, options.tempMaxAgeDays)) {
|
|
16896
17044
|
result.bytesFreed += stats.size;
|
|
@@ -16922,14 +17070,14 @@ function cleanSessions(options) {
|
|
|
16922
17070
|
if (!existsSync16(sessionsDir)) return result;
|
|
16923
17071
|
let entries;
|
|
16924
17072
|
try {
|
|
16925
|
-
entries =
|
|
17073
|
+
entries = readdirSync10(sessionsDir);
|
|
16926
17074
|
} catch {
|
|
16927
17075
|
return result;
|
|
16928
17076
|
}
|
|
16929
17077
|
for (const entry of entries) {
|
|
16930
17078
|
const fullPath = join16(sessionsDir, entry);
|
|
16931
17079
|
try {
|
|
16932
|
-
const stats =
|
|
17080
|
+
const stats = statSync8(fullPath);
|
|
16933
17081
|
if (!stats.isDirectory()) continue;
|
|
16934
17082
|
if (isStale(fullPath, options.sessionMaxAgeDays)) {
|
|
16935
17083
|
result.bytesFreed += stats.size;
|
|
@@ -16937,10 +17085,10 @@ function cleanSessions(options) {
|
|
|
16937
17085
|
if (!options.dryRun) {
|
|
16938
17086
|
try {
|
|
16939
17087
|
const removeRecursive = (dir) => {
|
|
16940
|
-
const items =
|
|
17088
|
+
const items = readdirSync10(dir);
|
|
16941
17089
|
for (const item of items) {
|
|
16942
17090
|
const itemPath = join16(dir, item);
|
|
16943
|
-
const itemStats =
|
|
17091
|
+
const itemStats = statSync8(itemPath);
|
|
16944
17092
|
if (itemStats.isDirectory()) {
|
|
16945
17093
|
removeRecursive(itemPath);
|
|
16946
17094
|
} else {
|
|
@@ -16973,14 +17121,14 @@ function cleanCache(options) {
|
|
|
16973
17121
|
if (!existsSync16(cacheDir)) return result;
|
|
16974
17122
|
let entries;
|
|
16975
17123
|
try {
|
|
16976
|
-
entries =
|
|
17124
|
+
entries = readdirSync10(cacheDir);
|
|
16977
17125
|
} catch {
|
|
16978
17126
|
return result;
|
|
16979
17127
|
}
|
|
16980
17128
|
for (const entry of entries) {
|
|
16981
17129
|
const fullPath = join16(cacheDir, entry);
|
|
16982
17130
|
try {
|
|
16983
|
-
const stats =
|
|
17131
|
+
const stats = statSync8(fullPath);
|
|
16984
17132
|
if (!stats.isFile()) continue;
|
|
16985
17133
|
if (isStale(fullPath, options.tempMaxAgeDays)) {
|
|
16986
17134
|
result.bytesFreed += stats.size;
|
|
@@ -17044,7 +17192,7 @@ function formatCleanupReport(report) {
|
|
|
17044
17192
|
}
|
|
17045
17193
|
|
|
17046
17194
|
// packages/utility/src/diagnostics/engine.ts
|
|
17047
|
-
import { existsSync as existsSync17, accessSync, constants } from "node:fs";
|
|
17195
|
+
import { existsSync as existsSync17, accessSync as accessSync2, constants as constants2 } from "node:fs";
|
|
17048
17196
|
import { join as join17 } from "node:path";
|
|
17049
17197
|
import { homedir as homedir13 } from "node:os";
|
|
17050
17198
|
function expandHome2(path28) {
|
|
@@ -17055,7 +17203,7 @@ function expandHome2(path28) {
|
|
|
17055
17203
|
}
|
|
17056
17204
|
function isReadable(path28) {
|
|
17057
17205
|
try {
|
|
17058
|
-
|
|
17206
|
+
accessSync2(path28, constants2.R_OK);
|
|
17059
17207
|
return true;
|
|
17060
17208
|
} catch {
|
|
17061
17209
|
return false;
|
|
@@ -17063,7 +17211,7 @@ function isReadable(path28) {
|
|
|
17063
17211
|
}
|
|
17064
17212
|
function isWritable(path28) {
|
|
17065
17213
|
try {
|
|
17066
|
-
|
|
17214
|
+
accessSync2(path28, constants2.W_OK);
|
|
17067
17215
|
return true;
|
|
17068
17216
|
} catch {
|
|
17069
17217
|
return false;
|
|
@@ -19333,7 +19481,7 @@ function registerInfoScreen(pi) {
|
|
|
19333
19481
|
}
|
|
19334
19482
|
|
|
19335
19483
|
// packages/utility/src/index.ts
|
|
19336
|
-
var VERSION6 = getPackageVersion(
|
|
19484
|
+
var VERSION6 = getPackageVersion(dirname14(fileURLToPath7(import.meta.url)));
|
|
19337
19485
|
var firstMessageSeen = false;
|
|
19338
19486
|
var firstUserText = "";
|
|
19339
19487
|
var firstInputCtx = null;
|
|
@@ -19545,7 +19693,7 @@ function registerUtilityTools(pi, nameBadgeState) {
|
|
|
19545
19693
|
|
|
19546
19694
|
// packages/ask-user/index.ts
|
|
19547
19695
|
init_core();
|
|
19548
|
-
import { dirname as
|
|
19696
|
+
import { dirname as dirname15 } from "node:path";
|
|
19549
19697
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
19550
19698
|
|
|
19551
19699
|
// packages/ask-user/tools.ts
|
|
@@ -20930,7 +21078,7 @@ function registerAskUserCommands(pi) {
|
|
|
20930
21078
|
}
|
|
20931
21079
|
|
|
20932
21080
|
// packages/ask-user/index.ts
|
|
20933
|
-
var VERSION7 = getPackageVersion(
|
|
21081
|
+
var VERSION7 = getPackageVersion(dirname15(fileURLToPath8(import.meta.url)));
|
|
20934
21082
|
function ask_user_default(pi) {
|
|
20935
21083
|
registerAskUserTools(pi);
|
|
20936
21084
|
registerAskUserCommands(pi);
|
|
@@ -20946,7 +21094,7 @@ function ask_user_default(pi) {
|
|
|
20946
21094
|
|
|
20947
21095
|
// packages/mcp/src/index.ts
|
|
20948
21096
|
init_core();
|
|
20949
|
-
import { dirname as
|
|
21097
|
+
import { dirname as dirname18 } from "node:path";
|
|
20950
21098
|
import { fileURLToPath as fileURLToPath9 } from "node:url";
|
|
20951
21099
|
|
|
20952
21100
|
// packages/mcp/src/config/manager.ts
|
|
@@ -21444,7 +21592,7 @@ var McpClient = class {
|
|
|
21444
21592
|
if (this.connected) {
|
|
21445
21593
|
throw new Error("McpClient is already connected");
|
|
21446
21594
|
}
|
|
21447
|
-
return new Promise((
|
|
21595
|
+
return new Promise((resolve14, reject) => {
|
|
21448
21596
|
try {
|
|
21449
21597
|
const mergedEnv = { ...process.env, ...env };
|
|
21450
21598
|
this.process = spawn2(command, args, {
|
|
@@ -21493,7 +21641,7 @@ Stderr: ${this.stderrBuffer}`
|
|
|
21493
21641
|
}).then(() => {
|
|
21494
21642
|
this.sendNotification("notifications/initialized", {});
|
|
21495
21643
|
this.connected = true;
|
|
21496
|
-
|
|
21644
|
+
resolve14();
|
|
21497
21645
|
}).catch((err) => {
|
|
21498
21646
|
this.cleanup();
|
|
21499
21647
|
reject(
|
|
@@ -21537,16 +21685,16 @@ Stderr: ${this.stderrBuffer}`
|
|
|
21537
21685
|
this.sendNotification("shutdown", {});
|
|
21538
21686
|
} catch {
|
|
21539
21687
|
}
|
|
21540
|
-
await new Promise((
|
|
21541
|
-
const timer = setTimeout(() =>
|
|
21688
|
+
await new Promise((resolve14) => {
|
|
21689
|
+
const timer = setTimeout(() => resolve14(), 500);
|
|
21542
21690
|
this.process.on("exit", () => {
|
|
21543
21691
|
clearTimeout(timer);
|
|
21544
|
-
|
|
21692
|
+
resolve14();
|
|
21545
21693
|
});
|
|
21546
21694
|
try {
|
|
21547
21695
|
this.process.kill("SIGTERM");
|
|
21548
21696
|
} catch {
|
|
21549
|
-
|
|
21697
|
+
resolve14();
|
|
21550
21698
|
}
|
|
21551
21699
|
});
|
|
21552
21700
|
if (this.process && !this.process.killed) {
|
|
@@ -21576,7 +21724,7 @@ Stderr: ${this.stderrBuffer}`
|
|
|
21576
21724
|
}
|
|
21577
21725
|
}
|
|
21578
21726
|
sendRequest(method, params) {
|
|
21579
|
-
return new Promise((
|
|
21727
|
+
return new Promise((resolve14, reject) => {
|
|
21580
21728
|
if (!this.process?.stdin) {
|
|
21581
21729
|
reject(new Error("MCP server process not available"));
|
|
21582
21730
|
return;
|
|
@@ -21596,7 +21744,7 @@ Stderr: ${this.stderrBuffer}`
|
|
|
21596
21744
|
)
|
|
21597
21745
|
);
|
|
21598
21746
|
}, this.timeoutMs);
|
|
21599
|
-
this.pending.set(id, { resolve:
|
|
21747
|
+
this.pending.set(id, { resolve: resolve14, reject, timer });
|
|
21600
21748
|
const message = JSON.stringify(request) + "\n";
|
|
21601
21749
|
this.process.stdin.write(message);
|
|
21602
21750
|
});
|
|
@@ -21659,15 +21807,45 @@ Stderr: ${this.stderrBuffer}`
|
|
|
21659
21807
|
|
|
21660
21808
|
// packages/mcp/src/bridge/translator.ts
|
|
21661
21809
|
init_core();
|
|
21810
|
+
function compareCodeUnits(left, right) {
|
|
21811
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
21812
|
+
}
|
|
21813
|
+
function isObject(value) {
|
|
21814
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21815
|
+
}
|
|
21816
|
+
var LITERAL_VALUE_KEYWORDS = /* @__PURE__ */ new Set(["const", "default", "enum", "examples"]);
|
|
21817
|
+
function canonicalizeValue(value, key, normalizeSchemaKeywords = true) {
|
|
21818
|
+
if (Array.isArray(value)) {
|
|
21819
|
+
if (normalizeSchemaKeywords && key === "required" && value.every((item) => typeof item === "string")) {
|
|
21820
|
+
return [...new Set(value)].sort(compareCodeUnits);
|
|
21821
|
+
}
|
|
21822
|
+
return value.map((item) => canonicalizeValue(item, void 0, normalizeSchemaKeywords));
|
|
21823
|
+
}
|
|
21824
|
+
if (!isObject(value)) return value;
|
|
21825
|
+
const canonical = {};
|
|
21826
|
+
for (const objectKey of Object.keys(value).sort(compareCodeUnits)) {
|
|
21827
|
+
const childNormalizesSchemaKeywords = normalizeSchemaKeywords && !LITERAL_VALUE_KEYWORDS.has(objectKey);
|
|
21828
|
+
canonical[objectKey] = canonicalizeValue(
|
|
21829
|
+
value[objectKey],
|
|
21830
|
+
objectKey,
|
|
21831
|
+
childNormalizesSchemaKeywords
|
|
21832
|
+
);
|
|
21833
|
+
}
|
|
21834
|
+
return canonical;
|
|
21835
|
+
}
|
|
21836
|
+
function canonicalizeJsonSchema(schema) {
|
|
21837
|
+
return canonicalizeValue(schema);
|
|
21838
|
+
}
|
|
21662
21839
|
function translateMcpTool(mcpTool, serverName, client) {
|
|
21663
21840
|
const separator = MCP_DEFAULTS.TOOL_NAME_SEPARATOR;
|
|
21664
21841
|
const toolName = `${serverName}${separator}${mcpTool.name}`;
|
|
21665
|
-
const inputSchema = mcpTool.inputSchema
|
|
21666
|
-
const
|
|
21842
|
+
const inputSchema = isObject(mcpTool.inputSchema) ? mcpTool.inputSchema : {};
|
|
21843
|
+
const normalizedSchema = {
|
|
21667
21844
|
type: "object",
|
|
21668
|
-
properties: inputSchema.properties
|
|
21669
|
-
required: inputSchema.required
|
|
21845
|
+
properties: isObject(inputSchema.properties) ? inputSchema.properties : {},
|
|
21846
|
+
required: Array.isArray(inputSchema.required) ? inputSchema.required : []
|
|
21670
21847
|
};
|
|
21848
|
+
const parameters = canonicalizeJsonSchema(normalizedSchema);
|
|
21671
21849
|
const description = [
|
|
21672
21850
|
mcpTool.description || `MCP tool: ${mcpTool.name}`,
|
|
21673
21851
|
`[Server: ${serverName}]`
|
|
@@ -21725,6 +21903,7 @@ Check server status via /unipi:mcp-settings`
|
|
|
21725
21903
|
};
|
|
21726
21904
|
return {
|
|
21727
21905
|
name: toolName,
|
|
21906
|
+
label: toolName,
|
|
21728
21907
|
description,
|
|
21729
21908
|
parameters,
|
|
21730
21909
|
execute: execute2
|
|
@@ -21737,26 +21916,125 @@ var ServerRegistry = class {
|
|
|
21737
21916
|
emitEvent;
|
|
21738
21917
|
registerTool;
|
|
21739
21918
|
unregisterTool;
|
|
21919
|
+
canUnregisterTools;
|
|
21740
21920
|
timeoutMs;
|
|
21921
|
+
createClient;
|
|
21741
21922
|
constructor(options) {
|
|
21742
21923
|
this.emitEvent = options.emitEvent;
|
|
21743
21924
|
this.registerTool = options.registerTool;
|
|
21744
21925
|
this.unregisterTool = options.unregisterTool;
|
|
21926
|
+
this.canUnregisterTools = options.canUnregisterTools ?? true;
|
|
21745
21927
|
this.timeoutMs = options.timeoutMs ?? MCP_DEFAULTS.STARTUP_TIMEOUT_MS;
|
|
21928
|
+
this.createClient = options.createClient ?? (() => new McpClient({ timeoutMs: this.timeoutMs }));
|
|
21746
21929
|
}
|
|
21747
21930
|
/**
|
|
21748
|
-
* Start
|
|
21931
|
+
* Start one MCP server. Discovery completes before its tools are registered,
|
|
21932
|
+
* and registration always follows final Pi tool-name order.
|
|
21749
21933
|
*/
|
|
21750
21934
|
async startServer(resolved) {
|
|
21751
|
-
|
|
21752
|
-
|
|
21935
|
+
await this.startServers([resolved]);
|
|
21936
|
+
const state = this.getServerState(resolved.name);
|
|
21937
|
+
if (state?.status === "error") {
|
|
21938
|
+
throw new Error(state.error ?? `MCP server "${resolved.name}" failed to start`);
|
|
21939
|
+
}
|
|
21940
|
+
}
|
|
21941
|
+
/**
|
|
21942
|
+
* Start MCP servers behind a discovery barrier.
|
|
21943
|
+
*
|
|
21944
|
+
* Connections and tool discovery run in parallel. Once every server has
|
|
21945
|
+
* either prepared or failed, tools from all successful servers are checked
|
|
21946
|
+
* for duplicate final names, sorted, and only then registered with Pi.
|
|
21947
|
+
* Individual connection failures remain represented by error registry
|
|
21948
|
+
* entries and do not prevent tools from other servers being registered.
|
|
21949
|
+
*/
|
|
21950
|
+
async startServers(resolvedServers) {
|
|
21951
|
+
if (resolvedServers.length === 0) return;
|
|
21952
|
+
const names = /* @__PURE__ */ new Set();
|
|
21953
|
+
for (const { name } of resolvedServers) {
|
|
21954
|
+
if (names.has(name)) {
|
|
21955
|
+
throw new Error(`Duplicate MCP server name in startup batch: "${name}"`);
|
|
21956
|
+
}
|
|
21957
|
+
names.add(name);
|
|
21958
|
+
}
|
|
21959
|
+
const replacementCount = [...names].filter((name) => this.entries.has(name)).length;
|
|
21960
|
+
if (this.entries.size - replacementCount + resolvedServers.length > MCP_DEFAULTS.MAX_SERVERS) {
|
|
21753
21961
|
throw new Error(
|
|
21754
21962
|
`Maximum number of MCP servers (${MCP_DEFAULTS.MAX_SERVERS}) reached. Stop a server before starting a new one.`
|
|
21755
21963
|
);
|
|
21756
21964
|
}
|
|
21757
|
-
|
|
21758
|
-
|
|
21965
|
+
await Promise.all(
|
|
21966
|
+
[...names].filter((name) => this.entries.has(name)).map((name) => this.stopServer(name))
|
|
21967
|
+
);
|
|
21968
|
+
const settled = await Promise.allSettled(
|
|
21969
|
+
resolvedServers.map((resolved) => this.prepareServer(resolved))
|
|
21970
|
+
);
|
|
21971
|
+
const prepared = settled.filter((result) => result.status === "fulfilled").map((result) => result.value);
|
|
21972
|
+
if (prepared.length === 0) return;
|
|
21973
|
+
const registrations = prepared.flatMap(({ entry, tools }) => tools.map((tool) => ({ entry, tool }))).sort((left, right) => compareCodeUnits(left.tool.name, right.tool.name));
|
|
21974
|
+
try {
|
|
21975
|
+
this.assertUniqueFinalToolNames(registrations.map(({ tool }) => tool.name));
|
|
21976
|
+
} catch (error) {
|
|
21977
|
+
await this.failPreparedServers(prepared, error);
|
|
21978
|
+
throw error;
|
|
21979
|
+
}
|
|
21980
|
+
const registeredNames = [];
|
|
21981
|
+
try {
|
|
21982
|
+
for (const { tool } of registrations) {
|
|
21983
|
+
this.registerTool(tool);
|
|
21984
|
+
registeredNames.push(tool.name);
|
|
21985
|
+
}
|
|
21986
|
+
} catch (error) {
|
|
21987
|
+
if (this.canUnregisterTools) {
|
|
21988
|
+
for (const toolName of registeredNames.reverse()) {
|
|
21989
|
+
try {
|
|
21990
|
+
this.unregisterTool(toolName);
|
|
21991
|
+
} catch {
|
|
21992
|
+
}
|
|
21993
|
+
}
|
|
21994
|
+
await this.failPreparedServers(prepared, error);
|
|
21995
|
+
} else {
|
|
21996
|
+
const message = `${error instanceof Error ? error.message : String(error)}; some MCP tools remain registered until Pi restarts`;
|
|
21997
|
+
for (const { entry, client, tools } of prepared) {
|
|
21998
|
+
const toolNames = tools.map((tool) => tool.name).filter((name) => registeredNames.includes(name)).sort(compareCodeUnits);
|
|
21999
|
+
entry.toolNames = toolNames;
|
|
22000
|
+
entry.state = {
|
|
22001
|
+
...entry.state,
|
|
22002
|
+
status: "error",
|
|
22003
|
+
pid: client.pid,
|
|
22004
|
+
toolCount: toolNames.length,
|
|
22005
|
+
error: message
|
|
22006
|
+
};
|
|
22007
|
+
this.emitEvent(UNIPI_EVENTS.MCP_SERVER_ERROR, {
|
|
22008
|
+
name: entry.name,
|
|
22009
|
+
error: message
|
|
22010
|
+
});
|
|
22011
|
+
}
|
|
22012
|
+
}
|
|
22013
|
+
throw error;
|
|
21759
22014
|
}
|
|
22015
|
+
for (const { entry, client, tools } of [...prepared].sort((left, right) => compareCodeUnits(left.entry.name, right.entry.name))) {
|
|
22016
|
+
const toolNames = tools.map((tool) => tool.name).sort(compareCodeUnits);
|
|
22017
|
+
entry.toolNames = toolNames;
|
|
22018
|
+
entry.state = {
|
|
22019
|
+
...entry.state,
|
|
22020
|
+
status: "running",
|
|
22021
|
+
pid: client.pid,
|
|
22022
|
+
toolCount: toolNames.length
|
|
22023
|
+
};
|
|
22024
|
+
this.emitEvent(UNIPI_EVENTS.MCP_SERVER_STARTED, {
|
|
22025
|
+
name: entry.name,
|
|
22026
|
+
toolCount: toolNames.length
|
|
22027
|
+
});
|
|
22028
|
+
if (toolNames.length > 0) {
|
|
22029
|
+
this.emitEvent(UNIPI_EVENTS.MCP_TOOLS_REGISTERED, {
|
|
22030
|
+
serverName: entry.name,
|
|
22031
|
+
toolNames
|
|
22032
|
+
});
|
|
22033
|
+
}
|
|
22034
|
+
}
|
|
22035
|
+
}
|
|
22036
|
+
async prepareServer(resolved) {
|
|
22037
|
+
const { name, def } = resolved;
|
|
21760
22038
|
const state = {
|
|
21761
22039
|
name,
|
|
21762
22040
|
status: "starting",
|
|
@@ -21771,73 +22049,74 @@ var ServerRegistry = class {
|
|
|
21771
22049
|
toolNames: []
|
|
21772
22050
|
};
|
|
21773
22051
|
this.entries.set(name, entry);
|
|
22052
|
+
let client = null;
|
|
21774
22053
|
try {
|
|
21775
22054
|
const safeCommand = typeof def.command === "string" ? def.command : String(def.command);
|
|
21776
22055
|
const safeArgs = Array.isArray(def.args) ? def.args : [];
|
|
21777
22056
|
let safeEnv;
|
|
21778
|
-
if (def.env !== void 0 && def.env !== null) {
|
|
21779
|
-
|
|
21780
|
-
|
|
21781
|
-
|
|
21782
|
-
|
|
21783
|
-
|
|
21784
|
-
|
|
21785
|
-
|
|
21786
|
-
|
|
21787
|
-
|
|
21788
|
-
await
|
|
21789
|
-
|
|
21790
|
-
|
|
21791
|
-
|
|
21792
|
-
|
|
21793
|
-
|
|
21794
|
-
|
|
21795
|
-
toolNames.push(piTool.name);
|
|
21796
|
-
}
|
|
21797
|
-
entry.state = {
|
|
21798
|
-
...state,
|
|
21799
|
-
status: "running",
|
|
21800
|
-
pid: client.pid,
|
|
21801
|
-
toolCount: toolNames.length
|
|
21802
|
-
};
|
|
21803
|
-
entry.toolNames = toolNames;
|
|
21804
|
-
this.emitEvent(UNIPI_EVENTS.MCP_SERVER_STARTED, {
|
|
21805
|
-
name,
|
|
21806
|
-
toolCount: toolNames.length
|
|
21807
|
-
});
|
|
21808
|
-
if (toolNames.length > 0) {
|
|
21809
|
-
this.emitEvent(UNIPI_EVENTS.MCP_TOOLS_REGISTERED, {
|
|
21810
|
-
serverName: name,
|
|
21811
|
-
toolNames
|
|
21812
|
-
});
|
|
21813
|
-
}
|
|
21814
|
-
} catch (err) {
|
|
21815
|
-
const error = err instanceof Error ? err.message : String(err);
|
|
21816
|
-
entry.state = {
|
|
21817
|
-
...state,
|
|
21818
|
-
status: "error",
|
|
21819
|
-
error
|
|
21820
|
-
};
|
|
21821
|
-
if (entry.client) {
|
|
22057
|
+
if (def.env !== void 0 && def.env !== null && typeof def.env === "object" && !Array.isArray(def.env)) {
|
|
22058
|
+
safeEnv = {};
|
|
22059
|
+
for (const [key, value] of Object.entries(def.env)) {
|
|
22060
|
+
safeEnv[key] = typeof value === "string" ? value : String(value);
|
|
22061
|
+
}
|
|
22062
|
+
}
|
|
22063
|
+
client = this.createClient();
|
|
22064
|
+
const connectedClient = client;
|
|
22065
|
+
await connectedClient.connect(safeCommand, safeArgs, safeEnv);
|
|
22066
|
+
entry.client = connectedClient;
|
|
22067
|
+
const mcpTools = await connectedClient.listTools();
|
|
22068
|
+
const tools = mcpTools.map((tool) => translateMcpTool(tool, name, connectedClient)).sort((left, right) => compareCodeUnits(left.name, right.name));
|
|
22069
|
+
return { entry, client: connectedClient, tools };
|
|
22070
|
+
} catch (error) {
|
|
22071
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
22072
|
+
entry.state = { ...state, status: "error", error: message };
|
|
22073
|
+
if (client) {
|
|
21822
22074
|
try {
|
|
21823
|
-
await
|
|
22075
|
+
await client.disconnect();
|
|
21824
22076
|
} catch {
|
|
21825
22077
|
}
|
|
21826
|
-
entry.client = null;
|
|
21827
22078
|
}
|
|
21828
|
-
|
|
21829
|
-
|
|
21830
|
-
|
|
21831
|
-
});
|
|
21832
|
-
throw err;
|
|
22079
|
+
entry.client = null;
|
|
22080
|
+
this.emitEvent(UNIPI_EVENTS.MCP_SERVER_ERROR, { name, error: message });
|
|
22081
|
+
throw error;
|
|
21833
22082
|
}
|
|
21834
22083
|
}
|
|
21835
|
-
|
|
21836
|
-
|
|
21837
|
-
|
|
22084
|
+
assertUniqueFinalToolNames(newNames) {
|
|
22085
|
+
const existingNames = this.getActive().flatMap((state) => this.entries.get(state.name)?.toolNames ?? []);
|
|
22086
|
+
const seen = /* @__PURE__ */ new Set();
|
|
22087
|
+
const duplicates = /* @__PURE__ */ new Set();
|
|
22088
|
+
for (const name of [...existingNames, ...newNames]) {
|
|
22089
|
+
if (seen.has(name)) duplicates.add(name);
|
|
22090
|
+
seen.add(name);
|
|
22091
|
+
}
|
|
22092
|
+
if (duplicates.size > 0) {
|
|
22093
|
+
throw new Error(
|
|
22094
|
+
`Duplicate final MCP tool name(s): ${[...duplicates].sort(compareCodeUnits).join(", ")}`
|
|
22095
|
+
);
|
|
22096
|
+
}
|
|
22097
|
+
}
|
|
22098
|
+
async failPreparedServers(prepared, error) {
|
|
22099
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
22100
|
+
await Promise.all(prepared.map(async ({ entry, client }) => {
|
|
22101
|
+
entry.state = { ...entry.state, status: "error", toolCount: 0, error: message };
|
|
22102
|
+
entry.toolNames = [];
|
|
22103
|
+
try {
|
|
22104
|
+
await client.disconnect();
|
|
22105
|
+
} catch {
|
|
22106
|
+
}
|
|
22107
|
+
entry.client = null;
|
|
22108
|
+
this.emitEvent(UNIPI_EVENTS.MCP_SERVER_ERROR, { name: entry.name, error: message });
|
|
22109
|
+
}));
|
|
22110
|
+
}
|
|
22111
|
+
/** Stop an MCP server: unregister tools, disconnect client. */
|
|
21838
22112
|
async stopServer(name) {
|
|
21839
22113
|
const entry = this.entries.get(name);
|
|
21840
22114
|
if (!entry) return;
|
|
22115
|
+
if (entry.toolNames.length > 0 && !this.canUnregisterTools) {
|
|
22116
|
+
throw new Error(
|
|
22117
|
+
"This Pi version cannot remove MCP tools at runtime; restart Pi to change the MCP tool set."
|
|
22118
|
+
);
|
|
22119
|
+
}
|
|
21841
22120
|
for (const toolName of entry.toolNames) {
|
|
21842
22121
|
this.unregisterTool(toolName);
|
|
21843
22122
|
}
|
|
@@ -21854,78 +22133,63 @@ var ServerRegistry = class {
|
|
|
21854
22133
|
}
|
|
21855
22134
|
entry.client = null;
|
|
21856
22135
|
}
|
|
21857
|
-
entry.state = {
|
|
21858
|
-
...entry.state,
|
|
21859
|
-
status: "stopped",
|
|
21860
|
-
toolCount: 0
|
|
21861
|
-
};
|
|
22136
|
+
entry.state = { ...entry.state, status: "stopped", toolCount: 0 };
|
|
21862
22137
|
entry.toolNames = [];
|
|
21863
22138
|
this.emitEvent(UNIPI_EVENTS.MCP_SERVER_STOPPED, { name });
|
|
21864
22139
|
}
|
|
21865
|
-
/**
|
|
21866
|
-
* Restart an MCP server: stop then start.
|
|
21867
|
-
*/
|
|
22140
|
+
/** Restart an MCP server: stop then start. */
|
|
21868
22141
|
async restartServer(name) {
|
|
21869
22142
|
const entry = this.entries.get(name);
|
|
21870
|
-
if (!entry) {
|
|
21871
|
-
throw new Error(`Server '${name}' not found in registry`);
|
|
21872
|
-
}
|
|
22143
|
+
if (!entry) throw new Error(`Server '${name}' not found in registry`);
|
|
21873
22144
|
const resolved = entry.resolved;
|
|
21874
22145
|
await this.stopServer(name);
|
|
21875
22146
|
await this.startServer(resolved);
|
|
21876
22147
|
}
|
|
21877
|
-
/**
|
|
21878
|
-
* Stop all running servers.
|
|
21879
|
-
*/
|
|
22148
|
+
/** Stop all running servers when runtime unregistration is supported. */
|
|
21880
22149
|
async stopAll() {
|
|
21881
22150
|
const names = Array.from(this.entries.keys());
|
|
21882
22151
|
await Promise.allSettled(names.map((name) => this.stopServer(name)));
|
|
21883
22152
|
}
|
|
21884
|
-
/**
|
|
21885
|
-
|
|
21886
|
-
|
|
22153
|
+
/** Disconnect clients during extension shutdown without claiming tools were removed. */
|
|
22154
|
+
async disconnectAll() {
|
|
22155
|
+
await Promise.allSettled([...this.entries.values()].map(async (entry) => {
|
|
22156
|
+
if (!entry.client) return;
|
|
22157
|
+
try {
|
|
22158
|
+
await entry.client.disconnect();
|
|
22159
|
+
} finally {
|
|
22160
|
+
entry.client = null;
|
|
22161
|
+
}
|
|
22162
|
+
}));
|
|
22163
|
+
}
|
|
22164
|
+
/** Get all registered server states. */
|
|
21887
22165
|
getAll() {
|
|
21888
|
-
return Array.from(this.entries.values()).map((
|
|
22166
|
+
return Array.from(this.entries.values()).map((entry) => entry.state);
|
|
21889
22167
|
}
|
|
21890
|
-
/**
|
|
21891
|
-
* Get states of running servers.
|
|
21892
|
-
*/
|
|
22168
|
+
/** Get states of running servers. */
|
|
21893
22169
|
getActive() {
|
|
21894
|
-
return this.getAll().filter((
|
|
22170
|
+
return this.getAll().filter((state) => state.status === "running");
|
|
21895
22171
|
}
|
|
21896
|
-
/**
|
|
21897
|
-
* Get states of servers in error state.
|
|
21898
|
-
*/
|
|
22172
|
+
/** Get states of servers in error state. */
|
|
21899
22173
|
getFailed() {
|
|
21900
|
-
return this.getAll().filter((
|
|
22174
|
+
return this.getAll().filter((state) => state.status === "error");
|
|
21901
22175
|
}
|
|
21902
|
-
/**
|
|
21903
|
-
* Get total number of tools across all active servers.
|
|
21904
|
-
*/
|
|
22176
|
+
/** Get total number of tools across all active servers. */
|
|
21905
22177
|
getTotalToolCount() {
|
|
21906
|
-
return this.getActive().reduce((sum,
|
|
22178
|
+
return this.getActive().reduce((sum, state) => sum + state.toolCount, 0);
|
|
21907
22179
|
}
|
|
21908
|
-
/**
|
|
21909
|
-
* Get the state of a specific server.
|
|
21910
|
-
*/
|
|
22180
|
+
/** Get the state of a specific server. */
|
|
21911
22181
|
getServerState(name) {
|
|
21912
22182
|
return this.entries.get(name)?.state ?? null;
|
|
21913
22183
|
}
|
|
21914
|
-
/**
|
|
21915
|
-
* Get the full registry entry for a server.
|
|
21916
|
-
*/
|
|
22184
|
+
/** Get the full registry entry for a server. */
|
|
21917
22185
|
getEntry(name) {
|
|
21918
22186
|
return this.entries.get(name) ?? null;
|
|
21919
22187
|
}
|
|
21920
|
-
/**
|
|
21921
|
-
* Check if a server exists in the registry.
|
|
21922
|
-
*/
|
|
22188
|
+
/** Check if a server exists in the registry. */
|
|
21923
22189
|
hasServer(name) {
|
|
21924
22190
|
return this.entries.has(name);
|
|
21925
22191
|
}
|
|
21926
|
-
/**
|
|
21927
|
-
* Get the number of registered servers.
|
|
21928
|
-
*/
|
|
22192
|
+
/** Get the number of registered servers. */
|
|
21929
22193
|
get size() {
|
|
21930
22194
|
return this.entries.size;
|
|
21931
22195
|
}
|
|
@@ -22538,12 +22802,6 @@ function renderMcpSettingsOverlay(params) {
|
|
|
22538
22802
|
addedAt: meta.servers[server.name]?.addedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
22539
22803
|
};
|
|
22540
22804
|
saveMetadata(configDir, meta);
|
|
22541
|
-
if (!newEnabled && registry3) {
|
|
22542
|
-
try {
|
|
22543
|
-
await registry3.stopServer(server.name);
|
|
22544
|
-
} catch {
|
|
22545
|
-
}
|
|
22546
|
-
}
|
|
22547
22805
|
refreshServers();
|
|
22548
22806
|
refresh();
|
|
22549
22807
|
} catch (err) {
|
|
@@ -22690,7 +22948,7 @@ function renderMcpSettingsOverlay(params) {
|
|
|
22690
22948
|
}
|
|
22691
22949
|
|
|
22692
22950
|
// packages/mcp/src/index.ts
|
|
22693
|
-
var VERSION8 = getPackageVersion(
|
|
22951
|
+
var VERSION8 = getPackageVersion(dirname18(fileURLToPath9(import.meta.url)));
|
|
22694
22952
|
var registry2 = null;
|
|
22695
22953
|
function getInfoRegistry5() {
|
|
22696
22954
|
return globalThis.__unipi_info_registry;
|
|
@@ -22700,20 +22958,18 @@ function getRegistry() {
|
|
|
22700
22958
|
}
|
|
22701
22959
|
function src_default4(pi) {
|
|
22702
22960
|
pi.on("session_start", async (_event, ctx) => {
|
|
22961
|
+
const toolApi = pi;
|
|
22962
|
+
const registerTool = typeof toolApi.registerTool === "function" ? (tool) => toolApi.registerTool(tool) : typeof toolApi.registerExternalTool === "function" ? (tool) => toolApi.registerExternalTool(tool) : () => {
|
|
22963
|
+
throw new Error("Pi does not expose a supported MCP tool registration API");
|
|
22964
|
+
};
|
|
22965
|
+
const canUnregisterTools = typeof toolApi.unregisterTool === "function" || typeof toolApi.unregisterExternalTool === "function";
|
|
22966
|
+
const unregisterTool = typeof toolApi.unregisterTool === "function" ? (toolName) => toolApi.unregisterTool(toolName) : typeof toolApi.unregisterExternalTool === "function" ? (toolName) => toolApi.unregisterExternalTool(toolName) : () => {
|
|
22967
|
+
};
|
|
22703
22968
|
registry2 = new ServerRegistry({
|
|
22704
22969
|
emitEvent: (event, payload) => emitEvent(pi, event, payload),
|
|
22705
|
-
registerTool
|
|
22706
|
-
|
|
22707
|
-
|
|
22708
|
-
} catch {
|
|
22709
|
-
}
|
|
22710
|
-
},
|
|
22711
|
-
unregisterTool: (toolName) => {
|
|
22712
|
-
try {
|
|
22713
|
-
pi.unregisterTool?.(toolName) ?? pi.unregisterExternalTool?.(toolName);
|
|
22714
|
-
} catch {
|
|
22715
|
-
}
|
|
22716
|
-
}
|
|
22970
|
+
registerTool,
|
|
22971
|
+
unregisterTool,
|
|
22972
|
+
canUnregisterTools
|
|
22717
22973
|
});
|
|
22718
22974
|
const cwd = ctx.cwd ?? process.cwd();
|
|
22719
22975
|
let servers = [];
|
|
@@ -22722,13 +22978,10 @@ function src_default4(pi) {
|
|
|
22722
22978
|
servers = result.servers;
|
|
22723
22979
|
} catch (_err) {
|
|
22724
22980
|
}
|
|
22725
|
-
|
|
22726
|
-
|
|
22727
|
-
|
|
22728
|
-
|
|
22729
|
-
}
|
|
22730
|
-
});
|
|
22731
|
-
await Promise.allSettled(startPromises);
|
|
22981
|
+
try {
|
|
22982
|
+
await registry2.startServers(servers.filter((server) => server.enabled));
|
|
22983
|
+
} catch (_err) {
|
|
22984
|
+
}
|
|
22732
22985
|
const infoRegistry2 = getInfoRegistry5();
|
|
22733
22986
|
if (infoRegistry2 && registry2) {
|
|
22734
22987
|
const reg = registry2;
|
|
@@ -22785,14 +23038,12 @@ function src_default4(pi) {
|
|
|
22785
23038
|
`unipi:${MCP_COMMANDS.STATUS}`,
|
|
22786
23039
|
`unipi:${MCP_COMMANDS.RELOAD}`
|
|
22787
23040
|
],
|
|
22788
|
-
tools: activeServers.flatMap(
|
|
22789
|
-
(s) => registry2?.getEntry(s.name)?.toolNames ?? []
|
|
22790
|
-
)
|
|
23041
|
+
tools: activeServers.flatMap((server) => registry2?.getEntry(server.name)?.toolNames ?? []).sort(compareCodeUnits)
|
|
22791
23042
|
});
|
|
22792
23043
|
});
|
|
22793
23044
|
pi.on("session_shutdown", async (_event, _ctx) => {
|
|
22794
23045
|
if (registry2) {
|
|
22795
|
-
await registry2.
|
|
23046
|
+
await registry2.disconnectAll();
|
|
22796
23047
|
registry2 = null;
|
|
22797
23048
|
}
|
|
22798
23049
|
});
|
|
@@ -22906,38 +23157,16 @@ Updated: ${catalog.lastUpdated}`,
|
|
|
22906
23157
|
}
|
|
22907
23158
|
});
|
|
22908
23159
|
pi.registerCommand(`unipi:${MCP_COMMANDS.RELOAD}`, {
|
|
22909
|
-
description: "
|
|
23160
|
+
description: "Explain how to reload MCP servers safely",
|
|
22910
23161
|
handler: async (_args, ctx) => {
|
|
22911
|
-
|
|
22912
|
-
if (!reg) {
|
|
22913
|
-
ctx.ui.notify("MCP extension not initialized", "warning");
|
|
22914
|
-
return;
|
|
22915
|
-
}
|
|
22916
|
-
const all = reg.getAll();
|
|
22917
|
-
if (all.length === 0) {
|
|
22918
|
-
ctx.ui.notify("No MCP servers configured. Use /unipi:mcp-add to add one.", "info");
|
|
22919
|
-
return;
|
|
22920
|
-
}
|
|
22921
|
-
ctx.ui.notify(`Reloading ${all.length} MCP server(s)...`, "info");
|
|
22922
|
-
let restarted = 0;
|
|
22923
|
-
let failed = 0;
|
|
22924
|
-
for (const state of all) {
|
|
22925
|
-
try {
|
|
22926
|
-
await reg.restartServer(state.name);
|
|
22927
|
-
restarted++;
|
|
22928
|
-
} catch (_err) {
|
|
22929
|
-
failed++;
|
|
22930
|
-
}
|
|
22931
|
-
}
|
|
22932
|
-
const msg = failed > 0 ? `Reloaded: ${restarted} ok, ${failed} failed` : `Reloaded ${restarted} MCP server(s) successfully`;
|
|
22933
|
-
ctx.ui.notify(msg, failed > 0 ? "warning" : "info");
|
|
23162
|
+
ctx.ui.notify("Restart Pi to reload MCP servers and tool schemas safely.", "info");
|
|
22934
23163
|
}
|
|
22935
23164
|
});
|
|
22936
23165
|
}
|
|
22937
23166
|
|
|
22938
23167
|
// packages/notify/index.ts
|
|
22939
23168
|
init_core();
|
|
22940
|
-
import { dirname as
|
|
23169
|
+
import { dirname as dirname21 } from "node:path";
|
|
22941
23170
|
import { fileURLToPath as fileURLToPath10 } from "node:url";
|
|
22942
23171
|
|
|
22943
23172
|
// packages/notify/tools.ts
|
|
@@ -22947,7 +23176,7 @@ import { Type as Type6 } from "typebox";
|
|
|
22947
23176
|
// packages/notify/settings.ts
|
|
22948
23177
|
init_core();
|
|
22949
23178
|
import { readFileSync as readFileSync19, writeFileSync as writeFileSync17, mkdirSync as mkdirSync15, existsSync as existsSync24 } from "fs";
|
|
22950
|
-
import { dirname as
|
|
23179
|
+
import { dirname as dirname19, join as join22 } from "path";
|
|
22951
23180
|
import { homedir as homedir17 } from "os";
|
|
22952
23181
|
function resolveConfigPath() {
|
|
22953
23182
|
const base = NOTIFY_DIRS.CONFIG.replace("~", homedir17());
|
|
@@ -23001,7 +23230,7 @@ function loadConfig2() {
|
|
|
23001
23230
|
}
|
|
23002
23231
|
function saveConfig2(config) {
|
|
23003
23232
|
const configPath = resolveConfigPath();
|
|
23004
|
-
const dir =
|
|
23233
|
+
const dir = dirname19(configPath);
|
|
23005
23234
|
mkdirSync15(dir, { recursive: true });
|
|
23006
23235
|
writeFileSync17(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
23007
23236
|
}
|
|
@@ -23062,7 +23291,7 @@ init_core();
|
|
|
23062
23291
|
|
|
23063
23292
|
// packages/notify/ntfy-config.ts
|
|
23064
23293
|
import { readFileSync as readFileSync20, writeFileSync as writeFileSync18, mkdirSync as mkdirSync16, existsSync as existsSync25 } from "fs";
|
|
23065
|
-
import { dirname as
|
|
23294
|
+
import { dirname as dirname20, join as join23 } from "path";
|
|
23066
23295
|
import { homedir as homedir18 } from "os";
|
|
23067
23296
|
var DEFAULT_NTFY_CONFIG = {
|
|
23068
23297
|
enabled: false,
|
|
@@ -23102,7 +23331,7 @@ function loadNtfyConfig(cwd) {
|
|
|
23102
23331
|
}
|
|
23103
23332
|
function saveNtfyConfig(scope, cwd, config) {
|
|
23104
23333
|
const filePath = scope === "project" ? getProjectNtfyPath(cwd) : getGlobalNtfyPath();
|
|
23105
|
-
const dir =
|
|
23334
|
+
const dir = dirname20(filePath);
|
|
23106
23335
|
mkdirSync16(dir, { recursive: true });
|
|
23107
23336
|
writeFileSync18(filePath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
23108
23337
|
}
|
|
@@ -23142,7 +23371,7 @@ function migrateFromLegacyConfig() {
|
|
|
23142
23371
|
token: ntfySection.token,
|
|
23143
23372
|
priority: ntfySection.priority ?? 3
|
|
23144
23373
|
};
|
|
23145
|
-
const dir =
|
|
23374
|
+
const dir = dirname20(globalNtfyPath);
|
|
23146
23375
|
mkdirSync16(dir, { recursive: true });
|
|
23147
23376
|
writeFileSync18(
|
|
23148
23377
|
globalNtfyPath,
|
|
@@ -23198,7 +23427,7 @@ async function isWindowFocusedOnWindows() {
|
|
|
23198
23427
|
tmpDir = mkdtempSync(join24(tmpdir2(), "pi-focus-"));
|
|
23199
23428
|
const scriptPath = join24(tmpDir, "check.ps1");
|
|
23200
23429
|
writeFileSync19(scriptPath, POWERCHECK_SCRIPT, "utf-8");
|
|
23201
|
-
const stdout = await new Promise((
|
|
23430
|
+
const stdout = await new Promise((resolve14, reject) => {
|
|
23202
23431
|
execFile(
|
|
23203
23432
|
"powershell.exe",
|
|
23204
23433
|
[
|
|
@@ -23213,7 +23442,7 @@ async function isWindowFocusedOnWindows() {
|
|
|
23213
23442
|
{ timeout: 5e3, encoding: "utf-8" },
|
|
23214
23443
|
(err, out) => {
|
|
23215
23444
|
if (err) reject(err);
|
|
23216
|
-
else
|
|
23445
|
+
else resolve14(out);
|
|
23217
23446
|
}
|
|
23218
23447
|
);
|
|
23219
23448
|
});
|
|
@@ -23255,7 +23484,7 @@ async function sendNativeNotification(title, message, options) {
|
|
|
23255
23484
|
if (options?.suppressWhenFocused && await isWindowFocused()) {
|
|
23256
23485
|
throw new SuppressedError2();
|
|
23257
23486
|
}
|
|
23258
|
-
return new Promise((
|
|
23487
|
+
return new Promise((resolve14, reject) => {
|
|
23259
23488
|
notifier.notify(
|
|
23260
23489
|
{
|
|
23261
23490
|
title,
|
|
@@ -23270,7 +23499,7 @@ async function sendNativeNotification(title, message, options) {
|
|
|
23270
23499
|
)
|
|
23271
23500
|
);
|
|
23272
23501
|
} else {
|
|
23273
|
-
|
|
23502
|
+
resolve14();
|
|
23274
23503
|
}
|
|
23275
23504
|
}
|
|
23276
23505
|
);
|
|
@@ -26006,7 +26235,7 @@ ${results.join("\n")}`, "info");
|
|
|
26006
26235
|
}
|
|
26007
26236
|
|
|
26008
26237
|
// packages/notify/index.ts
|
|
26009
|
-
var VERSION9 = getPackageVersion(
|
|
26238
|
+
var VERSION9 = getPackageVersion(dirname21(fileURLToPath10(import.meta.url)));
|
|
26010
26239
|
function notify_default(pi) {
|
|
26011
26240
|
registerNotifyTools(pi);
|
|
26012
26241
|
registerNotifyCommands(pi);
|
|
@@ -26035,6 +26264,9 @@ init_core();
|
|
|
26035
26264
|
init_core();
|
|
26036
26265
|
import * as fs14 from "node:fs";
|
|
26037
26266
|
import * as path13 from "node:path";
|
|
26267
|
+
import {
|
|
26268
|
+
buildSessionContext as buildSessionContext3
|
|
26269
|
+
} from "@earendil-works/pi-coding-agent";
|
|
26038
26270
|
|
|
26039
26271
|
// packages/milestone/milestone.ts
|
|
26040
26272
|
init_core();
|
|
@@ -26180,7 +26412,7 @@ function getProgressSummary(filePath) {
|
|
|
26180
26412
|
}
|
|
26181
26413
|
|
|
26182
26414
|
// packages/milestone/hooks.ts
|
|
26183
|
-
var
|
|
26415
|
+
var MILESTONE_SNAPSHOT_TYPE = "unipi-milestone-snapshot";
|
|
26184
26416
|
function formatMilestoneContext(filePath) {
|
|
26185
26417
|
const summary = getProgressSummary(filePath);
|
|
26186
26418
|
if (summary.totalItems === 0) return null;
|
|
@@ -26193,16 +26425,67 @@ function formatMilestoneContext(filePath) {
|
|
|
26193
26425
|
focus
|
|
26194
26426
|
].filter(Boolean).join("\n");
|
|
26195
26427
|
}
|
|
26428
|
+
function formatMilestoneSnapshot(workspace, context) {
|
|
26429
|
+
return [
|
|
26430
|
+
"# UniPi Milestone Snapshot",
|
|
26431
|
+
"This snapshot supersedes all prior UniPi milestone snapshots; use only this snapshot for milestone status.",
|
|
26432
|
+
`Workspace: ${workspace}`,
|
|
26433
|
+
`Status: ${context ? "active" : "inactive"}`,
|
|
26434
|
+
context ?? "No milestones are active for this workspace."
|
|
26435
|
+
].join("\n\n");
|
|
26436
|
+
}
|
|
26437
|
+
function latestEffectiveSnapshot(branch) {
|
|
26438
|
+
const messages = buildSessionContext3(branch).messages;
|
|
26439
|
+
for (let index = messages.length - 1; index >= 0; index--) {
|
|
26440
|
+
const message = messages[index];
|
|
26441
|
+
if (message.role === "custom" && message.customType === MILESTONE_SNAPSHOT_TYPE) {
|
|
26442
|
+
return {
|
|
26443
|
+
content: message.content,
|
|
26444
|
+
details: message.details
|
|
26445
|
+
};
|
|
26446
|
+
}
|
|
26447
|
+
}
|
|
26448
|
+
return void 0;
|
|
26449
|
+
}
|
|
26450
|
+
function latestHistoricalSnapshot(branch) {
|
|
26451
|
+
for (let index = branch.length - 1; index >= 0; index--) {
|
|
26452
|
+
const entry = branch[index];
|
|
26453
|
+
if (entry.type === "custom_message" && entry.customType === MILESTONE_SNAPSHOT_TYPE) {
|
|
26454
|
+
return {
|
|
26455
|
+
content: entry.content,
|
|
26456
|
+
details: entry.details
|
|
26457
|
+
};
|
|
26458
|
+
}
|
|
26459
|
+
}
|
|
26460
|
+
return void 0;
|
|
26461
|
+
}
|
|
26462
|
+
function isActiveSnapshot2(snapshot) {
|
|
26463
|
+
if (typeof snapshot.details?.active === "boolean") return snapshot.details.active;
|
|
26464
|
+
return typeof snapshot.content === "string" && snapshot.content.includes("Status: active");
|
|
26465
|
+
}
|
|
26196
26466
|
function registerSessionStartHook(pi) {
|
|
26197
|
-
pi.on("before_agent_start", (
|
|
26198
|
-
|
|
26199
|
-
const
|
|
26200
|
-
const milestonesPath = path13.join(cwd, MILESTONE_DIRS.MILESTONES);
|
|
26467
|
+
pi.on("before_agent_start", (_event, ctx) => {
|
|
26468
|
+
const workspace = ctx.cwd;
|
|
26469
|
+
const milestonesPath = path13.join(workspace, MILESTONE_DIRS.MILESTONES);
|
|
26201
26470
|
const context = formatMilestoneContext(milestonesPath);
|
|
26202
|
-
|
|
26203
|
-
const
|
|
26471
|
+
const branch = ctx.sessionManager.getBranch();
|
|
26472
|
+
const latest = latestEffectiveSnapshot(branch);
|
|
26473
|
+
const historical = latestHistoricalSnapshot(branch);
|
|
26474
|
+
if (!context && !latest && !historical) return void 0;
|
|
26475
|
+
const prior = latest ?? historical;
|
|
26476
|
+
if (!context && prior && !isActiveSnapshot2(prior)) return void 0;
|
|
26477
|
+
const content = formatMilestoneSnapshot(workspace, context);
|
|
26478
|
+
if (latest?.content === content) return void 0;
|
|
26204
26479
|
return {
|
|
26205
|
-
|
|
26480
|
+
message: {
|
|
26481
|
+
customType: MILESTONE_SNAPSHOT_TYPE,
|
|
26482
|
+
content,
|
|
26483
|
+
display: false,
|
|
26484
|
+
details: {
|
|
26485
|
+
active: context !== null,
|
|
26486
|
+
workspace
|
|
26487
|
+
}
|
|
26488
|
+
}
|
|
26206
26489
|
};
|
|
26207
26490
|
});
|
|
26208
26491
|
}
|
|
@@ -26258,14 +26541,16 @@ function scanModifiedDocs(dirs, since) {
|
|
|
26258
26541
|
}
|
|
26259
26542
|
function registerSessionEndHook(pi) {
|
|
26260
26543
|
const baselineSnapshots = /* @__PURE__ */ new Map();
|
|
26261
|
-
|
|
26544
|
+
let sessionStartMs = 0;
|
|
26545
|
+
let sessionWorkspace = null;
|
|
26546
|
+
pi.on("session_start", (_event, ctx) => {
|
|
26262
26547
|
sessionStartMs = Date.now();
|
|
26548
|
+
sessionWorkspace = ctx.cwd;
|
|
26263
26549
|
baselineSnapshots.clear();
|
|
26264
|
-
const cwd = process.cwd();
|
|
26265
26550
|
const scanDirs = [
|
|
26266
|
-
path13.join(
|
|
26267
|
-
path13.join(
|
|
26268
|
-
path13.join(
|
|
26551
|
+
path13.join(sessionWorkspace, ".unipi/docs/specs"),
|
|
26552
|
+
path13.join(sessionWorkspace, ".unipi/docs/plans"),
|
|
26553
|
+
path13.join(sessionWorkspace, ".unipi/docs/quick-work")
|
|
26269
26554
|
];
|
|
26270
26555
|
for (const dir of scanDirs) {
|
|
26271
26556
|
if (!fs14.existsSync(dir)) continue;
|
|
@@ -26279,13 +26564,13 @@ function registerSessionEndHook(pi) {
|
|
|
26279
26564
|
}
|
|
26280
26565
|
});
|
|
26281
26566
|
const syncModifiedDocs = () => {
|
|
26282
|
-
|
|
26283
|
-
const milestonesPath = path13.join(
|
|
26567
|
+
if (!sessionWorkspace) return;
|
|
26568
|
+
const milestonesPath = path13.join(sessionWorkspace, MILESTONE_DIRS.MILESTONES);
|
|
26284
26569
|
if (!fs14.existsSync(milestonesPath)) return;
|
|
26285
26570
|
const scanDirs = [
|
|
26286
|
-
path13.join(
|
|
26287
|
-
path13.join(
|
|
26288
|
-
path13.join(
|
|
26571
|
+
path13.join(sessionWorkspace, ".unipi/docs/specs"),
|
|
26572
|
+
path13.join(sessionWorkspace, ".unipi/docs/plans"),
|
|
26573
|
+
path13.join(sessionWorkspace, ".unipi/docs/quick-work")
|
|
26289
26574
|
];
|
|
26290
26575
|
const modifiedFiles = scanModifiedDocs(scanDirs, sessionStartMs);
|
|
26291
26576
|
for (const filePath of modifiedFiles) {
|
|
@@ -26303,10 +26588,10 @@ function registerSessionEndHook(pi) {
|
|
|
26303
26588
|
|
|
26304
26589
|
// packages/milestone/commands.ts
|
|
26305
26590
|
init_core();
|
|
26306
|
-
import { dirname as
|
|
26591
|
+
import { dirname as dirname22, join as join26 } from "node:path";
|
|
26307
26592
|
import { fileURLToPath as fileURLToPath11 } from "node:url";
|
|
26308
26593
|
import { readFileSync as readFileSync21 } from "node:fs";
|
|
26309
|
-
var SKILLS_DIR = join26(
|
|
26594
|
+
var SKILLS_DIR = join26(dirname22(fileURLToPath11(import.meta.url)), "skills");
|
|
26310
26595
|
function loadSkill(skillName) {
|
|
26311
26596
|
try {
|
|
26312
26597
|
return readFileSync21(join26(SKILLS_DIR, skillName, "SKILL.md"), "utf-8");
|
|
@@ -26533,9 +26818,9 @@ var KanboardServer = class {
|
|
|
26533
26818
|
}
|
|
26534
26819
|
/** Bind server to a port */
|
|
26535
26820
|
listen(port) {
|
|
26536
|
-
return new Promise((
|
|
26821
|
+
return new Promise((resolve14, reject) => {
|
|
26537
26822
|
this.server.once("error", reject);
|
|
26538
|
-
this.server.listen(port, () =>
|
|
26823
|
+
this.server.listen(port, () => resolve14());
|
|
26539
26824
|
});
|
|
26540
26825
|
}
|
|
26541
26826
|
/** Handle incoming HTTP request */
|
|
@@ -27504,11 +27789,11 @@ function markAutoCompactionError(state, nowMs) {
|
|
|
27504
27789
|
}
|
|
27505
27790
|
|
|
27506
27791
|
// packages/compactor/src/session/db.ts
|
|
27507
|
-
import { createHash as
|
|
27792
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
27508
27793
|
import { execFileSync } from "node:child_process";
|
|
27509
27794
|
import { existsSync as existsSync32, mkdirSync as mkdirSync20 } from "node:fs";
|
|
27510
27795
|
import { homedir as homedir21 } from "node:os";
|
|
27511
|
-
import { dirname as
|
|
27796
|
+
import { dirname as dirname25, join as join33 } from "node:path";
|
|
27512
27797
|
function getWorktreeSuffix() {
|
|
27513
27798
|
const envSuffix = process.env.COMPACTOR_SESSION_SUFFIX;
|
|
27514
27799
|
if (envSuffix !== void 0) {
|
|
@@ -27522,7 +27807,7 @@ function getWorktreeSuffix() {
|
|
|
27522
27807
|
{ encoding: "utf-8", timeout: 2e3, stdio: ["ignore", "pipe", "ignore"] }
|
|
27523
27808
|
).split(/\r?\n/).find((l) => l.startsWith("worktree "))?.replace("worktree ", "")?.trim();
|
|
27524
27809
|
if (mainWorktree && cwd !== mainWorktree) {
|
|
27525
|
-
const suffix =
|
|
27810
|
+
const suffix = createHash3("sha256").update(cwd).digest("hex").slice(0, 8);
|
|
27526
27811
|
return `__${suffix}`;
|
|
27527
27812
|
}
|
|
27528
27813
|
} catch {
|
|
@@ -27553,7 +27838,7 @@ var SessionDB = class {
|
|
|
27553
27838
|
this.dbPath = opts?.dbPath ?? defaultDBPath("session");
|
|
27554
27839
|
}
|
|
27555
27840
|
async init() {
|
|
27556
|
-
const dir =
|
|
27841
|
+
const dir = dirname25(this.dbPath);
|
|
27557
27842
|
if (!existsSync32(dir)) mkdirSync20(dir, { recursive: true });
|
|
27558
27843
|
const sqlite = await getSQLite();
|
|
27559
27844
|
const Database2 = sqlite.Database ?? sqlite.default?.Database ?? sqlite.default ?? sqlite;
|
|
@@ -27664,7 +27949,7 @@ var SessionDB = class {
|
|
|
27664
27949
|
}
|
|
27665
27950
|
insertEvent(sessionId, event, sourceHook = "PostToolUse") {
|
|
27666
27951
|
if (!this.stmts) return;
|
|
27667
|
-
const dataHash =
|
|
27952
|
+
const dataHash = createHash3("sha256").update(event.data).digest("hex").slice(0, 16).toUpperCase();
|
|
27668
27953
|
const projectDir = String(event.project_dir ?? "").trim();
|
|
27669
27954
|
const attributionSource = String(event.attribution_source ?? "unknown");
|
|
27670
27955
|
const rawConfidence = Number(event.attribution_confidence ?? 0);
|
|
@@ -27948,7 +28233,7 @@ async function buildResumeContextMessage(db, sessionId) {
|
|
|
27948
28233
|
// packages/compactor/src/executor/executor.ts
|
|
27949
28234
|
import { spawn as spawn3, execSync, execFileSync as execFileSync2 } from "node:child_process";
|
|
27950
28235
|
import { mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync24, rmSync as rmSync3 } from "node:fs";
|
|
27951
|
-
import { join as join34, resolve as
|
|
28236
|
+
import { join as join34, resolve as resolve11 } from "node:path";
|
|
27952
28237
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
27953
28238
|
|
|
27954
28239
|
// packages/compactor/src/executor/runtime.ts
|
|
@@ -28040,7 +28325,7 @@ var OS_TMPDIR = (() => {
|
|
|
28040
28325
|
process.platform === "darwin" ? ["DARWIN_USER_TEMP_DIR"] : ["-u", "-d"],
|
|
28041
28326
|
{ env: { ...process.env, TMPDIR: void 0 }, encoding: "utf-8" }
|
|
28042
28327
|
).trim();
|
|
28043
|
-
const dir = process.platform === "darwin" ? result :
|
|
28328
|
+
const dir = process.platform === "darwin" ? result : resolve11(result, "..");
|
|
28044
28329
|
if (dir && dir !== process.cwd()) return dir;
|
|
28045
28330
|
} catch {
|
|
28046
28331
|
}
|
|
@@ -28161,7 +28446,7 @@ var PolyglotExecutor = class {
|
|
|
28161
28446
|
async executeFile(opts) {
|
|
28162
28447
|
const { language, path: path28, timeout = 3e4, background = false } = opts;
|
|
28163
28448
|
const cmd = buildCommand(this.#runtimes, language, path28);
|
|
28164
|
-
const cwd = language === "shell" ? this.#projectRoot :
|
|
28449
|
+
const cwd = language === "shell" ? this.#projectRoot : resolve11(path28, "..");
|
|
28165
28450
|
return this.#spawn(cmd, cwd, "", timeout, background);
|
|
28166
28451
|
}
|
|
28167
28452
|
#writeScript(tmpDir, code, language) {
|
|
@@ -28184,7 +28469,7 @@ var PolyglotExecutor = class {
|
|
|
28184
28469
|
return filePath;
|
|
28185
28470
|
}
|
|
28186
28471
|
async #spawn(cmd, cwd, tmpDir, timeout, background) {
|
|
28187
|
-
return new Promise((
|
|
28472
|
+
return new Promise((resolve14) => {
|
|
28188
28473
|
const proc = spawn3(cmd[0], cmd.slice(1), {
|
|
28189
28474
|
cwd,
|
|
28190
28475
|
env: sanitizeEnv(),
|
|
@@ -28220,14 +28505,14 @@ var PolyglotExecutor = class {
|
|
|
28220
28505
|
}, timeout);
|
|
28221
28506
|
proc.on("error", (err) => {
|
|
28222
28507
|
if (timer) clearTimeout(timer);
|
|
28223
|
-
|
|
28508
|
+
resolve14({ stdout, stderr: err.message, exitCode: 1, timedOut: false });
|
|
28224
28509
|
});
|
|
28225
28510
|
proc.on("close", (code) => {
|
|
28226
28511
|
if (timer) clearTimeout(timer);
|
|
28227
28512
|
if (background && proc.pid) {
|
|
28228
28513
|
this.#backgroundedPids.add(proc.pid);
|
|
28229
28514
|
}
|
|
28230
|
-
|
|
28515
|
+
resolve14({
|
|
28231
28516
|
stdout: stdout.slice(0, this.#hardCapBytes),
|
|
28232
28517
|
stderr: stderr.slice(0, this.#hardCapBytes),
|
|
28233
28518
|
exitCode: code ?? 0,
|
|
@@ -28265,7 +28550,7 @@ init_core();
|
|
|
28265
28550
|
init_hooks();
|
|
28266
28551
|
|
|
28267
28552
|
// packages/compactor/src/compaction/search-entries.ts
|
|
28268
|
-
import { createHash as
|
|
28553
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
28269
28554
|
function tokenize(text) {
|
|
28270
28555
|
return text.toLowerCase().replace(/[^\p{L}\p{N}\s]/gu, " ").split(/\s+/).filter((w) => w.length > 1);
|
|
28271
28556
|
}
|
|
@@ -28309,7 +28594,7 @@ function searchEntries(blocks, query, opts) {
|
|
|
28309
28594
|
kind: b.kind
|
|
28310
28595
|
}));
|
|
28311
28596
|
const hashSource = docs.length > 0 ? `${docs.length}:${docs[0].text.slice(0, 80)}:${docs[docs.length - 1].text.slice(-80)}` : "empty";
|
|
28312
|
-
const currentHash =
|
|
28597
|
+
const currentHash = createHash5("sha256").update(hashSource).digest("hex");
|
|
28313
28598
|
let index;
|
|
28314
28599
|
let docCount;
|
|
28315
28600
|
let avgDocLen;
|
|
@@ -32795,7 +33080,7 @@ import { Key as Key6, matchesKey as matchesKey14, truncateToWidth as truncateToW
|
|
|
32795
33080
|
// packages/updater/src/readme.ts
|
|
32796
33081
|
init_core();
|
|
32797
33082
|
init_core();
|
|
32798
|
-
import { dirname as
|
|
33083
|
+
import { dirname as dirname27 } from "node:path";
|
|
32799
33084
|
import { fileURLToPath as fileURLToPath12 } from "node:url";
|
|
32800
33085
|
import { existsSync as existsSync39, readFileSync as readFileSync34 } from "fs";
|
|
32801
33086
|
import { join as join38 } from "path";
|
|
@@ -32822,7 +33107,7 @@ var PACKAGE_MAP = {
|
|
|
32822
33107
|
updater: MODULES.UPDATER
|
|
32823
33108
|
};
|
|
32824
33109
|
function resolveUnipiRoot() {
|
|
32825
|
-
const dir =
|
|
33110
|
+
const dir = dirname27(fileURLToPath12(import.meta.url));
|
|
32826
33111
|
const root = findPackageRoot(dir, "@pi-unipi/unipi");
|
|
32827
33112
|
return root ?? join38(dir, "..");
|
|
32828
33113
|
}
|
|
@@ -33159,7 +33444,7 @@ import { Key as Key7, matchesKey as matchesKey15, truncateToWidth as truncateToW
|
|
|
33159
33444
|
// packages/updater/src/changelog.ts
|
|
33160
33445
|
init_core();
|
|
33161
33446
|
import { existsSync as existsSync40, readFileSync as readFileSync36 } from "fs";
|
|
33162
|
-
import { dirname as
|
|
33447
|
+
import { dirname as dirname28, join as join39 } from "node:path";
|
|
33163
33448
|
import { fileURLToPath as fileURLToPath13 } from "node:url";
|
|
33164
33449
|
|
|
33165
33450
|
// packages/updater/src/version.ts
|
|
@@ -33184,7 +33469,7 @@ function isNewerVersion(latest, current) {
|
|
|
33184
33469
|
// packages/updater/src/changelog.ts
|
|
33185
33470
|
function resolveChangelogPath() {
|
|
33186
33471
|
try {
|
|
33187
|
-
const dir =
|
|
33472
|
+
const dir = dirname28(fileURLToPath13(import.meta.url));
|
|
33188
33473
|
const root = findPackageRoot(dir, "@pi-unipi/unipi");
|
|
33189
33474
|
if (root) {
|
|
33190
33475
|
const packaged = join39(root, "CHANGELOG.md");
|
|
@@ -33445,7 +33730,7 @@ function renderChangelogOverlay() {
|
|
|
33445
33730
|
// packages/updater/src/settings.ts
|
|
33446
33731
|
init_core();
|
|
33447
33732
|
import { readFileSync as readFileSync37, writeFileSync as writeFileSync26, mkdirSync as mkdirSync22, existsSync as existsSync42 } from "fs";
|
|
33448
|
-
import { dirname as
|
|
33733
|
+
import { dirname as dirname29, join as join40 } from "path";
|
|
33449
33734
|
import { homedir as homedir24 } from "os";
|
|
33450
33735
|
var DEFAULT_CONFIG6 = {
|
|
33451
33736
|
checkIntervalMs: 36e5,
|
|
@@ -33477,7 +33762,7 @@ function loadConfig5() {
|
|
|
33477
33762
|
}
|
|
33478
33763
|
function saveConfig4(config) {
|
|
33479
33764
|
const configPath = resolveConfigPath2();
|
|
33480
|
-
const dir =
|
|
33765
|
+
const dir = dirname29(configPath);
|
|
33481
33766
|
mkdirSync22(dir, { recursive: true });
|
|
33482
33767
|
writeFileSync26(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
33483
33768
|
}
|
|
@@ -33713,7 +33998,7 @@ init_core();
|
|
|
33713
33998
|
// packages/updater/src/cache.ts
|
|
33714
33999
|
init_core();
|
|
33715
34000
|
import { readFileSync as readFileSync38, writeFileSync as writeFileSync27, mkdirSync as mkdirSync23, existsSync as existsSync43 } from "fs";
|
|
33716
|
-
import { dirname as
|
|
34001
|
+
import { dirname as dirname30, join as join41 } from "path";
|
|
33717
34002
|
import { homedir as homedir25 } from "os";
|
|
33718
34003
|
function resolveCachePath() {
|
|
33719
34004
|
const base = UPDATER_DIRS.CACHE.replace("~", homedir25());
|
|
@@ -33735,7 +34020,7 @@ function readLastCheck() {
|
|
|
33735
34020
|
}
|
|
33736
34021
|
function writeLastCheck(cache) {
|
|
33737
34022
|
const cachePath = resolveCachePath();
|
|
33738
|
-
const dir =
|
|
34023
|
+
const dir = dirname30(cachePath);
|
|
33739
34024
|
mkdirSync23(dir, { recursive: true });
|
|
33740
34025
|
writeFileSync27(cachePath, JSON.stringify(cache, null, 2) + "\n", "utf-8");
|
|
33741
34026
|
}
|
|
@@ -34145,8 +34430,8 @@ init_core();
|
|
|
34145
34430
|
import { Key as Key10 } from "@earendil-works/pi-tui";
|
|
34146
34431
|
|
|
34147
34432
|
// packages/input-shortcuts/src/registers.ts
|
|
34148
|
-
import { existsSync as existsSync44, mkdirSync as mkdirSync24, readFileSync as readFileSync39, renameSync as
|
|
34149
|
-
import { dirname as
|
|
34433
|
+
import { existsSync as existsSync44, mkdirSync as mkdirSync24, readFileSync as readFileSync39, renameSync as renameSync8, writeFileSync as writeFileSync28 } from "node:fs";
|
|
34434
|
+
import { dirname as dirname31, join as join42 } from "node:path";
|
|
34150
34435
|
|
|
34151
34436
|
// packages/input-shortcuts/src/types.ts
|
|
34152
34437
|
var DEFAULT_CONFIG7 = {
|
|
@@ -34216,13 +34501,13 @@ var RegisterStore = class {
|
|
|
34216
34501
|
/** Atomic write: write to .tmp then rename. */
|
|
34217
34502
|
save() {
|
|
34218
34503
|
try {
|
|
34219
|
-
const dir =
|
|
34504
|
+
const dir = dirname31(this.filePath);
|
|
34220
34505
|
if (!existsSync44(dir)) {
|
|
34221
34506
|
mkdirSync24(dir, { recursive: true });
|
|
34222
34507
|
}
|
|
34223
34508
|
const tmpPath = this.filePath + ".tmp";
|
|
34224
34509
|
writeFileSync28(tmpPath, JSON.stringify(this.data, null, 2), "utf-8");
|
|
34225
|
-
|
|
34510
|
+
renameSync8(tmpPath, this.filePath);
|
|
34226
34511
|
} catch {
|
|
34227
34512
|
}
|
|
34228
34513
|
}
|
|
@@ -34443,8 +34728,8 @@ var ChordOverlay = class extends Container2 {
|
|
|
34443
34728
|
|
|
34444
34729
|
// packages/input-shortcuts/src/settings-overlay.ts
|
|
34445
34730
|
import { SettingsList as SettingsList3 } from "@earendil-works/pi-tui";
|
|
34446
|
-
import { existsSync as existsSync45, mkdirSync as mkdirSync25, readFileSync as readFileSync40, renameSync as
|
|
34447
|
-
import { dirname as
|
|
34731
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync25, readFileSync as readFileSync40, renameSync as renameSync9, writeFileSync as writeFileSync29 } from "node:fs";
|
|
34732
|
+
import { dirname as dirname32, join as join43 } from "node:path";
|
|
34448
34733
|
var ALT_KEY_OPTIONS = [
|
|
34449
34734
|
"alt+a",
|
|
34450
34735
|
"alt+b",
|
|
@@ -34493,13 +34778,13 @@ function loadConfig6(baseDir) {
|
|
|
34493
34778
|
function saveConfig5(config, baseDir) {
|
|
34494
34779
|
const filePath = baseDir ? join43(baseDir, CONFIG_FILE) : CONFIG_FILE;
|
|
34495
34780
|
try {
|
|
34496
|
-
const dir =
|
|
34781
|
+
const dir = dirname32(filePath);
|
|
34497
34782
|
if (!existsSync45(dir)) {
|
|
34498
34783
|
mkdirSync25(dir, { recursive: true });
|
|
34499
34784
|
}
|
|
34500
34785
|
const tmpPath = filePath + ".tmp";
|
|
34501
34786
|
writeFileSync29(tmpPath, JSON.stringify(config, null, 2), "utf-8");
|
|
34502
|
-
|
|
34787
|
+
renameSync9(tmpPath, filePath);
|
|
34503
34788
|
} catch {
|
|
34504
34789
|
}
|
|
34505
34790
|
}
|
|
@@ -34927,7 +35212,7 @@ import { Type as Type8 } from "typebox";
|
|
|
34927
35212
|
// packages/cocoindex/bridge.ts
|
|
34928
35213
|
init_core();
|
|
34929
35214
|
import { execFileSync as execFileSync3, spawn as spawn4 } from "node:child_process";
|
|
34930
|
-
import { existsSync as existsSync46, mkdirSync as mkdirSync26, readFileSync as readFileSync41, writeFileSync as writeFileSync30, readdirSync as
|
|
35215
|
+
import { existsSync as existsSync46, mkdirSync as mkdirSync26, readFileSync as readFileSync41, writeFileSync as writeFileSync30, readdirSync as readdirSync14, statSync as statSync9 } from "node:fs";
|
|
34931
35216
|
import { homedir as homedir26 } from "node:os";
|
|
34932
35217
|
import { join as join44 } from "node:path";
|
|
34933
35218
|
var DEFAULT_PIPELINE_DIR = ".unipi/cocoindex";
|
|
@@ -35003,7 +35288,7 @@ function resolveCocoindexBin() {
|
|
|
35003
35288
|
if (existsSync46(uvToolBin)) return uvToolBin;
|
|
35004
35289
|
const miseRoot = join44(homedir26(), ".local", "share", "mise", "installs", "python");
|
|
35005
35290
|
try {
|
|
35006
|
-
const versions =
|
|
35291
|
+
const versions = readdirSync14(miseRoot).sort().reverse();
|
|
35007
35292
|
for (const ver of versions) {
|
|
35008
35293
|
const binPath = join44(miseRoot, ver, "bin", "cocoindex");
|
|
35009
35294
|
if (existsSync46(binPath)) return binPath;
|
|
@@ -35066,7 +35351,7 @@ async function indexProject(projectDir) {
|
|
|
35066
35351
|
}
|
|
35067
35352
|
const start = Date.now();
|
|
35068
35353
|
const cocoindexBin = resolveCocoindexBin();
|
|
35069
|
-
return new Promise((
|
|
35354
|
+
return new Promise((resolve14) => {
|
|
35070
35355
|
const proc = spawn4(cocoindexBin, ["update", "main.py"], {
|
|
35071
35356
|
cwd: pipelineDir,
|
|
35072
35357
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -35096,9 +35381,9 @@ async function indexProject(projectDir) {
|
|
|
35096
35381
|
const durationMs = Date.now() - start;
|
|
35097
35382
|
const chunksProcessed = parseChunksProcessed(stdout);
|
|
35098
35383
|
if (code === 0) {
|
|
35099
|
-
|
|
35384
|
+
resolve14({ success: true, chunksProcessed, durationMs });
|
|
35100
35385
|
} else {
|
|
35101
|
-
|
|
35386
|
+
resolve14({
|
|
35102
35387
|
success: false,
|
|
35103
35388
|
chunksProcessed,
|
|
35104
35389
|
durationMs,
|
|
@@ -35109,7 +35394,7 @@ async function indexProject(projectDir) {
|
|
|
35109
35394
|
proc.on("error", (err) => {
|
|
35110
35395
|
settled = true;
|
|
35111
35396
|
clearTimeout(timer);
|
|
35112
|
-
|
|
35397
|
+
resolve14({
|
|
35113
35398
|
success: false,
|
|
35114
35399
|
chunksProcessed: 0,
|
|
35115
35400
|
durationMs: Date.now() - start,
|
|
@@ -35174,9 +35459,9 @@ async function status(projectDir) {
|
|
|
35174
35459
|
const lancedbPath = join44(pipelineDir, ".lancedb");
|
|
35175
35460
|
if (existsSync46(lancedbPath)) {
|
|
35176
35461
|
try {
|
|
35177
|
-
const stat =
|
|
35462
|
+
const stat = statSync9(lancedbPath);
|
|
35178
35463
|
lastRun = stat.mtime.toISOString();
|
|
35179
|
-
const files =
|
|
35464
|
+
const files = readdirSync14(lancedbPath, { recursive: true });
|
|
35180
35465
|
docCount = files.filter((f) => f.endsWith(".lance")).length;
|
|
35181
35466
|
} catch {
|
|
35182
35467
|
}
|
|
@@ -35836,7 +36121,7 @@ function buildUvInstallerFallback(shell) {
|
|
|
35836
36121
|
];
|
|
35837
36122
|
}
|
|
35838
36123
|
function runStep(step) {
|
|
35839
|
-
return new Promise((
|
|
36124
|
+
return new Promise((resolve14) => {
|
|
35840
36125
|
const proc = spawn5(step.command, step.args ?? [], {
|
|
35841
36126
|
stdio: ["ignore", "pipe", "pipe"],
|
|
35842
36127
|
env: installerEnv()
|
|
@@ -35859,12 +36144,12 @@ Timed out after ${step.timeoutMs ?? DEFAULT_STEP_TIMEOUT_MS}ms.`;
|
|
|
35859
36144
|
proc.on("close", (code, signal) => {
|
|
35860
36145
|
settled = true;
|
|
35861
36146
|
clearTimeout(timeout);
|
|
35862
|
-
|
|
36147
|
+
resolve14({ ok: code === 0, stdout, stderr, exitCode: code, signal });
|
|
35863
36148
|
});
|
|
35864
36149
|
proc.on("error", (err) => {
|
|
35865
36150
|
settled = true;
|
|
35866
36151
|
clearTimeout(timeout);
|
|
35867
|
-
|
|
36152
|
+
resolve14({ ok: false, stdout, stderr: stderr || err.message });
|
|
35868
36153
|
});
|
|
35869
36154
|
});
|
|
35870
36155
|
}
|
|
@@ -36066,7 +36351,7 @@ function cocoindexExtension(pi) {
|
|
|
36066
36351
|
|
|
36067
36352
|
// packages/image/src/index.ts
|
|
36068
36353
|
init_core();
|
|
36069
|
-
import { dirname as
|
|
36354
|
+
import { dirname as dirname34 } from "node:path";
|
|
36070
36355
|
import { fileURLToPath as fileURLToPath14 } from "node:url";
|
|
36071
36356
|
|
|
36072
36357
|
// packages/image/src/commands.ts
|
|
@@ -37820,7 +38105,7 @@ function currentSessionModel(ctx) {
|
|
|
37820
38105
|
}
|
|
37821
38106
|
|
|
37822
38107
|
// packages/image/src/index.ts
|
|
37823
|
-
var VERSION11 = getPackageVersion(
|
|
38108
|
+
var VERSION11 = getPackageVersion(dirname34(fileURLToPath14(import.meta.url)));
|
|
37824
38109
|
function getInfoRegistry6() {
|
|
37825
38110
|
return globalThis.__unipi_info_registry;
|
|
37826
38111
|
}
|