@merittdev/horus 0.15.1 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1292 -621
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -8167,27 +8167,27 @@ var require_bson = __commonJS({
|
|
|
8167
8167
|
return new _Long(lowBits, highBits, unsigned);
|
|
8168
8168
|
}
|
|
8169
8169
|
static fromInt(value, unsigned) {
|
|
8170
|
-
let obj, cachedObj,
|
|
8170
|
+
let obj, cachedObj, cache2;
|
|
8171
8171
|
if (unsigned) {
|
|
8172
8172
|
value >>>= 0;
|
|
8173
|
-
if (
|
|
8173
|
+
if (cache2 = 0 <= value && value < 256) {
|
|
8174
8174
|
cachedObj = UINT_CACHE[value];
|
|
8175
8175
|
if (cachedObj)
|
|
8176
8176
|
return cachedObj;
|
|
8177
8177
|
}
|
|
8178
8178
|
obj = _Long.fromBits(value, (value | 0) < 0 ? -1 : 0, true);
|
|
8179
|
-
if (
|
|
8179
|
+
if (cache2)
|
|
8180
8180
|
UINT_CACHE[value] = obj;
|
|
8181
8181
|
return obj;
|
|
8182
8182
|
} else {
|
|
8183
8183
|
value |= 0;
|
|
8184
|
-
if (
|
|
8184
|
+
if (cache2 = -128 <= value && value < 128) {
|
|
8185
8185
|
cachedObj = INT_CACHE[value];
|
|
8186
8186
|
if (cachedObj)
|
|
8187
8187
|
return cachedObj;
|
|
8188
8188
|
}
|
|
8189
8189
|
obj = _Long.fromBits(value, value < 0 ? -1 : 0, false);
|
|
8190
|
-
if (
|
|
8190
|
+
if (cache2)
|
|
8191
8191
|
INT_CACHE[value] = obj;
|
|
8192
8192
|
return obj;
|
|
8193
8193
|
}
|
|
@@ -14538,10 +14538,10 @@ var require_utils = __commonJS({
|
|
|
14538
14538
|
function squashError(_error) {
|
|
14539
14539
|
return;
|
|
14540
14540
|
}
|
|
14541
|
-
var
|
|
14541
|
+
var randomBytes2 = (size2) => {
|
|
14542
14542
|
return Promise.resolve(crypto.getRandomValues(new Uint8Array(size2)));
|
|
14543
14543
|
};
|
|
14544
|
-
exports2.randomBytes =
|
|
14544
|
+
exports2.randomBytes = randomBytes2;
|
|
14545
14545
|
async function once(ee3, name2, options) {
|
|
14546
14546
|
options?.signal?.throwIfAborted();
|
|
14547
14547
|
const { promise, resolve: resolve13, reject } = promiseWithResolvers();
|
|
@@ -23435,9 +23435,9 @@ var require_client_metadata = __commonJS({
|
|
|
23435
23435
|
throw new error_1.MongoInvalidArgumentError("Unable to include driverInfo name and version, metadata cannot exceed 512 bytes");
|
|
23436
23436
|
}
|
|
23437
23437
|
let runtimeInfo = getRuntimeInfo();
|
|
23438
|
-
for (const { platform:
|
|
23439
|
-
if (
|
|
23440
|
-
runtimeInfo = `${runtimeInfo}|${
|
|
23438
|
+
for (const { platform: platform3 = "" } of driverInfoList) {
|
|
23439
|
+
if (platform3.length > 0) {
|
|
23440
|
+
runtimeInfo = `${runtimeInfo}|${platform3}`;
|
|
23441
23441
|
}
|
|
23442
23442
|
}
|
|
23443
23443
|
if (!metadataDocument.ifItFitsItSits("platform", runtimeInfo)) {
|
|
@@ -34620,8 +34620,8 @@ var require_callback_workflow = __commonJS({
|
|
|
34620
34620
|
/**
|
|
34621
34621
|
* Instantiate the callback workflow.
|
|
34622
34622
|
*/
|
|
34623
|
-
constructor(
|
|
34624
|
-
this.cache =
|
|
34623
|
+
constructor(cache2, callback) {
|
|
34624
|
+
this.cache = cache2;
|
|
34625
34625
|
this.callback = this.withLock(callback);
|
|
34626
34626
|
this.lastExecutionTime = Date.now() - THROTTLE_MS;
|
|
34627
34627
|
}
|
|
@@ -34731,8 +34731,8 @@ var require_automated_callback_workflow = __commonJS({
|
|
|
34731
34731
|
/**
|
|
34732
34732
|
* Instantiate the human callback workflow.
|
|
34733
34733
|
*/
|
|
34734
|
-
constructor(
|
|
34735
|
-
super(
|
|
34734
|
+
constructor(cache2, callback) {
|
|
34735
|
+
super(cache2, callback);
|
|
34736
34736
|
}
|
|
34737
34737
|
/**
|
|
34738
34738
|
* Execute the OIDC callback workflow.
|
|
@@ -35068,8 +35068,8 @@ var require_human_callback_workflow = __commonJS({
|
|
|
35068
35068
|
/**
|
|
35069
35069
|
* Instantiate the human callback workflow.
|
|
35070
35070
|
*/
|
|
35071
|
-
constructor(
|
|
35072
|
-
super(
|
|
35071
|
+
constructor(cache2, callback) {
|
|
35072
|
+
super(cache2, callback);
|
|
35073
35073
|
}
|
|
35074
35074
|
/**
|
|
35075
35075
|
* Execute the OIDC human callback workflow.
|
|
@@ -40701,7 +40701,7 @@ var require_utils4 = __commonJS({
|
|
|
40701
40701
|
var nodeCrypto = require("crypto");
|
|
40702
40702
|
module2.exports = {
|
|
40703
40703
|
postgresMd5PasswordHash,
|
|
40704
|
-
randomBytes,
|
|
40704
|
+
randomBytes: randomBytes2,
|
|
40705
40705
|
deriveKey,
|
|
40706
40706
|
sha256: sha2562,
|
|
40707
40707
|
hashByName,
|
|
@@ -40711,7 +40711,7 @@ var require_utils4 = __commonJS({
|
|
|
40711
40711
|
var webCrypto = nodeCrypto.webcrypto || globalThis.crypto;
|
|
40712
40712
|
var subtleCrypto = webCrypto.subtle;
|
|
40713
40713
|
var textEncoder = new TextEncoder();
|
|
40714
|
-
function
|
|
40714
|
+
function randomBytes2(length) {
|
|
40715
40715
|
return webCrypto.getRandomValues(Buffer.alloc(length));
|
|
40716
40716
|
}
|
|
40717
40717
|
async function md52(string3) {
|
|
@@ -65880,7 +65880,7 @@ init_cjs_shims();
|
|
|
65880
65880
|
|
|
65881
65881
|
// ../../packages/core/src/version.ts
|
|
65882
65882
|
init_cjs_shims();
|
|
65883
|
-
var HORUS_VERSION = true ? "0.
|
|
65883
|
+
var HORUS_VERSION = true ? "0.16.0" : "dev";
|
|
65884
65884
|
var PINNED_SOURCE_VERSION = "2.0.2";
|
|
65885
65885
|
|
|
65886
65886
|
// ../../packages/core/src/evidence.ts
|
|
@@ -69976,47 +69976,375 @@ function createJiti(id, opts = {}) {
|
|
|
69976
69976
|
}
|
|
69977
69977
|
|
|
69978
69978
|
// ../../packages/core/src/config.ts
|
|
69979
|
-
var
|
|
69980
|
-
var
|
|
69979
|
+
var import_node_path3 = require("path");
|
|
69980
|
+
var import_node_fs3 = require("fs");
|
|
69981
69981
|
var import_node_url = require("url");
|
|
69982
69982
|
|
|
69983
69983
|
// ../../packages/core/src/discovery.ts
|
|
69984
69984
|
init_cjs_shims();
|
|
69985
|
+
var import_node_fs2 = require("fs");
|
|
69986
|
+
var import_node_path2 = require("path");
|
|
69987
|
+
var import_node_os2 = require("os");
|
|
69988
|
+
|
|
69989
|
+
// ../../packages/core/src/secrets.ts
|
|
69990
|
+
init_cjs_shims();
|
|
69991
|
+
var import_node_crypto = require("crypto");
|
|
69992
|
+
var import_node_child_process = require("child_process");
|
|
69985
69993
|
var import_node_fs = require("fs");
|
|
69986
|
-
var import_node_path = require("path");
|
|
69987
69994
|
var import_node_os = require("os");
|
|
69995
|
+
var import_node_path = require("path");
|
|
69996
|
+
var MasterKeyUnavailableError = class extends Error {
|
|
69997
|
+
constructor(message) {
|
|
69998
|
+
super(message);
|
|
69999
|
+
this.name = "MasterKeyUnavailableError";
|
|
70000
|
+
}
|
|
70001
|
+
};
|
|
70002
|
+
function isEncryptedSecret(v4) {
|
|
70003
|
+
if (typeof v4 !== "object" || v4 === null) return false;
|
|
70004
|
+
const o5 = v4;
|
|
70005
|
+
return o5["v"] === 1 && o5["alg"] === "aes-256-gcm" && typeof o5["kid"] === "string" && typeof o5["iv"] === "string" && typeof o5["ct"] === "string" && typeof o5["tag"] === "string";
|
|
70006
|
+
}
|
|
70007
|
+
var ENV_VAR = "HORUS_SECRET_KEY";
|
|
70008
|
+
var KEY_SERVICE = "horus";
|
|
70009
|
+
var KEY_ACCOUNT = "master-key";
|
|
70010
|
+
var KEY_LABEL = "Horus connector-secret master key";
|
|
70011
|
+
var KDF_SALT = Buffer.from("horus.secret.kdf.v1");
|
|
70012
|
+
var KEY_BYTES = 32;
|
|
70013
|
+
var IV_BYTES = 12;
|
|
70014
|
+
var CMD_TIMEOUT_MS = 4e3;
|
|
70015
|
+
var cachedKey = null;
|
|
70016
|
+
var cachedSource = null;
|
|
70017
|
+
function fingerprint(key) {
|
|
70018
|
+
return (0, import_node_crypto.createHash)("sha256").update(key).digest("hex").slice(0, 16);
|
|
70019
|
+
}
|
|
70020
|
+
function keyFromEnvValue(value) {
|
|
70021
|
+
const trimmed = value.trim();
|
|
70022
|
+
try {
|
|
70023
|
+
const decoded = Buffer.from(trimmed, "base64");
|
|
70024
|
+
if (decoded.length === KEY_BYTES && decoded.toString("base64") === trimmed) {
|
|
70025
|
+
return decoded;
|
|
70026
|
+
}
|
|
70027
|
+
} catch {
|
|
70028
|
+
}
|
|
70029
|
+
return (0, import_node_crypto.scryptSync)(trimmed, KDF_SALT, KEY_BYTES);
|
|
70030
|
+
}
|
|
70031
|
+
function keyringDir() {
|
|
70032
|
+
return (0, import_node_path.join)((0, import_node_os.homedir)(), ".horus", "keyring");
|
|
70033
|
+
}
|
|
70034
|
+
function keyFilePath() {
|
|
70035
|
+
return (0, import_node_path.join)(keyringDir(), "master.key");
|
|
70036
|
+
}
|
|
70037
|
+
function dpapiBlobPath() {
|
|
70038
|
+
return (0, import_node_path.join)(keyringDir(), "master.key.dpapi");
|
|
70039
|
+
}
|
|
70040
|
+
function macKeychainGet() {
|
|
70041
|
+
try {
|
|
70042
|
+
const out2 = (0, import_node_child_process.execFileSync)(
|
|
70043
|
+
"security",
|
|
70044
|
+
["find-generic-password", "-s", KEY_SERVICE, "-a", KEY_ACCOUNT, "-w"],
|
|
70045
|
+
{ stdio: ["ignore", "pipe", "ignore"], timeout: CMD_TIMEOUT_MS }
|
|
70046
|
+
);
|
|
70047
|
+
const v4 = out2.toString("utf8").trim();
|
|
70048
|
+
return v4.length > 0 ? v4 : null;
|
|
70049
|
+
} catch {
|
|
70050
|
+
return null;
|
|
70051
|
+
}
|
|
70052
|
+
}
|
|
70053
|
+
function macKeychainSet(b64) {
|
|
70054
|
+
try {
|
|
70055
|
+
(0, import_node_child_process.execFileSync)(
|
|
70056
|
+
"security",
|
|
70057
|
+
[
|
|
70058
|
+
"add-generic-password",
|
|
70059
|
+
"-U",
|
|
70060
|
+
// update if it already exists
|
|
70061
|
+
"-s",
|
|
70062
|
+
KEY_SERVICE,
|
|
70063
|
+
"-a",
|
|
70064
|
+
KEY_ACCOUNT,
|
|
70065
|
+
"-l",
|
|
70066
|
+
KEY_LABEL,
|
|
70067
|
+
"-w",
|
|
70068
|
+
b64
|
|
70069
|
+
],
|
|
70070
|
+
{ stdio: "ignore", timeout: CMD_TIMEOUT_MS }
|
|
70071
|
+
);
|
|
70072
|
+
return true;
|
|
70073
|
+
} catch {
|
|
70074
|
+
return false;
|
|
70075
|
+
}
|
|
70076
|
+
}
|
|
70077
|
+
function linuxKeychainGet() {
|
|
70078
|
+
try {
|
|
70079
|
+
const out2 = (0, import_node_child_process.execFileSync)(
|
|
70080
|
+
"secret-tool",
|
|
70081
|
+
["lookup", "service", KEY_SERVICE, "account", KEY_ACCOUNT],
|
|
70082
|
+
{ stdio: ["ignore", "pipe", "ignore"], timeout: CMD_TIMEOUT_MS }
|
|
70083
|
+
);
|
|
70084
|
+
const v4 = out2.toString("utf8").trim();
|
|
70085
|
+
return v4.length > 0 ? v4 : null;
|
|
70086
|
+
} catch {
|
|
70087
|
+
return null;
|
|
70088
|
+
}
|
|
70089
|
+
}
|
|
70090
|
+
function linuxKeychainSet(b64) {
|
|
70091
|
+
try {
|
|
70092
|
+
(0, import_node_child_process.execFileSync)(
|
|
70093
|
+
"secret-tool",
|
|
70094
|
+
["store", "--label", KEY_LABEL, "service", KEY_SERVICE, "account", KEY_ACCOUNT],
|
|
70095
|
+
{ input: b64, stdio: ["pipe", "ignore", "ignore"], timeout: CMD_TIMEOUT_MS }
|
|
70096
|
+
);
|
|
70097
|
+
return true;
|
|
70098
|
+
} catch {
|
|
70099
|
+
return false;
|
|
70100
|
+
}
|
|
70101
|
+
}
|
|
70102
|
+
function powershellBin() {
|
|
70103
|
+
for (const bin of ["powershell", "pwsh"]) {
|
|
70104
|
+
try {
|
|
70105
|
+
(0, import_node_child_process.execFileSync)(bin, ["-NoProfile", "-Command", "$PSVersionTable.PSVersion.Major"], {
|
|
70106
|
+
stdio: "ignore",
|
|
70107
|
+
timeout: CMD_TIMEOUT_MS
|
|
70108
|
+
});
|
|
70109
|
+
return bin;
|
|
70110
|
+
} catch {
|
|
70111
|
+
}
|
|
70112
|
+
}
|
|
70113
|
+
return null;
|
|
70114
|
+
}
|
|
70115
|
+
function winKeychainGet() {
|
|
70116
|
+
const ps = powershellBin();
|
|
70117
|
+
const blob = dpapiBlobPath();
|
|
70118
|
+
if (!ps || !(0, import_node_fs.existsSync)(blob)) return null;
|
|
70119
|
+
const script = `
|
|
70120
|
+
$enc = Get-Content -Path $env:HORUS_DPAPI_BLOB -Raw
|
|
70121
|
+
$sec = ConvertTo-SecureString $enc
|
|
70122
|
+
$ptr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec)
|
|
70123
|
+
try { [Console]::Out.Write([Runtime.InteropServices.Marshal]::PtrToStringBSTR($ptr)) }
|
|
70124
|
+
finally { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ptr) }`;
|
|
70125
|
+
try {
|
|
70126
|
+
const out2 = (0, import_node_child_process.execFileSync)(ps, ["-NoProfile", "-NonInteractive", "-Command", script], {
|
|
70127
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
70128
|
+
timeout: CMD_TIMEOUT_MS,
|
|
70129
|
+
env: { ...process.env, HORUS_DPAPI_BLOB: blob }
|
|
70130
|
+
});
|
|
70131
|
+
const v4 = out2.toString("utf8").trim();
|
|
70132
|
+
return v4.length > 0 ? v4 : null;
|
|
70133
|
+
} catch {
|
|
70134
|
+
return null;
|
|
70135
|
+
}
|
|
70136
|
+
}
|
|
70137
|
+
function winKeychainSet(b64) {
|
|
70138
|
+
const ps = powershellBin();
|
|
70139
|
+
if (!ps) return false;
|
|
70140
|
+
(0, import_node_fs.mkdirSync)(keyringDir(), { recursive: true });
|
|
70141
|
+
const blob = dpapiBlobPath();
|
|
70142
|
+
const script = `
|
|
70143
|
+
$sec = ConvertTo-SecureString $env:HORUS_DPAPI_KEY -AsPlainText -Force
|
|
70144
|
+
$enc = ConvertFrom-SecureString $sec
|
|
70145
|
+
Set-Content -Path $env:HORUS_DPAPI_BLOB -Value $enc -NoNewline`;
|
|
70146
|
+
try {
|
|
70147
|
+
(0, import_node_child_process.execFileSync)(ps, ["-NoProfile", "-NonInteractive", "-Command", script], {
|
|
70148
|
+
stdio: "ignore",
|
|
70149
|
+
timeout: CMD_TIMEOUT_MS,
|
|
70150
|
+
env: { ...process.env, HORUS_DPAPI_KEY: b64, HORUS_DPAPI_BLOB: blob }
|
|
70151
|
+
});
|
|
70152
|
+
return true;
|
|
70153
|
+
} catch {
|
|
70154
|
+
return false;
|
|
70155
|
+
}
|
|
70156
|
+
}
|
|
70157
|
+
function osKeychainGet() {
|
|
70158
|
+
switch ((0, import_node_os.platform)()) {
|
|
70159
|
+
case "darwin":
|
|
70160
|
+
return macKeychainGet();
|
|
70161
|
+
case "linux":
|
|
70162
|
+
return linuxKeychainGet();
|
|
70163
|
+
case "win32":
|
|
70164
|
+
return winKeychainGet();
|
|
70165
|
+
default:
|
|
70166
|
+
return null;
|
|
70167
|
+
}
|
|
70168
|
+
}
|
|
70169
|
+
function osKeychainSet(b64) {
|
|
70170
|
+
switch ((0, import_node_os.platform)()) {
|
|
70171
|
+
case "darwin":
|
|
70172
|
+
return macKeychainSet(b64);
|
|
70173
|
+
case "linux":
|
|
70174
|
+
return linuxKeychainSet(b64);
|
|
70175
|
+
case "win32":
|
|
70176
|
+
return winKeychainSet(b64);
|
|
70177
|
+
default:
|
|
70178
|
+
return false;
|
|
70179
|
+
}
|
|
70180
|
+
}
|
|
70181
|
+
function keyFileGet() {
|
|
70182
|
+
const p5 = keyFilePath();
|
|
70183
|
+
if (!(0, import_node_fs.existsSync)(p5)) return null;
|
|
70184
|
+
try {
|
|
70185
|
+
const v4 = (0, import_node_fs.readFileSync)(p5, "utf8").trim();
|
|
70186
|
+
return v4.length > 0 ? v4 : null;
|
|
70187
|
+
} catch {
|
|
70188
|
+
return null;
|
|
70189
|
+
}
|
|
70190
|
+
}
|
|
70191
|
+
function keyFileSet(b64) {
|
|
70192
|
+
try {
|
|
70193
|
+
(0, import_node_fs.mkdirSync)(keyringDir(), { recursive: true });
|
|
70194
|
+
const p5 = keyFilePath();
|
|
70195
|
+
(0, import_node_fs.writeFileSync)(p5, b64 + "\n", { mode: 384 });
|
|
70196
|
+
(0, import_node_fs.chmodSync)(p5, 384);
|
|
70197
|
+
return true;
|
|
70198
|
+
} catch {
|
|
70199
|
+
return false;
|
|
70200
|
+
}
|
|
70201
|
+
}
|
|
70202
|
+
function cache(key, source) {
|
|
70203
|
+
cachedKey = key;
|
|
70204
|
+
cachedSource = source;
|
|
70205
|
+
return { key, source };
|
|
70206
|
+
}
|
|
70207
|
+
function resolveExistingKey() {
|
|
70208
|
+
if (cachedKey && cachedSource) return { key: cachedKey, source: cachedSource };
|
|
70209
|
+
const envVal = process.env[ENV_VAR];
|
|
70210
|
+
if (envVal && envVal.trim().length > 0) {
|
|
70211
|
+
return cache(keyFromEnvValue(envVal), "env");
|
|
70212
|
+
}
|
|
70213
|
+
const fromKeychain = osKeychainGet();
|
|
70214
|
+
if (fromKeychain) {
|
|
70215
|
+
const key = Buffer.from(fromKeychain, "base64");
|
|
70216
|
+
if (key.length === KEY_BYTES) return cache(key, "keychain");
|
|
70217
|
+
}
|
|
70218
|
+
const fromFile = keyFileGet();
|
|
70219
|
+
if (fromFile) {
|
|
70220
|
+
const key = Buffer.from(fromFile, "base64");
|
|
70221
|
+
if (key.length === KEY_BYTES) return cache(key, "file");
|
|
70222
|
+
}
|
|
70223
|
+
return null;
|
|
70224
|
+
}
|
|
70225
|
+
function getMasterKeyForRead() {
|
|
70226
|
+
return resolveExistingKey()?.key ?? null;
|
|
70227
|
+
}
|
|
70228
|
+
function ensureMasterKey() {
|
|
70229
|
+
const existing = resolveExistingKey();
|
|
70230
|
+
if (existing) return { key: existing.key, source: existing.source };
|
|
70231
|
+
const key = (0, import_node_crypto.randomBytes)(KEY_BYTES);
|
|
70232
|
+
const b64 = key.toString("base64");
|
|
70233
|
+
if (osKeychainSet(b64)) {
|
|
70234
|
+
cache(key, "generated-keychain");
|
|
70235
|
+
return { key, source: "generated-keychain" };
|
|
70236
|
+
}
|
|
70237
|
+
if (keyFileSet(b64)) {
|
|
70238
|
+
cache(key, "generated-file");
|
|
70239
|
+
return {
|
|
70240
|
+
key,
|
|
70241
|
+
source: "generated-file",
|
|
70242
|
+
warning: `No OS keychain available \u2014 stored the master key at ${keyFilePath()} (mode 0600).
|
|
70243
|
+
It is in your home directory (never the repo), but is protected only by file permissions.
|
|
70244
|
+
For stronger isolation set ${ENV_VAR} to a passphrase, or run on a host with a keyring.`
|
|
70245
|
+
};
|
|
70246
|
+
}
|
|
70247
|
+
throw new MasterKeyUnavailableError(
|
|
70248
|
+
`Could not persist a master key (no keychain and ${keyFilePath()} is not writable). Set ${ENV_VAR} to a passphrase and retry.`
|
|
70249
|
+
);
|
|
70250
|
+
}
|
|
70251
|
+
function masterKeyStatus() {
|
|
70252
|
+
const existing = resolveExistingKey();
|
|
70253
|
+
if (!existing) {
|
|
70254
|
+
return {
|
|
70255
|
+
available: false,
|
|
70256
|
+
detail: `no master key yet \u2014 one is created on first \`horus connect\` (keychain, or ${ENV_VAR}).`
|
|
70257
|
+
};
|
|
70258
|
+
}
|
|
70259
|
+
const detail = {
|
|
70260
|
+
env: `${ENV_VAR} environment variable`,
|
|
70261
|
+
keychain: osKeychainLabel(),
|
|
70262
|
+
file: `key file ${keyFilePath()} (0600 fallback)`,
|
|
70263
|
+
"generated-keychain": osKeychainLabel(),
|
|
70264
|
+
"generated-file": `key file ${keyFilePath()} (0600 fallback)`
|
|
70265
|
+
};
|
|
70266
|
+
return { available: true, source: existing.source, detail: detail[existing.source] };
|
|
70267
|
+
}
|
|
70268
|
+
function osKeychainLabel() {
|
|
70269
|
+
switch ((0, import_node_os.platform)()) {
|
|
70270
|
+
case "darwin":
|
|
70271
|
+
return "macOS Keychain";
|
|
70272
|
+
case "linux":
|
|
70273
|
+
return "libsecret keyring (secret-tool)";
|
|
70274
|
+
case "win32":
|
|
70275
|
+
return "Windows DPAPI (user-scoped)";
|
|
70276
|
+
default:
|
|
70277
|
+
return "OS keychain";
|
|
70278
|
+
}
|
|
70279
|
+
}
|
|
70280
|
+
function encryptSecret(plaintext, key) {
|
|
70281
|
+
const k3 = key ?? ensureMasterKey().key;
|
|
70282
|
+
const iv = (0, import_node_crypto.randomBytes)(IV_BYTES);
|
|
70283
|
+
const cipher = (0, import_node_crypto.createCipheriv)("aes-256-gcm", k3, iv);
|
|
70284
|
+
const ct2 = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
|
|
70285
|
+
const tag = cipher.getAuthTag();
|
|
70286
|
+
return {
|
|
70287
|
+
v: 1,
|
|
70288
|
+
alg: "aes-256-gcm",
|
|
70289
|
+
kid: fingerprint(k3),
|
|
70290
|
+
iv: iv.toString("base64"),
|
|
70291
|
+
ct: ct2.toString("base64"),
|
|
70292
|
+
tag: tag.toString("base64")
|
|
70293
|
+
};
|
|
70294
|
+
}
|
|
70295
|
+
function decryptSecret(blob, key) {
|
|
70296
|
+
const k3 = key ?? getMasterKeyForRead();
|
|
70297
|
+
if (!k3) {
|
|
70298
|
+
throw new MasterKeyUnavailableError(
|
|
70299
|
+
`Cannot decrypt: master key not found (set ${ENV_VAR} or restore the OS keychain entry).`
|
|
70300
|
+
);
|
|
70301
|
+
}
|
|
70302
|
+
if (blob.kid !== fingerprint(k3)) {
|
|
70303
|
+
throw new Error(
|
|
70304
|
+
`Encrypted secret was sealed with a different master key (key fingerprint mismatch). Re-run \`horus connect\` to re-encrypt, or restore the original key.`
|
|
70305
|
+
);
|
|
70306
|
+
}
|
|
70307
|
+
const decipher = (0, import_node_crypto.createDecipheriv)("aes-256-gcm", k3, Buffer.from(blob.iv, "base64"));
|
|
70308
|
+
decipher.setAuthTag(Buffer.from(blob.tag, "base64"));
|
|
70309
|
+
return Buffer.concat([
|
|
70310
|
+
decipher.update(Buffer.from(blob.ct, "base64")),
|
|
70311
|
+
decipher.final()
|
|
70312
|
+
]).toString("utf8");
|
|
70313
|
+
}
|
|
70314
|
+
|
|
70315
|
+
// ../../packages/core/src/discovery.ts
|
|
69988
70316
|
var HORUS_DIR = ".horus";
|
|
69989
70317
|
var LOCAL_CONFIG_FILE = "config.json";
|
|
69990
70318
|
function localConfigPath(root) {
|
|
69991
|
-
return (0,
|
|
70319
|
+
return (0, import_node_path2.join)(root, HORUS_DIR, LOCAL_CONFIG_FILE);
|
|
69992
70320
|
}
|
|
69993
70321
|
function discoverLocalConfig(start2) {
|
|
69994
|
-
let dir = (0,
|
|
70322
|
+
let dir = (0, import_node_path2.resolve)(start2);
|
|
69995
70323
|
for (; ; ) {
|
|
69996
70324
|
const candidate = localConfigPath(dir);
|
|
69997
|
-
if ((0,
|
|
69998
|
-
const parent = (0,
|
|
70325
|
+
if ((0, import_node_fs2.existsSync)(candidate)) return candidate;
|
|
70326
|
+
const parent = (0, import_node_path2.dirname)(dir);
|
|
69999
70327
|
if (parent === dir) return null;
|
|
70000
70328
|
dir = parent;
|
|
70001
70329
|
}
|
|
70002
70330
|
}
|
|
70003
70331
|
function findRepoRoot(start2) {
|
|
70004
|
-
let dir = (0,
|
|
70332
|
+
let dir = (0, import_node_path2.resolve)(start2);
|
|
70005
70333
|
for (; ; ) {
|
|
70006
|
-
if ((0,
|
|
70007
|
-
const parent = (0,
|
|
70334
|
+
if ((0, import_node_fs2.existsSync)((0, import_node_path2.join)(dir, ".git"))) return dir;
|
|
70335
|
+
const parent = (0, import_node_path2.dirname)(dir);
|
|
70008
70336
|
if (parent === dir) return null;
|
|
70009
70337
|
dir = parent;
|
|
70010
70338
|
}
|
|
70011
70339
|
}
|
|
70012
70340
|
function registryPath() {
|
|
70013
|
-
return (0,
|
|
70341
|
+
return (0, import_node_path2.join)((0, import_node_os2.homedir)(), HORUS_DIR, "registry.json");
|
|
70014
70342
|
}
|
|
70015
70343
|
function readRegistry() {
|
|
70016
70344
|
const p5 = registryPath();
|
|
70017
|
-
if (!(0,
|
|
70345
|
+
if (!(0, import_node_fs2.existsSync)(p5)) return { projects: {} };
|
|
70018
70346
|
try {
|
|
70019
|
-
const parsed = JSON.parse((0,
|
|
70347
|
+
const parsed = JSON.parse((0, import_node_fs2.readFileSync)(p5, "utf8"));
|
|
70020
70348
|
return { projects: parsed.projects ?? {} };
|
|
70021
70349
|
} catch {
|
|
70022
70350
|
return { projects: {} };
|
|
@@ -70024,8 +70352,8 @@ function readRegistry() {
|
|
|
70024
70352
|
}
|
|
70025
70353
|
function writeRegistry(reg) {
|
|
70026
70354
|
const p5 = registryPath();
|
|
70027
|
-
(0,
|
|
70028
|
-
(0,
|
|
70355
|
+
(0, import_node_fs2.mkdirSync)((0, import_node_path2.dirname)(p5), { recursive: true });
|
|
70356
|
+
(0, import_node_fs2.writeFileSync)(p5, JSON.stringify(reg, null, 2) + "\n");
|
|
70029
70357
|
}
|
|
70030
70358
|
function registerProject(name2, root, configPath) {
|
|
70031
70359
|
const reg = readRegistry();
|
|
@@ -70036,72 +70364,97 @@ function lookupProject(name2) {
|
|
|
70036
70364
|
return readRegistry().projects[name2] ?? null;
|
|
70037
70365
|
}
|
|
70038
70366
|
function writeLocalConfig(root, file) {
|
|
70039
|
-
const dir = (0,
|
|
70040
|
-
(0,
|
|
70041
|
-
const p5 = (0,
|
|
70042
|
-
(0,
|
|
70043
|
-
(0,
|
|
70367
|
+
const dir = (0, import_node_path2.join)(root, HORUS_DIR);
|
|
70368
|
+
(0, import_node_fs2.mkdirSync)(dir, { recursive: true });
|
|
70369
|
+
const p5 = (0, import_node_path2.join)(dir, LOCAL_CONFIG_FILE);
|
|
70370
|
+
(0, import_node_fs2.writeFileSync)(p5, JSON.stringify(file, null, 2) + "\n", { mode: 384 });
|
|
70371
|
+
(0, import_node_fs2.chmodSync)(p5, 384);
|
|
70044
70372
|
return p5;
|
|
70045
70373
|
}
|
|
70046
|
-
function ensureCredentialGitignore(root) {
|
|
70047
|
-
const dir = (0, import_node_path.join)(root, HORUS_DIR);
|
|
70048
|
-
(0, import_node_fs.mkdirSync)(dir, { recursive: true });
|
|
70049
|
-
const gitignorePath = (0, import_node_path.join)(dir, ".gitignore");
|
|
70050
|
-
const entry2 = "config.json";
|
|
70051
|
-
if ((0, import_node_fs.existsSync)(gitignorePath)) {
|
|
70052
|
-
const existing = (0, import_node_fs.readFileSync)(gitignorePath, "utf8");
|
|
70053
|
-
if (existing.split("\n").some((l2) => l2.trim() === entry2)) return;
|
|
70054
|
-
(0, import_node_fs.writeFileSync)(gitignorePath, existing.trimEnd() + "\n" + entry2 + "\n");
|
|
70055
|
-
} else {
|
|
70056
|
-
(0, import_node_fs.writeFileSync)(gitignorePath, entry2 + "\n");
|
|
70057
|
-
}
|
|
70058
|
-
}
|
|
70059
70374
|
function readLocalConfig(path) {
|
|
70060
|
-
return JSON.parse((0,
|
|
70375
|
+
return JSON.parse((0, import_node_fs2.readFileSync)(path, "utf8"));
|
|
70061
70376
|
}
|
|
70062
70377
|
var LOCAL_SECRETS_FILE = "secrets.local.json";
|
|
70063
70378
|
function localSecretsPath(root) {
|
|
70064
|
-
return (0,
|
|
70379
|
+
return (0, import_node_path2.join)(root, HORUS_DIR, LOCAL_SECRETS_FILE);
|
|
70065
70380
|
}
|
|
70066
70381
|
function readLocalSecrets(root) {
|
|
70067
70382
|
const p5 = localSecretsPath(root);
|
|
70068
|
-
if (!(0,
|
|
70383
|
+
if (!(0, import_node_fs2.existsSync)(p5)) return {};
|
|
70069
70384
|
try {
|
|
70070
|
-
return JSON.parse((0,
|
|
70385
|
+
return JSON.parse((0, import_node_fs2.readFileSync)(p5, "utf8"));
|
|
70071
70386
|
} catch {
|
|
70072
70387
|
return {};
|
|
70073
70388
|
}
|
|
70074
70389
|
}
|
|
70075
70390
|
function writeLocalSecrets(root, secrets) {
|
|
70076
|
-
const dir = (0,
|
|
70077
|
-
(0,
|
|
70391
|
+
const dir = (0, import_node_path2.join)(root, HORUS_DIR);
|
|
70392
|
+
(0, import_node_fs2.mkdirSync)(dir, { recursive: true });
|
|
70078
70393
|
const p5 = localSecretsPath(root);
|
|
70079
|
-
(0,
|
|
70080
|
-
(0,
|
|
70081
|
-
const gitignorePath = (0,
|
|
70394
|
+
(0, import_node_fs2.writeFileSync)(p5, JSON.stringify(secrets, null, 2) + "\n", { mode: 384 });
|
|
70395
|
+
(0, import_node_fs2.chmodSync)(p5, 384);
|
|
70396
|
+
const gitignorePath = (0, import_node_path2.join)(dir, ".gitignore");
|
|
70082
70397
|
const entry2 = LOCAL_SECRETS_FILE;
|
|
70083
|
-
if ((0,
|
|
70084
|
-
const existing = (0,
|
|
70398
|
+
if ((0, import_node_fs2.existsSync)(gitignorePath)) {
|
|
70399
|
+
const existing = (0, import_node_fs2.readFileSync)(gitignorePath, "utf8");
|
|
70085
70400
|
if (!existing.split("\n").some((l2) => l2.trim() === entry2)) {
|
|
70086
|
-
(0,
|
|
70401
|
+
(0, import_node_fs2.writeFileSync)(gitignorePath, existing.trimEnd() + "\n" + entry2 + "\n");
|
|
70087
70402
|
}
|
|
70088
70403
|
} else {
|
|
70089
|
-
(0,
|
|
70404
|
+
(0, import_node_fs2.writeFileSync)(gitignorePath, entry2 + "\n");
|
|
70090
70405
|
}
|
|
70091
70406
|
return p5;
|
|
70092
70407
|
}
|
|
70408
|
+
function writeConnectorSecret(root, envName, connector, field, plaintext, key) {
|
|
70409
|
+
const secrets = readLocalSecrets(root);
|
|
70410
|
+
const blob = encryptSecret(plaintext, key);
|
|
70411
|
+
const byEnv = secrets.connectors ??= {};
|
|
70412
|
+
const byConnector = byEnv[envName] ??= {};
|
|
70413
|
+
const byField = byConnector[connector] ??= {};
|
|
70414
|
+
byField[field] = blob;
|
|
70415
|
+
writeLocalSecrets(root, secrets);
|
|
70416
|
+
ensureProjectGitignore(root);
|
|
70417
|
+
}
|
|
70418
|
+
function decryptConnectorSecrets(root) {
|
|
70419
|
+
const out2 = { values: {}, warnings: [] };
|
|
70420
|
+
const stored = readLocalSecrets(root).connectors;
|
|
70421
|
+
if (!stored) return out2;
|
|
70422
|
+
for (const [env, byConnector] of Object.entries(stored)) {
|
|
70423
|
+
for (const [connector, byField] of Object.entries(byConnector)) {
|
|
70424
|
+
for (const [field, blob] of Object.entries(byField)) {
|
|
70425
|
+
if (!isEncryptedSecret(blob)) continue;
|
|
70426
|
+
try {
|
|
70427
|
+
const plain = decryptSecret(blob);
|
|
70428
|
+
const e = out2.values[env] ??= {};
|
|
70429
|
+
const c4 = e[connector] ??= {};
|
|
70430
|
+
c4[field] = plain;
|
|
70431
|
+
} catch (err2) {
|
|
70432
|
+
const reason = err2 instanceof MasterKeyUnavailableError ? "no master key" : err2.message;
|
|
70433
|
+
out2.warnings.push(`${env}/${connector}.${field}: ${reason}`);
|
|
70434
|
+
}
|
|
70435
|
+
}
|
|
70436
|
+
}
|
|
70437
|
+
}
|
|
70438
|
+
return out2;
|
|
70439
|
+
}
|
|
70440
|
+
function isHorusGitignored(root) {
|
|
70441
|
+
if (!(0, import_node_fs2.existsSync)((0, import_node_path2.join)(root, ".git"))) return true;
|
|
70442
|
+
const gitignorePath = (0, import_node_path2.join)(root, ".gitignore");
|
|
70443
|
+
if (!(0, import_node_fs2.existsSync)(gitignorePath)) return false;
|
|
70444
|
+
return (0, import_node_fs2.readFileSync)(gitignorePath, "utf8").split("\n").map((l2) => l2.trim()).some((l2) => l2 === ".horus" || l2 === ".horus/" || l2 === "/.horus" || l2 === "/.horus/");
|
|
70445
|
+
}
|
|
70093
70446
|
function ensureProjectGitignore(root) {
|
|
70094
|
-
if (!(0,
|
|
70095
|
-
const gitignorePath = (0,
|
|
70447
|
+
if (!(0, import_node_fs2.existsSync)((0, import_node_path2.join)(root, ".git"))) return;
|
|
70448
|
+
const gitignorePath = (0, import_node_path2.join)(root, ".gitignore");
|
|
70096
70449
|
const entry2 = ".horus/";
|
|
70097
|
-
if (!(0,
|
|
70098
|
-
(0,
|
|
70450
|
+
if (!(0, import_node_fs2.existsSync)(gitignorePath)) {
|
|
70451
|
+
(0, import_node_fs2.writeFileSync)(gitignorePath, entry2 + "\n");
|
|
70099
70452
|
return;
|
|
70100
70453
|
}
|
|
70101
|
-
const existing = (0,
|
|
70454
|
+
const existing = (0, import_node_fs2.readFileSync)(gitignorePath, "utf8");
|
|
70102
70455
|
const alreadyIgnored = existing.split("\n").map((l2) => l2.trim()).some((l2) => l2 === ".horus" || l2 === ".horus/" || l2 === "/.horus" || l2 === "/.horus/");
|
|
70103
70456
|
if (alreadyIgnored) return;
|
|
70104
|
-
(0,
|
|
70457
|
+
(0, import_node_fs2.writeFileSync)(gitignorePath, existing.trimEnd() + "\n" + entry2 + "\n");
|
|
70105
70458
|
}
|
|
70106
70459
|
function patchLocalConnector(configPath, connectorType, patch, envName) {
|
|
70107
70460
|
const file = readLocalConfig(configPath);
|
|
@@ -70366,6 +70719,35 @@ function resolveAiSettings(config2) {
|
|
|
70366
70719
|
if (ai?.anthropic?.model !== void 0) out2.model = ai.anthropic.model;
|
|
70367
70720
|
return out2;
|
|
70368
70721
|
}
|
|
70722
|
+
var CONNECTOR_SECRET_FIELDS = {
|
|
70723
|
+
elasticsearch: ["username", "password"],
|
|
70724
|
+
mongodb: ["url"],
|
|
70725
|
+
postgres: ["url"],
|
|
70726
|
+
sentry: ["authToken"],
|
|
70727
|
+
axiom: ["token"],
|
|
70728
|
+
grafana: ["username", "password"],
|
|
70729
|
+
redis: ["url"]
|
|
70730
|
+
};
|
|
70731
|
+
function findPlaintextConnectorSecrets(project) {
|
|
70732
|
+
const out2 = [];
|
|
70733
|
+
const envs = project?.environments;
|
|
70734
|
+
if (!Array.isArray(envs)) return out2;
|
|
70735
|
+
for (const env of envs) {
|
|
70736
|
+
const envName = env["name"] ?? "(unnamed)";
|
|
70737
|
+
const connectors = env["connectors"];
|
|
70738
|
+
if (!connectors || typeof connectors !== "object") continue;
|
|
70739
|
+
for (const [connector, cfg] of Object.entries(connectors)) {
|
|
70740
|
+
if (!cfg || typeof cfg !== "object") continue;
|
|
70741
|
+
for (const field of CONNECTOR_SECRET_FIELDS[connector] ?? []) {
|
|
70742
|
+
const val = cfg[field];
|
|
70743
|
+
if (typeof val === "string" && val.length > 0) {
|
|
70744
|
+
out2.push(`${envName}/${connector}.${field}`);
|
|
70745
|
+
}
|
|
70746
|
+
}
|
|
70747
|
+
}
|
|
70748
|
+
}
|
|
70749
|
+
return out2;
|
|
70750
|
+
}
|
|
70369
70751
|
function listEnvironments(config2) {
|
|
70370
70752
|
const out2 = [];
|
|
70371
70753
|
for (const p5 of config2.projects) {
|
|
@@ -70392,9 +70774,9 @@ function resolveEnvironment(config2, opts) {
|
|
|
70392
70774
|
project = p5;
|
|
70393
70775
|
} else {
|
|
70394
70776
|
const cwd = opts?.cwd ?? process.cwd();
|
|
70395
|
-
const root = findRepoRoot(cwd) ?? (0,
|
|
70777
|
+
const root = findRepoRoot(cwd) ?? (0, import_node_path3.resolve)(cwd);
|
|
70396
70778
|
const matches = config2.projects.filter(
|
|
70397
|
-
(p5) => p5.repositories.some((r) => (0,
|
|
70779
|
+
(p5) => p5.repositories.some((r) => (0, import_node_path3.resolve)(r.path) === root)
|
|
70398
70780
|
);
|
|
70399
70781
|
const inferred = matches[0];
|
|
70400
70782
|
if (matches.length === 1 && inferred !== void 0) {
|
|
@@ -70572,15 +70954,41 @@ ${details}`);
|
|
|
70572
70954
|
}
|
|
70573
70955
|
return parsed.data;
|
|
70574
70956
|
}
|
|
70957
|
+
function hydrateConnectorSecrets(project, root) {
|
|
70958
|
+
const decrypted = decryptConnectorSecrets(root);
|
|
70959
|
+
for (const w4 of decrypted.warnings) {
|
|
70960
|
+
process.stderr.write(`horus: skipped encrypted connector secret (${w4})
|
|
70961
|
+
`);
|
|
70962
|
+
}
|
|
70963
|
+
if (Object.keys(decrypted.values).length === 0) return;
|
|
70964
|
+
const envs = project?.environments;
|
|
70965
|
+
if (!Array.isArray(envs)) return;
|
|
70966
|
+
for (const env of envs) {
|
|
70967
|
+
const envName = env["name"];
|
|
70968
|
+
if (!envName) continue;
|
|
70969
|
+
const byConnector = decrypted.values[envName];
|
|
70970
|
+
if (!byConnector) continue;
|
|
70971
|
+
const connectors = env["connectors"];
|
|
70972
|
+
if (!connectors || typeof connectors !== "object") continue;
|
|
70973
|
+
for (const [connector, fields] of Object.entries(byConnector)) {
|
|
70974
|
+
const target = connectors[connector];
|
|
70975
|
+
if (!target || typeof target !== "object") continue;
|
|
70976
|
+
for (const [field, value] of Object.entries(fields)) {
|
|
70977
|
+
target[field] = value;
|
|
70978
|
+
}
|
|
70979
|
+
}
|
|
70980
|
+
}
|
|
70981
|
+
}
|
|
70575
70982
|
async function loadConfigFile(target) {
|
|
70576
70983
|
if (target.endsWith(".json")) {
|
|
70577
70984
|
const file = readLocalConfig(target);
|
|
70578
|
-
const root = (0,
|
|
70985
|
+
const root = (0, import_node_path3.dirname)((0, import_node_path3.dirname)(target));
|
|
70579
70986
|
const secrets = readLocalSecrets(root);
|
|
70580
70987
|
let ai = file.ai;
|
|
70581
70988
|
if (secrets.anthropic?.apiKey) {
|
|
70582
70989
|
ai = { ...ai ?? {}, anthropic: { ...ai?.anthropic ?? {}, apiKey: secrets.anthropic.apiKey } };
|
|
70583
70990
|
}
|
|
70991
|
+
hydrateConnectorSecrets(file.project, root);
|
|
70584
70992
|
const raw = {
|
|
70585
70993
|
projects: file.project ? [file.project] : [],
|
|
70586
70994
|
database: file.database ?? {
|
|
@@ -70622,7 +71030,7 @@ async function loadConfig(configPath, opts) {
|
|
|
70622
71030
|
const cwd = opts?.cwd ?? process.cwd();
|
|
70623
71031
|
let target;
|
|
70624
71032
|
if (configPath) {
|
|
70625
|
-
target = (0,
|
|
71033
|
+
target = (0, import_node_path3.resolve)(configPath);
|
|
70626
71034
|
} else if (opts?.name) {
|
|
70627
71035
|
const entry2 = lookupProject(opts.name);
|
|
70628
71036
|
if (entry2 === null) {
|
|
@@ -70636,16 +71044,16 @@ async function loadConfig(configPath, opts) {
|
|
|
70636
71044
|
if (discovered) {
|
|
70637
71045
|
target = discovered;
|
|
70638
71046
|
} else if (process.env["HORUS_CONFIG"]) {
|
|
70639
|
-
target = (0,
|
|
71047
|
+
target = (0, import_node_path3.resolve)(process.env["HORUS_CONFIG"]);
|
|
70640
71048
|
} else {
|
|
70641
|
-
const jsPath = (0,
|
|
70642
|
-
const tsPath = (0,
|
|
70643
|
-
if (!(0,
|
|
71049
|
+
const jsPath = (0, import_node_path3.resolve)(cwd, "config/horus.config.js");
|
|
71050
|
+
const tsPath = (0, import_node_path3.resolve)(cwd, "config/horus.config.ts");
|
|
71051
|
+
if (!(0, import_node_fs3.existsSync)(jsPath) && !(0, import_node_fs3.existsSync)(tsPath)) {
|
|
70644
71052
|
throw new Error(
|
|
70645
71053
|
`No Horus config found for ${cwd}. Run \`horus index\` in this repo to set it up, or pass --config <path> / --name <project>.`
|
|
70646
71054
|
);
|
|
70647
71055
|
}
|
|
70648
|
-
target = (0,
|
|
71056
|
+
target = (0, import_node_fs3.existsSync)(jsPath) ? jsPath : tsPath;
|
|
70649
71057
|
}
|
|
70650
71058
|
}
|
|
70651
71059
|
return loadConfigFile(target);
|
|
@@ -70653,11 +71061,11 @@ async function loadConfig(configPath, opts) {
|
|
|
70653
71061
|
|
|
70654
71062
|
// ../../packages/core/src/git.ts
|
|
70655
71063
|
init_cjs_shims();
|
|
70656
|
-
var
|
|
71064
|
+
var import_node_child_process2 = require("child_process");
|
|
70657
71065
|
function collectLocalChanges(opts) {
|
|
70658
71066
|
const cwd = opts?.cwd ?? process.cwd();
|
|
70659
71067
|
const baseRef = opts?.baseRef ?? "HEAD~1";
|
|
70660
|
-
const gitCheck = (0,
|
|
71068
|
+
const gitCheck = (0, import_node_child_process2.spawnSync)("git", ["rev-parse", "--git-dir"], {
|
|
70661
71069
|
cwd,
|
|
70662
71070
|
encoding: "utf8",
|
|
70663
71071
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -70666,14 +71074,14 @@ function collectLocalChanges(opts) {
|
|
|
70666
71074
|
return { kind: "no-git-repo", cwd };
|
|
70667
71075
|
}
|
|
70668
71076
|
const changedFiles = parseDiff(
|
|
70669
|
-
(0,
|
|
71077
|
+
(0, import_node_child_process2.spawnSync)("git", ["diff", "--name-status", `${baseRef}..HEAD`], {
|
|
70670
71078
|
cwd,
|
|
70671
71079
|
encoding: "utf8",
|
|
70672
71080
|
stdio: ["ignore", "pipe", "pipe"]
|
|
70673
71081
|
}).stdout ?? ""
|
|
70674
71082
|
);
|
|
70675
71083
|
const commits = parseLog(
|
|
70676
|
-
(0,
|
|
71084
|
+
(0, import_node_child_process2.spawnSync)("git", ["log", "--oneline", `${baseRef}..HEAD`], {
|
|
70677
71085
|
cwd,
|
|
70678
71086
|
encoding: "utf8",
|
|
70679
71087
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -70682,7 +71090,7 @@ function collectLocalChanges(opts) {
|
|
|
70682
71090
|
return { kind: "local-changes", baseRef, changedFiles, commits };
|
|
70683
71091
|
}
|
|
70684
71092
|
function runGit(args2, cwd) {
|
|
70685
|
-
const res = (0,
|
|
71093
|
+
const res = (0, import_node_child_process2.spawnSync)("git", args2, {
|
|
70686
71094
|
cwd: cwd ?? process.cwd(),
|
|
70687
71095
|
encoding: "utf8",
|
|
70688
71096
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -70698,7 +71106,7 @@ function getCurrentBranch(cwd) {
|
|
|
70698
71106
|
return runGit(["rev-parse", "--abbrev-ref", "HEAD"], cwd);
|
|
70699
71107
|
}
|
|
70700
71108
|
function isWorkingTreeDirty(cwd) {
|
|
70701
|
-
const res = (0,
|
|
71109
|
+
const res = (0, import_node_child_process2.spawnSync)("git", ["status", "--porcelain"], {
|
|
70702
71110
|
cwd: cwd ?? process.cwd(),
|
|
70703
71111
|
encoding: "utf8",
|
|
70704
71112
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -70833,18 +71241,18 @@ function redactOrDrop(input) {
|
|
|
70833
71241
|
|
|
70834
71242
|
// ../../packages/cli/src/lib/update-notifier.ts
|
|
70835
71243
|
init_cjs_shims();
|
|
70836
|
-
var
|
|
70837
|
-
var
|
|
70838
|
-
var
|
|
71244
|
+
var import_node_fs6 = require("fs");
|
|
71245
|
+
var import_node_path6 = require("path");
|
|
71246
|
+
var import_node_os4 = require("os");
|
|
70839
71247
|
var import_picocolors2 = __toESM(require_picocolors(), 1);
|
|
70840
71248
|
|
|
70841
71249
|
// ../../packages/cli/src/commands/update.ts
|
|
70842
71250
|
init_cjs_shims();
|
|
70843
|
-
var
|
|
70844
|
-
var
|
|
70845
|
-
var
|
|
70846
|
-
var
|
|
70847
|
-
var
|
|
71251
|
+
var import_node_fs5 = require("fs");
|
|
71252
|
+
var import_node_path5 = require("path");
|
|
71253
|
+
var import_node_os3 = require("os");
|
|
71254
|
+
var import_node_crypto2 = require("crypto");
|
|
71255
|
+
var import_node_child_process5 = require("child_process");
|
|
70848
71256
|
var import_node_util3 = require("util");
|
|
70849
71257
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
70850
71258
|
|
|
@@ -71082,12 +71490,12 @@ var SourceHttpClient = class {
|
|
|
71082
71490
|
|
|
71083
71491
|
// ../../packages/connectors/src/source/lifecycle.ts
|
|
71084
71492
|
init_cjs_shims();
|
|
71085
|
-
var
|
|
71493
|
+
var import_node_child_process3 = require("child_process");
|
|
71086
71494
|
var import_node_util = require("util");
|
|
71087
|
-
var
|
|
71088
|
-
var
|
|
71495
|
+
var import_node_fs4 = require("fs");
|
|
71496
|
+
var import_node_path4 = require("path");
|
|
71089
71497
|
var import_node_net = require("net");
|
|
71090
|
-
var exec = (0, import_node_util.promisify)(
|
|
71498
|
+
var exec = (0, import_node_util.promisify)(import_node_child_process3.execFile);
|
|
71091
71499
|
var SOURCE_BINARY = "horus-source";
|
|
71092
71500
|
async function resolveSourceBin() {
|
|
71093
71501
|
try {
|
|
@@ -71129,12 +71537,12 @@ async function assertSourceVersionPinned() {
|
|
|
71129
71537
|
}
|
|
71130
71538
|
}
|
|
71131
71539
|
function isAnalyzed(root) {
|
|
71132
|
-
return (0,
|
|
71540
|
+
return (0, import_node_fs4.existsSync)((0, import_node_path4.join)(root, ".horus", "source"));
|
|
71133
71541
|
}
|
|
71134
71542
|
var CURRENT_STORE_BACKEND = (process.env["HORUS_SOURCE_STORAGE_BACKEND"] ?? "sqlite").trim().toLowerCase();
|
|
71135
71543
|
function readSourceMeta(root) {
|
|
71136
71544
|
try {
|
|
71137
|
-
const raw = (0,
|
|
71545
|
+
const raw = (0, import_node_fs4.readFileSync)((0, import_node_path4.join)(root, ".horus", "source", "meta.json"), "utf8");
|
|
71138
71546
|
const j3 = JSON.parse(raw);
|
|
71139
71547
|
const stats = j3["stats"] ?? void 0;
|
|
71140
71548
|
return {
|
|
@@ -71154,7 +71562,7 @@ function metaHasEmbeddings(meta) {
|
|
|
71154
71562
|
}
|
|
71155
71563
|
function indexNeedsReanalyze(root) {
|
|
71156
71564
|
if (!isAnalyzed(root)) return null;
|
|
71157
|
-
if (CURRENT_STORE_BACKEND !== "kuzu" && (0,
|
|
71565
|
+
if (CURRENT_STORE_BACKEND !== "kuzu" && (0, import_node_fs4.existsSync)((0, import_node_path4.join)(root, ".horus", "source", "kuzu"))) {
|
|
71158
71566
|
return "legacy K\xF9zuDB store present";
|
|
71159
71567
|
}
|
|
71160
71568
|
const meta = readSourceMeta(root);
|
|
@@ -71188,20 +71596,20 @@ async function analyzeRepo(root) {
|
|
|
71188
71596
|
}
|
|
71189
71597
|
}
|
|
71190
71598
|
function readSourceHostUrl(root) {
|
|
71191
|
-
const p5 = (0,
|
|
71192
|
-
if (!(0,
|
|
71599
|
+
const p5 = (0, import_node_path4.join)(root, ".horus", "source", "host.json");
|
|
71600
|
+
if (!(0, import_node_fs4.existsSync)(p5)) return null;
|
|
71193
71601
|
try {
|
|
71194
|
-
const j3 = JSON.parse((0,
|
|
71602
|
+
const j3 = JSON.parse((0, import_node_fs4.readFileSync)(p5, "utf8"));
|
|
71195
71603
|
return typeof j3.host_url === "string" ? j3.host_url : null;
|
|
71196
71604
|
} catch {
|
|
71197
71605
|
return null;
|
|
71198
71606
|
}
|
|
71199
71607
|
}
|
|
71200
71608
|
function readSourceHostPid(root) {
|
|
71201
|
-
const p5 = (0,
|
|
71202
|
-
if (!(0,
|
|
71609
|
+
const p5 = (0, import_node_path4.join)(root, ".horus", "source", "host.json");
|
|
71610
|
+
if (!(0, import_node_fs4.existsSync)(p5)) return null;
|
|
71203
71611
|
try {
|
|
71204
|
-
const j3 = JSON.parse((0,
|
|
71612
|
+
const j3 = JSON.parse((0, import_node_fs4.readFileSync)(p5, "utf8"));
|
|
71205
71613
|
if (typeof j3.pid !== "number" || !Number.isInteger(j3.pid) || j3.pid <= 0) return null;
|
|
71206
71614
|
return {
|
|
71207
71615
|
pid: j3.pid,
|
|
@@ -71250,19 +71658,19 @@ async function findFreePort(start2 = 8420, end = 8520) {
|
|
|
71250
71658
|
}
|
|
71251
71659
|
var SPAWNED_HOST_FILE = "spawned-host.json";
|
|
71252
71660
|
function readSpawnedHost(root) {
|
|
71253
|
-
const p5 = (0,
|
|
71254
|
-
if (!(0,
|
|
71661
|
+
const p5 = (0, import_node_path4.join)(root, ".horus", SPAWNED_HOST_FILE);
|
|
71662
|
+
if (!(0, import_node_fs4.existsSync)(p5)) return null;
|
|
71255
71663
|
try {
|
|
71256
|
-
return JSON.parse((0,
|
|
71664
|
+
return JSON.parse((0, import_node_fs4.readFileSync)(p5, "utf8"));
|
|
71257
71665
|
} catch {
|
|
71258
71666
|
return null;
|
|
71259
71667
|
}
|
|
71260
71668
|
}
|
|
71261
71669
|
function startHost(root, port) {
|
|
71262
|
-
(0,
|
|
71263
|
-
const logPath = (0,
|
|
71264
|
-
const fd = (0,
|
|
71265
|
-
const child = (0,
|
|
71670
|
+
(0, import_node_fs4.mkdirSync)((0, import_node_path4.join)(root, ".horus"), { recursive: true });
|
|
71671
|
+
const logPath = (0, import_node_path4.join)(root, ".horus", "source-host.log");
|
|
71672
|
+
const fd = (0, import_node_fs4.openSync)(logPath, "a");
|
|
71673
|
+
const child = (0, import_node_child_process3.spawn)(SOURCE_BINARY, ["host", "--port", String(port)], {
|
|
71266
71674
|
cwd: root,
|
|
71267
71675
|
detached: true,
|
|
71268
71676
|
stdio: ["ignore", fd, fd]
|
|
@@ -71281,14 +71689,14 @@ function startHost(root, port) {
|
|
|
71281
71689
|
root,
|
|
71282
71690
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
71283
71691
|
};
|
|
71284
|
-
(0,
|
|
71692
|
+
(0, import_node_fs4.writeFileSync)((0, import_node_path4.join)(root, ".horus", SPAWNED_HOST_FILE), JSON.stringify(record2, null, 2) + "\n");
|
|
71285
71693
|
}
|
|
71286
71694
|
child.unref();
|
|
71287
71695
|
}
|
|
71288
71696
|
function removeSpawnedHostRecord(root) {
|
|
71289
|
-
const p5 = (0,
|
|
71697
|
+
const p5 = (0, import_node_path4.join)(root, ".horus", SPAWNED_HOST_FILE);
|
|
71290
71698
|
try {
|
|
71291
|
-
(0,
|
|
71699
|
+
(0, import_node_fs4.unlinkSync)(p5);
|
|
71292
71700
|
} catch {
|
|
71293
71701
|
}
|
|
71294
71702
|
}
|
|
@@ -71329,8 +71737,8 @@ function reconcileSpawnedHost(root, actualPort) {
|
|
|
71329
71737
|
const port = backend && Number.isFinite(backend.port) && backend.port > 0 ? backend.port : actualPort;
|
|
71330
71738
|
if (spawned.pid === pid && spawned.port === port) return;
|
|
71331
71739
|
const updated = { ...spawned, pid, port };
|
|
71332
|
-
(0,
|
|
71333
|
-
(0,
|
|
71740
|
+
(0, import_node_fs4.writeFileSync)(
|
|
71741
|
+
(0, import_node_path4.join)(root, ".horus", SPAWNED_HOST_FILE),
|
|
71334
71742
|
JSON.stringify(updated, null, 2) + "\n"
|
|
71335
71743
|
);
|
|
71336
71744
|
} catch {
|
|
@@ -71340,7 +71748,7 @@ async function waitForOwnHost(root, requestedUrl, timeoutMs = 45e3) {
|
|
|
71340
71748
|
const deadline = Date.now() + timeoutMs;
|
|
71341
71749
|
const servesThisRepo = async (url) => {
|
|
71342
71750
|
const served = await fetchHostRepoPath(url);
|
|
71343
|
-
return served === null || (0,
|
|
71751
|
+
return served === null || (0, import_node_path4.resolve)(served) === (0, import_node_path4.resolve)(root);
|
|
71344
71752
|
};
|
|
71345
71753
|
while (Date.now() < deadline) {
|
|
71346
71754
|
const candidates = [];
|
|
@@ -75160,9 +75568,9 @@ init_cjs_shims();
|
|
|
75160
75568
|
|
|
75161
75569
|
// ../../packages/connectors/src/git/provider.ts
|
|
75162
75570
|
init_cjs_shims();
|
|
75163
|
-
var
|
|
75571
|
+
var import_node_child_process4 = require("child_process");
|
|
75164
75572
|
var import_node_util2 = require("util");
|
|
75165
|
-
var exec2 = (0, import_node_util2.promisify)(
|
|
75573
|
+
var exec2 = (0, import_node_util2.promisify)(import_node_child_process4.execFile);
|
|
75166
75574
|
function parseGitLog(stdout) {
|
|
75167
75575
|
const commits = [];
|
|
75168
75576
|
if (!stdout.trim()) return commits;
|
|
@@ -75420,7 +75828,7 @@ async function redisServerStatus(renv) {
|
|
|
75420
75828
|
}
|
|
75421
75829
|
|
|
75422
75830
|
// ../../packages/cli/src/commands/update.ts
|
|
75423
|
-
var execFileAsync = (0, import_node_util3.promisify)(
|
|
75831
|
+
var execFileAsync = (0, import_node_util3.promisify)(import_node_child_process5.execFile);
|
|
75424
75832
|
async function ensureBackendPinned(write) {
|
|
75425
75833
|
let installed = null;
|
|
75426
75834
|
try {
|
|
@@ -75479,13 +75887,13 @@ async function fetchLatestRelease(_fetch = fetch) {
|
|
|
75479
75887
|
return res.json();
|
|
75480
75888
|
}
|
|
75481
75889
|
function sha256hex(buf) {
|
|
75482
|
-
return (0,
|
|
75890
|
+
return (0, import_node_crypto2.createHash)("sha256").update(buf).digest("hex");
|
|
75483
75891
|
}
|
|
75484
75892
|
function resolveBinaryPath() {
|
|
75485
75893
|
const raw = process.argv[1];
|
|
75486
75894
|
if (!raw) throw new Error("Cannot determine binary path from process.argv[1]");
|
|
75487
75895
|
try {
|
|
75488
|
-
return (0,
|
|
75896
|
+
return (0, import_node_fs5.realpathSync)(raw);
|
|
75489
75897
|
} catch {
|
|
75490
75898
|
return raw;
|
|
75491
75899
|
}
|
|
@@ -75571,37 +75979,37 @@ ${import_picocolors.default.bold("Horus update")}
|
|
|
75571
75979
|
write(` ${import_picocolors.default.red("\u2717")} ${e.message}`);
|
|
75572
75980
|
return 1;
|
|
75573
75981
|
}
|
|
75574
|
-
if (!(0,
|
|
75982
|
+
if (!(0, import_node_fs5.existsSync)(binaryPath)) {
|
|
75575
75983
|
write(` ${import_picocolors.default.red("\u2717")} Binary not found at ${binaryPath}`);
|
|
75576
75984
|
return 1;
|
|
75577
75985
|
}
|
|
75578
|
-
const tmpPath = (0,
|
|
75986
|
+
const tmpPath = (0, import_node_path5.join)((0, import_node_os3.tmpdir)(), `horus-update-${tag}-${process.pid}`);
|
|
75579
75987
|
const backupPath = `${binaryPath}.bak`;
|
|
75580
75988
|
try {
|
|
75581
|
-
(0,
|
|
75989
|
+
(0, import_node_fs5.writeFileSync)(tmpPath, binBuf, { mode: 493 });
|
|
75582
75990
|
} catch (e) {
|
|
75583
75991
|
write(` ${import_picocolors.default.red("\u2717")} Could not write to temp dir: ${e.message}`);
|
|
75584
75992
|
return 1;
|
|
75585
75993
|
}
|
|
75586
75994
|
try {
|
|
75587
|
-
(0,
|
|
75995
|
+
(0, import_node_fs5.renameSync)(binaryPath, backupPath);
|
|
75588
75996
|
try {
|
|
75589
|
-
(0,
|
|
75590
|
-
(0,
|
|
75997
|
+
(0, import_node_fs5.renameSync)(tmpPath, binaryPath);
|
|
75998
|
+
(0, import_node_fs5.chmodSync)(binaryPath, 493);
|
|
75591
75999
|
} catch (e) {
|
|
75592
76000
|
try {
|
|
75593
|
-
(0,
|
|
76001
|
+
(0, import_node_fs5.renameSync)(backupPath, binaryPath);
|
|
75594
76002
|
} catch {
|
|
75595
76003
|
}
|
|
75596
76004
|
throw e;
|
|
75597
76005
|
}
|
|
75598
76006
|
try {
|
|
75599
|
-
(0,
|
|
76007
|
+
(0, import_node_fs5.unlinkSync)(backupPath);
|
|
75600
76008
|
} catch {
|
|
75601
76009
|
}
|
|
75602
76010
|
} catch (e) {
|
|
75603
76011
|
try {
|
|
75604
|
-
(0,
|
|
76012
|
+
(0, import_node_fs5.unlinkSync)(tmpPath);
|
|
75605
76013
|
} catch {
|
|
75606
76014
|
}
|
|
75607
76015
|
const msg = e.message ?? String(e);
|
|
@@ -75623,7 +76031,7 @@ ${import_picocolors.default.bold("Horus update")}
|
|
|
75623
76031
|
}
|
|
75624
76032
|
|
|
75625
76033
|
// ../../packages/cli/src/lib/update-notifier.ts
|
|
75626
|
-
var CACHE_PATH = (0,
|
|
76034
|
+
var CACHE_PATH = (0, import_node_path6.join)((0, import_node_os4.homedir)(), ".horus", "update-check.json");
|
|
75627
76035
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
75628
76036
|
var RELEASES_API2 = "https://api.github.com/repos/meritt-dev/horus/releases/latest";
|
|
75629
76037
|
var FETCH_TIMEOUT_MS = 2500;
|
|
@@ -75639,7 +76047,7 @@ function formatHint(latest, current) {
|
|
|
75639
76047
|
}
|
|
75640
76048
|
function readCache(path) {
|
|
75641
76049
|
try {
|
|
75642
|
-
const j3 = JSON.parse((0,
|
|
76050
|
+
const j3 = JSON.parse((0, import_node_fs6.readFileSync)(path, "utf8"));
|
|
75643
76051
|
if (typeof j3["latest"] === "string" && typeof j3["lastCheckMs"] === "number") {
|
|
75644
76052
|
return { latest: j3["latest"], lastCheckMs: j3["lastCheckMs"] };
|
|
75645
76053
|
}
|
|
@@ -75647,22 +76055,22 @@ function readCache(path) {
|
|
|
75647
76055
|
}
|
|
75648
76056
|
return null;
|
|
75649
76057
|
}
|
|
75650
|
-
function writeCache(path,
|
|
76058
|
+
function writeCache(path, cache2) {
|
|
75651
76059
|
try {
|
|
75652
|
-
(0,
|
|
75653
|
-
(0,
|
|
76060
|
+
(0, import_node_fs6.mkdirSync)((0, import_node_path6.dirname)(path), { recursive: true });
|
|
76061
|
+
(0, import_node_fs6.writeFileSync)(path, JSON.stringify(cache2) + "\n", "utf8");
|
|
75654
76062
|
} catch {
|
|
75655
76063
|
}
|
|
75656
76064
|
}
|
|
75657
|
-
function decideNotification(
|
|
76065
|
+
function decideNotification(cache2, current, nowMs) {
|
|
75658
76066
|
let hint = null;
|
|
75659
|
-
if (
|
|
76067
|
+
if (cache2 && cache2.latest) {
|
|
75660
76068
|
try {
|
|
75661
|
-
if (isNewer(
|
|
76069
|
+
if (isNewer(cache2.latest, current)) hint = formatHint(cache2.latest, current);
|
|
75662
76070
|
} catch {
|
|
75663
76071
|
}
|
|
75664
76072
|
}
|
|
75665
|
-
const refreshDue =
|
|
76073
|
+
const refreshDue = cache2 === null || nowMs - cache2.lastCheckMs > CHECK_INTERVAL_MS;
|
|
75666
76074
|
return { hint, refreshDue };
|
|
75667
76075
|
}
|
|
75668
76076
|
async function refresh(path, nowMs) {
|
|
@@ -75688,8 +76096,8 @@ function maybeNotifyUpdate() {
|
|
|
75688
76096
|
try {
|
|
75689
76097
|
if (isSuppressed()) return;
|
|
75690
76098
|
const nowMs = Date.now();
|
|
75691
|
-
const
|
|
75692
|
-
const { hint, refreshDue } = decideNotification(
|
|
76099
|
+
const cache2 = readCache(CACHE_PATH);
|
|
76100
|
+
const { hint, refreshDue } = decideNotification(cache2, HORUS_VERSION, nowMs);
|
|
75693
76101
|
if (hint) process.stderr.write(hint);
|
|
75694
76102
|
if (refreshDue) void refresh(CACHE_PATH, nowMs);
|
|
75695
76103
|
} catch {
|
|
@@ -75698,9 +76106,9 @@ function maybeNotifyUpdate() {
|
|
|
75698
76106
|
|
|
75699
76107
|
// ../../packages/cli/src/lib/feedback-nudge.ts
|
|
75700
76108
|
init_cjs_shims();
|
|
75701
|
-
var
|
|
75702
|
-
var
|
|
75703
|
-
var
|
|
76109
|
+
var import_node_fs11 = require("fs");
|
|
76110
|
+
var import_node_path12 = require("path");
|
|
76111
|
+
var import_node_os8 = require("os");
|
|
75704
76112
|
var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
75705
76113
|
|
|
75706
76114
|
// ../../packages/db/src/index.ts
|
|
@@ -76751,7 +77159,7 @@ function sql(strings, ...params) {
|
|
|
76751
77159
|
return new SQL([new StringChunk(str3)]);
|
|
76752
77160
|
}
|
|
76753
77161
|
sql2.raw = raw;
|
|
76754
|
-
function
|
|
77162
|
+
function join21(chunks, separator) {
|
|
76755
77163
|
const result = [];
|
|
76756
77164
|
for (const [i3, chunk] of chunks.entries()) {
|
|
76757
77165
|
if (i3 > 0 && separator !== void 0) {
|
|
@@ -76761,7 +77169,7 @@ function sql(strings, ...params) {
|
|
|
76761
77169
|
}
|
|
76762
77170
|
return new SQL(result);
|
|
76763
77171
|
}
|
|
76764
|
-
sql2.join =
|
|
77172
|
+
sql2.join = join21;
|
|
76765
77173
|
function identifier(value) {
|
|
76766
77174
|
return new Name(value);
|
|
76767
77175
|
}
|
|
@@ -80352,7 +80760,7 @@ var PgSelectQueryBuilderBase = class extends TypedQueryBuilder {
|
|
|
80352
80760
|
return (table, on2) => {
|
|
80353
80761
|
const baseTableName = this.tableName;
|
|
80354
80762
|
const tableName = getTableLikeName(table);
|
|
80355
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
80763
|
+
if (typeof tableName === "string" && this.config.joins?.some((join21) => join21.alias === tableName)) {
|
|
80356
80764
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
80357
80765
|
}
|
|
80358
80766
|
if (!this.isPartialSelect) {
|
|
@@ -81364,7 +81772,7 @@ var PgUpdateBase = class extends QueryPromise {
|
|
|
81364
81772
|
createJoin(joinType) {
|
|
81365
81773
|
return (table, on2) => {
|
|
81366
81774
|
const tableName = getTableLikeName(table);
|
|
81367
|
-
if (typeof tableName === "string" && this.config.joins.some((
|
|
81775
|
+
if (typeof tableName === "string" && this.config.joins.some((join21) => join21.alias === tableName)) {
|
|
81368
81776
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
81369
81777
|
}
|
|
81370
81778
|
if (typeof on2 === "function") {
|
|
@@ -81460,10 +81868,10 @@ var PgUpdateBase = class extends QueryPromise {
|
|
|
81460
81868
|
const fromFields = this.getTableLikeFields(this.config.from);
|
|
81461
81869
|
fields[tableName] = fromFields;
|
|
81462
81870
|
}
|
|
81463
|
-
for (const
|
|
81464
|
-
const tableName2 = getTableLikeName(
|
|
81465
|
-
if (typeof tableName2 === "string" && !is(
|
|
81466
|
-
const fromFields = this.getTableLikeFields(
|
|
81871
|
+
for (const join21 of this.config.joins) {
|
|
81872
|
+
const tableName2 = getTableLikeName(join21.table);
|
|
81873
|
+
if (typeof tableName2 === "string" && !is(join21.table, SQL)) {
|
|
81874
|
+
const fromFields = this.getTableLikeFields(join21.table);
|
|
81467
81875
|
fields[tableName2] = fromFields;
|
|
81468
81876
|
}
|
|
81469
81877
|
}
|
|
@@ -90456,9 +90864,9 @@ function drizzle2(...params) {
|
|
|
90456
90864
|
})(drizzle2 || (drizzle2 = {}));
|
|
90457
90865
|
|
|
90458
90866
|
// ../../packages/db/src/client.ts
|
|
90459
|
-
var
|
|
90460
|
-
var
|
|
90461
|
-
var
|
|
90867
|
+
var import_node_os5 = require("os");
|
|
90868
|
+
var import_node_path7 = require("path");
|
|
90869
|
+
var import_node_fs7 = require("fs");
|
|
90462
90870
|
var import_node_url2 = require("url");
|
|
90463
90871
|
|
|
90464
90872
|
// ../../packages/db/src/guard.ts
|
|
@@ -90659,8 +91067,8 @@ function createDb(url, opts) {
|
|
|
90659
91067
|
return { db, sql: sql2 };
|
|
90660
91068
|
}
|
|
90661
91069
|
function localDbPath() {
|
|
90662
|
-
const dir = process.env["HORUS_DB_DIR"] || (0,
|
|
90663
|
-
return (0,
|
|
91070
|
+
const dir = process.env["HORUS_DB_DIR"] || (0, import_node_path7.join)((0, import_node_os5.homedir)(), ".horus");
|
|
91071
|
+
return (0, import_node_path7.join)(dir, "horus.db");
|
|
90664
91072
|
}
|
|
90665
91073
|
var DEFAULT_LOCAL_PG_URL = "postgresql://horus:horus@localhost:5433/horus";
|
|
90666
91074
|
function shouldUseEmbeddedDb(url) {
|
|
@@ -90719,7 +91127,7 @@ async function applyEmbeddedMigrations(client) {
|
|
|
90719
91127
|
async function createLocalDb(opts) {
|
|
90720
91128
|
const dataDir = opts?.path ?? localDbPath();
|
|
90721
91129
|
try {
|
|
90722
|
-
(0,
|
|
91130
|
+
(0, import_node_fs7.mkdirSync)(dataDir.replace(/[^/]+$/, ""), { recursive: true });
|
|
90723
91131
|
} catch {
|
|
90724
91132
|
}
|
|
90725
91133
|
assertEmbeddedAssetsPresent();
|
|
@@ -90752,20 +91160,20 @@ async function acquireDbLock(dataDir) {
|
|
|
90752
91160
|
};
|
|
90753
91161
|
for (; ; ) {
|
|
90754
91162
|
try {
|
|
90755
|
-
const fd = (0,
|
|
90756
|
-
(0,
|
|
90757
|
-
(0,
|
|
91163
|
+
const fd = (0, import_node_fs7.openSync)(lockPath, "wx");
|
|
91164
|
+
(0, import_node_fs7.writeSync)(fd, `${process.pid} ${Date.now()}`);
|
|
91165
|
+
(0, import_node_fs7.closeSync)(fd);
|
|
90758
91166
|
return () => {
|
|
90759
91167
|
try {
|
|
90760
|
-
(0,
|
|
91168
|
+
(0, import_node_fs7.unlinkSync)(lockPath);
|
|
90761
91169
|
} catch {
|
|
90762
91170
|
}
|
|
90763
91171
|
};
|
|
90764
91172
|
} catch (e) {
|
|
90765
91173
|
if (e.code !== "EEXIST") return noop3;
|
|
90766
91174
|
try {
|
|
90767
|
-
if (Date.now() - (0,
|
|
90768
|
-
(0,
|
|
91175
|
+
if (Date.now() - (0, import_node_fs7.statSync)(lockPath).mtimeMs > STALE_MS) {
|
|
91176
|
+
(0, import_node_fs7.unlinkSync)(lockPath);
|
|
90769
91177
|
continue;
|
|
90770
91178
|
}
|
|
90771
91179
|
} catch {
|
|
@@ -90779,9 +91187,9 @@ async function acquireDbLock(dataDir) {
|
|
|
90779
91187
|
var EMBEDDED_PGLITE_ASSETS = ["pglite.wasm", "pglite.data", "initdb.wasm"];
|
|
90780
91188
|
function assertEmbeddedAssetsPresent() {
|
|
90781
91189
|
if (false) return;
|
|
90782
|
-
const selfDir = (0,
|
|
91190
|
+
const selfDir = (0, import_node_path7.dirname)((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
90783
91191
|
for (const asset of EMBEDDED_PGLITE_ASSETS) {
|
|
90784
|
-
if (!(0,
|
|
91192
|
+
if (!(0, import_node_fs7.existsSync)((0, import_node_path7.join)(selfDir, asset))) {
|
|
90785
91193
|
throw new Error(
|
|
90786
91194
|
`HORUS_DB_UNAVAILABLE: embedded database asset missing (${asset}). This build does not ship local persistence \u2014 install via npm or Homebrew, or set DATABASE_URL.`
|
|
90787
91195
|
);
|
|
@@ -90931,21 +91339,21 @@ init_cjs_shims();
|
|
|
90931
91339
|
|
|
90932
91340
|
// ../../node_modules/.pnpm/drizzle-orm@0.38.4_@electric-sql+pglite@0.5.3_@types+pg@8.20.0_pg@8.22.0_postgres@3.4.9/node_modules/drizzle-orm/migrator.js
|
|
90933
91341
|
init_cjs_shims();
|
|
90934
|
-
var
|
|
90935
|
-
var
|
|
91342
|
+
var import_node_crypto3 = __toESM(require("crypto"), 1);
|
|
91343
|
+
var import_node_fs8 = __toESM(require("fs"), 1);
|
|
90936
91344
|
function readMigrationFiles(config2) {
|
|
90937
91345
|
const migrationFolderTo = config2.migrationsFolder;
|
|
90938
91346
|
const migrationQueries = [];
|
|
90939
91347
|
const journalPath = `${migrationFolderTo}/meta/_journal.json`;
|
|
90940
|
-
if (!
|
|
91348
|
+
if (!import_node_fs8.default.existsSync(journalPath)) {
|
|
90941
91349
|
throw new Error(`Can't find meta/_journal.json file`);
|
|
90942
91350
|
}
|
|
90943
|
-
const journalAsString =
|
|
91351
|
+
const journalAsString = import_node_fs8.default.readFileSync(`${migrationFolderTo}/meta/_journal.json`).toString();
|
|
90944
91352
|
const journal = JSON.parse(journalAsString);
|
|
90945
91353
|
for (const journalEntry of journal.entries) {
|
|
90946
91354
|
const migrationPath = `${migrationFolderTo}/${journalEntry.tag}.sql`;
|
|
90947
91355
|
try {
|
|
90948
|
-
const query =
|
|
91356
|
+
const query = import_node_fs8.default.readFileSync(`${migrationFolderTo}/${journalEntry.tag}.sql`).toString();
|
|
90949
91357
|
const result = query.split("--> statement-breakpoint").map((it2) => {
|
|
90950
91358
|
return it2;
|
|
90951
91359
|
});
|
|
@@ -90953,7 +91361,7 @@ function readMigrationFiles(config2) {
|
|
|
90953
91361
|
sql: result,
|
|
90954
91362
|
bps: journalEntry.breakpoints,
|
|
90955
91363
|
folderMillis: journalEntry.when,
|
|
90956
|
-
hash:
|
|
91364
|
+
hash: import_node_crypto3.default.createHash("sha256").update(query).digest("hex")
|
|
90957
91365
|
});
|
|
90958
91366
|
} catch {
|
|
90959
91367
|
throw new Error(`No file ${migrationPath} found in ${migrationFolderTo} folder`);
|
|
@@ -90970,8 +91378,8 @@ async function migrate(db, config2) {
|
|
|
90970
91378
|
|
|
90971
91379
|
// ../../packages/db/src/migrate.ts
|
|
90972
91380
|
var import_node_url3 = require("url");
|
|
90973
|
-
var
|
|
90974
|
-
var migrationsFolder = (0,
|
|
91381
|
+
var import_node_path8 = require("path");
|
|
91382
|
+
var migrationsFolder = (0, import_node_path8.resolve)((0, import_node_path8.dirname)((0, import_node_url3.fileURLToPath)(importMetaUrl)), "../drizzle");
|
|
90975
91383
|
async function runMigrations(url) {
|
|
90976
91384
|
assertLocalDatabaseUrl(url);
|
|
90977
91385
|
const sql2 = src_default(url, { max: 1, onnotice: () => {
|
|
@@ -90983,7 +91391,7 @@ async function runMigrations(url) {
|
|
|
90983
91391
|
}
|
|
90984
91392
|
}
|
|
90985
91393
|
var entry = process.argv[1];
|
|
90986
|
-
var invokedDirectly = entry !== void 0 && (0, import_node_url3.fileURLToPath)(importMetaUrl) === (0,
|
|
91394
|
+
var invokedDirectly = entry !== void 0 && (0, import_node_url3.fileURLToPath)(importMetaUrl) === (0, import_node_path8.resolve)(entry) && (0, import_node_path8.basename)(entry).replace(/\.[cm]?[jt]s$/, "") === "migrate";
|
|
90987
91395
|
if (invokedDirectly) {
|
|
90988
91396
|
const url = process.env.DATABASE_URL ?? "postgresql://horus:horus@localhost:5433/horus";
|
|
90989
91397
|
runMigrations(url).then(() => {
|
|
@@ -91053,43 +91461,43 @@ var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
|
91053
91461
|
|
|
91054
91462
|
// ../../packages/cli/src/lib/telemetry/client.ts
|
|
91055
91463
|
init_cjs_shims();
|
|
91056
|
-
var
|
|
91057
|
-
var
|
|
91464
|
+
var import_node_crypto5 = require("crypto");
|
|
91465
|
+
var import_node_os7 = require("os");
|
|
91058
91466
|
|
|
91059
91467
|
// ../../packages/cli/src/lib/telemetry/consent.ts
|
|
91060
91468
|
init_cjs_shims();
|
|
91061
91469
|
|
|
91062
91470
|
// ../../packages/cli/src/lib/telemetry/store.ts
|
|
91063
91471
|
init_cjs_shims();
|
|
91064
|
-
var
|
|
91065
|
-
var
|
|
91472
|
+
var import_node_fs9 = require("fs");
|
|
91473
|
+
var import_node_crypto4 = require("crypto");
|
|
91066
91474
|
|
|
91067
91475
|
// ../../packages/cli/src/lib/cloud/paths.ts
|
|
91068
91476
|
init_cjs_shims();
|
|
91069
|
-
var
|
|
91070
|
-
var
|
|
91477
|
+
var import_node_path9 = require("path");
|
|
91478
|
+
var import_node_os6 = require("os");
|
|
91071
91479
|
var CLOUD_CONFIG_FILE = "cloud.json";
|
|
91072
91480
|
var AUTH_FILE = "auth.json";
|
|
91073
91481
|
function cloudConfigPath(root) {
|
|
91074
|
-
return (0,
|
|
91482
|
+
return (0, import_node_path9.join)(root, HORUS_DIR, CLOUD_CONFIG_FILE);
|
|
91075
91483
|
}
|
|
91076
91484
|
function horusHome() {
|
|
91077
|
-
return process.env.HORUS_HOME ?? (0,
|
|
91485
|
+
return process.env.HORUS_HOME ?? (0, import_node_path9.join)((0, import_node_os6.homedir)(), HORUS_DIR);
|
|
91078
91486
|
}
|
|
91079
91487
|
function authPath() {
|
|
91080
|
-
return (0,
|
|
91488
|
+
return (0, import_node_path9.join)(horusHome(), AUTH_FILE);
|
|
91081
91489
|
}
|
|
91082
91490
|
|
|
91083
91491
|
// ../../packages/cli/src/lib/telemetry/paths.ts
|
|
91084
91492
|
init_cjs_shims();
|
|
91085
|
-
var
|
|
91493
|
+
var import_node_path10 = require("path");
|
|
91086
91494
|
var TELEMETRY_FILE = "telemetry.json";
|
|
91087
91495
|
var TELEMETRY_QUEUE_DIR = "telemetry-queue";
|
|
91088
91496
|
function telemetryPath() {
|
|
91089
|
-
return (0,
|
|
91497
|
+
return (0, import_node_path10.join)(horusHome(), TELEMETRY_FILE);
|
|
91090
91498
|
}
|
|
91091
91499
|
function telemetryQueueDir() {
|
|
91092
|
-
return (0,
|
|
91500
|
+
return (0, import_node_path10.join)(horusHome(), TELEMETRY_QUEUE_DIR);
|
|
91093
91501
|
}
|
|
91094
91502
|
|
|
91095
91503
|
// ../../packages/cli/src/lib/telemetry/store.ts
|
|
@@ -91097,7 +91505,7 @@ var TELEMETRY_SCHEMA_VERSION = 1;
|
|
|
91097
91505
|
function nowIso() {
|
|
91098
91506
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
91099
91507
|
}
|
|
91100
|
-
function defaultTelemetryState(installId = (0,
|
|
91508
|
+
function defaultTelemetryState(installId = (0, import_node_crypto4.randomUUID)()) {
|
|
91101
91509
|
const now = nowIso();
|
|
91102
91510
|
return {
|
|
91103
91511
|
schemaVersion: TELEMETRY_SCHEMA_VERSION,
|
|
@@ -91131,29 +91539,29 @@ function coerce2(raw) {
|
|
|
91131
91539
|
}
|
|
91132
91540
|
function readTelemetryState() {
|
|
91133
91541
|
const p5 = telemetryPath();
|
|
91134
|
-
if (!(0,
|
|
91542
|
+
if (!(0, import_node_fs9.existsSync)(p5)) return null;
|
|
91135
91543
|
try {
|
|
91136
|
-
return coerce2(JSON.parse((0,
|
|
91544
|
+
return coerce2(JSON.parse((0, import_node_fs9.readFileSync)(p5, "utf8")));
|
|
91137
91545
|
} catch {
|
|
91138
91546
|
return null;
|
|
91139
91547
|
}
|
|
91140
91548
|
}
|
|
91141
91549
|
function writeTelemetryState(state) {
|
|
91142
|
-
(0,
|
|
91550
|
+
(0, import_node_fs9.mkdirSync)(horusHome(), { recursive: true });
|
|
91143
91551
|
const p5 = telemetryPath();
|
|
91144
91552
|
const tmp = `${p5}.${process.pid}.tmp`;
|
|
91145
|
-
(0,
|
|
91553
|
+
(0, import_node_fs9.writeFileSync)(tmp, JSON.stringify(state, null, 2) + "\n", { mode: 384 });
|
|
91146
91554
|
try {
|
|
91147
|
-
(0,
|
|
91555
|
+
(0, import_node_fs9.renameSync)(tmp, p5);
|
|
91148
91556
|
} catch (err2) {
|
|
91149
91557
|
try {
|
|
91150
|
-
(0,
|
|
91558
|
+
(0, import_node_fs9.rmSync)(tmp);
|
|
91151
91559
|
} catch {
|
|
91152
91560
|
}
|
|
91153
91561
|
throw err2;
|
|
91154
91562
|
}
|
|
91155
91563
|
try {
|
|
91156
|
-
(0,
|
|
91564
|
+
(0, import_node_fs9.chmodSync)(p5, 384);
|
|
91157
91565
|
} catch {
|
|
91158
91566
|
}
|
|
91159
91567
|
}
|
|
@@ -91173,7 +91581,7 @@ function updateTelemetryState(mutate) {
|
|
|
91173
91581
|
}
|
|
91174
91582
|
function deleteTelemetryState() {
|
|
91175
91583
|
const p5 = telemetryPath();
|
|
91176
|
-
if ((0,
|
|
91584
|
+
if ((0, import_node_fs9.existsSync)(p5)) (0, import_node_fs9.rmSync)(p5);
|
|
91177
91585
|
}
|
|
91178
91586
|
|
|
91179
91587
|
// ../../packages/cli/src/lib/telemetry/consent.ts
|
|
@@ -91251,32 +91659,32 @@ function isContentSharingEnabled(env = process.env) {
|
|
|
91251
91659
|
|
|
91252
91660
|
// ../../packages/cli/src/lib/telemetry/spool.ts
|
|
91253
91661
|
init_cjs_shims();
|
|
91254
|
-
var
|
|
91255
|
-
var
|
|
91662
|
+
var import_node_fs10 = require("fs");
|
|
91663
|
+
var import_node_path11 = require("path");
|
|
91256
91664
|
var SPOOL_FILE = "events.jsonl";
|
|
91257
91665
|
var MAX_SPOOL_BYTES = 256 * 1024;
|
|
91258
91666
|
function spoolFilePath() {
|
|
91259
|
-
return (0,
|
|
91667
|
+
return (0, import_node_path11.join)(telemetryQueueDir(), SPOOL_FILE);
|
|
91260
91668
|
}
|
|
91261
91669
|
function spoolEvent(event) {
|
|
91262
91670
|
try {
|
|
91263
|
-
(0,
|
|
91671
|
+
(0, import_node_fs10.mkdirSync)(telemetryQueueDir(), { recursive: true });
|
|
91264
91672
|
const file = spoolFilePath();
|
|
91265
91673
|
let size2 = 0;
|
|
91266
91674
|
try {
|
|
91267
|
-
size2 = (0,
|
|
91675
|
+
size2 = (0, import_node_fs10.statSync)(file).size;
|
|
91268
91676
|
} catch {
|
|
91269
91677
|
}
|
|
91270
91678
|
if (size2 >= MAX_SPOOL_BYTES) return;
|
|
91271
|
-
(0,
|
|
91679
|
+
(0, import_node_fs10.appendFileSync)(file, JSON.stringify(event) + "\n", { mode: 384 });
|
|
91272
91680
|
} catch {
|
|
91273
91681
|
}
|
|
91274
91682
|
}
|
|
91275
91683
|
function readSpooledEvents() {
|
|
91276
91684
|
try {
|
|
91277
91685
|
const file = spoolFilePath();
|
|
91278
|
-
if (!(0,
|
|
91279
|
-
return (0,
|
|
91686
|
+
if (!(0, import_node_fs10.existsSync)(file)) return [];
|
|
91687
|
+
return (0, import_node_fs10.readFileSync)(file, "utf8").split("\n").filter((line2) => line2.trim().length > 0).map((line2) => {
|
|
91280
91688
|
try {
|
|
91281
91689
|
return JSON.parse(line2);
|
|
91282
91690
|
} catch {
|
|
@@ -91290,7 +91698,7 @@ function readSpooledEvents() {
|
|
|
91290
91698
|
function clearSpool() {
|
|
91291
91699
|
try {
|
|
91292
91700
|
const file = spoolFilePath();
|
|
91293
|
-
if ((0,
|
|
91701
|
+
if ((0, import_node_fs10.existsSync)(file)) (0, import_node_fs10.rmSync)(file);
|
|
91294
91702
|
} catch {
|
|
91295
91703
|
}
|
|
91296
91704
|
}
|
|
@@ -91316,7 +91724,7 @@ function extractFlagNames(argv) {
|
|
|
91316
91724
|
// ../../packages/cli/src/lib/telemetry/client.ts
|
|
91317
91725
|
var sessionId = null;
|
|
91318
91726
|
function getSessionId() {
|
|
91319
|
-
if (!sessionId) sessionId = (0,
|
|
91727
|
+
if (!sessionId) sessionId = (0, import_node_crypto5.randomUUID)();
|
|
91320
91728
|
return sessionId;
|
|
91321
91729
|
}
|
|
91322
91730
|
function track(input) {
|
|
@@ -91333,8 +91741,8 @@ function track(input) {
|
|
|
91333
91741
|
installId: state.installId,
|
|
91334
91742
|
sessionId: getSessionId(),
|
|
91335
91743
|
cliVersion: HORUS_VERSION,
|
|
91336
|
-
os: (0,
|
|
91337
|
-
arch: (0,
|
|
91744
|
+
os: (0, import_node_os7.platform)(),
|
|
91745
|
+
arch: (0, import_node_os7.arch)(),
|
|
91338
91746
|
...input
|
|
91339
91747
|
};
|
|
91340
91748
|
spoolEvent(event);
|
|
@@ -91484,7 +91892,7 @@ async function runFeedback(investigationId, opts = {}) {
|
|
|
91484
91892
|
}
|
|
91485
91893
|
|
|
91486
91894
|
// ../../packages/cli/src/lib/feedback-nudge.ts
|
|
91487
|
-
var STATE_PATH = (0,
|
|
91895
|
+
var STATE_PATH = (0, import_node_path12.join)((0, import_node_os8.homedir)(), ".horus", "feedback-nudge.json");
|
|
91488
91896
|
var MIN_AGE_MS = 2 * 60 * 60 * 1e3;
|
|
91489
91897
|
var RATE_LIMIT_MS = 20 * 60 * 60 * 1e3;
|
|
91490
91898
|
var MAX_REMEMBERED = 50;
|
|
@@ -91500,7 +91908,7 @@ function isSuppressed2(env = process.env, isTTY = Boolean(process.stdin.isTTY &&
|
|
|
91500
91908
|
}
|
|
91501
91909
|
function readState(path = STATE_PATH) {
|
|
91502
91910
|
try {
|
|
91503
|
-
const j3 = JSON.parse((0,
|
|
91911
|
+
const j3 = JSON.parse((0, import_node_fs11.readFileSync)(path, "utf8"));
|
|
91504
91912
|
const lastPromptMs = typeof j3["lastPromptMs"] === "number" ? j3["lastPromptMs"] : 0;
|
|
91505
91913
|
const promptedIds = Array.isArray(j3["promptedIds"]) ? j3["promptedIds"].filter((x4) => typeof x4 === "string") : [];
|
|
91506
91914
|
return { lastPromptMs, promptedIds };
|
|
@@ -91510,12 +91918,12 @@ function readState(path = STATE_PATH) {
|
|
|
91510
91918
|
}
|
|
91511
91919
|
function writeState(state, path = STATE_PATH) {
|
|
91512
91920
|
try {
|
|
91513
|
-
(0,
|
|
91921
|
+
(0, import_node_fs11.mkdirSync)((0, import_node_path12.dirname)(path), { recursive: true });
|
|
91514
91922
|
const trimmed = {
|
|
91515
91923
|
lastPromptMs: state.lastPromptMs,
|
|
91516
91924
|
promptedIds: state.promptedIds.slice(-MAX_REMEMBERED)
|
|
91517
91925
|
};
|
|
91518
|
-
(0,
|
|
91926
|
+
(0, import_node_fs11.writeFileSync)(path, JSON.stringify(trimmed) + "\n", "utf8");
|
|
91519
91927
|
} catch {
|
|
91520
91928
|
}
|
|
91521
91929
|
}
|
|
@@ -93610,6 +94018,19 @@ function detectFixedCadence(body2, name2) {
|
|
|
93610
94018
|
}
|
|
93611
94019
|
return null;
|
|
93612
94020
|
}
|
|
94021
|
+
function detectExactMatchQuery(body2, name2) {
|
|
94022
|
+
const sql2 = /\bWHERE\b[^;]*?["'`]?\b\w+\b["'`]?\s*=\s*[$?:]\w*/i.exec(body2);
|
|
94023
|
+
if (sql2 && !/\b(?:LIKE|ILIKE|LOWER|UPPER|TRIM|SIMILAR|REGEXP)\b/i.test(grp(sql2, 0))) {
|
|
94024
|
+
const frag = grp(sql2, 0).trim().slice(0, 48);
|
|
94025
|
+
return { pattern: "exact-match-query", matched: frag, baseScore: 0.2, title: hedged(name2, `matches on an exact-equality query (\`${frag}\`) with no normalization, so a value differing only in formatting (case, whitespace, leading zeros) returns no rows`) };
|
|
94026
|
+
}
|
|
94027
|
+
const orm = /\.(?:find|findOne|findFirst|findUnique)\s*\(\s*\{\s*\w+\s*:/.exec(body2);
|
|
94028
|
+
if (orm) {
|
|
94029
|
+
const frag = grp(orm, 0).trim().slice(0, 40);
|
|
94030
|
+
return { pattern: "exact-match-query", matched: frag, baseScore: 0.2, title: hedged(name2, `looks up by an exact field match (\`${frag}\`) with no normalization, so a value differing only in formatting returns no match`) };
|
|
94031
|
+
}
|
|
94032
|
+
return null;
|
|
94033
|
+
}
|
|
93613
94034
|
function detectInPlaceMutation(body2, ctx) {
|
|
93614
94035
|
const hay = `${ctx.symbol.name} ${ctx.symbol.filePath ?? ""} ${ctx.symbol.signature ?? ""}`;
|
|
93615
94036
|
const contextual = /reduc|\bslice\b|store|mutat|\bstate\b/i.test(hay) || ctx.imports.some((i3) => /redux|zustand|immer|valtio|mobx/i.test(i3));
|
|
@@ -93665,7 +94086,14 @@ function detectDataFlowCause(ctx) {
|
|
|
93665
94086
|
if (raw.length < 40) return null;
|
|
93666
94087
|
const body2 = stripComments(raw);
|
|
93667
94088
|
const nm = ctx.symbol.name;
|
|
93668
|
-
return detectFixedCadence(body2, nm) ?? detectInPlaceMutation(body2, ctx) ?? detectUnawaitedWrite(body2, ctx) ?? detectHardcodedBound(body2, nm);
|
|
94089
|
+
return detectFixedCadence(body2, nm) ?? detectExactMatchQuery(body2, nm) ?? detectInPlaceMutation(body2, ctx) ?? detectUnawaitedWrite(body2, ctx) ?? detectHardcodedBound(body2, nm);
|
|
94090
|
+
}
|
|
94091
|
+
function detectDataFlowCauseAcross(contexts) {
|
|
94092
|
+
for (const c4 of contexts) {
|
|
94093
|
+
const f5 = detectDataFlowCause(c4);
|
|
94094
|
+
if (f5) return f5;
|
|
94095
|
+
}
|
|
94096
|
+
return null;
|
|
93669
94097
|
}
|
|
93670
94098
|
|
|
93671
94099
|
// ../../packages/engine/src/hypotheses.ts
|
|
@@ -94376,7 +94804,7 @@ init_cjs_shims();
|
|
|
94376
94804
|
|
|
94377
94805
|
// ../../packages/engine/src/memory-detect.ts
|
|
94378
94806
|
init_cjs_shims();
|
|
94379
|
-
var
|
|
94807
|
+
var import_node_crypto6 = require("crypto");
|
|
94380
94808
|
|
|
94381
94809
|
// ../../packages/engine/src/memory-store.ts
|
|
94382
94810
|
init_cjs_shims();
|
|
@@ -94462,7 +94890,7 @@ function sharedNonGenericTags(a2, b5) {
|
|
|
94462
94890
|
}
|
|
94463
94891
|
function recurrenceEdgeId(idA, idB) {
|
|
94464
94892
|
const [lo, hi] = idA <= idB ? [idA, idB] : [idB, idA];
|
|
94465
|
-
const h3 = (0,
|
|
94893
|
+
const h3 = (0, import_node_crypto6.createHash)("sha256").update(`recurs-with\0${lo}\0${hi}`).digest("hex");
|
|
94466
94894
|
return `lnk_recurs_${h3.slice(0, 32)}`;
|
|
94467
94895
|
}
|
|
94468
94896
|
function normalizeCause(s5) {
|
|
@@ -95498,9 +95926,9 @@ function computeWeightedEvidenceConfidence(evidence2, ambientEvidenceIds) {
|
|
|
95498
95926
|
|
|
95499
95927
|
// ../../packages/engine/src/git-collector.ts
|
|
95500
95928
|
init_cjs_shims();
|
|
95501
|
-
var
|
|
95929
|
+
var import_node_child_process6 = require("child_process");
|
|
95502
95930
|
var import_node_util4 = require("util");
|
|
95503
|
-
var exec3 = (0, import_node_util4.promisify)(
|
|
95931
|
+
var exec3 = (0, import_node_util4.promisify)(import_node_child_process6.execFile);
|
|
95504
95932
|
var DEFAULT_MAX_COMMITS = 50;
|
|
95505
95933
|
var DEFAULT_MAX_FILES = 100;
|
|
95506
95934
|
var DEFAULT_MAX_BYTES = 5e4;
|
|
@@ -96378,6 +96806,13 @@ function isNoiseCommit(commit) {
|
|
|
96378
96806
|
return true;
|
|
96379
96807
|
}
|
|
96380
96808
|
if (/pre-commit.*autoupdate/i.test(subject) || /\[pre-commit\.ci\]/i.test(subject)) return true;
|
|
96809
|
+
if (/^(docs|style|test|ci)(\([^)]*\))?[:!]/i.test(subject)) return true;
|
|
96810
|
+
if (/\b(reformat|whitespace|prettier|eslint)\b/i.test(subject)) return true;
|
|
96811
|
+
if (/\bcode\s*(style|formatting)\b/i.test(subject)) return true;
|
|
96812
|
+
if (/\bclean\s*up\b[^.]*\bformat/i.test(subject)) return true;
|
|
96813
|
+
if (/\b(documentation|docs|readme)\b/i.test(subject) && !/\b(endpoint|api|service|handler|controller|component|module|feature|migration|schema|query|cache|queue|webhook|sdk|cli|route)\b/i.test(subject)) {
|
|
96814
|
+
return true;
|
|
96815
|
+
}
|
|
96381
96816
|
return false;
|
|
96382
96817
|
}
|
|
96383
96818
|
function seedTouchedByRelevantChange(recentChanges, seedFile) {
|
|
@@ -96389,6 +96824,26 @@ function seedTouchedByRelevantChange(recentChanges, seedFile) {
|
|
|
96389
96824
|
(c4) => !isNoiseCommit(c4) && c4.files.some(matchesSeed)
|
|
96390
96825
|
);
|
|
96391
96826
|
}
|
|
96827
|
+
function seedTouchingCommitFocus(recentChanges, seedFile) {
|
|
96828
|
+
if (recentChanges === void 0 || seedFile === void 0) return null;
|
|
96829
|
+
if (recentChanges.degenerate) return null;
|
|
96830
|
+
const matchesSeed = (f5) => f5 === seedFile || seedFile.endsWith(f5) || f5.endsWith(seedFile);
|
|
96831
|
+
let min = null;
|
|
96832
|
+
for (const c4 of recentChanges.commits) {
|
|
96833
|
+
if (isNoiseCommit(c4)) continue;
|
|
96834
|
+
if (!c4.files.some(matchesSeed)) continue;
|
|
96835
|
+
const n4 = c4.files.length;
|
|
96836
|
+
if (min === null || n4 < min) min = n4;
|
|
96837
|
+
}
|
|
96838
|
+
return min;
|
|
96839
|
+
}
|
|
96840
|
+
function regressionSeedTouchedScore(focus) {
|
|
96841
|
+
if (focus === null) return 0.18;
|
|
96842
|
+
if (focus <= 4) return 0.45;
|
|
96843
|
+
if (focus <= 8) return 0.38;
|
|
96844
|
+
if (focus <= 14) return 0.3;
|
|
96845
|
+
return 0.2;
|
|
96846
|
+
}
|
|
96392
96847
|
function formatRegressionCitation(recentChanges, changes, seedFile) {
|
|
96393
96848
|
const matchesSeed = (f5) => seedFile === void 0 || f5 === seedFile || seedFile.endsWith(f5) || f5.endsWith(seedFile);
|
|
96394
96849
|
const all = (recentChanges?.commits ?? []).filter((c4) => !isNoiseCommit(c4));
|
|
@@ -97727,7 +98182,11 @@ async function investigate(input, deps) {
|
|
|
97727
98182
|
category: "deployment-regression",
|
|
97728
98183
|
sourceEvidenceIds: [changeEvId, ...seedEv ? [seedEv.id] : []],
|
|
97729
98184
|
// A regression NOT backed by a seed-touching commit must not score like one that is.
|
|
97730
|
-
|
|
98185
|
+
// HOR-451: scale the seed-touched prior by commit focus — a broad/diffuse commit that merely
|
|
98186
|
+
// touched the seed no longer outranks an evidence-backed runtime cause.
|
|
98187
|
+
baseScore: clamp015(
|
|
98188
|
+
(seedInChanges ? regressionSeedTouchedScore(seedTouchingCommitFocus(recentChanges, top?.filePath)) : 0.18) + (queueHits.length > 0 ? 0.05 : 0)
|
|
98189
|
+
),
|
|
97731
98190
|
metadata: { blastRadius }
|
|
97732
98191
|
});
|
|
97733
98192
|
}
|
|
@@ -97766,36 +98225,39 @@ async function investigate(input, deps) {
|
|
|
97766
98225
|
const raiser = bySeed ? top.name : lead.raiserName || top.name;
|
|
97767
98226
|
const depClause = bySeed ? "" : `, a dependency of ${top.name}`;
|
|
97768
98227
|
const calleePenalty = bySeed ? 0 : 0.18;
|
|
97769
|
-
|
|
97770
|
-
|
|
97771
|
-
|
|
97772
|
-
|
|
97773
|
-
|
|
97774
|
-
|
|
97775
|
-
|
|
97776
|
-
|
|
97777
|
-
|
|
97778
|
-
title = `Diagnostic signal ${lead.code} (${lead.count}x in Elasticsearch) is logged by ${raiser}${depClause} \u2014 informational, not an error${msgClause}`;
|
|
97779
|
-
baseScore = clamp015(0.3 + volumeBoost - calleePenalty);
|
|
97780
|
-
}
|
|
97781
|
-
causeInputs.push({
|
|
97782
|
-
id: "cause:seed-emitted-error",
|
|
97783
|
-
title: title.slice(0, 220),
|
|
97784
|
-
category: "error-correlation",
|
|
97785
|
-
sourceEvidenceIds,
|
|
97786
|
-
baseScore,
|
|
97787
|
-
metadata: {
|
|
97788
|
-
blastRadius,
|
|
97789
|
-
seedEmitted: true,
|
|
97790
|
-
code: lead.code,
|
|
97791
|
-
count: lead.count,
|
|
97792
|
-
severity: tier === SEV_ERROR ? "error" : tier === SEV_WARN ? "warn" : "info"
|
|
98228
|
+
if (tier === SEV_ERROR || tier === SEV_WARN) {
|
|
98229
|
+
let title;
|
|
98230
|
+
let baseScore;
|
|
98231
|
+
if (tier === SEV_ERROR) {
|
|
98232
|
+
title = bySeed ? `Runtime error ${lead.code} (${lead.count}x in Elasticsearch) is raised by ${raiser} \u2014 the likely failure${msgClause}` : `Runtime error ${lead.code} (${lead.count}x in Elasticsearch) surfaces on ${raiser}${depClause}${msgClause}`;
|
|
98233
|
+
baseScore = clamp015(0.6 + volumeBoost - calleePenalty);
|
|
98234
|
+
} else {
|
|
98235
|
+
title = `Warning ${lead.code} (${lead.count}x in Elasticsearch) ${bySeed ? "is raised by" : "surfaces on"} ${raiser}${depClause}${msgClause}`;
|
|
98236
|
+
baseScore = clamp015(0.42 + volumeBoost - calleePenalty);
|
|
97793
98237
|
}
|
|
97794
|
-
|
|
98238
|
+
causeInputs.push({
|
|
98239
|
+
id: "cause:seed-emitted-error",
|
|
98240
|
+
title: title.slice(0, 220),
|
|
98241
|
+
category: "error-correlation",
|
|
98242
|
+
sourceEvidenceIds,
|
|
98243
|
+
baseScore,
|
|
98244
|
+
metadata: {
|
|
98245
|
+
blastRadius,
|
|
98246
|
+
seedEmitted: true,
|
|
98247
|
+
code: lead.code,
|
|
98248
|
+
count: lead.count,
|
|
98249
|
+
severity: tier === SEV_ERROR ? "error" : "warn"
|
|
98250
|
+
}
|
|
98251
|
+
});
|
|
98252
|
+
}
|
|
97795
98253
|
}
|
|
97796
98254
|
}
|
|
97797
|
-
if (top && seedEv && ctx && !sourceImpactHint) {
|
|
97798
|
-
const
|
|
98255
|
+
if (top && seedEv && ctx && code && !sourceImpactHint) {
|
|
98256
|
+
const scanIds = [
|
|
98257
|
+
.../* @__PURE__ */ new Set([...seeds.slice(1, 4).map((s5) => s5.id), ...(ctx.callees ?? []).slice(0, 4).map((c4) => c4.id)])
|
|
98258
|
+
].filter((id) => id !== top.id);
|
|
98259
|
+
const extraCtxs = (await Promise.all(scanIds.map((id) => code.context(id).catch(() => null)))).filter((c4) => c4 !== null);
|
|
98260
|
+
const dataFlow = detectDataFlowCauseAcross([ctx, ...extraCtxs]);
|
|
97799
98261
|
if (dataFlow) {
|
|
97800
98262
|
causeInputs.push({
|
|
97801
98263
|
id: "cause:seed-data-flow",
|
|
@@ -98914,7 +99376,7 @@ function blastRadiusToJSON(r) {
|
|
|
98914
99376
|
|
|
98915
99377
|
// ../../packages/engine/src/memory-recall.ts
|
|
98916
99378
|
init_cjs_shims();
|
|
98917
|
-
var
|
|
99379
|
+
var import_node_crypto7 = require("crypto");
|
|
98918
99380
|
var FRESHNESS_HALF_LIFE_DAYS = 30;
|
|
98919
99381
|
var NO_ANCHOR_DECAY = 0.5;
|
|
98920
99382
|
var STALE_RANK_FACTOR = 0.5;
|
|
@@ -98934,7 +99396,7 @@ function recallCodeProviderFromCodeProvider(code) {
|
|
|
98934
99396
|
};
|
|
98935
99397
|
}
|
|
98936
99398
|
function hashNodeContent(content) {
|
|
98937
|
-
return "sha256:" + (0,
|
|
99399
|
+
return "sha256:" + (0, import_node_crypto7.createHash)("sha256").update(content, "utf8").digest("hex");
|
|
98938
99400
|
}
|
|
98939
99401
|
function clamp016(n4) {
|
|
98940
99402
|
if (!Number.isFinite(n4)) return 0;
|
|
@@ -101537,7 +101999,7 @@ function renderReport2(top, ctx, impact, flows, siblings) {
|
|
|
101537
101999
|
|
|
101538
102000
|
// ../../packages/cli/src/commands/index-repo.ts
|
|
101539
102001
|
init_cjs_shims();
|
|
101540
|
-
var
|
|
102002
|
+
var import_node_path18 = require("path");
|
|
101541
102003
|
var import_picocolors9 = __toESM(require_picocolors(), 1);
|
|
101542
102004
|
|
|
101543
102005
|
// ../../packages/knowledge/src/index.ts
|
|
@@ -101746,7 +102208,7 @@ var KnowledgeManifestSchema = external_exports.object({
|
|
|
101746
102208
|
|
|
101747
102209
|
// ../../packages/knowledge/src/layout.ts
|
|
101748
102210
|
init_cjs_shims();
|
|
101749
|
-
var
|
|
102211
|
+
var import_node_path13 = require("path");
|
|
101750
102212
|
var HORUS_DIR2 = ".horus";
|
|
101751
102213
|
var KNOWLEDGE_DIR = "index";
|
|
101752
102214
|
var KNOWLEDGE_FILES = {
|
|
@@ -101761,37 +102223,37 @@ var KNOWLEDGE_FILES = {
|
|
|
101761
102223
|
db: "index.db"
|
|
101762
102224
|
};
|
|
101763
102225
|
function knowledgeDir(root) {
|
|
101764
|
-
return (0,
|
|
102226
|
+
return (0, import_node_path13.join)(root, HORUS_DIR2, KNOWLEDGE_DIR);
|
|
101765
102227
|
}
|
|
101766
102228
|
function knowledgePath(root, file) {
|
|
101767
|
-
return (0,
|
|
102229
|
+
return (0, import_node_path13.join)(knowledgeDir(root), KNOWLEDGE_FILES[file]);
|
|
101768
102230
|
}
|
|
101769
102231
|
|
|
101770
102232
|
// ../../packages/knowledge/src/store.ts
|
|
101771
102233
|
init_cjs_shims();
|
|
101772
|
-
var
|
|
101773
|
-
var
|
|
101774
|
-
var
|
|
102234
|
+
var import_node_crypto8 = require("crypto");
|
|
102235
|
+
var import_node_fs12 = require("fs");
|
|
102236
|
+
var import_node_path14 = require("path");
|
|
101775
102237
|
function readJson(path) {
|
|
101776
|
-
return JSON.parse((0,
|
|
102238
|
+
return JSON.parse((0, import_node_fs12.readFileSync)(path, "utf8"));
|
|
101777
102239
|
}
|
|
101778
102240
|
function writeJson(path, value) {
|
|
101779
|
-
(0,
|
|
101780
|
-
(0,
|
|
102241
|
+
(0, import_node_fs12.mkdirSync)((0, import_node_path14.dirname)(path), { recursive: true });
|
|
102242
|
+
(0, import_node_fs12.writeFileSync)(path, JSON.stringify(value, null, 2) + "\n");
|
|
101781
102243
|
}
|
|
101782
102244
|
function createJsonKnowledgeStore(root) {
|
|
101783
102245
|
const manifestPath = knowledgePath(root, "manifest");
|
|
101784
102246
|
const basePath = knowledgePath(root, "knowledgeBase");
|
|
101785
102247
|
return {
|
|
101786
102248
|
exists() {
|
|
101787
|
-
return (0,
|
|
102249
|
+
return (0, import_node_fs12.existsSync)(basePath);
|
|
101788
102250
|
},
|
|
101789
102251
|
readManifest() {
|
|
101790
|
-
if (!(0,
|
|
102252
|
+
if (!(0, import_node_fs12.existsSync)(manifestPath)) return null;
|
|
101791
102253
|
return KnowledgeManifestSchema.parse(readJson(manifestPath));
|
|
101792
102254
|
},
|
|
101793
102255
|
readSnapshot() {
|
|
101794
|
-
if (!(0,
|
|
102256
|
+
if (!(0, import_node_fs12.existsSync)(basePath)) return null;
|
|
101795
102257
|
return KnowledgeSnapshotSchema.parse(readJson(basePath));
|
|
101796
102258
|
},
|
|
101797
102259
|
write(snapshot, opts = {}) {
|
|
@@ -101799,9 +102261,9 @@ function createJsonKnowledgeStore(root) {
|
|
|
101799
102261
|
const counts = {};
|
|
101800
102262
|
for (const cat of KNOWLEDGE_CATEGORIES) counts[cat] = parsed[cat].length;
|
|
101801
102263
|
const snapshotJson = JSON.stringify(parsed, null, 2) + "\n";
|
|
101802
|
-
const contentHash = (0,
|
|
101803
|
-
(0,
|
|
101804
|
-
(0,
|
|
102264
|
+
const contentHash = (0, import_node_crypto8.createHash)("sha256").update(snapshotJson).digest("hex");
|
|
102265
|
+
(0, import_node_fs12.mkdirSync)((0, import_node_path14.dirname)(basePath), { recursive: true });
|
|
102266
|
+
(0, import_node_fs12.writeFileSync)(basePath, snapshotJson);
|
|
101805
102267
|
writeJson(knowledgePath(root, "contracts"), {
|
|
101806
102268
|
operations: parsed.operations,
|
|
101807
102269
|
types: parsed.types,
|
|
@@ -101887,9 +102349,9 @@ function searchSnapshot(snapshot, query, opts = {}) {
|
|
|
101887
102349
|
|
|
101888
102350
|
// ../../packages/knowledge/src/import/index.ts
|
|
101889
102351
|
init_cjs_shims();
|
|
101890
|
-
var
|
|
101891
|
-
var
|
|
101892
|
-
var
|
|
102352
|
+
var import_node_crypto9 = require("crypto");
|
|
102353
|
+
var import_node_fs13 = require("fs");
|
|
102354
|
+
var import_node_path15 = require("path");
|
|
101893
102355
|
|
|
101894
102356
|
// ../../packages/knowledge/src/import/maison-safqa.ts
|
|
101895
102357
|
init_cjs_shims();
|
|
@@ -102127,8 +102589,8 @@ function importMaisonSafqaKnowledgeBase(raw, opts = {}) {
|
|
|
102127
102589
|
// ../../packages/knowledge/src/import/index.ts
|
|
102128
102590
|
function importKnowledgeBaseFile(filePath, opts = {}) {
|
|
102129
102591
|
const source = opts.source ?? MAISON_SAFQA_SOURCE;
|
|
102130
|
-
const content = (0,
|
|
102131
|
-
const contentHash = (0,
|
|
102592
|
+
const content = (0, import_node_fs13.readFileSync)(filePath, "utf8");
|
|
102593
|
+
const contentHash = (0, import_node_crypto9.createHash)("sha256").update(content).digest("hex");
|
|
102132
102594
|
let raw;
|
|
102133
102595
|
try {
|
|
102134
102596
|
raw = JSON.parse(content);
|
|
@@ -102147,7 +102609,7 @@ function importKnowledgeBaseFile(filePath, opts = {}) {
|
|
|
102147
102609
|
generator: { tool: source, version: result.kbVersion ?? void 0 },
|
|
102148
102610
|
sourceIntelligence: { tool: source },
|
|
102149
102611
|
extraFiles: [
|
|
102150
|
-
{ name: `${source}:${(0,
|
|
102612
|
+
{ name: `${source}:${(0, import_node_path15.basename)(filePath)}`, category: "import-source", contentHash }
|
|
102151
102613
|
]
|
|
102152
102614
|
});
|
|
102153
102615
|
}
|
|
@@ -102156,8 +102618,8 @@ function importKnowledgeBaseFile(filePath, opts = {}) {
|
|
|
102156
102618
|
|
|
102157
102619
|
// ../../packages/knowledge/src/build/project-landscape.ts
|
|
102158
102620
|
init_cjs_shims();
|
|
102159
|
-
var
|
|
102160
|
-
var
|
|
102621
|
+
var import_node_fs14 = require("fs");
|
|
102622
|
+
var import_node_path16 = require("path");
|
|
102161
102623
|
|
|
102162
102624
|
// ../../packages/knowledge/src/build/source-graph.ts
|
|
102163
102625
|
init_cjs_shims();
|
|
@@ -102357,14 +102819,14 @@ function deriveExternalIntegrations(profiles) {
|
|
|
102357
102819
|
// ../../packages/knowledge/src/build/project-landscape.ts
|
|
102358
102820
|
function readPackageJson(repoPath) {
|
|
102359
102821
|
try {
|
|
102360
|
-
return JSON.parse((0,
|
|
102822
|
+
return JSON.parse((0, import_node_fs14.readFileSync)((0, import_node_path16.join)(repoPath, "package.json"), "utf8"));
|
|
102361
102823
|
} catch {
|
|
102362
102824
|
return null;
|
|
102363
102825
|
}
|
|
102364
102826
|
}
|
|
102365
102827
|
function readText(repoPath, file) {
|
|
102366
102828
|
try {
|
|
102367
|
-
return (0,
|
|
102829
|
+
return (0, import_node_fs14.readFileSync)((0, import_node_path16.join)(repoPath, file), "utf8");
|
|
102368
102830
|
} catch {
|
|
102369
102831
|
return null;
|
|
102370
102832
|
}
|
|
@@ -102917,27 +103379,27 @@ function extractQueueGraph(input) {
|
|
|
102917
103379
|
}
|
|
102918
103380
|
}
|
|
102919
103381
|
const producers = [];
|
|
102920
|
-
for (const
|
|
102921
|
-
const loopVarEnums = loopVarEnumsFor(
|
|
102922
|
-
for (const m5 of
|
|
103382
|
+
for (const pc60 of input.producerClasses) {
|
|
103383
|
+
const loopVarEnums = loopVarEnumsFor(pc60.content);
|
|
103384
|
+
for (const m5 of pc60.content.matchAll(INJECT_QUEUE_RE)) {
|
|
102923
103385
|
const queue = m5[1] ?? "";
|
|
102924
|
-
if (queue) producers.push({ queue, symbol:
|
|
103386
|
+
if (queue) producers.push({ queue, symbol: pc60.name, file: pc60.filePath });
|
|
102925
103387
|
}
|
|
102926
|
-
for (const m5 of
|
|
103388
|
+
for (const m5 of pc60.content.matchAll(NEW_BULL_RE)) {
|
|
102927
103389
|
if (m5[2] !== "Queue") continue;
|
|
102928
103390
|
const queues2 = resolveArg(m5[3] ?? "", constMap, enums, loopVarEnums);
|
|
102929
103391
|
for (const queue of queues2) {
|
|
102930
103392
|
producers.push({
|
|
102931
103393
|
queue,
|
|
102932
|
-
symbol: (m5[1] ??
|
|
102933
|
-
file:
|
|
103394
|
+
symbol: (m5[1] ?? pc60.name) || baseName(pc60.filePath),
|
|
103395
|
+
file: pc60.filePath
|
|
102934
103396
|
});
|
|
102935
103397
|
}
|
|
102936
103398
|
}
|
|
102937
|
-
for (const m5 of
|
|
103399
|
+
for (const m5 of pc60.content.matchAll(QUEUE_NAME_CONST_RE)) {
|
|
102938
103400
|
const ident = m5[1] ?? "";
|
|
102939
103401
|
const queue = m5[2] ?? "";
|
|
102940
|
-
if (queue) producers.push({ queue, symbol: ident || baseName(
|
|
103402
|
+
if (queue) producers.push({ queue, symbol: ident || baseName(pc60.filePath), file: pc60.filePath });
|
|
102941
103403
|
}
|
|
102942
103404
|
}
|
|
102943
103405
|
const workers = [];
|
|
@@ -103237,7 +103699,7 @@ async function stitch(client, db, opts = {}) {
|
|
|
103237
103699
|
|
|
103238
103700
|
// ../../packages/cli/src/lib/ensure-host.ts
|
|
103239
103701
|
init_cjs_shims();
|
|
103240
|
-
var
|
|
103702
|
+
var import_node_path17 = require("path");
|
|
103241
103703
|
var import_picocolors8 = __toESM(require_picocolors(), 1);
|
|
103242
103704
|
function parseHostPort(hostUrl) {
|
|
103243
103705
|
try {
|
|
@@ -103266,7 +103728,7 @@ function ensureHostReasonHint(reason) {
|
|
|
103266
103728
|
async function verifyHostServesRepo(hostUrl, root) {
|
|
103267
103729
|
const served = await fetchHostRepoPath(hostUrl);
|
|
103268
103730
|
if (served === null) return "unknown";
|
|
103269
|
-
return (0,
|
|
103731
|
+
return (0, import_node_path17.resolve)(served) === (0, import_node_path17.resolve)(root) ? "match" : "foreign";
|
|
103270
103732
|
}
|
|
103271
103733
|
async function ensureOwnSourceHost(root, opts = {}) {
|
|
103272
103734
|
const ownUrl = readSourceHostUrl(root);
|
|
@@ -103376,16 +103838,16 @@ async function stitchQueueMap(hostUrl, dbUrl, label) {
|
|
|
103376
103838
|
async function hostServesRepo(hostUrl, root) {
|
|
103377
103839
|
try {
|
|
103378
103840
|
const info2 = await new SourceHttpClient({ baseUrl: hostUrl }).hostInfo();
|
|
103379
|
-
return (0,
|
|
103841
|
+
return (0, import_node_path18.resolve)(info2.repoPath) === (0, import_node_path18.resolve)(root);
|
|
103380
103842
|
} catch {
|
|
103381
103843
|
return true;
|
|
103382
103844
|
}
|
|
103383
103845
|
}
|
|
103384
103846
|
function findConfiguredRepo(config2, root) {
|
|
103385
|
-
const target = (0,
|
|
103847
|
+
const target = (0, import_node_path18.resolve)(root);
|
|
103386
103848
|
for (const p5 of config2.projects) {
|
|
103387
103849
|
for (const r of p5.repositories) {
|
|
103388
|
-
if ((0,
|
|
103850
|
+
if ((0, import_node_path18.resolve)(r.path) === target) {
|
|
103389
103851
|
const hostUrl = r.source?.hostUrl;
|
|
103390
103852
|
return { project: p5.name, ...hostUrl ? { hostUrl } : {} };
|
|
103391
103853
|
}
|
|
@@ -103447,7 +103909,7 @@ async function buildKnowledgeIndex(root, config2, label, configuredProject, opts
|
|
|
103447
103909
|
const gitSha = getHeadSha(root) ?? void 0;
|
|
103448
103910
|
const branch = getCurrentBranch(root) ?? void 0;
|
|
103449
103911
|
if (opts.importKb) {
|
|
103450
|
-
const res = importKnowledgeBaseFile((0,
|
|
103912
|
+
const res = importKnowledgeBaseFile((0, import_node_path18.resolve)(opts.importKb), { root, project: label });
|
|
103451
103913
|
const total = res.manifest ? Object.values(res.manifest.counts).reduce((a2, b5) => a2 + b5, 0) : 0;
|
|
103452
103914
|
console.log(import_picocolors9.default.dim(` project knowledge: imported ${total} item(s) from ${opts.importKb}`));
|
|
103453
103915
|
if (res.warnings.length) console.log(import_picocolors9.default.dim(` (${res.warnings.length} import warning(s))`));
|
|
@@ -103462,12 +103924,12 @@ async function buildKnowledgeIndex(root, config2, label, configuredProject, opts
|
|
|
103462
103924
|
const repos = [];
|
|
103463
103925
|
if (config2 && configuredProject) {
|
|
103464
103926
|
const proj = config2.projects.find((p5) => p5.name === configuredProject);
|
|
103465
|
-
for (const r of proj?.repositories ?? []) repos.push({ name: r.name, path: (0,
|
|
103927
|
+
for (const r of proj?.repositories ?? []) repos.push({ name: r.name, path: (0, import_node_path18.resolve)(r.path) });
|
|
103466
103928
|
}
|
|
103467
103929
|
if (repos.length === 0) repos.push({ name: label, path: root });
|
|
103468
103930
|
let sourceGraph;
|
|
103469
103931
|
if (hostUrl) {
|
|
103470
|
-
const graphRepo = repos.find((r) => (0,
|
|
103932
|
+
const graphRepo = repos.find((r) => (0, import_node_path18.resolve)(r.path) === (0, import_node_path18.resolve)(root))?.name ?? label;
|
|
103471
103933
|
try {
|
|
103472
103934
|
const extract = await extractSourceGraph(hostUrl, graphRepo);
|
|
103473
103935
|
if (extract) sourceGraph = extract;
|
|
@@ -103527,7 +103989,7 @@ async function runIndex(opts) {
|
|
|
103527
103989
|
}
|
|
103528
103990
|
}
|
|
103529
103991
|
const isConfigured = configuredProject !== null;
|
|
103530
|
-
const name2 = opts.name ?? configuredProject ?? (0,
|
|
103992
|
+
const name2 = opts.name ?? configuredProject ?? (0, import_node_path18.basename)(root);
|
|
103531
103993
|
const label = configuredProject ?? name2;
|
|
103532
103994
|
let hostUrl;
|
|
103533
103995
|
let spawned = false;
|
|
@@ -103674,8 +104136,8 @@ async function runIndex(opts) {
|
|
|
103674
104136
|
|
|
103675
104137
|
// ../../packages/cli/src/commands/knowledge.ts
|
|
103676
104138
|
init_cjs_shims();
|
|
103677
|
-
var
|
|
103678
|
-
var
|
|
104139
|
+
var import_node_fs15 = require("fs");
|
|
104140
|
+
var import_node_crypto10 = require("crypto");
|
|
103679
104141
|
var import_picocolors10 = __toESM(require_picocolors(), 1);
|
|
103680
104142
|
function resolveRoot(opts) {
|
|
103681
104143
|
if (opts.root) return opts.root;
|
|
@@ -103943,7 +104405,7 @@ function runKnowledgeValidate(opts = {}) {
|
|
|
103943
104405
|
if (manifest && snapshot) {
|
|
103944
104406
|
const recorded = manifest.files.find((f5) => f5.name === "knowledge-base.json")?.contentHash;
|
|
103945
104407
|
if (recorded) {
|
|
103946
|
-
const actual = (0,
|
|
104408
|
+
const actual = (0, import_node_crypto10.createHash)("sha256").update((0, import_node_fs15.readFileSync)(knowledgePath(root, "knowledgeBase"), "utf8")).digest("hex");
|
|
103947
104409
|
if (actual !== recorded) {
|
|
103948
104410
|
issues.push("knowledge-base.json content hash does not match the manifest (file modified after write)");
|
|
103949
104411
|
}
|
|
@@ -114277,12 +114739,12 @@ var import_picocolors11 = __toESM(require_picocolors(), 1);
|
|
|
114277
114739
|
|
|
114278
114740
|
// ../../packages/cli/src/lib/open-url.ts
|
|
114279
114741
|
init_cjs_shims();
|
|
114280
|
-
var
|
|
114742
|
+
var import_node_child_process7 = require("child_process");
|
|
114281
114743
|
function openBrowser(url) {
|
|
114282
114744
|
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
114283
114745
|
const args2 = process.platform === "win32" ? ["/c", "start", "", url] : [url];
|
|
114284
114746
|
try {
|
|
114285
|
-
(0,
|
|
114747
|
+
(0, import_node_child_process7.execFile)(cmd, args2, () => {
|
|
114286
114748
|
});
|
|
114287
114749
|
} catch {
|
|
114288
114750
|
}
|
|
@@ -114670,8 +115132,8 @@ async function runMcpServer(opts = {}) {
|
|
|
114670
115132
|
|
|
114671
115133
|
// ../../packages/cli/src/commands/knowledge-cloud.ts
|
|
114672
115134
|
init_cjs_shims();
|
|
114673
|
-
var
|
|
114674
|
-
var
|
|
115135
|
+
var import_node_fs18 = require("fs");
|
|
115136
|
+
var import_node_path20 = require("path");
|
|
114675
115137
|
var import_picocolors13 = __toESM(require_picocolors(), 1);
|
|
114676
115138
|
|
|
114677
115139
|
// ../../packages/cli/src/lib/cloud/session.ts
|
|
@@ -114895,12 +115357,12 @@ var CloudClient = class {
|
|
|
114895
115357
|
|
|
114896
115358
|
// ../../packages/cli/src/lib/cloud/auth-store.ts
|
|
114897
115359
|
init_cjs_shims();
|
|
114898
|
-
var
|
|
115360
|
+
var import_node_fs16 = require("fs");
|
|
114899
115361
|
function readAuth() {
|
|
114900
115362
|
const p5 = authPath();
|
|
114901
|
-
if (!(0,
|
|
115363
|
+
if (!(0, import_node_fs16.existsSync)(p5)) return null;
|
|
114902
115364
|
try {
|
|
114903
|
-
const parsed = JSON.parse((0,
|
|
115365
|
+
const parsed = JSON.parse((0, import_node_fs16.readFileSync)(p5, "utf8"));
|
|
114904
115366
|
if (!parsed.token || !parsed.apiBaseUrl || !parsed.account) return null;
|
|
114905
115367
|
return parsed;
|
|
114906
115368
|
} catch {
|
|
@@ -114908,17 +115370,17 @@ function readAuth() {
|
|
|
114908
115370
|
}
|
|
114909
115371
|
}
|
|
114910
115372
|
function writeAuth(state) {
|
|
114911
|
-
(0,
|
|
115373
|
+
(0, import_node_fs16.mkdirSync)(horusHome(), { recursive: true });
|
|
114912
115374
|
const p5 = authPath();
|
|
114913
|
-
(0,
|
|
115375
|
+
(0, import_node_fs16.writeFileSync)(p5, JSON.stringify(state, null, 2) + "\n", { mode: 384 });
|
|
114914
115376
|
try {
|
|
114915
|
-
(0,
|
|
115377
|
+
(0, import_node_fs16.chmodSync)(p5, 384);
|
|
114916
115378
|
} catch {
|
|
114917
115379
|
}
|
|
114918
115380
|
}
|
|
114919
115381
|
function clearAuth() {
|
|
114920
115382
|
const p5 = authPath();
|
|
114921
|
-
if ((0,
|
|
115383
|
+
if ((0, import_node_fs16.existsSync)(p5)) (0, import_node_fs16.rmSync)(p5);
|
|
114922
115384
|
}
|
|
114923
115385
|
|
|
114924
115386
|
// ../../packages/cli/src/lib/cloud/session.ts
|
|
@@ -114936,13 +115398,13 @@ function authedClient() {
|
|
|
114936
115398
|
|
|
114937
115399
|
// ../../packages/cli/src/lib/cloud/context-store.ts
|
|
114938
115400
|
init_cjs_shims();
|
|
114939
|
-
var
|
|
114940
|
-
var
|
|
115401
|
+
var import_node_fs17 = require("fs");
|
|
115402
|
+
var import_node_path19 = require("path");
|
|
114941
115403
|
function readCloudConfig(root) {
|
|
114942
115404
|
const p5 = cloudConfigPath(root);
|
|
114943
|
-
if (!(0,
|
|
115405
|
+
if (!(0, import_node_fs17.existsSync)(p5)) return null;
|
|
114944
115406
|
try {
|
|
114945
|
-
const parsed = JSON.parse((0,
|
|
115407
|
+
const parsed = JSON.parse((0, import_node_fs17.readFileSync)(p5, "utf8"));
|
|
114946
115408
|
if (parsed.context !== "local" && parsed.context !== "cloud") return null;
|
|
114947
115409
|
return parsed;
|
|
114948
115410
|
} catch {
|
|
@@ -114951,12 +115413,12 @@ function readCloudConfig(root) {
|
|
|
114951
115413
|
}
|
|
114952
115414
|
function writeCloudConfig(root, cfg) {
|
|
114953
115415
|
const p5 = cloudConfigPath(root);
|
|
114954
|
-
(0,
|
|
114955
|
-
(0,
|
|
115416
|
+
(0, import_node_fs17.mkdirSync)((0, import_node_path19.dirname)(p5), { recursive: true });
|
|
115417
|
+
(0, import_node_fs17.writeFileSync)(p5, JSON.stringify(cfg, null, 2) + "\n");
|
|
114956
115418
|
}
|
|
114957
115419
|
function clearCloudConfig(root) {
|
|
114958
115420
|
const p5 = cloudConfigPath(root);
|
|
114959
|
-
if ((0,
|
|
115421
|
+
if ((0, import_node_fs17.existsSync)(p5)) (0, import_node_fs17.rmSync)(p5);
|
|
114960
115422
|
}
|
|
114961
115423
|
function isCloudActive(cfg) {
|
|
114962
115424
|
return !!cfg && cfg.context === "cloud" && !!cfg.project;
|
|
@@ -115152,10 +115614,10 @@ function reportCloudError(err2) {
|
|
|
115152
115614
|
|
|
115153
115615
|
// ../../packages/cli/src/commands/knowledge-cloud.ts
|
|
115154
115616
|
function readKnowledgeRedactConfig(root) {
|
|
115155
|
-
const configPath = (0,
|
|
115156
|
-
if (!(0,
|
|
115617
|
+
const configPath = (0, import_node_path20.join)(root, ".horus", "config.json");
|
|
115618
|
+
if (!(0, import_node_fs18.existsSync)(configPath)) return {};
|
|
115157
115619
|
try {
|
|
115158
|
-
const raw = JSON.parse((0,
|
|
115620
|
+
const raw = JSON.parse((0, import_node_fs18.readFileSync)(configPath, "utf8"));
|
|
115159
115621
|
const redact = raw["knowledge"]?.["redact"];
|
|
115160
115622
|
return { dropProvenancePaths: !!redact?.dropProvenancePaths, summariesOnly: !!redact?.summariesOnly };
|
|
115161
115623
|
} catch {
|
|
@@ -116576,12 +117038,12 @@ async function listCloudInvestigations(client, cfg) {
|
|
|
116576
117038
|
|
|
116577
117039
|
// ../../packages/cli/src/lib/freshness.ts
|
|
116578
117040
|
init_cjs_shims();
|
|
116579
|
-
var
|
|
116580
|
-
var
|
|
116581
|
-
var
|
|
117041
|
+
var import_node_child_process8 = require("child_process");
|
|
117042
|
+
var import_node_fs19 = require("fs");
|
|
117043
|
+
var import_node_path21 = require("path");
|
|
116582
117044
|
var import_node_util5 = require("util");
|
|
116583
117045
|
var import_picocolors15 = __toESM(require_picocolors(), 1);
|
|
116584
|
-
var execFileAsync2 = (0, import_node_util5.promisify)(
|
|
117046
|
+
var execFileAsync2 = (0, import_node_util5.promisify)(import_node_child_process8.execFile);
|
|
116585
117047
|
async function commitsSince(repoRoot, sinceIso) {
|
|
116586
117048
|
try {
|
|
116587
117049
|
const { stdout } = await execFileAsync2(
|
|
@@ -116599,7 +117061,7 @@ var RUNTIME_SOURCES = /* @__PURE__ */ new Set(["logs", "metrics", "state", "queu
|
|
|
116599
117061
|
var STALE_INDEX_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
116600
117062
|
function readIndexMeta(repoRoot) {
|
|
116601
117063
|
try {
|
|
116602
|
-
const raw = (0,
|
|
117064
|
+
const raw = (0, import_node_fs19.readFileSync)((0, import_node_path21.join)(repoRoot, ".horus", "source", "meta.json"), "utf8");
|
|
116603
117065
|
const j3 = JSON.parse(raw);
|
|
116604
117066
|
return {
|
|
116605
117067
|
lastIndexedAt: typeof j3.last_indexed_at === "string" ? j3.last_indexed_at : void 0,
|
|
@@ -116686,9 +117148,9 @@ function renderFreshness(f5) {
|
|
|
116686
117148
|
// ../../packages/cli/src/lib/investigation-runner.ts
|
|
116687
117149
|
init_cjs_shims();
|
|
116688
117150
|
var import_picocolors16 = __toESM(require_picocolors(), 1);
|
|
116689
|
-
var
|
|
116690
|
-
var
|
|
116691
|
-
var
|
|
117151
|
+
var import_node_fs20 = require("fs");
|
|
117152
|
+
var import_node_path22 = require("path");
|
|
117153
|
+
var import_node_os9 = require("os");
|
|
116692
117154
|
|
|
116693
117155
|
// ../../packages/eval/src/index.ts
|
|
116694
117156
|
init_cjs_shims();
|
|
@@ -117221,7 +117683,7 @@ function loadReranker() {
|
|
|
117221
117683
|
const flag = process.env.HORUS_RERANK;
|
|
117222
117684
|
if (!flag || flag === "0" || flag.toLowerCase() === "false") return void 0;
|
|
117223
117685
|
try {
|
|
117224
|
-
const blob = JSON.parse((0,
|
|
117686
|
+
const blob = JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path22.join)((0, import_node_os9.homedir)(), ".horus", "reranker.json"), "utf8"));
|
|
117225
117687
|
if (!isRerankerModel(blob)) return void 0;
|
|
117226
117688
|
if ((blob.holdout?.delta ?? 0) <= 0) return void 0;
|
|
117227
117689
|
return (causes) => applyReranker(blob, causes);
|
|
@@ -118602,8 +119064,8 @@ async function runOwner(query, opts) {
|
|
|
118602
119064
|
|
|
118603
119065
|
// ../../packages/cli/src/commands/postmortem.ts
|
|
118604
119066
|
init_cjs_shims();
|
|
118605
|
-
var
|
|
118606
|
-
var
|
|
119067
|
+
var import_node_fs21 = require("fs");
|
|
119068
|
+
var import_node_path23 = require("path");
|
|
118607
119069
|
var import_picocolors30 = __toESM(require_picocolors(), 1);
|
|
118608
119070
|
async function runPostmortem(id, opts) {
|
|
118609
119071
|
const log = opts.write ?? ((line2) => console.log(line2));
|
|
@@ -118714,14 +119176,14 @@ _AI summary unavailable: ${validationErrors?.[0] ?? "provider error"}_
|
|
|
118714
119176
|
}
|
|
118715
119177
|
}
|
|
118716
119178
|
if (opts.output) {
|
|
118717
|
-
const outputPath = (0,
|
|
118718
|
-
if ((0,
|
|
119179
|
+
const outputPath = (0, import_node_path23.resolve)(opts.output);
|
|
119180
|
+
if ((0, import_node_fs21.existsSync)(outputPath) && !opts.force) {
|
|
118719
119181
|
log(import_picocolors30.default.red("\u2717") + " " + outputPath + " already exists");
|
|
118720
119182
|
log(import_picocolors30.default.dim(" pass --force to overwrite"));
|
|
118721
119183
|
return 1;
|
|
118722
119184
|
}
|
|
118723
119185
|
try {
|
|
118724
|
-
(0,
|
|
119186
|
+
(0, import_node_fs21.writeFileSync)(outputPath, content, "utf8");
|
|
118725
119187
|
} catch (err2) {
|
|
118726
119188
|
log(import_picocolors30.default.red("\u2717 Could not write " + outputPath + ": ") + err2.message);
|
|
118727
119189
|
return 1;
|
|
@@ -121119,12 +121581,12 @@ async function runState(opts) {
|
|
|
121119
121581
|
// ../../packages/cli/src/commands/init.ts
|
|
121120
121582
|
init_cjs_shims();
|
|
121121
121583
|
var import_picocolors39 = __toESM(require_picocolors(), 1);
|
|
121122
|
-
var
|
|
121584
|
+
var import_node_path24 = require("path");
|
|
121123
121585
|
async function runInit(opts) {
|
|
121124
121586
|
try {
|
|
121125
121587
|
const cwd = process.cwd();
|
|
121126
|
-
const root = opts.path ? (0,
|
|
121127
|
-
const name2 = opts.name ?? (0,
|
|
121588
|
+
const root = opts.path ? (0, import_node_path24.resolve)(opts.path) : findRepoRoot(cwd) ?? cwd;
|
|
121589
|
+
const name2 = opts.name ?? (0, import_node_path24.basename)(root);
|
|
121128
121590
|
const envName = opts.env ?? "production";
|
|
121129
121591
|
const repo = { name: name2, path: root };
|
|
121130
121592
|
if (opts.source) repo["source"] = { hostUrl: opts.source };
|
|
@@ -121314,7 +121776,6 @@ async function runSetup(opts) {
|
|
|
121314
121776
|
// ../../packages/cli/src/commands/connect.ts
|
|
121315
121777
|
init_cjs_shims();
|
|
121316
121778
|
var import_node_readline = require("readline");
|
|
121317
|
-
var import_node_child_process9 = require("child_process");
|
|
121318
121779
|
var import_picocolors44 = __toESM(require_picocolors(), 1);
|
|
121319
121780
|
|
|
121320
121781
|
// ../../packages/cli/src/lib/tty-selector.ts
|
|
@@ -121639,10 +122100,10 @@ async function selectSearch(opts) {
|
|
|
121639
122100
|
|
|
121640
122101
|
// ../../packages/cli/src/commands/connect-ai.ts
|
|
121641
122102
|
init_cjs_shims();
|
|
121642
|
-
var
|
|
122103
|
+
var import_node_child_process9 = require("child_process");
|
|
121643
122104
|
var import_picocolors43 = __toESM(require_picocolors(), 1);
|
|
121644
122105
|
function cliInstalled(id) {
|
|
121645
|
-
const r = (0,
|
|
122106
|
+
const r = (0, import_node_child_process9.spawnSync)(id, ["--version"], { stdio: "ignore", timeout: 2e3 });
|
|
121646
122107
|
return !r.error;
|
|
121647
122108
|
}
|
|
121648
122109
|
async function probeAnthropic(apiKey) {
|
|
@@ -121792,7 +122253,7 @@ async function runConnect(type, opts) {
|
|
|
121792
122253
|
}
|
|
121793
122254
|
const connectorType = type;
|
|
121794
122255
|
try {
|
|
121795
|
-
const cwd = process.cwd();
|
|
122256
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
121796
122257
|
const root = findRepoRoot(cwd) ?? cwd;
|
|
121797
122258
|
const configPath = discoverLocalConfig(cwd) ?? localConfigPath(root);
|
|
121798
122259
|
const filled = await fillInteractive(connectorType, opts);
|
|
@@ -121834,22 +122295,45 @@ ${import_picocolors44.default.red(`\u2717 Could not reach ${connectorType}:`)} $
|
|
|
121834
122295
|
${import_picocolors44.default.green("\u2713")} ${connectorType} reachable ${import_picocolors44.default.dim(`(${probeResult.detail})`)}`
|
|
121835
122296
|
);
|
|
121836
122297
|
}
|
|
121837
|
-
const
|
|
121838
|
-
|
|
121839
|
-
|
|
121840
|
-
|
|
121841
|
-
|
|
121842
|
-
|
|
121843
|
-
|
|
121844
|
-
|
|
122298
|
+
const envName = resolveEnvName(configPath, filled.env);
|
|
122299
|
+
const secretFields = CONNECTOR_SECRET_FIELDS[connectorType] ?? [];
|
|
122300
|
+
const nonSecretPatch = {};
|
|
122301
|
+
const secretPatch = [];
|
|
122302
|
+
for (const [k3, v4] of Object.entries(patch)) {
|
|
122303
|
+
if (secretFields.includes(k3) && typeof v4 === "string" && v4.length > 0) {
|
|
122304
|
+
secretPatch.push([k3, v4]);
|
|
122305
|
+
} else {
|
|
122306
|
+
nonSecretPatch[k3] = v4;
|
|
122307
|
+
}
|
|
122308
|
+
}
|
|
122309
|
+
ensureProjectGitignore(root);
|
|
122310
|
+
if (secretPatch.length > 0) {
|
|
122311
|
+
let keyResult;
|
|
122312
|
+
try {
|
|
122313
|
+
keyResult = ensureMasterKey();
|
|
122314
|
+
} catch (err2) {
|
|
122315
|
+
console.error(import_picocolors44.default.red(err2.message));
|
|
121845
122316
|
return 1;
|
|
121846
122317
|
}
|
|
121847
|
-
|
|
122318
|
+
for (const [field, value] of secretPatch) {
|
|
122319
|
+
writeConnectorSecret(root, envName, connectorType, field, value, keyResult.key);
|
|
122320
|
+
}
|
|
122321
|
+
if (keyResult.warning) console.warn(import_picocolors44.default.yellow(`
|
|
122322
|
+
\u26A0 ${keyResult.warning}`));
|
|
121848
122323
|
}
|
|
121849
|
-
patchLocalConnector(configPath, connectorType,
|
|
122324
|
+
patchLocalConnector(configPath, connectorType, nonSecretPatch, envName);
|
|
121850
122325
|
console.log(
|
|
121851
122326
|
`${import_picocolors44.default.green("\u2713")} ${import_picocolors44.default.bold(connectorType)} connector saved \u2192 ${import_picocolors44.default.dim(configPath)}`
|
|
121852
122327
|
);
|
|
122328
|
+
if (secretPatch.length > 0) {
|
|
122329
|
+
const n4 = secretPatch.length;
|
|
122330
|
+
console.log(
|
|
122331
|
+
import_picocolors44.default.dim(
|
|
122332
|
+
` ${n4} secret${n4 > 1 ? "s" : ""} encrypted \u2192 ${localSecretsPath(root)}
|
|
122333
|
+
master key: ${masterKeyStatus().detail}`
|
|
122334
|
+
)
|
|
122335
|
+
);
|
|
122336
|
+
}
|
|
121853
122337
|
printSummary(connectorType, filled);
|
|
121854
122338
|
console.log(import_picocolors44.default.dim(`
|
|
121855
122339
|
run: horus investigate "<hint>"`));
|
|
@@ -122313,16 +122797,19 @@ function printSummary(type, opts) {
|
|
|
122313
122797
|
}
|
|
122314
122798
|
if (lines.length > 0) console.log(import_picocolors44.default.dim(lines.join("\n")));
|
|
122315
122799
|
}
|
|
122316
|
-
function
|
|
122317
|
-
|
|
122318
|
-
|
|
122319
|
-
|
|
122320
|
-
|
|
122321
|
-
|
|
122322
|
-
|
|
122323
|
-
|
|
122324
|
-
return
|
|
122800
|
+
function resolveEnvName(configPath, requested) {
|
|
122801
|
+
const file = readLocalConfig(configPath);
|
|
122802
|
+
const project = file.project;
|
|
122803
|
+
const envs = project?.environments ?? [];
|
|
122804
|
+
if (requested) {
|
|
122805
|
+
if (!envs.some((e) => e.name === requested)) {
|
|
122806
|
+
throw new Error(`Environment "${requested}" not found in config.`);
|
|
122807
|
+
}
|
|
122808
|
+
return requested;
|
|
122325
122809
|
}
|
|
122810
|
+
const first = envs[0]?.name;
|
|
122811
|
+
if (!first) throw new Error("No environments found in config.");
|
|
122812
|
+
return first;
|
|
122326
122813
|
}
|
|
122327
122814
|
async function discoverEsIndices(url, username, password) {
|
|
122328
122815
|
if (!url) return [];
|
|
@@ -122507,15 +122994,157 @@ function redactUrl(raw) {
|
|
|
122507
122994
|
}
|
|
122508
122995
|
}
|
|
122509
122996
|
|
|
122997
|
+
// ../../packages/cli/src/commands/secrets.ts
|
|
122998
|
+
init_cjs_shims();
|
|
122999
|
+
var import_node_fs22 = require("fs");
|
|
123000
|
+
var import_picocolors45 = __toESM(require_picocolors(), 1);
|
|
123001
|
+
function locate(cwd = process.cwd()) {
|
|
123002
|
+
const root = findRepoRoot(cwd) ?? cwd;
|
|
123003
|
+
const configPath = discoverLocalConfig(cwd) ?? localConfigPath(root);
|
|
123004
|
+
return { root, configPath, exists: (0, import_node_fs22.existsSync)(configPath) };
|
|
123005
|
+
}
|
|
123006
|
+
function countStoredSecrets(root) {
|
|
123007
|
+
const stored = readLocalSecrets(root).connectors;
|
|
123008
|
+
if (!stored) return 0;
|
|
123009
|
+
let n4 = 0;
|
|
123010
|
+
for (const byConnector of Object.values(stored)) {
|
|
123011
|
+
for (const byField of Object.values(byConnector)) {
|
|
123012
|
+
n4 += Object.keys(byField).length;
|
|
123013
|
+
}
|
|
123014
|
+
}
|
|
123015
|
+
return n4;
|
|
123016
|
+
}
|
|
123017
|
+
function runSecretsStatus(opts = {}) {
|
|
123018
|
+
const { root, configPath, exists: exists2 } = locate(opts.cwd);
|
|
123019
|
+
const key = masterKeyStatus();
|
|
123020
|
+
console.log(import_picocolors45.default.bold("\nMaster key"));
|
|
123021
|
+
console.log(
|
|
123022
|
+
key.available ? ` ${import_picocolors45.default.green("\u25CF")} ${key.detail}` : ` ${import_picocolors45.default.dim("\u25CB")} ${key.detail}`
|
|
123023
|
+
);
|
|
123024
|
+
const stored = countStoredSecrets(root);
|
|
123025
|
+
console.log(import_picocolors45.default.bold("\nEncrypted secrets"));
|
|
123026
|
+
console.log(` ${stored} stored \u2192 ${import_picocolors45.default.dim(localSecretsPath(root))}`);
|
|
123027
|
+
if (stored > 0) {
|
|
123028
|
+
const { warnings } = decryptConnectorSecrets(root);
|
|
123029
|
+
if (warnings.length > 0) {
|
|
123030
|
+
console.log(import_picocolors45.default.yellow(` \u26A0 ${warnings.length} cannot be decrypted with the current key:`));
|
|
123031
|
+
for (const w4 of warnings) console.log(import_picocolors45.default.dim(` - ${w4}`));
|
|
123032
|
+
} else {
|
|
123033
|
+
console.log(import_picocolors45.default.dim(" all decrypt cleanly with the current key"));
|
|
123034
|
+
}
|
|
123035
|
+
}
|
|
123036
|
+
console.log(import_picocolors45.default.bold("\nPlaintext in config.json"));
|
|
123037
|
+
if (!exists2) {
|
|
123038
|
+
console.log(import_picocolors45.default.dim(" no .horus/config.json found"));
|
|
123039
|
+
} else {
|
|
123040
|
+
const plaintext = findPlaintextConnectorSecrets(readLocalConfig(configPath).project);
|
|
123041
|
+
if (plaintext.length === 0) {
|
|
123042
|
+
console.log(` ${import_picocolors45.default.green("\u2713")} none \u2014 config carries no credentials`);
|
|
123043
|
+
} else {
|
|
123044
|
+
console.log(import_picocolors45.default.yellow(` \u26A0 ${plaintext.length} plaintext secret(s) \u2014 run \`horus secrets migrate\`:`));
|
|
123045
|
+
for (const p5 of plaintext) console.log(import_picocolors45.default.dim(` - ${p5}`));
|
|
123046
|
+
}
|
|
123047
|
+
}
|
|
123048
|
+
console.log(import_picocolors45.default.bold("\nGitignore"));
|
|
123049
|
+
console.log(
|
|
123050
|
+
isHorusGitignored(root) ? ` ${import_picocolors45.default.green("\u2713")} .horus/ is gitignored` : import_picocolors45.default.yellow(" \u26A0 .horus/ is NOT gitignored \u2014 run `horus secrets migrate` or add `.horus/` to .gitignore")
|
|
123051
|
+
);
|
|
123052
|
+
console.log("");
|
|
123053
|
+
return 0;
|
|
123054
|
+
}
|
|
123055
|
+
function runSecretsMigrate(opts = {}) {
|
|
123056
|
+
const { root, configPath, exists: exists2 } = locate(opts.cwd);
|
|
123057
|
+
if (!exists2) {
|
|
123058
|
+
console.error(import_picocolors45.default.red(`No .horus/config.json found at ${configPath}.`));
|
|
123059
|
+
console.error(import_picocolors45.default.dim(" Run `horus index` in this repo first."));
|
|
123060
|
+
return 1;
|
|
123061
|
+
}
|
|
123062
|
+
const file = readLocalConfig(configPath);
|
|
123063
|
+
const plaintext = findPlaintextConnectorSecrets(file.project);
|
|
123064
|
+
ensureProjectGitignore(root);
|
|
123065
|
+
if (plaintext.length === 0) {
|
|
123066
|
+
console.log(`${import_picocolors45.default.green("\u2713")} No plaintext connector secrets in config.json \u2014 nothing to migrate.`);
|
|
123067
|
+
if (!isHorusGitignored(root)) {
|
|
123068
|
+
console.log(import_picocolors45.default.dim(" Ensured `.horus/` is gitignored."));
|
|
123069
|
+
}
|
|
123070
|
+
return 0;
|
|
123071
|
+
}
|
|
123072
|
+
if (opts.dryRun) {
|
|
123073
|
+
console.log(import_picocolors45.default.bold(`Would migrate ${plaintext.length} plaintext secret(s) \u2192 encrypted store:`));
|
|
123074
|
+
for (const p5 of plaintext) console.log(import_picocolors45.default.dim(` - ${p5}`));
|
|
123075
|
+
console.log(import_picocolors45.default.dim("\n Re-run without --dry-run to apply."));
|
|
123076
|
+
return 0;
|
|
123077
|
+
}
|
|
123078
|
+
let keyResult;
|
|
123079
|
+
try {
|
|
123080
|
+
keyResult = ensureMasterKey();
|
|
123081
|
+
} catch (err2) {
|
|
123082
|
+
console.error(import_picocolors45.default.red(err2.message));
|
|
123083
|
+
return 1;
|
|
123084
|
+
}
|
|
123085
|
+
const project = file.project;
|
|
123086
|
+
let migrated = 0;
|
|
123087
|
+
for (const env of project?.environments ?? []) {
|
|
123088
|
+
const envName = env["name"];
|
|
123089
|
+
const connectors = env["connectors"];
|
|
123090
|
+
if (!envName || !connectors) continue;
|
|
123091
|
+
for (const [connector, cfg] of Object.entries(connectors)) {
|
|
123092
|
+
if (!cfg || typeof cfg !== "object") continue;
|
|
123093
|
+
for (const field of CONNECTOR_SECRET_FIELDS[connector] ?? []) {
|
|
123094
|
+
const val = cfg[field];
|
|
123095
|
+
if (typeof val === "string" && val.length > 0) {
|
|
123096
|
+
writeConnectorSecret(root, envName, connector, field, val, keyResult.key);
|
|
123097
|
+
delete cfg[field];
|
|
123098
|
+
migrated++;
|
|
123099
|
+
}
|
|
123100
|
+
}
|
|
123101
|
+
}
|
|
123102
|
+
}
|
|
123103
|
+
writeLocalConfig(root, file);
|
|
123104
|
+
console.log(`${import_picocolors45.default.green("\u2713")} Migrated ${migrated} secret(s) \u2192 ${import_picocolors45.default.dim(localSecretsPath(root))}`);
|
|
123105
|
+
console.log(import_picocolors45.default.dim(` master key: ${masterKeyStatus().detail}`));
|
|
123106
|
+
console.log(import_picocolors45.default.dim(" config.json now carries no credentials."));
|
|
123107
|
+
if (keyResult.warning) console.warn(import_picocolors45.default.yellow(`
|
|
123108
|
+
\u26A0 ${keyResult.warning}`));
|
|
123109
|
+
console.log(
|
|
123110
|
+
import_picocolors45.default.dim(
|
|
123111
|
+
"\n If config.json was ever committed, scrub the old secret from history:\n git rm --cached .horus/config.json # if tracked\n # then rotate the exposed credential at its provider."
|
|
123112
|
+
)
|
|
123113
|
+
);
|
|
123114
|
+
return 0;
|
|
123115
|
+
}
|
|
123116
|
+
function runSecretsKey(opts = {}) {
|
|
123117
|
+
const status = masterKeyStatus();
|
|
123118
|
+
if (!status.available) {
|
|
123119
|
+
console.log(import_picocolors45.default.dim("No master key yet \u2014 created on first `horus connect` or `horus secrets migrate`."));
|
|
123120
|
+
return 0;
|
|
123121
|
+
}
|
|
123122
|
+
console.log(`Master key source: ${status.detail}`);
|
|
123123
|
+
if (!opts.show) {
|
|
123124
|
+
console.log(import_picocolors45.default.dim(" Pass --show to print the key (base64) for CI use (HORUS_SECRET_KEY)."));
|
|
123125
|
+
return 0;
|
|
123126
|
+
}
|
|
123127
|
+
const key = getMasterKeyForRead();
|
|
123128
|
+
if (!key) {
|
|
123129
|
+
console.error(import_picocolors45.default.red("Could not read the master key."));
|
|
123130
|
+
return 1;
|
|
123131
|
+
}
|
|
123132
|
+
console.warn(import_picocolors45.default.yellow("\u26A0 Treat this as a credential. Anyone with it can decrypt your connector secrets."));
|
|
123133
|
+
console.log(`
|
|
123134
|
+
export HORUS_SECRET_KEY=${key.toString("base64")}
|
|
123135
|
+
`);
|
|
123136
|
+
return 0;
|
|
123137
|
+
}
|
|
123138
|
+
|
|
122510
123139
|
// ../../packages/cli/src/commands/stop.ts
|
|
122511
123140
|
init_cjs_shims();
|
|
122512
123141
|
var import_node_child_process10 = require("child_process");
|
|
122513
|
-
var
|
|
123142
|
+
var import_node_fs23 = require("fs");
|
|
122514
123143
|
var import_node_util6 = require("util");
|
|
122515
|
-
var
|
|
122516
|
-
var
|
|
123144
|
+
var import_node_path25 = require("path");
|
|
123145
|
+
var import_picocolors46 = __toESM(require_picocolors(), 1);
|
|
122517
123146
|
var execFileAsync3 = (0, import_node_util6.promisify)(import_node_child_process10.execFile);
|
|
122518
|
-
var unlinkAsync = (0, import_node_util6.promisify)(
|
|
123147
|
+
var unlinkAsync = (0, import_node_util6.promisify)(import_node_fs23.unlink);
|
|
122519
123148
|
var SPAWNED_HOST_FILE2 = "spawned-host.json";
|
|
122520
123149
|
var START_TIME_TOLERANCE_S = 60;
|
|
122521
123150
|
var STOP_WAIT_MS = 5e3;
|
|
@@ -122531,19 +123160,19 @@ async function runStop(opts) {
|
|
|
122531
123160
|
const root = findRepoRoot(cwd) ?? cwd;
|
|
122532
123161
|
const hostUrl = readSourceHostUrl(root);
|
|
122533
123162
|
if (!hostUrl) {
|
|
122534
|
-
console.log(
|
|
123163
|
+
console.log(import_picocolors46.default.dim("No source-intelligence host found for this repo (.horus/source/host.json absent)."));
|
|
122535
123164
|
return 0;
|
|
122536
123165
|
}
|
|
122537
123166
|
return await stopHost(root, hostUrl);
|
|
122538
123167
|
} catch (err2) {
|
|
122539
|
-
console.error(
|
|
123168
|
+
console.error(import_picocolors46.default.red(err2.message));
|
|
122540
123169
|
return 1;
|
|
122541
123170
|
}
|
|
122542
123171
|
}
|
|
122543
123172
|
async function stopHost(root, hostUrl) {
|
|
122544
123173
|
const port = extractPort(hostUrl);
|
|
122545
123174
|
if (port === null) {
|
|
122546
|
-
console.error(
|
|
123175
|
+
console.error(import_picocolors46.default.red(`Cannot determine port from host URL: ${hostUrl}`));
|
|
122547
123176
|
return 1;
|
|
122548
123177
|
}
|
|
122549
123178
|
const healthy = await isHostHealthy(hostUrl);
|
|
@@ -122553,12 +123182,12 @@ async function stopHost(root, hostUrl) {
|
|
|
122553
123182
|
if (!wrapperAlive) {
|
|
122554
123183
|
const res = await stopBackendServerPid(root, port);
|
|
122555
123184
|
if (res === "failed") return 1;
|
|
122556
|
-
if (res !== "stopped") console.log(
|
|
123185
|
+
if (res !== "stopped") console.log(import_picocolors46.default.dim(`Host ${hostUrl} is already stopped.`));
|
|
122557
123186
|
await cleanupSpawnedRecord(root);
|
|
122558
123187
|
return 0;
|
|
122559
123188
|
}
|
|
122560
123189
|
console.log(
|
|
122561
|
-
|
|
123190
|
+
import_picocolors46.default.dim(
|
|
122562
123191
|
`Host ${hostUrl} is unreachable but pid ${owned.pid} is still running \u2014 terminating a stuck host.`
|
|
122563
123192
|
)
|
|
122564
123193
|
);
|
|
@@ -122566,7 +123195,7 @@ async function stopHost(root, hostUrl) {
|
|
|
122566
123195
|
const spawned = readSpawnedHost(root);
|
|
122567
123196
|
if (spawned === null) {
|
|
122568
123197
|
console.error(
|
|
122569
|
-
|
|
123198
|
+
import_picocolors46.default.red(
|
|
122570
123199
|
`No ownership record found (.horus/${SPAWNED_HOST_FILE2} absent). Horus will not stop a host it did not spawn.`
|
|
122571
123200
|
)
|
|
122572
123201
|
);
|
|
@@ -122574,12 +123203,12 @@ async function stopHost(root, hostUrl) {
|
|
|
122574
123203
|
}
|
|
122575
123204
|
const recordError = validateSpawnedRecord(spawned);
|
|
122576
123205
|
if (recordError !== null) {
|
|
122577
|
-
console.error(
|
|
123206
|
+
console.error(import_picocolors46.default.red(`Ownership record is malformed: ${recordError}. Aborting for safety.`));
|
|
122578
123207
|
return 1;
|
|
122579
123208
|
}
|
|
122580
123209
|
if (spawned.port !== port) {
|
|
122581
123210
|
console.error(
|
|
122582
|
-
|
|
123211
|
+
import_picocolors46.default.red(
|
|
122583
123212
|
`Ownership record port (${spawned.port}) does not match host URL port (${port}). Record may be stale.`
|
|
122584
123213
|
)
|
|
122585
123214
|
);
|
|
@@ -122587,7 +123216,7 @@ async function stopHost(root, hostUrl) {
|
|
|
122587
123216
|
}
|
|
122588
123217
|
if (spawned.root !== root) {
|
|
122589
123218
|
console.error(
|
|
122590
|
-
|
|
123219
|
+
import_picocolors46.default.red(
|
|
122591
123220
|
`Ownership record root (${spawned.root}) does not match resolved root (${root}). Record may be stale.`
|
|
122592
123221
|
)
|
|
122593
123222
|
);
|
|
@@ -122598,14 +123227,14 @@ async function stopHost(root, hostUrl) {
|
|
|
122598
123227
|
const res = await stopBackendServerPid(root, port);
|
|
122599
123228
|
if (res === "failed") return 1;
|
|
122600
123229
|
if (res !== "stopped") {
|
|
122601
|
-
console.log(
|
|
123230
|
+
console.log(import_picocolors46.default.dim(`Process pid ${spawned.pid} is no longer running \u2014 already stopped.`));
|
|
122602
123231
|
}
|
|
122603
123232
|
await cleanupSpawnedRecord(root);
|
|
122604
123233
|
return 0;
|
|
122605
123234
|
}
|
|
122606
123235
|
if (!isOwnHostProcess(spawned.pid, port, root, info2.args)) {
|
|
122607
123236
|
console.error(
|
|
122608
|
-
|
|
123237
|
+
import_picocolors46.default.red(
|
|
122609
123238
|
`Pid ${spawned.pid} args do not match "horus-source host --port ${port}". Got: "${info2.args.slice(0, 120)}". Aborting for safety.`
|
|
122610
123239
|
)
|
|
122611
123240
|
);
|
|
@@ -122614,12 +123243,12 @@ async function stopHost(root, hostUrl) {
|
|
|
122614
123243
|
const startTs = new Date(spawned.startedAt).getTime();
|
|
122615
123244
|
const recordedAgeS = Math.round((Date.now() - startTs) / 1e3);
|
|
122616
123245
|
if (!Number.isFinite(info2.etimeSeconds)) {
|
|
122617
|
-
console.error(
|
|
123246
|
+
console.error(import_picocolors46.default.red(`Could not read elapsed time for pid ${spawned.pid}. Aborting for safety.`));
|
|
122618
123247
|
return 1;
|
|
122619
123248
|
}
|
|
122620
123249
|
if (Math.abs(info2.etimeSeconds - recordedAgeS) > START_TIME_TOLERANCE_S) {
|
|
122621
123250
|
console.error(
|
|
122622
|
-
|
|
123251
|
+
import_picocolors46.default.red(
|
|
122623
123252
|
`Pid ${spawned.pid} age mismatch: record says ~${recordedAgeS}s, process reports ${info2.etimeSeconds}s elapsed. Possible PID reuse \u2014 aborting for safety.`
|
|
122624
123253
|
)
|
|
122625
123254
|
);
|
|
@@ -122629,17 +123258,17 @@ async function stopHost(root, hostUrl) {
|
|
|
122629
123258
|
try {
|
|
122630
123259
|
terminated = await terminatePid(spawned.pid);
|
|
122631
123260
|
} catch (err2) {
|
|
122632
|
-
console.error(
|
|
123261
|
+
console.error(import_picocolors46.default.red(`Failed to signal pid ${spawned.pid}: ${err2.message}`));
|
|
122633
123262
|
return 1;
|
|
122634
123263
|
}
|
|
122635
123264
|
if (!terminated) {
|
|
122636
123265
|
console.error(
|
|
122637
|
-
|
|
123266
|
+
import_picocolors46.default.red(`Host pid ${spawned.pid} did not exit even after SIGKILL \u2014 could not reclaim the port.`)
|
|
122638
123267
|
);
|
|
122639
123268
|
return 1;
|
|
122640
123269
|
}
|
|
122641
123270
|
console.log(
|
|
122642
|
-
`${
|
|
123271
|
+
`${import_picocolors46.default.green("\u2713")} Stopped source-intelligence host ` + import_picocolors46.default.dim(`(pid ${spawned.pid}, port ${port})`) + ` for ${root}`
|
|
122643
123272
|
);
|
|
122644
123273
|
if (await stopBackendServerPid(root, port) === "failed") return 1;
|
|
122645
123274
|
await cleanupSpawnedRecord(root);
|
|
@@ -122657,11 +123286,11 @@ function isOwnHostProcess(pid, port, root, args2) {
|
|
|
122657
123286
|
if (hostArgvRegex(port).test(args2)) return true;
|
|
122658
123287
|
if (!hostArgvAnyPortRegex().test(args2)) return false;
|
|
122659
123288
|
const rec = readSourceHostPid(root);
|
|
122660
|
-
return rec !== null && rec.pid === pid && Number.isFinite(rec.port) && rec.port === port && !!rec.repoPath && (0,
|
|
123289
|
+
return rec !== null && rec.pid === pid && Number.isFinite(rec.port) && rec.port === port && !!rec.repoPath && (0, import_node_path25.resolve)(rec.repoPath) === (0, import_node_path25.resolve)(root);
|
|
122661
123290
|
}
|
|
122662
123291
|
async function cleanupSpawnedRecord(root) {
|
|
122663
123292
|
try {
|
|
122664
|
-
await unlinkAsync((0,
|
|
123293
|
+
await unlinkAsync((0, import_node_path25.join)(root, HORUS_DIR, SPAWNED_HOST_FILE2));
|
|
122665
123294
|
} catch {
|
|
122666
123295
|
}
|
|
122667
123296
|
}
|
|
@@ -122674,7 +123303,7 @@ async function stopBackendServerPid(root, port) {
|
|
|
122674
123303
|
if (info2 === null) return "none";
|
|
122675
123304
|
if (!isOwnHostProcess(rec.pid, port, root, info2.args)) {
|
|
122676
123305
|
console.log(
|
|
122677
|
-
|
|
123306
|
+
import_picocolors46.default.dim(
|
|
122678
123307
|
`Host pid ${rec.pid} is now an unrelated process (stale source/host.json / PID reuse) \u2014 host already gone.`
|
|
122679
123308
|
)
|
|
122680
123309
|
);
|
|
@@ -122684,17 +123313,17 @@ async function stopBackendServerPid(root, port) {
|
|
|
122684
123313
|
try {
|
|
122685
123314
|
terminated = await terminatePid(rec.pid);
|
|
122686
123315
|
} catch (err2) {
|
|
122687
|
-
console.error(
|
|
123316
|
+
console.error(import_picocolors46.default.red(`Failed to signal pid ${rec.pid}: ${err2.message}`));
|
|
122688
123317
|
return "failed";
|
|
122689
123318
|
}
|
|
122690
123319
|
if (!terminated) {
|
|
122691
123320
|
console.error(
|
|
122692
|
-
|
|
123321
|
+
import_picocolors46.default.red(`Host pid ${rec.pid} did not exit even after SIGKILL \u2014 could not reclaim the port.`)
|
|
122693
123322
|
);
|
|
122694
123323
|
return "failed";
|
|
122695
123324
|
}
|
|
122696
123325
|
console.log(
|
|
122697
|
-
`${
|
|
123326
|
+
`${import_picocolors46.default.green("\u2713")} Stopped source-intelligence host ` + import_picocolors46.default.dim(`(pid ${rec.pid}, port ${port})`) + ` for ${root}`
|
|
122698
123327
|
);
|
|
122699
123328
|
return "stopped";
|
|
122700
123329
|
}
|
|
@@ -122702,7 +123331,7 @@ async function stopAll() {
|
|
|
122702
123331
|
const registry2 = readRegistry();
|
|
122703
123332
|
const projects2 = Object.entries(registry2.projects);
|
|
122704
123333
|
if (projects2.length === 0) {
|
|
122705
|
-
console.log(
|
|
123334
|
+
console.log(import_picocolors46.default.dim("No registered projects."));
|
|
122706
123335
|
return 0;
|
|
122707
123336
|
}
|
|
122708
123337
|
let stopped = 0;
|
|
@@ -122714,17 +123343,17 @@ async function stopAll() {
|
|
|
122714
123343
|
if (!healthy && readSpawnedHost(entry2.root) === null && readSourceHostPid(entry2.root) === null) {
|
|
122715
123344
|
continue;
|
|
122716
123345
|
}
|
|
122717
|
-
console.log(` Stopping ${
|
|
123346
|
+
console.log(` Stopping ${import_picocolors46.default.bold(name2)} ${import_picocolors46.default.dim(`(${hostUrl})`)}`);
|
|
122718
123347
|
const code = await stopHost(entry2.root, hostUrl);
|
|
122719
123348
|
if (code === 0) stopped++;
|
|
122720
123349
|
else failed++;
|
|
122721
123350
|
}
|
|
122722
123351
|
if (stopped === 0 && failed === 0) {
|
|
122723
|
-
console.log(
|
|
123352
|
+
console.log(import_picocolors46.default.dim("No running source-intelligence hosts found."));
|
|
122724
123353
|
} else {
|
|
122725
123354
|
console.log(
|
|
122726
123355
|
`
|
|
122727
|
-
Stopped ${stopped} host(s)${failed > 0 ?
|
|
123356
|
+
Stopped ${stopped} host(s)${failed > 0 ? import_picocolors46.default.red(`, ${failed} failed`) : ""}.`
|
|
122728
123357
|
);
|
|
122729
123358
|
}
|
|
122730
123359
|
return failed > 0 ? 1 : 0;
|
|
@@ -122812,7 +123441,7 @@ function extractPort(hostUrl) {
|
|
|
122812
123441
|
|
|
122813
123442
|
// ../../packages/cli/src/commands/hosts.ts
|
|
122814
123443
|
init_cjs_shims();
|
|
122815
|
-
var
|
|
123444
|
+
var import_picocolors47 = __toESM(require_picocolors(), 1);
|
|
122816
123445
|
|
|
122817
123446
|
// ../../packages/cli/src/lib/host-reaper.ts
|
|
122818
123447
|
init_cjs_shims();
|
|
@@ -122917,14 +123546,14 @@ async function runHosts(opts = {}) {
|
|
|
122917
123546
|
for (const row of rows) {
|
|
122918
123547
|
if (row.hostUrl === null) continue;
|
|
122919
123548
|
printedAny = true;
|
|
122920
|
-
const status = row.live ?
|
|
123549
|
+
const status = row.live ? import_picocolors47.default.green("\u25CF running") : import_picocolors47.default.red("\u25CF stopped");
|
|
122921
123550
|
const port = row.port ?? "?";
|
|
122922
123551
|
console.log(
|
|
122923
|
-
` ${status} ${
|
|
123552
|
+
` ${status} ${import_picocolors47.default.bold(row.name.padEnd(24))} port ${String(port).padEnd(6)} ${import_picocolors47.default.dim(row.root)}`
|
|
122924
123553
|
);
|
|
122925
123554
|
}
|
|
122926
123555
|
const noHost = rows.filter((r) => r.hostUrl === null);
|
|
122927
|
-
for (const row of noHost) console.log(` ${
|
|
123556
|
+
for (const row of noHost) console.log(` ${import_picocolors47.default.dim("\u25CB no host")} ${import_picocolors47.default.dim(row.name)}`);
|
|
122928
123557
|
if (printedAny || noHost.length > 0) console.log("");
|
|
122929
123558
|
const claimedPids = /* @__PURE__ */ new Set();
|
|
122930
123559
|
for (const [, entry2] of projects2) {
|
|
@@ -122937,37 +123566,37 @@ async function runHosts(opts = {}) {
|
|
|
122937
123566
|
let reapFailed = 0;
|
|
122938
123567
|
if (orphans.length > 0) {
|
|
122939
123568
|
console.log(
|
|
122940
|
-
|
|
123569
|
+
import_picocolors47.default.yellow(` \u26A0 ${orphans.length} orphaned source host(s) \u2014 no registered repo owns them:`)
|
|
122941
123570
|
);
|
|
122942
|
-
for (const o5 of orphans) console.log(
|
|
123571
|
+
for (const o5 of orphans) console.log(import_picocolors47.default.dim(` pid ${o5.pid} port ${o5.port}`));
|
|
122943
123572
|
if (opts.reap) {
|
|
122944
123573
|
let reaped = 0;
|
|
122945
123574
|
for (const o5 of orphans) {
|
|
122946
123575
|
if (await reapPid(o5.pid)) {
|
|
122947
123576
|
reaped++;
|
|
122948
|
-
console.log(` ${
|
|
123577
|
+
console.log(` ${import_picocolors47.default.green("\u2713")} reaped pid ${o5.pid} ${import_picocolors47.default.dim(`(port ${o5.port})`)}`);
|
|
122949
123578
|
} else {
|
|
122950
123579
|
reapFailed++;
|
|
122951
|
-
console.log(
|
|
123580
|
+
console.log(import_picocolors47.default.red(` \u2717 could not stop pid ${o5.pid} (port ${o5.port})`));
|
|
122952
123581
|
}
|
|
122953
123582
|
}
|
|
122954
|
-
console.log(
|
|
123583
|
+
console.log(import_picocolors47.default.dim(` Reaped ${reaped}/${orphans.length} orphan(s).`));
|
|
122955
123584
|
} else {
|
|
122956
|
-
console.log(
|
|
123585
|
+
console.log(import_picocolors47.default.dim(" Run `horus hosts --reap` to stop them."));
|
|
122957
123586
|
}
|
|
122958
123587
|
console.log("");
|
|
122959
123588
|
}
|
|
122960
123589
|
if (projects2.length === 0 && orphans.length === 0) {
|
|
122961
|
-
console.log(
|
|
123590
|
+
console.log(import_picocolors47.default.dim("No registered projects. Run `horus index` in a repo first."));
|
|
122962
123591
|
return 0;
|
|
122963
123592
|
}
|
|
122964
123593
|
if (!printedAny && orphans.length === 0) {
|
|
122965
|
-
console.log(
|
|
123594
|
+
console.log(import_picocolors47.default.dim("No source-intelligence hosts found. Run `horus index` to start one."));
|
|
122966
123595
|
return 0;
|
|
122967
123596
|
}
|
|
122968
123597
|
const running = countDistinctLiveHosts(rows);
|
|
122969
123598
|
console.log(
|
|
122970
|
-
|
|
123599
|
+
import_picocolors47.default.dim(
|
|
122971
123600
|
`${running} running${orphans.length ? ` \xB7 ${orphans.length} orphan(s)` : ""} \xB7 horus hosts --reap to clear orphans \xB7 horus stop --all to stop everything`
|
|
122972
123601
|
)
|
|
122973
123602
|
);
|
|
@@ -122984,7 +123613,7 @@ function extractPort2(hostUrl) {
|
|
|
122984
123613
|
|
|
122985
123614
|
// ../../packages/cli/src/commands/doctor.ts
|
|
122986
123615
|
init_cjs_shims();
|
|
122987
|
-
var
|
|
123616
|
+
var import_picocolors48 = __toESM(require_picocolors(), 1);
|
|
122988
123617
|
var DEFAULT_DB_URL4 = "postgresql://horus:horus@localhost:5433/horus";
|
|
122989
123618
|
var CONNECTOR_CHECKS = {
|
|
122990
123619
|
// Elasticsearch (runtime logs)
|
|
@@ -123101,9 +123730,9 @@ var CONNECTOR_CHECKS = {
|
|
|
123101
123730
|
};
|
|
123102
123731
|
var DOCTOR_CONNECTOR_KEYS = Object.keys(CONNECTOR_CHECKS);
|
|
123103
123732
|
function mark2(status) {
|
|
123104
|
-
if (status === "pass") return
|
|
123105
|
-
if (status === "warn") return
|
|
123106
|
-
return
|
|
123733
|
+
if (status === "pass") return import_picocolors48.default.green("\u2713");
|
|
123734
|
+
if (status === "warn") return import_picocolors48.default.yellow("~");
|
|
123735
|
+
return import_picocolors48.default.red("\u2717");
|
|
123107
123736
|
}
|
|
123108
123737
|
async function runDoctor(opts) {
|
|
123109
123738
|
const cwd = opts?.cwd ?? process.cwd();
|
|
@@ -123167,6 +123796,38 @@ async function runDoctor(opts) {
|
|
|
123167
123796
|
next: "run `horus init` then `horus index` to set up source intelligence"
|
|
123168
123797
|
});
|
|
123169
123798
|
}
|
|
123799
|
+
{
|
|
123800
|
+
if (repoRoot && !isHorusGitignored(repoRoot)) {
|
|
123801
|
+
checks.push({
|
|
123802
|
+
label: "Secrets gitignore",
|
|
123803
|
+
status: "warn",
|
|
123804
|
+
detail: ".horus/ is NOT gitignored \u2014 credentials could be committed",
|
|
123805
|
+
next: "run `horus secrets migrate` (also hardens .gitignore), or add `.horus/` to .gitignore"
|
|
123806
|
+
});
|
|
123807
|
+
} else if (repoRoot) {
|
|
123808
|
+
checks.push({ label: "Secrets gitignore", status: "pass", detail: ".horus/ is gitignored" });
|
|
123809
|
+
}
|
|
123810
|
+
if (configPath) {
|
|
123811
|
+
try {
|
|
123812
|
+
const plaintext = findPlaintextConnectorSecrets(readLocalConfig(configPath).project);
|
|
123813
|
+
if (plaintext.length > 0) {
|
|
123814
|
+
checks.push({
|
|
123815
|
+
label: "Secret storage",
|
|
123816
|
+
status: "warn",
|
|
123817
|
+
detail: `${plaintext.length} plaintext credential(s) in config.json: ${plaintext.join(", ")}`,
|
|
123818
|
+
next: "run `horus secrets migrate` to encrypt them and strip config.json"
|
|
123819
|
+
});
|
|
123820
|
+
} else {
|
|
123821
|
+
checks.push({
|
|
123822
|
+
label: "Secret storage",
|
|
123823
|
+
status: "pass",
|
|
123824
|
+
detail: "no plaintext credentials in config.json"
|
|
123825
|
+
});
|
|
123826
|
+
}
|
|
123827
|
+
} catch {
|
|
123828
|
+
}
|
|
123829
|
+
}
|
|
123830
|
+
}
|
|
123170
123831
|
{
|
|
123171
123832
|
const dbChecker = opts?._dbCheck ?? checkDatabase;
|
|
123172
123833
|
let dbUrl = process.env["DATABASE_URL"] ?? DEFAULT_DB_URL4;
|
|
@@ -123243,15 +123904,15 @@ async function runDoctor(opts) {
|
|
|
123243
123904
|
write(JSON.stringify(output, null, 2));
|
|
123244
123905
|
return hasFailure ? 1 : 0;
|
|
123245
123906
|
}
|
|
123246
|
-
write(
|
|
123907
|
+
write(import_picocolors48.default.bold("\nHorus readiness check\n"));
|
|
123247
123908
|
for (const check2 of checks) {
|
|
123248
|
-
write(` ${mark2(check2.status)} ${
|
|
123909
|
+
write(` ${mark2(check2.status)} ${import_picocolors48.default.bold(check2.label.padEnd(26))} ${import_picocolors48.default.dim(check2.detail)}`);
|
|
123249
123910
|
if (check2.next) {
|
|
123250
|
-
write(` ${
|
|
123911
|
+
write(` ${import_picocolors48.default.dim("\u2192 " + check2.next)}`);
|
|
123251
123912
|
}
|
|
123252
123913
|
}
|
|
123253
123914
|
write("");
|
|
123254
|
-
write(
|
|
123915
|
+
write(import_picocolors48.default.dim(" Hit a bug or a missing capability? Report it: horus report"));
|
|
123255
123916
|
write("");
|
|
123256
123917
|
return hasFailure ? 1 : 0;
|
|
123257
123918
|
}
|
|
@@ -123259,16 +123920,16 @@ async function runDoctor(opts) {
|
|
|
123259
123920
|
// ../../packages/cli/src/commands/providers-doctor.ts
|
|
123260
123921
|
init_cjs_shims();
|
|
123261
123922
|
var import_node_child_process12 = require("child_process");
|
|
123262
|
-
var
|
|
123923
|
+
var import_picocolors49 = __toESM(require_picocolors(), 1);
|
|
123263
123924
|
function statusMark(status) {
|
|
123264
|
-
if (status === "ready") return
|
|
123265
|
-
if (status === "installed") return
|
|
123266
|
-
return
|
|
123925
|
+
if (status === "ready") return import_picocolors49.default.green("\u2713");
|
|
123926
|
+
if (status === "installed") return import_picocolors49.default.yellow("~");
|
|
123927
|
+
return import_picocolors49.default.red("\u2717");
|
|
123267
123928
|
}
|
|
123268
123929
|
function statusLabel(status) {
|
|
123269
|
-
if (status === "ready") return
|
|
123270
|
-
if (status === "installed") return
|
|
123271
|
-
return
|
|
123930
|
+
if (status === "ready") return import_picocolors49.default.green("ready");
|
|
123931
|
+
if (status === "installed") return import_picocolors49.default.yellow("installed (not configured)");
|
|
123932
|
+
return import_picocolors49.default.dim("not found on PATH");
|
|
123272
123933
|
}
|
|
123273
123934
|
function detectBinary(id) {
|
|
123274
123935
|
const result = (0, import_node_child_process12.spawnSync)(id, ["--version"], { stdio: "pipe", timeout: 2e3 });
|
|
@@ -123285,7 +123946,7 @@ async function runProvidersDoctorCommand(opts) {
|
|
|
123285
123946
|
const registry2 = opts?.registry ?? DEFAULT_LOCAL_PROVIDER_REGISTRY;
|
|
123286
123947
|
const write = opts?.write ?? ((line2) => console.log(line2));
|
|
123287
123948
|
const results = buildProviderResults(registry2, opts?._detect);
|
|
123288
|
-
write(
|
|
123949
|
+
write(import_picocolors49.default.bold("\nLocal AI providers\n"));
|
|
123289
123950
|
for (const result of results) {
|
|
123290
123951
|
const descriptor = registry2.get(result.id);
|
|
123291
123952
|
const name2 = descriptor?.displayName ?? result.id;
|
|
@@ -123293,11 +123954,11 @@ async function runProvidersDoctorCommand(opts) {
|
|
|
123293
123954
|
` ${statusMark(result.status)} ${result.id.padEnd(8)} ${name2.padEnd(22)} ${statusLabel(result.status)}`
|
|
123294
123955
|
);
|
|
123295
123956
|
if (result.status !== "ready" && result.detail) {
|
|
123296
|
-
write(` ${
|
|
123957
|
+
write(` ${import_picocolors49.default.dim("\u2192 " + result.detail)}`);
|
|
123297
123958
|
}
|
|
123298
123959
|
}
|
|
123299
123960
|
write("");
|
|
123300
|
-
write(
|
|
123961
|
+
write(import_picocolors49.default.bold("Cloud AI providers\n"));
|
|
123301
123962
|
let source = null;
|
|
123302
123963
|
if (opts?._anthropicKey !== void 0) {
|
|
123303
123964
|
source = opts._anthropicKey ? "env" : null;
|
|
@@ -123312,18 +123973,18 @@ async function runProvidersDoctorCommand(opts) {
|
|
|
123312
123973
|
}
|
|
123313
123974
|
if (source === "config") {
|
|
123314
123975
|
write(
|
|
123315
|
-
` ${
|
|
123976
|
+
` ${import_picocolors49.default.green("\u2713")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors49.default.green("configured (local .horus config)")}`
|
|
123316
123977
|
);
|
|
123317
123978
|
} else if (source === "env") {
|
|
123318
123979
|
write(
|
|
123319
|
-
` ${
|
|
123980
|
+
` ${import_picocolors49.default.green("\u2713")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors49.default.green("configured (ANTHROPIC_API_KEY env)")}`
|
|
123320
123981
|
);
|
|
123321
123982
|
} else {
|
|
123322
123983
|
write(
|
|
123323
|
-
` ${
|
|
123984
|
+
` ${import_picocolors49.default.red("\u2717")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors49.default.dim("not configured")}`
|
|
123324
123985
|
);
|
|
123325
123986
|
write(
|
|
123326
|
-
` ${
|
|
123987
|
+
` ${import_picocolors49.default.dim("\u2192 run `horus connect ai` (or set ANTHROPIC_API_KEY) to enable `horus investigate --ai`")}`
|
|
123327
123988
|
);
|
|
123328
123989
|
}
|
|
123329
123990
|
write("");
|
|
@@ -123332,9 +123993,9 @@ async function runProvidersDoctorCommand(opts) {
|
|
|
123332
123993
|
|
|
123333
123994
|
// ../../packages/cli/src/commands/generate-config.ts
|
|
123334
123995
|
init_cjs_shims();
|
|
123335
|
-
var
|
|
123336
|
-
var
|
|
123337
|
-
var
|
|
123996
|
+
var import_node_fs24 = require("fs");
|
|
123997
|
+
var import_node_path26 = require("path");
|
|
123998
|
+
var import_picocolors50 = __toESM(require_picocolors(), 1);
|
|
123338
123999
|
function configTemplate(name2, repoPath) {
|
|
123339
124000
|
return `export default {
|
|
123340
124001
|
database: {
|
|
@@ -123382,39 +124043,39 @@ async function runGenerateConfig(opts) {
|
|
|
123382
124043
|
const defaults2 = localConfigPath2 != null ? projectDefaults(localConfigPath2) : null;
|
|
123383
124044
|
const hasLocalConfig = defaults2 != null;
|
|
123384
124045
|
const defaultOut = hasLocalConfig ? "horus.config.example.js" : "horus.config.js";
|
|
123385
|
-
const outPath = (0,
|
|
124046
|
+
const outPath = (0, import_node_path26.resolve)(cwd, opts.out ?? defaultOut);
|
|
123386
124047
|
const name2 = opts.name ?? defaults2?.name ?? "my-project";
|
|
123387
124048
|
const repoPath = opts.repo ?? defaults2?.repoPath ?? `/path/to/${name2}`;
|
|
123388
|
-
if ((0,
|
|
123389
|
-
log(`${
|
|
123390
|
-
log(
|
|
124049
|
+
if ((0, import_node_fs24.existsSync)(outPath) && !opts.force) {
|
|
124050
|
+
log(`${import_picocolors50.default.red("\u2717")} ${outPath} already exists`);
|
|
124051
|
+
log(import_picocolors50.default.dim(" pass --force to overwrite"));
|
|
123391
124052
|
return 1;
|
|
123392
124053
|
}
|
|
123393
124054
|
try {
|
|
123394
|
-
(0,
|
|
123395
|
-
(0,
|
|
124055
|
+
(0, import_node_fs24.mkdirSync)((0, import_node_path26.dirname)(outPath), { recursive: true });
|
|
124056
|
+
(0, import_node_fs24.writeFileSync)(outPath, configTemplate(name2, repoPath), "utf8");
|
|
123396
124057
|
} catch (err2) {
|
|
123397
|
-
log(`${
|
|
124058
|
+
log(`${import_picocolors50.default.red("\u2717")} Could not write ${outPath}: ${err2.message}`);
|
|
123398
124059
|
return 1;
|
|
123399
124060
|
}
|
|
123400
|
-
log(`${
|
|
123401
|
-
log(
|
|
123402
|
-
log(
|
|
124061
|
+
log(`${import_picocolors50.default.green("\u2713")} Created ${outPath}`);
|
|
124062
|
+
log(import_picocolors50.default.dim(` project: ${name2}`));
|
|
124063
|
+
log(import_picocolors50.default.dim(` repo: ${repoPath}`));
|
|
123403
124064
|
if (hasLocalConfig && localConfigPath2 != null) {
|
|
123404
124065
|
log("");
|
|
123405
|
-
log(
|
|
124066
|
+
log(import_picocolors50.default.yellow("Note:") + ` an initialized Horus project config exists at ${localConfigPath2}`);
|
|
123406
124067
|
log(" \u2022 .horus/config.json \u2014 project config used by `horus investigate` from this repo");
|
|
123407
124068
|
log(" \u2022 horus.config.js \u2014 standalone/global config used with `horus doctor --config <path>`");
|
|
123408
|
-
log(
|
|
124069
|
+
log(import_picocolors50.default.dim(` next: review ${outPath} and copy/adapt it as needed`));
|
|
123409
124070
|
} else {
|
|
123410
|
-
log(
|
|
124071
|
+
log(import_picocolors50.default.dim(` next: horus doctor --config ${outPath}`));
|
|
123411
124072
|
}
|
|
123412
124073
|
return 0;
|
|
123413
124074
|
}
|
|
123414
124075
|
|
|
123415
124076
|
// ../../packages/cli/src/commands/readiness.ts
|
|
123416
124077
|
init_cjs_shims();
|
|
123417
|
-
var
|
|
124078
|
+
var import_picocolors51 = __toESM(require_picocolors(), 1);
|
|
123418
124079
|
var READINESS_AI_CONTRACT = `Provide a clearly separated AI readiness summary with:
|
|
123419
124080
|
|
|
123420
124081
|
Overall assessment
|
|
@@ -123437,9 +124098,9 @@ Confidence / gaps
|
|
|
123437
124098
|
- Which checks Horus could verify vs. which require manual confirmation`;
|
|
123438
124099
|
var DEFAULT_DB_URL5 = "postgresql://horus:horus@localhost:5433/horus";
|
|
123439
124100
|
function mark3(status) {
|
|
123440
|
-
if (status === "pass") return
|
|
123441
|
-
if (status === "warn") return
|
|
123442
|
-
return
|
|
124101
|
+
if (status === "pass") return import_picocolors51.default.green("\u2713");
|
|
124102
|
+
if (status === "warn") return import_picocolors51.default.yellow("~");
|
|
124103
|
+
return import_picocolors51.default.red("\u2717");
|
|
123443
124104
|
}
|
|
123444
124105
|
async function runReadiness(opts) {
|
|
123445
124106
|
const cwd = opts?.cwd ?? process.cwd();
|
|
@@ -123644,20 +124305,20 @@ async function runReadiness(opts) {
|
|
|
123644
124305
|
}
|
|
123645
124306
|
const blockingChecks = checks.filter((c4) => c4.blocking);
|
|
123646
124307
|
const optionalChecks = checks.filter((c4) => !c4.blocking);
|
|
123647
|
-
write(
|
|
123648
|
-
write(
|
|
124308
|
+
write(import_picocolors51.default.bold("\nHorus release readiness\n"));
|
|
124309
|
+
write(import_picocolors51.default.bold(" Blocking"));
|
|
123649
124310
|
for (const check2 of blockingChecks) {
|
|
123650
|
-
write(` ${mark3(check2.status)} ${
|
|
124311
|
+
write(` ${mark3(check2.status)} ${import_picocolors51.default.bold(check2.label.padEnd(22))} ${import_picocolors51.default.dim(check2.detail)}`);
|
|
123651
124312
|
if (check2.next) {
|
|
123652
|
-
write(` ${
|
|
124313
|
+
write(` ${import_picocolors51.default.dim("\u2192 " + check2.next)}`);
|
|
123653
124314
|
}
|
|
123654
124315
|
}
|
|
123655
124316
|
write("");
|
|
123656
|
-
write(
|
|
124317
|
+
write(import_picocolors51.default.bold(" Optional"));
|
|
123657
124318
|
for (const check2 of optionalChecks) {
|
|
123658
|
-
write(` ${mark3(check2.status)} ${
|
|
124319
|
+
write(` ${mark3(check2.status)} ${import_picocolors51.default.bold(check2.label.padEnd(22))} ${import_picocolors51.default.dim(check2.detail)}`);
|
|
123659
124320
|
if (check2.next) {
|
|
123660
|
-
write(` ${
|
|
124321
|
+
write(` ${import_picocolors51.default.dim("\u2192 " + check2.next)}`);
|
|
123661
124322
|
}
|
|
123662
124323
|
}
|
|
123663
124324
|
write("");
|
|
@@ -123665,21 +124326,21 @@ async function runReadiness(opts) {
|
|
|
123665
124326
|
const optionalWarns = optionalChecks.filter((c4) => c4.status === "warn").length;
|
|
123666
124327
|
if (blockingFails.length === 0) {
|
|
123667
124328
|
if (optionalWarns === 0) {
|
|
123668
|
-
write(
|
|
124329
|
+
write(import_picocolors51.default.green(" Ready for demo/release."));
|
|
123669
124330
|
} else {
|
|
123670
124331
|
write(
|
|
123671
|
-
|
|
124332
|
+
import_picocolors51.default.yellow(
|
|
123672
124333
|
` Ready for a basic demo. ${optionalWarns} optional item(s) not configured \u2014 investigation evidence will be limited.`
|
|
123673
124334
|
)
|
|
123674
124335
|
);
|
|
123675
124336
|
}
|
|
123676
124337
|
} else {
|
|
123677
124338
|
write(
|
|
123678
|
-
|
|
124339
|
+
import_picocolors51.default.red(
|
|
123679
124340
|
` Not ready. ${blockingFails.length} blocking item(s) must be resolved before demo/release.`
|
|
123680
124341
|
)
|
|
123681
124342
|
);
|
|
123682
|
-
write(
|
|
124343
|
+
write(import_picocolors51.default.dim(" Re-run `horus readiness` after resolving the items above."));
|
|
123683
124344
|
}
|
|
123684
124345
|
write("");
|
|
123685
124346
|
if (opts?.ai) {
|
|
@@ -123694,7 +124355,7 @@ async function runReadiness(opts) {
|
|
|
123694
124355
|
});
|
|
123695
124356
|
console.log("\n" + renderInterpretation(result));
|
|
123696
124357
|
if (!result.ok) {
|
|
123697
|
-
console.error(
|
|
124358
|
+
console.error(import_picocolors51.default.yellow(`[ai] ${result.warning}`));
|
|
123698
124359
|
}
|
|
123699
124360
|
}
|
|
123700
124361
|
return blockingFails.length > 0 ? 1 : 0;
|
|
@@ -123702,33 +124363,33 @@ async function runReadiness(opts) {
|
|
|
123702
124363
|
|
|
123703
124364
|
// ../../packages/cli/src/commands/skill.ts
|
|
123704
124365
|
init_cjs_shims();
|
|
123705
|
-
var
|
|
123706
|
-
var
|
|
123707
|
-
var
|
|
124366
|
+
var import_node_fs25 = require("fs");
|
|
124367
|
+
var import_node_path27 = require("path");
|
|
124368
|
+
var import_node_os10 = require("os");
|
|
123708
124369
|
var import_promises3 = require("readline/promises");
|
|
123709
|
-
var
|
|
124370
|
+
var import_picocolors52 = __toESM(require_picocolors(), 1);
|
|
123710
124371
|
var SUPPORTED_TARGETS = ["claude", "codex", "gemini", "cursor", "generic"];
|
|
123711
124372
|
function isValidTarget(target) {
|
|
123712
124373
|
return SUPPORTED_TARGETS.includes(target);
|
|
123713
124374
|
}
|
|
123714
124375
|
function getLegacyClaudeSkillPath(opts) {
|
|
123715
|
-
const base2 = opts.global ? (0,
|
|
123716
|
-
return (0,
|
|
124376
|
+
const base2 = opts.global ? (0, import_node_os10.homedir)() : opts.cwd ?? process.cwd();
|
|
124377
|
+
return (0, import_node_path27.join)(base2, ".claude", "skills", "horus.md");
|
|
123717
124378
|
}
|
|
123718
124379
|
function getSkillInstallPath(target, opts) {
|
|
123719
|
-
const base2 = opts.global ? (0,
|
|
124380
|
+
const base2 = opts.global ? (0, import_node_os10.homedir)() : opts.cwd ?? process.cwd();
|
|
123720
124381
|
switch (target) {
|
|
123721
124382
|
case "claude":
|
|
123722
|
-
return (0,
|
|
124383
|
+
return (0, import_node_path27.join)(base2, ".claude", "skills", "horus", "SKILL.md");
|
|
123723
124384
|
case "gemini":
|
|
123724
|
-
return opts.global ? (0,
|
|
124385
|
+
return opts.global ? (0, import_node_path27.join)(base2, ".gemini", "GEMINI.md") : (0, import_node_path27.join)(base2, "GEMINI.md");
|
|
123725
124386
|
case "cursor":
|
|
123726
|
-
return opts.global ? (0,
|
|
124387
|
+
return opts.global ? (0, import_node_path27.join)(base2, ".cursorrules") : (0, import_node_path27.join)(base2, ".cursor", "rules", "horus.mdc");
|
|
123727
124388
|
case "codex":
|
|
123728
|
-
return opts.global ? (0,
|
|
124389
|
+
return opts.global ? (0, import_node_path27.join)(base2, ".codex", "AGENTS.md") : (0, import_node_path27.join)(base2, "AGENTS.md");
|
|
123729
124390
|
case "generic":
|
|
123730
124391
|
default:
|
|
123731
|
-
return (0,
|
|
124392
|
+
return (0, import_node_path27.join)(base2, ".horus", "skills", `horus-${target}.md`);
|
|
123732
124393
|
}
|
|
123733
124394
|
}
|
|
123734
124395
|
var BASE_SKILL = `# Horus Grounded Investigation Skill
|
|
@@ -124045,66 +124706,66 @@ async function confirm(message) {
|
|
|
124045
124706
|
async function runSkillInstall(target, opts) {
|
|
124046
124707
|
const log = opts.write ?? ((line2) => console.log(line2));
|
|
124047
124708
|
if (!isValidTarget(target)) {
|
|
124048
|
-
log(`${
|
|
124049
|
-
log(
|
|
124709
|
+
log(`${import_picocolors52.default.red("\u2717")} Unknown target: ${import_picocolors52.default.bold(target)}`);
|
|
124710
|
+
log(import_picocolors52.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
|
|
124050
124711
|
return 1;
|
|
124051
124712
|
}
|
|
124052
124713
|
const outPath = getSkillInstallPath(target, { global: opts.global, cwd: opts.cwd });
|
|
124053
124714
|
const content = generateSkillContent(target);
|
|
124054
124715
|
if (target === "claude") {
|
|
124055
124716
|
const legacyPath = getLegacyClaudeSkillPath({ global: opts.global, cwd: opts.cwd });
|
|
124056
|
-
if ((0,
|
|
124717
|
+
if ((0, import_node_fs25.existsSync)(legacyPath)) {
|
|
124057
124718
|
if (!opts.force) {
|
|
124058
124719
|
const confirmed = await (opts.confirm ?? confirm)(
|
|
124059
124720
|
`Found old flat skill file at ${legacyPath}. Replace it with the new directory layout?`
|
|
124060
124721
|
);
|
|
124061
124722
|
if (!confirmed) {
|
|
124062
|
-
log(`${
|
|
124063
|
-
log(
|
|
124723
|
+
log(`${import_picocolors52.default.yellow("!")} Migration cancelled; existing skill left untouched.`);
|
|
124724
|
+
log(import_picocolors52.default.dim(" Pass --force to replace without prompting."));
|
|
124064
124725
|
return 1;
|
|
124065
124726
|
}
|
|
124066
124727
|
}
|
|
124067
124728
|
try {
|
|
124068
|
-
(0,
|
|
124069
|
-
log(`${
|
|
124729
|
+
(0, import_node_fs25.rmSync)(legacyPath);
|
|
124730
|
+
log(`${import_picocolors52.default.yellow("!")} Replaced old flat skill file: ${legacyPath}`);
|
|
124070
124731
|
} catch (err2) {
|
|
124071
|
-
log(`${
|
|
124732
|
+
log(`${import_picocolors52.default.red("\u2717")} Could not remove legacy skill file ${legacyPath}: ${err2.message}`);
|
|
124072
124733
|
return 1;
|
|
124073
124734
|
}
|
|
124074
124735
|
}
|
|
124075
124736
|
}
|
|
124076
|
-
if ((0,
|
|
124077
|
-
log(`${
|
|
124078
|
-
log(
|
|
124737
|
+
if ((0, import_node_fs25.existsSync)(outPath) && !opts.force) {
|
|
124738
|
+
log(`${import_picocolors52.default.red("\u2717")} ${outPath} already exists`);
|
|
124739
|
+
log(import_picocolors52.default.dim(" pass --force to overwrite"));
|
|
124079
124740
|
return 1;
|
|
124080
124741
|
}
|
|
124081
124742
|
try {
|
|
124082
|
-
(0,
|
|
124083
|
-
(0,
|
|
124743
|
+
(0, import_node_fs25.mkdirSync)((0, import_node_path27.dirname)(outPath), { recursive: true });
|
|
124744
|
+
(0, import_node_fs25.writeFileSync)(outPath, content, "utf8");
|
|
124084
124745
|
} catch (err2) {
|
|
124085
|
-
log(`${
|
|
124746
|
+
log(`${import_picocolors52.default.red("\u2717")} Could not write ${outPath}: ${err2.message}`);
|
|
124086
124747
|
return 1;
|
|
124087
124748
|
}
|
|
124088
|
-
log(`${
|
|
124749
|
+
log(`${import_picocolors52.default.green("\u2713")} Horus skill installed \u2192 ${outPath}`);
|
|
124089
124750
|
if (target === "claude") {
|
|
124090
|
-
log(
|
|
124091
|
-
log(
|
|
124751
|
+
log(import_picocolors52.default.dim(" Claude Code will load this skill automatically."));
|
|
124752
|
+
log(import_picocolors52.default.dim(" Invoke it with: /horus"));
|
|
124092
124753
|
} else if (target === "gemini") {
|
|
124093
|
-
log(
|
|
124754
|
+
log(import_picocolors52.default.dim(" Gemini CLI will load this context file automatically."));
|
|
124094
124755
|
} else if (target === "cursor") {
|
|
124095
|
-
log(
|
|
124756
|
+
log(import_picocolors52.default.dim(" Cursor will load this rule automatically."));
|
|
124096
124757
|
} else if (target === "codex") {
|
|
124097
|
-
log(
|
|
124758
|
+
log(import_picocolors52.default.dim(" Codex CLI will load this file automatically."));
|
|
124098
124759
|
} else {
|
|
124099
|
-
log(
|
|
124760
|
+
log(import_picocolors52.default.dim(` Copy or reference this file in your ${target} agent instructions.`));
|
|
124100
124761
|
}
|
|
124101
124762
|
return 0;
|
|
124102
124763
|
}
|
|
124103
124764
|
async function runSkillPrint(target, opts) {
|
|
124104
124765
|
const log = opts.write ?? ((line2) => console.log(line2));
|
|
124105
124766
|
if (!isValidTarget(target)) {
|
|
124106
|
-
log(`${
|
|
124107
|
-
log(
|
|
124767
|
+
log(`${import_picocolors52.default.red("\u2717")} Unknown target: ${import_picocolors52.default.bold(target)}`);
|
|
124768
|
+
log(import_picocolors52.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
|
|
124108
124769
|
return 1;
|
|
124109
124770
|
}
|
|
124110
124771
|
process.stdout.write(generateSkillContent(target));
|
|
@@ -124113,8 +124774,8 @@ async function runSkillPrint(target, opts) {
|
|
|
124113
124774
|
async function runSkillPath(target, opts) {
|
|
124114
124775
|
const log = opts.write ?? ((line2) => console.log(line2));
|
|
124115
124776
|
if (!isValidTarget(target)) {
|
|
124116
|
-
log(`${
|
|
124117
|
-
log(
|
|
124777
|
+
log(`${import_picocolors52.default.red("\u2717")} Unknown target: ${import_picocolors52.default.bold(target)}`);
|
|
124778
|
+
log(import_picocolors52.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
|
|
124118
124779
|
return 1;
|
|
124119
124780
|
}
|
|
124120
124781
|
const outPath = getSkillInstallPath(target, { global: opts.global, cwd: opts.cwd });
|
|
@@ -124124,7 +124785,7 @@ async function runSkillPath(target, opts) {
|
|
|
124124
124785
|
|
|
124125
124786
|
// ../../packages/cli/src/commands/login.ts
|
|
124126
124787
|
init_cjs_shims();
|
|
124127
|
-
var
|
|
124788
|
+
var import_picocolors53 = __toESM(require_picocolors(), 1);
|
|
124128
124789
|
var sleep2 = (ms) => new Promise((resolve13) => setTimeout(resolve13, ms));
|
|
124129
124790
|
async function loginWithToken(apiBaseUrl, token) {
|
|
124130
124791
|
const client = new CloudClient(apiBaseUrl, token);
|
|
@@ -124140,19 +124801,19 @@ async function loginWithToken(apiBaseUrl, token) {
|
|
|
124140
124801
|
}
|
|
124141
124802
|
});
|
|
124142
124803
|
console.log(
|
|
124143
|
-
`${
|
|
124804
|
+
`${import_picocolors53.default.green("\u2713")} Logged in as ${import_picocolors53.default.bold(me3.user.primaryEmail)}. Run ${import_picocolors53.default.bold("horus cloud link")} to connect this repo.`
|
|
124144
124805
|
);
|
|
124145
124806
|
return 0;
|
|
124146
124807
|
} catch (err2) {
|
|
124147
124808
|
if (err2 instanceof CloudOfflineError) {
|
|
124148
|
-
console.error(
|
|
124809
|
+
console.error(import_picocolors53.default.red(err2.message));
|
|
124149
124810
|
return 1;
|
|
124150
124811
|
}
|
|
124151
124812
|
if (err2 instanceof CloudError && err2.status === 401) {
|
|
124152
|
-
console.error(
|
|
124813
|
+
console.error(import_picocolors53.default.red("That token is not valid. Create a fresh one in the dashboard and try again."));
|
|
124153
124814
|
return 1;
|
|
124154
124815
|
}
|
|
124155
|
-
console.error(
|
|
124816
|
+
console.error(import_picocolors53.default.red(`Login failed: ${err2.message}`));
|
|
124156
124817
|
return 1;
|
|
124157
124818
|
}
|
|
124158
124819
|
}
|
|
@@ -124163,19 +124824,19 @@ async function loginWithBrowser(apiBaseUrl) {
|
|
|
124163
124824
|
session = await client.startCliSession();
|
|
124164
124825
|
} catch (err2) {
|
|
124165
124826
|
if (err2 instanceof CloudOfflineError) {
|
|
124166
|
-
console.error(
|
|
124827
|
+
console.error(import_picocolors53.default.red(err2.message));
|
|
124167
124828
|
return 1;
|
|
124168
124829
|
}
|
|
124169
|
-
console.error(
|
|
124830
|
+
console.error(import_picocolors53.default.red(`Could not start login: ${err2.message}`));
|
|
124170
124831
|
return 1;
|
|
124171
124832
|
}
|
|
124172
124833
|
console.log("");
|
|
124173
124834
|
console.log(` To sign in, open this URL in your browser:`);
|
|
124174
|
-
console.log(` ${
|
|
124835
|
+
console.log(` ${import_picocolors53.default.cyan(import_picocolors53.default.bold(session.verificationUri))}`);
|
|
124175
124836
|
console.log("");
|
|
124176
|
-
console.log(` and enter the code: ${
|
|
124837
|
+
console.log(` and enter the code: ${import_picocolors53.default.bold(session.userCode)}`);
|
|
124177
124838
|
console.log("");
|
|
124178
|
-
console.log(
|
|
124839
|
+
console.log(import_picocolors53.default.dim(` Waiting for approval\u2026 (press Ctrl+C to cancel)`));
|
|
124179
124840
|
openBrowser(session.verificationUriComplete);
|
|
124180
124841
|
const deadline = Date.now() + session.expiresIn * 1e3;
|
|
124181
124842
|
let intervalMs = Math.max(session.interval, 1) * 1e3;
|
|
@@ -124186,7 +124847,7 @@ async function loginWithBrowser(apiBaseUrl) {
|
|
|
124186
124847
|
poll = await client.pollCliSession(session.deviceCode);
|
|
124187
124848
|
} catch (err2) {
|
|
124188
124849
|
if (err2 instanceof CloudOfflineError) {
|
|
124189
|
-
console.error(
|
|
124850
|
+
console.error(import_picocolors53.default.red(`
|
|
124190
124851
|
${err2.message}`));
|
|
124191
124852
|
return 1;
|
|
124192
124853
|
}
|
|
@@ -124199,14 +124860,14 @@ ${err2.message}`));
|
|
|
124199
124860
|
intervalMs += 2e3;
|
|
124200
124861
|
break;
|
|
124201
124862
|
case "denied":
|
|
124202
|
-
console.error(
|
|
124863
|
+
console.error(import_picocolors53.default.red("\nLogin was denied in the browser."));
|
|
124203
124864
|
return 1;
|
|
124204
124865
|
case "expired":
|
|
124205
|
-
console.error(
|
|
124866
|
+
console.error(import_picocolors53.default.red("\nThis login request expired. Run `horus login` again."));
|
|
124206
124867
|
return 1;
|
|
124207
124868
|
case "approved":
|
|
124208
124869
|
if (!poll.token || !poll.account) {
|
|
124209
|
-
console.error(
|
|
124870
|
+
console.error(import_picocolors53.default.red("\nLogin approved but no token was returned. Try again."));
|
|
124210
124871
|
return 1;
|
|
124211
124872
|
}
|
|
124212
124873
|
writeAuth({
|
|
@@ -124216,12 +124877,12 @@ ${err2.message}`));
|
|
|
124216
124877
|
});
|
|
124217
124878
|
console.log(
|
|
124218
124879
|
`
|
|
124219
|
-
${
|
|
124880
|
+
${import_picocolors53.default.green("\u2713")} Logged in as ${import_picocolors53.default.bold(poll.account.email)}. Run ${import_picocolors53.default.bold("horus cloud link")} to connect this repo.`
|
|
124220
124881
|
);
|
|
124221
124882
|
return 0;
|
|
124222
124883
|
}
|
|
124223
124884
|
}
|
|
124224
|
-
console.error(
|
|
124885
|
+
console.error(import_picocolors53.default.red("\nTimed out waiting for approval. Run `horus login` again."));
|
|
124225
124886
|
return 1;
|
|
124226
124887
|
}
|
|
124227
124888
|
async function runLogin(opts = {}) {
|
|
@@ -124235,7 +124896,7 @@ async function runLogin(opts = {}) {
|
|
|
124235
124896
|
async function runLogout() {
|
|
124236
124897
|
const auth = readAuth();
|
|
124237
124898
|
if (!auth) {
|
|
124238
|
-
console.log(
|
|
124899
|
+
console.log(import_picocolors53.default.dim("Not logged in."));
|
|
124239
124900
|
return 0;
|
|
124240
124901
|
}
|
|
124241
124902
|
const session = authedClient();
|
|
@@ -124249,13 +124910,13 @@ async function runLogout() {
|
|
|
124249
124910
|
}
|
|
124250
124911
|
}
|
|
124251
124912
|
clearAuth();
|
|
124252
|
-
console.log(`${
|
|
124913
|
+
console.log(`${import_picocolors53.default.green("\u2713")} Logged out. Local mode still works.`);
|
|
124253
124914
|
return 0;
|
|
124254
124915
|
}
|
|
124255
124916
|
|
|
124256
124917
|
// ../../packages/cli/src/commands/cloud.ts
|
|
124257
124918
|
init_cjs_shims();
|
|
124258
|
-
var
|
|
124919
|
+
var import_picocolors54 = __toESM(require_picocolors(), 1);
|
|
124259
124920
|
var import_promises4 = require("readline/promises");
|
|
124260
124921
|
|
|
124261
124922
|
// ../../packages/cli/src/lib/cloud/git.ts
|
|
@@ -124300,7 +124961,7 @@ async function runCloudLink(opts = {}) {
|
|
|
124300
124961
|
const root = repoRootOrCwd(opts.cwd);
|
|
124301
124962
|
const session = authedClient();
|
|
124302
124963
|
if (!session) {
|
|
124303
|
-
console.error(
|
|
124964
|
+
console.error(import_picocolors54.default.red(`Not logged in. Run ${import_picocolors54.default.bold("horus login")} first.`));
|
|
124304
124965
|
return 1;
|
|
124305
124966
|
}
|
|
124306
124967
|
let ctx;
|
|
@@ -124310,7 +124971,7 @@ async function runCloudLink(opts = {}) {
|
|
|
124310
124971
|
return reportCloudError(err2);
|
|
124311
124972
|
}
|
|
124312
124973
|
const remote = detectGitRemote(root);
|
|
124313
|
-
if (remote) console.log(
|
|
124974
|
+
if (remote) console.log(import_picocolors54.default.dim(`Detected git remote: ${remote.remoteUrl}`));
|
|
124314
124975
|
let resolved = null;
|
|
124315
124976
|
let target = opts.project;
|
|
124316
124977
|
if (!target) {
|
|
@@ -124326,7 +124987,7 @@ async function runCloudLink(opts = {}) {
|
|
|
124326
124987
|
const org = ctx.organizations.find((o5) => o5.id === match.organizationId);
|
|
124327
124988
|
if (ws && org) {
|
|
124328
124989
|
target = `${org.slug}/${ws.slug}/${match.slug}`;
|
|
124329
|
-
console.log(
|
|
124990
|
+
console.log(import_picocolors54.default.dim(`Matched existing project by remote: ${import_picocolors54.default.bold(target)}`));
|
|
124330
124991
|
}
|
|
124331
124992
|
}
|
|
124332
124993
|
}
|
|
@@ -124335,8 +124996,8 @@ async function runCloudLink(opts = {}) {
|
|
|
124335
124996
|
if (created === "aborted") return 1;
|
|
124336
124997
|
if (!created) {
|
|
124337
124998
|
console.error(
|
|
124338
|
-
|
|
124339
|
-
Run ${
|
|
124999
|
+
import_picocolors54.default.red("No project to link.") + `
|
|
125000
|
+
Run ${import_picocolors54.default.bold("horus cloud link")} in a TTY to create one, pass ${import_picocolors54.default.bold("--project <org/workspace/project>")}, or create a project at ${import_picocolors54.default.bold("https://cloud.horus.sh")}.`
|
|
124340
125001
|
);
|
|
124341
125002
|
return 1;
|
|
124342
125003
|
}
|
|
@@ -124346,8 +125007,8 @@ async function runCloudLink(opts = {}) {
|
|
|
124346
125007
|
resolved = resolveTriple(ctx, target);
|
|
124347
125008
|
if (!resolved) {
|
|
124348
125009
|
console.error(
|
|
124349
|
-
|
|
124350
|
-
Run ${
|
|
125010
|
+
import_picocolors54.default.red(`You don't have access to ${import_picocolors54.default.bold(target)}.`) + `
|
|
125011
|
+
Run ${import_picocolors54.default.bold("horus context list")} to see available projects.`
|
|
124351
125012
|
);
|
|
124352
125013
|
return 1;
|
|
124353
125014
|
}
|
|
@@ -124360,10 +125021,10 @@ async function runCloudLink(opts = {}) {
|
|
|
124360
125021
|
project: resolved.project
|
|
124361
125022
|
});
|
|
124362
125023
|
console.log(
|
|
124363
|
-
`${
|
|
125024
|
+
`${import_picocolors54.default.green("\u2713")} Linked. Context for this repo is now ${import_picocolors54.default.bold(label)} ${import_picocolors54.default.dim("(cloud)")}.`
|
|
124364
125025
|
);
|
|
124365
125026
|
console.log(
|
|
124366
|
-
|
|
125027
|
+
import_picocolors54.default.dim(` Investigations here save to Horus Cloud. ${import_picocolors54.default.bold("horus context use local")} to switch back.`)
|
|
124367
125028
|
);
|
|
124368
125029
|
return 0;
|
|
124369
125030
|
}
|
|
@@ -124371,11 +125032,11 @@ async function runCloudUnlink(opts = {}) {
|
|
|
124371
125032
|
const root = repoRootOrCwd(opts.cwd);
|
|
124372
125033
|
const cfg = readCloudConfig(root);
|
|
124373
125034
|
if (!cfg || cfg.context !== "cloud") {
|
|
124374
|
-
console.log(
|
|
125035
|
+
console.log(import_picocolors54.default.dim("This repo isn't linked to a cloud project."));
|
|
124375
125036
|
return 0;
|
|
124376
125037
|
}
|
|
124377
125038
|
clearCloudConfig(root);
|
|
124378
|
-
console.log(`${
|
|
125039
|
+
console.log(`${import_picocolors54.default.green("\u2713")} Unlinked. This repo is back to ${import_picocolors54.default.bold("local")} mode.`);
|
|
124379
125040
|
return 0;
|
|
124380
125041
|
}
|
|
124381
125042
|
async function runCloudStatus(opts = {}) {
|
|
@@ -124383,18 +125044,18 @@ async function runCloudStatus(opts = {}) {
|
|
|
124383
125044
|
const cfg = readCloudConfig(root);
|
|
124384
125045
|
const session = authedClient();
|
|
124385
125046
|
if (!isCloudActive(cfg) || !cfg?.project) {
|
|
124386
|
-
console.log(`${
|
|
124387
|
-
console.log(`${
|
|
125047
|
+
console.log(`${import_picocolors54.default.bold("Context:")} local`);
|
|
125048
|
+
console.log(`${import_picocolors54.default.bold("Storage:")} local Postgres (~/.horus)`);
|
|
124388
125049
|
console.log(
|
|
124389
|
-
|
|
125050
|
+
import_picocolors54.default.dim(`Tip: ${import_picocolors54.default.bold("horus login")} then ${import_picocolors54.default.bold("horus cloud link")} to share investigations with your team.`)
|
|
124390
125051
|
);
|
|
124391
125052
|
return 0;
|
|
124392
125053
|
}
|
|
124393
125054
|
const triple = `${cfg.organization?.slug}/${cfg.workspace?.slug}/${cfg.project.slug}`;
|
|
124394
|
-
console.log(`${
|
|
125055
|
+
console.log(`${import_picocolors54.default.bold("Context:")} ${triple} ${import_picocolors54.default.dim("(cloud)")}`);
|
|
124395
125056
|
let projectLine = `${cfg.project.slug}`;
|
|
124396
125057
|
let metaLines = [];
|
|
124397
|
-
let account =
|
|
125058
|
+
let account = import_picocolors54.default.dim("not logged in");
|
|
124398
125059
|
if (session) {
|
|
124399
125060
|
account = session.auth.account.email;
|
|
124400
125061
|
try {
|
|
@@ -124409,9 +125070,9 @@ async function runCloudStatus(opts = {}) {
|
|
|
124409
125070
|
} catch {
|
|
124410
125071
|
}
|
|
124411
125072
|
}
|
|
124412
|
-
console.log(`${
|
|
125073
|
+
console.log(`${import_picocolors54.default.bold("Project:")} ${projectLine}`);
|
|
124413
125074
|
for (const line2 of metaLines) console.log(line2);
|
|
124414
|
-
console.log(`${
|
|
125075
|
+
console.log(`${import_picocolors54.default.bold("Account:")} ${account}`);
|
|
124415
125076
|
return 0;
|
|
124416
125077
|
}
|
|
124417
125078
|
async function runCloudSync(opts = {}) {
|
|
@@ -124419,13 +125080,13 @@ async function runCloudSync(opts = {}) {
|
|
|
124419
125080
|
const cfg = readCloudConfig(root);
|
|
124420
125081
|
if (!isCloudActive(cfg) || !cfg.project) {
|
|
124421
125082
|
console.error(
|
|
124422
|
-
|
|
125083
|
+
import_picocolors54.default.red("This repo isn't linked to a cloud project.") + ` Run ${import_picocolors54.default.bold("horus cloud link")} first.`
|
|
124423
125084
|
);
|
|
124424
125085
|
return 1;
|
|
124425
125086
|
}
|
|
124426
125087
|
const session = authedClient();
|
|
124427
125088
|
if (!session) {
|
|
124428
|
-
console.error(
|
|
125089
|
+
console.error(import_picocolors54.default.red(`Not logged in. Run ${import_picocolors54.default.bold("horus login")} first.`));
|
|
124429
125090
|
return 1;
|
|
124430
125091
|
}
|
|
124431
125092
|
const { db, sql: sql2 } = await openDb(await resolveDbUrl(opts.config));
|
|
@@ -124443,26 +125104,26 @@ async function runCloudSync(opts = {}) {
|
|
|
124443
125104
|
const target = `${cfg.organization?.slug}/${cfg.workspace?.slug}/${cfg.project.slug}`;
|
|
124444
125105
|
if (uploadable.length === 0) {
|
|
124445
125106
|
console.log(
|
|
124446
|
-
|
|
125107
|
+
import_picocolors54.default.dim(
|
|
124447
125108
|
`No local investigations with reports to upload.` + (skippedNoReport ? ` (${skippedNoReport} without a report skipped)` : "")
|
|
124448
125109
|
)
|
|
124449
125110
|
);
|
|
124450
125111
|
return 0;
|
|
124451
125112
|
}
|
|
124452
|
-
console.log(
|
|
125113
|
+
console.log(import_picocolors54.default.bold(`Will upload ${uploadable.length} investigation(s) to ${target} ${import_picocolors54.default.dim("(cloud)")}:`));
|
|
124453
125114
|
for (const c4 of uploadable.slice(0, 20)) {
|
|
124454
|
-
console.log(` ${
|
|
125115
|
+
console.log(` ${import_picocolors54.default.dim(c4.id.slice(0, 8))} ${(c4.title ?? "untitled").slice(0, 70)}`);
|
|
124455
125116
|
}
|
|
124456
|
-
if (uploadable.length > 20) console.log(
|
|
124457
|
-
if (skippedNoReport) console.log(
|
|
125117
|
+
if (uploadable.length > 20) console.log(import_picocolors54.default.dim(` \u2026and ${uploadable.length - 20} more`));
|
|
125118
|
+
if (skippedNoReport) console.log(import_picocolors54.default.dim(` (${skippedNoReport} local investigation(s) without a report will be skipped)`));
|
|
124458
125119
|
if (opts.dryRun) {
|
|
124459
|
-
console.log(
|
|
125120
|
+
console.log(import_picocolors54.default.dim("Dry run \u2014 nothing uploaded. Re-run without --dry-run to upload."));
|
|
124460
125121
|
return 0;
|
|
124461
125122
|
}
|
|
124462
125123
|
if (!opts.yes) {
|
|
124463
125124
|
if (!process.stdin.isTTY) {
|
|
124464
125125
|
console.error(
|
|
124465
|
-
|
|
125126
|
+
import_picocolors54.default.yellow(`Re-run with ${import_picocolors54.default.bold("--yes")} to upload, or ${import_picocolors54.default.bold("--dry-run")} to preview only.`)
|
|
124466
125127
|
);
|
|
124467
125128
|
return 1;
|
|
124468
125129
|
}
|
|
@@ -124470,7 +125131,7 @@ async function runCloudSync(opts = {}) {
|
|
|
124470
125131
|
try {
|
|
124471
125132
|
const answer = (await rl.question(`Upload ${uploadable.length} investigation(s) to ${target}? (y/N) `)).trim().toLowerCase();
|
|
124472
125133
|
if (answer !== "y" && answer !== "yes") {
|
|
124473
|
-
console.log(
|
|
125134
|
+
console.log(import_picocolors54.default.dim("Aborted. Nothing uploaded."));
|
|
124474
125135
|
return 0;
|
|
124475
125136
|
}
|
|
124476
125137
|
} finally {
|
|
@@ -124483,18 +125144,18 @@ async function runCloudSync(opts = {}) {
|
|
|
124483
125144
|
try {
|
|
124484
125145
|
const refs = await uploadInvestigationToCloud(session.client, cfg, c4.report, { db });
|
|
124485
125146
|
created++;
|
|
124486
|
-
console.log(`${
|
|
125147
|
+
console.log(`${import_picocolors54.default.green("\u2713")} ${import_picocolors54.default.dim(c4.id.slice(0, 8))} \u2192 ${refs.investigationId}`);
|
|
124487
125148
|
} catch (err2) {
|
|
124488
125149
|
failed++;
|
|
124489
|
-
console.error(`${
|
|
125150
|
+
console.error(`${import_picocolors54.default.red("\u2717")} ${import_picocolors54.default.dim(c4.id.slice(0, 8))} ${err2.message}`);
|
|
124490
125151
|
}
|
|
124491
125152
|
}
|
|
124492
125153
|
console.log("");
|
|
124493
125154
|
console.log(
|
|
124494
|
-
`${
|
|
125155
|
+
`${import_picocolors54.default.bold("Sync complete:")} ${import_picocolors54.default.green(`${created} uploaded`)}, ${skippedNoReport} skipped, ` + (failed ? import_picocolors54.default.red(`${failed} failed`) : "0 failed") + "."
|
|
124495
125156
|
);
|
|
124496
125157
|
console.log(
|
|
124497
|
-
|
|
125158
|
+
import_picocolors54.default.dim("Local data was not modified. Re-running is safe \u2014 duplicates are deduped by idempotency key.")
|
|
124498
125159
|
);
|
|
124499
125160
|
return failed > 0 ? 1 : 0;
|
|
124500
125161
|
} finally {
|
|
@@ -124505,8 +125166,8 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
|
|
|
124505
125166
|
if (!process.stdin.isTTY && !yes) return null;
|
|
124506
125167
|
if (ctx.organizations.length === 0) {
|
|
124507
125168
|
console.error(
|
|
124508
|
-
|
|
124509
|
-
Create one at ${
|
|
125169
|
+
import_picocolors54.default.red("You're not a member of any organization yet.") + `
|
|
125170
|
+
Create one at ${import_picocolors54.default.bold("https://cloud.horus.sh")} first.`
|
|
124510
125171
|
);
|
|
124511
125172
|
return null;
|
|
124512
125173
|
}
|
|
@@ -124531,9 +125192,9 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
|
|
|
124531
125192
|
const wsName = await ask2("New workspace name", repoName || "default");
|
|
124532
125193
|
const ws = await client.createWorkspace(org.id, { name: wsName });
|
|
124533
125194
|
workspace = { id: ws.id, slug: ws.slug };
|
|
124534
|
-
console.log(
|
|
125195
|
+
console.log(import_picocolors54.default.dim(`Created workspace ${import_picocolors54.default.bold(ws.slug)}.`));
|
|
124535
125196
|
} else {
|
|
124536
|
-
console.log(`Workspaces in ${
|
|
125197
|
+
console.log(`Workspaces in ${import_picocolors54.default.bold(org.slug)}:`);
|
|
124537
125198
|
orgWorkspaces.forEach((w4, i3) => console.log(` ${i3 + 1}) ${w4.slug}`));
|
|
124538
125199
|
console.log(` ${orgWorkspaces.length + 1}) + create a new workspace`);
|
|
124539
125200
|
const pick2 = Number(await ask2("Workspace number", "1"));
|
|
@@ -124541,7 +125202,7 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
|
|
|
124541
125202
|
const wsName = await ask2("New workspace name", repoName || "default");
|
|
124542
125203
|
const ws = await client.createWorkspace(org.id, { name: wsName });
|
|
124543
125204
|
workspace = { id: ws.id, slug: ws.slug };
|
|
124544
|
-
console.log(
|
|
125205
|
+
console.log(import_picocolors54.default.dim(`Created workspace ${import_picocolors54.default.bold(ws.slug)}.`));
|
|
124545
125206
|
} else {
|
|
124546
125207
|
const chosen = orgWorkspaces[pick2 - 1] ?? orgWorkspaces[0];
|
|
124547
125208
|
workspace = { id: chosen.id, slug: chosen.slug };
|
|
@@ -124553,7 +125214,7 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
|
|
|
124553
125214
|
remoteUrl: remote?.remoteUrl,
|
|
124554
125215
|
provider: remote ? inferProvider(remote.remoteUrl) : void 0
|
|
124555
125216
|
});
|
|
124556
|
-
console.log(
|
|
125217
|
+
console.log(import_picocolors54.default.dim(`Created project ${import_picocolors54.default.bold(project.slug)}.`));
|
|
124557
125218
|
return {
|
|
124558
125219
|
organization: { id: org.id, slug: org.slug },
|
|
124559
125220
|
workspace,
|
|
@@ -124569,8 +125230,8 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
|
|
|
124569
125230
|
|
|
124570
125231
|
// ../../packages/cli/src/commands/telemetry.ts
|
|
124571
125232
|
init_cjs_shims();
|
|
124572
|
-
var
|
|
124573
|
-
var
|
|
125233
|
+
var import_picocolors56 = __toESM(require_picocolors(), 1);
|
|
125234
|
+
var import_node_crypto11 = require("crypto");
|
|
124574
125235
|
|
|
124575
125236
|
// ../../packages/cli/src/lib/telemetry/transport.ts
|
|
124576
125237
|
init_cjs_shims();
|
|
@@ -124630,7 +125291,7 @@ async function deleteRemoteTelemetry(installId, opts = {}) {
|
|
|
124630
125291
|
|
|
124631
125292
|
// ../../packages/cli/src/lib/telemetry/notice.ts
|
|
124632
125293
|
init_cjs_shims();
|
|
124633
|
-
var
|
|
125294
|
+
var import_picocolors55 = __toESM(require_picocolors(), 1);
|
|
124634
125295
|
var PRIVACY_URL = "https://horus.sh/privacy";
|
|
124635
125296
|
var SUPPRESS_FIRST_TOKEN = /* @__PURE__ */ new Set(["telemetry", "help"]);
|
|
124636
125297
|
var SUPPRESS_FLAGS = /* @__PURE__ */ new Set(["-V", "--version", "-h", "--help"]);
|
|
@@ -124642,11 +125303,11 @@ function shouldSuppressFor(argv) {
|
|
|
124642
125303
|
return firstToken != null && SUPPRESS_FIRST_TOKEN.has(firstToken);
|
|
124643
125304
|
}
|
|
124644
125305
|
function banner() {
|
|
124645
|
-
const b5 =
|
|
124646
|
-
const dim =
|
|
125306
|
+
const b5 = import_picocolors55.default.bold;
|
|
125307
|
+
const dim = import_picocolors55.default.dim;
|
|
124647
125308
|
return [
|
|
124648
125309
|
"",
|
|
124649
|
-
|
|
125310
|
+
import_picocolors55.default.cyan(b5("Horus collects anonymous usage data to improve the tool.")),
|
|
124650
125311
|
dim(" \u2022 On by default: command names, timings, success/failure, and where the"),
|
|
124651
125312
|
dim(" engine ran out of evidence. No file contents, queries, or secrets."),
|
|
124652
125313
|
dim(" \u2022 Off by default: your investigation inputs/outputs (opt in to help train"),
|
|
@@ -124654,7 +125315,7 @@ function banner() {
|
|
|
124654
125315
|
dim(" \u2022 If you use Horus Cloud, linked investigations sync to your workspace."),
|
|
124655
125316
|
"",
|
|
124656
125317
|
` ${dim("Opt out anytime:")} ${b5("horus telemetry disable")} ${dim("\xB7")} ${b5("HORUS_TELEMETRY=0")} ${dim("\xB7")} ${b5("DO_NOT_TRACK=1")}`,
|
|
124657
|
-
` ${dim("Details:")} ${
|
|
125318
|
+
` ${dim("Details:")} ${import_picocolors55.default.underline(PRIVACY_URL)}`,
|
|
124658
125319
|
""
|
|
124659
125320
|
].join("\n");
|
|
124660
125321
|
}
|
|
@@ -124677,45 +125338,45 @@ function maybeShowFirstRunNotice(argv = process.argv) {
|
|
|
124677
125338
|
|
|
124678
125339
|
// ../../packages/cli/src/commands/telemetry.ts
|
|
124679
125340
|
function onOff(enabled) {
|
|
124680
|
-
return enabled ?
|
|
125341
|
+
return enabled ? import_picocolors56.default.green("on") : import_picocolors56.default.dim("off");
|
|
124681
125342
|
}
|
|
124682
125343
|
function warnIfEnvOverrides() {
|
|
124683
125344
|
const decision = resolveConsent();
|
|
124684
125345
|
if (decision.forcedOff) {
|
|
124685
125346
|
console.log(
|
|
124686
|
-
|
|
125347
|
+
import_picocolors56.default.yellow(
|
|
124687
125348
|
`
|
|
124688
125349
|
Note: telemetry is currently forced off by your environment (${decision.reason}).`
|
|
124689
125350
|
)
|
|
124690
125351
|
);
|
|
124691
|
-
console.log(
|
|
125352
|
+
console.log(import_picocolors56.default.dim("Your saved preference will apply once that override is removed."));
|
|
124692
125353
|
} else if (decision.source === "ci") {
|
|
124693
125354
|
console.log(
|
|
124694
|
-
|
|
125355
|
+
import_picocolors56.default.yellow("\nNote: CI environment detected \u2014 telemetry stays off here regardless.")
|
|
124695
125356
|
);
|
|
124696
125357
|
}
|
|
124697
125358
|
}
|
|
124698
125359
|
async function runTelemetryStatus() {
|
|
124699
125360
|
const state = readTelemetryState();
|
|
124700
125361
|
const decision = resolveConsent({ state });
|
|
124701
|
-
console.log(
|
|
125362
|
+
console.log(import_picocolors56.default.bold("Horus telemetry"));
|
|
124702
125363
|
console.log(
|
|
124703
|
-
` Usage metadata (Tier A): ${onOff(decision.tierA)} ${
|
|
125364
|
+
` Usage metadata (Tier A): ${onOff(decision.tierA)} ${import_picocolors56.default.dim(`[${decision.source}]`)}`
|
|
124704
125365
|
);
|
|
124705
125366
|
console.log(` Content sharing (Tier B): ${onOff(decision.tierB)}`);
|
|
124706
|
-
console.log(
|
|
125367
|
+
console.log(import_picocolors56.default.dim(` Reason: ${decision.reason}`));
|
|
124707
125368
|
if (state) {
|
|
124708
|
-
console.log(
|
|
125369
|
+
console.log(import_picocolors56.default.dim(` Install ID: ${state.installId}`));
|
|
124709
125370
|
console.log(
|
|
124710
|
-
|
|
125371
|
+
import_picocolors56.default.dim(
|
|
124711
125372
|
` Saved: Tier A ${state.tierA.enabled ? "on" : "off"}, Tier B ${state.tierB.enabled ? "on" : "off"}`
|
|
124712
125373
|
)
|
|
124713
125374
|
);
|
|
124714
125375
|
} else {
|
|
124715
|
-
console.log(
|
|
125376
|
+
console.log(import_picocolors56.default.dim(" No saved preference yet (defaults apply)."));
|
|
124716
125377
|
}
|
|
124717
|
-
console.log(
|
|
124718
|
-
console.log(
|
|
125378
|
+
console.log(import_picocolors56.default.dim(` Config: ${telemetryPath()}`));
|
|
125379
|
+
console.log(import_picocolors56.default.dim(` Privacy: ${PRIVACY_URL}`));
|
|
124719
125380
|
if (!state || decision.source === "env" || decision.source === "ci") {
|
|
124720
125381
|
warnIfEnvOverrides();
|
|
124721
125382
|
}
|
|
@@ -124726,7 +125387,7 @@ async function runTelemetryEnable() {
|
|
|
124726
125387
|
s5.tierA.enabled = true;
|
|
124727
125388
|
if (!s5.tierA.noticeShownAt) s5.tierA.noticeShownAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
124728
125389
|
});
|
|
124729
|
-
console.log(
|
|
125390
|
+
console.log(import_picocolors56.default.green("Anonymous usage metadata (Tier A) is now ON. Thank you!"));
|
|
124730
125391
|
warnIfEnvOverrides();
|
|
124731
125392
|
return 0;
|
|
124732
125393
|
}
|
|
@@ -124736,7 +125397,7 @@ async function runTelemetryDisable() {
|
|
|
124736
125397
|
s5.tierB.enabled = false;
|
|
124737
125398
|
if (!s5.tierA.noticeShownAt) s5.tierA.noticeShownAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
124738
125399
|
});
|
|
124739
|
-
console.log(
|
|
125400
|
+
console.log(import_picocolors56.default.yellow("All telemetry is now OFF (Tier A and Tier B)."));
|
|
124740
125401
|
return 0;
|
|
124741
125402
|
}
|
|
124742
125403
|
async function runTelemetryEnableContent() {
|
|
@@ -124747,10 +125408,10 @@ async function runTelemetryEnableContent() {
|
|
|
124747
125408
|
if (!s5.tierA.noticeShownAt) s5.tierA.noticeShownAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
124748
125409
|
});
|
|
124749
125410
|
console.log(
|
|
124750
|
-
|
|
125411
|
+
import_picocolors56.default.green("Content sharing (Tier B) is now ON \u2014 redacted inputs/outputs help improve Horus.")
|
|
124751
125412
|
);
|
|
124752
|
-
console.log(
|
|
124753
|
-
console.log(
|
|
125413
|
+
console.log(import_picocolors56.default.dim("Content is scrubbed of secrets/PII before it ever leaves your machine."));
|
|
125414
|
+
console.log(import_picocolors56.default.dim(`What this means: ${PRIVACY_URL}`));
|
|
124754
125415
|
warnIfEnvOverrides();
|
|
124755
125416
|
return 0;
|
|
124756
125417
|
}
|
|
@@ -124758,16 +125419,16 @@ async function runTelemetryDisableContent() {
|
|
|
124758
125419
|
updateTelemetryState((s5) => {
|
|
124759
125420
|
s5.tierB.enabled = false;
|
|
124760
125421
|
});
|
|
124761
|
-
console.log(
|
|
125422
|
+
console.log(import_picocolors56.default.yellow("Content sharing (Tier B) is now OFF. Usage metadata is unchanged."));
|
|
124762
125423
|
return 0;
|
|
124763
125424
|
}
|
|
124764
125425
|
async function runTelemetryResetId() {
|
|
124765
|
-
const next = (0,
|
|
125426
|
+
const next = (0, import_node_crypto11.randomUUID)();
|
|
124766
125427
|
updateTelemetryState((s5) => {
|
|
124767
125428
|
s5.installId = next;
|
|
124768
125429
|
});
|
|
124769
|
-
console.log(
|
|
124770
|
-
console.log(
|
|
125430
|
+
console.log(import_picocolors56.default.green("Install ID reset."));
|
|
125431
|
+
console.log(import_picocolors56.default.dim(` New install ID: ${next}`));
|
|
124771
125432
|
return 0;
|
|
124772
125433
|
}
|
|
124773
125434
|
async function runTelemetryDelete() {
|
|
@@ -124775,9 +125436,9 @@ async function runTelemetryDelete() {
|
|
|
124775
125436
|
if (installId) await deleteRemoteTelemetry(installId);
|
|
124776
125437
|
deleteTelemetryState();
|
|
124777
125438
|
clearSpool();
|
|
124778
|
-
console.log(
|
|
125439
|
+
console.log(import_picocolors56.default.green("Telemetry deleted \u2014 local state cleared and a server purge requested."));
|
|
124779
125440
|
console.log(
|
|
124780
|
-
|
|
125441
|
+
import_picocolors56.default.dim(
|
|
124781
125442
|
"Next run will treat this as a fresh install and re-show the notice. If the purge could not reach the server (offline), re-run this command when back online."
|
|
124782
125443
|
)
|
|
124783
125444
|
);
|
|
@@ -124821,8 +125482,8 @@ function installCommandTelemetry(program2) {
|
|
|
124821
125482
|
// ../../packages/cli/src/commands/eval.ts
|
|
124822
125483
|
init_cjs_shims();
|
|
124823
125484
|
var import_promises5 = require("fs/promises");
|
|
124824
|
-
var
|
|
124825
|
-
var
|
|
125485
|
+
var import_node_path28 = require("path");
|
|
125486
|
+
var import_picocolors57 = __toESM(require_picocolors(), 1);
|
|
124826
125487
|
function resolveProject2(config2, repo) {
|
|
124827
125488
|
let project;
|
|
124828
125489
|
try {
|
|
@@ -124830,7 +125491,7 @@ function resolveProject2(config2, repo) {
|
|
|
124830
125491
|
} catch {
|
|
124831
125492
|
}
|
|
124832
125493
|
if (!project) {
|
|
124833
|
-
console.error(
|
|
125494
|
+
console.error(import_picocolors57.default.red("Could not resolve a project \u2014 pass --repo <name> or run inside a repo."));
|
|
124834
125495
|
return null;
|
|
124835
125496
|
}
|
|
124836
125497
|
return project;
|
|
@@ -124839,7 +125500,7 @@ function readSlice(opts) {
|
|
|
124839
125500
|
let source;
|
|
124840
125501
|
if (opts.source !== void 0) {
|
|
124841
125502
|
if (!isOutcomeSource(opts.source)) {
|
|
124842
|
-
console.error(
|
|
125503
|
+
console.error(import_picocolors57.default.red(`Unknown --source "${opts.source}" (one of: feedback, confirm).`));
|
|
124843
125504
|
return null;
|
|
124844
125505
|
}
|
|
124845
125506
|
source = opts.source;
|
|
@@ -124847,7 +125508,7 @@ function readSlice(opts) {
|
|
|
124847
125508
|
let since;
|
|
124848
125509
|
if (opts.days !== void 0) {
|
|
124849
125510
|
if (!Number.isFinite(opts.days) || opts.days <= 0) {
|
|
124850
|
-
console.error(
|
|
125511
|
+
console.error(import_picocolors57.default.red("--days must be a positive number."));
|
|
124851
125512
|
return null;
|
|
124852
125513
|
}
|
|
124853
125514
|
since = new Date(Date.now() - opts.days * 24 * 60 * 60 * 1e3);
|
|
@@ -124871,7 +125532,7 @@ async function runEvalBuild(opts) {
|
|
|
124871
125532
|
const project = resolveProject2(config2, opts.repo);
|
|
124872
125533
|
if (!project) return 1;
|
|
124873
125534
|
const version3 = opts.version ?? CORPUS_VERSION;
|
|
124874
|
-
const outDir = opts.out ? (0,
|
|
125535
|
+
const outDir = opts.out ? (0, import_node_path28.isAbsolute)(opts.out) ? opts.out : (0, import_node_path28.resolve)(process.cwd(), opts.out) : (0, import_node_path28.join)(process.cwd(), ".horus", "eval");
|
|
124875
125536
|
const { db, sql: sql2 } = await openDb(config2.database.url);
|
|
124876
125537
|
try {
|
|
124877
125538
|
const labels = await listOutcomeLabels(db, {
|
|
@@ -124887,34 +125548,34 @@ async function runEvalBuild(opts) {
|
|
|
124887
125548
|
const build = buildCorpus(labels, resolveReport);
|
|
124888
125549
|
const artifact = serializeCorpus(build, version3);
|
|
124889
125550
|
await (0, import_promises5.mkdir)(outDir, { recursive: true });
|
|
124890
|
-
const corpusPath = (0,
|
|
124891
|
-
const manifestPath = (0,
|
|
125551
|
+
const corpusPath = (0, import_node_path28.join)(outDir, artifact.filename);
|
|
125552
|
+
const manifestPath = (0, import_node_path28.join)(outDir, `corpus-${version3}.manifest.json`);
|
|
124892
125553
|
const manifest = { ...artifact.manifest, generatedAt: (/* @__PURE__ */ new Date()).toISOString(), project };
|
|
124893
125554
|
await (0, import_promises5.writeFile)(corpusPath, artifact.jsonl, "utf8");
|
|
124894
125555
|
await (0, import_promises5.writeFile)(manifestPath, JSON.stringify(manifest, null, 2) + "\n", "utf8");
|
|
124895
125556
|
if (opts.json) {
|
|
124896
125557
|
console.log(JSON.stringify({ project, corpusPath, manifestPath, manifest }, null, 2));
|
|
124897
125558
|
} else {
|
|
124898
|
-
console.log(
|
|
125559
|
+
console.log(import_picocolors57.default.bold(`Eval corpus \u2014 ${project}`));
|
|
124899
125560
|
console.log(
|
|
124900
|
-
` Rows: ${
|
|
125561
|
+
` Rows: ${import_picocolors57.default.green(String(build.rows.length))} ` + import_picocolors57.default.dim(
|
|
124901
125562
|
`(evaluated ${build.evaluated}, quarantined ${build.quarantined.length}, unjoinable ${build.unjoinable.length})`
|
|
124902
125563
|
)
|
|
124903
125564
|
);
|
|
124904
125565
|
console.log(
|
|
124905
|
-
|
|
125566
|
+
import_picocolors57.default.dim(
|
|
124906
125567
|
` Class balance: ${build.classBalance.yes} yes, ${build.classBalance.partly} partly, ${build.classBalance.no} no \xB7 source: ${build.bySource.feedback} feedback, ${build.bySource.confirm} confirm`
|
|
124907
125568
|
)
|
|
124908
125569
|
);
|
|
124909
|
-
console.log(` Corpus: ${
|
|
124910
|
-
console.log(` Manifest: ${
|
|
125570
|
+
console.log(` Corpus: ${import_picocolors57.default.cyan(corpusPath)}`);
|
|
125571
|
+
console.log(` Manifest: ${import_picocolors57.default.cyan(manifestPath)}`);
|
|
124911
125572
|
}
|
|
124912
125573
|
return 0;
|
|
124913
125574
|
} finally {
|
|
124914
125575
|
await sql2.end();
|
|
124915
125576
|
}
|
|
124916
125577
|
} catch (err2) {
|
|
124917
|
-
console.error(
|
|
125578
|
+
console.error(import_picocolors57.default.red(err2.message));
|
|
124918
125579
|
return 1;
|
|
124919
125580
|
}
|
|
124920
125581
|
}
|
|
@@ -124944,31 +125605,31 @@ async function runEvalBaseline(opts) {
|
|
|
124944
125605
|
console.log(JSON.stringify({ project, baseline, separation }, null, 2));
|
|
124945
125606
|
} else {
|
|
124946
125607
|
const pct2 = (n4) => `${(n4 * 100).toFixed(0)}%`;
|
|
124947
|
-
console.log(
|
|
125608
|
+
console.log(import_picocolors57.default.bold(`Eval baseline \u2014 ${project}`));
|
|
124948
125609
|
if (baseline.n === 0) {
|
|
124949
125610
|
console.log(
|
|
124950
|
-
|
|
125611
|
+
import_picocolors57.default.dim(
|
|
124951
125612
|
"No outcome labels yet. Leave feedback (`horus feedback`) or confirm an investigation (`horus memory confirm`) to seed the eval set."
|
|
124952
125613
|
)
|
|
124953
125614
|
);
|
|
124954
125615
|
} else {
|
|
124955
125616
|
console.log(
|
|
124956
|
-
` Strict hit-rate: ${
|
|
125617
|
+
` Strict hit-rate: ${import_picocolors57.default.green(pct2(baseline.strictHitRate))} ` + import_picocolors57.default.dim(`(weighted ${pct2(baseline.weightedHitRate)}) over ${baseline.n} investigation(s)`)
|
|
124957
125618
|
);
|
|
124958
125619
|
console.log(
|
|
124959
|
-
` Class balance: ${
|
|
125620
|
+
` Class balance: ${import_picocolors57.default.green(`${baseline.classBalance.yes} yes`)}, ${import_picocolors57.default.yellow(`${baseline.classBalance.partly} partly`)}, ${import_picocolors57.default.red(`${baseline.classBalance.no} no`)} \xB7 ` + import_picocolors57.default.dim(`source: ${baseline.bySource.feedback} feedback, ${baseline.bySource.confirm} confirm`)
|
|
124960
125621
|
);
|
|
124961
125622
|
if (separation.factors.length === 0) {
|
|
124962
125623
|
console.log(
|
|
124963
|
-
|
|
125624
|
+
import_picocolors57.default.dim(
|
|
124964
125625
|
` Feature separation: no discriminative sample yet (needs feedback rows with yes AND no verdicts and a ranked cause).`
|
|
124965
125626
|
)
|
|
124966
125627
|
);
|
|
124967
125628
|
} else {
|
|
124968
|
-
console.log(
|
|
125629
|
+
console.log(import_picocolors57.default.dim(` Feature separation (yes vs no, ${separation.evaluated} row(s)):`));
|
|
124969
125630
|
for (const f5 of separation.factors.slice(0, 10)) {
|
|
124970
125631
|
console.log(
|
|
124971
|
-
|
|
125632
|
+
import_picocolors57.default.dim(
|
|
124972
125633
|
` ${f5.factor}: \u0394 ${f5.separation.toFixed(3)} (yes ${f5.meanYes.toFixed(3)} vs no ${f5.meanNo.toFixed(3)}, effect ${f5.effectSize.toFixed(2)})`
|
|
124973
125634
|
)
|
|
124974
125635
|
);
|
|
@@ -124981,7 +125642,7 @@ async function runEvalBaseline(opts) {
|
|
|
124981
125642
|
await sql2.end();
|
|
124982
125643
|
}
|
|
124983
125644
|
} catch (err2) {
|
|
124984
|
-
console.error(
|
|
125645
|
+
console.error(import_picocolors57.default.red(err2.message));
|
|
124985
125646
|
return 1;
|
|
124986
125647
|
}
|
|
124987
125648
|
}
|
|
@@ -124989,10 +125650,10 @@ async function runEvalBaseline(opts) {
|
|
|
124989
125650
|
// ../../packages/cli/src/commands/train.ts
|
|
124990
125651
|
init_cjs_shims();
|
|
124991
125652
|
var import_promises6 = require("fs/promises");
|
|
124992
|
-
var
|
|
124993
|
-
var
|
|
124994
|
-
var
|
|
124995
|
-
var RERANKER_MODEL_PATH = (0,
|
|
125653
|
+
var import_node_path29 = require("path");
|
|
125654
|
+
var import_node_os11 = require("os");
|
|
125655
|
+
var import_picocolors58 = __toESM(require_picocolors(), 1);
|
|
125656
|
+
var RERANKER_MODEL_PATH = (0, import_node_path29.join)((0, import_node_os11.homedir)(), ".horus", "reranker.json");
|
|
124996
125657
|
function candidatesFromReport(blob) {
|
|
124997
125658
|
if (blob === null || typeof blob !== "object") return null;
|
|
124998
125659
|
const causes = blob.suspectedCauses;
|
|
@@ -125006,7 +125667,7 @@ async function runTrain(opts) {
|
|
|
125006
125667
|
let source;
|
|
125007
125668
|
if (opts.source !== void 0) {
|
|
125008
125669
|
if (!isOutcomeSource(opts.source)) {
|
|
125009
|
-
console.error(
|
|
125670
|
+
console.error(import_picocolors58.default.red(`Unknown --source "${opts.source}" (one of: feedback, confirm).`));
|
|
125010
125671
|
return 1;
|
|
125011
125672
|
}
|
|
125012
125673
|
source = opts.source;
|
|
@@ -125014,7 +125675,7 @@ async function runTrain(opts) {
|
|
|
125014
125675
|
let since;
|
|
125015
125676
|
if (opts.days !== void 0) {
|
|
125016
125677
|
if (!Number.isFinite(opts.days) || opts.days <= 0) {
|
|
125017
|
-
console.error(
|
|
125678
|
+
console.error(import_picocolors58.default.red("--days must be a positive number."));
|
|
125018
125679
|
return 1;
|
|
125019
125680
|
}
|
|
125020
125681
|
since = new Date(Date.now() - opts.days * 24 * 60 * 60 * 1e3);
|
|
@@ -125050,7 +125711,7 @@ async function runTrain(opts) {
|
|
|
125050
125711
|
await sql2.end();
|
|
125051
125712
|
}
|
|
125052
125713
|
} catch (err2) {
|
|
125053
|
-
console.error(
|
|
125714
|
+
console.error(import_picocolors58.default.red(`Could not read the local corpus: ${err2.message}`));
|
|
125054
125715
|
return 1;
|
|
125055
125716
|
}
|
|
125056
125717
|
const split = holdoutSplit(investigations2);
|
|
@@ -125058,48 +125719,48 @@ async function runTrain(opts) {
|
|
|
125058
125719
|
if (!result.ok) {
|
|
125059
125720
|
if (result.reason === "insufficient-corpus") {
|
|
125060
125721
|
console.log(
|
|
125061
|
-
|
|
125722
|
+
import_picocolors58.default.yellow(
|
|
125062
125723
|
`Not enough labeled investigations to train yet (have ${result.labeledInvestigations} with a known-correct cause; need \u2265${MIN_TRAIN_INVESTIGATIONS}).`
|
|
125063
125724
|
)
|
|
125064
125725
|
);
|
|
125065
|
-
console.log(
|
|
125726
|
+
console.log(import_picocolors58.default.dim(" Keep labeling outcomes with `horus feedback` \u2014 the reranker trains once the corpus is large enough."));
|
|
125066
125727
|
} else {
|
|
125067
|
-
console.log(
|
|
125728
|
+
console.log(import_picocolors58.default.yellow(`Cannot train a meaningful model yet: ${result.detail}.`));
|
|
125068
125729
|
}
|
|
125069
125730
|
return 0;
|
|
125070
125731
|
}
|
|
125071
125732
|
const { baselineHitRate, rerankedHitRate, delta, n: n4 } = result.holdout;
|
|
125072
|
-
console.log(
|
|
125733
|
+
console.log(import_picocolors58.default.bold("\nReranker training (local, per-tenant)\n"));
|
|
125073
125734
|
console.log(` Holdout investigations: ${n4}`);
|
|
125074
125735
|
console.log(` Baseline top-1 hit-rate: ${pct(baselineHitRate)}`);
|
|
125075
125736
|
console.log(` Reranked top-1 hit-rate: ${pct(rerankedHitRate)}`);
|
|
125076
125737
|
console.log(` Delta: ${delta >= 0 ? "+" : ""}${pct(delta)}`);
|
|
125077
125738
|
console.log("");
|
|
125078
125739
|
if (delta <= 0) {
|
|
125079
|
-
console.log(
|
|
125080
|
-
console.log(
|
|
125740
|
+
console.log(import_picocolors58.default.yellow(" The reranker did NOT beat the deterministic baseline \u2014 not saving a model."));
|
|
125741
|
+
console.log(import_picocolors58.default.dim(" Horus stays on its hand-tuned ranking. Re-run as more labels accumulate."));
|
|
125081
125742
|
return 0;
|
|
125082
125743
|
}
|
|
125083
125744
|
try {
|
|
125084
|
-
await (0, import_promises6.mkdir)((0,
|
|
125745
|
+
await (0, import_promises6.mkdir)((0, import_node_path29.join)((0, import_node_os11.homedir)(), ".horus"), { recursive: true });
|
|
125085
125746
|
const { ok: _ok, ...model } = result;
|
|
125086
125747
|
void _ok;
|
|
125087
125748
|
await (0, import_promises6.writeFile)(RERANKER_MODEL_PATH, JSON.stringify(model, null, 2) + "\n", "utf8");
|
|
125088
125749
|
} catch (err2) {
|
|
125089
|
-
console.error(
|
|
125750
|
+
console.error(import_picocolors58.default.red(`Trained, but could not write the model: ${err2.message}`));
|
|
125090
125751
|
return 1;
|
|
125091
125752
|
}
|
|
125092
|
-
console.log(
|
|
125093
|
-
console.log(
|
|
125753
|
+
console.log(import_picocolors58.default.green(` \u2713 Reranker beats baseline by +${pct(delta)} \u2014 saved to ${RERANKER_MODEL_PATH}`));
|
|
125754
|
+
console.log(import_picocolors58.default.dim(" It ships OFF by default. Enable it with `HORUS_RERANK=1 horus investigate \u2026`."));
|
|
125094
125755
|
return 0;
|
|
125095
125756
|
}
|
|
125096
125757
|
|
|
125097
125758
|
// ../../packages/cli/src/lib/report-crash.ts
|
|
125098
125759
|
init_cjs_shims();
|
|
125099
|
-
var
|
|
125760
|
+
var import_picocolors59 = __toESM(require_picocolors(), 1);
|
|
125100
125761
|
function reportCrash(err2, log = console.error) {
|
|
125101
125762
|
log(err2);
|
|
125102
|
-
log(
|
|
125763
|
+
log(import_picocolors59.default.dim("\n Looks like a Horus bug or a missing capability? Report it: horus report"));
|
|
125103
125764
|
}
|
|
125104
125765
|
|
|
125105
125766
|
// ../../packages/cli/src/index.ts
|
|
@@ -125187,6 +125848,16 @@ Examples:
|
|
|
125187
125848
|
});
|
|
125188
125849
|
}
|
|
125189
125850
|
);
|
|
125851
|
+
const secrets = program2.command("secrets").description("Manage encrypted connector credentials (.horus/secrets.local.json) \u2014 HOR-452");
|
|
125852
|
+
secrets.command("status").description("Show the master key source, stored secrets, plaintext in config, and gitignore state").action(() => {
|
|
125853
|
+
process.exitCode = runSecretsStatus();
|
|
125854
|
+
});
|
|
125855
|
+
secrets.command("migrate").description("Move plaintext connector secrets out of config.json into the encrypted store").option("--dry-run", "list what would be migrated without changing anything").action((opts) => {
|
|
125856
|
+
process.exitCode = runSecretsMigrate({ dryRun: opts.dryRun });
|
|
125857
|
+
});
|
|
125858
|
+
secrets.command("key").description("Show the master key source; --show prints it (base64) for CI (HORUS_SECRET_KEY)").option("--show", "print the master key (treat as a credential)").action((opts) => {
|
|
125859
|
+
process.exitCode = runSecretsKey({ show: opts.show });
|
|
125860
|
+
});
|
|
125190
125861
|
program2.command("stop").description("Stop the source-intelligence host for the current repo (or --all to stop every host)").option("--all", "stop all registered source-intelligence hosts").action(async (opts) => {
|
|
125191
125862
|
process.exitCode = await runStop(opts);
|
|
125192
125863
|
});
|