@askexenow/exe-os 0.9.38 → 0.9.39
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/dist/bin/backfill-conversations.js +34 -7
- package/dist/bin/backfill-responses.js +34 -7
- package/dist/bin/backfill-vectors.js +34 -7
- package/dist/bin/cleanup-stale-review-tasks.js +35 -8
- package/dist/bin/cli.js +72 -42
- package/dist/bin/exe-agent.js +11 -3
- package/dist/bin/exe-assign.js +34 -7
- package/dist/bin/exe-boot.js +48 -18
- package/dist/bin/exe-call.js +132 -340
- package/dist/bin/exe-dispatch.js +34 -7
- package/dist/bin/exe-doctor.js +37 -10
- package/dist/bin/exe-export-behaviors.js +36 -9
- package/dist/bin/exe-forget.js +34 -7
- package/dist/bin/exe-gateway.js +40 -12
- package/dist/bin/exe-heartbeat.js +35 -8
- package/dist/bin/exe-kill.js +34 -7
- package/dist/bin/exe-launch-agent.js +285 -1079
- package/dist/bin/exe-new-employee.js +29 -10
- package/dist/bin/exe-pending-messages.js +34 -7
- package/dist/bin/exe-pending-notifications.js +34 -7
- package/dist/bin/exe-pending-reviews.js +34 -7
- package/dist/bin/exe-rename.js +41 -13
- package/dist/bin/exe-review.js +34 -7
- package/dist/bin/exe-search.js +36 -9
- package/dist/bin/exe-session-cleanup.js +36 -9
- package/dist/bin/exe-start-codex.js +36 -9
- package/dist/bin/exe-start-opencode.js +36 -9
- package/dist/bin/exe-status.js +35 -8
- package/dist/bin/exe-team.js +34 -7
- package/dist/bin/git-sweep.js +34 -7
- package/dist/bin/graph-backfill.js +34 -7
- package/dist/bin/graph-export.js +34 -7
- package/dist/bin/install.js +2 -1
- package/dist/bin/intercom-check.js +36 -9
- package/dist/bin/scan-tasks.js +34 -7
- package/dist/bin/setup.js +18 -17
- package/dist/bin/shard-migrate.js +34 -7
- package/dist/gateway/index.js +38 -10
- package/dist/hooks/bug-report-worker.js +38 -10
- package/dist/hooks/codex-stop-task-finalizer.js +36 -9
- package/dist/hooks/commit-complete.js +34 -7
- package/dist/hooks/error-recall.js +36 -9
- package/dist/hooks/ingest.js +36 -8
- package/dist/hooks/instructions-loaded.js +42 -10
- package/dist/hooks/notification.js +34 -7
- package/dist/hooks/post-compact.js +34 -7
- package/dist/hooks/post-tool-combined.js +37 -10
- package/dist/hooks/pre-compact.js +35 -8
- package/dist/hooks/pre-tool-use.js +36 -8
- package/dist/hooks/prompt-submit.js +41 -13
- package/dist/hooks/session-end.js +35 -8
- package/dist/hooks/session-start.js +47 -14
- package/dist/hooks/stop.js +35 -8
- package/dist/hooks/subagent-stop.js +34 -7
- package/dist/hooks/summary-worker.js +43 -16
- package/dist/index.js +36 -8
- package/dist/lib/consolidation.js +2 -1
- package/dist/lib/employee-templates.js +2 -1
- package/dist/lib/employees.js +2 -1
- package/dist/lib/exe-daemon.js +136 -36
- package/dist/lib/hybrid-search.js +36 -9
- package/dist/lib/identity.js +8 -3
- package/dist/lib/schedules.js +34 -7
- package/dist/lib/store.js +34 -7
- package/dist/mcp/server.js +133 -33
- package/dist/mcp/tools/create-task.js +10 -4
- package/dist/runtime/index.js +34 -7
- package/dist/tui/App.js +40 -11
- package/package.json +1 -1
package/dist/lib/exe-daemon.js
CHANGED
|
@@ -727,7 +727,8 @@ function isMultiInstance(agentName, employees) {
|
|
|
727
727
|
return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
|
|
728
728
|
}
|
|
729
729
|
function addEmployee(employees, employee) {
|
|
730
|
-
const
|
|
730
|
+
const { systemPrompt: _legacyPrompt, ...rest } = employee;
|
|
731
|
+
const normalized = { ...rest, name: employee.name.toLowerCase() };
|
|
731
732
|
if (employees.some((e) => e.name.toLowerCase() === normalized.name)) {
|
|
732
733
|
throw new Error(`Employee '${normalized.name}' already exists`);
|
|
733
734
|
}
|
|
@@ -3646,7 +3647,7 @@ __export(shard_manager_exports, {
|
|
|
3646
3647
|
shardExists: () => shardExists
|
|
3647
3648
|
});
|
|
3648
3649
|
import path9 from "path";
|
|
3649
|
-
import { existsSync as existsSync9, mkdirSync as mkdirSync2, readdirSync } from "fs";
|
|
3650
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync2, readdirSync, renameSync as renameSync3, statSync as statSync2 } from "fs";
|
|
3650
3651
|
import { createClient as createClient2 } from "@libsql/client";
|
|
3651
3652
|
function initShardManager(encryptionKey) {
|
|
3652
3653
|
_encryptionKey = encryptionKey;
|
|
@@ -3668,7 +3669,7 @@ function getShardClient(projectName) {
|
|
|
3668
3669
|
if (!_encryptionKey) {
|
|
3669
3670
|
throw new Error("Shard manager not initialized. Call initShardManager() first.");
|
|
3670
3671
|
}
|
|
3671
|
-
const safeName = projectName
|
|
3672
|
+
const safeName = safeShardName(projectName);
|
|
3672
3673
|
if (!safeName || safeName === "unknown") {
|
|
3673
3674
|
throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
|
|
3674
3675
|
}
|
|
@@ -3690,9 +3691,12 @@ function getShardClient(projectName) {
|
|
|
3690
3691
|
return client;
|
|
3691
3692
|
}
|
|
3692
3693
|
function shardExists(projectName) {
|
|
3693
|
-
const safeName = projectName
|
|
3694
|
+
const safeName = safeShardName(projectName);
|
|
3694
3695
|
return existsSync9(path9.join(SHARDS_DIR, `${safeName}.db`));
|
|
3695
3696
|
}
|
|
3697
|
+
function safeShardName(projectName) {
|
|
3698
|
+
return projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
3699
|
+
}
|
|
3696
3700
|
function listShards() {
|
|
3697
3701
|
if (!existsSync9(SHARDS_DIR)) return [];
|
|
3698
3702
|
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
@@ -3786,7 +3790,8 @@ async function ensureShardSchema(client) {
|
|
|
3786
3790
|
"ALTER TABLE memories ADD COLUMN token_cost REAL",
|
|
3787
3791
|
"ALTER TABLE memories ADD COLUMN audience TEXT",
|
|
3788
3792
|
"ALTER TABLE memories ADD COLUMN language_type TEXT",
|
|
3789
|
-
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
|
|
3793
|
+
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT",
|
|
3794
|
+
"ALTER TABLE memories ADD COLUMN deleted_at TEXT"
|
|
3790
3795
|
]) {
|
|
3791
3796
|
try {
|
|
3792
3797
|
await client.execute(col);
|
|
@@ -3882,9 +3887,32 @@ async function ensureShardSchema(client) {
|
|
|
3882
3887
|
}
|
|
3883
3888
|
}
|
|
3884
3889
|
async function getReadyShardClient(projectName) {
|
|
3885
|
-
const
|
|
3886
|
-
|
|
3887
|
-
|
|
3890
|
+
const safeName = safeShardName(projectName);
|
|
3891
|
+
let client = getShardClient(projectName);
|
|
3892
|
+
try {
|
|
3893
|
+
await ensureShardSchema(client);
|
|
3894
|
+
return client;
|
|
3895
|
+
} catch (err) {
|
|
3896
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
3897
|
+
if (!/SQLITE_NOTADB|file is not a database/i.test(message)) throw err;
|
|
3898
|
+
client.close();
|
|
3899
|
+
_shards.delete(safeName);
|
|
3900
|
+
_shardLastAccess.delete(safeName);
|
|
3901
|
+
const dbPath = path9.join(SHARDS_DIR, `${safeName}.db`);
|
|
3902
|
+
if (existsSync9(dbPath)) {
|
|
3903
|
+
const stat = statSync2(dbPath);
|
|
3904
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
3905
|
+
const archivedPath = path9.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
|
|
3906
|
+
renameSync3(dbPath, archivedPath);
|
|
3907
|
+
process.stderr.write(
|
|
3908
|
+
`[shard-manager] Archived unreadable shard ${safeName}: ${archivedPath} (${stat.size} bytes, mtime ${stat.mtime.toISOString()})
|
|
3909
|
+
`
|
|
3910
|
+
);
|
|
3911
|
+
}
|
|
3912
|
+
client = getShardClient(projectName);
|
|
3913
|
+
await ensureShardSchema(client);
|
|
3914
|
+
return client;
|
|
3915
|
+
}
|
|
3888
3916
|
}
|
|
3889
3917
|
function evictLRU() {
|
|
3890
3918
|
let oldest = null;
|
|
@@ -5178,7 +5206,7 @@ __export(memory_queue_exports, {
|
|
|
5178
5206
|
enqueueMemory: () => enqueueMemory,
|
|
5179
5207
|
queueDepth: () => queueDepth
|
|
5180
5208
|
});
|
|
5181
|
-
import { appendFileSync, readFileSync as readFileSync7, renameSync as
|
|
5209
|
+
import { appendFileSync, readFileSync as readFileSync7, renameSync as renameSync4, unlinkSync as unlinkSync3, existsSync as existsSync11, statSync as statSync3 } from "fs";
|
|
5182
5210
|
import path11 from "path";
|
|
5183
5211
|
function enqueueMemory(entry) {
|
|
5184
5212
|
appendFileSync(QUEUE_PATH, JSON.stringify(entry) + "\n");
|
|
@@ -5194,13 +5222,13 @@ function drainQueue() {
|
|
|
5194
5222
|
}
|
|
5195
5223
|
if (!existsSync11(QUEUE_PATH)) return entries;
|
|
5196
5224
|
try {
|
|
5197
|
-
const stat =
|
|
5225
|
+
const stat = statSync3(QUEUE_PATH);
|
|
5198
5226
|
if (stat.size === 0) return entries;
|
|
5199
5227
|
} catch {
|
|
5200
5228
|
return entries;
|
|
5201
5229
|
}
|
|
5202
5230
|
try {
|
|
5203
|
-
|
|
5231
|
+
renameSync4(QUEUE_PATH, PROCESSING_PATH);
|
|
5204
5232
|
} catch {
|
|
5205
5233
|
return entries;
|
|
5206
5234
|
}
|
|
@@ -5661,7 +5689,7 @@ __export(file_grep_exports, {
|
|
|
5661
5689
|
grepProjectFiles: () => grepProjectFiles
|
|
5662
5690
|
});
|
|
5663
5691
|
import { execSync as execSync4 } from "child_process";
|
|
5664
|
-
import { readFileSync as readFileSync8, readdirSync as readdirSync2, statSync as
|
|
5692
|
+
import { readFileSync as readFileSync8, readdirSync as readdirSync2, statSync as statSync4, existsSync as existsSync13 } from "fs";
|
|
5665
5693
|
import path14 from "path";
|
|
5666
5694
|
import crypto3 from "crypto";
|
|
5667
5695
|
function hasRipgrep() {
|
|
@@ -5778,7 +5806,7 @@ function grepWithNodeFs(pattern, projectRoot, patterns) {
|
|
|
5778
5806
|
for (const filePath of files.slice(0, MAX_FILES)) {
|
|
5779
5807
|
const absPath = path14.join(projectRoot, filePath);
|
|
5780
5808
|
try {
|
|
5781
|
-
const stat =
|
|
5809
|
+
const stat = statSync4(absPath);
|
|
5782
5810
|
if (stat.size > MAX_FILE_SIZE) continue;
|
|
5783
5811
|
const content = readFileSync8(absPath, "utf8");
|
|
5784
5812
|
const lines = content.split("\n");
|
|
@@ -7349,6 +7377,12 @@ var init_active_agent = __esm({
|
|
|
7349
7377
|
|
|
7350
7378
|
// src/mcp/tools/recall-my-memory.ts
|
|
7351
7379
|
import { z } from "zod";
|
|
7380
|
+
function formatMemoryBody(rawText, maxChars) {
|
|
7381
|
+
if (rawText.length <= maxChars) return rawText;
|
|
7382
|
+
const marker = ` \u2026 [truncated; +${rawText.length - maxChars} chars \u2014 re-call with max_chars up to 20000 for more]`;
|
|
7383
|
+
const sliceLen = Math.max(0, maxChars - marker.length);
|
|
7384
|
+
return `${rawText.slice(0, sliceLen)}${marker}`;
|
|
7385
|
+
}
|
|
7352
7386
|
function formatSourceLine(record) {
|
|
7353
7387
|
const doc2 = record.document_metadata;
|
|
7354
7388
|
if (!doc2) return "";
|
|
@@ -7374,6 +7408,7 @@ function registerRecallMyMemory(server) {
|
|
|
7374
7408
|
has_error: z.boolean().optional().describe("Filter for error-containing memories"),
|
|
7375
7409
|
tool_name: z.string().optional().describe("Filter by tool name (Bash, Write, etc)"),
|
|
7376
7410
|
limit: z.coerce.number().optional().default(10).describe("Max results to return"),
|
|
7411
|
+
max_chars: z.coerce.number().int().min(100).max(2e4).optional().default(2e3).describe("Max characters to include per memory result. Use a higher value for canonical plans/runbooks."),
|
|
7377
7412
|
since: z.string().optional().describe("ISO 8601 timestamp \u2014 only return memories at or after this time"),
|
|
7378
7413
|
include_archived: z.boolean().optional().default(false).describe(
|
|
7379
7414
|
"Include deprecated (archived) memories alongside active ones. Default false."
|
|
@@ -7395,6 +7430,7 @@ function registerRecallMyMemory(server) {
|
|
|
7395
7430
|
has_error,
|
|
7396
7431
|
tool_name,
|
|
7397
7432
|
limit,
|
|
7433
|
+
max_chars,
|
|
7398
7434
|
since,
|
|
7399
7435
|
include_archived,
|
|
7400
7436
|
workspace_id,
|
|
@@ -7440,7 +7476,7 @@ function registerRecallMyMemory(server) {
|
|
|
7440
7476
|
}
|
|
7441
7477
|
const formatted = results.map((r) => {
|
|
7442
7478
|
const header = `[${r.timestamp}] ${r.tool_name} (${r.project_name})${r.has_error ? " [ERROR]" : ""}`;
|
|
7443
|
-
const body = r.raw_text
|
|
7479
|
+
const body = formatMemoryBody(r.raw_text, max_chars ?? 2e3);
|
|
7444
7480
|
const parts = [header];
|
|
7445
7481
|
if (r.source_path) {
|
|
7446
7482
|
const typeTag = r.source_type && r.source_type !== "text" ? ` [${r.source_type}]` : "";
|
|
@@ -7485,6 +7521,12 @@ var init_recall_my_memory = __esm({
|
|
|
7485
7521
|
|
|
7486
7522
|
// src/mcp/tools/ask-team-memory.ts
|
|
7487
7523
|
import { z as z2 } from "zod";
|
|
7524
|
+
function formatMemoryBody2(rawText, maxChars) {
|
|
7525
|
+
if (rawText.length <= maxChars) return rawText;
|
|
7526
|
+
const marker = ` \u2026 [truncated; +${rawText.length - maxChars} chars \u2014 re-call with max_chars up to 20000 for more]`;
|
|
7527
|
+
const sliceLen = Math.max(0, maxChars - marker.length);
|
|
7528
|
+
return `${rawText.slice(0, sliceLen)}${marker}`;
|
|
7529
|
+
}
|
|
7488
7530
|
function canSeeRaw(queryingRole, targetRole) {
|
|
7489
7531
|
if (queryingRole === "COO") return true;
|
|
7490
7532
|
if (queryingRole === "CTO" && [
|
|
@@ -7509,6 +7551,7 @@ function registerAskTeamMemory(server) {
|
|
|
7509
7551
|
query: z2.string().describe("What to search for"),
|
|
7510
7552
|
project_name: z2.string().optional().describe("Filter by project name"),
|
|
7511
7553
|
limit: z2.coerce.number().optional().default(10).describe("Max results to return"),
|
|
7554
|
+
max_chars: z2.coerce.number().int().min(100).max(2e4).optional().default(2e3).describe("Max characters to include per memory result. Use a higher value for canonical plans/runbooks."),
|
|
7512
7555
|
since: z2.string().optional().describe("ISO 8601 timestamp \u2014 only return memories at or after this time"),
|
|
7513
7556
|
include_archived: z2.boolean().optional().default(false).describe(
|
|
7514
7557
|
"Include deprecated (archived) memories alongside active ones. Default false."
|
|
@@ -7519,7 +7562,7 @@ function registerAskTeamMemory(server) {
|
|
|
7519
7562
|
retrieval_mode: z2.enum(RETRIEVAL_MODES).optional().default("all").describe(`Typed retrieval mode. Raw visibility is still ACL-gated. ${formatRetrievalModes()}`)
|
|
7520
7563
|
}
|
|
7521
7564
|
},
|
|
7522
|
-
async ({ team_member, query, project_name, limit, since, include_archived, include_raw: _include_raw, retrieval_mode }) => {
|
|
7565
|
+
async ({ team_member, query, project_name, limit, max_chars, since, include_archived, include_raw: _include_raw, retrieval_mode }) => {
|
|
7523
7566
|
try {
|
|
7524
7567
|
const { agentId: queryingAgentId, agentRole: queryingAgentRole } = getActiveAgent();
|
|
7525
7568
|
const employees = loadEmployeesSync();
|
|
@@ -7552,7 +7595,7 @@ function registerAskTeamMemory(server) {
|
|
|
7552
7595
|
}
|
|
7553
7596
|
const formatted = results.map(
|
|
7554
7597
|
(r) => `[${r.timestamp}] ${r.tool_name} (${r.project_name})${r.has_error ? " [ERROR]" : ""}
|
|
7555
|
-
${r.raw_text
|
|
7598
|
+
${formatMemoryBody2(r.raw_text, max_chars ?? 2e3)}`
|
|
7556
7599
|
).join("\n\n---\n\n");
|
|
7557
7600
|
return {
|
|
7558
7601
|
content: [
|
|
@@ -7830,8 +7873,8 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
7830
7873
|
}
|
|
7831
7874
|
function getCacheAgeMs() {
|
|
7832
7875
|
try {
|
|
7833
|
-
const { statSync:
|
|
7834
|
-
const s =
|
|
7876
|
+
const { statSync: statSync8 } = __require("fs");
|
|
7877
|
+
const s = statSync8(CACHE_PATH);
|
|
7835
7878
|
return Date.now() - s.mtimeMs;
|
|
7836
7879
|
} catch {
|
|
7837
7880
|
return Infinity;
|
|
@@ -8395,7 +8438,8 @@ var init_wiki_client = __esm({
|
|
|
8395
8438
|
// src/lib/unified-search.ts
|
|
8396
8439
|
function truncate(text3, max) {
|
|
8397
8440
|
if (text3.length <= max) return text3;
|
|
8398
|
-
|
|
8441
|
+
const marker = ` \u2026 [truncated; +${text3.length - max} chars]`;
|
|
8442
|
+
return text3.slice(0, Math.max(0, max - marker.length)) + marker;
|
|
8399
8443
|
}
|
|
8400
8444
|
async function searchMemories2(query, agentId, limit) {
|
|
8401
8445
|
const { hybridSearch: hybridSearch2 } = await Promise.resolve().then(() => (init_hybrid_search(), hybrid_search_exports));
|
|
@@ -8631,6 +8675,12 @@ var init_search_everything = __esm({
|
|
|
8631
8675
|
|
|
8632
8676
|
// src/mcp/tools/get-session-context.ts
|
|
8633
8677
|
import { z as z6 } from "zod";
|
|
8678
|
+
function formatMemoryBody3(rawText, maxChars) {
|
|
8679
|
+
if (rawText.length <= maxChars) return rawText;
|
|
8680
|
+
const marker = ` \u2026 [truncated; +${rawText.length - maxChars} chars \u2014 re-call with max_chars up to 20000 for more]`;
|
|
8681
|
+
const sliceLen = Math.max(0, maxChars - marker.length);
|
|
8682
|
+
return `${rawText.slice(0, sliceLen)}${marker}`;
|
|
8683
|
+
}
|
|
8634
8684
|
function registerGetSessionContext(server) {
|
|
8635
8685
|
server.registerTool(
|
|
8636
8686
|
"get_session_context",
|
|
@@ -8642,10 +8692,11 @@ function registerGetSessionContext(server) {
|
|
|
8642
8692
|
target_timestamp: z6.string().describe(
|
|
8643
8693
|
"ISO 8601 timestamp to center the context window around"
|
|
8644
8694
|
),
|
|
8645
|
-
window_size: z6.number().optional().default(3).describe("Number of memories before and after the target")
|
|
8695
|
+
window_size: z6.number().optional().default(3).describe("Number of memories before and after the target"),
|
|
8696
|
+
max_chars: z6.coerce.number().int().min(100).max(2e4).optional().default(2e3).describe("Max characters to include per memory result.")
|
|
8646
8697
|
}
|
|
8647
8698
|
},
|
|
8648
|
-
async ({ session_id, target_timestamp, window_size }) => {
|
|
8699
|
+
async ({ session_id, target_timestamp, window_size, max_chars }) => {
|
|
8649
8700
|
const client = getClient();
|
|
8650
8701
|
const result = await client.execute({
|
|
8651
8702
|
sql: `SELECT id, agent_id, agent_role, session_id, timestamp,
|
|
@@ -8691,7 +8742,7 @@ function registerGetSessionContext(server) {
|
|
|
8691
8742
|
const windowMemories = sorted.slice(start, end);
|
|
8692
8743
|
const formatted = windowMemories.map(
|
|
8693
8744
|
(r) => `[${r.timestamp}] ${r.tool_name} (${r.project_name})${r.has_error ? " [ERROR]" : ""}
|
|
8694
|
-
${r.raw_text
|
|
8745
|
+
${formatMemoryBody3(r.raw_text, max_chars ?? 2e3)}`
|
|
8695
8746
|
).join("\n\n---\n\n");
|
|
8696
8747
|
return {
|
|
8697
8748
|
content: [
|
|
@@ -9837,7 +9888,7 @@ __export(intercom_queue_exports, {
|
|
|
9837
9888
|
queueIntercom: () => queueIntercom,
|
|
9838
9889
|
readQueue: () => readQueue
|
|
9839
9890
|
});
|
|
9840
|
-
import { readFileSync as readFileSync13, writeFileSync as writeFileSync10, renameSync as
|
|
9891
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync10, renameSync as renameSync5, existsSync as existsSync17, mkdirSync as mkdirSync6 } from "fs";
|
|
9841
9892
|
import path21 from "path";
|
|
9842
9893
|
import os9 from "os";
|
|
9843
9894
|
function ensureDir() {
|
|
@@ -9856,7 +9907,7 @@ function writeQueue(queue) {
|
|
|
9856
9907
|
ensureDir();
|
|
9857
9908
|
const tmp = `${QUEUE_PATH2}.tmp`;
|
|
9858
9909
|
writeFileSync10(tmp, JSON.stringify(queue, null, 2));
|
|
9859
|
-
|
|
9910
|
+
renameSync5(tmp, QUEUE_PATH2);
|
|
9860
9911
|
}
|
|
9861
9912
|
function queueIntercom(targetSession, reason) {
|
|
9862
9913
|
const queue = readQueue();
|
|
@@ -12987,6 +13038,9 @@ function ensureDir2() {
|
|
|
12987
13038
|
function identityPath(agentId) {
|
|
12988
13039
|
return path28.join(IDENTITY_DIR2, `${agentId}.md`);
|
|
12989
13040
|
}
|
|
13041
|
+
function sanitizeIdentityBody(body) {
|
|
13042
|
+
return body.replace(/<!--[\s\S]*?-->/g, "").trim();
|
|
13043
|
+
}
|
|
12990
13044
|
function parseFrontmatter(raw) {
|
|
12991
13045
|
const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
12992
13046
|
if (!match) {
|
|
@@ -12999,11 +13053,11 @@ function parseFrontmatter(raw) {
|
|
|
12999
13053
|
created_by: "system",
|
|
13000
13054
|
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
13001
13055
|
},
|
|
13002
|
-
body: raw
|
|
13056
|
+
body: sanitizeIdentityBody(raw)
|
|
13003
13057
|
};
|
|
13004
13058
|
}
|
|
13005
13059
|
const yamlStr = match[1];
|
|
13006
|
-
const body = match[2]
|
|
13060
|
+
const body = sanitizeIdentityBody(match[2]);
|
|
13007
13061
|
const fm = {};
|
|
13008
13062
|
for (const line of yamlStr.split("\n")) {
|
|
13009
13063
|
const kv = line.match(/^(\w+):\s*(.+)$/);
|
|
@@ -13068,7 +13122,9 @@ function listIdentities() {
|
|
|
13068
13122
|
const summary = lines[0]?.trim().slice(0, 120) ?? identity.frontmatter.title;
|
|
13069
13123
|
results.push({
|
|
13070
13124
|
agentId,
|
|
13071
|
-
title
|
|
13125
|
+
// User-facing/team-facing title only. `frontmatter.role` is internal
|
|
13126
|
+
// routing metadata and must not leak as an external title.
|
|
13127
|
+
title: identity.frontmatter.title,
|
|
13072
13128
|
summary
|
|
13073
13129
|
});
|
|
13074
13130
|
}
|
|
@@ -13859,6 +13915,40 @@ var init_list_tasks = __esm({
|
|
|
13859
13915
|
|
|
13860
13916
|
// src/mcp/tools/get-task.ts
|
|
13861
13917
|
import { z as z13 } from "zod";
|
|
13918
|
+
async function diagnoseMissingTask(client, identifier) {
|
|
13919
|
+
const shortUuid = /^[a-f0-9]{7,12}$/i.test(identifier);
|
|
13920
|
+
const args = [];
|
|
13921
|
+
const clauses = [];
|
|
13922
|
+
if (shortUuid) {
|
|
13923
|
+
clauses.push("id LIKE ?");
|
|
13924
|
+
args.push(`${identifier}%`);
|
|
13925
|
+
}
|
|
13926
|
+
clauses.push("task_file LIKE ?");
|
|
13927
|
+
args.push(`%${identifier}%`);
|
|
13928
|
+
clauses.push("title LIKE ?");
|
|
13929
|
+
args.push(`%${identifier}%`);
|
|
13930
|
+
const result = await client.execute({
|
|
13931
|
+
sql: `SELECT id, title, status, assigned_to, project_name, session_scope, task_file
|
|
13932
|
+
FROM tasks
|
|
13933
|
+
WHERE ${clauses.map((c) => `(${c})`).join(" OR ")}
|
|
13934
|
+
ORDER BY updated_at DESC
|
|
13935
|
+
LIMIT 10`,
|
|
13936
|
+
args
|
|
13937
|
+
});
|
|
13938
|
+
if (result.rows.length === 0) return null;
|
|
13939
|
+
const scoped = sessionScopeFilter();
|
|
13940
|
+
const scopeNote = scoped.args.length > 0 ? `Current session scope appears to be ${String(scoped.args[0])}. get_task is session-scoped by default.` : "No current session scope detected.";
|
|
13941
|
+
const matches = result.rows.map((r) => {
|
|
13942
|
+
const id = String(r.id);
|
|
13943
|
+
return `- ${id.slice(0, 8)} ${String(r.title)} [${String(r.status)}] assigned_to=${String(r.assigned_to)} project=${String(r.project_name)} session_scope=${String(r.session_scope ?? "NULL")}`;
|
|
13944
|
+
}).join("\n");
|
|
13945
|
+
return `Task not found in the current scoped lookup, but similar task rows exist. ${scopeNote}
|
|
13946
|
+
|
|
13947
|
+
Matches across all scopes/statuses:
|
|
13948
|
+
${matches}
|
|
13949
|
+
|
|
13950
|
+
Use the full UUID from the matching row, switch to the owning coordinator session, or list tasks with the correct project/session scope.`;
|
|
13951
|
+
}
|
|
13862
13952
|
function registerGetTask(server) {
|
|
13863
13953
|
server.registerTool(
|
|
13864
13954
|
"get_task",
|
|
@@ -13871,7 +13961,16 @@ function registerGetTask(server) {
|
|
|
13871
13961
|
},
|
|
13872
13962
|
async ({ task_id }) => {
|
|
13873
13963
|
const client = getClient();
|
|
13874
|
-
|
|
13964
|
+
let row;
|
|
13965
|
+
try {
|
|
13966
|
+
row = await resolveTask(client, task_id);
|
|
13967
|
+
} catch (err) {
|
|
13968
|
+
const fallback = await diagnoseMissingTask(client, task_id);
|
|
13969
|
+
if (fallback) {
|
|
13970
|
+
return { content: [{ type: "text", text: fallback }], isError: true };
|
|
13971
|
+
}
|
|
13972
|
+
throw err;
|
|
13973
|
+
}
|
|
13875
13974
|
const contextText = row.context ? String(row.context) : "";
|
|
13876
13975
|
const hasEmbeddedMandatoryReminder = contextText.includes('update_task with status "done"') || contextText.includes("update_task(done)");
|
|
13877
13976
|
const lines = [
|
|
@@ -13967,6 +14066,7 @@ var init_get_task = __esm({
|
|
|
13967
14066
|
"use strict";
|
|
13968
14067
|
init_tasks();
|
|
13969
14068
|
init_database();
|
|
14069
|
+
init_task_scope();
|
|
13970
14070
|
init_employees();
|
|
13971
14071
|
}
|
|
13972
14072
|
});
|
|
@@ -19513,7 +19613,7 @@ var init_import_orchestration = __esm({
|
|
|
19513
19613
|
|
|
19514
19614
|
// src/mcp/tools/load-skill.ts
|
|
19515
19615
|
import { z as z50 } from "zod";
|
|
19516
|
-
import { readFileSync as readFileSync23, readdirSync as readdirSync9, statSync as
|
|
19616
|
+
import { readFileSync as readFileSync23, readdirSync as readdirSync9, statSync as statSync5 } from "fs";
|
|
19517
19617
|
import path35 from "path";
|
|
19518
19618
|
import { homedir as homedir2 } from "os";
|
|
19519
19619
|
function listAvailableSkills() {
|
|
@@ -19522,9 +19622,9 @@ function listAvailableSkills() {
|
|
|
19522
19622
|
return entries.filter((entry) => {
|
|
19523
19623
|
try {
|
|
19524
19624
|
const entryPath = path35.join(SKILLS_DIR, entry);
|
|
19525
|
-
if (!
|
|
19625
|
+
if (!statSync5(entryPath).isDirectory()) return false;
|
|
19526
19626
|
const skillFile = path35.join(entryPath, "SKILL.md");
|
|
19527
|
-
|
|
19627
|
+
statSync5(skillFile);
|
|
19528
19628
|
return true;
|
|
19529
19629
|
} catch {
|
|
19530
19630
|
return false;
|
|
@@ -22954,7 +23054,7 @@ __export(db_backup_exports, {
|
|
|
22954
23054
|
listBackups: () => listBackups,
|
|
22955
23055
|
rotateBackups: () => rotateBackups
|
|
22956
23056
|
});
|
|
22957
|
-
import { copyFileSync as copyFileSync2, existsSync as existsSync33, mkdirSync as mkdirSync15, readdirSync as readdirSync12, unlinkSync as unlinkSync10, statSync as
|
|
23057
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync33, mkdirSync as mkdirSync15, readdirSync as readdirSync12, unlinkSync as unlinkSync10, statSync as statSync6 } from "fs";
|
|
22958
23058
|
import path41 from "path";
|
|
22959
23059
|
function findActiveDb() {
|
|
22960
23060
|
for (const name of DB_NAMES) {
|
|
@@ -22998,7 +23098,7 @@ function rotateBackups(keepDays = DEFAULT_KEEP_DAYS) {
|
|
|
22998
23098
|
if (!file.endsWith(".db") && !file.endsWith(".db-wal") && !file.endsWith(".db-shm")) continue;
|
|
22999
23099
|
const filePath = path41.join(BACKUP_DIR, file);
|
|
23000
23100
|
try {
|
|
23001
|
-
const stat =
|
|
23101
|
+
const stat = statSync6(filePath);
|
|
23002
23102
|
if (stat.mtimeMs < cutoff) {
|
|
23003
23103
|
unlinkSync10(filePath);
|
|
23004
23104
|
deleted++;
|
|
@@ -23016,7 +23116,7 @@ function listBackups() {
|
|
|
23016
23116
|
const files = readdirSync12(BACKUP_DIR).filter((f) => f.endsWith(".db") && !f.endsWith("-wal") && !f.endsWith("-shm"));
|
|
23017
23117
|
return files.map((name) => {
|
|
23018
23118
|
const p = path41.join(BACKUP_DIR, name);
|
|
23019
|
-
const stat =
|
|
23119
|
+
const stat = statSync6(p);
|
|
23020
23120
|
return { path: p, name, size: stat.size, date: stat.mtime };
|
|
23021
23121
|
}).sort((a, b) => b.date.getTime() - a.date.getTime());
|
|
23022
23122
|
} catch {
|
|
@@ -23982,7 +24082,7 @@ __export(cloud_sync_exports, {
|
|
|
23982
24082
|
pushToPostgres: () => pushToPostgres,
|
|
23983
24083
|
recordRosterDeletion: () => recordRosterDeletion
|
|
23984
24084
|
});
|
|
23985
|
-
import { readFileSync as readFileSync29, writeFileSync as writeFileSync21, existsSync as existsSync36, readdirSync as readdirSync13, mkdirSync as mkdirSync17, appendFileSync as appendFileSync3, unlinkSync as unlinkSync12, openSync as openSync2, closeSync as closeSync2, statSync as
|
|
24085
|
+
import { readFileSync as readFileSync29, writeFileSync as writeFileSync21, existsSync as existsSync36, readdirSync as readdirSync13, mkdirSync as mkdirSync17, appendFileSync as appendFileSync3, unlinkSync as unlinkSync12, openSync as openSync2, closeSync as closeSync2, statSync as statSync7 } from "fs";
|
|
23986
24086
|
import crypto18 from "crypto";
|
|
23987
24087
|
import path44 from "path";
|
|
23988
24088
|
import { homedir as homedir6 } from "os";
|
|
@@ -24474,7 +24574,7 @@ async function cloudSync(config2) {
|
|
|
24474
24574
|
const { getLatestBackup: getLatestBackup2 } = await Promise.resolve().then(() => (init_db_backup(), db_backup_exports));
|
|
24475
24575
|
const latestBackup = getLatestBackup2();
|
|
24476
24576
|
if (latestBackup) {
|
|
24477
|
-
const backupSize =
|
|
24577
|
+
const backupSize = statSync7(latestBackup).size;
|
|
24478
24578
|
const MAX_CLOUD_BACKUP_BYTES = 50 * 1024 * 1024;
|
|
24479
24579
|
if (backupSize <= MAX_CLOUD_BACKUP_BYTES) {
|
|
24480
24580
|
const backupData = readFileSync29(latestBackup);
|
|
@@ -3238,7 +3238,7 @@ __export(shard_manager_exports, {
|
|
|
3238
3238
|
shardExists: () => shardExists
|
|
3239
3239
|
});
|
|
3240
3240
|
import path7 from "path";
|
|
3241
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync } from "fs";
|
|
3241
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync, renameSync as renameSync3, statSync as statSync2 } from "fs";
|
|
3242
3242
|
import { createClient as createClient2 } from "@libsql/client";
|
|
3243
3243
|
function initShardManager(encryptionKey) {
|
|
3244
3244
|
_encryptionKey = encryptionKey;
|
|
@@ -3260,7 +3260,7 @@ function getShardClient(projectName) {
|
|
|
3260
3260
|
if (!_encryptionKey) {
|
|
3261
3261
|
throw new Error("Shard manager not initialized. Call initShardManager() first.");
|
|
3262
3262
|
}
|
|
3263
|
-
const safeName = projectName
|
|
3263
|
+
const safeName = safeShardName(projectName);
|
|
3264
3264
|
if (!safeName || safeName === "unknown") {
|
|
3265
3265
|
throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
|
|
3266
3266
|
}
|
|
@@ -3282,9 +3282,12 @@ function getShardClient(projectName) {
|
|
|
3282
3282
|
return client;
|
|
3283
3283
|
}
|
|
3284
3284
|
function shardExists(projectName) {
|
|
3285
|
-
const safeName = projectName
|
|
3285
|
+
const safeName = safeShardName(projectName);
|
|
3286
3286
|
return existsSync7(path7.join(SHARDS_DIR, `${safeName}.db`));
|
|
3287
3287
|
}
|
|
3288
|
+
function safeShardName(projectName) {
|
|
3289
|
+
return projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
3290
|
+
}
|
|
3288
3291
|
function listShards() {
|
|
3289
3292
|
if (!existsSync7(SHARDS_DIR)) return [];
|
|
3290
3293
|
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
@@ -3378,7 +3381,8 @@ async function ensureShardSchema(client) {
|
|
|
3378
3381
|
"ALTER TABLE memories ADD COLUMN token_cost REAL",
|
|
3379
3382
|
"ALTER TABLE memories ADD COLUMN audience TEXT",
|
|
3380
3383
|
"ALTER TABLE memories ADD COLUMN language_type TEXT",
|
|
3381
|
-
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
|
|
3384
|
+
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT",
|
|
3385
|
+
"ALTER TABLE memories ADD COLUMN deleted_at TEXT"
|
|
3382
3386
|
]) {
|
|
3383
3387
|
try {
|
|
3384
3388
|
await client.execute(col);
|
|
@@ -3474,9 +3478,32 @@ async function ensureShardSchema(client) {
|
|
|
3474
3478
|
}
|
|
3475
3479
|
}
|
|
3476
3480
|
async function getReadyShardClient(projectName) {
|
|
3477
|
-
const
|
|
3478
|
-
|
|
3479
|
-
|
|
3481
|
+
const safeName = safeShardName(projectName);
|
|
3482
|
+
let client = getShardClient(projectName);
|
|
3483
|
+
try {
|
|
3484
|
+
await ensureShardSchema(client);
|
|
3485
|
+
return client;
|
|
3486
|
+
} catch (err) {
|
|
3487
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
3488
|
+
if (!/SQLITE_NOTADB|file is not a database/i.test(message)) throw err;
|
|
3489
|
+
client.close();
|
|
3490
|
+
_shards.delete(safeName);
|
|
3491
|
+
_shardLastAccess.delete(safeName);
|
|
3492
|
+
const dbPath = path7.join(SHARDS_DIR, `${safeName}.db`);
|
|
3493
|
+
if (existsSync7(dbPath)) {
|
|
3494
|
+
const stat = statSync2(dbPath);
|
|
3495
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
3496
|
+
const archivedPath = path7.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
|
|
3497
|
+
renameSync3(dbPath, archivedPath);
|
|
3498
|
+
process.stderr.write(
|
|
3499
|
+
`[shard-manager] Archived unreadable shard ${safeName}: ${archivedPath} (${stat.size} bytes, mtime ${stat.mtime.toISOString()})
|
|
3500
|
+
`
|
|
3501
|
+
);
|
|
3502
|
+
}
|
|
3503
|
+
client = getShardClient(projectName);
|
|
3504
|
+
await ensureShardSchema(client);
|
|
3505
|
+
return client;
|
|
3506
|
+
}
|
|
3480
3507
|
}
|
|
3481
3508
|
function evictLRU() {
|
|
3482
3509
|
let oldest = null;
|
|
@@ -4751,7 +4778,7 @@ __export(file_grep_exports, {
|
|
|
4751
4778
|
grepProjectFiles: () => grepProjectFiles
|
|
4752
4779
|
});
|
|
4753
4780
|
import { execSync as execSync4 } from "child_process";
|
|
4754
|
-
import { readFileSync as readFileSync5, readdirSync as readdirSync2, statSync as
|
|
4781
|
+
import { readFileSync as readFileSync5, readdirSync as readdirSync2, statSync as statSync3, existsSync as existsSync9 } from "fs";
|
|
4755
4782
|
import path10 from "path";
|
|
4756
4783
|
import crypto2 from "crypto";
|
|
4757
4784
|
function hasRipgrep() {
|
|
@@ -4868,7 +4895,7 @@ function grepWithNodeFs(pattern, projectRoot, patterns) {
|
|
|
4868
4895
|
for (const filePath of files.slice(0, MAX_FILES)) {
|
|
4869
4896
|
const absPath = path10.join(projectRoot, filePath);
|
|
4870
4897
|
try {
|
|
4871
|
-
const stat =
|
|
4898
|
+
const stat = statSync3(absPath);
|
|
4872
4899
|
if (stat.size > MAX_FILE_SIZE) continue;
|
|
4873
4900
|
const content = readFileSync5(absPath, "utf8");
|
|
4874
4901
|
const lines = content.split("\n");
|
package/dist/lib/identity.js
CHANGED
|
@@ -169,6 +169,9 @@ function ensureDir() {
|
|
|
169
169
|
function identityPath(agentId) {
|
|
170
170
|
return path4.join(IDENTITY_DIR2, `${agentId}.md`);
|
|
171
171
|
}
|
|
172
|
+
function sanitizeIdentityBody(body) {
|
|
173
|
+
return body.replace(/<!--[\s\S]*?-->/g, "").trim();
|
|
174
|
+
}
|
|
172
175
|
function parseFrontmatter(raw) {
|
|
173
176
|
const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
174
177
|
if (!match) {
|
|
@@ -181,11 +184,11 @@ function parseFrontmatter(raw) {
|
|
|
181
184
|
created_by: "system",
|
|
182
185
|
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
183
186
|
},
|
|
184
|
-
body: raw
|
|
187
|
+
body: sanitizeIdentityBody(raw)
|
|
185
188
|
};
|
|
186
189
|
}
|
|
187
190
|
const yamlStr = match[1];
|
|
188
|
-
const body = match[2]
|
|
191
|
+
const body = sanitizeIdentityBody(match[2]);
|
|
189
192
|
const fm = {};
|
|
190
193
|
for (const line of yamlStr.split("\n")) {
|
|
191
194
|
const kv = line.match(/^(\w+):\s*(.+)$/);
|
|
@@ -250,7 +253,9 @@ function listIdentities() {
|
|
|
250
253
|
const summary = lines[0]?.trim().slice(0, 120) ?? identity.frontmatter.title;
|
|
251
254
|
results.push({
|
|
252
255
|
agentId,
|
|
253
|
-
title
|
|
256
|
+
// User-facing/team-facing title only. `frontmatter.role` is internal
|
|
257
|
+
// routing metadata and must not leak as an external title.
|
|
258
|
+
title: identity.frontmatter.title,
|
|
254
259
|
summary
|
|
255
260
|
});
|
|
256
261
|
}
|
package/dist/lib/schedules.js
CHANGED
|
@@ -2600,7 +2600,7 @@ __export(shard_manager_exports, {
|
|
|
2600
2600
|
shardExists: () => shardExists
|
|
2601
2601
|
});
|
|
2602
2602
|
import path7 from "path";
|
|
2603
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync } from "fs";
|
|
2603
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync, renameSync as renameSync3, statSync as statSync2 } from "fs";
|
|
2604
2604
|
import { createClient as createClient2 } from "@libsql/client";
|
|
2605
2605
|
function initShardManager(encryptionKey) {
|
|
2606
2606
|
_encryptionKey = encryptionKey;
|
|
@@ -2622,7 +2622,7 @@ function getShardClient(projectName) {
|
|
|
2622
2622
|
if (!_encryptionKey) {
|
|
2623
2623
|
throw new Error("Shard manager not initialized. Call initShardManager() first.");
|
|
2624
2624
|
}
|
|
2625
|
-
const safeName = projectName
|
|
2625
|
+
const safeName = safeShardName(projectName);
|
|
2626
2626
|
if (!safeName || safeName === "unknown") {
|
|
2627
2627
|
throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
|
|
2628
2628
|
}
|
|
@@ -2644,9 +2644,12 @@ function getShardClient(projectName) {
|
|
|
2644
2644
|
return client;
|
|
2645
2645
|
}
|
|
2646
2646
|
function shardExists(projectName) {
|
|
2647
|
-
const safeName = projectName
|
|
2647
|
+
const safeName = safeShardName(projectName);
|
|
2648
2648
|
return existsSync7(path7.join(SHARDS_DIR, `${safeName}.db`));
|
|
2649
2649
|
}
|
|
2650
|
+
function safeShardName(projectName) {
|
|
2651
|
+
return projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2652
|
+
}
|
|
2650
2653
|
function listShards() {
|
|
2651
2654
|
if (!existsSync7(SHARDS_DIR)) return [];
|
|
2652
2655
|
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
@@ -2740,7 +2743,8 @@ async function ensureShardSchema(client) {
|
|
|
2740
2743
|
"ALTER TABLE memories ADD COLUMN token_cost REAL",
|
|
2741
2744
|
"ALTER TABLE memories ADD COLUMN audience TEXT",
|
|
2742
2745
|
"ALTER TABLE memories ADD COLUMN language_type TEXT",
|
|
2743
|
-
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
|
|
2746
|
+
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT",
|
|
2747
|
+
"ALTER TABLE memories ADD COLUMN deleted_at TEXT"
|
|
2744
2748
|
]) {
|
|
2745
2749
|
try {
|
|
2746
2750
|
await client.execute(col);
|
|
@@ -2836,9 +2840,32 @@ async function ensureShardSchema(client) {
|
|
|
2836
2840
|
}
|
|
2837
2841
|
}
|
|
2838
2842
|
async function getReadyShardClient(projectName) {
|
|
2839
|
-
const
|
|
2840
|
-
|
|
2841
|
-
|
|
2843
|
+
const safeName = safeShardName(projectName);
|
|
2844
|
+
let client = getShardClient(projectName);
|
|
2845
|
+
try {
|
|
2846
|
+
await ensureShardSchema(client);
|
|
2847
|
+
return client;
|
|
2848
|
+
} catch (err) {
|
|
2849
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2850
|
+
if (!/SQLITE_NOTADB|file is not a database/i.test(message)) throw err;
|
|
2851
|
+
client.close();
|
|
2852
|
+
_shards.delete(safeName);
|
|
2853
|
+
_shardLastAccess.delete(safeName);
|
|
2854
|
+
const dbPath = path7.join(SHARDS_DIR, `${safeName}.db`);
|
|
2855
|
+
if (existsSync7(dbPath)) {
|
|
2856
|
+
const stat = statSync2(dbPath);
|
|
2857
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
2858
|
+
const archivedPath = path7.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
|
|
2859
|
+
renameSync3(dbPath, archivedPath);
|
|
2860
|
+
process.stderr.write(
|
|
2861
|
+
`[shard-manager] Archived unreadable shard ${safeName}: ${archivedPath} (${stat.size} bytes, mtime ${stat.mtime.toISOString()})
|
|
2862
|
+
`
|
|
2863
|
+
);
|
|
2864
|
+
}
|
|
2865
|
+
client = getShardClient(projectName);
|
|
2866
|
+
await ensureShardSchema(client);
|
|
2867
|
+
return client;
|
|
2868
|
+
}
|
|
2842
2869
|
}
|
|
2843
2870
|
function evictLRU() {
|
|
2844
2871
|
let oldest = null;
|