chat-recall 0.6.5 → 0.6.7
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 +45 -0
- 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 +1501 -353
- package/dist/cli.js.map +1 -1
- package/dist/mcp-relay.js +1 -1
- package/dist/mcp.js +85 -30
- 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 +111 -56
- package/hooks/chat_recall_guard_hook.sh +54 -0
- package/package.json +1 -1
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.7" : "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
|
@@ -19728,7 +19728,7 @@ var init_http = __esm({
|
|
|
19728
19728
|
CLI_VERSION = JSON.parse(readFileSync35(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
19729
19729
|
} catch {
|
|
19730
19730
|
try {
|
|
19731
|
-
if (true) CLI_VERSION = "0.6.
|
|
19731
|
+
if (true) CLI_VERSION = "0.6.7";
|
|
19732
19732
|
} catch {
|
|
19733
19733
|
}
|
|
19734
19734
|
}
|
|
@@ -20248,7 +20248,7 @@ var init_telemetry = __esm({
|
|
|
20248
20248
|
init_sync_client();
|
|
20249
20249
|
cliVersion2 = () => {
|
|
20250
20250
|
try {
|
|
20251
|
-
return true ? "0.6.
|
|
20251
|
+
return true ? "0.6.7" : "dev";
|
|
20252
20252
|
} catch {
|
|
20253
20253
|
return "dev";
|
|
20254
20254
|
}
|
|
@@ -20398,12 +20398,16 @@ var init_server_probe = __esm({
|
|
|
20398
20398
|
// src/auto-update.ts
|
|
20399
20399
|
var auto_update_exports = {};
|
|
20400
20400
|
__export(auto_update_exports, {
|
|
20401
|
+
clearUpdateFailures: () => clearUpdateFailures,
|
|
20401
20402
|
compareVersions: () => compareVersions,
|
|
20402
20403
|
executeAutoUpdate: () => executeAutoUpdate,
|
|
20404
|
+
hasGivenUpOn: () => hasGivenUpOn,
|
|
20403
20405
|
installedVersion: () => installedVersion,
|
|
20404
20406
|
isAutoUpdateEnabled: () => isAutoUpdateEnabled,
|
|
20405
20407
|
newerOf: () => newerOf,
|
|
20408
|
+
noteUpdateFailure: () => noteUpdateFailure,
|
|
20406
20409
|
planAutoUpdate: () => planAutoUpdate,
|
|
20410
|
+
readUpdateState: () => readUpdateState,
|
|
20407
20411
|
runAutoUpdate: () => runAutoUpdate,
|
|
20408
20412
|
runningPrefix: () => runningPrefix,
|
|
20409
20413
|
sweepStaleStaging: () => sweepStaleStaging,
|
|
@@ -20412,9 +20416,9 @@ __export(auto_update_exports, {
|
|
|
20412
20416
|
import { execSync as execSync4 } from "node:child_process";
|
|
20413
20417
|
import { readFileSync as readFileSync36 } from "node:fs";
|
|
20414
20418
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
20415
|
-
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";
|
|
20416
20420
|
import { join as join47, dirname as dirname19, sep as sep3 } from "node:path";
|
|
20417
|
-
import { tmpdir as tmpdir3 } from "node:os";
|
|
20421
|
+
import { tmpdir as tmpdir3, homedir as homedir17 } from "node:os";
|
|
20418
20422
|
import { createHash as createHash10 } from "node:crypto";
|
|
20419
20423
|
function compareVersions(a, b) {
|
|
20420
20424
|
const pa = String(a).split("-")[0].split(".").map((n) => parseInt(n, 10) || 0);
|
|
@@ -20528,16 +20532,25 @@ function runningPrefix(moduleUrl = import.meta.url) {
|
|
|
20528
20532
|
const beforeNodeModules = here.slice(0, at);
|
|
20529
20533
|
return beforeNodeModules.endsWith(`${sep3}lib`) ? beforeNodeModules.slice(0, -4) : beforeNodeModules;
|
|
20530
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
|
+
}
|
|
20531
20544
|
function realInstall(tgz) {
|
|
20532
20545
|
const prefix = runningPrefix();
|
|
20533
20546
|
if (prefix) {
|
|
20534
|
-
|
|
20547
|
+
npmInstall(`npm install -g --prefix "${prefix}" "${tgz}"`);
|
|
20535
20548
|
return;
|
|
20536
20549
|
}
|
|
20537
20550
|
try {
|
|
20538
|
-
|
|
20551
|
+
npmInstall(`npm install -g "${tgz}"`);
|
|
20539
20552
|
} catch {
|
|
20540
|
-
|
|
20553
|
+
npmInstall(`npm install -g --prefix "${process.env.HOME}/.local" "${tgz}"`);
|
|
20541
20554
|
}
|
|
20542
20555
|
}
|
|
20543
20556
|
function realRestart(platform2) {
|
|
@@ -20545,6 +20558,37 @@ function realRestart(platform2) {
|
|
|
20545
20558
|
else if (platform2 === "darwin") execSync4("launchctl kickstart -k gui/$(id -u)/com.chat-recall.watch", { stdio: "ignore", shell: "/bin/bash" });
|
|
20546
20559
|
else if (platform2 === "win32") execSync4("schtasks /End /TN chat-recall-watch & schtasks /Run /TN chat-recall-watch", { stdio: "ignore" });
|
|
20547
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
|
+
}
|
|
20548
20592
|
async function runAutoUpdate(base, authHeaders, ownVersion2, deps) {
|
|
20549
20593
|
let caps;
|
|
20550
20594
|
try {
|
|
@@ -20567,6 +20611,10 @@ async function runAutoUpdate(base, authHeaders, ownVersion2, deps) {
|
|
|
20567
20611
|
}
|
|
20568
20612
|
return { updated: false, reason: plan.reason };
|
|
20569
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
|
+
}
|
|
20570
20618
|
const result = await executeAutoUpdate(plan, {
|
|
20571
20619
|
download: deps?.download ?? realDownload,
|
|
20572
20620
|
install: deps?.install ?? realInstall,
|
|
@@ -20574,20 +20622,27 @@ async function runAutoUpdate(base, authHeaders, ownVersion2, deps) {
|
|
|
20574
20622
|
platform: deps?.platform
|
|
20575
20623
|
});
|
|
20576
20624
|
if (!result.updated) {
|
|
20577
|
-
|
|
20578
|
-
|
|
20579
|
-
|
|
20580
|
-
|
|
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
|
+
}
|
|
20581
20633
|
}
|
|
20634
|
+
} else {
|
|
20635
|
+
clearUpdateFailures();
|
|
20582
20636
|
}
|
|
20583
20637
|
return result;
|
|
20584
20638
|
}
|
|
20585
|
-
var tarballUrl, reportedStandingSkip;
|
|
20639
|
+
var tarballUrl, GIVE_UP_AFTER, reportedStandingSkip;
|
|
20586
20640
|
var init_auto_update = __esm({
|
|
20587
20641
|
"src/auto-update.ts"() {
|
|
20588
20642
|
"use strict";
|
|
20589
20643
|
init_http();
|
|
20590
20644
|
tarballUrl = (base) => `${base.replace(/\/+$/, "")}/install/chat-recall.tgz`;
|
|
20645
|
+
GIVE_UP_AFTER = 3;
|
|
20591
20646
|
reportedStandingSkip = /* @__PURE__ */ new Set();
|
|
20592
20647
|
}
|
|
20593
20648
|
});
|
|
@@ -20622,7 +20677,7 @@ __export(sync_client_exports, {
|
|
|
20622
20677
|
syncSessions: () => syncSessions
|
|
20623
20678
|
});
|
|
20624
20679
|
import { join as join48, dirname as dirname20, basename as basename21 } from "node:path";
|
|
20625
|
-
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";
|
|
20626
20681
|
import { tmpdir as tmpdir4, hostname as hostname2 } from "node:os";
|
|
20627
20682
|
import { createHash as createHash11 } from "node:crypto";
|
|
20628
20683
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
@@ -20657,7 +20712,7 @@ function classifyError(msg, err) {
|
|
|
20657
20712
|
}
|
|
20658
20713
|
function saveCredentials(c) {
|
|
20659
20714
|
assertTransportSafe(c.serverUrl);
|
|
20660
|
-
|
|
20715
|
+
mkdirSync13(dirname20(credPath()), { recursive: true });
|
|
20661
20716
|
const targets = loadAllCredentials().filter((t) => t.serverUrl !== c.serverUrl);
|
|
20662
20717
|
targets.unshift(c);
|
|
20663
20718
|
writeFileSync10(credPath(), JSON.stringify({ targets }, null, 2));
|
|
@@ -20752,7 +20807,7 @@ function persistSyncConfig(base, config2) {
|
|
|
20752
20807
|
try {
|
|
20753
20808
|
const all = readPersistedSyncConfigs();
|
|
20754
20809
|
all[base] = { fetchedAt: Date.now(), config: config2 };
|
|
20755
|
-
|
|
20810
|
+
mkdirSync13(dirname20(syncConfigCachePath()), { recursive: true });
|
|
20756
20811
|
writeFileSync10(syncConfigCachePath(), JSON.stringify(all, null, 2));
|
|
20757
20812
|
} catch {
|
|
20758
20813
|
}
|
|
@@ -22158,7 +22213,7 @@ var init_sync_client = __esm({
|
|
|
22158
22213
|
ownVersion = JSON.parse(readFileSync37(join48(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
22159
22214
|
} catch {
|
|
22160
22215
|
try {
|
|
22161
|
-
if (true) ownVersion = "0.6.
|
|
22216
|
+
if (true) ownVersion = "0.6.7";
|
|
22162
22217
|
} catch {
|
|
22163
22218
|
}
|
|
22164
22219
|
}
|
|
@@ -22381,7 +22436,7 @@ __export(install_skills_exports, {
|
|
|
22381
22436
|
skillsSourceDir: () => skillsSourceDir,
|
|
22382
22437
|
uninstallSkills: () => uninstallSkills
|
|
22383
22438
|
});
|
|
22384
|
-
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";
|
|
22385
22440
|
import { createHash as createHash12 } from "crypto";
|
|
22386
22441
|
import { join as join50, basename as basename22 } from "path";
|
|
22387
22442
|
function skillsSourceDir() {
|
|
@@ -22491,7 +22546,7 @@ function installSkills(opts = {}) {
|
|
|
22491
22546
|
skippedUserOwned.push(name);
|
|
22492
22547
|
continue;
|
|
22493
22548
|
}
|
|
22494
|
-
|
|
22549
|
+
mkdirSync14(t.dir, { recursive: true });
|
|
22495
22550
|
rmSync7(dest, { recursive: true, force: true });
|
|
22496
22551
|
cpSync(join50(src, name), dest, { recursive: true });
|
|
22497
22552
|
writeFileSync12(join50(dest, MARKER), `${stamp}
|
|
@@ -22589,14 +22644,14 @@ __export(service_installer_exports, {
|
|
|
22589
22644
|
uninstallService: () => uninstallService
|
|
22590
22645
|
});
|
|
22591
22646
|
import { execSync as execSync5 } from "child_process";
|
|
22592
|
-
import { existsSync as existsSync46, mkdirSync as
|
|
22593
|
-
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";
|
|
22594
22649
|
import { join as join51 } from "path";
|
|
22595
22650
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
22596
22651
|
function resolveDaemonPaths() {
|
|
22597
22652
|
const watchJs = fileURLToPath4(new URL("./watch.js", import.meta.url));
|
|
22598
22653
|
const node = process.execPath;
|
|
22599
|
-
const dataDir = join51(
|
|
22654
|
+
const dataDir = join51(homedir18(), ".chat-recall");
|
|
22600
22655
|
const logFile = join51(dataDir, "watch.log");
|
|
22601
22656
|
return { watchJs, node, logFile, dataDir };
|
|
22602
22657
|
}
|
|
@@ -22624,7 +22679,7 @@ function refreshServiceDefinition() {
|
|
|
22624
22679
|
if (process.platform !== "linux") return false;
|
|
22625
22680
|
try {
|
|
22626
22681
|
const { watchJs, node, logFile } = resolveDaemonPaths();
|
|
22627
|
-
const unitPath = join51(
|
|
22682
|
+
const unitPath = join51(homedir18(), ".config", "systemd", "user", "chat-recall-watch.service");
|
|
22628
22683
|
if (!existsSync46(unitPath)) return false;
|
|
22629
22684
|
const current = readFileSync41(unitPath, "utf8");
|
|
22630
22685
|
if (!current.includes(watchJs)) return false;
|
|
@@ -22639,7 +22694,7 @@ function refreshServiceDefinition() {
|
|
|
22639
22694
|
}
|
|
22640
22695
|
function installService() {
|
|
22641
22696
|
const { watchJs, node, logFile, dataDir } = resolveDaemonPaths();
|
|
22642
|
-
|
|
22697
|
+
mkdirSync15(dataDir, { recursive: true });
|
|
22643
22698
|
if (process.platform === "linux") {
|
|
22644
22699
|
return installSystemd(watchJs, node, logFile);
|
|
22645
22700
|
}
|
|
@@ -22655,10 +22710,10 @@ function installService() {
|
|
|
22655
22710
|
);
|
|
22656
22711
|
}
|
|
22657
22712
|
function installSystemd(watchJs, node, logFile) {
|
|
22658
|
-
const unitDir = join51(
|
|
22713
|
+
const unitDir = join51(homedir18(), ".config", "systemd", "user");
|
|
22659
22714
|
const unitPath = join51(unitDir, "chat-recall-watch.service");
|
|
22660
22715
|
const unit = renderSystemdUnit(watchJs, node, logFile);
|
|
22661
|
-
|
|
22716
|
+
mkdirSync15(unitDir, { recursive: true });
|
|
22662
22717
|
writeFileSync13(unitPath, unit);
|
|
22663
22718
|
try {
|
|
22664
22719
|
execSync5("systemctl --user daemon-reload && systemctl --user enable chat-recall-watch.service && systemctl --user restart chat-recall-watch.service", { stdio: "inherit" });
|
|
@@ -22730,10 +22785,10 @@ function renderSystemdUnit(watchJs, node, logFile) {
|
|
|
22730
22785
|
}
|
|
22731
22786
|
function installLaunchd(watchJs, node, logFile) {
|
|
22732
22787
|
const label = "com.chat-recall.watch";
|
|
22733
|
-
const plistDir = join51(
|
|
22788
|
+
const plistDir = join51(homedir18(), "Library", "LaunchAgents");
|
|
22734
22789
|
const plistPath = join51(plistDir, `${label}.plist`);
|
|
22735
22790
|
const plist = renderLaunchdPlist(watchJs, node, logFile, label);
|
|
22736
|
-
|
|
22791
|
+
mkdirSync15(plistDir, { recursive: true });
|
|
22737
22792
|
writeFileSync13(plistPath, plist);
|
|
22738
22793
|
try {
|
|
22739
22794
|
try {
|
|
@@ -22787,7 +22842,7 @@ function uninstallService() {
|
|
|
22787
22842
|
removed = true;
|
|
22788
22843
|
} catch {
|
|
22789
22844
|
}
|
|
22790
|
-
const unitPath = join51(
|
|
22845
|
+
const unitPath = join51(homedir18(), ".config", "systemd", "user", "chat-recall-watch.service");
|
|
22791
22846
|
if (existsSync46(unitPath)) {
|
|
22792
22847
|
rmSync8(unitPath, { force: true });
|
|
22793
22848
|
removed = true;
|
|
@@ -22799,7 +22854,7 @@ function uninstallService() {
|
|
|
22799
22854
|
return removed;
|
|
22800
22855
|
}
|
|
22801
22856
|
if (process.platform === "darwin") {
|
|
22802
|
-
const plistPath = join51(
|
|
22857
|
+
const plistPath = join51(homedir18(), "Library", "LaunchAgents", "com.chat-recall.watch.plist");
|
|
22803
22858
|
try {
|
|
22804
22859
|
execSync5(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" });
|
|
22805
22860
|
} catch {
|
|
@@ -28006,7 +28061,7 @@ function installCrashGuards() {
|
|
|
28006
28061
|
reportClientEvent2("mcp_crash", { message: err.stack || err.message });
|
|
28007
28062
|
});
|
|
28008
28063
|
}
|
|
28009
|
-
var RELAY_VERSION = true ? "0.6.
|
|
28064
|
+
var RELAY_VERSION = true ? "0.6.7" : "0.0.0";
|
|
28010
28065
|
function daemonIdleSecs() {
|
|
28011
28066
|
const raw = process.env.CHAT_RECALL_DAEMON_IDLE_SECS;
|
|
28012
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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ask, once per machine, for a GitHub star — after a search that worked.
|
|
3
|
+
*
|
|
4
|
+
* WHY IT EXISTS. Measured 2026-09-13: npm reported 6,973 downloads in the last
|
|
5
|
+
* month and 440 in the last week, while github.com/munhq/chat-recall had 2
|
|
6
|
+
* stars, 0 forks and 0 watchers. People install this, use it, and leave no
|
|
7
|
+
* public trace, and a star count is the signal both recommendation paths read —
|
|
8
|
+
* the corpus a model is trained on, and the "best MCP servers" articles that
|
|
9
|
+
* rank for the queries buyers actually type.
|
|
10
|
+
*
|
|
11
|
+
* WHERE IT IS SAFE TO PRINT. Here, and nowhere else. The MCP server is a
|
|
12
|
+
* different entry point (mcp.ts, reached through mcp-relay.js) and speaks
|
|
13
|
+
* JSON-RPC over stdio, where one stray line of text corrupts the stream. This
|
|
14
|
+
* module is imported by cli.ts only. Keep it that way.
|
|
15
|
+
*
|
|
16
|
+
* Four conditions, all required:
|
|
17
|
+
* - the search returned results, so the ask follows something that worked
|
|
18
|
+
* - stderr is a TTY, so a piped or redirected run is untouched
|
|
19
|
+
* - no CI marker in the environment
|
|
20
|
+
* - the marker file is absent, so it has never been shown on this machine
|
|
21
|
+
*/
|
|
22
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
23
|
+
import { dirname, join } from 'node:path';
|
|
24
|
+
import { getDataDir } from '@chat-recall/engine/core/paths.js';
|
|
25
|
+
const REPO = 'https://github.com/munhq/chat-recall';
|
|
26
|
+
/** One file, written once. Deliberately not a settings field: AppSettings is a
|
|
27
|
+
* versioned schema merged field by field, and a cosmetic one-shot marker is
|
|
28
|
+
* not worth a migration or a chance to corrupt a user's real settings. */
|
|
29
|
+
function markerPath() {
|
|
30
|
+
return join(getDataDir(), '.star-asked');
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Environments that must never see it: CI, and anyone who has opted out.
|
|
34
|
+
* CI=true is set by GitHub Actions, GitLab, CircleCI and Travis; the others are
|
|
35
|
+
* belt and braces for runners that set only their own name.
|
|
36
|
+
*/
|
|
37
|
+
function suppressed() {
|
|
38
|
+
const env = process.env;
|
|
39
|
+
if (env.CHAT_RECALL_NO_STAR_PROMPT)
|
|
40
|
+
return true;
|
|
41
|
+
return Boolean(env.CI || env.GITHUB_ACTIONS || env.GITLAB_CI || env.BUILDKITE || env.TEAMCITY_VERSION);
|
|
42
|
+
}
|
|
43
|
+
export function shouldAskForStar(resultCount) {
|
|
44
|
+
if (resultCount <= 0)
|
|
45
|
+
return false;
|
|
46
|
+
if (suppressed())
|
|
47
|
+
return false;
|
|
48
|
+
// stderr, because that is where the line goes. A run whose stdout is a pipe
|
|
49
|
+
// but whose stderr is still the terminal is a person watching, so it shows.
|
|
50
|
+
if (!process.stderr.isTTY)
|
|
51
|
+
return false;
|
|
52
|
+
try {
|
|
53
|
+
return !existsSync(markerPath());
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** Record that it has been shown. A failure here means it may be shown once
|
|
60
|
+
* more on the next run, which is the harmless direction to fail in. */
|
|
61
|
+
export function markStarAsked() {
|
|
62
|
+
try {
|
|
63
|
+
const p = markerPath();
|
|
64
|
+
mkdirSync(dirname(p), { recursive: true });
|
|
65
|
+
writeFileSync(p, `${new Date().toISOString()}\n`);
|
|
66
|
+
}
|
|
67
|
+
catch { /* read-only home, or no disk — never worth failing a search over */ }
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Print the ask and record it. Writes to stderr so a piped stdout carries only
|
|
71
|
+
* search results.
|
|
72
|
+
*
|
|
73
|
+
* `dim` is passed in rather than imported so this module pulls in no colour
|
|
74
|
+
* dependency of its own and a caller can hand it a no-op.
|
|
75
|
+
*/
|
|
76
|
+
export function askForStar(resultCount, dim) {
|
|
77
|
+
if (!shouldAskForStar(resultCount))
|
|
78
|
+
return;
|
|
79
|
+
markStarAsked();
|
|
80
|
+
process.stderr.write(`${dim(`If this saved you time, a star helps other people find it: ${REPO}`)}\n`);
|
|
81
|
+
process.stderr.write(`${dim('You will not be asked again. CHAT_RECALL_NO_STAR_PROMPT=1 disables it everywhere.')}\n`);
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=star-nudge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"star-nudge.js","sourceRoot":"","sources":["../src/star-nudge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAE/D,MAAM,IAAI,GAAG,sCAAsC,CAAC;AAEpD;;2EAE2E;AAC3E,SAAS,UAAU;IACjB,OAAO,IAAI,CAAC,UAAU,EAAE,EAAE,aAAa,CAAC,CAAC;AAC3C,CAAC;AAED;;;;GAIG;AACH,SAAS,UAAU;IACjB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IACxB,IAAI,GAAG,CAAC,0BAA0B;QAAE,OAAO,IAAI,CAAC;IAChD,OAAO,OAAO,CAAC,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,cAAc,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,gBAAgB,CAAC,CAAC;AACzG,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,WAAmB;IAClD,IAAI,WAAW,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACnC,IAAI,UAAU,EAAE;QAAE,OAAO,KAAK,CAAC;IAC/B,4EAA4E;IAC5E,4EAA4E;IAC5E,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACxC,IAAI,CAAC;QAAC,OAAO,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,KAAK,CAAC;IAAC,CAAC;AACnE,CAAC;AAED;wEACwE;AACxE,MAAM,UAAU,aAAa;IAC3B,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,UAAU,EAAE,CAAC;QACvB,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,aAAa,CAAC,CAAC,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC,CAAC,oEAAoE,CAAC,CAAC;AAClF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,WAAmB,EAAE,GAA0B;IACxE,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC;QAAE,OAAO;IAC3C,aAAa,EAAE,CAAC;IAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,8DAA8D,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC;IACvG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,mFAAmF,CAAC,IAAI,CAAC,CAAC;AACxH,CAAC"}
|