@pi-unipi/unipi 2.4.1 → 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 +62 -0
- package/package.json +28 -23
- package/packages/ask-user/package.json +2 -2
- package/packages/autocomplete/package.json +4 -2
- package/packages/btw/package.json +2 -2
- package/packages/cocoindex/package.json +2 -2
- package/packages/cocoindex/tools.ts +0 -8
- package/packages/compactor/README.md +18 -22
- package/packages/compactor/package.json +3 -3
- package/packages/compactor/src/compaction/build-sections.ts +2 -2
- package/packages/compactor/src/compaction/format.ts +1 -1
- package/packages/compactor/src/config/presets.ts +19 -30
- package/packages/compactor/src/index.ts +39 -56
- package/packages/compactor/src/session/resume-inject.ts +27 -0
- package/packages/compactor/src/tools/ctx-batch-execute.ts +4 -2
- package/packages/compactor/src/tools/ctx-execute-file.ts +4 -2
- package/packages/compactor/src/tools/ctx-execute.ts +4 -2
- package/packages/compactor/src/tools/register.ts +22 -4
- package/packages/compactor/src/tui/settings-overlay.ts +9 -22
- package/packages/compactor/src/types.ts +24 -2
- package/packages/core/events.ts +13 -13
- package/packages/core/package.json +3 -2
- package/packages/core/sandbox.ts +7 -6
- package/packages/footer/README.md +2 -2
- package/packages/footer/package.json +3 -3
- package/packages/footer/src/events.ts +0 -10
- package/packages/footer/src/segments/core.ts +0 -9
- package/packages/image/package.json +2 -2
- package/packages/info-screen/core-groups.ts +0 -14
- package/packages/info-screen/package.json +2 -2
- package/packages/input-shortcuts/package.json +2 -2
- package/packages/kanboard/commands.ts +0 -1
- 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 -28
- package/packages/memory/tools.ts +0 -1
- package/packages/milestone/README.md +11 -3
- package/packages/milestone/hooks.ts +112 -44
- package/packages/milestone/index.ts +1 -1
- package/packages/milestone/package.json +5 -2
- package/packages/notify/README.md +2 -0
- package/packages/notify/events.ts +23 -13
- package/packages/notify/package.json +2 -2
- package/packages/notify/tools.ts +17 -8
- package/packages/notify/types.ts +5 -1
- package/packages/ralph/package.json +3 -3
- package/packages/ralph/ralph-loop.ts +10 -0
- package/packages/subagents/README.md +3 -1
- package/packages/subagents/package.json +10 -6
- package/packages/subagents/src/agent-manager.ts +46 -11
- package/packages/subagents/src/core-compat.ts +38 -0
- package/packages/subagents/src/global.d.ts +7 -0
- package/packages/subagents/src/index.ts +6 -3
- package/packages/subagents/src/widget.ts +0 -7
- package/packages/unipi/bundled.js +1052 -837
- package/packages/updater/package.json +4 -3
- package/packages/utility/README.md +1 -1
- package/packages/utility/package.json +7 -4
- package/packages/utility/src/commands.ts +2 -10
- package/packages/utility/src/diff/theme.ts +0 -3
- package/packages/utility/src/tui/name-badge.ts +0 -9
- package/packages/web-api/package.json +2 -2
- package/packages/web-api/src/engine/extract.ts +0 -26
- package/packages/web-api/src/tools.ts +0 -13
- package/packages/workflow/README.md +8 -0
- package/packages/workflow/commands.ts +25 -23
- package/packages/workflow/index.ts +172 -81
- package/packages/workflow/lifecycle.ts +43 -0
- package/packages/workflow/package.json +6 -2
- package/packages/autocomplete/index.ts +0 -7
- package/packages/autocomplete/src/__tests__/command-registry.audit.test.ts +0 -120
- package/packages/autocomplete/src/__tests__/provider.sorting.test.ts +0 -423
- package/packages/compactor/src/compaction/recall-scope.ts +0 -32
- package/packages/compactor/src/compaction/sections.ts +0 -15
- package/packages/compactor/src/display/bash-display.ts +0 -28
- package/packages/compactor/src/display/diff-presentation.ts +0 -25
- package/packages/compactor/src/display/pending-diff-preview.ts +0 -51
- package/packages/compactor/src/display/user-message-box.ts +0 -16
- package/packages/compactor/src/session/analytics.ts +0 -205
- package/packages/image/index.ts +0 -1
- package/packages/input-shortcuts/index.ts +0 -5
- package/packages/input-shortcuts/src/status.ts +0 -35
- package/packages/kanboard/tui/kanboard-overlay.ts +0 -300
- package/packages/mcp/index.ts +0 -1
- package/packages/memory/search.ts +0 -134
- package/packages/milestone/coexist.ts +0 -114
- package/packages/notify/src/__tests__/ask-user-prompt-message.test.ts +0 -159
- package/packages/notify/src/__tests__/event-bus.test.ts +0 -119
- package/packages/notify/src/__tests__/permission-prompt-message.test.ts +0 -172
- package/packages/subagents/src/__tests__/badge-generation.test.ts +0 -315
- package/packages/subagents/src/__tests__/config.test.ts +0 -240
- package/packages/subagents/src/__tests__/esc-propagation.test.ts +0 -162
- package/packages/subagents/src/__tests__/file-lock.test.ts +0 -244
- package/packages/subagents/src/__tests__/shutdown-stale-ctx.test.ts +0 -185
- package/packages/subagents/src/__tests__/workflow-integration.test.ts +0 -334
- package/packages/subagents/src/prompts.ts +0 -39
- package/packages/utility/index.ts +0 -1
- package/packages/web-api/src/tui/progress.ts +0 -168
- package/packages/web-api/src/tui/result.ts +0 -173
|
@@ -327,7 +327,7 @@ var init_events = __esm({
|
|
|
327
327
|
UNIPI_EVENTS = {
|
|
328
328
|
/** Module loaded and ready */
|
|
329
329
|
MODULE_READY: "unipi:module:ready",
|
|
330
|
-
/**
|
|
330
|
+
/** @deprecated No built-in emitter; retained for external compatibility. */
|
|
331
331
|
MODULE_GONE: "unipi:module:gone",
|
|
332
332
|
/** Workflow command started */
|
|
333
333
|
WORKFLOW_START: "unipi:workflow:start",
|
|
@@ -339,9 +339,9 @@ var init_events = __esm({
|
|
|
339
339
|
RALPH_LOOP_END: "unipi:ralph:loop:end",
|
|
340
340
|
/** Ralph loop iteration completed */
|
|
341
341
|
RALPH_ITERATION_DONE: "unipi:ralph:iteration:done",
|
|
342
|
-
/**
|
|
342
|
+
/** @deprecated No built-in responders; use the info registry and /unipi:info. */
|
|
343
343
|
MODULE_STATUS_REQUEST: "unipi:module:status:request",
|
|
344
|
-
/**
|
|
344
|
+
/** @deprecated No built-in aggregator; use the info registry and /unipi:info. */
|
|
345
345
|
MODULE_STATUS_RESPONSE: "unipi:module:status:response",
|
|
346
346
|
/** Info screen group registered */
|
|
347
347
|
INFO_GROUP_REGISTERED: "unipi:info:group:registered",
|
|
@@ -351,7 +351,7 @@ var init_events = __esm({
|
|
|
351
351
|
MEMORY_STORED: "unipi:memory:stored",
|
|
352
352
|
/** Memory deleted */
|
|
353
353
|
MEMORY_DELETED: "unipi:memory:deleted",
|
|
354
|
-
/**
|
|
354
|
+
/** @deprecated No built-in emitter; retained for external compatibility. */
|
|
355
355
|
MEMORY_SEARCHED: "unipi:memory:searched",
|
|
356
356
|
/** Memory consolidation completed */
|
|
357
357
|
MEMORY_CONSOLIDATED: "unipi:memory:consolidated",
|
|
@@ -369,9 +369,9 @@ var init_events = __esm({
|
|
|
369
369
|
MCP_CATALOG_SYNCED: "unipi:mcp:catalog:synced",
|
|
370
370
|
/** Compactor: compaction completed */
|
|
371
371
|
COMPACTOR_COMPACTED: "unipi:compactor:compacted",
|
|
372
|
-
/**
|
|
372
|
+
/** @deprecated Footer reads live Pi session data; retained for compatibility. */
|
|
373
373
|
COMPACTOR_STATS_UPDATED: "unipi:compactor:stats:updated",
|
|
374
|
-
/**
|
|
374
|
+
/** @deprecated No built-in emitter; retained for external compatibility. */
|
|
375
375
|
UTILITY_CLEANUP_START: "unipi:utility:cleanup:start",
|
|
376
376
|
/** Utility module cleanup completed */
|
|
377
377
|
UTILITY_CLEANUP_DONE: "unipi:utility:cleanup:done",
|
|
@@ -379,9 +379,9 @@ var init_events = __esm({
|
|
|
379
379
|
UTILITY_DIAGNOSTICS_START: "unipi:utility:diagnostics:start",
|
|
380
380
|
/** Utility diagnostics completed */
|
|
381
381
|
UTILITY_DIAGNOSTICS_DONE: "unipi:utility:diagnostics:done",
|
|
382
|
-
/**
|
|
382
|
+
/** @deprecated No built-in emitter; retained for external compatibility. */
|
|
383
383
|
UTILITY_CACHE_INVALIDATED: "unipi:utility:cache:invalidated",
|
|
384
|
-
/**
|
|
384
|
+
/** @deprecated No built-in emitter; retained for external compatibility. */
|
|
385
385
|
UTILITY_LIFECYCLE_STATE: "unipi:utility:lifecycle:state",
|
|
386
386
|
/** Notification sent */
|
|
387
387
|
NOTIFICATION_SENT: "unipi:notify:sent",
|
|
@@ -397,11 +397,11 @@ var init_events = __esm({
|
|
|
397
397
|
UPDATE_APPLIED: "unipi:update:applied",
|
|
398
398
|
/** Update error */
|
|
399
399
|
UPDATE_ERROR: "unipi:update:error",
|
|
400
|
-
/**
|
|
400
|
+
/** @deprecated Reserved external contract; no built-in emitter. */
|
|
401
401
|
COCOINDEX_UPDATE_STARTED: "unipi:cocoindex:update:started",
|
|
402
|
-
/**
|
|
402
|
+
/** @deprecated Reserved external contract; no built-in emitter. */
|
|
403
403
|
COCOINDEX_UPDATE_COMPLETED: "unipi:cocoindex:update:completed",
|
|
404
|
-
/**
|
|
404
|
+
/** @deprecated Reserved external contract; no built-in emitter. */
|
|
405
405
|
COCOINDEX_SEARCH_PERFORMED: "unipi:cocoindex:search:performed"
|
|
406
406
|
};
|
|
407
407
|
}
|
|
@@ -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");
|
|
978
1035
|
}
|
|
979
|
-
function
|
|
1036
|
+
function readMigrationState(flagPath = MIGRATED_FLAG) {
|
|
980
1037
|
try {
|
|
981
|
-
|
|
982
|
-
|
|
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;
|
|
983
1041
|
} catch {
|
|
1042
|
+
return null;
|
|
984
1043
|
}
|
|
985
1044
|
}
|
|
986
|
-
function
|
|
1045
|
+
function isMigrated(sourceFingerprint = getMemorySourceFingerprint(), flagPath = MIGRATED_FLAG) {
|
|
1046
|
+
return readMigrationState(flagPath)?.sourceFingerprint === sourceFingerprint;
|
|
1047
|
+
}
|
|
1048
|
+
function markMigrated(sourceFingerprint, result, flagPath = MIGRATED_FLAG) {
|
|
1049
|
+
if (result.failed !== 0 || result.verified !== result.discovered) return false;
|
|
1050
|
+
try {
|
|
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;
|
|
1062
|
+
} catch {
|
|
1063
|
+
return false;
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
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
|
}
|
|
@@ -1457,21 +1548,6 @@ var init_storage = __esm({
|
|
|
1457
1548
|
this.db = null;
|
|
1458
1549
|
}
|
|
1459
1550
|
}
|
|
1460
|
-
/**
|
|
1461
|
-
* Remove corrupted database files (db, wal, shm).
|
|
1462
|
-
*/
|
|
1463
|
-
removeCorruptedDb() {
|
|
1464
|
-
const dbPath = path5.join(this.scopeDir, MEMORY_DB_NAME);
|
|
1465
|
-
const files = [dbPath, `${dbPath}-wal`, `${dbPath}-shm`];
|
|
1466
|
-
for (const file of files) {
|
|
1467
|
-
try {
|
|
1468
|
-
if (fs5.existsSync(file)) {
|
|
1469
|
-
fs5.unlinkSync(file);
|
|
1470
|
-
}
|
|
1471
|
-
} catch {
|
|
1472
|
-
}
|
|
1473
|
-
}
|
|
1474
|
-
}
|
|
1475
1551
|
/**
|
|
1476
1552
|
* Check if database is healthy.
|
|
1477
1553
|
*/
|
|
@@ -1612,7 +1688,7 @@ ${record.content}
|
|
|
1612
1688
|
const filePath = path5.join(this.scopeDir, file);
|
|
1613
1689
|
const record = parseMemoryFile(filePath);
|
|
1614
1690
|
if (!record) continue;
|
|
1615
|
-
const id = record.title.toLowerCase().replace(/[^a-z0-9]+/g, "_");
|
|
1691
|
+
const id = record.id || record.title.toLowerCase().replace(/[^a-z0-9]+/g, "_");
|
|
1616
1692
|
if (existingIds.has(id)) continue;
|
|
1617
1693
|
try {
|
|
1618
1694
|
record.id = id;
|
|
@@ -2254,8 +2330,8 @@ var init_embedding = __esm({
|
|
|
2254
2330
|
});
|
|
2255
2331
|
|
|
2256
2332
|
// packages/info-screen/usage-parser.ts
|
|
2257
|
-
import { readdirSync as
|
|
2258
|
-
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";
|
|
2259
2335
|
import { homedir as homedir5 } from "node:os";
|
|
2260
2336
|
function getCachePath() {
|
|
2261
2337
|
const base = process.env.UNIPI_DIR || join9(homedir5(), ".unipi");
|
|
@@ -2277,10 +2353,10 @@ function readCache() {
|
|
|
2277
2353
|
function writeCache(cache) {
|
|
2278
2354
|
try {
|
|
2279
2355
|
const path28 = getCachePath();
|
|
2280
|
-
mkdirSync7(
|
|
2356
|
+
mkdirSync7(dirname9(path28), { recursive: true });
|
|
2281
2357
|
const tmp = `${path28}.${process.pid}.tmp`;
|
|
2282
2358
|
writeFileSync8(tmp, JSON.stringify(cache), "utf-8");
|
|
2283
|
-
|
|
2359
|
+
renameSync3(tmp, path28);
|
|
2284
2360
|
} catch {
|
|
2285
2361
|
}
|
|
2286
2362
|
}
|
|
@@ -2376,7 +2452,7 @@ function extractRecords(filePath, modelIndex, models) {
|
|
|
2376
2452
|
}
|
|
2377
2453
|
function collectSessionFiles(dir, files) {
|
|
2378
2454
|
try {
|
|
2379
|
-
const entries =
|
|
2455
|
+
const entries = readdirSync5(dir, { withFileTypes: true });
|
|
2380
2456
|
for (const entry of entries) {
|
|
2381
2457
|
const entryPath = join9(dir, entry.name);
|
|
2382
2458
|
if (entry.isDirectory()) {
|
|
@@ -2390,7 +2466,7 @@ function collectSessionFiles(dir, files) {
|
|
|
2390
2466
|
}
|
|
2391
2467
|
async function parseUsageStatsAsync() {
|
|
2392
2468
|
const yielder = async () => {
|
|
2393
|
-
await new Promise((
|
|
2469
|
+
await new Promise((resolve14) => setImmediate(resolve14));
|
|
2394
2470
|
};
|
|
2395
2471
|
const { stats, pending } = collectStats(yielder);
|
|
2396
2472
|
if (pending) await pending;
|
|
@@ -2426,7 +2502,7 @@ function collectStats(yielder) {
|
|
|
2426
2502
|
let mtimeMs = 0;
|
|
2427
2503
|
let size = 0;
|
|
2428
2504
|
try {
|
|
2429
|
-
const st =
|
|
2505
|
+
const st = statSync5(filePath);
|
|
2430
2506
|
mtimeMs = st.mtimeMs;
|
|
2431
2507
|
size = st.size;
|
|
2432
2508
|
} catch {
|
|
@@ -2607,19 +2683,19 @@ __export(env_exports, {
|
|
|
2607
2683
|
formatEnvironmentInfo: () => formatEnvironmentInfo,
|
|
2608
2684
|
getEnvironmentInfo: () => getEnvironmentInfo
|
|
2609
2685
|
});
|
|
2610
|
-
import { existsSync as existsSync18, readdirSync as
|
|
2611
|
-
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";
|
|
2612
2688
|
import { homedir as homedir14 } from "node:os";
|
|
2613
2689
|
function getEnvironmentInfo() {
|
|
2614
2690
|
const unipiModules = [];
|
|
2615
2691
|
const configPaths = [];
|
|
2616
2692
|
const extensionPaths = [];
|
|
2617
2693
|
try {
|
|
2618
|
-
const nodeModules =
|
|
2694
|
+
const nodeModules = resolve6(process.cwd(), "node_modules");
|
|
2619
2695
|
if (existsSync18(nodeModules)) {
|
|
2620
2696
|
const scopePath = join18(nodeModules, "@pi-unipi");
|
|
2621
2697
|
if (existsSync18(scopePath)) {
|
|
2622
|
-
for (const entry of
|
|
2698
|
+
for (const entry of readdirSync11(scopePath)) {
|
|
2623
2699
|
if (entry.startsWith(".")) continue;
|
|
2624
2700
|
const pkgPath = join18(scopePath, entry, "package.json");
|
|
2625
2701
|
if (existsSync18(pkgPath)) {
|
|
@@ -2631,7 +2707,7 @@ function getEnvironmentInfo() {
|
|
|
2631
2707
|
} catch {
|
|
2632
2708
|
}
|
|
2633
2709
|
const globalConfig = join18(homedir14(), ".unipi", "config");
|
|
2634
|
-
const projectConfig =
|
|
2710
|
+
const projectConfig = resolve6(process.cwd(), ".unipi", "config");
|
|
2635
2711
|
if (existsSync18(globalConfig)) {
|
|
2636
2712
|
configPaths.push(globalConfig);
|
|
2637
2713
|
}
|
|
@@ -3878,7 +3954,7 @@ var init_schema = __esm({
|
|
|
3878
3954
|
// packages/compactor/src/config/manager.ts
|
|
3879
3955
|
import { existsSync as existsSync31, mkdirSync as mkdirSync19, readFileSync as readFileSync29, writeFileSync as writeFileSync23 } from "node:fs";
|
|
3880
3956
|
import { homedir as homedir20 } from "node:os";
|
|
3881
|
-
import { dirname as
|
|
3957
|
+
import { dirname as dirname24, join as join32 } from "node:path";
|
|
3882
3958
|
function projectConfigPath(cwd) {
|
|
3883
3959
|
return join32(cwd, ".unipi", "config", "compactor.json");
|
|
3884
3960
|
}
|
|
@@ -3915,7 +3991,7 @@ function loadConfig4(cwd) {
|
|
|
3915
3991
|
function saveConfig3(config, opts) {
|
|
3916
3992
|
try {
|
|
3917
3993
|
const targetPath = opts?.perProject && opts?.cwd ? projectConfigPath(opts.cwd) : COMPACTOR_CONFIG_PATH;
|
|
3918
|
-
const dir =
|
|
3994
|
+
const dir = dirname24(targetPath);
|
|
3919
3995
|
if (!existsSync31(dir)) mkdirSync19(dir, { recursive: true });
|
|
3920
3996
|
writeFileSync23(targetPath, `${JSON.stringify(config, null, 2)}
|
|
3921
3997
|
`);
|
|
@@ -3950,7 +4026,7 @@ function migrateConfig(partial) {
|
|
|
3950
4026
|
}
|
|
3951
4027
|
function scaffoldConfig() {
|
|
3952
4028
|
try {
|
|
3953
|
-
const dir =
|
|
4029
|
+
const dir = dirname24(COMPACTOR_CONFIG_PATH);
|
|
3954
4030
|
if (!existsSync31(dir)) mkdirSync19(dir, { recursive: true });
|
|
3955
4031
|
if (!existsSync31(COMPACTOR_CONFIG_PATH)) {
|
|
3956
4032
|
writeFileSync23(COMPACTOR_CONFIG_PATH, `${JSON.stringify(DEFAULT_COMPACTOR_CONFIG, null, 2)}
|
|
@@ -5466,57 +5542,10 @@ var init_snapshot = __esm({
|
|
|
5466
5542
|
}
|
|
5467
5543
|
});
|
|
5468
5544
|
|
|
5469
|
-
// packages/compactor/src/session/auto-inject.ts
|
|
5470
|
-
var auto_inject_exports = {};
|
|
5471
|
-
__export(auto_inject_exports, {
|
|
5472
|
-
buildAutoInjection: () => buildAutoInjection
|
|
5473
|
-
});
|
|
5474
|
-
function estimateTokens(text) {
|
|
5475
|
-
return Math.ceil(text.length / 4);
|
|
5476
|
-
}
|
|
5477
|
-
function buildAutoInjection(events) {
|
|
5478
|
-
const parts = [];
|
|
5479
|
-
let tokenBudget = MAX_TOKENS2;
|
|
5480
|
-
const roleEvents = events.filter((e) => e.category === "rule");
|
|
5481
|
-
if (roleEvents.length > 0) {
|
|
5482
|
-
const directive = roleEvents[roleEvents.length - 1].data;
|
|
5483
|
-
const directiveText = `[Role Directive]
|
|
5484
|
-
${directive}`;
|
|
5485
|
-
const tokens = estimateTokens(directiveText);
|
|
5486
|
-
if (tokens <= tokenBudget) {
|
|
5487
|
-
parts.push(directiveText);
|
|
5488
|
-
tokenBudget -= tokens;
|
|
5489
|
-
}
|
|
5490
|
-
}
|
|
5491
|
-
if (tokenBudget > 80) {
|
|
5492
|
-
const intentEvents = events.filter((e) => e.category === "intent");
|
|
5493
|
-
if (intentEvents.length > 0) {
|
|
5494
|
-
const mode = intentEvents[intentEvents.length - 1].data;
|
|
5495
|
-
const modeText = `[Session Mode]
|
|
5496
|
-
${mode}`;
|
|
5497
|
-
const tokens = estimateTokens(modeText);
|
|
5498
|
-
if (tokens <= tokenBudget) {
|
|
5499
|
-
parts.push(modeText);
|
|
5500
|
-
tokenBudget -= tokens;
|
|
5501
|
-
}
|
|
5502
|
-
}
|
|
5503
|
-
}
|
|
5504
|
-
if (parts.length === 0) return null;
|
|
5505
|
-
const text = parts.join("\n\n");
|
|
5506
|
-
return { text, tokens: estimateTokens(text) };
|
|
5507
|
-
}
|
|
5508
|
-
var MAX_TOKENS2;
|
|
5509
|
-
var init_auto_inject = __esm({
|
|
5510
|
-
"packages/compactor/src/session/auto-inject.ts"() {
|
|
5511
|
-
"use strict";
|
|
5512
|
-
MAX_TOKENS2 = 150;
|
|
5513
|
-
}
|
|
5514
|
-
});
|
|
5515
|
-
|
|
5516
5545
|
// packages/compactor/src/config/presets.ts
|
|
5517
|
-
import { createHash as
|
|
5546
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
5518
5547
|
function presetHash(config) {
|
|
5519
|
-
return
|
|
5548
|
+
return createHash4("sha256").update(JSON.stringify(config)).digest("hex");
|
|
5520
5549
|
}
|
|
5521
5550
|
function configsEqual(a, b) {
|
|
5522
5551
|
const aHash = presetHash(a);
|
|
@@ -5546,7 +5575,7 @@ function parsePreset(raw) {
|
|
|
5546
5575
|
}
|
|
5547
5576
|
return void 0;
|
|
5548
5577
|
}
|
|
5549
|
-
var pipeline,
|
|
5578
|
+
var pipeline, pipelineWithAutoInjection, preset, PRESET_CONFIGS, presetHashes, OLD_TO_NEW;
|
|
5550
5579
|
var init_presets = __esm({
|
|
5551
5580
|
"packages/compactor/src/config/presets.ts"() {
|
|
5552
5581
|
"use strict";
|
|
@@ -5556,13 +5585,8 @@ var init_presets = __esm({
|
|
|
5556
5585
|
...overrides,
|
|
5557
5586
|
customNoisePatterns: [...overrides.customNoisePatterns ?? DEFAULT_COMPACTOR_CONFIG.pipeline.customNoisePatterns]
|
|
5558
5587
|
});
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
autoInjection: true,
|
|
5562
|
-
proximityReranking: true,
|
|
5563
|
-
timelineSort: true,
|
|
5564
|
-
progressiveThrottling: true,
|
|
5565
|
-
mmapPragma: true
|
|
5588
|
+
pipelineWithAutoInjection = () => pipeline({
|
|
5589
|
+
autoInjection: true
|
|
5566
5590
|
});
|
|
5567
5591
|
preset = (overrides) => ({
|
|
5568
5592
|
...structuredClone(DEFAULT_COMPACTOR_CONFIG),
|
|
@@ -5574,23 +5598,23 @@ var init_presets = __esm({
|
|
|
5574
5598
|
userPreferences: { ...DEFAULT_COMPACTOR_CONFIG.userPreferences, ...overrides.userPreferences ?? {} },
|
|
5575
5599
|
briefTranscript: { ...DEFAULT_COMPACTOR_CONFIG.briefTranscript, ...overrides.briefTranscript ?? {} },
|
|
5576
5600
|
sessionContinuity: { ...DEFAULT_COMPACTOR_CONFIG.sessionContinuity, ...overrides.sessionContinuity ?? {} },
|
|
5577
|
-
|
|
5601
|
+
// Legacy compatibility data only; presets never advertise or alter it.
|
|
5602
|
+
fts5Index: { ...DEFAULT_COMPACTOR_CONFIG.fts5Index },
|
|
5578
5603
|
sandboxExecution: { ...DEFAULT_COMPACTOR_CONFIG.sandboxExecution, ...overrides.sandboxExecution ?? {} },
|
|
5579
|
-
|
|
5604
|
+
// Legacy compatibility data only; presets never advertise or alter it.
|
|
5605
|
+
toolDisplay: { ...DEFAULT_COMPACTOR_CONFIG.toolDisplay },
|
|
5580
5606
|
pipeline: pipeline(overrides.pipeline),
|
|
5581
5607
|
autoCompaction: { ...DEFAULT_COMPACTOR_CONFIG.autoCompaction, ...overrides.autoCompaction ?? {} }
|
|
5582
5608
|
});
|
|
5583
5609
|
PRESET_CONFIGS = {
|
|
5584
5610
|
// New preset names
|
|
5585
5611
|
precise: preset({
|
|
5586
|
-
pipeline: pipeline(
|
|
5587
|
-
sandboxExecution: { ...DEFAULT_COMPACTOR_CONFIG.sandboxExecution, mode: "
|
|
5588
|
-
toolDisplay: { ...DEFAULT_COMPACTOR_CONFIG.toolDisplay, mode: "opencode" }
|
|
5612
|
+
pipeline: pipeline(),
|
|
5613
|
+
sandboxExecution: { ...DEFAULT_COMPACTOR_CONFIG.sandboxExecution, mode: "all" }
|
|
5589
5614
|
}),
|
|
5590
5615
|
thorough: preset({
|
|
5591
|
-
pipeline:
|
|
5592
|
-
briefTranscript: { ...DEFAULT_COMPACTOR_CONFIG.briefTranscript, mode: "full" }
|
|
5593
|
-
toolDisplay: { ...DEFAULT_COMPACTOR_CONFIG.toolDisplay, mode: "verbose" }
|
|
5616
|
+
pipeline: pipelineWithAutoInjection(),
|
|
5617
|
+
briefTranscript: { ...DEFAULT_COMPACTOR_CONFIG.briefTranscript, mode: "full" }
|
|
5594
5618
|
}),
|
|
5595
5619
|
lean: preset({
|
|
5596
5620
|
pipeline: pipeline(),
|
|
@@ -5601,26 +5625,20 @@ var init_presets = __esm({
|
|
|
5601
5625
|
userPreferences: { ...DEFAULT_COMPACTOR_CONFIG.userPreferences, enabled: false, mode: "off" },
|
|
5602
5626
|
briefTranscript: { ...DEFAULT_COMPACTOR_CONFIG.briefTranscript, enabled: true, mode: "minimal" },
|
|
5603
5627
|
sessionContinuity: { ...DEFAULT_COMPACTOR_CONFIG.sessionContinuity, enabled: false, mode: "off" },
|
|
5604
|
-
|
|
5605
|
-
sandboxExecution: { ...DEFAULT_COMPACTOR_CONFIG.sandboxExecution, enabled: false, mode: "off" },
|
|
5606
|
-
toolDisplay: { ...DEFAULT_COMPACTOR_CONFIG.toolDisplay, enabled: true, mode: "opencode" }
|
|
5628
|
+
sandboxExecution: { ...DEFAULT_COMPACTOR_CONFIG.sandboxExecution, enabled: false, mode: "off" }
|
|
5607
5629
|
}),
|
|
5608
5630
|
balanced: preset({
|
|
5609
|
-
pipeline:
|
|
5610
|
-
briefTranscript: { ...DEFAULT_COMPACTOR_CONFIG.briefTranscript, mode: "compact" }
|
|
5611
|
-
toolDisplay: { ...DEFAULT_COMPACTOR_CONFIG.toolDisplay, mode: "balanced" },
|
|
5612
|
-
fts5Index: { ...DEFAULT_COMPACTOR_CONFIG.fts5Index, mode: "auto" }
|
|
5631
|
+
pipeline: pipelineWithAutoInjection(),
|
|
5632
|
+
briefTranscript: { ...DEFAULT_COMPACTOR_CONFIG.briefTranscript, mode: "compact" }
|
|
5613
5633
|
}),
|
|
5614
5634
|
// Backward-compat aliases — map old names to new
|
|
5615
5635
|
opencode: preset({
|
|
5616
|
-
pipeline: pipeline(
|
|
5617
|
-
sandboxExecution: { ...DEFAULT_COMPACTOR_CONFIG.sandboxExecution, mode: "
|
|
5618
|
-
toolDisplay: { ...DEFAULT_COMPACTOR_CONFIG.toolDisplay, mode: "opencode" }
|
|
5636
|
+
pipeline: pipeline(),
|
|
5637
|
+
sandboxExecution: { ...DEFAULT_COMPACTOR_CONFIG.sandboxExecution, mode: "all" }
|
|
5619
5638
|
}),
|
|
5620
5639
|
verbose: preset({
|
|
5621
|
-
pipeline:
|
|
5622
|
-
briefTranscript: { ...DEFAULT_COMPACTOR_CONFIG.briefTranscript, mode: "full" }
|
|
5623
|
-
toolDisplay: { ...DEFAULT_COMPACTOR_CONFIG.toolDisplay, mode: "verbose" }
|
|
5640
|
+
pipeline: pipelineWithAutoInjection(),
|
|
5641
|
+
briefTranscript: { ...DEFAULT_COMPACTOR_CONFIG.briefTranscript, mode: "full" }
|
|
5624
5642
|
}),
|
|
5625
5643
|
minimal: preset({
|
|
5626
5644
|
pipeline: pipeline(),
|
|
@@ -5631,9 +5649,7 @@ var init_presets = __esm({
|
|
|
5631
5649
|
userPreferences: { ...DEFAULT_COMPACTOR_CONFIG.userPreferences, enabled: false, mode: "off" },
|
|
5632
5650
|
briefTranscript: { ...DEFAULT_COMPACTOR_CONFIG.briefTranscript, enabled: true, mode: "minimal" },
|
|
5633
5651
|
sessionContinuity: { ...DEFAULT_COMPACTOR_CONFIG.sessionContinuity, enabled: false, mode: "off" },
|
|
5634
|
-
|
|
5635
|
-
sandboxExecution: { ...DEFAULT_COMPACTOR_CONFIG.sandboxExecution, enabled: false, mode: "off" },
|
|
5636
|
-
toolDisplay: { ...DEFAULT_COMPACTOR_CONFIG.toolDisplay, enabled: true, mode: "opencode" }
|
|
5652
|
+
sandboxExecution: { ...DEFAULT_COMPACTOR_CONFIG.sandboxExecution, enabled: false, mode: "off" }
|
|
5637
5653
|
}),
|
|
5638
5654
|
custom: structuredClone(DEFAULT_COMPACTOR_CONFIG)
|
|
5639
5655
|
};
|
|
@@ -5791,7 +5807,7 @@ var init_settings_overlay = __esm({
|
|
|
5791
5807
|
key: "sessionContinuity",
|
|
5792
5808
|
label: "Session Continuity",
|
|
5793
5809
|
description: "XML resume snapshot for compaction survival",
|
|
5794
|
-
modes: ["full", "
|
|
5810
|
+
modes: ["full", "off"],
|
|
5795
5811
|
getEnabled: (c) => c.sessionContinuity.enabled,
|
|
5796
5812
|
setEnabled: (c, v) => c.sessionContinuity.enabled = v,
|
|
5797
5813
|
getMode: (c) => c.sessionContinuity.mode,
|
|
@@ -5801,30 +5817,17 @@ var init_settings_overlay = __esm({
|
|
|
5801
5817
|
key: "sandboxExecution",
|
|
5802
5818
|
label: "Sandbox Execution",
|
|
5803
5819
|
description: "Polyglot code execution",
|
|
5804
|
-
modes: ["all", "
|
|
5820
|
+
modes: ["all", "off"],
|
|
5805
5821
|
getEnabled: (c) => c.sandboxExecution.enabled,
|
|
5806
5822
|
setEnabled: (c, v) => c.sandboxExecution.enabled = v,
|
|
5807
5823
|
getMode: (c) => c.sandboxExecution.mode,
|
|
5808
5824
|
setMode: (c, v) => c.sandboxExecution.mode = v
|
|
5809
|
-
},
|
|
5810
|
-
{
|
|
5811
|
-
key: "toolDisplay",
|
|
5812
|
-
label: "Tool Display",
|
|
5813
|
-
description: "Override tool output rendering",
|
|
5814
|
-
modes: ["opencode", "balanced", "verbose", "custom"],
|
|
5815
|
-
getEnabled: (c) => c.toolDisplay.enabled,
|
|
5816
|
-
setEnabled: (c, v) => c.toolDisplay.enabled = v,
|
|
5817
|
-
getMode: (c) => c.toolDisplay.mode,
|
|
5818
|
-
setMode: (c, v) => c.toolDisplay.mode = v
|
|
5819
5825
|
}
|
|
5820
5826
|
];
|
|
5821
5827
|
PIPELINE_ITEMS = [
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
{ key: "
|
|
5825
|
-
{ key: "proximityReranking", label: "Proximity Reranking", description: "Rerank search results by proximity", group: "On Search", getValue: (c) => c.pipeline.proximityReranking, setValue: (c, v) => c.pipeline.proximityReranking = v },
|
|
5826
|
-
{ key: "timelineSort", label: "Timeline Sort", description: "Sort session events chronologically", group: "On Search", getValue: (c) => c.pipeline.timelineSort, setValue: (c, v) => c.pipeline.timelineSort = v },
|
|
5827
|
-
{ key: "progressiveThrottling", label: "Progressive Throttling", description: "Slow down processing for large projects", group: "On Compaction", getValue: (c) => c.pipeline.progressiveThrottling, setValue: (c, v) => c.pipeline.progressiveThrottling = v }
|
|
5828
|
+
// Only expose implemented behavior. Reserved compatibility fields remain in
|
|
5829
|
+
// the persisted schema so existing config files continue to load.
|
|
5830
|
+
{ key: "autoInjection", label: "Auto Injection", description: "Inject behavioral state after compaction", group: "On Compaction", getValue: (c) => c.pipeline.autoInjection, setValue: (c, v) => c.pipeline.autoInjection = v }
|
|
5828
5831
|
];
|
|
5829
5832
|
PRESETS2 = ["precise", "balanced", "thorough", "lean"];
|
|
5830
5833
|
THRESHOLD_VALUES = ["60%", "70%", "75%", "80%", "85%", "90%", "95%"];
|
|
@@ -5832,20 +5835,20 @@ var init_settings_overlay = __esm({
|
|
|
5832
5835
|
REPEAT_GROWTH_VALUES = ["0", "1k", "4k", "8k", "16k", "32k"];
|
|
5833
5836
|
PRESET_DESCRIPTIONS = {
|
|
5834
5837
|
precise: {
|
|
5835
|
-
summary: "Code-heavy, minimal waste \u2014 compaction: full, sandbox:
|
|
5836
|
-
detail: "Max token savings. Compaction: full
|
|
5838
|
+
summary: "Code-heavy, minimal waste \u2014 compaction: full, sandbox: all",
|
|
5839
|
+
detail: "Max token savings. Compaction: full.\nSandbox: all. Auto injection: off."
|
|
5837
5840
|
},
|
|
5838
5841
|
balanced: {
|
|
5839
5842
|
summary: "Daily use (default) \u2014 all strategies moderate",
|
|
5840
|
-
detail: "Moderate all strategies
|
|
5843
|
+
detail: "Moderate all strategies.\nSandbox: all. Auto injection: on."
|
|
5841
5844
|
},
|
|
5842
5845
|
thorough: {
|
|
5843
5846
|
summary: "Debug/audit \u2014 everything on, full transcript",
|
|
5844
|
-
detail: "Everything enabled
|
|
5847
|
+
detail: "Everything enabled.\nSandbox: all. Auto injection: on."
|
|
5845
5848
|
},
|
|
5846
5849
|
lean: {
|
|
5847
5850
|
summary: "Quick fixes, short sessions \u2014 compaction only",
|
|
5848
|
-
detail: "Compaction only
|
|
5851
|
+
detail: "Compaction only.\nSandbox: off. Auto injection: off."
|
|
5849
5852
|
}
|
|
5850
5853
|
};
|
|
5851
5854
|
THEME = {
|
|
@@ -6397,7 +6400,7 @@ __export(evaluator_exports, {
|
|
|
6397
6400
|
splitChainedCommands: () => splitChainedCommands
|
|
6398
6401
|
});
|
|
6399
6402
|
import { realpathSync as realpathSync2, existsSync as existsSync37, readFileSync as readFileSync32 } from "node:fs";
|
|
6400
|
-
import { resolve as
|
|
6403
|
+
import { resolve as resolve12, join as join36 } from "node:path";
|
|
6401
6404
|
import { homedir as homedir22 } from "node:os";
|
|
6402
6405
|
function loadProjectPermissions(cwd, basePolicy) {
|
|
6403
6406
|
const settingsPath = join36(cwd, ".pi", "settings.json");
|
|
@@ -6469,7 +6472,7 @@ function splitChainedCommands(command) {
|
|
|
6469
6472
|
return commands;
|
|
6470
6473
|
}
|
|
6471
6474
|
function evaluateFilePath(filePath, policy, cwd = process.cwd()) {
|
|
6472
|
-
const resolved =
|
|
6475
|
+
const resolved = resolve12(cwd, filePath);
|
|
6473
6476
|
try {
|
|
6474
6477
|
const real = realpathSync2(resolved);
|
|
6475
6478
|
const home = homedir22();
|
|
@@ -6571,137 +6574,6 @@ var init_scanner = __esm({
|
|
|
6571
6574
|
}
|
|
6572
6575
|
});
|
|
6573
6576
|
|
|
6574
|
-
// packages/compactor/src/display/render-utils.ts
|
|
6575
|
-
function splitLines(text) {
|
|
6576
|
-
return text.split(/\r?\n/);
|
|
6577
|
-
}
|
|
6578
|
-
function countNonEmptyLines(text) {
|
|
6579
|
-
return splitLines(text).filter((l) => l.trim()).length;
|
|
6580
|
-
}
|
|
6581
|
-
function previewLines(text, lines) {
|
|
6582
|
-
const all = splitLines(text);
|
|
6583
|
-
if (all.length <= lines) return text;
|
|
6584
|
-
return all.slice(0, lines).join("\n") + `
|
|
6585
|
-
...(${all.length - lines} more lines)`;
|
|
6586
|
-
}
|
|
6587
|
-
function shortenPath(path28, maxLen = 60) {
|
|
6588
|
-
if (path28.length <= maxLen) return path28;
|
|
6589
|
-
const parts = path28.split("/");
|
|
6590
|
-
if (parts.length <= 2) return "..." + path28.slice(-(maxLen - 3));
|
|
6591
|
-
return parts[0] + "/.../" + parts.slice(-2).join("/");
|
|
6592
|
-
}
|
|
6593
|
-
var init_render_utils = __esm({
|
|
6594
|
-
"packages/compactor/src/display/render-utils.ts"() {
|
|
6595
|
-
"use strict";
|
|
6596
|
-
}
|
|
6597
|
-
});
|
|
6598
|
-
|
|
6599
|
-
// packages/compactor/src/display/tool-overrides.ts
|
|
6600
|
-
var tool_overrides_exports = {};
|
|
6601
|
-
__export(tool_overrides_exports, {
|
|
6602
|
-
applyToolDisplayOverride: () => applyToolDisplayOverride,
|
|
6603
|
-
renderBashResult: () => renderBashResult,
|
|
6604
|
-
renderReadResult: () => renderReadResult,
|
|
6605
|
-
renderSearchResult: () => renderSearchResult
|
|
6606
|
-
});
|
|
6607
|
-
function renderReadResult(content, filePath, config) {
|
|
6608
|
-
switch (config.readOutputMode) {
|
|
6609
|
-
case "hidden":
|
|
6610
|
-
return `[Read: ${shortenPath(filePath)}]`;
|
|
6611
|
-
case "summary":
|
|
6612
|
-
return `[Read: ${shortenPath(filePath)} \u2014 ${countNonEmptyLines(content)} lines]`;
|
|
6613
|
-
case "preview":
|
|
6614
|
-
return previewLines(content, config.previewLines ?? 20);
|
|
6615
|
-
default:
|
|
6616
|
-
return content;
|
|
6617
|
-
}
|
|
6618
|
-
}
|
|
6619
|
-
function renderSearchResult(results, config) {
|
|
6620
|
-
switch (config.searchOutputMode) {
|
|
6621
|
-
case "hidden":
|
|
6622
|
-
return `[Search results hidden]`;
|
|
6623
|
-
case "count":
|
|
6624
|
-
return `[Search: ${countNonEmptyLines(results)} matches]`;
|
|
6625
|
-
case "preview":
|
|
6626
|
-
return previewLines(results, config.previewLines ?? 20);
|
|
6627
|
-
default:
|
|
6628
|
-
return results;
|
|
6629
|
-
}
|
|
6630
|
-
}
|
|
6631
|
-
function renderBashResult(output, command, config) {
|
|
6632
|
-
switch (config.bashOutputMode) {
|
|
6633
|
-
case "hidden":
|
|
6634
|
-
return `[Bash: ${command.slice(0, 60)}]`;
|
|
6635
|
-
case "summary":
|
|
6636
|
-
return `[Bash: ${command.slice(0, 60)} \u2014 ${countNonEmptyLines(output)} lines]`;
|
|
6637
|
-
case "preview":
|
|
6638
|
-
return previewLines(output, config.bashCollapsedLines ?? 5);
|
|
6639
|
-
default:
|
|
6640
|
-
return output;
|
|
6641
|
-
}
|
|
6642
|
-
}
|
|
6643
|
-
function applyToolDisplayOverride(toolName, event, config) {
|
|
6644
|
-
const content = event.content;
|
|
6645
|
-
if (!content || !Array.isArray(content) || content.length === 0) return void 0;
|
|
6646
|
-
const textContent = content[0]?.text ?? "";
|
|
6647
|
-
const previewLinesCount = config.previewLines ?? 20;
|
|
6648
|
-
const collapsedLines = config.bashCollapsedLines ?? 5;
|
|
6649
|
-
let overridden;
|
|
6650
|
-
switch (toolName) {
|
|
6651
|
-
case "read": {
|
|
6652
|
-
const filePath = String(event.args?.path ?? "");
|
|
6653
|
-
const mode = config.readOutputMode ?? "full";
|
|
6654
|
-
if (mode === "hidden") {
|
|
6655
|
-
overridden = `[Read: ${shortenPath(filePath)}]`;
|
|
6656
|
-
} else if (mode === "summary") {
|
|
6657
|
-
overridden = `[Read: ${shortenPath(filePath)} \u2014 ${countNonEmptyLines(textContent)} lines]`;
|
|
6658
|
-
} else if (mode === "preview") {
|
|
6659
|
-
overridden = previewLines(textContent, previewLinesCount);
|
|
6660
|
-
}
|
|
6661
|
-
break;
|
|
6662
|
-
}
|
|
6663
|
-
case "grep":
|
|
6664
|
-
case "find":
|
|
6665
|
-
case "ls": {
|
|
6666
|
-
const mode = config.searchOutputMode ?? "full";
|
|
6667
|
-
if (mode === "hidden") {
|
|
6668
|
-
overridden = `[${toolName} results hidden]`;
|
|
6669
|
-
} else if (mode === "count") {
|
|
6670
|
-
overridden = `[${toolName}: ${countNonEmptyLines(textContent)} matches]`;
|
|
6671
|
-
} else if (mode === "preview") {
|
|
6672
|
-
overridden = previewLines(textContent, previewLinesCount);
|
|
6673
|
-
}
|
|
6674
|
-
break;
|
|
6675
|
-
}
|
|
6676
|
-
case "bash": {
|
|
6677
|
-
const command = String(event.args?.command ?? "");
|
|
6678
|
-
const mode = config.bashOutputMode ?? "full";
|
|
6679
|
-
if (mode === "hidden") {
|
|
6680
|
-
overridden = `[Bash: ${command.slice(0, 60)}]`;
|
|
6681
|
-
} else if (mode === "summary") {
|
|
6682
|
-
overridden = `[Bash: ${command.slice(0, 60)} \u2014 ${countNonEmptyLines(textContent)} lines]`;
|
|
6683
|
-
} else if (mode === "preview") {
|
|
6684
|
-
overridden = previewLines(textContent, collapsedLines);
|
|
6685
|
-
}
|
|
6686
|
-
break;
|
|
6687
|
-
}
|
|
6688
|
-
default:
|
|
6689
|
-
return void 0;
|
|
6690
|
-
}
|
|
6691
|
-
if (overridden !== void 0) {
|
|
6692
|
-
return {
|
|
6693
|
-
content: [{ type: "text", text: overridden }]
|
|
6694
|
-
};
|
|
6695
|
-
}
|
|
6696
|
-
return void 0;
|
|
6697
|
-
}
|
|
6698
|
-
var init_tool_overrides = __esm({
|
|
6699
|
-
"packages/compactor/src/display/tool-overrides.ts"() {
|
|
6700
|
-
"use strict";
|
|
6701
|
-
init_render_utils();
|
|
6702
|
-
}
|
|
6703
|
-
});
|
|
6704
|
-
|
|
6705
6577
|
// packages/compactor/src/display/diff-width-safety.ts
|
|
6706
6578
|
var diff_width_safety_exports = {};
|
|
6707
6579
|
__export(diff_width_safety_exports, {
|
|
@@ -6770,6 +6642,9 @@ var init_thinking_label = __esm({
|
|
|
6770
6642
|
init_core();
|
|
6771
6643
|
import { dirname as dirname2 } from "node:path";
|
|
6772
6644
|
import { fileURLToPath } from "node:url";
|
|
6645
|
+
import {
|
|
6646
|
+
buildSessionContext
|
|
6647
|
+
} from "@earendil-works/pi-coding-agent";
|
|
6773
6648
|
|
|
6774
6649
|
// packages/workflow/commands.ts
|
|
6775
6650
|
init_core();
|
|
@@ -7038,11 +6913,15 @@ function registerWorkflowCommands(pi, options) {
|
|
|
7038
6913
|
return null;
|
|
7039
6914
|
},
|
|
7040
6915
|
handler: async (args, ctx) => {
|
|
7041
|
-
const
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
6916
|
+
const workflowEvent = {
|
|
6917
|
+
command: cmd.name,
|
|
6918
|
+
fullCommand: `/${fullCommand}`,
|
|
6919
|
+
args: args?.trim() ?? ""
|
|
6920
|
+
};
|
|
6921
|
+
if (!options.activateSandbox(workflowEvent)) {
|
|
6922
|
+
if (ctx.hasUI) ctx.ui.notify("Another UniPi workflow is still active", "warning");
|
|
6923
|
+
return;
|
|
6924
|
+
}
|
|
7046
6925
|
let skillContent = "";
|
|
7047
6926
|
try {
|
|
7048
6927
|
const skillPath = join3(
|
|
@@ -7071,7 +6950,12 @@ Arguments: ${args.trim()}`;
|
|
|
7071
6950
|
${skillContent}
|
|
7072
6951
|
</skill_content>`;
|
|
7073
6952
|
}
|
|
7074
|
-
|
|
6953
|
+
try {
|
|
6954
|
+
pi.sendUserMessage(message, { deliverAs: "followUp" });
|
|
6955
|
+
} catch (error) {
|
|
6956
|
+
options.abortWorkflow();
|
|
6957
|
+
throw error;
|
|
6958
|
+
}
|
|
7075
6959
|
if (ctx.hasUI) {
|
|
7076
6960
|
ctx.ui.notify(`Running /${fullCommand}`, "info");
|
|
7077
6961
|
const ralphStatus = options.isRalphDetected() ? "\u2713 rl" : "\u25CB rl";
|
|
@@ -7106,84 +6990,180 @@ ${taskContent}`,
|
|
|
7106
6990
|
});
|
|
7107
6991
|
}
|
|
7108
6992
|
|
|
6993
|
+
// packages/workflow/lifecycle.ts
|
|
6994
|
+
var WorkflowLifecycle = class {
|
|
6995
|
+
constructor(now2 = Date.now) {
|
|
6996
|
+
this.now = now2;
|
|
6997
|
+
}
|
|
6998
|
+
now;
|
|
6999
|
+
active = null;
|
|
7000
|
+
start(event) {
|
|
7001
|
+
if (this.active) return false;
|
|
7002
|
+
this.active = { ...event, startedAt: this.now() };
|
|
7003
|
+
return true;
|
|
7004
|
+
}
|
|
7005
|
+
complete(messages) {
|
|
7006
|
+
if (!this.active) return void 0;
|
|
7007
|
+
const workflow = this.active;
|
|
7008
|
+
this.active = null;
|
|
7009
|
+
const finalAssistant = [...messages].reverse().find((message) => message.role === "assistant");
|
|
7010
|
+
const success = finalAssistant?.stopReason !== "error" && finalAssistant?.stopReason !== "aborted";
|
|
7011
|
+
return {
|
|
7012
|
+
command: workflow.command,
|
|
7013
|
+
fullCommand: workflow.fullCommand,
|
|
7014
|
+
args: workflow.args,
|
|
7015
|
+
success,
|
|
7016
|
+
durationMs: this.now() - workflow.startedAt
|
|
7017
|
+
};
|
|
7018
|
+
}
|
|
7019
|
+
reset() {
|
|
7020
|
+
this.active = null;
|
|
7021
|
+
}
|
|
7022
|
+
};
|
|
7023
|
+
|
|
7109
7024
|
// packages/workflow/index.ts
|
|
7110
7025
|
var VERSION = getPackageVersion(dirname2(fileURLToPath(import.meta.url)));
|
|
7111
|
-
var
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
7115
|
-
|
|
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
|
+
}
|
|
7116
7100
|
function workflow_default(pi) {
|
|
7101
|
+
const workflowLifecycle = new WorkflowLifecycle();
|
|
7102
|
+
let ralphDetected = false;
|
|
7103
|
+
let sandboxCommand = null;
|
|
7117
7104
|
registerWorkflowCommands(pi, {
|
|
7118
7105
|
isRalphDetected: () => ralphDetected,
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
currentSandboxTools = tools;
|
|
7106
|
+
activateSandbox: (event) => {
|
|
7107
|
+
if (!workflowLifecycle.start(event)) return false;
|
|
7108
|
+
sandboxCommand = event.command;
|
|
7109
|
+
emitEvent(pi, UNIPI_EVENTS.WORKFLOW_START, event);
|
|
7110
|
+
return true;
|
|
7125
7111
|
},
|
|
7126
|
-
|
|
7127
|
-
|
|
7112
|
+
abortWorkflow: () => {
|
|
7113
|
+
sandboxCommand = null;
|
|
7114
|
+
workflowLifecycle.reset();
|
|
7128
7115
|
}
|
|
7129
7116
|
});
|
|
7130
7117
|
pi.on("tool_call", async (event, _ctx) => {
|
|
7131
|
-
if (!
|
|
7132
|
-
const
|
|
7133
|
-
if (!
|
|
7118
|
+
if (!sandboxCommand) return;
|
|
7119
|
+
const level = getSandboxLevel(sandboxCommand);
|
|
7120
|
+
if (!isToolAllowed(level, event.toolName)) {
|
|
7121
|
+
const blocked = getBlockedToolsForLevel(level);
|
|
7134
7122
|
return {
|
|
7135
7123
|
block: true,
|
|
7136
|
-
reason: `Tool "${event.toolName}" is not allowed in ${
|
|
7124
|
+
reason: `Tool "${event.toolName}" is not allowed in ${level} sandbox. Blocked: ${blocked.join(", ")}`
|
|
7137
7125
|
};
|
|
7138
7126
|
}
|
|
7139
7127
|
});
|
|
7140
|
-
pi.on("before_agent_start", async (
|
|
7141
|
-
|
|
7142
|
-
const
|
|
7143
|
-
const
|
|
7144
|
-
|
|
7145
|
-
|
|
7146
|
-
|
|
7147
|
-
|
|
7148
|
-
<sandbox>
|
|
7149
|
-
Sandbox mode: ${currentSandboxLevel}.
|
|
7150
|
-
Available tools: ${allowed.join(", ")}.${blockedLine}`;
|
|
7151
|
-
if (currentSandboxLevel === "brainstorm") {
|
|
7152
|
-
return {
|
|
7153
|
-
systemPrompt: event.systemPrompt + base + `
|
|
7154
|
-
The write tool is available but restricted to .unipi/docs/specs/ only.
|
|
7155
|
-
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.
|
|
7156
|
-
Do NOT attempt to call blocked tools. Do NOT output tool call XML for them.
|
|
7157
|
-
If the user requests an action that requires a blocked tool, respond that you do not have access.
|
|
7158
|
-
</sandbox>`
|
|
7159
|
-
};
|
|
7160
|
-
}
|
|
7161
|
-
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;
|
|
7162
7136
|
return {
|
|
7163
|
-
|
|
7164
|
-
|
|
7165
|
-
|
|
7166
|
-
|
|
7167
|
-
|
|
7168
|
-
|
|
7169
|
-
|
|
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
|
+
}
|
|
7170
7147
|
};
|
|
7171
7148
|
}
|
|
7149
|
+
const prior = latest ?? historical;
|
|
7150
|
+
if (!prior || !isActiveSnapshot(prior)) return void 0;
|
|
7172
7151
|
return {
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
|
|
7176
|
-
|
|
7152
|
+
message: {
|
|
7153
|
+
customType: WORKFLOW_SANDBOX_SNAPSHOT_TYPE,
|
|
7154
|
+
content: formatInactiveSandboxSnapshot(),
|
|
7155
|
+
display: false,
|
|
7156
|
+
details: {
|
|
7157
|
+
active: false
|
|
7158
|
+
}
|
|
7159
|
+
}
|
|
7177
7160
|
};
|
|
7178
7161
|
});
|
|
7179
|
-
pi.on("agent_end", async (
|
|
7180
|
-
|
|
7181
|
-
|
|
7182
|
-
|
|
7183
|
-
|
|
7184
|
-
currentSandboxLevel = null;
|
|
7185
|
-
currentSandboxTools = null;
|
|
7186
|
-
}
|
|
7162
|
+
pi.on("agent_end", async (event, _ctx) => {
|
|
7163
|
+
const completedWorkflow = workflowLifecycle.complete(event.messages);
|
|
7164
|
+
if (!completedWorkflow) return;
|
|
7165
|
+
sandboxCommand = null;
|
|
7166
|
+
emitEvent(pi, UNIPI_EVENTS.WORKFLOW_END, completedWorkflow);
|
|
7187
7167
|
});
|
|
7188
7168
|
pi.on("session_start", async (_event, ctx) => {
|
|
7189
7169
|
initUnipiDirs();
|
|
@@ -7196,7 +7176,7 @@ If the user requires an action that requires a blocked tool, respond that you do
|
|
|
7196
7176
|
if (!ralphDetected) {
|
|
7197
7177
|
try {
|
|
7198
7178
|
const allTools = pi.getAllTools();
|
|
7199
|
-
ralphDetected = allTools.some((
|
|
7179
|
+
ralphDetected = allTools.some((tool) => tool.name === "ralph_start");
|
|
7200
7180
|
} catch {
|
|
7201
7181
|
}
|
|
7202
7182
|
}
|
|
@@ -7207,14 +7187,12 @@ If the user requires an action that requires a blocked tool, respond that you do
|
|
|
7207
7187
|
});
|
|
7208
7188
|
pi.events.on(UNIPI_EVENTS.MODULE_READY, (data) => {
|
|
7209
7189
|
const event = data;
|
|
7210
|
-
if (event?.name === MODULES.RALPH)
|
|
7211
|
-
ralphDetected = true;
|
|
7212
|
-
}
|
|
7190
|
+
if (event?.name === MODULES.RALPH) ralphDetected = true;
|
|
7213
7191
|
});
|
|
7214
7192
|
pi.on("session_shutdown", async () => {
|
|
7215
7193
|
ralphDetected = false;
|
|
7216
|
-
|
|
7217
|
-
|
|
7194
|
+
sandboxCommand = null;
|
|
7195
|
+
workflowLifecycle.reset();
|
|
7218
7196
|
});
|
|
7219
7197
|
}
|
|
7220
7198
|
|
|
@@ -7480,12 +7458,20 @@ Use /unipi:ralph-resume <name> to continue`, "info");
|
|
|
7480
7458
|
);
|
|
7481
7459
|
return null;
|
|
7482
7460
|
}
|
|
7461
|
+
this.emitIterationDone(state);
|
|
7483
7462
|
const needsReflection = state.reflectEvery > 0 && (state.iteration - 1) % state.reflectEvery === 0;
|
|
7484
7463
|
if (needsReflection) state.lastReflectionAt = state.iteration;
|
|
7485
7464
|
this.saveState(state);
|
|
7486
7465
|
this.updateUI();
|
|
7487
7466
|
return { state, needsReflection };
|
|
7488
7467
|
}
|
|
7468
|
+
emitIterationDone(state) {
|
|
7469
|
+
this.emitFn(UNIPI_EVENTS.RALPH_ITERATION_DONE, {
|
|
7470
|
+
name: state.name,
|
|
7471
|
+
iteration: state.iteration - 1,
|
|
7472
|
+
nextIteration: state.iteration
|
|
7473
|
+
});
|
|
7474
|
+
}
|
|
7489
7475
|
archiveLoop(name) {
|
|
7490
7476
|
const state = this.loadState(name);
|
|
7491
7477
|
if (!state) return false;
|
|
@@ -8084,7 +8070,7 @@ function handleNuke(rest, ctx, pi) {
|
|
|
8084
8070
|
// packages/memory/index.ts
|
|
8085
8071
|
init_core();
|
|
8086
8072
|
init_storage();
|
|
8087
|
-
import { dirname as
|
|
8073
|
+
import { dirname as dirname7 } from "node:path";
|
|
8088
8074
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
8089
8075
|
|
|
8090
8076
|
// packages/memory/tools.ts
|
|
@@ -8792,7 +8778,7 @@ init_settings();
|
|
|
8792
8778
|
function getInfoRegistry2() {
|
|
8793
8779
|
return globalThis.__unipi_info_registry;
|
|
8794
8780
|
}
|
|
8795
|
-
var VERSION3 = getPackageVersion(
|
|
8781
|
+
var VERSION3 = getPackageVersion(dirname7(fileURLToPath4(import.meta.url)));
|
|
8796
8782
|
var projectStorage = null;
|
|
8797
8783
|
var orphanSyncPending = false;
|
|
8798
8784
|
function ensureOrphanSync(storage) {
|
|
@@ -9014,12 +9000,12 @@ function memory_default(pi) {
|
|
|
9014
9000
|
|
|
9015
9001
|
// packages/info-screen/index.ts
|
|
9016
9002
|
init_core();
|
|
9017
|
-
import { dirname as
|
|
9003
|
+
import { dirname as dirname10 } from "node:path";
|
|
9018
9004
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
9019
9005
|
|
|
9020
9006
|
// packages/info-screen/config.ts
|
|
9021
9007
|
import { readFileSync as readFileSync7, writeFileSync as writeFileSync7, existsSync as existsSync8, mkdirSync as mkdirSync6 } from "node:fs";
|
|
9022
|
-
import { join as join8, dirname as
|
|
9008
|
+
import { join as join8, dirname as dirname8 } from "node:path";
|
|
9023
9009
|
import { homedir as homedir4 } from "node:os";
|
|
9024
9010
|
|
|
9025
9011
|
// packages/info-screen/types.ts
|
|
@@ -9048,7 +9034,7 @@ function readSettingsFile() {
|
|
|
9048
9034
|
}
|
|
9049
9035
|
}
|
|
9050
9036
|
function writeSettingsFile(data) {
|
|
9051
|
-
const dir =
|
|
9037
|
+
const dir = dirname8(SETTINGS_PATH);
|
|
9052
9038
|
if (!existsSync8(dir)) {
|
|
9053
9039
|
mkdirSync6(dir, { recursive: true });
|
|
9054
9040
|
}
|
|
@@ -9349,7 +9335,7 @@ if (!globalThis.__unipi_info_registry) {
|
|
|
9349
9335
|
|
|
9350
9336
|
// packages/info-screen/core-groups.ts
|
|
9351
9337
|
init_core();
|
|
9352
|
-
import { readFileSync as readFileSync9, readdirSync as
|
|
9338
|
+
import { readFileSync as readFileSync9, readdirSync as readdirSync6, existsSync as existsSync10 } from "node:fs";
|
|
9353
9339
|
import { join as join10 } from "node:path";
|
|
9354
9340
|
import { homedir as homedir6 } from "node:os";
|
|
9355
9341
|
init_usage_parser();
|
|
@@ -9410,7 +9396,7 @@ function discoverExtensions() {
|
|
|
9410
9396
|
for (const dir of extensionDirs) {
|
|
9411
9397
|
if (!existsSync10(dir)) continue;
|
|
9412
9398
|
try {
|
|
9413
|
-
const entries =
|
|
9399
|
+
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
9414
9400
|
for (const entry of entries) {
|
|
9415
9401
|
const name = entry.name;
|
|
9416
9402
|
if (counted.has(name)) continue;
|
|
@@ -9484,7 +9470,7 @@ function discoverSkills() {
|
|
|
9484
9470
|
for (const dir of skillDirs) {
|
|
9485
9471
|
if (!existsSync10(dir)) continue;
|
|
9486
9472
|
try {
|
|
9487
|
-
const entries =
|
|
9473
|
+
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
9488
9474
|
for (const entry of entries) {
|
|
9489
9475
|
if (!entry.isDirectory()) continue;
|
|
9490
9476
|
const name = entry.name;
|
|
@@ -10595,7 +10581,7 @@ var SettingsOverlay = class _SettingsOverlay {
|
|
|
10595
10581
|
};
|
|
10596
10582
|
|
|
10597
10583
|
// packages/info-screen/index.ts
|
|
10598
|
-
var VERSION4 = getPackageVersion(
|
|
10584
|
+
var VERSION4 = getPackageVersion(dirname10(fileURLToPath5(import.meta.url)));
|
|
10599
10585
|
function info_screen_default(pi) {
|
|
10600
10586
|
setPiApi(pi);
|
|
10601
10587
|
registerCoreGroups();
|
|
@@ -10735,14 +10721,36 @@ function info_screen_default(pi) {
|
|
|
10735
10721
|
}
|
|
10736
10722
|
|
|
10737
10723
|
// packages/subagents/src/index.ts
|
|
10738
|
-
init_core();
|
|
10739
10724
|
import { defineTool } from "@earendil-works/pi-coding-agent";
|
|
10740
10725
|
import { Text } from "@earendil-works/pi-tui";
|
|
10741
10726
|
import { Type as Type3 } from "typebox";
|
|
10742
|
-
import { existsSync as existsSync13, readdirSync as
|
|
10727
|
+
import { existsSync as existsSync13, readdirSync as readdirSync8 } from "node:fs";
|
|
10743
10728
|
import { join as join13 } from "node:path";
|
|
10744
10729
|
import { homedir as homedir9 } from "node:os";
|
|
10745
10730
|
|
|
10731
|
+
// packages/subagents/src/core-compat.ts
|
|
10732
|
+
var MODULES2 = { SUBAGENTS: "subagents" };
|
|
10733
|
+
var UNIPI_EVENTS2 = {
|
|
10734
|
+
MODULE_READY: "unipi:module:ready",
|
|
10735
|
+
BADGE_GENERATE_REQUEST: "unipi:badge:generate:request"
|
|
10736
|
+
};
|
|
10737
|
+
function emitEvent2(pi, eventName, payload) {
|
|
10738
|
+
try {
|
|
10739
|
+
pi.events.emit(eventName, payload);
|
|
10740
|
+
return true;
|
|
10741
|
+
} catch {
|
|
10742
|
+
return false;
|
|
10743
|
+
}
|
|
10744
|
+
}
|
|
10745
|
+
async function withHerdrBlocked2(pi, label, fn) {
|
|
10746
|
+
emitEvent2(pi, "herdr:blocked", { active: true, label });
|
|
10747
|
+
try {
|
|
10748
|
+
return await fn();
|
|
10749
|
+
} finally {
|
|
10750
|
+
emitEvent2(pi, "herdr:blocked", { active: false, label });
|
|
10751
|
+
}
|
|
10752
|
+
}
|
|
10753
|
+
|
|
10746
10754
|
// packages/subagents/src/agent-manager.ts
|
|
10747
10755
|
import { randomUUID } from "node:crypto";
|
|
10748
10756
|
|
|
@@ -10955,14 +10963,14 @@ ${agentPrompt}`;
|
|
|
10955
10963
|
init_model_resolver();
|
|
10956
10964
|
|
|
10957
10965
|
// packages/subagents/src/custom-agents.ts
|
|
10958
|
-
import { existsSync as existsSync11, readdirSync as
|
|
10966
|
+
import { existsSync as existsSync11, readdirSync as readdirSync7, readFileSync as readFileSync10, renameSync as renameSync4 } from "node:fs";
|
|
10959
10967
|
import { join as join11 } from "node:path";
|
|
10960
10968
|
import { homedir as homedir7 } from "node:os";
|
|
10961
10969
|
import { parseFrontmatter } from "@earendil-works/pi-coding-agent";
|
|
10962
10970
|
function backupCorrupted(filePath) {
|
|
10963
10971
|
const backupPath = filePath + ".bak";
|
|
10964
10972
|
try {
|
|
10965
|
-
|
|
10973
|
+
renameSync4(filePath, backupPath);
|
|
10966
10974
|
} catch {
|
|
10967
10975
|
}
|
|
10968
10976
|
}
|
|
@@ -11011,7 +11019,7 @@ function loadCustomAgents(cwd) {
|
|
|
11011
11019
|
const agents = /* @__PURE__ */ new Map();
|
|
11012
11020
|
const globalDir = getGlobalAgentsDir();
|
|
11013
11021
|
if (existsSync11(globalDir)) {
|
|
11014
|
-
const files =
|
|
11022
|
+
const files = readdirSync7(globalDir).filter((f) => f.endsWith(".md"));
|
|
11015
11023
|
for (const file of files) {
|
|
11016
11024
|
const agent = loadAgentFromFile(join11(globalDir, file), "global");
|
|
11017
11025
|
if (agent) {
|
|
@@ -11021,7 +11029,7 @@ function loadCustomAgents(cwd) {
|
|
|
11021
11029
|
}
|
|
11022
11030
|
const projectDir = getProjectAgentsDir(cwd);
|
|
11023
11031
|
if (existsSync11(projectDir)) {
|
|
11024
|
-
const files =
|
|
11032
|
+
const files = readdirSync7(projectDir).filter((f) => f.endsWith(".md"));
|
|
11025
11033
|
for (const file of files) {
|
|
11026
11034
|
const agent = loadAgentFromFile(join11(projectDir, file), "project");
|
|
11027
11035
|
if (agent) {
|
|
@@ -11048,17 +11056,17 @@ var FileLock = class {
|
|
|
11048
11056
|
*/
|
|
11049
11057
|
async acquire(filePath, agentId) {
|
|
11050
11058
|
while (this.locks.has(filePath)) {
|
|
11051
|
-
await new Promise((
|
|
11059
|
+
await new Promise((resolve14) => {
|
|
11052
11060
|
const queue = this.queues.get(filePath) ?? [];
|
|
11053
|
-
queue.push(
|
|
11061
|
+
queue.push(resolve14);
|
|
11054
11062
|
this.queues.set(filePath, queue);
|
|
11055
11063
|
});
|
|
11056
11064
|
}
|
|
11057
11065
|
let releaseFn;
|
|
11058
|
-
const promise = new Promise((
|
|
11066
|
+
const promise = new Promise((resolve14) => {
|
|
11059
11067
|
releaseFn = () => {
|
|
11060
11068
|
this.locks.delete(filePath);
|
|
11061
|
-
|
|
11069
|
+
resolve14();
|
|
11062
11070
|
const queue = this.queues.get(filePath);
|
|
11063
11071
|
if (queue && queue.length > 0) {
|
|
11064
11072
|
const next = queue.shift();
|
|
@@ -11124,23 +11132,43 @@ var AgentManager = class {
|
|
|
11124
11132
|
onStart;
|
|
11125
11133
|
maxConcurrent;
|
|
11126
11134
|
customAgents;
|
|
11135
|
+
typeSettings;
|
|
11127
11136
|
/** Per-file transparent locking for write agents. */
|
|
11128
11137
|
fileLock = new FileLock();
|
|
11129
11138
|
/** Queue of background agents waiting to start. */
|
|
11130
11139
|
queue = [];
|
|
11131
11140
|
/** Number of currently running background agents. */
|
|
11132
11141
|
runningBackground = 0;
|
|
11133
|
-
constructor(onComplete, maxConcurrent = DEFAULT_MAX_CONCURRENT, onStart) {
|
|
11142
|
+
constructor(onComplete, maxConcurrent = DEFAULT_MAX_CONCURRENT, onStart, typeSettings = {}, agentsCwd = process.cwd()) {
|
|
11134
11143
|
this.onComplete = onComplete;
|
|
11135
11144
|
this.onStart = onStart;
|
|
11136
11145
|
this.maxConcurrent = maxConcurrent;
|
|
11137
|
-
this.
|
|
11146
|
+
this.typeSettings = typeSettings;
|
|
11147
|
+
this.customAgents = loadCustomAgents(agentsCwd);
|
|
11138
11148
|
this.cleanupInterval = setInterval(() => this.cleanup(), 6e4);
|
|
11139
11149
|
}
|
|
11140
11150
|
/** Get resolved agent config for a type. */
|
|
11141
11151
|
getAgentConfig(type) {
|
|
11142
11152
|
return this.customAgents.get(type) ?? BUILTIN_CONFIGS[type];
|
|
11143
11153
|
}
|
|
11154
|
+
/** Public agent types known from built-ins, custom files, or JSON config. */
|
|
11155
|
+
getKnownTypes() {
|
|
11156
|
+
return [.../* @__PURE__ */ new Set([
|
|
11157
|
+
...Object.keys(BUILTIN_CONFIGS).filter((type) => type !== "name-gen"),
|
|
11158
|
+
...this.customAgents.keys(),
|
|
11159
|
+
...Object.keys(this.typeSettings)
|
|
11160
|
+
])];
|
|
11161
|
+
}
|
|
11162
|
+
/** A type is enabled only when both JSON config and agent frontmatter allow it. */
|
|
11163
|
+
isTypeEnabled(type) {
|
|
11164
|
+
const agentConfig = this.getAgentConfig(type);
|
|
11165
|
+
return this.typeSettings[type]?.enabled !== false && agentConfig?.enabled !== false;
|
|
11166
|
+
}
|
|
11167
|
+
assertTypeEnabled(type) {
|
|
11168
|
+
if (!this.isTypeEnabled(type)) {
|
|
11169
|
+
throw new Error(`Agent type "${type}" is disabled by configuration.`);
|
|
11170
|
+
}
|
|
11171
|
+
}
|
|
11144
11172
|
setMaxConcurrent(n) {
|
|
11145
11173
|
this.maxConcurrent = Math.max(1, n);
|
|
11146
11174
|
this.drainQueue();
|
|
@@ -11152,6 +11180,7 @@ var AgentManager = class {
|
|
|
11152
11180
|
* Spawn an agent. Returns ID immediately for background, waits for foreground.
|
|
11153
11181
|
*/
|
|
11154
11182
|
spawn(pi, ctx, type, prompt, options) {
|
|
11183
|
+
this.assertTypeEnabled(type);
|
|
11155
11184
|
const id = randomUUID().slice(0, 17);
|
|
11156
11185
|
const abortController = new AbortController();
|
|
11157
11186
|
const record = {
|
|
@@ -11179,9 +11208,11 @@ var AgentManager = class {
|
|
|
11179
11208
|
record.startedAt = Date.now();
|
|
11180
11209
|
if (options.isBackground) this.runningBackground++;
|
|
11181
11210
|
this.onStart?.(record);
|
|
11211
|
+
const agentConfig = this.getAgentConfig(type);
|
|
11182
11212
|
let model = options.model;
|
|
11183
|
-
|
|
11184
|
-
|
|
11213
|
+
const modelInput = options.modelInput ?? agentConfig?.model;
|
|
11214
|
+
if (!model && modelInput && options.modelRegistry) {
|
|
11215
|
+
const resolved = resolveModel(modelInput, options.modelRegistry);
|
|
11185
11216
|
if (typeof resolved === "string") {
|
|
11186
11217
|
record.status = "error";
|
|
11187
11218
|
record.error = resolved;
|
|
@@ -11194,15 +11225,14 @@ var AgentManager = class {
|
|
|
11194
11225
|
}
|
|
11195
11226
|
model = resolved;
|
|
11196
11227
|
}
|
|
11197
|
-
const agentConfig = this.getAgentConfig(type);
|
|
11198
11228
|
const promise = runAgent(ctx, type, prompt, {
|
|
11199
11229
|
pi,
|
|
11200
11230
|
model,
|
|
11201
11231
|
agentConfig,
|
|
11202
|
-
maxTurns: options.maxTurns,
|
|
11203
|
-
isolated: options.isolated,
|
|
11204
|
-
inheritContext: options.inheritContext,
|
|
11205
|
-
thinkingLevel: options.thinkingLevel,
|
|
11232
|
+
maxTurns: options.maxTurns ?? agentConfig?.maxTurns,
|
|
11233
|
+
isolated: options.isolated ?? agentConfig?.isolated,
|
|
11234
|
+
inheritContext: options.inheritContext ?? agentConfig?.inheritContext,
|
|
11235
|
+
thinkingLevel: options.thinkingLevel ?? agentConfig?.thinking,
|
|
11206
11236
|
signal: record.abortController.signal,
|
|
11207
11237
|
onToolActivity: (activity) => {
|
|
11208
11238
|
if (activity.type === "end") record.toolUses++;
|
|
@@ -11354,7 +11384,7 @@ var AgentManager = class {
|
|
|
11354
11384
|
};
|
|
11355
11385
|
|
|
11356
11386
|
// packages/subagents/src/config.ts
|
|
11357
|
-
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";
|
|
11358
11388
|
import { join as join12 } from "node:path";
|
|
11359
11389
|
import { homedir as homedir8 } from "node:os";
|
|
11360
11390
|
var DEFAULT_CONFIG2 = {
|
|
@@ -11379,7 +11409,7 @@ function ensureDirExists(dirPath) {
|
|
|
11379
11409
|
function writeConfigAtomic(filePath, config) {
|
|
11380
11410
|
const tmpPath = filePath + ".tmp";
|
|
11381
11411
|
writeFileSync9(tmpPath, JSON.stringify(config, null, 2), "utf-8");
|
|
11382
|
-
|
|
11412
|
+
renameSync5(tmpPath, filePath);
|
|
11383
11413
|
}
|
|
11384
11414
|
function loadConfigFromPath(filePath) {
|
|
11385
11415
|
if (!existsSync12(filePath)) return null;
|
|
@@ -11395,7 +11425,7 @@ function loadConfigFromPath(filePath) {
|
|
|
11395
11425
|
function repairCorrupted(filePath) {
|
|
11396
11426
|
const backupPath = filePath + ".bak";
|
|
11397
11427
|
try {
|
|
11398
|
-
|
|
11428
|
+
renameSync5(filePath, backupPath);
|
|
11399
11429
|
} catch {
|
|
11400
11430
|
}
|
|
11401
11431
|
writeConfigAtomic(filePath, DEFAULT_CONFIG2);
|
|
@@ -12142,7 +12172,8 @@ function src_default(pi) {
|
|
|
12142
12172
|
type: record.type,
|
|
12143
12173
|
description: record.description
|
|
12144
12174
|
});
|
|
12145
|
-
}
|
|
12175
|
+
},
|
|
12176
|
+
config.types
|
|
12146
12177
|
);
|
|
12147
12178
|
function buildNotificationDetails(record, activity) {
|
|
12148
12179
|
return {
|
|
@@ -12213,7 +12244,7 @@ function src_default(pi) {
|
|
|
12213
12244
|
for (const dir of [globalAgentsDir, workspaceAgentsDir]) {
|
|
12214
12245
|
try {
|
|
12215
12246
|
if (existsSync13(dir)) {
|
|
12216
|
-
for (const file of
|
|
12247
|
+
for (const file of readdirSync8(dir)) {
|
|
12217
12248
|
if (file.endsWith(".md") && !customTypes.includes(file.replace(".md", ""))) {
|
|
12218
12249
|
customTypes.push(file.replace(".md", ""));
|
|
12219
12250
|
}
|
|
@@ -12245,14 +12276,14 @@ function src_default(pi) {
|
|
|
12245
12276
|
let sessionCtx2 = null;
|
|
12246
12277
|
pi.on("session_start", async (_event, ctx) => {
|
|
12247
12278
|
sessionCtx2 = ctx;
|
|
12248
|
-
|
|
12249
|
-
name:
|
|
12279
|
+
emitEvent2(pi, UNIPI_EVENTS2.MODULE_READY, {
|
|
12280
|
+
name: MODULES2.SUBAGENTS || "subagents",
|
|
12250
12281
|
version: "0.2.0",
|
|
12251
12282
|
commands: [],
|
|
12252
12283
|
tools: ["spawn_helper", "get_helper_result"]
|
|
12253
12284
|
});
|
|
12254
12285
|
});
|
|
12255
|
-
pi.events.on(
|
|
12286
|
+
pi.events.on(UNIPI_EVENTS2.BADGE_GENERATE_REQUEST, async (data) => {
|
|
12256
12287
|
const event = data;
|
|
12257
12288
|
if (!sessionCtx2) return;
|
|
12258
12289
|
const summary = event?.conversationSummary ?? "";
|
|
@@ -12338,13 +12369,15 @@ ${summary}` : `Generate a concise session title (MAX 5 WORDS) for this session.
|
|
|
12338
12369
|
return { state, callbacks };
|
|
12339
12370
|
}
|
|
12340
12371
|
const builtinTypes = BUILTIN_TYPES.join(", ");
|
|
12372
|
+
const enabledTypes = manager2.getKnownTypes().filter((type) => manager2.isTypeEnabled(type));
|
|
12373
|
+
const availableTypes = enabledTypes.join(", ") || "none";
|
|
12341
12374
|
pi.registerTool(
|
|
12342
12375
|
defineTool({
|
|
12343
12376
|
name: "spawn_helper",
|
|
12344
12377
|
label: "Spawn Helper",
|
|
12345
12378
|
description: `Launch a sub-agent for parallel work.
|
|
12346
12379
|
|
|
12347
|
-
Available agent types: ${
|
|
12380
|
+
Available agent types: ${availableTypes}
|
|
12348
12381
|
Custom types can be defined in:
|
|
12349
12382
|
- ~/.unipi/config/agents/<name>.md (global)
|
|
12350
12383
|
- <workspace>/.unipi/config/agents/<name>.md (project)
|
|
@@ -12357,7 +12390,7 @@ Guidelines:
|
|
|
12357
12390
|
- Agents inherit the parent model by default`,
|
|
12358
12391
|
parameters: Type3.Object({
|
|
12359
12392
|
type: Type3.String({
|
|
12360
|
-
description: `
|
|
12393
|
+
description: `Enabled agent type: ${availableTypes}`
|
|
12361
12394
|
}),
|
|
12362
12395
|
prompt: Type3.String({
|
|
12363
12396
|
description: "The task for the agent to perform."
|
|
@@ -12600,7 +12633,7 @@ Use get_result to retrieve full results.`,
|
|
|
12600
12633
|
}
|
|
12601
12634
|
if (params.view && record.session) {
|
|
12602
12635
|
const activity = agentActivity.get(record.id);
|
|
12603
|
-
await
|
|
12636
|
+
await withHerdrBlocked2(
|
|
12604
12637
|
pi,
|
|
12605
12638
|
"helper viewer",
|
|
12606
12639
|
() => ctx.ui.custom(
|
|
@@ -12657,7 +12690,7 @@ Description: ${record.description}
|
|
|
12657
12690
|
// packages/btw/extensions/btw.ts
|
|
12658
12691
|
init_core();
|
|
12659
12692
|
import {
|
|
12660
|
-
buildSessionContext,
|
|
12693
|
+
buildSessionContext as buildSessionContext2,
|
|
12661
12694
|
createAgentSession as createAgentSession2,
|
|
12662
12695
|
createExtensionRuntime,
|
|
12663
12696
|
SessionManager as SessionManager2
|
|
@@ -12743,7 +12776,7 @@ function buildBtwSeedState(ctx, thread, mode) {
|
|
|
12743
12776
|
if (mode === "contextual") {
|
|
12744
12777
|
try {
|
|
12745
12778
|
messages.push(
|
|
12746
|
-
...
|
|
12779
|
+
...buildSessionContext2(ctx.sessionManager.getEntries(), ctx.sessionManager.getLeafId()).messages.filter(
|
|
12747
12780
|
(message) => !isVisibleBtwMessage(message)
|
|
12748
12781
|
)
|
|
12749
12782
|
);
|
|
@@ -14146,7 +14179,7 @@ ${summary}`;
|
|
|
14146
14179
|
|
|
14147
14180
|
// packages/web-api/src/index.ts
|
|
14148
14181
|
init_core();
|
|
14149
|
-
import { dirname as
|
|
14182
|
+
import { dirname as dirname11 } from "node:path";
|
|
14150
14183
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
14151
14184
|
|
|
14152
14185
|
// packages/web-api/src/tools.ts
|
|
@@ -16816,7 +16849,7 @@ var llmSummarizeProvider = {
|
|
|
16816
16849
|
registry.register(llmSummarizeProvider);
|
|
16817
16850
|
|
|
16818
16851
|
// packages/web-api/src/index.ts
|
|
16819
|
-
var VERSION5 = getPackageVersion(
|
|
16852
|
+
var VERSION5 = getPackageVersion(dirname11(fileURLToPath6(import.meta.url)));
|
|
16820
16853
|
function getInfoRegistry4() {
|
|
16821
16854
|
return globalThis.__unipi_info_registry;
|
|
16822
16855
|
}
|
|
@@ -16888,14 +16921,14 @@ function src_default2(pi) {
|
|
|
16888
16921
|
|
|
16889
16922
|
// packages/utility/src/index.ts
|
|
16890
16923
|
init_core();
|
|
16891
|
-
import { dirname as
|
|
16924
|
+
import { dirname as dirname14 } from "node:path";
|
|
16892
16925
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
16893
16926
|
|
|
16894
16927
|
// packages/utility/src/commands.ts
|
|
16895
16928
|
init_core();
|
|
16896
16929
|
|
|
16897
16930
|
// packages/utility/src/lifecycle/cleanup.ts
|
|
16898
|
-
import { existsSync as existsSync16, statSync as
|
|
16931
|
+
import { existsSync as existsSync16, statSync as statSync8, readdirSync as readdirSync10, unlinkSync as unlinkSync5, rmdirSync } from "node:fs";
|
|
16899
16932
|
import { join as join16 } from "node:path";
|
|
16900
16933
|
import { homedir as homedir12, tmpdir } from "node:os";
|
|
16901
16934
|
var DEFAULTS = {
|
|
@@ -16912,7 +16945,7 @@ function expandHome(path28) {
|
|
|
16912
16945
|
}
|
|
16913
16946
|
function isStale(path28, maxAgeDays) {
|
|
16914
16947
|
try {
|
|
16915
|
-
const stats =
|
|
16948
|
+
const stats = statSync8(path28);
|
|
16916
16949
|
const ageMs = Date.now() - stats.mtime.getTime();
|
|
16917
16950
|
return ageMs > maxAgeDays * 24 * 60 * 60 * 1e3;
|
|
16918
16951
|
} catch {
|
|
@@ -16924,7 +16957,7 @@ function hasWalLock(dbPath) {
|
|
|
16924
16957
|
const shmPath = dbPath + "-shm";
|
|
16925
16958
|
if (existsSync16(walPath)) {
|
|
16926
16959
|
try {
|
|
16927
|
-
const walStats =
|
|
16960
|
+
const walStats = statSync8(walPath);
|
|
16928
16961
|
const ageMs = Date.now() - walStats.mtime.getTime();
|
|
16929
16962
|
return ageMs > 5 * 60 * 1e3;
|
|
16930
16963
|
} catch {
|
|
@@ -16945,14 +16978,14 @@ function cleanDbs(options) {
|
|
|
16945
16978
|
const scanDir = (dir) => {
|
|
16946
16979
|
let entries;
|
|
16947
16980
|
try {
|
|
16948
|
-
entries =
|
|
16981
|
+
entries = readdirSync10(dir);
|
|
16949
16982
|
} catch {
|
|
16950
16983
|
return;
|
|
16951
16984
|
}
|
|
16952
16985
|
for (const entry of entries) {
|
|
16953
16986
|
const fullPath = join16(dir, entry);
|
|
16954
16987
|
try {
|
|
16955
|
-
const stats =
|
|
16988
|
+
const stats = statSync8(fullPath);
|
|
16956
16989
|
if (stats.isDirectory()) {
|
|
16957
16990
|
scanDir(fullPath);
|
|
16958
16991
|
continue;
|
|
@@ -16968,7 +17001,7 @@ function cleanDbs(options) {
|
|
|
16968
17001
|
const companion = fullPath + suffix;
|
|
16969
17002
|
if (existsSync16(companion)) {
|
|
16970
17003
|
unlinkSync5(companion);
|
|
16971
|
-
result.bytesFreed +=
|
|
17004
|
+
result.bytesFreed += statSync8(companion).size;
|
|
16972
17005
|
}
|
|
16973
17006
|
}
|
|
16974
17007
|
result.removed++;
|
|
@@ -16997,7 +17030,7 @@ function cleanTemps(options) {
|
|
|
16997
17030
|
const tmpDir = tmpdir();
|
|
16998
17031
|
let entries;
|
|
16999
17032
|
try {
|
|
17000
|
-
entries =
|
|
17033
|
+
entries = readdirSync10(tmpDir);
|
|
17001
17034
|
} catch {
|
|
17002
17035
|
return result;
|
|
17003
17036
|
}
|
|
@@ -17005,7 +17038,7 @@ function cleanTemps(options) {
|
|
|
17005
17038
|
if (!patterns.some((p) => p.test(entry))) continue;
|
|
17006
17039
|
const fullPath = join16(tmpDir, entry);
|
|
17007
17040
|
try {
|
|
17008
|
-
const stats =
|
|
17041
|
+
const stats = statSync8(fullPath);
|
|
17009
17042
|
if (!stats.isFile()) continue;
|
|
17010
17043
|
if (isStale(fullPath, options.tempMaxAgeDays)) {
|
|
17011
17044
|
result.bytesFreed += stats.size;
|
|
@@ -17037,14 +17070,14 @@ function cleanSessions(options) {
|
|
|
17037
17070
|
if (!existsSync16(sessionsDir)) return result;
|
|
17038
17071
|
let entries;
|
|
17039
17072
|
try {
|
|
17040
|
-
entries =
|
|
17073
|
+
entries = readdirSync10(sessionsDir);
|
|
17041
17074
|
} catch {
|
|
17042
17075
|
return result;
|
|
17043
17076
|
}
|
|
17044
17077
|
for (const entry of entries) {
|
|
17045
17078
|
const fullPath = join16(sessionsDir, entry);
|
|
17046
17079
|
try {
|
|
17047
|
-
const stats =
|
|
17080
|
+
const stats = statSync8(fullPath);
|
|
17048
17081
|
if (!stats.isDirectory()) continue;
|
|
17049
17082
|
if (isStale(fullPath, options.sessionMaxAgeDays)) {
|
|
17050
17083
|
result.bytesFreed += stats.size;
|
|
@@ -17052,10 +17085,10 @@ function cleanSessions(options) {
|
|
|
17052
17085
|
if (!options.dryRun) {
|
|
17053
17086
|
try {
|
|
17054
17087
|
const removeRecursive = (dir) => {
|
|
17055
|
-
const items =
|
|
17088
|
+
const items = readdirSync10(dir);
|
|
17056
17089
|
for (const item of items) {
|
|
17057
17090
|
const itemPath = join16(dir, item);
|
|
17058
|
-
const itemStats =
|
|
17091
|
+
const itemStats = statSync8(itemPath);
|
|
17059
17092
|
if (itemStats.isDirectory()) {
|
|
17060
17093
|
removeRecursive(itemPath);
|
|
17061
17094
|
} else {
|
|
@@ -17088,14 +17121,14 @@ function cleanCache(options) {
|
|
|
17088
17121
|
if (!existsSync16(cacheDir)) return result;
|
|
17089
17122
|
let entries;
|
|
17090
17123
|
try {
|
|
17091
|
-
entries =
|
|
17124
|
+
entries = readdirSync10(cacheDir);
|
|
17092
17125
|
} catch {
|
|
17093
17126
|
return result;
|
|
17094
17127
|
}
|
|
17095
17128
|
for (const entry of entries) {
|
|
17096
17129
|
const fullPath = join16(cacheDir, entry);
|
|
17097
17130
|
try {
|
|
17098
|
-
const stats =
|
|
17131
|
+
const stats = statSync8(fullPath);
|
|
17099
17132
|
if (!stats.isFile()) continue;
|
|
17100
17133
|
if (isStale(fullPath, options.tempMaxAgeDays)) {
|
|
17101
17134
|
result.bytesFreed += stats.size;
|
|
@@ -17159,7 +17192,7 @@ function formatCleanupReport(report) {
|
|
|
17159
17192
|
}
|
|
17160
17193
|
|
|
17161
17194
|
// packages/utility/src/diagnostics/engine.ts
|
|
17162
|
-
import { existsSync as existsSync17, accessSync, constants } from "node:fs";
|
|
17195
|
+
import { existsSync as existsSync17, accessSync as accessSync2, constants as constants2 } from "node:fs";
|
|
17163
17196
|
import { join as join17 } from "node:path";
|
|
17164
17197
|
import { homedir as homedir13 } from "node:os";
|
|
17165
17198
|
function expandHome2(path28) {
|
|
@@ -17170,7 +17203,7 @@ function expandHome2(path28) {
|
|
|
17170
17203
|
}
|
|
17171
17204
|
function isReadable(path28) {
|
|
17172
17205
|
try {
|
|
17173
|
-
|
|
17206
|
+
accessSync2(path28, constants2.R_OK);
|
|
17174
17207
|
return true;
|
|
17175
17208
|
} catch {
|
|
17176
17209
|
return false;
|
|
@@ -17178,7 +17211,7 @@ function isReadable(path28) {
|
|
|
17178
17211
|
}
|
|
17179
17212
|
function isWritable(path28) {
|
|
17180
17213
|
try {
|
|
17181
|
-
|
|
17214
|
+
accessSync2(path28, constants2.W_OK);
|
|
17182
17215
|
return true;
|
|
17183
17216
|
} catch {
|
|
17184
17217
|
return false;
|
|
@@ -17587,7 +17620,6 @@ var PRESETS = {
|
|
|
17587
17620
|
}
|
|
17588
17621
|
}
|
|
17589
17622
|
};
|
|
17590
|
-
var HARDCODED_FALLBACK = PRESETS.default.colors;
|
|
17591
17623
|
function getPreset(name) {
|
|
17592
17624
|
return PRESETS[name] ?? PRESETS.default;
|
|
17593
17625
|
}
|
|
@@ -18242,17 +18274,9 @@ function registerUtilityCommands(pi) {
|
|
|
18242
18274
|
}
|
|
18243
18275
|
return;
|
|
18244
18276
|
}
|
|
18245
|
-
const requestId = `status-${Date.now()}`;
|
|
18246
|
-
emitEvent(pi, UNIPI_EVENTS.MODULE_STATUS_REQUEST, { requestId });
|
|
18247
|
-
await new Promise((resolve13) => setTimeout(resolve13, 500));
|
|
18248
18277
|
sendResponse(
|
|
18249
18278
|
pi,
|
|
18250
|
-
|
|
18251
|
-
|
|
18252
|
-
Status request broadcast to all modules.
|
|
18253
|
-
Modules that support status reporting will respond via events.
|
|
18254
|
-
|
|
18255
|
-
*Request ID: \`${requestId}\`*`
|
|
18279
|
+
"## \u{1F4CA} Module Status\n\nUse `/unipi:info` for the live module and tool dashboard.\nUse `/unipi:doctor` to run configuration and runtime diagnostics."
|
|
18256
18280
|
);
|
|
18257
18281
|
}
|
|
18258
18282
|
});
|
|
@@ -19457,7 +19481,7 @@ function registerInfoScreen(pi) {
|
|
|
19457
19481
|
}
|
|
19458
19482
|
|
|
19459
19483
|
// packages/utility/src/index.ts
|
|
19460
|
-
var VERSION6 = getPackageVersion(
|
|
19484
|
+
var VERSION6 = getPackageVersion(dirname14(fileURLToPath7(import.meta.url)));
|
|
19461
19485
|
var firstMessageSeen = false;
|
|
19462
19486
|
var firstUserText = "";
|
|
19463
19487
|
var firstInputCtx = null;
|
|
@@ -19669,7 +19693,7 @@ function registerUtilityTools(pi, nameBadgeState) {
|
|
|
19669
19693
|
|
|
19670
19694
|
// packages/ask-user/index.ts
|
|
19671
19695
|
init_core();
|
|
19672
|
-
import { dirname as
|
|
19696
|
+
import { dirname as dirname15 } from "node:path";
|
|
19673
19697
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
19674
19698
|
|
|
19675
19699
|
// packages/ask-user/tools.ts
|
|
@@ -21054,7 +21078,7 @@ function registerAskUserCommands(pi) {
|
|
|
21054
21078
|
}
|
|
21055
21079
|
|
|
21056
21080
|
// packages/ask-user/index.ts
|
|
21057
|
-
var VERSION7 = getPackageVersion(
|
|
21081
|
+
var VERSION7 = getPackageVersion(dirname15(fileURLToPath8(import.meta.url)));
|
|
21058
21082
|
function ask_user_default(pi) {
|
|
21059
21083
|
registerAskUserTools(pi);
|
|
21060
21084
|
registerAskUserCommands(pi);
|
|
@@ -21070,7 +21094,7 @@ function ask_user_default(pi) {
|
|
|
21070
21094
|
|
|
21071
21095
|
// packages/mcp/src/index.ts
|
|
21072
21096
|
init_core();
|
|
21073
|
-
import { dirname as
|
|
21097
|
+
import { dirname as dirname18 } from "node:path";
|
|
21074
21098
|
import { fileURLToPath as fileURLToPath9 } from "node:url";
|
|
21075
21099
|
|
|
21076
21100
|
// packages/mcp/src/config/manager.ts
|
|
@@ -21568,7 +21592,7 @@ var McpClient = class {
|
|
|
21568
21592
|
if (this.connected) {
|
|
21569
21593
|
throw new Error("McpClient is already connected");
|
|
21570
21594
|
}
|
|
21571
|
-
return new Promise((
|
|
21595
|
+
return new Promise((resolve14, reject) => {
|
|
21572
21596
|
try {
|
|
21573
21597
|
const mergedEnv = { ...process.env, ...env };
|
|
21574
21598
|
this.process = spawn2(command, args, {
|
|
@@ -21617,7 +21641,7 @@ Stderr: ${this.stderrBuffer}`
|
|
|
21617
21641
|
}).then(() => {
|
|
21618
21642
|
this.sendNotification("notifications/initialized", {});
|
|
21619
21643
|
this.connected = true;
|
|
21620
|
-
|
|
21644
|
+
resolve14();
|
|
21621
21645
|
}).catch((err) => {
|
|
21622
21646
|
this.cleanup();
|
|
21623
21647
|
reject(
|
|
@@ -21661,16 +21685,16 @@ Stderr: ${this.stderrBuffer}`
|
|
|
21661
21685
|
this.sendNotification("shutdown", {});
|
|
21662
21686
|
} catch {
|
|
21663
21687
|
}
|
|
21664
|
-
await new Promise((
|
|
21665
|
-
const timer = setTimeout(() =>
|
|
21688
|
+
await new Promise((resolve14) => {
|
|
21689
|
+
const timer = setTimeout(() => resolve14(), 500);
|
|
21666
21690
|
this.process.on("exit", () => {
|
|
21667
21691
|
clearTimeout(timer);
|
|
21668
|
-
|
|
21692
|
+
resolve14();
|
|
21669
21693
|
});
|
|
21670
21694
|
try {
|
|
21671
21695
|
this.process.kill("SIGTERM");
|
|
21672
21696
|
} catch {
|
|
21673
|
-
|
|
21697
|
+
resolve14();
|
|
21674
21698
|
}
|
|
21675
21699
|
});
|
|
21676
21700
|
if (this.process && !this.process.killed) {
|
|
@@ -21700,7 +21724,7 @@ Stderr: ${this.stderrBuffer}`
|
|
|
21700
21724
|
}
|
|
21701
21725
|
}
|
|
21702
21726
|
sendRequest(method, params) {
|
|
21703
|
-
return new Promise((
|
|
21727
|
+
return new Promise((resolve14, reject) => {
|
|
21704
21728
|
if (!this.process?.stdin) {
|
|
21705
21729
|
reject(new Error("MCP server process not available"));
|
|
21706
21730
|
return;
|
|
@@ -21720,7 +21744,7 @@ Stderr: ${this.stderrBuffer}`
|
|
|
21720
21744
|
)
|
|
21721
21745
|
);
|
|
21722
21746
|
}, this.timeoutMs);
|
|
21723
|
-
this.pending.set(id, { resolve:
|
|
21747
|
+
this.pending.set(id, { resolve: resolve14, reject, timer });
|
|
21724
21748
|
const message = JSON.stringify(request) + "\n";
|
|
21725
21749
|
this.process.stdin.write(message);
|
|
21726
21750
|
});
|
|
@@ -21783,15 +21807,45 @@ Stderr: ${this.stderrBuffer}`
|
|
|
21783
21807
|
|
|
21784
21808
|
// packages/mcp/src/bridge/translator.ts
|
|
21785
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
|
+
}
|
|
21786
21839
|
function translateMcpTool(mcpTool, serverName, client) {
|
|
21787
21840
|
const separator = MCP_DEFAULTS.TOOL_NAME_SEPARATOR;
|
|
21788
21841
|
const toolName = `${serverName}${separator}${mcpTool.name}`;
|
|
21789
|
-
const inputSchema = mcpTool.inputSchema
|
|
21790
|
-
const
|
|
21842
|
+
const inputSchema = isObject(mcpTool.inputSchema) ? mcpTool.inputSchema : {};
|
|
21843
|
+
const normalizedSchema = {
|
|
21791
21844
|
type: "object",
|
|
21792
|
-
properties: inputSchema.properties
|
|
21793
|
-
required: inputSchema.required
|
|
21845
|
+
properties: isObject(inputSchema.properties) ? inputSchema.properties : {},
|
|
21846
|
+
required: Array.isArray(inputSchema.required) ? inputSchema.required : []
|
|
21794
21847
|
};
|
|
21848
|
+
const parameters = canonicalizeJsonSchema(normalizedSchema);
|
|
21795
21849
|
const description = [
|
|
21796
21850
|
mcpTool.description || `MCP tool: ${mcpTool.name}`,
|
|
21797
21851
|
`[Server: ${serverName}]`
|
|
@@ -21849,6 +21903,7 @@ Check server status via /unipi:mcp-settings`
|
|
|
21849
21903
|
};
|
|
21850
21904
|
return {
|
|
21851
21905
|
name: toolName,
|
|
21906
|
+
label: toolName,
|
|
21852
21907
|
description,
|
|
21853
21908
|
parameters,
|
|
21854
21909
|
execute: execute2
|
|
@@ -21861,26 +21916,125 @@ var ServerRegistry = class {
|
|
|
21861
21916
|
emitEvent;
|
|
21862
21917
|
registerTool;
|
|
21863
21918
|
unregisterTool;
|
|
21919
|
+
canUnregisterTools;
|
|
21864
21920
|
timeoutMs;
|
|
21921
|
+
createClient;
|
|
21865
21922
|
constructor(options) {
|
|
21866
21923
|
this.emitEvent = options.emitEvent;
|
|
21867
21924
|
this.registerTool = options.registerTool;
|
|
21868
21925
|
this.unregisterTool = options.unregisterTool;
|
|
21926
|
+
this.canUnregisterTools = options.canUnregisterTools ?? true;
|
|
21869
21927
|
this.timeoutMs = options.timeoutMs ?? MCP_DEFAULTS.STARTUP_TIMEOUT_MS;
|
|
21928
|
+
this.createClient = options.createClient ?? (() => new McpClient({ timeoutMs: this.timeoutMs }));
|
|
21870
21929
|
}
|
|
21871
21930
|
/**
|
|
21872
|
-
* Start
|
|
21931
|
+
* Start one MCP server. Discovery completes before its tools are registered,
|
|
21932
|
+
* and registration always follows final Pi tool-name order.
|
|
21873
21933
|
*/
|
|
21874
21934
|
async startServer(resolved) {
|
|
21875
|
-
|
|
21876
|
-
|
|
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) {
|
|
21877
21961
|
throw new Error(
|
|
21878
21962
|
`Maximum number of MCP servers (${MCP_DEFAULTS.MAX_SERVERS}) reached. Stop a server before starting a new one.`
|
|
21879
21963
|
);
|
|
21880
21964
|
}
|
|
21881
|
-
|
|
21882
|
-
|
|
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;
|
|
21883
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;
|
|
21884
22038
|
const state = {
|
|
21885
22039
|
name,
|
|
21886
22040
|
status: "starting",
|
|
@@ -21895,73 +22049,74 @@ var ServerRegistry = class {
|
|
|
21895
22049
|
toolNames: []
|
|
21896
22050
|
};
|
|
21897
22051
|
this.entries.set(name, entry);
|
|
22052
|
+
let client = null;
|
|
21898
22053
|
try {
|
|
21899
22054
|
const safeCommand = typeof def.command === "string" ? def.command : String(def.command);
|
|
21900
22055
|
const safeArgs = Array.isArray(def.args) ? def.args : [];
|
|
21901
22056
|
let safeEnv;
|
|
21902
|
-
if (def.env !== void 0 && def.env !== null) {
|
|
21903
|
-
|
|
21904
|
-
|
|
21905
|
-
|
|
21906
|
-
|
|
21907
|
-
|
|
21908
|
-
|
|
21909
|
-
|
|
21910
|
-
|
|
21911
|
-
|
|
21912
|
-
await
|
|
21913
|
-
|
|
21914
|
-
|
|
21915
|
-
|
|
21916
|
-
|
|
21917
|
-
|
|
21918
|
-
|
|
21919
|
-
toolNames.push(piTool.name);
|
|
21920
|
-
}
|
|
21921
|
-
entry.state = {
|
|
21922
|
-
...state,
|
|
21923
|
-
status: "running",
|
|
21924
|
-
pid: client.pid,
|
|
21925
|
-
toolCount: toolNames.length
|
|
21926
|
-
};
|
|
21927
|
-
entry.toolNames = toolNames;
|
|
21928
|
-
this.emitEvent(UNIPI_EVENTS.MCP_SERVER_STARTED, {
|
|
21929
|
-
name,
|
|
21930
|
-
toolCount: toolNames.length
|
|
21931
|
-
});
|
|
21932
|
-
if (toolNames.length > 0) {
|
|
21933
|
-
this.emitEvent(UNIPI_EVENTS.MCP_TOOLS_REGISTERED, {
|
|
21934
|
-
serverName: name,
|
|
21935
|
-
toolNames
|
|
21936
|
-
});
|
|
21937
|
-
}
|
|
21938
|
-
} catch (err) {
|
|
21939
|
-
const error = err instanceof Error ? err.message : String(err);
|
|
21940
|
-
entry.state = {
|
|
21941
|
-
...state,
|
|
21942
|
-
status: "error",
|
|
21943
|
-
error
|
|
21944
|
-
};
|
|
21945
|
-
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) {
|
|
21946
22074
|
try {
|
|
21947
|
-
await
|
|
22075
|
+
await client.disconnect();
|
|
21948
22076
|
} catch {
|
|
21949
22077
|
}
|
|
21950
|
-
entry.client = null;
|
|
21951
22078
|
}
|
|
21952
|
-
|
|
21953
|
-
|
|
21954
|
-
|
|
21955
|
-
});
|
|
21956
|
-
throw err;
|
|
22079
|
+
entry.client = null;
|
|
22080
|
+
this.emitEvent(UNIPI_EVENTS.MCP_SERVER_ERROR, { name, error: message });
|
|
22081
|
+
throw error;
|
|
21957
22082
|
}
|
|
21958
22083
|
}
|
|
21959
|
-
|
|
21960
|
-
|
|
21961
|
-
|
|
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. */
|
|
21962
22112
|
async stopServer(name) {
|
|
21963
22113
|
const entry = this.entries.get(name);
|
|
21964
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
|
+
}
|
|
21965
22120
|
for (const toolName of entry.toolNames) {
|
|
21966
22121
|
this.unregisterTool(toolName);
|
|
21967
22122
|
}
|
|
@@ -21978,78 +22133,63 @@ var ServerRegistry = class {
|
|
|
21978
22133
|
}
|
|
21979
22134
|
entry.client = null;
|
|
21980
22135
|
}
|
|
21981
|
-
entry.state = {
|
|
21982
|
-
...entry.state,
|
|
21983
|
-
status: "stopped",
|
|
21984
|
-
toolCount: 0
|
|
21985
|
-
};
|
|
22136
|
+
entry.state = { ...entry.state, status: "stopped", toolCount: 0 };
|
|
21986
22137
|
entry.toolNames = [];
|
|
21987
22138
|
this.emitEvent(UNIPI_EVENTS.MCP_SERVER_STOPPED, { name });
|
|
21988
22139
|
}
|
|
21989
|
-
/**
|
|
21990
|
-
* Restart an MCP server: stop then start.
|
|
21991
|
-
*/
|
|
22140
|
+
/** Restart an MCP server: stop then start. */
|
|
21992
22141
|
async restartServer(name) {
|
|
21993
22142
|
const entry = this.entries.get(name);
|
|
21994
|
-
if (!entry) {
|
|
21995
|
-
throw new Error(`Server '${name}' not found in registry`);
|
|
21996
|
-
}
|
|
22143
|
+
if (!entry) throw new Error(`Server '${name}' not found in registry`);
|
|
21997
22144
|
const resolved = entry.resolved;
|
|
21998
22145
|
await this.stopServer(name);
|
|
21999
22146
|
await this.startServer(resolved);
|
|
22000
22147
|
}
|
|
22001
|
-
/**
|
|
22002
|
-
* Stop all running servers.
|
|
22003
|
-
*/
|
|
22148
|
+
/** Stop all running servers when runtime unregistration is supported. */
|
|
22004
22149
|
async stopAll() {
|
|
22005
22150
|
const names = Array.from(this.entries.keys());
|
|
22006
22151
|
await Promise.allSettled(names.map((name) => this.stopServer(name)));
|
|
22007
22152
|
}
|
|
22008
|
-
/**
|
|
22009
|
-
|
|
22010
|
-
|
|
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. */
|
|
22011
22165
|
getAll() {
|
|
22012
|
-
return Array.from(this.entries.values()).map((
|
|
22166
|
+
return Array.from(this.entries.values()).map((entry) => entry.state);
|
|
22013
22167
|
}
|
|
22014
|
-
/**
|
|
22015
|
-
* Get states of running servers.
|
|
22016
|
-
*/
|
|
22168
|
+
/** Get states of running servers. */
|
|
22017
22169
|
getActive() {
|
|
22018
|
-
return this.getAll().filter((
|
|
22170
|
+
return this.getAll().filter((state) => state.status === "running");
|
|
22019
22171
|
}
|
|
22020
|
-
/**
|
|
22021
|
-
* Get states of servers in error state.
|
|
22022
|
-
*/
|
|
22172
|
+
/** Get states of servers in error state. */
|
|
22023
22173
|
getFailed() {
|
|
22024
|
-
return this.getAll().filter((
|
|
22174
|
+
return this.getAll().filter((state) => state.status === "error");
|
|
22025
22175
|
}
|
|
22026
|
-
/**
|
|
22027
|
-
* Get total number of tools across all active servers.
|
|
22028
|
-
*/
|
|
22176
|
+
/** Get total number of tools across all active servers. */
|
|
22029
22177
|
getTotalToolCount() {
|
|
22030
|
-
return this.getActive().reduce((sum,
|
|
22178
|
+
return this.getActive().reduce((sum, state) => sum + state.toolCount, 0);
|
|
22031
22179
|
}
|
|
22032
|
-
/**
|
|
22033
|
-
* Get the state of a specific server.
|
|
22034
|
-
*/
|
|
22180
|
+
/** Get the state of a specific server. */
|
|
22035
22181
|
getServerState(name) {
|
|
22036
22182
|
return this.entries.get(name)?.state ?? null;
|
|
22037
22183
|
}
|
|
22038
|
-
/**
|
|
22039
|
-
* Get the full registry entry for a server.
|
|
22040
|
-
*/
|
|
22184
|
+
/** Get the full registry entry for a server. */
|
|
22041
22185
|
getEntry(name) {
|
|
22042
22186
|
return this.entries.get(name) ?? null;
|
|
22043
22187
|
}
|
|
22044
|
-
/**
|
|
22045
|
-
* Check if a server exists in the registry.
|
|
22046
|
-
*/
|
|
22188
|
+
/** Check if a server exists in the registry. */
|
|
22047
22189
|
hasServer(name) {
|
|
22048
22190
|
return this.entries.has(name);
|
|
22049
22191
|
}
|
|
22050
|
-
/**
|
|
22051
|
-
* Get the number of registered servers.
|
|
22052
|
-
*/
|
|
22192
|
+
/** Get the number of registered servers. */
|
|
22053
22193
|
get size() {
|
|
22054
22194
|
return this.entries.size;
|
|
22055
22195
|
}
|
|
@@ -22662,12 +22802,6 @@ function renderMcpSettingsOverlay(params) {
|
|
|
22662
22802
|
addedAt: meta.servers[server.name]?.addedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
22663
22803
|
};
|
|
22664
22804
|
saveMetadata(configDir, meta);
|
|
22665
|
-
if (!newEnabled && registry3) {
|
|
22666
|
-
try {
|
|
22667
|
-
await registry3.stopServer(server.name);
|
|
22668
|
-
} catch {
|
|
22669
|
-
}
|
|
22670
|
-
}
|
|
22671
22805
|
refreshServers();
|
|
22672
22806
|
refresh();
|
|
22673
22807
|
} catch (err) {
|
|
@@ -22814,7 +22948,7 @@ function renderMcpSettingsOverlay(params) {
|
|
|
22814
22948
|
}
|
|
22815
22949
|
|
|
22816
22950
|
// packages/mcp/src/index.ts
|
|
22817
|
-
var VERSION8 = getPackageVersion(
|
|
22951
|
+
var VERSION8 = getPackageVersion(dirname18(fileURLToPath9(import.meta.url)));
|
|
22818
22952
|
var registry2 = null;
|
|
22819
22953
|
function getInfoRegistry5() {
|
|
22820
22954
|
return globalThis.__unipi_info_registry;
|
|
@@ -22824,20 +22958,18 @@ function getRegistry() {
|
|
|
22824
22958
|
}
|
|
22825
22959
|
function src_default4(pi) {
|
|
22826
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
|
+
};
|
|
22827
22968
|
registry2 = new ServerRegistry({
|
|
22828
22969
|
emitEvent: (event, payload) => emitEvent(pi, event, payload),
|
|
22829
|
-
registerTool
|
|
22830
|
-
|
|
22831
|
-
|
|
22832
|
-
} catch {
|
|
22833
|
-
}
|
|
22834
|
-
},
|
|
22835
|
-
unregisterTool: (toolName) => {
|
|
22836
|
-
try {
|
|
22837
|
-
pi.unregisterTool?.(toolName) ?? pi.unregisterExternalTool?.(toolName);
|
|
22838
|
-
} catch {
|
|
22839
|
-
}
|
|
22840
|
-
}
|
|
22970
|
+
registerTool,
|
|
22971
|
+
unregisterTool,
|
|
22972
|
+
canUnregisterTools
|
|
22841
22973
|
});
|
|
22842
22974
|
const cwd = ctx.cwd ?? process.cwd();
|
|
22843
22975
|
let servers = [];
|
|
@@ -22846,13 +22978,10 @@ function src_default4(pi) {
|
|
|
22846
22978
|
servers = result.servers;
|
|
22847
22979
|
} catch (_err) {
|
|
22848
22980
|
}
|
|
22849
|
-
|
|
22850
|
-
|
|
22851
|
-
|
|
22852
|
-
|
|
22853
|
-
}
|
|
22854
|
-
});
|
|
22855
|
-
await Promise.allSettled(startPromises);
|
|
22981
|
+
try {
|
|
22982
|
+
await registry2.startServers(servers.filter((server) => server.enabled));
|
|
22983
|
+
} catch (_err) {
|
|
22984
|
+
}
|
|
22856
22985
|
const infoRegistry2 = getInfoRegistry5();
|
|
22857
22986
|
if (infoRegistry2 && registry2) {
|
|
22858
22987
|
const reg = registry2;
|
|
@@ -22909,14 +23038,12 @@ function src_default4(pi) {
|
|
|
22909
23038
|
`unipi:${MCP_COMMANDS.STATUS}`,
|
|
22910
23039
|
`unipi:${MCP_COMMANDS.RELOAD}`
|
|
22911
23040
|
],
|
|
22912
|
-
tools: activeServers.flatMap(
|
|
22913
|
-
(s) => registry2?.getEntry(s.name)?.toolNames ?? []
|
|
22914
|
-
)
|
|
23041
|
+
tools: activeServers.flatMap((server) => registry2?.getEntry(server.name)?.toolNames ?? []).sort(compareCodeUnits)
|
|
22915
23042
|
});
|
|
22916
23043
|
});
|
|
22917
23044
|
pi.on("session_shutdown", async (_event, _ctx) => {
|
|
22918
23045
|
if (registry2) {
|
|
22919
|
-
await registry2.
|
|
23046
|
+
await registry2.disconnectAll();
|
|
22920
23047
|
registry2 = null;
|
|
22921
23048
|
}
|
|
22922
23049
|
});
|
|
@@ -23030,38 +23157,16 @@ Updated: ${catalog.lastUpdated}`,
|
|
|
23030
23157
|
}
|
|
23031
23158
|
});
|
|
23032
23159
|
pi.registerCommand(`unipi:${MCP_COMMANDS.RELOAD}`, {
|
|
23033
|
-
description: "
|
|
23160
|
+
description: "Explain how to reload MCP servers safely",
|
|
23034
23161
|
handler: async (_args, ctx) => {
|
|
23035
|
-
|
|
23036
|
-
if (!reg) {
|
|
23037
|
-
ctx.ui.notify("MCP extension not initialized", "warning");
|
|
23038
|
-
return;
|
|
23039
|
-
}
|
|
23040
|
-
const all = reg.getAll();
|
|
23041
|
-
if (all.length === 0) {
|
|
23042
|
-
ctx.ui.notify("No MCP servers configured. Use /unipi:mcp-add to add one.", "info");
|
|
23043
|
-
return;
|
|
23044
|
-
}
|
|
23045
|
-
ctx.ui.notify(`Reloading ${all.length} MCP server(s)...`, "info");
|
|
23046
|
-
let restarted = 0;
|
|
23047
|
-
let failed = 0;
|
|
23048
|
-
for (const state of all) {
|
|
23049
|
-
try {
|
|
23050
|
-
await reg.restartServer(state.name);
|
|
23051
|
-
restarted++;
|
|
23052
|
-
} catch (_err) {
|
|
23053
|
-
failed++;
|
|
23054
|
-
}
|
|
23055
|
-
}
|
|
23056
|
-
const msg = failed > 0 ? `Reloaded: ${restarted} ok, ${failed} failed` : `Reloaded ${restarted} MCP server(s) successfully`;
|
|
23057
|
-
ctx.ui.notify(msg, failed > 0 ? "warning" : "info");
|
|
23162
|
+
ctx.ui.notify("Restart Pi to reload MCP servers and tool schemas safely.", "info");
|
|
23058
23163
|
}
|
|
23059
23164
|
});
|
|
23060
23165
|
}
|
|
23061
23166
|
|
|
23062
23167
|
// packages/notify/index.ts
|
|
23063
23168
|
init_core();
|
|
23064
|
-
import { dirname as
|
|
23169
|
+
import { dirname as dirname21 } from "node:path";
|
|
23065
23170
|
import { fileURLToPath as fileURLToPath10 } from "node:url";
|
|
23066
23171
|
|
|
23067
23172
|
// packages/notify/tools.ts
|
|
@@ -23071,7 +23176,7 @@ import { Type as Type6 } from "typebox";
|
|
|
23071
23176
|
// packages/notify/settings.ts
|
|
23072
23177
|
init_core();
|
|
23073
23178
|
import { readFileSync as readFileSync19, writeFileSync as writeFileSync17, mkdirSync as mkdirSync15, existsSync as existsSync24 } from "fs";
|
|
23074
|
-
import { dirname as
|
|
23179
|
+
import { dirname as dirname19, join as join22 } from "path";
|
|
23075
23180
|
import { homedir as homedir17 } from "os";
|
|
23076
23181
|
function resolveConfigPath() {
|
|
23077
23182
|
const base = NOTIFY_DIRS.CONFIG.replace("~", homedir17());
|
|
@@ -23125,7 +23230,7 @@ function loadConfig2() {
|
|
|
23125
23230
|
}
|
|
23126
23231
|
function saveConfig2(config) {
|
|
23127
23232
|
const configPath = resolveConfigPath();
|
|
23128
|
-
const dir =
|
|
23233
|
+
const dir = dirname19(configPath);
|
|
23129
23234
|
mkdirSync15(dir, { recursive: true });
|
|
23130
23235
|
writeFileSync17(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
23131
23236
|
}
|
|
@@ -23186,7 +23291,7 @@ init_core();
|
|
|
23186
23291
|
|
|
23187
23292
|
// packages/notify/ntfy-config.ts
|
|
23188
23293
|
import { readFileSync as readFileSync20, writeFileSync as writeFileSync18, mkdirSync as mkdirSync16, existsSync as existsSync25 } from "fs";
|
|
23189
|
-
import { dirname as
|
|
23294
|
+
import { dirname as dirname20, join as join23 } from "path";
|
|
23190
23295
|
import { homedir as homedir18 } from "os";
|
|
23191
23296
|
var DEFAULT_NTFY_CONFIG = {
|
|
23192
23297
|
enabled: false,
|
|
@@ -23226,7 +23331,7 @@ function loadNtfyConfig(cwd) {
|
|
|
23226
23331
|
}
|
|
23227
23332
|
function saveNtfyConfig(scope, cwd, config) {
|
|
23228
23333
|
const filePath = scope === "project" ? getProjectNtfyPath(cwd) : getGlobalNtfyPath();
|
|
23229
|
-
const dir =
|
|
23334
|
+
const dir = dirname20(filePath);
|
|
23230
23335
|
mkdirSync16(dir, { recursive: true });
|
|
23231
23336
|
writeFileSync18(filePath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
23232
23337
|
}
|
|
@@ -23266,7 +23371,7 @@ function migrateFromLegacyConfig() {
|
|
|
23266
23371
|
token: ntfySection.token,
|
|
23267
23372
|
priority: ntfySection.priority ?? 3
|
|
23268
23373
|
};
|
|
23269
|
-
const dir =
|
|
23374
|
+
const dir = dirname20(globalNtfyPath);
|
|
23270
23375
|
mkdirSync16(dir, { recursive: true });
|
|
23271
23376
|
writeFileSync18(
|
|
23272
23377
|
globalNtfyPath,
|
|
@@ -23322,7 +23427,7 @@ async function isWindowFocusedOnWindows() {
|
|
|
23322
23427
|
tmpDir = mkdtempSync(join24(tmpdir2(), "pi-focus-"));
|
|
23323
23428
|
const scriptPath = join24(tmpDir, "check.ps1");
|
|
23324
23429
|
writeFileSync19(scriptPath, POWERCHECK_SCRIPT, "utf-8");
|
|
23325
|
-
const stdout = await new Promise((
|
|
23430
|
+
const stdout = await new Promise((resolve14, reject) => {
|
|
23326
23431
|
execFile(
|
|
23327
23432
|
"powershell.exe",
|
|
23328
23433
|
[
|
|
@@ -23337,7 +23442,7 @@ async function isWindowFocusedOnWindows() {
|
|
|
23337
23442
|
{ timeout: 5e3, encoding: "utf-8" },
|
|
23338
23443
|
(err, out) => {
|
|
23339
23444
|
if (err) reject(err);
|
|
23340
|
-
else
|
|
23445
|
+
else resolve14(out);
|
|
23341
23446
|
}
|
|
23342
23447
|
);
|
|
23343
23448
|
});
|
|
@@ -23379,7 +23484,7 @@ async function sendNativeNotification(title, message, options) {
|
|
|
23379
23484
|
if (options?.suppressWhenFocused && await isWindowFocused()) {
|
|
23380
23485
|
throw new SuppressedError2();
|
|
23381
23486
|
}
|
|
23382
|
-
return new Promise((
|
|
23487
|
+
return new Promise((resolve14, reject) => {
|
|
23383
23488
|
notifier.notify(
|
|
23384
23489
|
{
|
|
23385
23490
|
title,
|
|
@@ -23394,7 +23499,7 @@ async function sendNativeNotification(title, message, options) {
|
|
|
23394
23499
|
)
|
|
23395
23500
|
);
|
|
23396
23501
|
} else {
|
|
23397
|
-
|
|
23502
|
+
resolve14();
|
|
23398
23503
|
}
|
|
23399
23504
|
}
|
|
23400
23505
|
);
|
|
@@ -23731,7 +23836,7 @@ function getEnabledPlatforms(config, ntfyEnabled) {
|
|
|
23731
23836
|
function unregisterEventListeners() {
|
|
23732
23837
|
unregisterAll();
|
|
23733
23838
|
}
|
|
23734
|
-
async function dispatchNotification(pi, title, message, eventPlatforms, eventType, config, cwd) {
|
|
23839
|
+
async function dispatchNotification(pi, title, message, eventPlatforms, eventType, config, cwd, priority) {
|
|
23735
23840
|
const ntfyConfig = loadNtfyConfig(cwd);
|
|
23736
23841
|
const platforms = eventPlatforms.length > 0 ? eventPlatforms : getEnabledPlatforms(config, ntfyConfig.enabled).length > 0 ? getEnabledPlatforms(config, ntfyConfig.enabled) : config.defaultPlatforms;
|
|
23737
23842
|
const enabledPlatforms = platforms.filter((p) => {
|
|
@@ -23744,8 +23849,8 @@ async function dispatchNotification(pi, title, message, eventPlatforms, eventTyp
|
|
|
23744
23849
|
const results = await Promise.all(
|
|
23745
23850
|
enabledPlatforms.map(async (platform) => {
|
|
23746
23851
|
try {
|
|
23747
|
-
await sendToPlatform(platform, title, message, config, cwd);
|
|
23748
|
-
return { platform, success: true };
|
|
23852
|
+
const effectivePriority = await sendToPlatform(platform, title, message, config, cwd, priority);
|
|
23853
|
+
return { platform, success: true, ...effectivePriority === void 0 ? {} : { priority: effectivePriority } };
|
|
23749
23854
|
} catch (err) {
|
|
23750
23855
|
if (err instanceof SuppressedError2) {
|
|
23751
23856
|
return { platform, success: true, suppressed: true };
|
|
@@ -23770,14 +23875,21 @@ async function dispatchNotification(pi, title, message, eventPlatforms, eventTyp
|
|
|
23770
23875
|
});
|
|
23771
23876
|
return { results, allSuccess };
|
|
23772
23877
|
}
|
|
23773
|
-
|
|
23878
|
+
function mapNotifyPriority(platform, priority) {
|
|
23879
|
+
const mappings = {
|
|
23880
|
+
gotify: { low: 2, normal: 5, high: 8 },
|
|
23881
|
+
ntfy: { low: 2, normal: 3, high: 5 }
|
|
23882
|
+
};
|
|
23883
|
+
return mappings[platform][priority];
|
|
23884
|
+
}
|
|
23885
|
+
async function sendToPlatform(platform, title, message, config, cwd, priority) {
|
|
23774
23886
|
switch (platform) {
|
|
23775
23887
|
case "native":
|
|
23776
23888
|
await sendNativeNotification(title, message, {
|
|
23777
23889
|
windowsAppId: config.native.windowsAppId,
|
|
23778
23890
|
suppressWhenFocused: config.native.suppressWhenFocused
|
|
23779
23891
|
});
|
|
23780
|
-
|
|
23892
|
+
return void 0;
|
|
23781
23893
|
case "gotify":
|
|
23782
23894
|
if (!config.gotify.serverUrl || !config.gotify.appToken) {
|
|
23783
23895
|
throw new Error("Gotify: serverUrl and appToken are required");
|
|
@@ -23787,9 +23899,9 @@ async function sendToPlatform(platform, title, message, config, cwd) {
|
|
|
23787
23899
|
config.gotify.appToken,
|
|
23788
23900
|
title,
|
|
23789
23901
|
message,
|
|
23790
|
-
config.gotify.priority
|
|
23902
|
+
priority ? mapNotifyPriority("gotify", priority) : config.gotify.priority
|
|
23791
23903
|
);
|
|
23792
|
-
|
|
23904
|
+
return priority ? mapNotifyPriority("gotify", priority) : config.gotify.priority;
|
|
23793
23905
|
case "telegram":
|
|
23794
23906
|
if (!config.telegram.botToken || !config.telegram.chatId) {
|
|
23795
23907
|
throw new Error("Telegram: botToken and chatId are required");
|
|
@@ -23800,10 +23912,10 @@ async function sendToPlatform(platform, title, message, config, cwd) {
|
|
|
23800
23912
|
title,
|
|
23801
23913
|
message
|
|
23802
23914
|
);
|
|
23803
|
-
|
|
23915
|
+
return void 0;
|
|
23804
23916
|
case "ntfy": {
|
|
23805
23917
|
const ntfyConfig = loadNtfyConfig(cwd);
|
|
23806
|
-
if (!ntfyConfig.enabled) return;
|
|
23918
|
+
if (!ntfyConfig.enabled) return void 0;
|
|
23807
23919
|
if (!ntfyConfig.serverUrl || !ntfyConfig.topic) {
|
|
23808
23920
|
throw new Error("ntfy: serverUrl and topic are required");
|
|
23809
23921
|
}
|
|
@@ -23812,10 +23924,10 @@ async function sendToPlatform(platform, title, message, config, cwd) {
|
|
|
23812
23924
|
ntfyConfig.topic,
|
|
23813
23925
|
title,
|
|
23814
23926
|
message,
|
|
23815
|
-
ntfyConfig.priority,
|
|
23927
|
+
priority ? mapNotifyPriority("ntfy", priority) : ntfyConfig.priority,
|
|
23816
23928
|
ntfyConfig.token
|
|
23817
23929
|
);
|
|
23818
|
-
|
|
23930
|
+
return priority ? mapNotifyPriority("ntfy", priority) : ntfyConfig.priority;
|
|
23819
23931
|
}
|
|
23820
23932
|
}
|
|
23821
23933
|
}
|
|
@@ -23944,7 +24056,6 @@ var NotifyUserSchema = Type6.Object({
|
|
|
23944
24056
|
priority: Type6.Optional(
|
|
23945
24057
|
Type6.String({
|
|
23946
24058
|
enum: ["low", "normal", "high"],
|
|
23947
|
-
default: "normal",
|
|
23948
24059
|
description: "Priority level"
|
|
23949
24060
|
})
|
|
23950
24061
|
),
|
|
@@ -23965,23 +24076,31 @@ function registerNotifyTools(pi) {
|
|
|
23965
24076
|
const {
|
|
23966
24077
|
message,
|
|
23967
24078
|
title,
|
|
23968
|
-
priority
|
|
24079
|
+
priority,
|
|
23969
24080
|
platforms
|
|
23970
24081
|
} = params;
|
|
23971
24082
|
const config = loadConfig2();
|
|
23972
24083
|
const notifTitle = title || "Pi Notification";
|
|
23973
24084
|
const notifPlatforms = platforms || config.defaultPlatforms;
|
|
23974
24085
|
const cwd = process.cwd();
|
|
23975
|
-
dispatchNotification(
|
|
24086
|
+
const dispatchPromise = dispatchNotification(
|
|
23976
24087
|
pi,
|
|
23977
24088
|
notifTitle,
|
|
23978
24089
|
message,
|
|
23979
24090
|
notifPlatforms,
|
|
23980
24091
|
"agent_tool",
|
|
23981
24092
|
config,
|
|
23982
|
-
cwd
|
|
23983
|
-
|
|
24093
|
+
cwd,
|
|
24094
|
+
priority
|
|
24095
|
+
);
|
|
24096
|
+
void dispatchPromise.catch(() => {
|
|
23984
24097
|
});
|
|
24098
|
+
const priorityByPlatform = priority ? Object.fromEntries(
|
|
24099
|
+
notifPlatforms.flatMap((platform) => {
|
|
24100
|
+
if (platform === "gotify" || platform === "ntfy") return [[platform, mapNotifyPriority(platform, priority)]];
|
|
24101
|
+
return [];
|
|
24102
|
+
})
|
|
24103
|
+
) : void 0;
|
|
23985
24104
|
return {
|
|
23986
24105
|
content: [
|
|
23987
24106
|
{
|
|
@@ -23989,7 +24108,7 @@ function registerNotifyTools(pi) {
|
|
|
23989
24108
|
text: `Notification sending to ${notifPlatforms.length} platform(s): ${notifPlatforms.join(", ")}`
|
|
23990
24109
|
}
|
|
23991
24110
|
],
|
|
23992
|
-
details: { platforms: notifPlatforms }
|
|
24111
|
+
details: { platforms: notifPlatforms, priority, priorityByPlatform }
|
|
23993
24112
|
};
|
|
23994
24113
|
}
|
|
23995
24114
|
});
|
|
@@ -26116,7 +26235,7 @@ ${results.join("\n")}`, "info");
|
|
|
26116
26235
|
}
|
|
26117
26236
|
|
|
26118
26237
|
// packages/notify/index.ts
|
|
26119
|
-
var VERSION9 = getPackageVersion(
|
|
26238
|
+
var VERSION9 = getPackageVersion(dirname21(fileURLToPath10(import.meta.url)));
|
|
26120
26239
|
function notify_default(pi) {
|
|
26121
26240
|
registerNotifyTools(pi);
|
|
26122
26241
|
registerNotifyCommands(pi);
|
|
@@ -26145,6 +26264,9 @@ init_core();
|
|
|
26145
26264
|
init_core();
|
|
26146
26265
|
import * as fs14 from "node:fs";
|
|
26147
26266
|
import * as path13 from "node:path";
|
|
26267
|
+
import {
|
|
26268
|
+
buildSessionContext as buildSessionContext3
|
|
26269
|
+
} from "@earendil-works/pi-coding-agent";
|
|
26148
26270
|
|
|
26149
26271
|
// packages/milestone/milestone.ts
|
|
26150
26272
|
init_core();
|
|
@@ -26290,7 +26412,7 @@ function getProgressSummary(filePath) {
|
|
|
26290
26412
|
}
|
|
26291
26413
|
|
|
26292
26414
|
// packages/milestone/hooks.ts
|
|
26293
|
-
var
|
|
26415
|
+
var MILESTONE_SNAPSHOT_TYPE = "unipi-milestone-snapshot";
|
|
26294
26416
|
function formatMilestoneContext(filePath) {
|
|
26295
26417
|
const summary = getProgressSummary(filePath);
|
|
26296
26418
|
if (summary.totalItems === 0) return null;
|
|
@@ -26303,16 +26425,67 @@ function formatMilestoneContext(filePath) {
|
|
|
26303
26425
|
focus
|
|
26304
26426
|
].filter(Boolean).join("\n");
|
|
26305
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
|
+
}
|
|
26306
26466
|
function registerSessionStartHook(pi) {
|
|
26307
|
-
pi.on("before_agent_start", (
|
|
26308
|
-
|
|
26309
|
-
const
|
|
26310
|
-
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);
|
|
26311
26470
|
const context = formatMilestoneContext(milestonesPath);
|
|
26312
|
-
|
|
26313
|
-
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;
|
|
26314
26479
|
return {
|
|
26315
|
-
|
|
26480
|
+
message: {
|
|
26481
|
+
customType: MILESTONE_SNAPSHOT_TYPE,
|
|
26482
|
+
content,
|
|
26483
|
+
display: false,
|
|
26484
|
+
details: {
|
|
26485
|
+
active: context !== null,
|
|
26486
|
+
workspace
|
|
26487
|
+
}
|
|
26488
|
+
}
|
|
26316
26489
|
};
|
|
26317
26490
|
});
|
|
26318
26491
|
}
|
|
@@ -26368,14 +26541,16 @@ function scanModifiedDocs(dirs, since) {
|
|
|
26368
26541
|
}
|
|
26369
26542
|
function registerSessionEndHook(pi) {
|
|
26370
26543
|
const baselineSnapshots = /* @__PURE__ */ new Map();
|
|
26371
|
-
|
|
26544
|
+
let sessionStartMs = 0;
|
|
26545
|
+
let sessionWorkspace = null;
|
|
26546
|
+
pi.on("session_start", (_event, ctx) => {
|
|
26372
26547
|
sessionStartMs = Date.now();
|
|
26548
|
+
sessionWorkspace = ctx.cwd;
|
|
26373
26549
|
baselineSnapshots.clear();
|
|
26374
|
-
const cwd = process.cwd();
|
|
26375
26550
|
const scanDirs = [
|
|
26376
|
-
path13.join(
|
|
26377
|
-
path13.join(
|
|
26378
|
-
path13.join(
|
|
26551
|
+
path13.join(sessionWorkspace, ".unipi/docs/specs"),
|
|
26552
|
+
path13.join(sessionWorkspace, ".unipi/docs/plans"),
|
|
26553
|
+
path13.join(sessionWorkspace, ".unipi/docs/quick-work")
|
|
26379
26554
|
];
|
|
26380
26555
|
for (const dir of scanDirs) {
|
|
26381
26556
|
if (!fs14.existsSync(dir)) continue;
|
|
@@ -26388,17 +26563,14 @@ function registerSessionEndHook(pi) {
|
|
|
26388
26563
|
}
|
|
26389
26564
|
}
|
|
26390
26565
|
});
|
|
26391
|
-
|
|
26392
|
-
|
|
26393
|
-
|
|
26394
|
-
pi.on("session_shutdown", () => {
|
|
26395
|
-
const cwd = process.cwd();
|
|
26396
|
-
const milestonesPath = path13.join(cwd, MILESTONE_DIRS.MILESTONES);
|
|
26566
|
+
const syncModifiedDocs = () => {
|
|
26567
|
+
if (!sessionWorkspace) return;
|
|
26568
|
+
const milestonesPath = path13.join(sessionWorkspace, MILESTONE_DIRS.MILESTONES);
|
|
26397
26569
|
if (!fs14.existsSync(milestonesPath)) return;
|
|
26398
26570
|
const scanDirs = [
|
|
26399
|
-
path13.join(
|
|
26400
|
-
path13.join(
|
|
26401
|
-
path13.join(
|
|
26571
|
+
path13.join(sessionWorkspace, ".unipi/docs/specs"),
|
|
26572
|
+
path13.join(sessionWorkspace, ".unipi/docs/plans"),
|
|
26573
|
+
path13.join(sessionWorkspace, ".unipi/docs/quick-work")
|
|
26402
26574
|
];
|
|
26403
26575
|
const modifiedFiles = scanModifiedDocs(scanDirs, sessionStartMs);
|
|
26404
26576
|
for (const filePath of modifiedFiles) {
|
|
@@ -26409,15 +26581,17 @@ function registerSessionEndHook(pi) {
|
|
|
26409
26581
|
updateItemStatus(milestonesPath, phase, text, true);
|
|
26410
26582
|
}
|
|
26411
26583
|
}
|
|
26412
|
-
}
|
|
26584
|
+
};
|
|
26585
|
+
pi.events.on(UNIPI_EVENTS.WORKFLOW_END, syncModifiedDocs);
|
|
26586
|
+
pi.on("session_shutdown", syncModifiedDocs);
|
|
26413
26587
|
}
|
|
26414
26588
|
|
|
26415
26589
|
// packages/milestone/commands.ts
|
|
26416
26590
|
init_core();
|
|
26417
|
-
import { dirname as
|
|
26591
|
+
import { dirname as dirname22, join as join26 } from "node:path";
|
|
26418
26592
|
import { fileURLToPath as fileURLToPath11 } from "node:url";
|
|
26419
26593
|
import { readFileSync as readFileSync21 } from "node:fs";
|
|
26420
|
-
var SKILLS_DIR = join26(
|
|
26594
|
+
var SKILLS_DIR = join26(dirname22(fileURLToPath11(import.meta.url)), "skills");
|
|
26421
26595
|
function loadSkill(skillName) {
|
|
26422
26596
|
try {
|
|
26423
26597
|
return readFileSync21(join26(SKILLS_DIR, skillName, "SKILL.md"), "utf-8");
|
|
@@ -26644,9 +26818,9 @@ var KanboardServer = class {
|
|
|
26644
26818
|
}
|
|
26645
26819
|
/** Bind server to a port */
|
|
26646
26820
|
listen(port) {
|
|
26647
|
-
return new Promise((
|
|
26821
|
+
return new Promise((resolve14, reject) => {
|
|
26648
26822
|
this.server.once("error", reject);
|
|
26649
|
-
this.server.listen(port, () =>
|
|
26823
|
+
this.server.listen(port, () => resolve14());
|
|
26650
26824
|
});
|
|
26651
26825
|
}
|
|
26652
26826
|
/** Handle incoming HTTP request */
|
|
@@ -27615,11 +27789,11 @@ function markAutoCompactionError(state, nowMs) {
|
|
|
27615
27789
|
}
|
|
27616
27790
|
|
|
27617
27791
|
// packages/compactor/src/session/db.ts
|
|
27618
|
-
import { createHash as
|
|
27792
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
27619
27793
|
import { execFileSync } from "node:child_process";
|
|
27620
27794
|
import { existsSync as existsSync32, mkdirSync as mkdirSync20 } from "node:fs";
|
|
27621
27795
|
import { homedir as homedir21 } from "node:os";
|
|
27622
|
-
import { dirname as
|
|
27796
|
+
import { dirname as dirname25, join as join33 } from "node:path";
|
|
27623
27797
|
function getWorktreeSuffix() {
|
|
27624
27798
|
const envSuffix = process.env.COMPACTOR_SESSION_SUFFIX;
|
|
27625
27799
|
if (envSuffix !== void 0) {
|
|
@@ -27633,7 +27807,7 @@ function getWorktreeSuffix() {
|
|
|
27633
27807
|
{ encoding: "utf-8", timeout: 2e3, stdio: ["ignore", "pipe", "ignore"] }
|
|
27634
27808
|
).split(/\r?\n/).find((l) => l.startsWith("worktree "))?.replace("worktree ", "")?.trim();
|
|
27635
27809
|
if (mainWorktree && cwd !== mainWorktree) {
|
|
27636
|
-
const suffix =
|
|
27810
|
+
const suffix = createHash3("sha256").update(cwd).digest("hex").slice(0, 8);
|
|
27637
27811
|
return `__${suffix}`;
|
|
27638
27812
|
}
|
|
27639
27813
|
} catch {
|
|
@@ -27664,7 +27838,7 @@ var SessionDB = class {
|
|
|
27664
27838
|
this.dbPath = opts?.dbPath ?? defaultDBPath("session");
|
|
27665
27839
|
}
|
|
27666
27840
|
async init() {
|
|
27667
|
-
const dir =
|
|
27841
|
+
const dir = dirname25(this.dbPath);
|
|
27668
27842
|
if (!existsSync32(dir)) mkdirSync20(dir, { recursive: true });
|
|
27669
27843
|
const sqlite = await getSQLite();
|
|
27670
27844
|
const Database2 = sqlite.Database ?? sqlite.default?.Database ?? sqlite.default ?? sqlite;
|
|
@@ -27775,7 +27949,7 @@ var SessionDB = class {
|
|
|
27775
27949
|
}
|
|
27776
27950
|
insertEvent(sessionId, event, sourceHook = "PostToolUse") {
|
|
27777
27951
|
if (!this.stmts) return;
|
|
27778
|
-
const dataHash =
|
|
27952
|
+
const dataHash = createHash3("sha256").update(event.data).digest("hex").slice(0, 16).toUpperCase();
|
|
27779
27953
|
const projectDir = String(event.project_dir ?? "").trim();
|
|
27780
27954
|
const attributionSource = String(event.attribution_source ?? "unknown");
|
|
27781
27955
|
const rawConfidence = Number(event.attribution_confidence ?? 0);
|
|
@@ -27979,8 +28153,49 @@ function extractEventsFromToolResult(result) {
|
|
|
27979
28153
|
|
|
27980
28154
|
// packages/compactor/src/session/resume-inject.ts
|
|
27981
28155
|
init_snapshot();
|
|
27982
|
-
|
|
28156
|
+
|
|
28157
|
+
// packages/compactor/src/session/auto-inject.ts
|
|
28158
|
+
var MAX_TOKENS2 = 150;
|
|
28159
|
+
function estimateTokens(text) {
|
|
28160
|
+
return Math.ceil(text.length / 4);
|
|
28161
|
+
}
|
|
28162
|
+
function buildAutoInjection(events) {
|
|
28163
|
+
const parts = [];
|
|
28164
|
+
let tokenBudget = MAX_TOKENS2;
|
|
28165
|
+
const roleEvents = events.filter((e) => e.category === "rule");
|
|
28166
|
+
if (roleEvents.length > 0) {
|
|
28167
|
+
const directive = roleEvents[roleEvents.length - 1].data;
|
|
28168
|
+
const directiveText = `[Role Directive]
|
|
28169
|
+
${directive}`;
|
|
28170
|
+
const tokens = estimateTokens(directiveText);
|
|
28171
|
+
if (tokens <= tokenBudget) {
|
|
28172
|
+
parts.push(directiveText);
|
|
28173
|
+
tokenBudget -= tokens;
|
|
28174
|
+
}
|
|
28175
|
+
}
|
|
28176
|
+
if (tokenBudget > 80) {
|
|
28177
|
+
const intentEvents = events.filter((e) => e.category === "intent");
|
|
28178
|
+
if (intentEvents.length > 0) {
|
|
28179
|
+
const mode = intentEvents[intentEvents.length - 1].data;
|
|
28180
|
+
const modeText = `[Session Mode]
|
|
28181
|
+
${mode}`;
|
|
28182
|
+
const tokens = estimateTokens(modeText);
|
|
28183
|
+
if (tokens <= tokenBudget) {
|
|
28184
|
+
parts.push(modeText);
|
|
28185
|
+
tokenBudget -= tokens;
|
|
28186
|
+
}
|
|
28187
|
+
}
|
|
28188
|
+
}
|
|
28189
|
+
if (parts.length === 0) return null;
|
|
28190
|
+
const text = parts.join("\n\n");
|
|
28191
|
+
return { text, tokens: estimateTokens(text) };
|
|
28192
|
+
}
|
|
28193
|
+
|
|
28194
|
+
// packages/compactor/src/session/resume-inject.ts
|
|
27983
28195
|
init_manager();
|
|
28196
|
+
function isSessionContinuityEnabled(config) {
|
|
28197
|
+
return config.sessionContinuity.enabled && config.sessionContinuity.mode !== "off";
|
|
28198
|
+
}
|
|
27984
28199
|
async function injectResumeSnapshot(db, sessionId, opts) {
|
|
27985
28200
|
const resume = db.getResume(sessionId);
|
|
27986
28201
|
if (!resume || resume.consumed) return null;
|
|
@@ -28003,11 +28218,22 @@ ${autoInjection}`;
|
|
|
28003
28218
|
db.markResumeConsumed(sessionId);
|
|
28004
28219
|
return fullSnapshot;
|
|
28005
28220
|
}
|
|
28221
|
+
async function buildResumeContextMessage(db, sessionId) {
|
|
28222
|
+
const snapshot = await injectResumeSnapshot(db, sessionId);
|
|
28223
|
+
if (!snapshot) return void 0;
|
|
28224
|
+
return {
|
|
28225
|
+
message: {
|
|
28226
|
+
customType: "unipi-compactor-resume",
|
|
28227
|
+
content: snapshot,
|
|
28228
|
+
display: false
|
|
28229
|
+
}
|
|
28230
|
+
};
|
|
28231
|
+
}
|
|
28006
28232
|
|
|
28007
28233
|
// packages/compactor/src/executor/executor.ts
|
|
28008
28234
|
import { spawn as spawn3, execSync, execFileSync as execFileSync2 } from "node:child_process";
|
|
28009
28235
|
import { mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync24, rmSync as rmSync3 } from "node:fs";
|
|
28010
|
-
import { join as join34, resolve as
|
|
28236
|
+
import { join as join34, resolve as resolve11 } from "node:path";
|
|
28011
28237
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
28012
28238
|
|
|
28013
28239
|
// packages/compactor/src/executor/runtime.ts
|
|
@@ -28099,7 +28325,7 @@ var OS_TMPDIR = (() => {
|
|
|
28099
28325
|
process.platform === "darwin" ? ["DARWIN_USER_TEMP_DIR"] : ["-u", "-d"],
|
|
28100
28326
|
{ env: { ...process.env, TMPDIR: void 0 }, encoding: "utf-8" }
|
|
28101
28327
|
).trim();
|
|
28102
|
-
const dir = process.platform === "darwin" ? result :
|
|
28328
|
+
const dir = process.platform === "darwin" ? result : resolve11(result, "..");
|
|
28103
28329
|
if (dir && dir !== process.cwd()) return dir;
|
|
28104
28330
|
} catch {
|
|
28105
28331
|
}
|
|
@@ -28220,7 +28446,7 @@ var PolyglotExecutor = class {
|
|
|
28220
28446
|
async executeFile(opts) {
|
|
28221
28447
|
const { language, path: path28, timeout = 3e4, background = false } = opts;
|
|
28222
28448
|
const cmd = buildCommand(this.#runtimes, language, path28);
|
|
28223
|
-
const cwd = language === "shell" ? this.#projectRoot :
|
|
28449
|
+
const cwd = language === "shell" ? this.#projectRoot : resolve11(path28, "..");
|
|
28224
28450
|
return this.#spawn(cmd, cwd, "", timeout, background);
|
|
28225
28451
|
}
|
|
28226
28452
|
#writeScript(tmpDir, code, language) {
|
|
@@ -28243,7 +28469,7 @@ var PolyglotExecutor = class {
|
|
|
28243
28469
|
return filePath;
|
|
28244
28470
|
}
|
|
28245
28471
|
async #spawn(cmd, cwd, tmpDir, timeout, background) {
|
|
28246
|
-
return new Promise((
|
|
28472
|
+
return new Promise((resolve14) => {
|
|
28247
28473
|
const proc = spawn3(cmd[0], cmd.slice(1), {
|
|
28248
28474
|
cwd,
|
|
28249
28475
|
env: sanitizeEnv(),
|
|
@@ -28279,14 +28505,14 @@ var PolyglotExecutor = class {
|
|
|
28279
28505
|
}, timeout);
|
|
28280
28506
|
proc.on("error", (err) => {
|
|
28281
28507
|
if (timer) clearTimeout(timer);
|
|
28282
|
-
|
|
28508
|
+
resolve14({ stdout, stderr: err.message, exitCode: 1, timedOut: false });
|
|
28283
28509
|
});
|
|
28284
28510
|
proc.on("close", (code) => {
|
|
28285
28511
|
if (timer) clearTimeout(timer);
|
|
28286
28512
|
if (background && proc.pid) {
|
|
28287
28513
|
this.#backgroundedPids.add(proc.pid);
|
|
28288
28514
|
}
|
|
28289
|
-
|
|
28515
|
+
resolve14({
|
|
28290
28516
|
stdout: stdout.slice(0, this.#hardCapBytes),
|
|
28291
28517
|
stderr: stderr.slice(0, this.#hardCapBytes),
|
|
28292
28518
|
exitCode: code ?? 0,
|
|
@@ -28324,7 +28550,7 @@ init_core();
|
|
|
28324
28550
|
init_hooks();
|
|
28325
28551
|
|
|
28326
28552
|
// packages/compactor/src/compaction/search-entries.ts
|
|
28327
|
-
import { createHash as
|
|
28553
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
28328
28554
|
function tokenize(text) {
|
|
28329
28555
|
return text.toLowerCase().replace(/[^\p{L}\p{N}\s]/gu, " ").split(/\s+/).filter((w) => w.length > 1);
|
|
28330
28556
|
}
|
|
@@ -28368,7 +28594,7 @@ function searchEntries(blocks, query, opts) {
|
|
|
28368
28594
|
kind: b.kind
|
|
28369
28595
|
}));
|
|
28370
28596
|
const hashSource = docs.length > 0 ? `${docs.length}:${docs[0].text.slice(0, 80)}:${docs[docs.length - 1].text.slice(-80)}` : "empty";
|
|
28371
|
-
const currentHash =
|
|
28597
|
+
const currentHash = createHash5("sha256").update(hashSource).digest("hex");
|
|
28372
28598
|
let index;
|
|
28373
28599
|
let docCount;
|
|
28374
28600
|
let avgDocLen;
|
|
@@ -28811,8 +29037,7 @@ function compactTool() {
|
|
|
28811
29037
|
}
|
|
28812
29038
|
|
|
28813
29039
|
// packages/compactor/src/tools/ctx-execute.ts
|
|
28814
|
-
async function ctxExecute(input) {
|
|
28815
|
-
const executor = new PolyglotExecutor();
|
|
29040
|
+
async function ctxExecute(input, executor = new PolyglotExecutor()) {
|
|
28816
29041
|
return executor.execute({
|
|
28817
29042
|
language: input.language,
|
|
28818
29043
|
code: input.code,
|
|
@@ -28822,12 +29047,11 @@ async function ctxExecute(input) {
|
|
|
28822
29047
|
|
|
28823
29048
|
// packages/compactor/src/tools/ctx-execute-file.ts
|
|
28824
29049
|
import { readFileSync as readFileSync30 } from "node:fs";
|
|
28825
|
-
async function ctxExecuteFile(input) {
|
|
29050
|
+
async function ctxExecuteFile(input, executor = new PolyglotExecutor()) {
|
|
28826
29051
|
const content = readFileSync30(input.path, "utf-8");
|
|
28827
29052
|
const code = `const FILE_CONTENT = ${JSON.stringify(content)};
|
|
28828
29053
|
// User script follows:
|
|
28829
29054
|
`;
|
|
28830
|
-
const executor = new PolyglotExecutor();
|
|
28831
29055
|
return executor.executeFile({
|
|
28832
29056
|
language: input.language,
|
|
28833
29057
|
path: input.path,
|
|
@@ -28837,9 +29061,8 @@ async function ctxExecuteFile(input) {
|
|
|
28837
29061
|
}
|
|
28838
29062
|
|
|
28839
29063
|
// packages/compactor/src/tools/ctx-batch-execute.ts
|
|
28840
|
-
async function ctxBatchExecute(items) {
|
|
29064
|
+
async function ctxBatchExecute(items, executor = new PolyglotExecutor()) {
|
|
28841
29065
|
const results = [];
|
|
28842
|
-
const executor = new PolyglotExecutor();
|
|
28843
29066
|
for (const item of items) {
|
|
28844
29067
|
if (item.type === "execute") {
|
|
28845
29068
|
const result = await executor.execute({
|
|
@@ -29024,74 +29247,85 @@ ${lines.join("\n\n")}`,
|
|
|
29024
29247
|
deprecationLog2("vcc_recall", "session_recall");
|
|
29025
29248
|
return recallExec(tcId, p);
|
|
29026
29249
|
} });
|
|
29027
|
-
|
|
29028
|
-
|
|
29029
|
-
|
|
29030
|
-
if (
|
|
29031
|
-
|
|
29250
|
+
if (deps.sandbox) {
|
|
29251
|
+
const { executor, allowedLanguages } = deps.sandbox;
|
|
29252
|
+
const assertAllowedLanguage = (language) => {
|
|
29253
|
+
if (!allowedLanguages.includes(language)) {
|
|
29254
|
+
throw new Error(`Language "${language}" is disabled by Compactor sandbox settings. Allowed: ${allowedLanguages.join(", ") || "none"}`);
|
|
29032
29255
|
}
|
|
29033
|
-
|
|
29034
|
-
|
|
29035
|
-
|
|
29036
|
-
|
|
29037
|
-
|
|
29038
|
-
|
|
29039
|
-
|
|
29040
|
-
|
|
29041
|
-
|
|
29042
|
-
|
|
29043
|
-
|
|
29044
|
-
|
|
29045
|
-
|
|
29046
|
-
|
|
29047
|
-
|
|
29048
|
-
|
|
29049
|
-
|
|
29050
|
-
|
|
29051
|
-
try {
|
|
29052
|
-
const c = deps.getCounters?.();
|
|
29053
|
-
if (c) {
|
|
29054
|
-
c.sandboxRuns++;
|
|
29256
|
+
};
|
|
29257
|
+
const sandboxExec = async (_toolCallId, params) => {
|
|
29258
|
+
try {
|
|
29259
|
+
const c = deps.getCounters?.();
|
|
29260
|
+
if (c) {
|
|
29261
|
+
c.sandboxRuns++;
|
|
29262
|
+
}
|
|
29263
|
+
deps.sessionDB.incrementSandboxRuns(deps.getSessionId());
|
|
29264
|
+
assertAllowedLanguage(params.language);
|
|
29265
|
+
const result = await ctxExecute(params, executor);
|
|
29266
|
+
const parts = [];
|
|
29267
|
+
if (result.stdout) parts.push(result.stdout);
|
|
29268
|
+
if (result.stderr) parts.push(`[stderr] ${result.stderr}`);
|
|
29269
|
+
if (result.timedOut) parts.push("[timed out]");
|
|
29270
|
+
if (result.exitCode !== 0) parts.push(`[exit code: ${result.exitCode}]`);
|
|
29271
|
+
return textResult2(parts.join("\n") || "(no output)", result);
|
|
29272
|
+
} catch (err) {
|
|
29273
|
+
return textResult2(`Execution error: ${err}`, { error: true });
|
|
29055
29274
|
}
|
|
29056
|
-
|
|
29057
|
-
|
|
29058
|
-
|
|
29059
|
-
|
|
29060
|
-
|
|
29061
|
-
|
|
29062
|
-
|
|
29063
|
-
|
|
29064
|
-
|
|
29065
|
-
|
|
29066
|
-
|
|
29067
|
-
|
|
29068
|
-
|
|
29069
|
-
|
|
29070
|
-
|
|
29071
|
-
|
|
29072
|
-
|
|
29073
|
-
|
|
29074
|
-
|
|
29075
|
-
|
|
29076
|
-
|
|
29275
|
+
};
|
|
29276
|
+
pi.registerTool({ name: "sandbox", label: "Sandbox", description: "Run code in a sandboxed environment. Supports 11 languages. Only stdout enters context.", parameters: SandboxParams, execute: sandboxExec });
|
|
29277
|
+
pi.registerTool({ name: "ctx_execute", label: "Sandbox", description: "Run code in sandbox. (DEPRECATED: use sandbox instead)", parameters: CtxExecuteParams, async execute(tcId, p) {
|
|
29278
|
+
deprecationLog2("ctx_execute", "sandbox");
|
|
29279
|
+
return sandboxExec(tcId, p);
|
|
29280
|
+
} });
|
|
29281
|
+
const sandboxFileExec = async (_toolCallId, params) => {
|
|
29282
|
+
try {
|
|
29283
|
+
const c = deps.getCounters?.();
|
|
29284
|
+
if (c) {
|
|
29285
|
+
c.sandboxRuns++;
|
|
29286
|
+
}
|
|
29287
|
+
deps.sessionDB.incrementSandboxRuns(deps.getSessionId());
|
|
29288
|
+
assertAllowedLanguage(params.language);
|
|
29289
|
+
const result = await ctxExecuteFile(params, executor);
|
|
29290
|
+
const parts = [];
|
|
29291
|
+
if (result.stdout) parts.push(result.stdout);
|
|
29292
|
+
if (result.stderr) parts.push(`[stderr] ${result.stderr}`);
|
|
29293
|
+
if (result.timedOut) parts.push("[timed out]");
|
|
29294
|
+
return textResult2(parts.join("\n") || "(no output)", result);
|
|
29295
|
+
} catch (err) {
|
|
29296
|
+
return textResult2(`Execution error: ${err}`, { error: true });
|
|
29077
29297
|
}
|
|
29078
|
-
|
|
29079
|
-
|
|
29080
|
-
|
|
29081
|
-
|
|
29082
|
-
|
|
29083
|
-
|
|
29084
|
-
|
|
29298
|
+
};
|
|
29299
|
+
pi.registerTool({ name: "sandbox_file", label: "Sandbox File", description: "Execute a file in the sandbox. File content is injected as FILE_CONTENT variable.", parameters: SandboxFileParams, execute: sandboxFileExec });
|
|
29300
|
+
pi.registerTool({ name: "ctx_execute_file", label: "Sandbox File", description: "Execute file in sandbox. (DEPRECATED: use sandbox_file instead)", parameters: CtxExecuteFileParams, async execute(tcId, p) {
|
|
29301
|
+
deprecationLog2("ctx_execute_file", "sandbox_file");
|
|
29302
|
+
return sandboxFileExec(tcId, p);
|
|
29303
|
+
} });
|
|
29304
|
+
const sandboxBatchExec = async (_toolCallId, params) => {
|
|
29305
|
+
try {
|
|
29306
|
+
const c = deps.getCounters?.();
|
|
29307
|
+
if (c) {
|
|
29308
|
+
c.sandboxRuns++;
|
|
29309
|
+
}
|
|
29310
|
+
deps.sessionDB.incrementSandboxRuns(deps.getSessionId());
|
|
29311
|
+
for (const item of params.items) assertAllowedLanguage(item.language);
|
|
29312
|
+
const result = await ctxBatchExecute(params.items, executor);
|
|
29313
|
+
const summaries = result.results.map((r, i) => {
|
|
29314
|
+
const s = r.result.stdout?.slice(0, 200) || "(no output)";
|
|
29315
|
+
return `[${i}] execute \u2192 ${r.result.exitCode === 0 ? "ok" : "fail"}: ${s}`;
|
|
29316
|
+
});
|
|
29317
|
+
return textResult2(`Batch results (${result.results.length} items):
|
|
29085
29318
|
${summaries.join("\n")}`, result);
|
|
29086
|
-
|
|
29087
|
-
|
|
29088
|
-
|
|
29089
|
-
|
|
29090
|
-
|
|
29091
|
-
|
|
29092
|
-
|
|
29093
|
-
|
|
29094
|
-
|
|
29319
|
+
} catch (err) {
|
|
29320
|
+
return textResult2(`Batch error: ${err}`, { error: true });
|
|
29321
|
+
}
|
|
29322
|
+
};
|
|
29323
|
+
pi.registerTool({ name: "sandbox_batch", label: "Sandbox Batch", description: "Run multiple code executions atomically as a batch.", parameters: SandboxBatchParams, execute: sandboxBatchExec });
|
|
29324
|
+
pi.registerTool({ name: "ctx_batch_execute", label: "Sandbox Batch", description: "Run batch operations. (DEPRECATED: use sandbox_batch instead)", parameters: CtxBatchExecuteParams, async execute(tcId, p) {
|
|
29325
|
+
deprecationLog2("ctx_batch_execute", "sandbox_batch");
|
|
29326
|
+
return sandboxBatchExec(tcId, p);
|
|
29327
|
+
} });
|
|
29328
|
+
}
|
|
29095
29329
|
const statsExec = async () => {
|
|
29096
29330
|
try {
|
|
29097
29331
|
const result = await ctxStats(deps.sessionDB, deps.getSessionId(), deps.getCounters?.());
|
|
@@ -29187,9 +29421,6 @@ function measureResponseBytes(event) {
|
|
|
29187
29421
|
function isSandboxTool(name) {
|
|
29188
29422
|
return name === "bash" || name === "Bash";
|
|
29189
29423
|
}
|
|
29190
|
-
function isIndexTool(_name) {
|
|
29191
|
-
return false;
|
|
29192
|
-
}
|
|
29193
29424
|
function compactorExtension(pi) {
|
|
29194
29425
|
let sessionDB = null;
|
|
29195
29426
|
let executor = null;
|
|
@@ -29207,7 +29438,6 @@ function compactorExtension(pi) {
|
|
|
29207
29438
|
const getCounters = () => counters;
|
|
29208
29439
|
const runtimeStats = {
|
|
29209
29440
|
bytesReturned: {},
|
|
29210
|
-
bytesIndexed: 0,
|
|
29211
29441
|
bytesSandboxed: 0,
|
|
29212
29442
|
calls: {},
|
|
29213
29443
|
sessionStart: Date.now(),
|
|
@@ -29225,7 +29455,7 @@ function compactorExtension(pi) {
|
|
|
29225
29455
|
} catch {
|
|
29226
29456
|
sessionDB = null;
|
|
29227
29457
|
}
|
|
29228
|
-
executor =
|
|
29458
|
+
executor = null;
|
|
29229
29459
|
};
|
|
29230
29460
|
registerCompactionHooks(pi, {
|
|
29231
29461
|
getSessionDB: () => sessionDB,
|
|
@@ -29254,7 +29484,6 @@ function compactorExtension(pi) {
|
|
|
29254
29484
|
}
|
|
29255
29485
|
}
|
|
29256
29486
|
runtimeStats.bytesReturned = {};
|
|
29257
|
-
runtimeStats.bytesIndexed = 0;
|
|
29258
29487
|
runtimeStats.bytesSandboxed = 0;
|
|
29259
29488
|
runtimeStats.calls = {};
|
|
29260
29489
|
runtimeStats.sessionStart = Date.now();
|
|
@@ -29263,11 +29492,17 @@ function compactorExtension(pi) {
|
|
|
29263
29492
|
autoCompactionState = createAutoCompactionState();
|
|
29264
29493
|
sessionDB?.ensureSession(fullSessionId, projectDir);
|
|
29265
29494
|
if (sessionDB) {
|
|
29495
|
+
const sandboxEnabled = config.sandboxExecution.enabled && config.sandboxExecution.mode !== "off";
|
|
29496
|
+
executor = sandboxEnabled ? new PolyglotExecutor({ hardCapBytes: config.sandboxExecution.outputLimit, projectRoot: projectDir }) : null;
|
|
29266
29497
|
registerCompactorTools(pi, {
|
|
29267
29498
|
sessionDB,
|
|
29268
29499
|
getSessionId: () => currentSessionId,
|
|
29269
29500
|
getBlocks: () => cachedBlocks,
|
|
29270
|
-
getCounters
|
|
29501
|
+
getCounters,
|
|
29502
|
+
sandbox: executor ? {
|
|
29503
|
+
executor,
|
|
29504
|
+
allowedLanguages: config.sandboxExecution.allowedLanguages
|
|
29505
|
+
} : void 0
|
|
29271
29506
|
});
|
|
29272
29507
|
}
|
|
29273
29508
|
registerCommands4(pi, getCommandDeps());
|
|
@@ -29353,21 +29588,11 @@ function compactorExtension(pi) {
|
|
|
29353
29588
|
}
|
|
29354
29589
|
} catch {
|
|
29355
29590
|
}
|
|
29356
|
-
|
|
29357
|
-
|
|
29358
|
-
|
|
29359
|
-
|
|
29360
|
-
|
|
29361
|
-
const { buildAutoInjection: buildAutoInjection2 } = await Promise.resolve().then(() => (init_auto_inject(), auto_inject_exports));
|
|
29362
|
-
const events = sessionDB.getEvents(currentSessionId, { limit: 100 });
|
|
29363
|
-
const autoInjection = buildAutoInjection2(events);
|
|
29364
|
-
if (autoInjection) {
|
|
29365
|
-
debug("auto_injection", { tokens: autoInjection.tokens, length: autoInjection.text.length });
|
|
29366
|
-
}
|
|
29367
|
-
} catch (err) {
|
|
29368
|
-
debug("auto_injection_error", { error: String(err) });
|
|
29369
|
-
}
|
|
29370
|
-
}
|
|
29591
|
+
const continuityEnabled = isSessionContinuityEnabled(config);
|
|
29592
|
+
if (sessionDB && continuityEnabled) {
|
|
29593
|
+
const resumeContext = await buildResumeContextMessage(sessionDB, currentSessionId);
|
|
29594
|
+
debug("resume_snapshot", { injected: !!resumeContext });
|
|
29595
|
+
return resumeContext;
|
|
29371
29596
|
}
|
|
29372
29597
|
});
|
|
29373
29598
|
pi.on("turn_end", async (_event, ctx) => {
|
|
@@ -29423,7 +29648,8 @@ function compactorExtension(pi) {
|
|
|
29423
29648
|
}
|
|
29424
29649
|
});
|
|
29425
29650
|
pi.on("session_before_compact", async (event, _ctx) => {
|
|
29426
|
-
|
|
29651
|
+
const continuityEnabled = isSessionContinuityEnabled(config);
|
|
29652
|
+
if (sessionDB && continuityEnabled) {
|
|
29427
29653
|
const sessionId = currentSessionId;
|
|
29428
29654
|
const events = sessionDB.getEvents(sessionId, { limit: 1e3 });
|
|
29429
29655
|
const stats = sessionDB.getSessionStats(sessionId);
|
|
@@ -29442,12 +29668,18 @@ function compactorExtension(pi) {
|
|
|
29442
29668
|
counters.compactions++;
|
|
29443
29669
|
const compactionEntry = event.compactionEntry;
|
|
29444
29670
|
const tokensBefore = compactionEntry?.tokensBefore ?? 0;
|
|
29671
|
+
let summarized = 0;
|
|
29672
|
+
let kept = 0;
|
|
29673
|
+
let tokensSaved = 0;
|
|
29445
29674
|
if (tokensBefore > 0) {
|
|
29446
29675
|
const charsBefore = tokensBefore * 4;
|
|
29447
|
-
const tokensAfter =
|
|
29676
|
+
const tokensAfter = Math.round(tokensBefore * 0.12);
|
|
29677
|
+
kept = tokensAfter;
|
|
29678
|
+
tokensSaved = tokensBefore - tokensAfter;
|
|
29448
29679
|
const charsKept = tokensAfter * 4;
|
|
29449
29680
|
const messagesSummarized = Math.max(1, Math.round(tokensBefore / 500));
|
|
29450
|
-
|
|
29681
|
+
summarized = messagesSummarized;
|
|
29682
|
+
counters.totalTokensCompacted += tokensSaved;
|
|
29451
29683
|
sessionDB.addCompactionStats(sessionId, charsBefore, charsKept, messagesSummarized);
|
|
29452
29684
|
} else {
|
|
29453
29685
|
try {
|
|
@@ -29457,12 +29689,23 @@ function compactorExtension(pi) {
|
|
|
29457
29689
|
const estTokensAfter = Math.round(estTokensBefore * 0.12);
|
|
29458
29690
|
const charsBefore = estTokensBefore * 4;
|
|
29459
29691
|
const charsKept = estTokensAfter * 4;
|
|
29460
|
-
|
|
29692
|
+
summarized = eventCount;
|
|
29693
|
+
kept = estTokensAfter;
|
|
29694
|
+
tokensSaved = estTokensBefore - estTokensAfter;
|
|
29695
|
+
counters.totalTokensCompacted += tokensSaved;
|
|
29461
29696
|
sessionDB.addCompactionStats(sessionId, charsBefore, charsKept, eventCount);
|
|
29462
29697
|
}
|
|
29463
29698
|
} catch {
|
|
29464
29699
|
}
|
|
29465
29700
|
}
|
|
29701
|
+
const totalEstimated = tokensSaved + kept;
|
|
29702
|
+
emitEvent(pi, UNIPI_EVENTS.COMPACTOR_COMPACTED, {
|
|
29703
|
+
sessionId,
|
|
29704
|
+
summarized,
|
|
29705
|
+
kept,
|
|
29706
|
+
tokensSaved,
|
|
29707
|
+
compressionRatio: kept > 0 ? `${Math.round(totalEstimated / kept)}:1` : "0:1"
|
|
29708
|
+
});
|
|
29466
29709
|
debug("session_compact", { sessionId, tokensBefore, hasCompactionEntry: !!compactionEntry });
|
|
29467
29710
|
}
|
|
29468
29711
|
});
|
|
@@ -29554,30 +29797,10 @@ function compactorExtension(pi) {
|
|
|
29554
29797
|
if (isSandboxTool(tName)) {
|
|
29555
29798
|
runtimeStats.bytesSandboxed += responseBytes;
|
|
29556
29799
|
}
|
|
29557
|
-
if (isIndexTool(tName)) {
|
|
29558
|
-
runtimeStats.bytesIndexed += responseBytes;
|
|
29559
|
-
}
|
|
29560
29800
|
}
|
|
29561
29801
|
} catch {
|
|
29562
29802
|
}
|
|
29563
29803
|
const toolName = event.toolName ?? "";
|
|
29564
|
-
const td = config.toolDisplay;
|
|
29565
|
-
const toolConfig = {
|
|
29566
|
-
readOutputMode: td?.mode,
|
|
29567
|
-
searchOutputMode: td?.mode,
|
|
29568
|
-
bashOutputMode: td?.mode,
|
|
29569
|
-
previewLines: 20,
|
|
29570
|
-
bashCollapsedLines: 5,
|
|
29571
|
-
showTruncationHints: true
|
|
29572
|
-
};
|
|
29573
|
-
try {
|
|
29574
|
-
const { applyToolDisplayOverride: applyToolDisplayOverride2 } = await Promise.resolve().then(() => (init_tool_overrides(), tool_overrides_exports));
|
|
29575
|
-
const override = applyToolDisplayOverride2(toolName, event, toolConfig);
|
|
29576
|
-
if (override !== void 0) {
|
|
29577
|
-
return override;
|
|
29578
|
-
}
|
|
29579
|
-
} catch {
|
|
29580
|
-
}
|
|
29581
29804
|
const diffToolNames = ["edit", "Edit", "write", "Write"];
|
|
29582
29805
|
if (diffToolNames.includes(toolName)) {
|
|
29583
29806
|
try {
|
|
@@ -30886,14 +31109,6 @@ var FooterRenderer = class _FooterRenderer {
|
|
|
30886
31109
|
init_core();
|
|
30887
31110
|
function subscribeToEvents(pi, registry3) {
|
|
30888
31111
|
const unsubscribers = [];
|
|
30889
|
-
unsubscribers.push(
|
|
30890
|
-
pi.events.on(UNIPI_EVENTS.COMPACTOR_STATS_UPDATED, (event) => {
|
|
30891
|
-
try {
|
|
30892
|
-
registry3.updateData("compactor", event);
|
|
30893
|
-
} catch {
|
|
30894
|
-
}
|
|
30895
|
-
})
|
|
30896
|
-
);
|
|
30897
31112
|
unsubscribers.push(
|
|
30898
31113
|
pi.events.on(UNIPI_EVENTS.COMPACTOR_COMPACTED, (event) => {
|
|
30899
31114
|
try {
|
|
@@ -32865,7 +33080,7 @@ import { Key as Key6, matchesKey as matchesKey14, truncateToWidth as truncateToW
|
|
|
32865
33080
|
// packages/updater/src/readme.ts
|
|
32866
33081
|
init_core();
|
|
32867
33082
|
init_core();
|
|
32868
|
-
import { dirname as
|
|
33083
|
+
import { dirname as dirname27 } from "node:path";
|
|
32869
33084
|
import { fileURLToPath as fileURLToPath12 } from "node:url";
|
|
32870
33085
|
import { existsSync as existsSync39, readFileSync as readFileSync34 } from "fs";
|
|
32871
33086
|
import { join as join38 } from "path";
|
|
@@ -32892,7 +33107,7 @@ var PACKAGE_MAP = {
|
|
|
32892
33107
|
updater: MODULES.UPDATER
|
|
32893
33108
|
};
|
|
32894
33109
|
function resolveUnipiRoot() {
|
|
32895
|
-
const dir =
|
|
33110
|
+
const dir = dirname27(fileURLToPath12(import.meta.url));
|
|
32896
33111
|
const root = findPackageRoot(dir, "@pi-unipi/unipi");
|
|
32897
33112
|
return root ?? join38(dir, "..");
|
|
32898
33113
|
}
|
|
@@ -33229,7 +33444,7 @@ import { Key as Key7, matchesKey as matchesKey15, truncateToWidth as truncateToW
|
|
|
33229
33444
|
// packages/updater/src/changelog.ts
|
|
33230
33445
|
init_core();
|
|
33231
33446
|
import { existsSync as existsSync40, readFileSync as readFileSync36 } from "fs";
|
|
33232
|
-
import { dirname as
|
|
33447
|
+
import { dirname as dirname28, join as join39 } from "node:path";
|
|
33233
33448
|
import { fileURLToPath as fileURLToPath13 } from "node:url";
|
|
33234
33449
|
|
|
33235
33450
|
// packages/updater/src/version.ts
|
|
@@ -33254,7 +33469,7 @@ function isNewerVersion(latest, current) {
|
|
|
33254
33469
|
// packages/updater/src/changelog.ts
|
|
33255
33470
|
function resolveChangelogPath() {
|
|
33256
33471
|
try {
|
|
33257
|
-
const dir =
|
|
33472
|
+
const dir = dirname28(fileURLToPath13(import.meta.url));
|
|
33258
33473
|
const root = findPackageRoot(dir, "@pi-unipi/unipi");
|
|
33259
33474
|
if (root) {
|
|
33260
33475
|
const packaged = join39(root, "CHANGELOG.md");
|
|
@@ -33515,7 +33730,7 @@ function renderChangelogOverlay() {
|
|
|
33515
33730
|
// packages/updater/src/settings.ts
|
|
33516
33731
|
init_core();
|
|
33517
33732
|
import { readFileSync as readFileSync37, writeFileSync as writeFileSync26, mkdirSync as mkdirSync22, existsSync as existsSync42 } from "fs";
|
|
33518
|
-
import { dirname as
|
|
33733
|
+
import { dirname as dirname29, join as join40 } from "path";
|
|
33519
33734
|
import { homedir as homedir24 } from "os";
|
|
33520
33735
|
var DEFAULT_CONFIG6 = {
|
|
33521
33736
|
checkIntervalMs: 36e5,
|
|
@@ -33547,7 +33762,7 @@ function loadConfig5() {
|
|
|
33547
33762
|
}
|
|
33548
33763
|
function saveConfig4(config) {
|
|
33549
33764
|
const configPath = resolveConfigPath2();
|
|
33550
|
-
const dir =
|
|
33765
|
+
const dir = dirname29(configPath);
|
|
33551
33766
|
mkdirSync22(dir, { recursive: true });
|
|
33552
33767
|
writeFileSync26(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
33553
33768
|
}
|
|
@@ -33783,7 +33998,7 @@ init_core();
|
|
|
33783
33998
|
// packages/updater/src/cache.ts
|
|
33784
33999
|
init_core();
|
|
33785
34000
|
import { readFileSync as readFileSync38, writeFileSync as writeFileSync27, mkdirSync as mkdirSync23, existsSync as existsSync43 } from "fs";
|
|
33786
|
-
import { dirname as
|
|
34001
|
+
import { dirname as dirname30, join as join41 } from "path";
|
|
33787
34002
|
import { homedir as homedir25 } from "os";
|
|
33788
34003
|
function resolveCachePath() {
|
|
33789
34004
|
const base = UPDATER_DIRS.CACHE.replace("~", homedir25());
|
|
@@ -33805,7 +34020,7 @@ function readLastCheck() {
|
|
|
33805
34020
|
}
|
|
33806
34021
|
function writeLastCheck(cache) {
|
|
33807
34022
|
const cachePath = resolveCachePath();
|
|
33808
|
-
const dir =
|
|
34023
|
+
const dir = dirname30(cachePath);
|
|
33809
34024
|
mkdirSync23(dir, { recursive: true });
|
|
33810
34025
|
writeFileSync27(cachePath, JSON.stringify(cache, null, 2) + "\n", "utf-8");
|
|
33811
34026
|
}
|
|
@@ -34215,8 +34430,8 @@ init_core();
|
|
|
34215
34430
|
import { Key as Key10 } from "@earendil-works/pi-tui";
|
|
34216
34431
|
|
|
34217
34432
|
// packages/input-shortcuts/src/registers.ts
|
|
34218
|
-
import { existsSync as existsSync44, mkdirSync as mkdirSync24, readFileSync as readFileSync39, renameSync as
|
|
34219
|
-
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";
|
|
34220
34435
|
|
|
34221
34436
|
// packages/input-shortcuts/src/types.ts
|
|
34222
34437
|
var DEFAULT_CONFIG7 = {
|
|
@@ -34286,13 +34501,13 @@ var RegisterStore = class {
|
|
|
34286
34501
|
/** Atomic write: write to .tmp then rename. */
|
|
34287
34502
|
save() {
|
|
34288
34503
|
try {
|
|
34289
|
-
const dir =
|
|
34504
|
+
const dir = dirname31(this.filePath);
|
|
34290
34505
|
if (!existsSync44(dir)) {
|
|
34291
34506
|
mkdirSync24(dir, { recursive: true });
|
|
34292
34507
|
}
|
|
34293
34508
|
const tmpPath = this.filePath + ".tmp";
|
|
34294
34509
|
writeFileSync28(tmpPath, JSON.stringify(this.data, null, 2), "utf-8");
|
|
34295
|
-
|
|
34510
|
+
renameSync8(tmpPath, this.filePath);
|
|
34296
34511
|
} catch {
|
|
34297
34512
|
}
|
|
34298
34513
|
}
|
|
@@ -34513,8 +34728,8 @@ var ChordOverlay = class extends Container2 {
|
|
|
34513
34728
|
|
|
34514
34729
|
// packages/input-shortcuts/src/settings-overlay.ts
|
|
34515
34730
|
import { SettingsList as SettingsList3 } from "@earendil-works/pi-tui";
|
|
34516
|
-
import { existsSync as existsSync45, mkdirSync as mkdirSync25, readFileSync as readFileSync40, renameSync as
|
|
34517
|
-
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";
|
|
34518
34733
|
var ALT_KEY_OPTIONS = [
|
|
34519
34734
|
"alt+a",
|
|
34520
34735
|
"alt+b",
|
|
@@ -34563,13 +34778,13 @@ function loadConfig6(baseDir) {
|
|
|
34563
34778
|
function saveConfig5(config, baseDir) {
|
|
34564
34779
|
const filePath = baseDir ? join43(baseDir, CONFIG_FILE) : CONFIG_FILE;
|
|
34565
34780
|
try {
|
|
34566
|
-
const dir =
|
|
34781
|
+
const dir = dirname32(filePath);
|
|
34567
34782
|
if (!existsSync45(dir)) {
|
|
34568
34783
|
mkdirSync25(dir, { recursive: true });
|
|
34569
34784
|
}
|
|
34570
34785
|
const tmpPath = filePath + ".tmp";
|
|
34571
34786
|
writeFileSync29(tmpPath, JSON.stringify(config, null, 2), "utf-8");
|
|
34572
|
-
|
|
34787
|
+
renameSync9(tmpPath, filePath);
|
|
34573
34788
|
} catch {
|
|
34574
34789
|
}
|
|
34575
34790
|
}
|
|
@@ -34997,7 +35212,7 @@ import { Type as Type8 } from "typebox";
|
|
|
34997
35212
|
// packages/cocoindex/bridge.ts
|
|
34998
35213
|
init_core();
|
|
34999
35214
|
import { execFileSync as execFileSync3, spawn as spawn4 } from "node:child_process";
|
|
35000
|
-
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";
|
|
35001
35216
|
import { homedir as homedir26 } from "node:os";
|
|
35002
35217
|
import { join as join44 } from "node:path";
|
|
35003
35218
|
var DEFAULT_PIPELINE_DIR = ".unipi/cocoindex";
|
|
@@ -35073,7 +35288,7 @@ function resolveCocoindexBin() {
|
|
|
35073
35288
|
if (existsSync46(uvToolBin)) return uvToolBin;
|
|
35074
35289
|
const miseRoot = join44(homedir26(), ".local", "share", "mise", "installs", "python");
|
|
35075
35290
|
try {
|
|
35076
|
-
const versions =
|
|
35291
|
+
const versions = readdirSync14(miseRoot).sort().reverse();
|
|
35077
35292
|
for (const ver of versions) {
|
|
35078
35293
|
const binPath = join44(miseRoot, ver, "bin", "cocoindex");
|
|
35079
35294
|
if (existsSync46(binPath)) return binPath;
|
|
@@ -35136,7 +35351,7 @@ async function indexProject(projectDir) {
|
|
|
35136
35351
|
}
|
|
35137
35352
|
const start = Date.now();
|
|
35138
35353
|
const cocoindexBin = resolveCocoindexBin();
|
|
35139
|
-
return new Promise((
|
|
35354
|
+
return new Promise((resolve14) => {
|
|
35140
35355
|
const proc = spawn4(cocoindexBin, ["update", "main.py"], {
|
|
35141
35356
|
cwd: pipelineDir,
|
|
35142
35357
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -35166,9 +35381,9 @@ async function indexProject(projectDir) {
|
|
|
35166
35381
|
const durationMs = Date.now() - start;
|
|
35167
35382
|
const chunksProcessed = parseChunksProcessed(stdout);
|
|
35168
35383
|
if (code === 0) {
|
|
35169
|
-
|
|
35384
|
+
resolve14({ success: true, chunksProcessed, durationMs });
|
|
35170
35385
|
} else {
|
|
35171
|
-
|
|
35386
|
+
resolve14({
|
|
35172
35387
|
success: false,
|
|
35173
35388
|
chunksProcessed,
|
|
35174
35389
|
durationMs,
|
|
@@ -35179,7 +35394,7 @@ async function indexProject(projectDir) {
|
|
|
35179
35394
|
proc.on("error", (err) => {
|
|
35180
35395
|
settled = true;
|
|
35181
35396
|
clearTimeout(timer);
|
|
35182
|
-
|
|
35397
|
+
resolve14({
|
|
35183
35398
|
success: false,
|
|
35184
35399
|
chunksProcessed: 0,
|
|
35185
35400
|
durationMs: Date.now() - start,
|
|
@@ -35244,9 +35459,9 @@ async function status(projectDir) {
|
|
|
35244
35459
|
const lancedbPath = join44(pipelineDir, ".lancedb");
|
|
35245
35460
|
if (existsSync46(lancedbPath)) {
|
|
35246
35461
|
try {
|
|
35247
|
-
const stat =
|
|
35462
|
+
const stat = statSync9(lancedbPath);
|
|
35248
35463
|
lastRun = stat.mtime.toISOString();
|
|
35249
|
-
const files =
|
|
35464
|
+
const files = readdirSync14(lancedbPath, { recursive: true });
|
|
35250
35465
|
docCount = files.filter((f) => f.endsWith(".lance")).length;
|
|
35251
35466
|
} catch {
|
|
35252
35467
|
}
|
|
@@ -35906,7 +36121,7 @@ function buildUvInstallerFallback(shell) {
|
|
|
35906
36121
|
];
|
|
35907
36122
|
}
|
|
35908
36123
|
function runStep(step) {
|
|
35909
|
-
return new Promise((
|
|
36124
|
+
return new Promise((resolve14) => {
|
|
35910
36125
|
const proc = spawn5(step.command, step.args ?? [], {
|
|
35911
36126
|
stdio: ["ignore", "pipe", "pipe"],
|
|
35912
36127
|
env: installerEnv()
|
|
@@ -35929,12 +36144,12 @@ Timed out after ${step.timeoutMs ?? DEFAULT_STEP_TIMEOUT_MS}ms.`;
|
|
|
35929
36144
|
proc.on("close", (code, signal) => {
|
|
35930
36145
|
settled = true;
|
|
35931
36146
|
clearTimeout(timeout);
|
|
35932
|
-
|
|
36147
|
+
resolve14({ ok: code === 0, stdout, stderr, exitCode: code, signal });
|
|
35933
36148
|
});
|
|
35934
36149
|
proc.on("error", (err) => {
|
|
35935
36150
|
settled = true;
|
|
35936
36151
|
clearTimeout(timeout);
|
|
35937
|
-
|
|
36152
|
+
resolve14({ ok: false, stdout, stderr: stderr || err.message });
|
|
35938
36153
|
});
|
|
35939
36154
|
});
|
|
35940
36155
|
}
|
|
@@ -36136,7 +36351,7 @@ function cocoindexExtension(pi) {
|
|
|
36136
36351
|
|
|
36137
36352
|
// packages/image/src/index.ts
|
|
36138
36353
|
init_core();
|
|
36139
|
-
import { dirname as
|
|
36354
|
+
import { dirname as dirname34 } from "node:path";
|
|
36140
36355
|
import { fileURLToPath as fileURLToPath14 } from "node:url";
|
|
36141
36356
|
|
|
36142
36357
|
// packages/image/src/commands.ts
|
|
@@ -37890,7 +38105,7 @@ function currentSessionModel(ctx) {
|
|
|
37890
38105
|
}
|
|
37891
38106
|
|
|
37892
38107
|
// packages/image/src/index.ts
|
|
37893
|
-
var VERSION11 = getPackageVersion(
|
|
38108
|
+
var VERSION11 = getPackageVersion(dirname34(fileURLToPath14(import.meta.url)));
|
|
37894
38109
|
function getInfoRegistry6() {
|
|
37895
38110
|
return globalThis.__unipi_info_registry;
|
|
37896
38111
|
}
|