chat-recall 0.6.4 → 0.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -3
- package/dist/auto-update.d.ts +12 -0
- package/dist/auto-update.d.ts.map +1 -1
- package/dist/auto-update.js +115 -9
- package/dist/auto-update.js.map +1 -1
- package/dist/board-hooks.d.ts +56 -0
- package/dist/board-hooks.d.ts.map +1 -0
- package/dist/board-hooks.js +144 -0
- package/dist/board-hooks.js.map +1 -0
- package/dist/cli.js +1508 -358
- package/dist/cli.js.map +1 -1
- package/dist/mcp-relay.js +1 -1
- package/dist/mcp.js +295 -42
- package/dist/star-nudge.d.ts +13 -0
- package/dist/star-nudge.d.ts.map +1 -0
- package/dist/star-nudge.js +83 -0
- package/dist/star-nudge.js.map +1 -0
- package/dist/watch.js +117 -61
- package/hooks/chat_recall_guard_hook.sh +54 -0
- package/package.json +1 -1
- package/skills/chat-recall/SKILL.md +2 -1
- package/skills/chat-recall-memory/SKILL.md +18 -2
package/dist/mcp-relay.js
CHANGED
|
@@ -118,7 +118,7 @@ function daemonEnabled() {
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
// src/mcp-relay.ts
|
|
121
|
-
var VERSION = true ? "0.6.
|
|
121
|
+
var VERSION = true ? "0.6.6" : "0.0.0";
|
|
122
122
|
var SERVER_URL = new URL("./mcp.js", import.meta.url);
|
|
123
123
|
var SERVER_PATH = fileURLToPath(SERVER_URL);
|
|
124
124
|
var START_TIMEOUT_MS = 15e3;
|
package/dist/mcp.js
CHANGED
|
@@ -15259,12 +15259,12 @@ function extractEntities(text, context = {}) {
|
|
|
15259
15259
|
if (chosen && looksLikeStrictTool(chosen) && looksLikeStrictTool(rejected)) {
|
|
15260
15260
|
const c = canonTool(chosen), r = canonTool(rejected);
|
|
15261
15261
|
if (projectName)
|
|
15262
|
-
addTriple(projectName, "chose", c,
|
|
15263
|
-
addTriple(projectName || "project", "rejected", r,
|
|
15264
|
-
addTriple(c, "chosen_over", r,
|
|
15262
|
+
addTriple(projectName, "chose", c, DECISION_GUESS_CONFIDENCE);
|
|
15263
|
+
addTriple(projectName || "project", "rejected", r, DECISION_GUESS_CONFIDENCE);
|
|
15264
|
+
addTriple(c, "chosen_over", r, DECISION_GUESS_CONFIDENCE);
|
|
15265
15265
|
}
|
|
15266
15266
|
} else if (chosen && looksLikeDecisionObject(chosen) && projectName) {
|
|
15267
|
-
addTriple(projectName, "chose", canonTool(chosen),
|
|
15267
|
+
addTriple(projectName, "chose", canonTool(chosen), DECISION_GUESS_CONFIDENCE);
|
|
15268
15268
|
}
|
|
15269
15269
|
}
|
|
15270
15270
|
}
|
|
@@ -15301,7 +15301,7 @@ function extractEntities(text, context = {}) {
|
|
|
15301
15301
|
}
|
|
15302
15302
|
return triples;
|
|
15303
15303
|
}
|
|
15304
|
-
var KNOWN_TOOLS, AMBIGUOUS_TOOLS, toolContextRe, TOOL_PATTERNS, DECISION_PATTERNS2, DECISION_OBJECT_STOPWORDS, KNOWN_TOOL_NAMES, CANONICAL_TOOL, canonTool, PROJECT_PATH_PATTERN, PEOPLE_PATTERNS, NOT_PEOPLE;
|
|
15304
|
+
var KNOWN_TOOLS, AMBIGUOUS_TOOLS, toolContextRe, TOOL_PATTERNS, DECISION_PATTERNS2, DECISION_OBJECT_STOPWORDS, KNOWN_TOOL_NAMES, CANONICAL_TOOL, canonTool, DECISION_GUESS_CONFIDENCE, PROJECT_PATH_PATTERN, PEOPLE_PATTERNS, NOT_PEOPLE;
|
|
15305
15305
|
var init_entity_extractor = __esm({
|
|
15306
15306
|
"../engine/dist/core/entity-extractor.js"() {
|
|
15307
15307
|
"use strict";
|
|
@@ -15522,6 +15522,7 @@ var init_entity_extractor = __esm({
|
|
|
15522
15522
|
"nextjs": "next.js"
|
|
15523
15523
|
};
|
|
15524
15524
|
canonTool = (n) => CANONICAL_TOOL[n.toLowerCase()] ?? n;
|
|
15525
|
+
DECISION_GUESS_CONFIDENCE = 0.6;
|
|
15525
15526
|
PROJECT_PATH_PATTERN = /\/(?:home|Users)\/\w+\/(?:code|projects|work|dev|src)\/(?:\w+\/)?([a-zA-Z][a-zA-Z0-9_-]{1,40})/g;
|
|
15526
15527
|
PEOPLE_PATTERNS = [
|
|
15527
15528
|
/\b(?:my name is|I'm|I am)\s+([A-Z][a-z]{1,15}(?:\s+[A-Z][a-z]{1,15})?)/g,
|
|
@@ -19727,7 +19728,7 @@ var init_http = __esm({
|
|
|
19727
19728
|
CLI_VERSION = JSON.parse(readFileSync35(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
19728
19729
|
} catch {
|
|
19729
19730
|
try {
|
|
19730
|
-
if (true) CLI_VERSION = "0.6.
|
|
19731
|
+
if (true) CLI_VERSION = "0.6.6";
|
|
19731
19732
|
} catch {
|
|
19732
19733
|
}
|
|
19733
19734
|
}
|
|
@@ -20247,7 +20248,7 @@ var init_telemetry = __esm({
|
|
|
20247
20248
|
init_sync_client();
|
|
20248
20249
|
cliVersion2 = () => {
|
|
20249
20250
|
try {
|
|
20250
|
-
return true ? "0.6.
|
|
20251
|
+
return true ? "0.6.6" : "dev";
|
|
20251
20252
|
} catch {
|
|
20252
20253
|
return "dev";
|
|
20253
20254
|
}
|
|
@@ -20397,12 +20398,16 @@ var init_server_probe = __esm({
|
|
|
20397
20398
|
// src/auto-update.ts
|
|
20398
20399
|
var auto_update_exports = {};
|
|
20399
20400
|
__export(auto_update_exports, {
|
|
20401
|
+
clearUpdateFailures: () => clearUpdateFailures,
|
|
20400
20402
|
compareVersions: () => compareVersions,
|
|
20401
20403
|
executeAutoUpdate: () => executeAutoUpdate,
|
|
20404
|
+
hasGivenUpOn: () => hasGivenUpOn,
|
|
20402
20405
|
installedVersion: () => installedVersion,
|
|
20403
20406
|
isAutoUpdateEnabled: () => isAutoUpdateEnabled,
|
|
20404
20407
|
newerOf: () => newerOf,
|
|
20408
|
+
noteUpdateFailure: () => noteUpdateFailure,
|
|
20405
20409
|
planAutoUpdate: () => planAutoUpdate,
|
|
20410
|
+
readUpdateState: () => readUpdateState,
|
|
20406
20411
|
runAutoUpdate: () => runAutoUpdate,
|
|
20407
20412
|
runningPrefix: () => runningPrefix,
|
|
20408
20413
|
sweepStaleStaging: () => sweepStaleStaging,
|
|
@@ -20411,9 +20416,9 @@ __export(auto_update_exports, {
|
|
|
20411
20416
|
import { execSync as execSync4 } from "node:child_process";
|
|
20412
20417
|
import { readFileSync as readFileSync36 } from "node:fs";
|
|
20413
20418
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
20414
|
-
import { writeFileSync as writeFileSync9, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync31, statSync as statSync40 } from "node:fs";
|
|
20419
|
+
import { writeFileSync as writeFileSync9, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync31, statSync as statSync40, mkdirSync as mkdirSync12 } from "node:fs";
|
|
20415
20420
|
import { join as join47, dirname as dirname19, sep as sep3 } from "node:path";
|
|
20416
|
-
import { tmpdir as tmpdir3 } from "node:os";
|
|
20421
|
+
import { tmpdir as tmpdir3, homedir as homedir17 } from "node:os";
|
|
20417
20422
|
import { createHash as createHash10 } from "node:crypto";
|
|
20418
20423
|
function compareVersions(a, b) {
|
|
20419
20424
|
const pa = String(a).split("-")[0].split(".").map((n) => parseInt(n, 10) || 0);
|
|
@@ -20527,16 +20532,25 @@ function runningPrefix(moduleUrl = import.meta.url) {
|
|
|
20527
20532
|
const beforeNodeModules = here.slice(0, at);
|
|
20528
20533
|
return beforeNodeModules.endsWith(`${sep3}lib`) ? beforeNodeModules.slice(0, -4) : beforeNodeModules;
|
|
20529
20534
|
}
|
|
20535
|
+
function npmInstall(cmd) {
|
|
20536
|
+
try {
|
|
20537
|
+
execSync4(cmd, { stdio: ["ignore", "ignore", "pipe"] });
|
|
20538
|
+
} catch (e) {
|
|
20539
|
+
const err = e;
|
|
20540
|
+
const detail = String(err.stderr ?? "").trim().split("\n").filter((l) => l.trim() && !/^npm (notice|warn)\b/i.test(l)).slice(-4).join(" | ").slice(0, 400);
|
|
20541
|
+
throw new Error(detail ? `${err.message ?? "install failed"} \u2014 ${detail}` : err.message ?? "install failed");
|
|
20542
|
+
}
|
|
20543
|
+
}
|
|
20530
20544
|
function realInstall(tgz) {
|
|
20531
20545
|
const prefix = runningPrefix();
|
|
20532
20546
|
if (prefix) {
|
|
20533
|
-
|
|
20547
|
+
npmInstall(`npm install -g --prefix "${prefix}" "${tgz}"`);
|
|
20534
20548
|
return;
|
|
20535
20549
|
}
|
|
20536
20550
|
try {
|
|
20537
|
-
|
|
20551
|
+
npmInstall(`npm install -g "${tgz}"`);
|
|
20538
20552
|
} catch {
|
|
20539
|
-
|
|
20553
|
+
npmInstall(`npm install -g --prefix "${process.env.HOME}/.local" "${tgz}"`);
|
|
20540
20554
|
}
|
|
20541
20555
|
}
|
|
20542
20556
|
function realRestart(platform2) {
|
|
@@ -20544,6 +20558,37 @@ function realRestart(platform2) {
|
|
|
20544
20558
|
else if (platform2 === "darwin") execSync4("launchctl kickstart -k gui/$(id -u)/com.chat-recall.watch", { stdio: "ignore", shell: "/bin/bash" });
|
|
20545
20559
|
else if (platform2 === "win32") execSync4("schtasks /End /TN chat-recall-watch & schtasks /Run /TN chat-recall-watch", { stdio: "ignore" });
|
|
20546
20560
|
}
|
|
20561
|
+
function updateStatePath() {
|
|
20562
|
+
const dir = process.env.CHAT_RECALL_DATA_DIR || join47(homedir17(), ".chat-recall");
|
|
20563
|
+
return join47(dir, "auto-update-state.json");
|
|
20564
|
+
}
|
|
20565
|
+
function readUpdateState() {
|
|
20566
|
+
try {
|
|
20567
|
+
return JSON.parse(readFileSync36(updateStatePath(), "utf8"));
|
|
20568
|
+
} catch {
|
|
20569
|
+
return {};
|
|
20570
|
+
}
|
|
20571
|
+
}
|
|
20572
|
+
function writeUpdateState(st) {
|
|
20573
|
+
try {
|
|
20574
|
+
const p = updateStatePath();
|
|
20575
|
+
mkdirSync12(dirname19(p), { recursive: true });
|
|
20576
|
+
writeFileSync9(p, JSON.stringify(st), "utf8");
|
|
20577
|
+
} catch {
|
|
20578
|
+
}
|
|
20579
|
+
}
|
|
20580
|
+
function hasGivenUpOn(target, st = readUpdateState()) {
|
|
20581
|
+
return st.target === target && (st.failures ?? 0) >= GIVE_UP_AFTER;
|
|
20582
|
+
}
|
|
20583
|
+
function noteUpdateFailure(target) {
|
|
20584
|
+
const st = readUpdateState();
|
|
20585
|
+
const failures = st.target === target ? (st.failures ?? 0) + 1 : 1;
|
|
20586
|
+
writeUpdateState({ target, failures });
|
|
20587
|
+
return failures;
|
|
20588
|
+
}
|
|
20589
|
+
function clearUpdateFailures() {
|
|
20590
|
+
writeUpdateState({});
|
|
20591
|
+
}
|
|
20547
20592
|
async function runAutoUpdate(base, authHeaders, ownVersion2, deps) {
|
|
20548
20593
|
let caps;
|
|
20549
20594
|
try {
|
|
@@ -20566,6 +20611,10 @@ async function runAutoUpdate(base, authHeaders, ownVersion2, deps) {
|
|
|
20566
20611
|
}
|
|
20567
20612
|
return { updated: false, reason: plan.reason };
|
|
20568
20613
|
}
|
|
20614
|
+
const target = plan.to ?? "";
|
|
20615
|
+
if (target && hasGivenUpOn(target)) {
|
|
20616
|
+
return { updated: false, reason: `gave up installing ${plan.to} after ${GIVE_UP_AFTER} failed attempts \u2014 run \`npm install -g chat-recall\` by hand` };
|
|
20617
|
+
}
|
|
20569
20618
|
const result = await executeAutoUpdate(plan, {
|
|
20570
20619
|
download: deps?.download ?? realDownload,
|
|
20571
20620
|
install: deps?.install ?? realInstall,
|
|
@@ -20573,20 +20622,27 @@ async function runAutoUpdate(base, authHeaders, ownVersion2, deps) {
|
|
|
20573
20622
|
platform: deps?.platform
|
|
20574
20623
|
});
|
|
20575
20624
|
if (!result.updated) {
|
|
20576
|
-
|
|
20577
|
-
|
|
20578
|
-
|
|
20579
|
-
|
|
20625
|
+
const failures = target ? noteUpdateFailure(target) : 1;
|
|
20626
|
+
if (failures <= GIVE_UP_AFTER) {
|
|
20627
|
+
try {
|
|
20628
|
+
const { reportClientEvent: reportClientEvent3 } = await Promise.resolve().then(() => (init_client_events(), client_events_exports));
|
|
20629
|
+
const suffix = failures >= GIVE_UP_AFTER ? ` \u2014 giving up after ${failures} attempts, needs a manual \`npm install -g chat-recall\`` : ` (attempt ${failures} of ${GIVE_UP_AFTER})`;
|
|
20630
|
+
reportClientEvent3("auto_update_failed", { message: `${plan.from} \u2192 ${plan.to}: ${result.reason}${suffix}` });
|
|
20631
|
+
} catch {
|
|
20632
|
+
}
|
|
20580
20633
|
}
|
|
20634
|
+
} else {
|
|
20635
|
+
clearUpdateFailures();
|
|
20581
20636
|
}
|
|
20582
20637
|
return result;
|
|
20583
20638
|
}
|
|
20584
|
-
var tarballUrl, reportedStandingSkip;
|
|
20639
|
+
var tarballUrl, GIVE_UP_AFTER, reportedStandingSkip;
|
|
20585
20640
|
var init_auto_update = __esm({
|
|
20586
20641
|
"src/auto-update.ts"() {
|
|
20587
20642
|
"use strict";
|
|
20588
20643
|
init_http();
|
|
20589
20644
|
tarballUrl = (base) => `${base.replace(/\/+$/, "")}/install/chat-recall.tgz`;
|
|
20645
|
+
GIVE_UP_AFTER = 3;
|
|
20590
20646
|
reportedStandingSkip = /* @__PURE__ */ new Set();
|
|
20591
20647
|
}
|
|
20592
20648
|
});
|
|
@@ -20621,7 +20677,7 @@ __export(sync_client_exports, {
|
|
|
20621
20677
|
syncSessions: () => syncSessions
|
|
20622
20678
|
});
|
|
20623
20679
|
import { join as join48, dirname as dirname20, basename as basename21 } from "node:path";
|
|
20624
|
-
import { readFileSync as readFileSync37, writeFileSync as writeFileSync10, mkdirSync as
|
|
20680
|
+
import { readFileSync as readFileSync37, writeFileSync as writeFileSync10, mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync4, rmSync as rmSync6, chmodSync as chmodSync6, unlinkSync as unlinkSync3, readdirSync as readdirSync32, statSync as statSync41 } from "node:fs";
|
|
20625
20681
|
import { tmpdir as tmpdir4, hostname as hostname2 } from "node:os";
|
|
20626
20682
|
import { createHash as createHash11 } from "node:crypto";
|
|
20627
20683
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
@@ -20656,7 +20712,7 @@ function classifyError(msg, err) {
|
|
|
20656
20712
|
}
|
|
20657
20713
|
function saveCredentials(c) {
|
|
20658
20714
|
assertTransportSafe(c.serverUrl);
|
|
20659
|
-
|
|
20715
|
+
mkdirSync13(dirname20(credPath()), { recursive: true });
|
|
20660
20716
|
const targets = loadAllCredentials().filter((t) => t.serverUrl !== c.serverUrl);
|
|
20661
20717
|
targets.unshift(c);
|
|
20662
20718
|
writeFileSync10(credPath(), JSON.stringify({ targets }, null, 2));
|
|
@@ -20751,7 +20807,7 @@ function persistSyncConfig(base, config2) {
|
|
|
20751
20807
|
try {
|
|
20752
20808
|
const all = readPersistedSyncConfigs();
|
|
20753
20809
|
all[base] = { fetchedAt: Date.now(), config: config2 };
|
|
20754
|
-
|
|
20810
|
+
mkdirSync13(dirname20(syncConfigCachePath()), { recursive: true });
|
|
20755
20811
|
writeFileSync10(syncConfigCachePath(), JSON.stringify(all, null, 2));
|
|
20756
20812
|
} catch {
|
|
20757
20813
|
}
|
|
@@ -22157,7 +22213,7 @@ var init_sync_client = __esm({
|
|
|
22157
22213
|
ownVersion = JSON.parse(readFileSync37(join48(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
22158
22214
|
} catch {
|
|
22159
22215
|
try {
|
|
22160
|
-
if (true) ownVersion = "0.6.
|
|
22216
|
+
if (true) ownVersion = "0.6.6";
|
|
22161
22217
|
} catch {
|
|
22162
22218
|
}
|
|
22163
22219
|
}
|
|
@@ -22380,7 +22436,7 @@ __export(install_skills_exports, {
|
|
|
22380
22436
|
skillsSourceDir: () => skillsSourceDir,
|
|
22381
22437
|
uninstallSkills: () => uninstallSkills
|
|
22382
22438
|
});
|
|
22383
|
-
import { readdirSync as readdirSync33, existsSync as existsSync45, mkdirSync as
|
|
22439
|
+
import { readdirSync as readdirSync33, existsSync as existsSync45, mkdirSync as mkdirSync14, rmSync as rmSync7, cpSync, writeFileSync as writeFileSync12, readFileSync as readFileSync40, statSync as statSync42, realpathSync as realpathSync4 } from "fs";
|
|
22384
22440
|
import { createHash as createHash12 } from "crypto";
|
|
22385
22441
|
import { join as join50, basename as basename22 } from "path";
|
|
22386
22442
|
function skillsSourceDir() {
|
|
@@ -22490,7 +22546,7 @@ function installSkills(opts = {}) {
|
|
|
22490
22546
|
skippedUserOwned.push(name);
|
|
22491
22547
|
continue;
|
|
22492
22548
|
}
|
|
22493
|
-
|
|
22549
|
+
mkdirSync14(t.dir, { recursive: true });
|
|
22494
22550
|
rmSync7(dest, { recursive: true, force: true });
|
|
22495
22551
|
cpSync(join50(src, name), dest, { recursive: true });
|
|
22496
22552
|
writeFileSync12(join50(dest, MARKER), `${stamp}
|
|
@@ -22588,14 +22644,14 @@ __export(service_installer_exports, {
|
|
|
22588
22644
|
uninstallService: () => uninstallService
|
|
22589
22645
|
});
|
|
22590
22646
|
import { execSync as execSync5 } from "child_process";
|
|
22591
|
-
import { existsSync as existsSync46, mkdirSync as
|
|
22592
|
-
import { homedir as
|
|
22647
|
+
import { existsSync as existsSync46, mkdirSync as mkdirSync15, readFileSync as readFileSync41, rmSync as rmSync8, writeFileSync as writeFileSync13 } from "fs";
|
|
22648
|
+
import { homedir as homedir18 } from "os";
|
|
22593
22649
|
import { join as join51 } from "path";
|
|
22594
22650
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
22595
22651
|
function resolveDaemonPaths() {
|
|
22596
22652
|
const watchJs = fileURLToPath4(new URL("./watch.js", import.meta.url));
|
|
22597
22653
|
const node = process.execPath;
|
|
22598
|
-
const dataDir = join51(
|
|
22654
|
+
const dataDir = join51(homedir18(), ".chat-recall");
|
|
22599
22655
|
const logFile = join51(dataDir, "watch.log");
|
|
22600
22656
|
return { watchJs, node, logFile, dataDir };
|
|
22601
22657
|
}
|
|
@@ -22623,7 +22679,7 @@ function refreshServiceDefinition() {
|
|
|
22623
22679
|
if (process.platform !== "linux") return false;
|
|
22624
22680
|
try {
|
|
22625
22681
|
const { watchJs, node, logFile } = resolveDaemonPaths();
|
|
22626
|
-
const unitPath = join51(
|
|
22682
|
+
const unitPath = join51(homedir18(), ".config", "systemd", "user", "chat-recall-watch.service");
|
|
22627
22683
|
if (!existsSync46(unitPath)) return false;
|
|
22628
22684
|
const current = readFileSync41(unitPath, "utf8");
|
|
22629
22685
|
if (!current.includes(watchJs)) return false;
|
|
@@ -22638,7 +22694,7 @@ function refreshServiceDefinition() {
|
|
|
22638
22694
|
}
|
|
22639
22695
|
function installService() {
|
|
22640
22696
|
const { watchJs, node, logFile, dataDir } = resolveDaemonPaths();
|
|
22641
|
-
|
|
22697
|
+
mkdirSync15(dataDir, { recursive: true });
|
|
22642
22698
|
if (process.platform === "linux") {
|
|
22643
22699
|
return installSystemd(watchJs, node, logFile);
|
|
22644
22700
|
}
|
|
@@ -22654,10 +22710,10 @@ function installService() {
|
|
|
22654
22710
|
);
|
|
22655
22711
|
}
|
|
22656
22712
|
function installSystemd(watchJs, node, logFile) {
|
|
22657
|
-
const unitDir = join51(
|
|
22713
|
+
const unitDir = join51(homedir18(), ".config", "systemd", "user");
|
|
22658
22714
|
const unitPath = join51(unitDir, "chat-recall-watch.service");
|
|
22659
22715
|
const unit = renderSystemdUnit(watchJs, node, logFile);
|
|
22660
|
-
|
|
22716
|
+
mkdirSync15(unitDir, { recursive: true });
|
|
22661
22717
|
writeFileSync13(unitPath, unit);
|
|
22662
22718
|
try {
|
|
22663
22719
|
execSync5("systemctl --user daemon-reload && systemctl --user enable chat-recall-watch.service && systemctl --user restart chat-recall-watch.service", { stdio: "inherit" });
|
|
@@ -22729,10 +22785,10 @@ function renderSystemdUnit(watchJs, node, logFile) {
|
|
|
22729
22785
|
}
|
|
22730
22786
|
function installLaunchd(watchJs, node, logFile) {
|
|
22731
22787
|
const label = "com.chat-recall.watch";
|
|
22732
|
-
const plistDir = join51(
|
|
22788
|
+
const plistDir = join51(homedir18(), "Library", "LaunchAgents");
|
|
22733
22789
|
const plistPath = join51(plistDir, `${label}.plist`);
|
|
22734
22790
|
const plist = renderLaunchdPlist(watchJs, node, logFile, label);
|
|
22735
|
-
|
|
22791
|
+
mkdirSync15(plistDir, { recursive: true });
|
|
22736
22792
|
writeFileSync13(plistPath, plist);
|
|
22737
22793
|
try {
|
|
22738
22794
|
try {
|
|
@@ -22786,7 +22842,7 @@ function uninstallService() {
|
|
|
22786
22842
|
removed = true;
|
|
22787
22843
|
} catch {
|
|
22788
22844
|
}
|
|
22789
|
-
const unitPath = join51(
|
|
22845
|
+
const unitPath = join51(homedir18(), ".config", "systemd", "user", "chat-recall-watch.service");
|
|
22790
22846
|
if (existsSync46(unitPath)) {
|
|
22791
22847
|
rmSync8(unitPath, { force: true });
|
|
22792
22848
|
removed = true;
|
|
@@ -22798,7 +22854,7 @@ function uninstallService() {
|
|
|
22798
22854
|
return removed;
|
|
22799
22855
|
}
|
|
22800
22856
|
if (process.platform === "darwin") {
|
|
22801
|
-
const plistPath = join51(
|
|
22857
|
+
const plistPath = join51(homedir18(), "Library", "LaunchAgents", "com.chat-recall.watch.plist");
|
|
22802
22858
|
try {
|
|
22803
22859
|
execSync5(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" });
|
|
22804
22860
|
} catch {
|
|
@@ -23008,6 +23064,118 @@ function resumeCommandFor(sessionId, tool) {
|
|
|
23008
23064
|
|
|
23009
23065
|
// ../engine/dist/mcp/tools.js
|
|
23010
23066
|
init_project_resolver();
|
|
23067
|
+
|
|
23068
|
+
// ../engine/dist/core/decision-areas.js
|
|
23069
|
+
var DECISION_AREAS = [
|
|
23070
|
+
"auth",
|
|
23071
|
+
"database",
|
|
23072
|
+
"payments",
|
|
23073
|
+
"api",
|
|
23074
|
+
"frontend",
|
|
23075
|
+
"deploy",
|
|
23076
|
+
"testing",
|
|
23077
|
+
"observability",
|
|
23078
|
+
"security",
|
|
23079
|
+
"pricing",
|
|
23080
|
+
"licensing",
|
|
23081
|
+
"positioning"
|
|
23082
|
+
];
|
|
23083
|
+
var AREA_SET = new Set(DECISION_AREAS);
|
|
23084
|
+
var AREA_ALIASES = {
|
|
23085
|
+
// auth
|
|
23086
|
+
authentication: "auth",
|
|
23087
|
+
authn: "auth",
|
|
23088
|
+
authz: "auth",
|
|
23089
|
+
authorisation: "auth",
|
|
23090
|
+
authorization: "auth",
|
|
23091
|
+
login: "auth",
|
|
23092
|
+
"sign-in": "auth",
|
|
23093
|
+
signin: "auth",
|
|
23094
|
+
sso: "auth",
|
|
23095
|
+
identity: "auth",
|
|
23096
|
+
// database
|
|
23097
|
+
db: "database",
|
|
23098
|
+
datastore: "database",
|
|
23099
|
+
storage: "database",
|
|
23100
|
+
persistence: "database",
|
|
23101
|
+
orm: "database",
|
|
23102
|
+
migrations: "database",
|
|
23103
|
+
// payments
|
|
23104
|
+
billing: "payments",
|
|
23105
|
+
payment: "payments",
|
|
23106
|
+
checkout: "payments",
|
|
23107
|
+
subscriptions: "payments",
|
|
23108
|
+
// api
|
|
23109
|
+
backend: "api",
|
|
23110
|
+
server: "api",
|
|
23111
|
+
rpc: "api",
|
|
23112
|
+
// frontend
|
|
23113
|
+
ui: "frontend",
|
|
23114
|
+
client: "frontend",
|
|
23115
|
+
web: "frontend",
|
|
23116
|
+
styling: "frontend",
|
|
23117
|
+
css: "frontend",
|
|
23118
|
+
// deploy
|
|
23119
|
+
deployment: "deploy",
|
|
23120
|
+
infra: "deploy",
|
|
23121
|
+
infrastructure: "deploy",
|
|
23122
|
+
hosting: "deploy",
|
|
23123
|
+
ci: "deploy",
|
|
23124
|
+
cd: "deploy",
|
|
23125
|
+
"ci-cd": "deploy",
|
|
23126
|
+
release: "deploy",
|
|
23127
|
+
// testing
|
|
23128
|
+
tests: "testing",
|
|
23129
|
+
test: "testing",
|
|
23130
|
+
qa: "testing",
|
|
23131
|
+
e2e: "testing",
|
|
23132
|
+
// observability
|
|
23133
|
+
monitoring: "observability",
|
|
23134
|
+
logging: "observability",
|
|
23135
|
+
metrics: "observability",
|
|
23136
|
+
alerting: "observability",
|
|
23137
|
+
tracing: "observability",
|
|
23138
|
+
// security
|
|
23139
|
+
secrets: "security",
|
|
23140
|
+
compliance: "security",
|
|
23141
|
+
privacy: "security",
|
|
23142
|
+
// pricing
|
|
23143
|
+
price: "pricing",
|
|
23144
|
+
plans: "pricing",
|
|
23145
|
+
tiers: "pricing",
|
|
23146
|
+
// licensing
|
|
23147
|
+
licence: "licensing",
|
|
23148
|
+
license: "licensing",
|
|
23149
|
+
// positioning
|
|
23150
|
+
marketing: "positioning",
|
|
23151
|
+
branding: "positioning",
|
|
23152
|
+
messaging: "positioning"
|
|
23153
|
+
};
|
|
23154
|
+
function canonArea(raw) {
|
|
23155
|
+
if (!raw)
|
|
23156
|
+
return null;
|
|
23157
|
+
const lowered = raw.trim().toLowerCase();
|
|
23158
|
+
if (!lowered)
|
|
23159
|
+
return null;
|
|
23160
|
+
const slug = lowered.replace(/[\s_/]+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-{2,}/g, "-").replace(/^-|-$/g, "");
|
|
23161
|
+
if (!slug)
|
|
23162
|
+
return null;
|
|
23163
|
+
if (AREA_SET.has(slug))
|
|
23164
|
+
return slug;
|
|
23165
|
+
if (AREA_ALIASES[slug])
|
|
23166
|
+
return AREA_ALIASES[slug];
|
|
23167
|
+
return slug.slice(0, 40);
|
|
23168
|
+
}
|
|
23169
|
+
function isKnownArea(key2) {
|
|
23170
|
+
return !!key2 && AREA_SET.has(key2);
|
|
23171
|
+
}
|
|
23172
|
+
var ACCOUNT_SCOPE = "*";
|
|
23173
|
+
function decisionSubject(project, area) {
|
|
23174
|
+
const p = (project || "").trim() || ACCOUNT_SCOPE;
|
|
23175
|
+
return `${p}:${area}`;
|
|
23176
|
+
}
|
|
23177
|
+
|
|
23178
|
+
// ../engine/dist/mcp/tools.js
|
|
23011
23179
|
import { config } from "dotenv";
|
|
23012
23180
|
|
|
23013
23181
|
// ../engine/dist/mcp/diagnostics.js
|
|
@@ -23856,10 +24024,20 @@ var RecallDecisionRecordSchema = z.object({
|
|
|
23856
24024
|
subject: z.string().describe('What the decision is about (e.g., "chat-recall", "auth strategy")'),
|
|
23857
24025
|
decision: z.string().describe('The decision itself in plain words (e.g., "use Postgres full-text search as the default backend")'),
|
|
23858
24026
|
reason: z.string().optional().describe("Why this was decided \u2014 short rationale"),
|
|
24027
|
+
// The key a reversal supersedes on. Without it the subject is free text, so
|
|
24028
|
+
// "auth", "authentication" and "auth setup" are three separate facts and a
|
|
24029
|
+
// later decision never closes an earlier one — see core/decision-areas.ts.
|
|
24030
|
+
area: z.string().optional().describe(`The area this decides, so a later decision about the SAME area supersedes it. Use one of: ${DECISION_AREAS.join(", ")} \u2014 or any short slug for an area not listed. Without it the decision is recorded but nothing it contradicts is closed.`),
|
|
24031
|
+
project: z.string().optional().describe("Project this decision applies to. Omit for an account-wide decision that applies everywhere."),
|
|
23859
24032
|
importance: z.number().min(1).max(5).optional().default(4).describe("1\u20135; the classifier surfaces 4+ in wake-up context"),
|
|
23860
24033
|
session_id: z.string().optional().describe("Session this decision was made in (for traceability)"),
|
|
23861
24034
|
agent_name: z.string().optional().default("agent").describe("Who recorded the decision (for diary linkage)")
|
|
23862
24035
|
});
|
|
24036
|
+
var RecallDecisionsSchema = z.object({
|
|
24037
|
+
area: z.string().optional().describe("Only this area"),
|
|
24038
|
+
project: z.string().optional().describe("Resolve for this project"),
|
|
24039
|
+
include_candidates: z.boolean().optional().default(false)
|
|
24040
|
+
});
|
|
23863
24041
|
var RecallAnalyticsSummarySchema = z.object({
|
|
23864
24042
|
// No required inputs — returns the same summary the dashboard renders.
|
|
23865
24043
|
view: z.enum(["summary", "patterns"]).optional().default("summary").describe("summary = spend/activity rollup; patterns = behavioural patterns across sessions")
|
|
@@ -24008,6 +24186,7 @@ var LEAN_TOOLS = /* @__PURE__ */ new Set([
|
|
|
24008
24186
|
"recall_kg_query",
|
|
24009
24187
|
"recall_kg_add",
|
|
24010
24188
|
"recall_decision_record",
|
|
24189
|
+
"recall_decisions",
|
|
24011
24190
|
"recall_diary_write",
|
|
24012
24191
|
"recall_diary_read",
|
|
24013
24192
|
// Health, and the one that pays out on day one.
|
|
@@ -24904,13 +25083,19 @@ I asking yesterday?" or "what did I tell the agent in this session?".`,
|
|
|
24904
25083
|
name: "recall_decision_record",
|
|
24905
25084
|
description: `Record an explicit decision so it shows up in wake-up context. Writes a KG triple
|
|
24906
25085
|
(subject \u2192 decided \u2192 decision) plus a diary entry. Use this when you and the user agree on
|
|
24907
|
-
something non-obvious that future sessions should remember
|
|
25086
|
+
something non-obvious that future sessions should remember.
|
|
25087
|
+
|
|
25088
|
+
PASS \`area\`. It is the key a reversal supersedes on: recording a new \`auth\` decision closes the
|
|
25089
|
+
previous \`auth\` one and leaves every other area alone. Without it the decision is stored but
|
|
25090
|
+
nothing it contradicts is closed, and both answers stay live forever.`,
|
|
24908
25091
|
inputSchema: {
|
|
24909
25092
|
type: "object",
|
|
24910
25093
|
properties: {
|
|
24911
25094
|
subject: { type: "string", description: "What the decision is about" },
|
|
24912
25095
|
decision: { type: "string", description: "The decision itself" },
|
|
24913
25096
|
reason: { type: "string", description: "Why this was decided" },
|
|
25097
|
+
area: { type: "string", description: `The area this decides, so a later decision on the same area supersedes it. Standard areas: ${DECISION_AREAS.join(", ")}. Any short slug works for an area not listed.` },
|
|
25098
|
+
project: { type: "string", description: "Project this applies to. Omit for an account-wide decision that applies everywhere." },
|
|
24914
25099
|
importance: { type: "number", minimum: 1, maximum: 5, default: 4, description: "1-5. Only 4 and 5 surface in the wake-up bundle, so reserve those for decisions a future session must not miss." },
|
|
24915
25100
|
session_id: { type: "string", description: "Session this decision came out of. Pass your own current session id so the decision can be traced back to the conversation that made it." },
|
|
24916
25101
|
agent_name: { type: "string", default: "agent", description: "Which agent is recording this, so diary entries stay separable per agent." }
|
|
@@ -24918,6 +25103,25 @@ something non-obvious that future sessions should remember.`,
|
|
|
24918
25103
|
required: ["subject", "decision"]
|
|
24919
25104
|
}
|
|
24920
25105
|
},
|
|
25106
|
+
{
|
|
25107
|
+
name: "recall_decisions",
|
|
25108
|
+
description: `What this codebase has already settled \u2014 read it BEFORE choosing a library, a
|
|
25109
|
+
datastore, an auth method or anything else in a decided area, and you will not rebuild what was
|
|
25110
|
+
already ruled out.
|
|
25111
|
+
|
|
25112
|
+
Returns one effective value per area with the cascade already resolved (project beats account;
|
|
25113
|
+
personal preferences fill gaps and never override a team decision), what each value replaced and
|
|
25114
|
+
when, and the session it came from. Also returns \`gaps\` \u2014 areas nobody has decided, where you are
|
|
25115
|
+
free to choose, and where recording the choice afterwards is worth doing.`,
|
|
25116
|
+
inputSchema: {
|
|
25117
|
+
type: "object",
|
|
25118
|
+
properties: {
|
|
25119
|
+
area: { type: "string", description: `Only this area. Standard areas: ${DECISION_AREAS.join(", ")}.` },
|
|
25120
|
+
project: { type: "string", description: "Resolve for this project, so its overrides win over account-wide decisions. Omit for the account-wide view." },
|
|
25121
|
+
include_candidates: { type: "boolean", default: false, description: "Also return unconfirmed guesses the indexer extracted. These are NOT decisions \u2014 never treat one as settled." }
|
|
25122
|
+
}
|
|
25123
|
+
}
|
|
25124
|
+
},
|
|
24921
25125
|
{
|
|
24922
25126
|
name: "recall_analytics_summary",
|
|
24923
25127
|
description: `Cross-tool spend & activity overview. Returns total sessions, total cost,
|
|
@@ -27028,8 +27232,10 @@ ${JSON.stringify(r, null, 2)}
|
|
|
27028
27232
|
const wal = getWAL();
|
|
27029
27233
|
wal.log("decision_record", { subject: params.subject, importance: params.importance });
|
|
27030
27234
|
const confidence = Math.min(1, params.importance / 5);
|
|
27235
|
+
const area = canonArea(params.area);
|
|
27236
|
+
const kgSubject = area ? decisionSubject(params.project, area) : params.subject;
|
|
27031
27237
|
await remotePost("/api/kg/add", {
|
|
27032
|
-
subject:
|
|
27238
|
+
subject: kgSubject,
|
|
27033
27239
|
predicate: "decided",
|
|
27034
27240
|
object: params.decision,
|
|
27035
27241
|
confidence,
|
|
@@ -27037,11 +27243,12 @@ ${JSON.stringify(r, null, 2)}
|
|
|
27037
27243
|
});
|
|
27038
27244
|
if (params.reason) {
|
|
27039
27245
|
await remotePost("/api/kg/add", {
|
|
27040
|
-
subject:
|
|
27246
|
+
subject: kgSubject,
|
|
27041
27247
|
predicate: "because",
|
|
27042
27248
|
object: params.reason,
|
|
27043
27249
|
confidence,
|
|
27044
|
-
source_session: params.session_id
|
|
27250
|
+
source_session: params.session_id,
|
|
27251
|
+
supersede: false
|
|
27045
27252
|
});
|
|
27046
27253
|
}
|
|
27047
27254
|
const diaryText = params.reason ? `Decided: ${params.decision}
|
|
@@ -27057,12 +27264,58 @@ Subject: ${params.subject}`;
|
|
|
27057
27264
|
return {
|
|
27058
27265
|
content: [{
|
|
27059
27266
|
type: "text",
|
|
27060
|
-
text:
|
|
27061
|
-
|
|
27062
|
-
|
|
27267
|
+
text: [
|
|
27268
|
+
"Decision recorded.",
|
|
27269
|
+
`- KG: ${kgSubject} \u2192 decided \u2192 ${params.decision}`,
|
|
27270
|
+
area ? `- Area: ${area}${isKnownArea(area) ? "" : " (not a standard area \u2014 kept as a slug)"} \xB7 a later decision on this area supersedes this one` : "- No area given, so nothing this contradicts was closed. Pass `area` to make reversals work.",
|
|
27271
|
+
`- Diary entry: ${diary.id} (importance ${params.importance})`
|
|
27272
|
+
].join("\n")
|
|
27063
27273
|
}]
|
|
27064
27274
|
};
|
|
27065
27275
|
}
|
|
27276
|
+
// ── The decision register ──────────────────────────────────
|
|
27277
|
+
case "recall_decisions": {
|
|
27278
|
+
const p = RecallDecisionsSchema.parse(args ?? {});
|
|
27279
|
+
requireRemote();
|
|
27280
|
+
const r = await remoteGetQS("/api/decisions", {
|
|
27281
|
+
project: p.project,
|
|
27282
|
+
include_candidates: p.include_candidates ? "1" : "0"
|
|
27283
|
+
});
|
|
27284
|
+
const rows = p.area ? r.decisions.filter((d) => d.area === canonArea(p.area)) : r.decisions;
|
|
27285
|
+
const lines = [];
|
|
27286
|
+
lines.push(r.project ? `Decisions for ${r.project}` : "Decisions \u2014 account-wide");
|
|
27287
|
+
if (rows.length === 0) {
|
|
27288
|
+
lines.push("", p.area ? `Nothing decided for "${p.area}". You are free to choose \u2014 record it afterwards with recall_decision_record.` : "Nothing decided yet.");
|
|
27289
|
+
} else {
|
|
27290
|
+
lines.push("");
|
|
27291
|
+
for (const d of rows) {
|
|
27292
|
+
const tags = [
|
|
27293
|
+
d.override ? "OVERRIDES ACCOUNT" : "",
|
|
27294
|
+
d.inherited ? "inherited from account" : "",
|
|
27295
|
+
d.advisory ? "advisory \u2014 a personal preference, not binding" : ""
|
|
27296
|
+
].filter(Boolean).join(" \xB7 ");
|
|
27297
|
+
lines.push(`${d.area}: ${d.value}${d.since ? ` (since ${d.since})` : ""}${tags ? ` [${tags}]` : ""}`);
|
|
27298
|
+
if (d.why)
|
|
27299
|
+
lines.push(` why: ${d.why}`);
|
|
27300
|
+
const replaced = d.history.filter((h) => !h.current);
|
|
27301
|
+
for (const h of replaced)
|
|
27302
|
+
lines.push(` replaced: ${h.value} (ended ${h.to})`);
|
|
27303
|
+
if (d.source_session)
|
|
27304
|
+
lines.push(` from session ${d.source_session}`);
|
|
27305
|
+
}
|
|
27306
|
+
}
|
|
27307
|
+
if (!p.area && r.gaps.length) {
|
|
27308
|
+
lines.push("", `Not decided: ${r.gaps.map((g) => g.area).join(", ")}`);
|
|
27309
|
+
lines.push("Free to choose in these. Record the choice so the next session inherits it.");
|
|
27310
|
+
}
|
|
27311
|
+
if (p.include_candidates && r.candidates?.length) {
|
|
27312
|
+
lines.push("", "Unconfirmed guesses from indexing \u2014 NOT decisions, do not treat as settled:");
|
|
27313
|
+
for (const c of r.candidates.slice(0, 10)) {
|
|
27314
|
+
lines.push(` ${c.value} (seen ${c.mentions}\xD7${c.last_seen ? `, latest ${c.last_seen}` : ""})`);
|
|
27315
|
+
}
|
|
27316
|
+
}
|
|
27317
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
27318
|
+
}
|
|
27066
27319
|
// ── Analytics summary ──────────────────────────────────────
|
|
27067
27320
|
case "recall_analytics_summary": {
|
|
27068
27321
|
const analyticsParams = RecallAnalyticsSummarySchema.parse(args ?? {});
|
|
@@ -27808,7 +28061,7 @@ function installCrashGuards() {
|
|
|
27808
28061
|
reportClientEvent2("mcp_crash", { message: err.stack || err.message });
|
|
27809
28062
|
});
|
|
27810
28063
|
}
|
|
27811
|
-
var RELAY_VERSION = true ? "0.6.
|
|
28064
|
+
var RELAY_VERSION = true ? "0.6.6" : "0.0.0";
|
|
27812
28065
|
function daemonIdleSecs() {
|
|
27813
28066
|
const raw = process.env.CHAT_RECALL_DAEMON_IDLE_SECS;
|
|
27814
28067
|
if (raw === void 0) return 900;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare function shouldAskForStar(resultCount: number): boolean;
|
|
2
|
+
/** Record that it has been shown. A failure here means it may be shown once
|
|
3
|
+
* more on the next run, which is the harmless direction to fail in. */
|
|
4
|
+
export declare function markStarAsked(): void;
|
|
5
|
+
/**
|
|
6
|
+
* Print the ask and record it. Writes to stderr so a piped stdout carries only
|
|
7
|
+
* search results.
|
|
8
|
+
*
|
|
9
|
+
* `dim` is passed in rather than imported so this module pulls in no colour
|
|
10
|
+
* dependency of its own and a caller can hand it a no-op.
|
|
11
|
+
*/
|
|
12
|
+
export declare function askForStar(resultCount: number, dim: (s: string) => string): void;
|
|
13
|
+
//# sourceMappingURL=star-nudge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"star-nudge.d.ts","sourceRoot":"","sources":["../src/star-nudge.ts"],"names":[],"mappings":"AA6CA,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAO7D;AAED;wEACwE;AACxE,wBAAgB,aAAa,IAAI,IAAI,CAMpC;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAKhF"}
|