engrm 0.4.45 → 0.4.46
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/cli.js +396 -118
- package/dist/hooks/elicitation-result.js +81 -15
- package/dist/hooks/post-tool-use.js +250 -23
- package/dist/hooks/pre-compact.js +249 -23
- package/dist/hooks/sentinel.js +81 -15
- package/dist/hooks/session-start.js +105 -17
- package/dist/hooks/stop.js +311 -27
- package/dist/hooks/user-prompt-submit.js +81 -15
- package/dist/server.js +193 -34
- package/package.json +1 -1
|
@@ -3280,7 +3280,7 @@ import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync
|
|
|
3280
3280
|
import { join as join3 } from "node:path";
|
|
3281
3281
|
import { homedir } from "node:os";
|
|
3282
3282
|
var STATE_PATH = join3(homedir(), ".engrm", "config-fingerprint.json");
|
|
3283
|
-
var CLIENT_VERSION = "0.4.
|
|
3283
|
+
var CLIENT_VERSION = "0.4.46";
|
|
3284
3284
|
function hashFile(filePath) {
|
|
3285
3285
|
try {
|
|
3286
3286
|
if (!existsSync3(filePath))
|
|
@@ -3415,11 +3415,20 @@ import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as rea
|
|
|
3415
3415
|
import { homedir as homedir2, hostname, networkInterfaces } from "node:os";
|
|
3416
3416
|
import { join as join5 } from "node:path";
|
|
3417
3417
|
import { createHash as createHash2 } from "node:crypto";
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3418
|
+
function resolveConfigDir() {
|
|
3419
|
+
return process.env["ENGRM_CONFIG_DIR"]?.trim() || join5(homedir2(), ".engrm");
|
|
3420
|
+
}
|
|
3421
|
+
function resolveSettingsPath() {
|
|
3422
|
+
return join5(resolveConfigDir(), "settings.json");
|
|
3423
|
+
}
|
|
3424
|
+
function resolveDbPath() {
|
|
3425
|
+
return join5(resolveConfigDir(), "engrm.db");
|
|
3426
|
+
}
|
|
3427
|
+
function resolveAuthBackupPath() {
|
|
3428
|
+
return join5(resolveConfigDir(), "auth-backup.json");
|
|
3429
|
+
}
|
|
3421
3430
|
function getDbPath() {
|
|
3422
|
-
return
|
|
3431
|
+
return resolveDbPath();
|
|
3423
3432
|
}
|
|
3424
3433
|
function generateDeviceId() {
|
|
3425
3434
|
const host = hostname().toLowerCase().replace(/[^a-z0-9-]/g, "");
|
|
@@ -3442,7 +3451,7 @@ function generateDeviceId() {
|
|
|
3442
3451
|
return `${host}-${suffix}`;
|
|
3443
3452
|
}
|
|
3444
3453
|
function createDefaultConfig() {
|
|
3445
|
-
|
|
3454
|
+
const merged = {
|
|
3446
3455
|
candengo_url: "",
|
|
3447
3456
|
candengo_api_key: "",
|
|
3448
3457
|
site_id: "",
|
|
@@ -3497,24 +3506,26 @@ function createDefaultConfig() {
|
|
|
3497
3506
|
},
|
|
3498
3507
|
tool_profile: "full"
|
|
3499
3508
|
};
|
|
3509
|
+
return merged;
|
|
3500
3510
|
}
|
|
3501
3511
|
function loadConfig() {
|
|
3502
|
-
|
|
3503
|
-
|
|
3512
|
+
const settingsPath = resolveSettingsPath();
|
|
3513
|
+
if (!existsSync5(settingsPath)) {
|
|
3514
|
+
throw new Error(`Config not found at ${settingsPath}. Run 'engrm init --manual' to configure.`);
|
|
3504
3515
|
}
|
|
3505
|
-
const raw = readFileSync4(
|
|
3516
|
+
const raw = readFileSync4(settingsPath, "utf-8");
|
|
3506
3517
|
let parsed;
|
|
3507
3518
|
try {
|
|
3508
3519
|
parsed = JSON.parse(raw);
|
|
3509
3520
|
} catch {
|
|
3510
|
-
throw new Error(`Invalid JSON in ${
|
|
3521
|
+
throw new Error(`Invalid JSON in ${settingsPath}`);
|
|
3511
3522
|
}
|
|
3512
3523
|
if (typeof parsed !== "object" || parsed === null) {
|
|
3513
|
-
throw new Error(`Config at ${
|
|
3524
|
+
throw new Error(`Config at ${settingsPath} is not a JSON object`);
|
|
3514
3525
|
}
|
|
3515
3526
|
const config = parsed;
|
|
3516
3527
|
const defaults = createDefaultConfig();
|
|
3517
|
-
|
|
3528
|
+
const merged = {
|
|
3518
3529
|
candengo_url: asString(config["candengo_url"], defaults.candengo_url),
|
|
3519
3530
|
candengo_api_key: asString(config["candengo_api_key"], defaults.candengo_api_key),
|
|
3520
3531
|
site_id: asString(config["site_id"], defaults.site_id),
|
|
@@ -3569,16 +3580,27 @@ function loadConfig() {
|
|
|
3569
3580
|
},
|
|
3570
3581
|
tool_profile: asToolProfile(config["tool_profile"], defaults.tool_profile)
|
|
3571
3582
|
};
|
|
3583
|
+
if (looksLikePlaceholderAuth(merged)) {
|
|
3584
|
+
return restoreAuthBackup(merged) ?? merged;
|
|
3585
|
+
}
|
|
3586
|
+
return merged;
|
|
3572
3587
|
}
|
|
3573
3588
|
function saveConfig(config) {
|
|
3574
|
-
|
|
3575
|
-
|
|
3589
|
+
const configDir = resolveConfigDir();
|
|
3590
|
+
const settingsPath = resolveSettingsPath();
|
|
3591
|
+
const authBackupPath = resolveAuthBackupPath();
|
|
3592
|
+
if (!existsSync5(configDir)) {
|
|
3593
|
+
mkdirSync2(configDir, { recursive: true });
|
|
3576
3594
|
}
|
|
3577
|
-
writeFileSync2(
|
|
3595
|
+
writeFileSync2(settingsPath, JSON.stringify(config, null, 2) + `
|
|
3578
3596
|
`, "utf-8");
|
|
3597
|
+
if (!looksLikePlaceholderAuth(config)) {
|
|
3598
|
+
writeFileSync2(authBackupPath, JSON.stringify(extractAuthBackup(config), null, 2) + `
|
|
3599
|
+
`, "utf-8");
|
|
3600
|
+
}
|
|
3579
3601
|
}
|
|
3580
3602
|
function configExists() {
|
|
3581
|
-
return existsSync5(
|
|
3603
|
+
return existsSync5(resolveSettingsPath());
|
|
3582
3604
|
}
|
|
3583
3605
|
function asString(value, fallback) {
|
|
3584
3606
|
return typeof value === "string" ? value : fallback;
|
|
@@ -3632,6 +3654,50 @@ function asTeams(value, fallback) {
|
|
|
3632
3654
|
return fallback;
|
|
3633
3655
|
return value.filter((t) => typeof t === "object" && t !== null && typeof t.id === "string" && typeof t.name === "string" && typeof t.namespace === "string");
|
|
3634
3656
|
}
|
|
3657
|
+
function looksLikePlaceholderAuth(config) {
|
|
3658
|
+
const apiKey = config.candengo_api_key.trim();
|
|
3659
|
+
const siteId = config.site_id.trim();
|
|
3660
|
+
const namespace = config.namespace.trim();
|
|
3661
|
+
const email = config.user_email.trim().toLowerCase();
|
|
3662
|
+
if (apiKey === "cvk_org" && siteId === "site-1" && namespace === "org-ns")
|
|
3663
|
+
return true;
|
|
3664
|
+
if (siteId === "site-1" && namespace === "org-ns" && email.endsWith("@example.com"))
|
|
3665
|
+
return true;
|
|
3666
|
+
return false;
|
|
3667
|
+
}
|
|
3668
|
+
function extractAuthBackup(config) {
|
|
3669
|
+
return {
|
|
3670
|
+
candengo_url: config.candengo_url,
|
|
3671
|
+
candengo_api_key: config.candengo_api_key,
|
|
3672
|
+
site_id: config.site_id,
|
|
3673
|
+
namespace: config.namespace,
|
|
3674
|
+
user_id: config.user_id,
|
|
3675
|
+
user_email: config.user_email,
|
|
3676
|
+
teams: config.teams
|
|
3677
|
+
};
|
|
3678
|
+
}
|
|
3679
|
+
function restoreAuthBackup(config) {
|
|
3680
|
+
const authBackupPath = resolveAuthBackupPath();
|
|
3681
|
+
if (!existsSync5(authBackupPath))
|
|
3682
|
+
return null;
|
|
3683
|
+
try {
|
|
3684
|
+
const raw = readFileSync4(authBackupPath, "utf-8");
|
|
3685
|
+
const parsed = JSON.parse(raw);
|
|
3686
|
+
const restored = {
|
|
3687
|
+
...config,
|
|
3688
|
+
candengo_url: asString(parsed["candengo_url"], config.candengo_url),
|
|
3689
|
+
candengo_api_key: asString(parsed["candengo_api_key"], config.candengo_api_key),
|
|
3690
|
+
site_id: asString(parsed["site_id"], config.site_id),
|
|
3691
|
+
namespace: asString(parsed["namespace"], config.namespace),
|
|
3692
|
+
user_id: asString(parsed["user_id"], config.user_id),
|
|
3693
|
+
user_email: asString(parsed["user_email"], config.user_email),
|
|
3694
|
+
teams: asTeams(parsed["teams"], config.teams)
|
|
3695
|
+
};
|
|
3696
|
+
return looksLikePlaceholderAuth(restored) ? null : restored;
|
|
3697
|
+
} catch {
|
|
3698
|
+
return null;
|
|
3699
|
+
}
|
|
3700
|
+
}
|
|
3635
3701
|
|
|
3636
3702
|
// src/sync/auth.ts
|
|
3637
3703
|
import { createHash as createHash3 } from "node:crypto";
|
|
@@ -3725,6 +3791,10 @@ function resetStaleSyncingEntries(db, maxAgeSeconds = 300) {
|
|
|
3725
3791
|
|
|
3726
3792
|
// src/sync/auth.ts
|
|
3727
3793
|
var LEGACY_PUBLIC_HOSTS = new Set(["www.candengo.com", "candengo.com"]);
|
|
3794
|
+
var PLACEHOLDER_API_KEYS = new Set(["cvk_org"]);
|
|
3795
|
+
var PLACEHOLDER_SITE_IDS = new Set(["site-1"]);
|
|
3796
|
+
var PLACEHOLDER_NAMESPACES = new Set(["org-ns", "fleet-ns"]);
|
|
3797
|
+
var PLACEHOLDER_EMAIL_SUFFIXES = ["@example.com"];
|
|
3728
3798
|
function normalizeBaseUrl(url) {
|
|
3729
3799
|
const trimmed = url.trim();
|
|
3730
3800
|
if (!trimmed)
|
|
@@ -3743,7 +3813,7 @@ function getApiKey(config) {
|
|
|
3743
3813
|
const envKey = process.env.ENGRM_TOKEN;
|
|
3744
3814
|
if (envKey && envKey.startsWith("cvk_"))
|
|
3745
3815
|
return envKey;
|
|
3746
|
-
if (config.candengo_api_key && config.candengo_api_key.length > 0) {
|
|
3816
|
+
if (config.candengo_api_key && config.candengo_api_key.length > 0 && !looksLikePlaceholderConfig(config)) {
|
|
3747
3817
|
return config.candengo_api_key;
|
|
3748
3818
|
}
|
|
3749
3819
|
return null;
|
|
@@ -3764,6 +3834,23 @@ ${apiKey}
|
|
|
3764
3834
|
${config.namespace}
|
|
3765
3835
|
${config.site_id}`).digest("hex");
|
|
3766
3836
|
}
|
|
3837
|
+
function looksLikePlaceholderConfig(config) {
|
|
3838
|
+
const apiKey = config.candengo_api_key?.trim() ?? "";
|
|
3839
|
+
const siteId = config.site_id?.trim() ?? "";
|
|
3840
|
+
const namespace = config.namespace?.trim() ?? "";
|
|
3841
|
+
const email = config.user_email?.trim().toLowerCase() ?? "";
|
|
3842
|
+
if (PLACEHOLDER_API_KEYS.has(apiKey) && PLACEHOLDER_SITE_IDS.has(siteId) && PLACEHOLDER_NAMESPACES.has(namespace)) {
|
|
3843
|
+
return true;
|
|
3844
|
+
}
|
|
3845
|
+
if (PLACEHOLDER_SITE_IDS.has(siteId) && PLACEHOLDER_NAMESPACES.has(namespace) && PLACEHOLDER_EMAIL_SUFFIXES.some((suffix) => email.endsWith(suffix))) {
|
|
3846
|
+
return true;
|
|
3847
|
+
}
|
|
3848
|
+
return false;
|
|
3849
|
+
}
|
|
3850
|
+
function clearSyncPushBlock(db) {
|
|
3851
|
+
db.setSyncState("sync_push_blocked_until", "0");
|
|
3852
|
+
db.setSyncState("sync_push_block_reason", "");
|
|
3853
|
+
}
|
|
3767
3854
|
function recoverOutboxAfterAuthChange(db, config) {
|
|
3768
3855
|
const fingerprint = getAuthFingerprint(config);
|
|
3769
3856
|
if (!fingerprint) {
|
|
@@ -3782,6 +3869,7 @@ function recoverOutboxAfterAuthChange(db, config) {
|
|
|
3782
3869
|
const syncingReset = resetSyncingEntries(db);
|
|
3783
3870
|
const staleSyncingReset = 0;
|
|
3784
3871
|
db.setSyncState(key, fingerprint);
|
|
3872
|
+
clearSyncPushBlock(db);
|
|
3785
3873
|
return { fingerprintChanged: true, failedReset, authFailedReset: 0, syncingReset, staleSyncingReset };
|
|
3786
3874
|
}
|
|
3787
3875
|
function buildSourceId(config, localId, type = "obs") {
|