@merittdev/horus 0.15.2 → 0.16.1
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 +1268 -619
- 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.1" : "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
|
}
|
|
@@ -94396,7 +94804,7 @@ init_cjs_shims();
|
|
|
94396
94804
|
|
|
94397
94805
|
// ../../packages/engine/src/memory-detect.ts
|
|
94398
94806
|
init_cjs_shims();
|
|
94399
|
-
var
|
|
94807
|
+
var import_node_crypto6 = require("crypto");
|
|
94400
94808
|
|
|
94401
94809
|
// ../../packages/engine/src/memory-store.ts
|
|
94402
94810
|
init_cjs_shims();
|
|
@@ -94482,7 +94890,7 @@ function sharedNonGenericTags(a2, b5) {
|
|
|
94482
94890
|
}
|
|
94483
94891
|
function recurrenceEdgeId(idA, idB) {
|
|
94484
94892
|
const [lo, hi] = idA <= idB ? [idA, idB] : [idB, idA];
|
|
94485
|
-
const h3 = (0,
|
|
94893
|
+
const h3 = (0, import_node_crypto6.createHash)("sha256").update(`recurs-with\0${lo}\0${hi}`).digest("hex");
|
|
94486
94894
|
return `lnk_recurs_${h3.slice(0, 32)}`;
|
|
94487
94895
|
}
|
|
94488
94896
|
function normalizeCause(s5) {
|
|
@@ -95518,9 +95926,9 @@ function computeWeightedEvidenceConfidence(evidence2, ambientEvidenceIds) {
|
|
|
95518
95926
|
|
|
95519
95927
|
// ../../packages/engine/src/git-collector.ts
|
|
95520
95928
|
init_cjs_shims();
|
|
95521
|
-
var
|
|
95929
|
+
var import_node_child_process6 = require("child_process");
|
|
95522
95930
|
var import_node_util4 = require("util");
|
|
95523
|
-
var exec3 = (0, import_node_util4.promisify)(
|
|
95931
|
+
var exec3 = (0, import_node_util4.promisify)(import_node_child_process6.execFile);
|
|
95524
95932
|
var DEFAULT_MAX_COMMITS = 50;
|
|
95525
95933
|
var DEFAULT_MAX_FILES = 100;
|
|
95526
95934
|
var DEFAULT_MAX_BYTES = 5e4;
|
|
@@ -96398,6 +96806,13 @@ function isNoiseCommit(commit) {
|
|
|
96398
96806
|
return true;
|
|
96399
96807
|
}
|
|
96400
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
|
+
}
|
|
96401
96816
|
return false;
|
|
96402
96817
|
}
|
|
96403
96818
|
function seedTouchedByRelevantChange(recentChanges, seedFile) {
|
|
@@ -96409,6 +96824,26 @@ function seedTouchedByRelevantChange(recentChanges, seedFile) {
|
|
|
96409
96824
|
(c4) => !isNoiseCommit(c4) && c4.files.some(matchesSeed)
|
|
96410
96825
|
);
|
|
96411
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
|
+
}
|
|
96412
96847
|
function formatRegressionCitation(recentChanges, changes, seedFile) {
|
|
96413
96848
|
const matchesSeed = (f5) => seedFile === void 0 || f5 === seedFile || seedFile.endsWith(f5) || f5.endsWith(seedFile);
|
|
96414
96849
|
const all = (recentChanges?.commits ?? []).filter((c4) => !isNoiseCommit(c4));
|
|
@@ -97740,14 +98175,20 @@ async function investigate(input, deps) {
|
|
|
97740
98175
|
const seedFile = top?.filePath;
|
|
97741
98176
|
const seedInChanges = recentChangeRelevant;
|
|
97742
98177
|
const citation = formatRegressionCitation(recentChanges, changes, seedFile);
|
|
97743
|
-
const
|
|
98178
|
+
const seedFocus = seedInChanges ? seedTouchingCommitFocus(recentChanges, top?.filePath) : null;
|
|
98179
|
+
const isBroadChange = seedFocus !== null && seedFocus > 14;
|
|
98180
|
+
const regressionTitle = top && seedInChanges && !isBroadChange ? `Recent change${citation.commitClause} to ${top.name}${citation.symbolClause} in ${changeRangeLabel} may have introduced the regression` : top && seedInChanges && isBroadChange ? `No specific cause identified from the available evidence \u2014 a broad recent change (${seedFocus} files) in ${changeRangeLabel} touched ${top.name}'s file but isn't clearly linked to the symptom; connect runtime evidence (logs/metrics) for a code-aware cause` : top ? `Changes shipped in ${changeRangeLabel} but none touched ${top.name} \u2014 a regression here is unlikely to be a code change to the seed itself (check upstream deps, data, or config)` : `Recent change${citation.commitClause}${citation.symbolClause} in ${changeRangeLabel} may have introduced the regression`;
|
|
97744
98181
|
causeInputs.push({
|
|
97745
98182
|
id: "cause:deployment-regression",
|
|
97746
98183
|
title: regressionTitle,
|
|
97747
98184
|
category: "deployment-regression",
|
|
97748
98185
|
sourceEvidenceIds: [changeEvId, ...seedEv ? [seedEv.id] : []],
|
|
97749
98186
|
// A regression NOT backed by a seed-touching commit must not score like one that is.
|
|
97750
|
-
|
|
98187
|
+
// HOR-451: scale the seed-touched prior by commit focus — a broad/diffuse commit that merely
|
|
98188
|
+
// touched the seed no longer outranks an evidence-backed runtime cause.
|
|
98189
|
+
baseScore: clamp015(
|
|
98190
|
+
(seedInChanges ? regressionSeedTouchedScore(seedFocus) : 0.18) + (queueHits.length > 0 ? 0.05 : 0)
|
|
98191
|
+
),
|
|
97751
98192
|
metadata: { blastRadius }
|
|
97752
98193
|
});
|
|
97753
98194
|
}
|
|
@@ -97786,32 +98227,31 @@ async function investigate(input, deps) {
|
|
|
97786
98227
|
const raiser = bySeed ? top.name : lead.raiserName || top.name;
|
|
97787
98228
|
const depClause = bySeed ? "" : `, a dependency of ${top.name}`;
|
|
97788
98229
|
const calleePenalty = bySeed ? 0 : 0.18;
|
|
97789
|
-
|
|
97790
|
-
|
|
97791
|
-
|
|
97792
|
-
|
|
97793
|
-
|
|
97794
|
-
|
|
97795
|
-
|
|
97796
|
-
|
|
97797
|
-
|
|
97798
|
-
title = `Diagnostic signal ${lead.code} (${lead.count}x in Elasticsearch) is logged by ${raiser}${depClause} \u2014 informational, not an error${msgClause}`;
|
|
97799
|
-
baseScore = clamp015(0.3 + volumeBoost - calleePenalty);
|
|
97800
|
-
}
|
|
97801
|
-
causeInputs.push({
|
|
97802
|
-
id: "cause:seed-emitted-error",
|
|
97803
|
-
title: title.slice(0, 220),
|
|
97804
|
-
category: "error-correlation",
|
|
97805
|
-
sourceEvidenceIds,
|
|
97806
|
-
baseScore,
|
|
97807
|
-
metadata: {
|
|
97808
|
-
blastRadius,
|
|
97809
|
-
seedEmitted: true,
|
|
97810
|
-
code: lead.code,
|
|
97811
|
-
count: lead.count,
|
|
97812
|
-
severity: tier === SEV_ERROR ? "error" : tier === SEV_WARN ? "warn" : "info"
|
|
98230
|
+
if (tier === SEV_ERROR || tier === SEV_WARN) {
|
|
98231
|
+
let title;
|
|
98232
|
+
let baseScore;
|
|
98233
|
+
if (tier === SEV_ERROR) {
|
|
98234
|
+
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}`;
|
|
98235
|
+
baseScore = clamp015(0.6 + volumeBoost - calleePenalty);
|
|
98236
|
+
} else {
|
|
98237
|
+
title = `Warning ${lead.code} (${lead.count}x in Elasticsearch) ${bySeed ? "is raised by" : "surfaces on"} ${raiser}${depClause}${msgClause}`;
|
|
98238
|
+
baseScore = clamp015(0.42 + volumeBoost - calleePenalty);
|
|
97813
98239
|
}
|
|
97814
|
-
|
|
98240
|
+
causeInputs.push({
|
|
98241
|
+
id: "cause:seed-emitted-error",
|
|
98242
|
+
title: title.slice(0, 220),
|
|
98243
|
+
category: "error-correlation",
|
|
98244
|
+
sourceEvidenceIds,
|
|
98245
|
+
baseScore,
|
|
98246
|
+
metadata: {
|
|
98247
|
+
blastRadius,
|
|
98248
|
+
seedEmitted: true,
|
|
98249
|
+
code: lead.code,
|
|
98250
|
+
count: lead.count,
|
|
98251
|
+
severity: tier === SEV_ERROR ? "error" : "warn"
|
|
98252
|
+
}
|
|
98253
|
+
});
|
|
98254
|
+
}
|
|
97815
98255
|
}
|
|
97816
98256
|
}
|
|
97817
98257
|
if (top && seedEv && ctx && code && !sourceImpactHint) {
|
|
@@ -98938,7 +99378,7 @@ function blastRadiusToJSON(r) {
|
|
|
98938
99378
|
|
|
98939
99379
|
// ../../packages/engine/src/memory-recall.ts
|
|
98940
99380
|
init_cjs_shims();
|
|
98941
|
-
var
|
|
99381
|
+
var import_node_crypto7 = require("crypto");
|
|
98942
99382
|
var FRESHNESS_HALF_LIFE_DAYS = 30;
|
|
98943
99383
|
var NO_ANCHOR_DECAY = 0.5;
|
|
98944
99384
|
var STALE_RANK_FACTOR = 0.5;
|
|
@@ -98958,7 +99398,7 @@ function recallCodeProviderFromCodeProvider(code) {
|
|
|
98958
99398
|
};
|
|
98959
99399
|
}
|
|
98960
99400
|
function hashNodeContent(content) {
|
|
98961
|
-
return "sha256:" + (0,
|
|
99401
|
+
return "sha256:" + (0, import_node_crypto7.createHash)("sha256").update(content, "utf8").digest("hex");
|
|
98962
99402
|
}
|
|
98963
99403
|
function clamp016(n4) {
|
|
98964
99404
|
if (!Number.isFinite(n4)) return 0;
|
|
@@ -101561,7 +102001,7 @@ function renderReport2(top, ctx, impact, flows, siblings) {
|
|
|
101561
102001
|
|
|
101562
102002
|
// ../../packages/cli/src/commands/index-repo.ts
|
|
101563
102003
|
init_cjs_shims();
|
|
101564
|
-
var
|
|
102004
|
+
var import_node_path18 = require("path");
|
|
101565
102005
|
var import_picocolors9 = __toESM(require_picocolors(), 1);
|
|
101566
102006
|
|
|
101567
102007
|
// ../../packages/knowledge/src/index.ts
|
|
@@ -101770,7 +102210,7 @@ var KnowledgeManifestSchema = external_exports.object({
|
|
|
101770
102210
|
|
|
101771
102211
|
// ../../packages/knowledge/src/layout.ts
|
|
101772
102212
|
init_cjs_shims();
|
|
101773
|
-
var
|
|
102213
|
+
var import_node_path13 = require("path");
|
|
101774
102214
|
var HORUS_DIR2 = ".horus";
|
|
101775
102215
|
var KNOWLEDGE_DIR = "index";
|
|
101776
102216
|
var KNOWLEDGE_FILES = {
|
|
@@ -101785,37 +102225,37 @@ var KNOWLEDGE_FILES = {
|
|
|
101785
102225
|
db: "index.db"
|
|
101786
102226
|
};
|
|
101787
102227
|
function knowledgeDir(root) {
|
|
101788
|
-
return (0,
|
|
102228
|
+
return (0, import_node_path13.join)(root, HORUS_DIR2, KNOWLEDGE_DIR);
|
|
101789
102229
|
}
|
|
101790
102230
|
function knowledgePath(root, file) {
|
|
101791
|
-
return (0,
|
|
102231
|
+
return (0, import_node_path13.join)(knowledgeDir(root), KNOWLEDGE_FILES[file]);
|
|
101792
102232
|
}
|
|
101793
102233
|
|
|
101794
102234
|
// ../../packages/knowledge/src/store.ts
|
|
101795
102235
|
init_cjs_shims();
|
|
101796
|
-
var
|
|
101797
|
-
var
|
|
101798
|
-
var
|
|
102236
|
+
var import_node_crypto8 = require("crypto");
|
|
102237
|
+
var import_node_fs12 = require("fs");
|
|
102238
|
+
var import_node_path14 = require("path");
|
|
101799
102239
|
function readJson(path) {
|
|
101800
|
-
return JSON.parse((0,
|
|
102240
|
+
return JSON.parse((0, import_node_fs12.readFileSync)(path, "utf8"));
|
|
101801
102241
|
}
|
|
101802
102242
|
function writeJson(path, value) {
|
|
101803
|
-
(0,
|
|
101804
|
-
(0,
|
|
102243
|
+
(0, import_node_fs12.mkdirSync)((0, import_node_path14.dirname)(path), { recursive: true });
|
|
102244
|
+
(0, import_node_fs12.writeFileSync)(path, JSON.stringify(value, null, 2) + "\n");
|
|
101805
102245
|
}
|
|
101806
102246
|
function createJsonKnowledgeStore(root) {
|
|
101807
102247
|
const manifestPath = knowledgePath(root, "manifest");
|
|
101808
102248
|
const basePath = knowledgePath(root, "knowledgeBase");
|
|
101809
102249
|
return {
|
|
101810
102250
|
exists() {
|
|
101811
|
-
return (0,
|
|
102251
|
+
return (0, import_node_fs12.existsSync)(basePath);
|
|
101812
102252
|
},
|
|
101813
102253
|
readManifest() {
|
|
101814
|
-
if (!(0,
|
|
102254
|
+
if (!(0, import_node_fs12.existsSync)(manifestPath)) return null;
|
|
101815
102255
|
return KnowledgeManifestSchema.parse(readJson(manifestPath));
|
|
101816
102256
|
},
|
|
101817
102257
|
readSnapshot() {
|
|
101818
|
-
if (!(0,
|
|
102258
|
+
if (!(0, import_node_fs12.existsSync)(basePath)) return null;
|
|
101819
102259
|
return KnowledgeSnapshotSchema.parse(readJson(basePath));
|
|
101820
102260
|
},
|
|
101821
102261
|
write(snapshot, opts = {}) {
|
|
@@ -101823,9 +102263,9 @@ function createJsonKnowledgeStore(root) {
|
|
|
101823
102263
|
const counts = {};
|
|
101824
102264
|
for (const cat of KNOWLEDGE_CATEGORIES) counts[cat] = parsed[cat].length;
|
|
101825
102265
|
const snapshotJson = JSON.stringify(parsed, null, 2) + "\n";
|
|
101826
|
-
const contentHash = (0,
|
|
101827
|
-
(0,
|
|
101828
|
-
(0,
|
|
102266
|
+
const contentHash = (0, import_node_crypto8.createHash)("sha256").update(snapshotJson).digest("hex");
|
|
102267
|
+
(0, import_node_fs12.mkdirSync)((0, import_node_path14.dirname)(basePath), { recursive: true });
|
|
102268
|
+
(0, import_node_fs12.writeFileSync)(basePath, snapshotJson);
|
|
101829
102269
|
writeJson(knowledgePath(root, "contracts"), {
|
|
101830
102270
|
operations: parsed.operations,
|
|
101831
102271
|
types: parsed.types,
|
|
@@ -101911,9 +102351,9 @@ function searchSnapshot(snapshot, query, opts = {}) {
|
|
|
101911
102351
|
|
|
101912
102352
|
// ../../packages/knowledge/src/import/index.ts
|
|
101913
102353
|
init_cjs_shims();
|
|
101914
|
-
var
|
|
101915
|
-
var
|
|
101916
|
-
var
|
|
102354
|
+
var import_node_crypto9 = require("crypto");
|
|
102355
|
+
var import_node_fs13 = require("fs");
|
|
102356
|
+
var import_node_path15 = require("path");
|
|
101917
102357
|
|
|
101918
102358
|
// ../../packages/knowledge/src/import/maison-safqa.ts
|
|
101919
102359
|
init_cjs_shims();
|
|
@@ -102151,8 +102591,8 @@ function importMaisonSafqaKnowledgeBase(raw, opts = {}) {
|
|
|
102151
102591
|
// ../../packages/knowledge/src/import/index.ts
|
|
102152
102592
|
function importKnowledgeBaseFile(filePath, opts = {}) {
|
|
102153
102593
|
const source = opts.source ?? MAISON_SAFQA_SOURCE;
|
|
102154
|
-
const content = (0,
|
|
102155
|
-
const contentHash = (0,
|
|
102594
|
+
const content = (0, import_node_fs13.readFileSync)(filePath, "utf8");
|
|
102595
|
+
const contentHash = (0, import_node_crypto9.createHash)("sha256").update(content).digest("hex");
|
|
102156
102596
|
let raw;
|
|
102157
102597
|
try {
|
|
102158
102598
|
raw = JSON.parse(content);
|
|
@@ -102171,7 +102611,7 @@ function importKnowledgeBaseFile(filePath, opts = {}) {
|
|
|
102171
102611
|
generator: { tool: source, version: result.kbVersion ?? void 0 },
|
|
102172
102612
|
sourceIntelligence: { tool: source },
|
|
102173
102613
|
extraFiles: [
|
|
102174
|
-
{ name: `${source}:${(0,
|
|
102614
|
+
{ name: `${source}:${(0, import_node_path15.basename)(filePath)}`, category: "import-source", contentHash }
|
|
102175
102615
|
]
|
|
102176
102616
|
});
|
|
102177
102617
|
}
|
|
@@ -102180,8 +102620,8 @@ function importKnowledgeBaseFile(filePath, opts = {}) {
|
|
|
102180
102620
|
|
|
102181
102621
|
// ../../packages/knowledge/src/build/project-landscape.ts
|
|
102182
102622
|
init_cjs_shims();
|
|
102183
|
-
var
|
|
102184
|
-
var
|
|
102623
|
+
var import_node_fs14 = require("fs");
|
|
102624
|
+
var import_node_path16 = require("path");
|
|
102185
102625
|
|
|
102186
102626
|
// ../../packages/knowledge/src/build/source-graph.ts
|
|
102187
102627
|
init_cjs_shims();
|
|
@@ -102381,14 +102821,14 @@ function deriveExternalIntegrations(profiles) {
|
|
|
102381
102821
|
// ../../packages/knowledge/src/build/project-landscape.ts
|
|
102382
102822
|
function readPackageJson(repoPath) {
|
|
102383
102823
|
try {
|
|
102384
|
-
return JSON.parse((0,
|
|
102824
|
+
return JSON.parse((0, import_node_fs14.readFileSync)((0, import_node_path16.join)(repoPath, "package.json"), "utf8"));
|
|
102385
102825
|
} catch {
|
|
102386
102826
|
return null;
|
|
102387
102827
|
}
|
|
102388
102828
|
}
|
|
102389
102829
|
function readText(repoPath, file) {
|
|
102390
102830
|
try {
|
|
102391
|
-
return (0,
|
|
102831
|
+
return (0, import_node_fs14.readFileSync)((0, import_node_path16.join)(repoPath, file), "utf8");
|
|
102392
102832
|
} catch {
|
|
102393
102833
|
return null;
|
|
102394
102834
|
}
|
|
@@ -102941,27 +103381,27 @@ function extractQueueGraph(input) {
|
|
|
102941
103381
|
}
|
|
102942
103382
|
}
|
|
102943
103383
|
const producers = [];
|
|
102944
|
-
for (const
|
|
102945
|
-
const loopVarEnums = loopVarEnumsFor(
|
|
102946
|
-
for (const m5 of
|
|
103384
|
+
for (const pc60 of input.producerClasses) {
|
|
103385
|
+
const loopVarEnums = loopVarEnumsFor(pc60.content);
|
|
103386
|
+
for (const m5 of pc60.content.matchAll(INJECT_QUEUE_RE)) {
|
|
102947
103387
|
const queue = m5[1] ?? "";
|
|
102948
|
-
if (queue) producers.push({ queue, symbol:
|
|
103388
|
+
if (queue) producers.push({ queue, symbol: pc60.name, file: pc60.filePath });
|
|
102949
103389
|
}
|
|
102950
|
-
for (const m5 of
|
|
103390
|
+
for (const m5 of pc60.content.matchAll(NEW_BULL_RE)) {
|
|
102951
103391
|
if (m5[2] !== "Queue") continue;
|
|
102952
103392
|
const queues2 = resolveArg(m5[3] ?? "", constMap, enums, loopVarEnums);
|
|
102953
103393
|
for (const queue of queues2) {
|
|
102954
103394
|
producers.push({
|
|
102955
103395
|
queue,
|
|
102956
|
-
symbol: (m5[1] ??
|
|
102957
|
-
file:
|
|
103396
|
+
symbol: (m5[1] ?? pc60.name) || baseName(pc60.filePath),
|
|
103397
|
+
file: pc60.filePath
|
|
102958
103398
|
});
|
|
102959
103399
|
}
|
|
102960
103400
|
}
|
|
102961
|
-
for (const m5 of
|
|
103401
|
+
for (const m5 of pc60.content.matchAll(QUEUE_NAME_CONST_RE)) {
|
|
102962
103402
|
const ident = m5[1] ?? "";
|
|
102963
103403
|
const queue = m5[2] ?? "";
|
|
102964
|
-
if (queue) producers.push({ queue, symbol: ident || baseName(
|
|
103404
|
+
if (queue) producers.push({ queue, symbol: ident || baseName(pc60.filePath), file: pc60.filePath });
|
|
102965
103405
|
}
|
|
102966
103406
|
}
|
|
102967
103407
|
const workers = [];
|
|
@@ -103261,7 +103701,7 @@ async function stitch(client, db, opts = {}) {
|
|
|
103261
103701
|
|
|
103262
103702
|
// ../../packages/cli/src/lib/ensure-host.ts
|
|
103263
103703
|
init_cjs_shims();
|
|
103264
|
-
var
|
|
103704
|
+
var import_node_path17 = require("path");
|
|
103265
103705
|
var import_picocolors8 = __toESM(require_picocolors(), 1);
|
|
103266
103706
|
function parseHostPort(hostUrl) {
|
|
103267
103707
|
try {
|
|
@@ -103290,7 +103730,7 @@ function ensureHostReasonHint(reason) {
|
|
|
103290
103730
|
async function verifyHostServesRepo(hostUrl, root) {
|
|
103291
103731
|
const served = await fetchHostRepoPath(hostUrl);
|
|
103292
103732
|
if (served === null) return "unknown";
|
|
103293
|
-
return (0,
|
|
103733
|
+
return (0, import_node_path17.resolve)(served) === (0, import_node_path17.resolve)(root) ? "match" : "foreign";
|
|
103294
103734
|
}
|
|
103295
103735
|
async function ensureOwnSourceHost(root, opts = {}) {
|
|
103296
103736
|
const ownUrl = readSourceHostUrl(root);
|
|
@@ -103400,16 +103840,16 @@ async function stitchQueueMap(hostUrl, dbUrl, label) {
|
|
|
103400
103840
|
async function hostServesRepo(hostUrl, root) {
|
|
103401
103841
|
try {
|
|
103402
103842
|
const info2 = await new SourceHttpClient({ baseUrl: hostUrl }).hostInfo();
|
|
103403
|
-
return (0,
|
|
103843
|
+
return (0, import_node_path18.resolve)(info2.repoPath) === (0, import_node_path18.resolve)(root);
|
|
103404
103844
|
} catch {
|
|
103405
103845
|
return true;
|
|
103406
103846
|
}
|
|
103407
103847
|
}
|
|
103408
103848
|
function findConfiguredRepo(config2, root) {
|
|
103409
|
-
const target = (0,
|
|
103849
|
+
const target = (0, import_node_path18.resolve)(root);
|
|
103410
103850
|
for (const p5 of config2.projects) {
|
|
103411
103851
|
for (const r of p5.repositories) {
|
|
103412
|
-
if ((0,
|
|
103852
|
+
if ((0, import_node_path18.resolve)(r.path) === target) {
|
|
103413
103853
|
const hostUrl = r.source?.hostUrl;
|
|
103414
103854
|
return { project: p5.name, ...hostUrl ? { hostUrl } : {} };
|
|
103415
103855
|
}
|
|
@@ -103471,7 +103911,7 @@ async function buildKnowledgeIndex(root, config2, label, configuredProject, opts
|
|
|
103471
103911
|
const gitSha = getHeadSha(root) ?? void 0;
|
|
103472
103912
|
const branch = getCurrentBranch(root) ?? void 0;
|
|
103473
103913
|
if (opts.importKb) {
|
|
103474
|
-
const res = importKnowledgeBaseFile((0,
|
|
103914
|
+
const res = importKnowledgeBaseFile((0, import_node_path18.resolve)(opts.importKb), { root, project: label });
|
|
103475
103915
|
const total = res.manifest ? Object.values(res.manifest.counts).reduce((a2, b5) => a2 + b5, 0) : 0;
|
|
103476
103916
|
console.log(import_picocolors9.default.dim(` project knowledge: imported ${total} item(s) from ${opts.importKb}`));
|
|
103477
103917
|
if (res.warnings.length) console.log(import_picocolors9.default.dim(` (${res.warnings.length} import warning(s))`));
|
|
@@ -103486,12 +103926,12 @@ async function buildKnowledgeIndex(root, config2, label, configuredProject, opts
|
|
|
103486
103926
|
const repos = [];
|
|
103487
103927
|
if (config2 && configuredProject) {
|
|
103488
103928
|
const proj = config2.projects.find((p5) => p5.name === configuredProject);
|
|
103489
|
-
for (const r of proj?.repositories ?? []) repos.push({ name: r.name, path: (0,
|
|
103929
|
+
for (const r of proj?.repositories ?? []) repos.push({ name: r.name, path: (0, import_node_path18.resolve)(r.path) });
|
|
103490
103930
|
}
|
|
103491
103931
|
if (repos.length === 0) repos.push({ name: label, path: root });
|
|
103492
103932
|
let sourceGraph;
|
|
103493
103933
|
if (hostUrl) {
|
|
103494
|
-
const graphRepo = repos.find((r) => (0,
|
|
103934
|
+
const graphRepo = repos.find((r) => (0, import_node_path18.resolve)(r.path) === (0, import_node_path18.resolve)(root))?.name ?? label;
|
|
103495
103935
|
try {
|
|
103496
103936
|
const extract = await extractSourceGraph(hostUrl, graphRepo);
|
|
103497
103937
|
if (extract) sourceGraph = extract;
|
|
@@ -103551,7 +103991,7 @@ async function runIndex(opts) {
|
|
|
103551
103991
|
}
|
|
103552
103992
|
}
|
|
103553
103993
|
const isConfigured = configuredProject !== null;
|
|
103554
|
-
const name2 = opts.name ?? configuredProject ?? (0,
|
|
103994
|
+
const name2 = opts.name ?? configuredProject ?? (0, import_node_path18.basename)(root);
|
|
103555
103995
|
const label = configuredProject ?? name2;
|
|
103556
103996
|
let hostUrl;
|
|
103557
103997
|
let spawned = false;
|
|
@@ -103698,8 +104138,8 @@ async function runIndex(opts) {
|
|
|
103698
104138
|
|
|
103699
104139
|
// ../../packages/cli/src/commands/knowledge.ts
|
|
103700
104140
|
init_cjs_shims();
|
|
103701
|
-
var
|
|
103702
|
-
var
|
|
104141
|
+
var import_node_fs15 = require("fs");
|
|
104142
|
+
var import_node_crypto10 = require("crypto");
|
|
103703
104143
|
var import_picocolors10 = __toESM(require_picocolors(), 1);
|
|
103704
104144
|
function resolveRoot(opts) {
|
|
103705
104145
|
if (opts.root) return opts.root;
|
|
@@ -103967,7 +104407,7 @@ function runKnowledgeValidate(opts = {}) {
|
|
|
103967
104407
|
if (manifest && snapshot) {
|
|
103968
104408
|
const recorded = manifest.files.find((f5) => f5.name === "knowledge-base.json")?.contentHash;
|
|
103969
104409
|
if (recorded) {
|
|
103970
|
-
const actual = (0,
|
|
104410
|
+
const actual = (0, import_node_crypto10.createHash)("sha256").update((0, import_node_fs15.readFileSync)(knowledgePath(root, "knowledgeBase"), "utf8")).digest("hex");
|
|
103971
104411
|
if (actual !== recorded) {
|
|
103972
104412
|
issues.push("knowledge-base.json content hash does not match the manifest (file modified after write)");
|
|
103973
104413
|
}
|
|
@@ -114301,12 +114741,12 @@ var import_picocolors11 = __toESM(require_picocolors(), 1);
|
|
|
114301
114741
|
|
|
114302
114742
|
// ../../packages/cli/src/lib/open-url.ts
|
|
114303
114743
|
init_cjs_shims();
|
|
114304
|
-
var
|
|
114744
|
+
var import_node_child_process7 = require("child_process");
|
|
114305
114745
|
function openBrowser(url) {
|
|
114306
114746
|
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
114307
114747
|
const args2 = process.platform === "win32" ? ["/c", "start", "", url] : [url];
|
|
114308
114748
|
try {
|
|
114309
|
-
(0,
|
|
114749
|
+
(0, import_node_child_process7.execFile)(cmd, args2, () => {
|
|
114310
114750
|
});
|
|
114311
114751
|
} catch {
|
|
114312
114752
|
}
|
|
@@ -114694,8 +115134,8 @@ async function runMcpServer(opts = {}) {
|
|
|
114694
115134
|
|
|
114695
115135
|
// ../../packages/cli/src/commands/knowledge-cloud.ts
|
|
114696
115136
|
init_cjs_shims();
|
|
114697
|
-
var
|
|
114698
|
-
var
|
|
115137
|
+
var import_node_fs18 = require("fs");
|
|
115138
|
+
var import_node_path20 = require("path");
|
|
114699
115139
|
var import_picocolors13 = __toESM(require_picocolors(), 1);
|
|
114700
115140
|
|
|
114701
115141
|
// ../../packages/cli/src/lib/cloud/session.ts
|
|
@@ -114919,12 +115359,12 @@ var CloudClient = class {
|
|
|
114919
115359
|
|
|
114920
115360
|
// ../../packages/cli/src/lib/cloud/auth-store.ts
|
|
114921
115361
|
init_cjs_shims();
|
|
114922
|
-
var
|
|
115362
|
+
var import_node_fs16 = require("fs");
|
|
114923
115363
|
function readAuth() {
|
|
114924
115364
|
const p5 = authPath();
|
|
114925
|
-
if (!(0,
|
|
115365
|
+
if (!(0, import_node_fs16.existsSync)(p5)) return null;
|
|
114926
115366
|
try {
|
|
114927
|
-
const parsed = JSON.parse((0,
|
|
115367
|
+
const parsed = JSON.parse((0, import_node_fs16.readFileSync)(p5, "utf8"));
|
|
114928
115368
|
if (!parsed.token || !parsed.apiBaseUrl || !parsed.account) return null;
|
|
114929
115369
|
return parsed;
|
|
114930
115370
|
} catch {
|
|
@@ -114932,17 +115372,17 @@ function readAuth() {
|
|
|
114932
115372
|
}
|
|
114933
115373
|
}
|
|
114934
115374
|
function writeAuth(state) {
|
|
114935
|
-
(0,
|
|
115375
|
+
(0, import_node_fs16.mkdirSync)(horusHome(), { recursive: true });
|
|
114936
115376
|
const p5 = authPath();
|
|
114937
|
-
(0,
|
|
115377
|
+
(0, import_node_fs16.writeFileSync)(p5, JSON.stringify(state, null, 2) + "\n", { mode: 384 });
|
|
114938
115378
|
try {
|
|
114939
|
-
(0,
|
|
115379
|
+
(0, import_node_fs16.chmodSync)(p5, 384);
|
|
114940
115380
|
} catch {
|
|
114941
115381
|
}
|
|
114942
115382
|
}
|
|
114943
115383
|
function clearAuth() {
|
|
114944
115384
|
const p5 = authPath();
|
|
114945
|
-
if ((0,
|
|
115385
|
+
if ((0, import_node_fs16.existsSync)(p5)) (0, import_node_fs16.rmSync)(p5);
|
|
114946
115386
|
}
|
|
114947
115387
|
|
|
114948
115388
|
// ../../packages/cli/src/lib/cloud/session.ts
|
|
@@ -114960,13 +115400,13 @@ function authedClient() {
|
|
|
114960
115400
|
|
|
114961
115401
|
// ../../packages/cli/src/lib/cloud/context-store.ts
|
|
114962
115402
|
init_cjs_shims();
|
|
114963
|
-
var
|
|
114964
|
-
var
|
|
115403
|
+
var import_node_fs17 = require("fs");
|
|
115404
|
+
var import_node_path19 = require("path");
|
|
114965
115405
|
function readCloudConfig(root) {
|
|
114966
115406
|
const p5 = cloudConfigPath(root);
|
|
114967
|
-
if (!(0,
|
|
115407
|
+
if (!(0, import_node_fs17.existsSync)(p5)) return null;
|
|
114968
115408
|
try {
|
|
114969
|
-
const parsed = JSON.parse((0,
|
|
115409
|
+
const parsed = JSON.parse((0, import_node_fs17.readFileSync)(p5, "utf8"));
|
|
114970
115410
|
if (parsed.context !== "local" && parsed.context !== "cloud") return null;
|
|
114971
115411
|
return parsed;
|
|
114972
115412
|
} catch {
|
|
@@ -114975,12 +115415,12 @@ function readCloudConfig(root) {
|
|
|
114975
115415
|
}
|
|
114976
115416
|
function writeCloudConfig(root, cfg) {
|
|
114977
115417
|
const p5 = cloudConfigPath(root);
|
|
114978
|
-
(0,
|
|
114979
|
-
(0,
|
|
115418
|
+
(0, import_node_fs17.mkdirSync)((0, import_node_path19.dirname)(p5), { recursive: true });
|
|
115419
|
+
(0, import_node_fs17.writeFileSync)(p5, JSON.stringify(cfg, null, 2) + "\n");
|
|
114980
115420
|
}
|
|
114981
115421
|
function clearCloudConfig(root) {
|
|
114982
115422
|
const p5 = cloudConfigPath(root);
|
|
114983
|
-
if ((0,
|
|
115423
|
+
if ((0, import_node_fs17.existsSync)(p5)) (0, import_node_fs17.rmSync)(p5);
|
|
114984
115424
|
}
|
|
114985
115425
|
function isCloudActive(cfg) {
|
|
114986
115426
|
return !!cfg && cfg.context === "cloud" && !!cfg.project;
|
|
@@ -115176,10 +115616,10 @@ function reportCloudError(err2) {
|
|
|
115176
115616
|
|
|
115177
115617
|
// ../../packages/cli/src/commands/knowledge-cloud.ts
|
|
115178
115618
|
function readKnowledgeRedactConfig(root) {
|
|
115179
|
-
const configPath = (0,
|
|
115180
|
-
if (!(0,
|
|
115619
|
+
const configPath = (0, import_node_path20.join)(root, ".horus", "config.json");
|
|
115620
|
+
if (!(0, import_node_fs18.existsSync)(configPath)) return {};
|
|
115181
115621
|
try {
|
|
115182
|
-
const raw = JSON.parse((0,
|
|
115622
|
+
const raw = JSON.parse((0, import_node_fs18.readFileSync)(configPath, "utf8"));
|
|
115183
115623
|
const redact = raw["knowledge"]?.["redact"];
|
|
115184
115624
|
return { dropProvenancePaths: !!redact?.dropProvenancePaths, summariesOnly: !!redact?.summariesOnly };
|
|
115185
115625
|
} catch {
|
|
@@ -116600,12 +117040,12 @@ async function listCloudInvestigations(client, cfg) {
|
|
|
116600
117040
|
|
|
116601
117041
|
// ../../packages/cli/src/lib/freshness.ts
|
|
116602
117042
|
init_cjs_shims();
|
|
116603
|
-
var
|
|
116604
|
-
var
|
|
116605
|
-
var
|
|
117043
|
+
var import_node_child_process8 = require("child_process");
|
|
117044
|
+
var import_node_fs19 = require("fs");
|
|
117045
|
+
var import_node_path21 = require("path");
|
|
116606
117046
|
var import_node_util5 = require("util");
|
|
116607
117047
|
var import_picocolors15 = __toESM(require_picocolors(), 1);
|
|
116608
|
-
var execFileAsync2 = (0, import_node_util5.promisify)(
|
|
117048
|
+
var execFileAsync2 = (0, import_node_util5.promisify)(import_node_child_process8.execFile);
|
|
116609
117049
|
async function commitsSince(repoRoot, sinceIso) {
|
|
116610
117050
|
try {
|
|
116611
117051
|
const { stdout } = await execFileAsync2(
|
|
@@ -116623,7 +117063,7 @@ var RUNTIME_SOURCES = /* @__PURE__ */ new Set(["logs", "metrics", "state", "queu
|
|
|
116623
117063
|
var STALE_INDEX_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
116624
117064
|
function readIndexMeta(repoRoot) {
|
|
116625
117065
|
try {
|
|
116626
|
-
const raw = (0,
|
|
117066
|
+
const raw = (0, import_node_fs19.readFileSync)((0, import_node_path21.join)(repoRoot, ".horus", "source", "meta.json"), "utf8");
|
|
116627
117067
|
const j3 = JSON.parse(raw);
|
|
116628
117068
|
return {
|
|
116629
117069
|
lastIndexedAt: typeof j3.last_indexed_at === "string" ? j3.last_indexed_at : void 0,
|
|
@@ -116710,9 +117150,9 @@ function renderFreshness(f5) {
|
|
|
116710
117150
|
// ../../packages/cli/src/lib/investigation-runner.ts
|
|
116711
117151
|
init_cjs_shims();
|
|
116712
117152
|
var import_picocolors16 = __toESM(require_picocolors(), 1);
|
|
116713
|
-
var
|
|
116714
|
-
var
|
|
116715
|
-
var
|
|
117153
|
+
var import_node_fs20 = require("fs");
|
|
117154
|
+
var import_node_path22 = require("path");
|
|
117155
|
+
var import_node_os9 = require("os");
|
|
116716
117156
|
|
|
116717
117157
|
// ../../packages/eval/src/index.ts
|
|
116718
117158
|
init_cjs_shims();
|
|
@@ -117245,7 +117685,7 @@ function loadReranker() {
|
|
|
117245
117685
|
const flag = process.env.HORUS_RERANK;
|
|
117246
117686
|
if (!flag || flag === "0" || flag.toLowerCase() === "false") return void 0;
|
|
117247
117687
|
try {
|
|
117248
|
-
const blob = JSON.parse((0,
|
|
117688
|
+
const blob = JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path22.join)((0, import_node_os9.homedir)(), ".horus", "reranker.json"), "utf8"));
|
|
117249
117689
|
if (!isRerankerModel(blob)) return void 0;
|
|
117250
117690
|
if ((blob.holdout?.delta ?? 0) <= 0) return void 0;
|
|
117251
117691
|
return (causes) => applyReranker(blob, causes);
|
|
@@ -118626,8 +119066,8 @@ async function runOwner(query, opts) {
|
|
|
118626
119066
|
|
|
118627
119067
|
// ../../packages/cli/src/commands/postmortem.ts
|
|
118628
119068
|
init_cjs_shims();
|
|
118629
|
-
var
|
|
118630
|
-
var
|
|
119069
|
+
var import_node_fs21 = require("fs");
|
|
119070
|
+
var import_node_path23 = require("path");
|
|
118631
119071
|
var import_picocolors30 = __toESM(require_picocolors(), 1);
|
|
118632
119072
|
async function runPostmortem(id, opts) {
|
|
118633
119073
|
const log = opts.write ?? ((line2) => console.log(line2));
|
|
@@ -118738,14 +119178,14 @@ _AI summary unavailable: ${validationErrors?.[0] ?? "provider error"}_
|
|
|
118738
119178
|
}
|
|
118739
119179
|
}
|
|
118740
119180
|
if (opts.output) {
|
|
118741
|
-
const outputPath = (0,
|
|
118742
|
-
if ((0,
|
|
119181
|
+
const outputPath = (0, import_node_path23.resolve)(opts.output);
|
|
119182
|
+
if ((0, import_node_fs21.existsSync)(outputPath) && !opts.force) {
|
|
118743
119183
|
log(import_picocolors30.default.red("\u2717") + " " + outputPath + " already exists");
|
|
118744
119184
|
log(import_picocolors30.default.dim(" pass --force to overwrite"));
|
|
118745
119185
|
return 1;
|
|
118746
119186
|
}
|
|
118747
119187
|
try {
|
|
118748
|
-
(0,
|
|
119188
|
+
(0, import_node_fs21.writeFileSync)(outputPath, content, "utf8");
|
|
118749
119189
|
} catch (err2) {
|
|
118750
119190
|
log(import_picocolors30.default.red("\u2717 Could not write " + outputPath + ": ") + err2.message);
|
|
118751
119191
|
return 1;
|
|
@@ -121143,12 +121583,12 @@ async function runState(opts) {
|
|
|
121143
121583
|
// ../../packages/cli/src/commands/init.ts
|
|
121144
121584
|
init_cjs_shims();
|
|
121145
121585
|
var import_picocolors39 = __toESM(require_picocolors(), 1);
|
|
121146
|
-
var
|
|
121586
|
+
var import_node_path24 = require("path");
|
|
121147
121587
|
async function runInit(opts) {
|
|
121148
121588
|
try {
|
|
121149
121589
|
const cwd = process.cwd();
|
|
121150
|
-
const root = opts.path ? (0,
|
|
121151
|
-
const name2 = opts.name ?? (0,
|
|
121590
|
+
const root = opts.path ? (0, import_node_path24.resolve)(opts.path) : findRepoRoot(cwd) ?? cwd;
|
|
121591
|
+
const name2 = opts.name ?? (0, import_node_path24.basename)(root);
|
|
121152
121592
|
const envName = opts.env ?? "production";
|
|
121153
121593
|
const repo = { name: name2, path: root };
|
|
121154
121594
|
if (opts.source) repo["source"] = { hostUrl: opts.source };
|
|
@@ -121338,7 +121778,6 @@ async function runSetup(opts) {
|
|
|
121338
121778
|
// ../../packages/cli/src/commands/connect.ts
|
|
121339
121779
|
init_cjs_shims();
|
|
121340
121780
|
var import_node_readline = require("readline");
|
|
121341
|
-
var import_node_child_process9 = require("child_process");
|
|
121342
121781
|
var import_picocolors44 = __toESM(require_picocolors(), 1);
|
|
121343
121782
|
|
|
121344
121783
|
// ../../packages/cli/src/lib/tty-selector.ts
|
|
@@ -121663,10 +122102,10 @@ async function selectSearch(opts) {
|
|
|
121663
122102
|
|
|
121664
122103
|
// ../../packages/cli/src/commands/connect-ai.ts
|
|
121665
122104
|
init_cjs_shims();
|
|
121666
|
-
var
|
|
122105
|
+
var import_node_child_process9 = require("child_process");
|
|
121667
122106
|
var import_picocolors43 = __toESM(require_picocolors(), 1);
|
|
121668
122107
|
function cliInstalled(id) {
|
|
121669
|
-
const r = (0,
|
|
122108
|
+
const r = (0, import_node_child_process9.spawnSync)(id, ["--version"], { stdio: "ignore", timeout: 2e3 });
|
|
121670
122109
|
return !r.error;
|
|
121671
122110
|
}
|
|
121672
122111
|
async function probeAnthropic(apiKey) {
|
|
@@ -121816,7 +122255,7 @@ async function runConnect(type, opts) {
|
|
|
121816
122255
|
}
|
|
121817
122256
|
const connectorType = type;
|
|
121818
122257
|
try {
|
|
121819
|
-
const cwd = process.cwd();
|
|
122258
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
121820
122259
|
const root = findRepoRoot(cwd) ?? cwd;
|
|
121821
122260
|
const configPath = discoverLocalConfig(cwd) ?? localConfigPath(root);
|
|
121822
122261
|
const filled = await fillInteractive(connectorType, opts);
|
|
@@ -121858,22 +122297,45 @@ ${import_picocolors44.default.red(`\u2717 Could not reach ${connectorType}:`)} $
|
|
|
121858
122297
|
${import_picocolors44.default.green("\u2713")} ${connectorType} reachable ${import_picocolors44.default.dim(`(${probeResult.detail})`)}`
|
|
121859
122298
|
);
|
|
121860
122299
|
}
|
|
121861
|
-
const
|
|
121862
|
-
|
|
121863
|
-
|
|
121864
|
-
|
|
121865
|
-
|
|
121866
|
-
|
|
121867
|
-
|
|
121868
|
-
|
|
122300
|
+
const envName = resolveEnvName(configPath, filled.env);
|
|
122301
|
+
const secretFields = CONNECTOR_SECRET_FIELDS[connectorType] ?? [];
|
|
122302
|
+
const nonSecretPatch = {};
|
|
122303
|
+
const secretPatch = [];
|
|
122304
|
+
for (const [k3, v4] of Object.entries(patch)) {
|
|
122305
|
+
if (secretFields.includes(k3) && typeof v4 === "string" && v4.length > 0) {
|
|
122306
|
+
secretPatch.push([k3, v4]);
|
|
122307
|
+
} else {
|
|
122308
|
+
nonSecretPatch[k3] = v4;
|
|
122309
|
+
}
|
|
122310
|
+
}
|
|
122311
|
+
ensureProjectGitignore(root);
|
|
122312
|
+
if (secretPatch.length > 0) {
|
|
122313
|
+
let keyResult;
|
|
122314
|
+
try {
|
|
122315
|
+
keyResult = ensureMasterKey();
|
|
122316
|
+
} catch (err2) {
|
|
122317
|
+
console.error(import_picocolors44.default.red(err2.message));
|
|
121869
122318
|
return 1;
|
|
121870
122319
|
}
|
|
121871
|
-
|
|
122320
|
+
for (const [field, value] of secretPatch) {
|
|
122321
|
+
writeConnectorSecret(root, envName, connectorType, field, value, keyResult.key);
|
|
122322
|
+
}
|
|
122323
|
+
if (keyResult.warning) console.warn(import_picocolors44.default.yellow(`
|
|
122324
|
+
\u26A0 ${keyResult.warning}`));
|
|
121872
122325
|
}
|
|
121873
|
-
patchLocalConnector(configPath, connectorType,
|
|
122326
|
+
patchLocalConnector(configPath, connectorType, nonSecretPatch, envName);
|
|
121874
122327
|
console.log(
|
|
121875
122328
|
`${import_picocolors44.default.green("\u2713")} ${import_picocolors44.default.bold(connectorType)} connector saved \u2192 ${import_picocolors44.default.dim(configPath)}`
|
|
121876
122329
|
);
|
|
122330
|
+
if (secretPatch.length > 0) {
|
|
122331
|
+
const n4 = secretPatch.length;
|
|
122332
|
+
console.log(
|
|
122333
|
+
import_picocolors44.default.dim(
|
|
122334
|
+
` ${n4} secret${n4 > 1 ? "s" : ""} encrypted \u2192 ${localSecretsPath(root)}
|
|
122335
|
+
master key: ${masterKeyStatus().detail}`
|
|
122336
|
+
)
|
|
122337
|
+
);
|
|
122338
|
+
}
|
|
121877
122339
|
printSummary(connectorType, filled);
|
|
121878
122340
|
console.log(import_picocolors44.default.dim(`
|
|
121879
122341
|
run: horus investigate "<hint>"`));
|
|
@@ -122337,16 +122799,19 @@ function printSummary(type, opts) {
|
|
|
122337
122799
|
}
|
|
122338
122800
|
if (lines.length > 0) console.log(import_picocolors44.default.dim(lines.join("\n")));
|
|
122339
122801
|
}
|
|
122340
|
-
function
|
|
122341
|
-
|
|
122342
|
-
|
|
122343
|
-
|
|
122344
|
-
|
|
122345
|
-
|
|
122346
|
-
|
|
122347
|
-
|
|
122348
|
-
return
|
|
122802
|
+
function resolveEnvName(configPath, requested) {
|
|
122803
|
+
const file = readLocalConfig(configPath);
|
|
122804
|
+
const project = file.project;
|
|
122805
|
+
const envs = project?.environments ?? [];
|
|
122806
|
+
if (requested) {
|
|
122807
|
+
if (!envs.some((e) => e.name === requested)) {
|
|
122808
|
+
throw new Error(`Environment "${requested}" not found in config.`);
|
|
122809
|
+
}
|
|
122810
|
+
return requested;
|
|
122349
122811
|
}
|
|
122812
|
+
const first = envs[0]?.name;
|
|
122813
|
+
if (!first) throw new Error("No environments found in config.");
|
|
122814
|
+
return first;
|
|
122350
122815
|
}
|
|
122351
122816
|
async function discoverEsIndices(url, username, password) {
|
|
122352
122817
|
if (!url) return [];
|
|
@@ -122531,15 +122996,157 @@ function redactUrl(raw) {
|
|
|
122531
122996
|
}
|
|
122532
122997
|
}
|
|
122533
122998
|
|
|
122999
|
+
// ../../packages/cli/src/commands/secrets.ts
|
|
123000
|
+
init_cjs_shims();
|
|
123001
|
+
var import_node_fs22 = require("fs");
|
|
123002
|
+
var import_picocolors45 = __toESM(require_picocolors(), 1);
|
|
123003
|
+
function locate(cwd = process.cwd()) {
|
|
123004
|
+
const root = findRepoRoot(cwd) ?? cwd;
|
|
123005
|
+
const configPath = discoverLocalConfig(cwd) ?? localConfigPath(root);
|
|
123006
|
+
return { root, configPath, exists: (0, import_node_fs22.existsSync)(configPath) };
|
|
123007
|
+
}
|
|
123008
|
+
function countStoredSecrets(root) {
|
|
123009
|
+
const stored = readLocalSecrets(root).connectors;
|
|
123010
|
+
if (!stored) return 0;
|
|
123011
|
+
let n4 = 0;
|
|
123012
|
+
for (const byConnector of Object.values(stored)) {
|
|
123013
|
+
for (const byField of Object.values(byConnector)) {
|
|
123014
|
+
n4 += Object.keys(byField).length;
|
|
123015
|
+
}
|
|
123016
|
+
}
|
|
123017
|
+
return n4;
|
|
123018
|
+
}
|
|
123019
|
+
function runSecretsStatus(opts = {}) {
|
|
123020
|
+
const { root, configPath, exists: exists2 } = locate(opts.cwd);
|
|
123021
|
+
const key = masterKeyStatus();
|
|
123022
|
+
console.log(import_picocolors45.default.bold("\nMaster key"));
|
|
123023
|
+
console.log(
|
|
123024
|
+
key.available ? ` ${import_picocolors45.default.green("\u25CF")} ${key.detail}` : ` ${import_picocolors45.default.dim("\u25CB")} ${key.detail}`
|
|
123025
|
+
);
|
|
123026
|
+
const stored = countStoredSecrets(root);
|
|
123027
|
+
console.log(import_picocolors45.default.bold("\nEncrypted secrets"));
|
|
123028
|
+
console.log(` ${stored} stored \u2192 ${import_picocolors45.default.dim(localSecretsPath(root))}`);
|
|
123029
|
+
if (stored > 0) {
|
|
123030
|
+
const { warnings } = decryptConnectorSecrets(root);
|
|
123031
|
+
if (warnings.length > 0) {
|
|
123032
|
+
console.log(import_picocolors45.default.yellow(` \u26A0 ${warnings.length} cannot be decrypted with the current key:`));
|
|
123033
|
+
for (const w4 of warnings) console.log(import_picocolors45.default.dim(` - ${w4}`));
|
|
123034
|
+
} else {
|
|
123035
|
+
console.log(import_picocolors45.default.dim(" all decrypt cleanly with the current key"));
|
|
123036
|
+
}
|
|
123037
|
+
}
|
|
123038
|
+
console.log(import_picocolors45.default.bold("\nPlaintext in config.json"));
|
|
123039
|
+
if (!exists2) {
|
|
123040
|
+
console.log(import_picocolors45.default.dim(" no .horus/config.json found"));
|
|
123041
|
+
} else {
|
|
123042
|
+
const plaintext = findPlaintextConnectorSecrets(readLocalConfig(configPath).project);
|
|
123043
|
+
if (plaintext.length === 0) {
|
|
123044
|
+
console.log(` ${import_picocolors45.default.green("\u2713")} none \u2014 config carries no credentials`);
|
|
123045
|
+
} else {
|
|
123046
|
+
console.log(import_picocolors45.default.yellow(` \u26A0 ${plaintext.length} plaintext secret(s) \u2014 run \`horus secrets migrate\`:`));
|
|
123047
|
+
for (const p5 of plaintext) console.log(import_picocolors45.default.dim(` - ${p5}`));
|
|
123048
|
+
}
|
|
123049
|
+
}
|
|
123050
|
+
console.log(import_picocolors45.default.bold("\nGitignore"));
|
|
123051
|
+
console.log(
|
|
123052
|
+
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")
|
|
123053
|
+
);
|
|
123054
|
+
console.log("");
|
|
123055
|
+
return 0;
|
|
123056
|
+
}
|
|
123057
|
+
function runSecretsMigrate(opts = {}) {
|
|
123058
|
+
const { root, configPath, exists: exists2 } = locate(opts.cwd);
|
|
123059
|
+
if (!exists2) {
|
|
123060
|
+
console.error(import_picocolors45.default.red(`No .horus/config.json found at ${configPath}.`));
|
|
123061
|
+
console.error(import_picocolors45.default.dim(" Run `horus index` in this repo first."));
|
|
123062
|
+
return 1;
|
|
123063
|
+
}
|
|
123064
|
+
const file = readLocalConfig(configPath);
|
|
123065
|
+
const plaintext = findPlaintextConnectorSecrets(file.project);
|
|
123066
|
+
ensureProjectGitignore(root);
|
|
123067
|
+
if (plaintext.length === 0) {
|
|
123068
|
+
console.log(`${import_picocolors45.default.green("\u2713")} No plaintext connector secrets in config.json \u2014 nothing to migrate.`);
|
|
123069
|
+
if (!isHorusGitignored(root)) {
|
|
123070
|
+
console.log(import_picocolors45.default.dim(" Ensured `.horus/` is gitignored."));
|
|
123071
|
+
}
|
|
123072
|
+
return 0;
|
|
123073
|
+
}
|
|
123074
|
+
if (opts.dryRun) {
|
|
123075
|
+
console.log(import_picocolors45.default.bold(`Would migrate ${plaintext.length} plaintext secret(s) \u2192 encrypted store:`));
|
|
123076
|
+
for (const p5 of plaintext) console.log(import_picocolors45.default.dim(` - ${p5}`));
|
|
123077
|
+
console.log(import_picocolors45.default.dim("\n Re-run without --dry-run to apply."));
|
|
123078
|
+
return 0;
|
|
123079
|
+
}
|
|
123080
|
+
let keyResult;
|
|
123081
|
+
try {
|
|
123082
|
+
keyResult = ensureMasterKey();
|
|
123083
|
+
} catch (err2) {
|
|
123084
|
+
console.error(import_picocolors45.default.red(err2.message));
|
|
123085
|
+
return 1;
|
|
123086
|
+
}
|
|
123087
|
+
const project = file.project;
|
|
123088
|
+
let migrated = 0;
|
|
123089
|
+
for (const env of project?.environments ?? []) {
|
|
123090
|
+
const envName = env["name"];
|
|
123091
|
+
const connectors = env["connectors"];
|
|
123092
|
+
if (!envName || !connectors) continue;
|
|
123093
|
+
for (const [connector, cfg] of Object.entries(connectors)) {
|
|
123094
|
+
if (!cfg || typeof cfg !== "object") continue;
|
|
123095
|
+
for (const field of CONNECTOR_SECRET_FIELDS[connector] ?? []) {
|
|
123096
|
+
const val = cfg[field];
|
|
123097
|
+
if (typeof val === "string" && val.length > 0) {
|
|
123098
|
+
writeConnectorSecret(root, envName, connector, field, val, keyResult.key);
|
|
123099
|
+
delete cfg[field];
|
|
123100
|
+
migrated++;
|
|
123101
|
+
}
|
|
123102
|
+
}
|
|
123103
|
+
}
|
|
123104
|
+
}
|
|
123105
|
+
writeLocalConfig(root, file);
|
|
123106
|
+
console.log(`${import_picocolors45.default.green("\u2713")} Migrated ${migrated} secret(s) \u2192 ${import_picocolors45.default.dim(localSecretsPath(root))}`);
|
|
123107
|
+
console.log(import_picocolors45.default.dim(` master key: ${masterKeyStatus().detail}`));
|
|
123108
|
+
console.log(import_picocolors45.default.dim(" config.json now carries no credentials."));
|
|
123109
|
+
if (keyResult.warning) console.warn(import_picocolors45.default.yellow(`
|
|
123110
|
+
\u26A0 ${keyResult.warning}`));
|
|
123111
|
+
console.log(
|
|
123112
|
+
import_picocolors45.default.dim(
|
|
123113
|
+
"\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."
|
|
123114
|
+
)
|
|
123115
|
+
);
|
|
123116
|
+
return 0;
|
|
123117
|
+
}
|
|
123118
|
+
function runSecretsKey(opts = {}) {
|
|
123119
|
+
const status = masterKeyStatus();
|
|
123120
|
+
if (!status.available) {
|
|
123121
|
+
console.log(import_picocolors45.default.dim("No master key yet \u2014 created on first `horus connect` or `horus secrets migrate`."));
|
|
123122
|
+
return 0;
|
|
123123
|
+
}
|
|
123124
|
+
console.log(`Master key source: ${status.detail}`);
|
|
123125
|
+
if (!opts.show) {
|
|
123126
|
+
console.log(import_picocolors45.default.dim(" Pass --show to print the key (base64) for CI use (HORUS_SECRET_KEY)."));
|
|
123127
|
+
return 0;
|
|
123128
|
+
}
|
|
123129
|
+
const key = getMasterKeyForRead();
|
|
123130
|
+
if (!key) {
|
|
123131
|
+
console.error(import_picocolors45.default.red("Could not read the master key."));
|
|
123132
|
+
return 1;
|
|
123133
|
+
}
|
|
123134
|
+
console.warn(import_picocolors45.default.yellow("\u26A0 Treat this as a credential. Anyone with it can decrypt your connector secrets."));
|
|
123135
|
+
console.log(`
|
|
123136
|
+
export HORUS_SECRET_KEY=${key.toString("base64")}
|
|
123137
|
+
`);
|
|
123138
|
+
return 0;
|
|
123139
|
+
}
|
|
123140
|
+
|
|
122534
123141
|
// ../../packages/cli/src/commands/stop.ts
|
|
122535
123142
|
init_cjs_shims();
|
|
122536
123143
|
var import_node_child_process10 = require("child_process");
|
|
122537
|
-
var
|
|
123144
|
+
var import_node_fs23 = require("fs");
|
|
122538
123145
|
var import_node_util6 = require("util");
|
|
122539
|
-
var
|
|
122540
|
-
var
|
|
123146
|
+
var import_node_path25 = require("path");
|
|
123147
|
+
var import_picocolors46 = __toESM(require_picocolors(), 1);
|
|
122541
123148
|
var execFileAsync3 = (0, import_node_util6.promisify)(import_node_child_process10.execFile);
|
|
122542
|
-
var unlinkAsync = (0, import_node_util6.promisify)(
|
|
123149
|
+
var unlinkAsync = (0, import_node_util6.promisify)(import_node_fs23.unlink);
|
|
122543
123150
|
var SPAWNED_HOST_FILE2 = "spawned-host.json";
|
|
122544
123151
|
var START_TIME_TOLERANCE_S = 60;
|
|
122545
123152
|
var STOP_WAIT_MS = 5e3;
|
|
@@ -122555,19 +123162,19 @@ async function runStop(opts) {
|
|
|
122555
123162
|
const root = findRepoRoot(cwd) ?? cwd;
|
|
122556
123163
|
const hostUrl = readSourceHostUrl(root);
|
|
122557
123164
|
if (!hostUrl) {
|
|
122558
|
-
console.log(
|
|
123165
|
+
console.log(import_picocolors46.default.dim("No source-intelligence host found for this repo (.horus/source/host.json absent)."));
|
|
122559
123166
|
return 0;
|
|
122560
123167
|
}
|
|
122561
123168
|
return await stopHost(root, hostUrl);
|
|
122562
123169
|
} catch (err2) {
|
|
122563
|
-
console.error(
|
|
123170
|
+
console.error(import_picocolors46.default.red(err2.message));
|
|
122564
123171
|
return 1;
|
|
122565
123172
|
}
|
|
122566
123173
|
}
|
|
122567
123174
|
async function stopHost(root, hostUrl) {
|
|
122568
123175
|
const port = extractPort(hostUrl);
|
|
122569
123176
|
if (port === null) {
|
|
122570
|
-
console.error(
|
|
123177
|
+
console.error(import_picocolors46.default.red(`Cannot determine port from host URL: ${hostUrl}`));
|
|
122571
123178
|
return 1;
|
|
122572
123179
|
}
|
|
122573
123180
|
const healthy = await isHostHealthy(hostUrl);
|
|
@@ -122577,12 +123184,12 @@ async function stopHost(root, hostUrl) {
|
|
|
122577
123184
|
if (!wrapperAlive) {
|
|
122578
123185
|
const res = await stopBackendServerPid(root, port);
|
|
122579
123186
|
if (res === "failed") return 1;
|
|
122580
|
-
if (res !== "stopped") console.log(
|
|
123187
|
+
if (res !== "stopped") console.log(import_picocolors46.default.dim(`Host ${hostUrl} is already stopped.`));
|
|
122581
123188
|
await cleanupSpawnedRecord(root);
|
|
122582
123189
|
return 0;
|
|
122583
123190
|
}
|
|
122584
123191
|
console.log(
|
|
122585
|
-
|
|
123192
|
+
import_picocolors46.default.dim(
|
|
122586
123193
|
`Host ${hostUrl} is unreachable but pid ${owned.pid} is still running \u2014 terminating a stuck host.`
|
|
122587
123194
|
)
|
|
122588
123195
|
);
|
|
@@ -122590,7 +123197,7 @@ async function stopHost(root, hostUrl) {
|
|
|
122590
123197
|
const spawned = readSpawnedHost(root);
|
|
122591
123198
|
if (spawned === null) {
|
|
122592
123199
|
console.error(
|
|
122593
|
-
|
|
123200
|
+
import_picocolors46.default.red(
|
|
122594
123201
|
`No ownership record found (.horus/${SPAWNED_HOST_FILE2} absent). Horus will not stop a host it did not spawn.`
|
|
122595
123202
|
)
|
|
122596
123203
|
);
|
|
@@ -122598,12 +123205,12 @@ async function stopHost(root, hostUrl) {
|
|
|
122598
123205
|
}
|
|
122599
123206
|
const recordError = validateSpawnedRecord(spawned);
|
|
122600
123207
|
if (recordError !== null) {
|
|
122601
|
-
console.error(
|
|
123208
|
+
console.error(import_picocolors46.default.red(`Ownership record is malformed: ${recordError}. Aborting for safety.`));
|
|
122602
123209
|
return 1;
|
|
122603
123210
|
}
|
|
122604
123211
|
if (spawned.port !== port) {
|
|
122605
123212
|
console.error(
|
|
122606
|
-
|
|
123213
|
+
import_picocolors46.default.red(
|
|
122607
123214
|
`Ownership record port (${spawned.port}) does not match host URL port (${port}). Record may be stale.`
|
|
122608
123215
|
)
|
|
122609
123216
|
);
|
|
@@ -122611,7 +123218,7 @@ async function stopHost(root, hostUrl) {
|
|
|
122611
123218
|
}
|
|
122612
123219
|
if (spawned.root !== root) {
|
|
122613
123220
|
console.error(
|
|
122614
|
-
|
|
123221
|
+
import_picocolors46.default.red(
|
|
122615
123222
|
`Ownership record root (${spawned.root}) does not match resolved root (${root}). Record may be stale.`
|
|
122616
123223
|
)
|
|
122617
123224
|
);
|
|
@@ -122622,14 +123229,14 @@ async function stopHost(root, hostUrl) {
|
|
|
122622
123229
|
const res = await stopBackendServerPid(root, port);
|
|
122623
123230
|
if (res === "failed") return 1;
|
|
122624
123231
|
if (res !== "stopped") {
|
|
122625
|
-
console.log(
|
|
123232
|
+
console.log(import_picocolors46.default.dim(`Process pid ${spawned.pid} is no longer running \u2014 already stopped.`));
|
|
122626
123233
|
}
|
|
122627
123234
|
await cleanupSpawnedRecord(root);
|
|
122628
123235
|
return 0;
|
|
122629
123236
|
}
|
|
122630
123237
|
if (!isOwnHostProcess(spawned.pid, port, root, info2.args)) {
|
|
122631
123238
|
console.error(
|
|
122632
|
-
|
|
123239
|
+
import_picocolors46.default.red(
|
|
122633
123240
|
`Pid ${spawned.pid} args do not match "horus-source host --port ${port}". Got: "${info2.args.slice(0, 120)}". Aborting for safety.`
|
|
122634
123241
|
)
|
|
122635
123242
|
);
|
|
@@ -122638,12 +123245,12 @@ async function stopHost(root, hostUrl) {
|
|
|
122638
123245
|
const startTs = new Date(spawned.startedAt).getTime();
|
|
122639
123246
|
const recordedAgeS = Math.round((Date.now() - startTs) / 1e3);
|
|
122640
123247
|
if (!Number.isFinite(info2.etimeSeconds)) {
|
|
122641
|
-
console.error(
|
|
123248
|
+
console.error(import_picocolors46.default.red(`Could not read elapsed time for pid ${spawned.pid}. Aborting for safety.`));
|
|
122642
123249
|
return 1;
|
|
122643
123250
|
}
|
|
122644
123251
|
if (Math.abs(info2.etimeSeconds - recordedAgeS) > START_TIME_TOLERANCE_S) {
|
|
122645
123252
|
console.error(
|
|
122646
|
-
|
|
123253
|
+
import_picocolors46.default.red(
|
|
122647
123254
|
`Pid ${spawned.pid} age mismatch: record says ~${recordedAgeS}s, process reports ${info2.etimeSeconds}s elapsed. Possible PID reuse \u2014 aborting for safety.`
|
|
122648
123255
|
)
|
|
122649
123256
|
);
|
|
@@ -122653,17 +123260,17 @@ async function stopHost(root, hostUrl) {
|
|
|
122653
123260
|
try {
|
|
122654
123261
|
terminated = await terminatePid(spawned.pid);
|
|
122655
123262
|
} catch (err2) {
|
|
122656
|
-
console.error(
|
|
123263
|
+
console.error(import_picocolors46.default.red(`Failed to signal pid ${spawned.pid}: ${err2.message}`));
|
|
122657
123264
|
return 1;
|
|
122658
123265
|
}
|
|
122659
123266
|
if (!terminated) {
|
|
122660
123267
|
console.error(
|
|
122661
|
-
|
|
123268
|
+
import_picocolors46.default.red(`Host pid ${spawned.pid} did not exit even after SIGKILL \u2014 could not reclaim the port.`)
|
|
122662
123269
|
);
|
|
122663
123270
|
return 1;
|
|
122664
123271
|
}
|
|
122665
123272
|
console.log(
|
|
122666
|
-
`${
|
|
123273
|
+
`${import_picocolors46.default.green("\u2713")} Stopped source-intelligence host ` + import_picocolors46.default.dim(`(pid ${spawned.pid}, port ${port})`) + ` for ${root}`
|
|
122667
123274
|
);
|
|
122668
123275
|
if (await stopBackendServerPid(root, port) === "failed") return 1;
|
|
122669
123276
|
await cleanupSpawnedRecord(root);
|
|
@@ -122681,11 +123288,11 @@ function isOwnHostProcess(pid, port, root, args2) {
|
|
|
122681
123288
|
if (hostArgvRegex(port).test(args2)) return true;
|
|
122682
123289
|
if (!hostArgvAnyPortRegex().test(args2)) return false;
|
|
122683
123290
|
const rec = readSourceHostPid(root);
|
|
122684
|
-
return rec !== null && rec.pid === pid && Number.isFinite(rec.port) && rec.port === port && !!rec.repoPath && (0,
|
|
123291
|
+
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);
|
|
122685
123292
|
}
|
|
122686
123293
|
async function cleanupSpawnedRecord(root) {
|
|
122687
123294
|
try {
|
|
122688
|
-
await unlinkAsync((0,
|
|
123295
|
+
await unlinkAsync((0, import_node_path25.join)(root, HORUS_DIR, SPAWNED_HOST_FILE2));
|
|
122689
123296
|
} catch {
|
|
122690
123297
|
}
|
|
122691
123298
|
}
|
|
@@ -122698,7 +123305,7 @@ async function stopBackendServerPid(root, port) {
|
|
|
122698
123305
|
if (info2 === null) return "none";
|
|
122699
123306
|
if (!isOwnHostProcess(rec.pid, port, root, info2.args)) {
|
|
122700
123307
|
console.log(
|
|
122701
|
-
|
|
123308
|
+
import_picocolors46.default.dim(
|
|
122702
123309
|
`Host pid ${rec.pid} is now an unrelated process (stale source/host.json / PID reuse) \u2014 host already gone.`
|
|
122703
123310
|
)
|
|
122704
123311
|
);
|
|
@@ -122708,17 +123315,17 @@ async function stopBackendServerPid(root, port) {
|
|
|
122708
123315
|
try {
|
|
122709
123316
|
terminated = await terminatePid(rec.pid);
|
|
122710
123317
|
} catch (err2) {
|
|
122711
|
-
console.error(
|
|
123318
|
+
console.error(import_picocolors46.default.red(`Failed to signal pid ${rec.pid}: ${err2.message}`));
|
|
122712
123319
|
return "failed";
|
|
122713
123320
|
}
|
|
122714
123321
|
if (!terminated) {
|
|
122715
123322
|
console.error(
|
|
122716
|
-
|
|
123323
|
+
import_picocolors46.default.red(`Host pid ${rec.pid} did not exit even after SIGKILL \u2014 could not reclaim the port.`)
|
|
122717
123324
|
);
|
|
122718
123325
|
return "failed";
|
|
122719
123326
|
}
|
|
122720
123327
|
console.log(
|
|
122721
|
-
`${
|
|
123328
|
+
`${import_picocolors46.default.green("\u2713")} Stopped source-intelligence host ` + import_picocolors46.default.dim(`(pid ${rec.pid}, port ${port})`) + ` for ${root}`
|
|
122722
123329
|
);
|
|
122723
123330
|
return "stopped";
|
|
122724
123331
|
}
|
|
@@ -122726,7 +123333,7 @@ async function stopAll() {
|
|
|
122726
123333
|
const registry2 = readRegistry();
|
|
122727
123334
|
const projects2 = Object.entries(registry2.projects);
|
|
122728
123335
|
if (projects2.length === 0) {
|
|
122729
|
-
console.log(
|
|
123336
|
+
console.log(import_picocolors46.default.dim("No registered projects."));
|
|
122730
123337
|
return 0;
|
|
122731
123338
|
}
|
|
122732
123339
|
let stopped = 0;
|
|
@@ -122738,17 +123345,17 @@ async function stopAll() {
|
|
|
122738
123345
|
if (!healthy && readSpawnedHost(entry2.root) === null && readSourceHostPid(entry2.root) === null) {
|
|
122739
123346
|
continue;
|
|
122740
123347
|
}
|
|
122741
|
-
console.log(` Stopping ${
|
|
123348
|
+
console.log(` Stopping ${import_picocolors46.default.bold(name2)} ${import_picocolors46.default.dim(`(${hostUrl})`)}`);
|
|
122742
123349
|
const code = await stopHost(entry2.root, hostUrl);
|
|
122743
123350
|
if (code === 0) stopped++;
|
|
122744
123351
|
else failed++;
|
|
122745
123352
|
}
|
|
122746
123353
|
if (stopped === 0 && failed === 0) {
|
|
122747
|
-
console.log(
|
|
123354
|
+
console.log(import_picocolors46.default.dim("No running source-intelligence hosts found."));
|
|
122748
123355
|
} else {
|
|
122749
123356
|
console.log(
|
|
122750
123357
|
`
|
|
122751
|
-
Stopped ${stopped} host(s)${failed > 0 ?
|
|
123358
|
+
Stopped ${stopped} host(s)${failed > 0 ? import_picocolors46.default.red(`, ${failed} failed`) : ""}.`
|
|
122752
123359
|
);
|
|
122753
123360
|
}
|
|
122754
123361
|
return failed > 0 ? 1 : 0;
|
|
@@ -122836,7 +123443,7 @@ function extractPort(hostUrl) {
|
|
|
122836
123443
|
|
|
122837
123444
|
// ../../packages/cli/src/commands/hosts.ts
|
|
122838
123445
|
init_cjs_shims();
|
|
122839
|
-
var
|
|
123446
|
+
var import_picocolors47 = __toESM(require_picocolors(), 1);
|
|
122840
123447
|
|
|
122841
123448
|
// ../../packages/cli/src/lib/host-reaper.ts
|
|
122842
123449
|
init_cjs_shims();
|
|
@@ -122941,14 +123548,14 @@ async function runHosts(opts = {}) {
|
|
|
122941
123548
|
for (const row of rows) {
|
|
122942
123549
|
if (row.hostUrl === null) continue;
|
|
122943
123550
|
printedAny = true;
|
|
122944
|
-
const status = row.live ?
|
|
123551
|
+
const status = row.live ? import_picocolors47.default.green("\u25CF running") : import_picocolors47.default.red("\u25CF stopped");
|
|
122945
123552
|
const port = row.port ?? "?";
|
|
122946
123553
|
console.log(
|
|
122947
|
-
` ${status} ${
|
|
123554
|
+
` ${status} ${import_picocolors47.default.bold(row.name.padEnd(24))} port ${String(port).padEnd(6)} ${import_picocolors47.default.dim(row.root)}`
|
|
122948
123555
|
);
|
|
122949
123556
|
}
|
|
122950
123557
|
const noHost = rows.filter((r) => r.hostUrl === null);
|
|
122951
|
-
for (const row of noHost) console.log(` ${
|
|
123558
|
+
for (const row of noHost) console.log(` ${import_picocolors47.default.dim("\u25CB no host")} ${import_picocolors47.default.dim(row.name)}`);
|
|
122952
123559
|
if (printedAny || noHost.length > 0) console.log("");
|
|
122953
123560
|
const claimedPids = /* @__PURE__ */ new Set();
|
|
122954
123561
|
for (const [, entry2] of projects2) {
|
|
@@ -122961,37 +123568,37 @@ async function runHosts(opts = {}) {
|
|
|
122961
123568
|
let reapFailed = 0;
|
|
122962
123569
|
if (orphans.length > 0) {
|
|
122963
123570
|
console.log(
|
|
122964
|
-
|
|
123571
|
+
import_picocolors47.default.yellow(` \u26A0 ${orphans.length} orphaned source host(s) \u2014 no registered repo owns them:`)
|
|
122965
123572
|
);
|
|
122966
|
-
for (const o5 of orphans) console.log(
|
|
123573
|
+
for (const o5 of orphans) console.log(import_picocolors47.default.dim(` pid ${o5.pid} port ${o5.port}`));
|
|
122967
123574
|
if (opts.reap) {
|
|
122968
123575
|
let reaped = 0;
|
|
122969
123576
|
for (const o5 of orphans) {
|
|
122970
123577
|
if (await reapPid(o5.pid)) {
|
|
122971
123578
|
reaped++;
|
|
122972
|
-
console.log(` ${
|
|
123579
|
+
console.log(` ${import_picocolors47.default.green("\u2713")} reaped pid ${o5.pid} ${import_picocolors47.default.dim(`(port ${o5.port})`)}`);
|
|
122973
123580
|
} else {
|
|
122974
123581
|
reapFailed++;
|
|
122975
|
-
console.log(
|
|
123582
|
+
console.log(import_picocolors47.default.red(` \u2717 could not stop pid ${o5.pid} (port ${o5.port})`));
|
|
122976
123583
|
}
|
|
122977
123584
|
}
|
|
122978
|
-
console.log(
|
|
123585
|
+
console.log(import_picocolors47.default.dim(` Reaped ${reaped}/${orphans.length} orphan(s).`));
|
|
122979
123586
|
} else {
|
|
122980
|
-
console.log(
|
|
123587
|
+
console.log(import_picocolors47.default.dim(" Run `horus hosts --reap` to stop them."));
|
|
122981
123588
|
}
|
|
122982
123589
|
console.log("");
|
|
122983
123590
|
}
|
|
122984
123591
|
if (projects2.length === 0 && orphans.length === 0) {
|
|
122985
|
-
console.log(
|
|
123592
|
+
console.log(import_picocolors47.default.dim("No registered projects. Run `horus index` in a repo first."));
|
|
122986
123593
|
return 0;
|
|
122987
123594
|
}
|
|
122988
123595
|
if (!printedAny && orphans.length === 0) {
|
|
122989
|
-
console.log(
|
|
123596
|
+
console.log(import_picocolors47.default.dim("No source-intelligence hosts found. Run `horus index` to start one."));
|
|
122990
123597
|
return 0;
|
|
122991
123598
|
}
|
|
122992
123599
|
const running = countDistinctLiveHosts(rows);
|
|
122993
123600
|
console.log(
|
|
122994
|
-
|
|
123601
|
+
import_picocolors47.default.dim(
|
|
122995
123602
|
`${running} running${orphans.length ? ` \xB7 ${orphans.length} orphan(s)` : ""} \xB7 horus hosts --reap to clear orphans \xB7 horus stop --all to stop everything`
|
|
122996
123603
|
)
|
|
122997
123604
|
);
|
|
@@ -123008,7 +123615,7 @@ function extractPort2(hostUrl) {
|
|
|
123008
123615
|
|
|
123009
123616
|
// ../../packages/cli/src/commands/doctor.ts
|
|
123010
123617
|
init_cjs_shims();
|
|
123011
|
-
var
|
|
123618
|
+
var import_picocolors48 = __toESM(require_picocolors(), 1);
|
|
123012
123619
|
var DEFAULT_DB_URL4 = "postgresql://horus:horus@localhost:5433/horus";
|
|
123013
123620
|
var CONNECTOR_CHECKS = {
|
|
123014
123621
|
// Elasticsearch (runtime logs)
|
|
@@ -123125,9 +123732,9 @@ var CONNECTOR_CHECKS = {
|
|
|
123125
123732
|
};
|
|
123126
123733
|
var DOCTOR_CONNECTOR_KEYS = Object.keys(CONNECTOR_CHECKS);
|
|
123127
123734
|
function mark2(status) {
|
|
123128
|
-
if (status === "pass") return
|
|
123129
|
-
if (status === "warn") return
|
|
123130
|
-
return
|
|
123735
|
+
if (status === "pass") return import_picocolors48.default.green("\u2713");
|
|
123736
|
+
if (status === "warn") return import_picocolors48.default.yellow("~");
|
|
123737
|
+
return import_picocolors48.default.red("\u2717");
|
|
123131
123738
|
}
|
|
123132
123739
|
async function runDoctor(opts) {
|
|
123133
123740
|
const cwd = opts?.cwd ?? process.cwd();
|
|
@@ -123191,6 +123798,38 @@ async function runDoctor(opts) {
|
|
|
123191
123798
|
next: "run `horus init` then `horus index` to set up source intelligence"
|
|
123192
123799
|
});
|
|
123193
123800
|
}
|
|
123801
|
+
{
|
|
123802
|
+
if (repoRoot && !isHorusGitignored(repoRoot)) {
|
|
123803
|
+
checks.push({
|
|
123804
|
+
label: "Secrets gitignore",
|
|
123805
|
+
status: "warn",
|
|
123806
|
+
detail: ".horus/ is NOT gitignored \u2014 credentials could be committed",
|
|
123807
|
+
next: "run `horus secrets migrate` (also hardens .gitignore), or add `.horus/` to .gitignore"
|
|
123808
|
+
});
|
|
123809
|
+
} else if (repoRoot) {
|
|
123810
|
+
checks.push({ label: "Secrets gitignore", status: "pass", detail: ".horus/ is gitignored" });
|
|
123811
|
+
}
|
|
123812
|
+
if (configPath) {
|
|
123813
|
+
try {
|
|
123814
|
+
const plaintext = findPlaintextConnectorSecrets(readLocalConfig(configPath).project);
|
|
123815
|
+
if (plaintext.length > 0) {
|
|
123816
|
+
checks.push({
|
|
123817
|
+
label: "Secret storage",
|
|
123818
|
+
status: "warn",
|
|
123819
|
+
detail: `${plaintext.length} plaintext credential(s) in config.json: ${plaintext.join(", ")}`,
|
|
123820
|
+
next: "run `horus secrets migrate` to encrypt them and strip config.json"
|
|
123821
|
+
});
|
|
123822
|
+
} else {
|
|
123823
|
+
checks.push({
|
|
123824
|
+
label: "Secret storage",
|
|
123825
|
+
status: "pass",
|
|
123826
|
+
detail: "no plaintext credentials in config.json"
|
|
123827
|
+
});
|
|
123828
|
+
}
|
|
123829
|
+
} catch {
|
|
123830
|
+
}
|
|
123831
|
+
}
|
|
123832
|
+
}
|
|
123194
123833
|
{
|
|
123195
123834
|
const dbChecker = opts?._dbCheck ?? checkDatabase;
|
|
123196
123835
|
let dbUrl = process.env["DATABASE_URL"] ?? DEFAULT_DB_URL4;
|
|
@@ -123267,15 +123906,15 @@ async function runDoctor(opts) {
|
|
|
123267
123906
|
write(JSON.stringify(output, null, 2));
|
|
123268
123907
|
return hasFailure ? 1 : 0;
|
|
123269
123908
|
}
|
|
123270
|
-
write(
|
|
123909
|
+
write(import_picocolors48.default.bold("\nHorus readiness check\n"));
|
|
123271
123910
|
for (const check2 of checks) {
|
|
123272
|
-
write(` ${mark2(check2.status)} ${
|
|
123911
|
+
write(` ${mark2(check2.status)} ${import_picocolors48.default.bold(check2.label.padEnd(26))} ${import_picocolors48.default.dim(check2.detail)}`);
|
|
123273
123912
|
if (check2.next) {
|
|
123274
|
-
write(` ${
|
|
123913
|
+
write(` ${import_picocolors48.default.dim("\u2192 " + check2.next)}`);
|
|
123275
123914
|
}
|
|
123276
123915
|
}
|
|
123277
123916
|
write("");
|
|
123278
|
-
write(
|
|
123917
|
+
write(import_picocolors48.default.dim(" Hit a bug or a missing capability? Report it: horus report"));
|
|
123279
123918
|
write("");
|
|
123280
123919
|
return hasFailure ? 1 : 0;
|
|
123281
123920
|
}
|
|
@@ -123283,16 +123922,16 @@ async function runDoctor(opts) {
|
|
|
123283
123922
|
// ../../packages/cli/src/commands/providers-doctor.ts
|
|
123284
123923
|
init_cjs_shims();
|
|
123285
123924
|
var import_node_child_process12 = require("child_process");
|
|
123286
|
-
var
|
|
123925
|
+
var import_picocolors49 = __toESM(require_picocolors(), 1);
|
|
123287
123926
|
function statusMark(status) {
|
|
123288
|
-
if (status === "ready") return
|
|
123289
|
-
if (status === "installed") return
|
|
123290
|
-
return
|
|
123927
|
+
if (status === "ready") return import_picocolors49.default.green("\u2713");
|
|
123928
|
+
if (status === "installed") return import_picocolors49.default.yellow("~");
|
|
123929
|
+
return import_picocolors49.default.red("\u2717");
|
|
123291
123930
|
}
|
|
123292
123931
|
function statusLabel(status) {
|
|
123293
|
-
if (status === "ready") return
|
|
123294
|
-
if (status === "installed") return
|
|
123295
|
-
return
|
|
123932
|
+
if (status === "ready") return import_picocolors49.default.green("ready");
|
|
123933
|
+
if (status === "installed") return import_picocolors49.default.yellow("installed (not configured)");
|
|
123934
|
+
return import_picocolors49.default.dim("not found on PATH");
|
|
123296
123935
|
}
|
|
123297
123936
|
function detectBinary(id) {
|
|
123298
123937
|
const result = (0, import_node_child_process12.spawnSync)(id, ["--version"], { stdio: "pipe", timeout: 2e3 });
|
|
@@ -123309,7 +123948,7 @@ async function runProvidersDoctorCommand(opts) {
|
|
|
123309
123948
|
const registry2 = opts?.registry ?? DEFAULT_LOCAL_PROVIDER_REGISTRY;
|
|
123310
123949
|
const write = opts?.write ?? ((line2) => console.log(line2));
|
|
123311
123950
|
const results = buildProviderResults(registry2, opts?._detect);
|
|
123312
|
-
write(
|
|
123951
|
+
write(import_picocolors49.default.bold("\nLocal AI providers\n"));
|
|
123313
123952
|
for (const result of results) {
|
|
123314
123953
|
const descriptor = registry2.get(result.id);
|
|
123315
123954
|
const name2 = descriptor?.displayName ?? result.id;
|
|
@@ -123317,11 +123956,11 @@ async function runProvidersDoctorCommand(opts) {
|
|
|
123317
123956
|
` ${statusMark(result.status)} ${result.id.padEnd(8)} ${name2.padEnd(22)} ${statusLabel(result.status)}`
|
|
123318
123957
|
);
|
|
123319
123958
|
if (result.status !== "ready" && result.detail) {
|
|
123320
|
-
write(` ${
|
|
123959
|
+
write(` ${import_picocolors49.default.dim("\u2192 " + result.detail)}`);
|
|
123321
123960
|
}
|
|
123322
123961
|
}
|
|
123323
123962
|
write("");
|
|
123324
|
-
write(
|
|
123963
|
+
write(import_picocolors49.default.bold("Cloud AI providers\n"));
|
|
123325
123964
|
let source = null;
|
|
123326
123965
|
if (opts?._anthropicKey !== void 0) {
|
|
123327
123966
|
source = opts._anthropicKey ? "env" : null;
|
|
@@ -123336,18 +123975,18 @@ async function runProvidersDoctorCommand(opts) {
|
|
|
123336
123975
|
}
|
|
123337
123976
|
if (source === "config") {
|
|
123338
123977
|
write(
|
|
123339
|
-
` ${
|
|
123978
|
+
` ${import_picocolors49.default.green("\u2713")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors49.default.green("configured (local .horus config)")}`
|
|
123340
123979
|
);
|
|
123341
123980
|
} else if (source === "env") {
|
|
123342
123981
|
write(
|
|
123343
|
-
` ${
|
|
123982
|
+
` ${import_picocolors49.default.green("\u2713")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors49.default.green("configured (ANTHROPIC_API_KEY env)")}`
|
|
123344
123983
|
);
|
|
123345
123984
|
} else {
|
|
123346
123985
|
write(
|
|
123347
|
-
` ${
|
|
123986
|
+
` ${import_picocolors49.default.red("\u2717")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors49.default.dim("not configured")}`
|
|
123348
123987
|
);
|
|
123349
123988
|
write(
|
|
123350
|
-
` ${
|
|
123989
|
+
` ${import_picocolors49.default.dim("\u2192 run `horus connect ai` (or set ANTHROPIC_API_KEY) to enable `horus investigate --ai`")}`
|
|
123351
123990
|
);
|
|
123352
123991
|
}
|
|
123353
123992
|
write("");
|
|
@@ -123356,9 +123995,9 @@ async function runProvidersDoctorCommand(opts) {
|
|
|
123356
123995
|
|
|
123357
123996
|
// ../../packages/cli/src/commands/generate-config.ts
|
|
123358
123997
|
init_cjs_shims();
|
|
123359
|
-
var
|
|
123360
|
-
var
|
|
123361
|
-
var
|
|
123998
|
+
var import_node_fs24 = require("fs");
|
|
123999
|
+
var import_node_path26 = require("path");
|
|
124000
|
+
var import_picocolors50 = __toESM(require_picocolors(), 1);
|
|
123362
124001
|
function configTemplate(name2, repoPath) {
|
|
123363
124002
|
return `export default {
|
|
123364
124003
|
database: {
|
|
@@ -123406,39 +124045,39 @@ async function runGenerateConfig(opts) {
|
|
|
123406
124045
|
const defaults2 = localConfigPath2 != null ? projectDefaults(localConfigPath2) : null;
|
|
123407
124046
|
const hasLocalConfig = defaults2 != null;
|
|
123408
124047
|
const defaultOut = hasLocalConfig ? "horus.config.example.js" : "horus.config.js";
|
|
123409
|
-
const outPath = (0,
|
|
124048
|
+
const outPath = (0, import_node_path26.resolve)(cwd, opts.out ?? defaultOut);
|
|
123410
124049
|
const name2 = opts.name ?? defaults2?.name ?? "my-project";
|
|
123411
124050
|
const repoPath = opts.repo ?? defaults2?.repoPath ?? `/path/to/${name2}`;
|
|
123412
|
-
if ((0,
|
|
123413
|
-
log(`${
|
|
123414
|
-
log(
|
|
124051
|
+
if ((0, import_node_fs24.existsSync)(outPath) && !opts.force) {
|
|
124052
|
+
log(`${import_picocolors50.default.red("\u2717")} ${outPath} already exists`);
|
|
124053
|
+
log(import_picocolors50.default.dim(" pass --force to overwrite"));
|
|
123415
124054
|
return 1;
|
|
123416
124055
|
}
|
|
123417
124056
|
try {
|
|
123418
|
-
(0,
|
|
123419
|
-
(0,
|
|
124057
|
+
(0, import_node_fs24.mkdirSync)((0, import_node_path26.dirname)(outPath), { recursive: true });
|
|
124058
|
+
(0, import_node_fs24.writeFileSync)(outPath, configTemplate(name2, repoPath), "utf8");
|
|
123420
124059
|
} catch (err2) {
|
|
123421
|
-
log(`${
|
|
124060
|
+
log(`${import_picocolors50.default.red("\u2717")} Could not write ${outPath}: ${err2.message}`);
|
|
123422
124061
|
return 1;
|
|
123423
124062
|
}
|
|
123424
|
-
log(`${
|
|
123425
|
-
log(
|
|
123426
|
-
log(
|
|
124063
|
+
log(`${import_picocolors50.default.green("\u2713")} Created ${outPath}`);
|
|
124064
|
+
log(import_picocolors50.default.dim(` project: ${name2}`));
|
|
124065
|
+
log(import_picocolors50.default.dim(` repo: ${repoPath}`));
|
|
123427
124066
|
if (hasLocalConfig && localConfigPath2 != null) {
|
|
123428
124067
|
log("");
|
|
123429
|
-
log(
|
|
124068
|
+
log(import_picocolors50.default.yellow("Note:") + ` an initialized Horus project config exists at ${localConfigPath2}`);
|
|
123430
124069
|
log(" \u2022 .horus/config.json \u2014 project config used by `horus investigate` from this repo");
|
|
123431
124070
|
log(" \u2022 horus.config.js \u2014 standalone/global config used with `horus doctor --config <path>`");
|
|
123432
|
-
log(
|
|
124071
|
+
log(import_picocolors50.default.dim(` next: review ${outPath} and copy/adapt it as needed`));
|
|
123433
124072
|
} else {
|
|
123434
|
-
log(
|
|
124073
|
+
log(import_picocolors50.default.dim(` next: horus doctor --config ${outPath}`));
|
|
123435
124074
|
}
|
|
123436
124075
|
return 0;
|
|
123437
124076
|
}
|
|
123438
124077
|
|
|
123439
124078
|
// ../../packages/cli/src/commands/readiness.ts
|
|
123440
124079
|
init_cjs_shims();
|
|
123441
|
-
var
|
|
124080
|
+
var import_picocolors51 = __toESM(require_picocolors(), 1);
|
|
123442
124081
|
var READINESS_AI_CONTRACT = `Provide a clearly separated AI readiness summary with:
|
|
123443
124082
|
|
|
123444
124083
|
Overall assessment
|
|
@@ -123461,9 +124100,9 @@ Confidence / gaps
|
|
|
123461
124100
|
- Which checks Horus could verify vs. which require manual confirmation`;
|
|
123462
124101
|
var DEFAULT_DB_URL5 = "postgresql://horus:horus@localhost:5433/horus";
|
|
123463
124102
|
function mark3(status) {
|
|
123464
|
-
if (status === "pass") return
|
|
123465
|
-
if (status === "warn") return
|
|
123466
|
-
return
|
|
124103
|
+
if (status === "pass") return import_picocolors51.default.green("\u2713");
|
|
124104
|
+
if (status === "warn") return import_picocolors51.default.yellow("~");
|
|
124105
|
+
return import_picocolors51.default.red("\u2717");
|
|
123467
124106
|
}
|
|
123468
124107
|
async function runReadiness(opts) {
|
|
123469
124108
|
const cwd = opts?.cwd ?? process.cwd();
|
|
@@ -123668,20 +124307,20 @@ async function runReadiness(opts) {
|
|
|
123668
124307
|
}
|
|
123669
124308
|
const blockingChecks = checks.filter((c4) => c4.blocking);
|
|
123670
124309
|
const optionalChecks = checks.filter((c4) => !c4.blocking);
|
|
123671
|
-
write(
|
|
123672
|
-
write(
|
|
124310
|
+
write(import_picocolors51.default.bold("\nHorus release readiness\n"));
|
|
124311
|
+
write(import_picocolors51.default.bold(" Blocking"));
|
|
123673
124312
|
for (const check2 of blockingChecks) {
|
|
123674
|
-
write(` ${mark3(check2.status)} ${
|
|
124313
|
+
write(` ${mark3(check2.status)} ${import_picocolors51.default.bold(check2.label.padEnd(22))} ${import_picocolors51.default.dim(check2.detail)}`);
|
|
123675
124314
|
if (check2.next) {
|
|
123676
|
-
write(` ${
|
|
124315
|
+
write(` ${import_picocolors51.default.dim("\u2192 " + check2.next)}`);
|
|
123677
124316
|
}
|
|
123678
124317
|
}
|
|
123679
124318
|
write("");
|
|
123680
|
-
write(
|
|
124319
|
+
write(import_picocolors51.default.bold(" Optional"));
|
|
123681
124320
|
for (const check2 of optionalChecks) {
|
|
123682
|
-
write(` ${mark3(check2.status)} ${
|
|
124321
|
+
write(` ${mark3(check2.status)} ${import_picocolors51.default.bold(check2.label.padEnd(22))} ${import_picocolors51.default.dim(check2.detail)}`);
|
|
123683
124322
|
if (check2.next) {
|
|
123684
|
-
write(` ${
|
|
124323
|
+
write(` ${import_picocolors51.default.dim("\u2192 " + check2.next)}`);
|
|
123685
124324
|
}
|
|
123686
124325
|
}
|
|
123687
124326
|
write("");
|
|
@@ -123689,21 +124328,21 @@ async function runReadiness(opts) {
|
|
|
123689
124328
|
const optionalWarns = optionalChecks.filter((c4) => c4.status === "warn").length;
|
|
123690
124329
|
if (blockingFails.length === 0) {
|
|
123691
124330
|
if (optionalWarns === 0) {
|
|
123692
|
-
write(
|
|
124331
|
+
write(import_picocolors51.default.green(" Ready for demo/release."));
|
|
123693
124332
|
} else {
|
|
123694
124333
|
write(
|
|
123695
|
-
|
|
124334
|
+
import_picocolors51.default.yellow(
|
|
123696
124335
|
` Ready for a basic demo. ${optionalWarns} optional item(s) not configured \u2014 investigation evidence will be limited.`
|
|
123697
124336
|
)
|
|
123698
124337
|
);
|
|
123699
124338
|
}
|
|
123700
124339
|
} else {
|
|
123701
124340
|
write(
|
|
123702
|
-
|
|
124341
|
+
import_picocolors51.default.red(
|
|
123703
124342
|
` Not ready. ${blockingFails.length} blocking item(s) must be resolved before demo/release.`
|
|
123704
124343
|
)
|
|
123705
124344
|
);
|
|
123706
|
-
write(
|
|
124345
|
+
write(import_picocolors51.default.dim(" Re-run `horus readiness` after resolving the items above."));
|
|
123707
124346
|
}
|
|
123708
124347
|
write("");
|
|
123709
124348
|
if (opts?.ai) {
|
|
@@ -123718,7 +124357,7 @@ async function runReadiness(opts) {
|
|
|
123718
124357
|
});
|
|
123719
124358
|
console.log("\n" + renderInterpretation(result));
|
|
123720
124359
|
if (!result.ok) {
|
|
123721
|
-
console.error(
|
|
124360
|
+
console.error(import_picocolors51.default.yellow(`[ai] ${result.warning}`));
|
|
123722
124361
|
}
|
|
123723
124362
|
}
|
|
123724
124363
|
return blockingFails.length > 0 ? 1 : 0;
|
|
@@ -123726,33 +124365,33 @@ async function runReadiness(opts) {
|
|
|
123726
124365
|
|
|
123727
124366
|
// ../../packages/cli/src/commands/skill.ts
|
|
123728
124367
|
init_cjs_shims();
|
|
123729
|
-
var
|
|
123730
|
-
var
|
|
123731
|
-
var
|
|
124368
|
+
var import_node_fs25 = require("fs");
|
|
124369
|
+
var import_node_path27 = require("path");
|
|
124370
|
+
var import_node_os10 = require("os");
|
|
123732
124371
|
var import_promises3 = require("readline/promises");
|
|
123733
|
-
var
|
|
124372
|
+
var import_picocolors52 = __toESM(require_picocolors(), 1);
|
|
123734
124373
|
var SUPPORTED_TARGETS = ["claude", "codex", "gemini", "cursor", "generic"];
|
|
123735
124374
|
function isValidTarget(target) {
|
|
123736
124375
|
return SUPPORTED_TARGETS.includes(target);
|
|
123737
124376
|
}
|
|
123738
124377
|
function getLegacyClaudeSkillPath(opts) {
|
|
123739
|
-
const base2 = opts.global ? (0,
|
|
123740
|
-
return (0,
|
|
124378
|
+
const base2 = opts.global ? (0, import_node_os10.homedir)() : opts.cwd ?? process.cwd();
|
|
124379
|
+
return (0, import_node_path27.join)(base2, ".claude", "skills", "horus.md");
|
|
123741
124380
|
}
|
|
123742
124381
|
function getSkillInstallPath(target, opts) {
|
|
123743
|
-
const base2 = opts.global ? (0,
|
|
124382
|
+
const base2 = opts.global ? (0, import_node_os10.homedir)() : opts.cwd ?? process.cwd();
|
|
123744
124383
|
switch (target) {
|
|
123745
124384
|
case "claude":
|
|
123746
|
-
return (0,
|
|
124385
|
+
return (0, import_node_path27.join)(base2, ".claude", "skills", "horus", "SKILL.md");
|
|
123747
124386
|
case "gemini":
|
|
123748
|
-
return opts.global ? (0,
|
|
124387
|
+
return opts.global ? (0, import_node_path27.join)(base2, ".gemini", "GEMINI.md") : (0, import_node_path27.join)(base2, "GEMINI.md");
|
|
123749
124388
|
case "cursor":
|
|
123750
|
-
return opts.global ? (0,
|
|
124389
|
+
return opts.global ? (0, import_node_path27.join)(base2, ".cursorrules") : (0, import_node_path27.join)(base2, ".cursor", "rules", "horus.mdc");
|
|
123751
124390
|
case "codex":
|
|
123752
|
-
return opts.global ? (0,
|
|
124391
|
+
return opts.global ? (0, import_node_path27.join)(base2, ".codex", "AGENTS.md") : (0, import_node_path27.join)(base2, "AGENTS.md");
|
|
123753
124392
|
case "generic":
|
|
123754
124393
|
default:
|
|
123755
|
-
return (0,
|
|
124394
|
+
return (0, import_node_path27.join)(base2, ".horus", "skills", `horus-${target}.md`);
|
|
123756
124395
|
}
|
|
123757
124396
|
}
|
|
123758
124397
|
var BASE_SKILL = `# Horus Grounded Investigation Skill
|
|
@@ -124069,66 +124708,66 @@ async function confirm(message) {
|
|
|
124069
124708
|
async function runSkillInstall(target, opts) {
|
|
124070
124709
|
const log = opts.write ?? ((line2) => console.log(line2));
|
|
124071
124710
|
if (!isValidTarget(target)) {
|
|
124072
|
-
log(`${
|
|
124073
|
-
log(
|
|
124711
|
+
log(`${import_picocolors52.default.red("\u2717")} Unknown target: ${import_picocolors52.default.bold(target)}`);
|
|
124712
|
+
log(import_picocolors52.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
|
|
124074
124713
|
return 1;
|
|
124075
124714
|
}
|
|
124076
124715
|
const outPath = getSkillInstallPath(target, { global: opts.global, cwd: opts.cwd });
|
|
124077
124716
|
const content = generateSkillContent(target);
|
|
124078
124717
|
if (target === "claude") {
|
|
124079
124718
|
const legacyPath = getLegacyClaudeSkillPath({ global: opts.global, cwd: opts.cwd });
|
|
124080
|
-
if ((0,
|
|
124719
|
+
if ((0, import_node_fs25.existsSync)(legacyPath)) {
|
|
124081
124720
|
if (!opts.force) {
|
|
124082
124721
|
const confirmed = await (opts.confirm ?? confirm)(
|
|
124083
124722
|
`Found old flat skill file at ${legacyPath}. Replace it with the new directory layout?`
|
|
124084
124723
|
);
|
|
124085
124724
|
if (!confirmed) {
|
|
124086
|
-
log(`${
|
|
124087
|
-
log(
|
|
124725
|
+
log(`${import_picocolors52.default.yellow("!")} Migration cancelled; existing skill left untouched.`);
|
|
124726
|
+
log(import_picocolors52.default.dim(" Pass --force to replace without prompting."));
|
|
124088
124727
|
return 1;
|
|
124089
124728
|
}
|
|
124090
124729
|
}
|
|
124091
124730
|
try {
|
|
124092
|
-
(0,
|
|
124093
|
-
log(`${
|
|
124731
|
+
(0, import_node_fs25.rmSync)(legacyPath);
|
|
124732
|
+
log(`${import_picocolors52.default.yellow("!")} Replaced old flat skill file: ${legacyPath}`);
|
|
124094
124733
|
} catch (err2) {
|
|
124095
|
-
log(`${
|
|
124734
|
+
log(`${import_picocolors52.default.red("\u2717")} Could not remove legacy skill file ${legacyPath}: ${err2.message}`);
|
|
124096
124735
|
return 1;
|
|
124097
124736
|
}
|
|
124098
124737
|
}
|
|
124099
124738
|
}
|
|
124100
|
-
if ((0,
|
|
124101
|
-
log(`${
|
|
124102
|
-
log(
|
|
124739
|
+
if ((0, import_node_fs25.existsSync)(outPath) && !opts.force) {
|
|
124740
|
+
log(`${import_picocolors52.default.red("\u2717")} ${outPath} already exists`);
|
|
124741
|
+
log(import_picocolors52.default.dim(" pass --force to overwrite"));
|
|
124103
124742
|
return 1;
|
|
124104
124743
|
}
|
|
124105
124744
|
try {
|
|
124106
|
-
(0,
|
|
124107
|
-
(0,
|
|
124745
|
+
(0, import_node_fs25.mkdirSync)((0, import_node_path27.dirname)(outPath), { recursive: true });
|
|
124746
|
+
(0, import_node_fs25.writeFileSync)(outPath, content, "utf8");
|
|
124108
124747
|
} catch (err2) {
|
|
124109
|
-
log(`${
|
|
124748
|
+
log(`${import_picocolors52.default.red("\u2717")} Could not write ${outPath}: ${err2.message}`);
|
|
124110
124749
|
return 1;
|
|
124111
124750
|
}
|
|
124112
|
-
log(`${
|
|
124751
|
+
log(`${import_picocolors52.default.green("\u2713")} Horus skill installed \u2192 ${outPath}`);
|
|
124113
124752
|
if (target === "claude") {
|
|
124114
|
-
log(
|
|
124115
|
-
log(
|
|
124753
|
+
log(import_picocolors52.default.dim(" Claude Code will load this skill automatically."));
|
|
124754
|
+
log(import_picocolors52.default.dim(" Invoke it with: /horus"));
|
|
124116
124755
|
} else if (target === "gemini") {
|
|
124117
|
-
log(
|
|
124756
|
+
log(import_picocolors52.default.dim(" Gemini CLI will load this context file automatically."));
|
|
124118
124757
|
} else if (target === "cursor") {
|
|
124119
|
-
log(
|
|
124758
|
+
log(import_picocolors52.default.dim(" Cursor will load this rule automatically."));
|
|
124120
124759
|
} else if (target === "codex") {
|
|
124121
|
-
log(
|
|
124760
|
+
log(import_picocolors52.default.dim(" Codex CLI will load this file automatically."));
|
|
124122
124761
|
} else {
|
|
124123
|
-
log(
|
|
124762
|
+
log(import_picocolors52.default.dim(` Copy or reference this file in your ${target} agent instructions.`));
|
|
124124
124763
|
}
|
|
124125
124764
|
return 0;
|
|
124126
124765
|
}
|
|
124127
124766
|
async function runSkillPrint(target, opts) {
|
|
124128
124767
|
const log = opts.write ?? ((line2) => console.log(line2));
|
|
124129
124768
|
if (!isValidTarget(target)) {
|
|
124130
|
-
log(`${
|
|
124131
|
-
log(
|
|
124769
|
+
log(`${import_picocolors52.default.red("\u2717")} Unknown target: ${import_picocolors52.default.bold(target)}`);
|
|
124770
|
+
log(import_picocolors52.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
|
|
124132
124771
|
return 1;
|
|
124133
124772
|
}
|
|
124134
124773
|
process.stdout.write(generateSkillContent(target));
|
|
@@ -124137,8 +124776,8 @@ async function runSkillPrint(target, opts) {
|
|
|
124137
124776
|
async function runSkillPath(target, opts) {
|
|
124138
124777
|
const log = opts.write ?? ((line2) => console.log(line2));
|
|
124139
124778
|
if (!isValidTarget(target)) {
|
|
124140
|
-
log(`${
|
|
124141
|
-
log(
|
|
124779
|
+
log(`${import_picocolors52.default.red("\u2717")} Unknown target: ${import_picocolors52.default.bold(target)}`);
|
|
124780
|
+
log(import_picocolors52.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
|
|
124142
124781
|
return 1;
|
|
124143
124782
|
}
|
|
124144
124783
|
const outPath = getSkillInstallPath(target, { global: opts.global, cwd: opts.cwd });
|
|
@@ -124148,7 +124787,7 @@ async function runSkillPath(target, opts) {
|
|
|
124148
124787
|
|
|
124149
124788
|
// ../../packages/cli/src/commands/login.ts
|
|
124150
124789
|
init_cjs_shims();
|
|
124151
|
-
var
|
|
124790
|
+
var import_picocolors53 = __toESM(require_picocolors(), 1);
|
|
124152
124791
|
var sleep2 = (ms) => new Promise((resolve13) => setTimeout(resolve13, ms));
|
|
124153
124792
|
async function loginWithToken(apiBaseUrl, token) {
|
|
124154
124793
|
const client = new CloudClient(apiBaseUrl, token);
|
|
@@ -124164,19 +124803,19 @@ async function loginWithToken(apiBaseUrl, token) {
|
|
|
124164
124803
|
}
|
|
124165
124804
|
});
|
|
124166
124805
|
console.log(
|
|
124167
|
-
`${
|
|
124806
|
+
`${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.`
|
|
124168
124807
|
);
|
|
124169
124808
|
return 0;
|
|
124170
124809
|
} catch (err2) {
|
|
124171
124810
|
if (err2 instanceof CloudOfflineError) {
|
|
124172
|
-
console.error(
|
|
124811
|
+
console.error(import_picocolors53.default.red(err2.message));
|
|
124173
124812
|
return 1;
|
|
124174
124813
|
}
|
|
124175
124814
|
if (err2 instanceof CloudError && err2.status === 401) {
|
|
124176
|
-
console.error(
|
|
124815
|
+
console.error(import_picocolors53.default.red("That token is not valid. Create a fresh one in the dashboard and try again."));
|
|
124177
124816
|
return 1;
|
|
124178
124817
|
}
|
|
124179
|
-
console.error(
|
|
124818
|
+
console.error(import_picocolors53.default.red(`Login failed: ${err2.message}`));
|
|
124180
124819
|
return 1;
|
|
124181
124820
|
}
|
|
124182
124821
|
}
|
|
@@ -124187,19 +124826,19 @@ async function loginWithBrowser(apiBaseUrl) {
|
|
|
124187
124826
|
session = await client.startCliSession();
|
|
124188
124827
|
} catch (err2) {
|
|
124189
124828
|
if (err2 instanceof CloudOfflineError) {
|
|
124190
|
-
console.error(
|
|
124829
|
+
console.error(import_picocolors53.default.red(err2.message));
|
|
124191
124830
|
return 1;
|
|
124192
124831
|
}
|
|
124193
|
-
console.error(
|
|
124832
|
+
console.error(import_picocolors53.default.red(`Could not start login: ${err2.message}`));
|
|
124194
124833
|
return 1;
|
|
124195
124834
|
}
|
|
124196
124835
|
console.log("");
|
|
124197
124836
|
console.log(` To sign in, open this URL in your browser:`);
|
|
124198
|
-
console.log(` ${
|
|
124837
|
+
console.log(` ${import_picocolors53.default.cyan(import_picocolors53.default.bold(session.verificationUri))}`);
|
|
124199
124838
|
console.log("");
|
|
124200
|
-
console.log(` and enter the code: ${
|
|
124839
|
+
console.log(` and enter the code: ${import_picocolors53.default.bold(session.userCode)}`);
|
|
124201
124840
|
console.log("");
|
|
124202
|
-
console.log(
|
|
124841
|
+
console.log(import_picocolors53.default.dim(` Waiting for approval\u2026 (press Ctrl+C to cancel)`));
|
|
124203
124842
|
openBrowser(session.verificationUriComplete);
|
|
124204
124843
|
const deadline = Date.now() + session.expiresIn * 1e3;
|
|
124205
124844
|
let intervalMs = Math.max(session.interval, 1) * 1e3;
|
|
@@ -124210,7 +124849,7 @@ async function loginWithBrowser(apiBaseUrl) {
|
|
|
124210
124849
|
poll = await client.pollCliSession(session.deviceCode);
|
|
124211
124850
|
} catch (err2) {
|
|
124212
124851
|
if (err2 instanceof CloudOfflineError) {
|
|
124213
|
-
console.error(
|
|
124852
|
+
console.error(import_picocolors53.default.red(`
|
|
124214
124853
|
${err2.message}`));
|
|
124215
124854
|
return 1;
|
|
124216
124855
|
}
|
|
@@ -124223,14 +124862,14 @@ ${err2.message}`));
|
|
|
124223
124862
|
intervalMs += 2e3;
|
|
124224
124863
|
break;
|
|
124225
124864
|
case "denied":
|
|
124226
|
-
console.error(
|
|
124865
|
+
console.error(import_picocolors53.default.red("\nLogin was denied in the browser."));
|
|
124227
124866
|
return 1;
|
|
124228
124867
|
case "expired":
|
|
124229
|
-
console.error(
|
|
124868
|
+
console.error(import_picocolors53.default.red("\nThis login request expired. Run `horus login` again."));
|
|
124230
124869
|
return 1;
|
|
124231
124870
|
case "approved":
|
|
124232
124871
|
if (!poll.token || !poll.account) {
|
|
124233
|
-
console.error(
|
|
124872
|
+
console.error(import_picocolors53.default.red("\nLogin approved but no token was returned. Try again."));
|
|
124234
124873
|
return 1;
|
|
124235
124874
|
}
|
|
124236
124875
|
writeAuth({
|
|
@@ -124240,12 +124879,12 @@ ${err2.message}`));
|
|
|
124240
124879
|
});
|
|
124241
124880
|
console.log(
|
|
124242
124881
|
`
|
|
124243
|
-
${
|
|
124882
|
+
${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.`
|
|
124244
124883
|
);
|
|
124245
124884
|
return 0;
|
|
124246
124885
|
}
|
|
124247
124886
|
}
|
|
124248
|
-
console.error(
|
|
124887
|
+
console.error(import_picocolors53.default.red("\nTimed out waiting for approval. Run `horus login` again."));
|
|
124249
124888
|
return 1;
|
|
124250
124889
|
}
|
|
124251
124890
|
async function runLogin(opts = {}) {
|
|
@@ -124259,7 +124898,7 @@ async function runLogin(opts = {}) {
|
|
|
124259
124898
|
async function runLogout() {
|
|
124260
124899
|
const auth = readAuth();
|
|
124261
124900
|
if (!auth) {
|
|
124262
|
-
console.log(
|
|
124901
|
+
console.log(import_picocolors53.default.dim("Not logged in."));
|
|
124263
124902
|
return 0;
|
|
124264
124903
|
}
|
|
124265
124904
|
const session = authedClient();
|
|
@@ -124273,13 +124912,13 @@ async function runLogout() {
|
|
|
124273
124912
|
}
|
|
124274
124913
|
}
|
|
124275
124914
|
clearAuth();
|
|
124276
|
-
console.log(`${
|
|
124915
|
+
console.log(`${import_picocolors53.default.green("\u2713")} Logged out. Local mode still works.`);
|
|
124277
124916
|
return 0;
|
|
124278
124917
|
}
|
|
124279
124918
|
|
|
124280
124919
|
// ../../packages/cli/src/commands/cloud.ts
|
|
124281
124920
|
init_cjs_shims();
|
|
124282
|
-
var
|
|
124921
|
+
var import_picocolors54 = __toESM(require_picocolors(), 1);
|
|
124283
124922
|
var import_promises4 = require("readline/promises");
|
|
124284
124923
|
|
|
124285
124924
|
// ../../packages/cli/src/lib/cloud/git.ts
|
|
@@ -124324,7 +124963,7 @@ async function runCloudLink(opts = {}) {
|
|
|
124324
124963
|
const root = repoRootOrCwd(opts.cwd);
|
|
124325
124964
|
const session = authedClient();
|
|
124326
124965
|
if (!session) {
|
|
124327
|
-
console.error(
|
|
124966
|
+
console.error(import_picocolors54.default.red(`Not logged in. Run ${import_picocolors54.default.bold("horus login")} first.`));
|
|
124328
124967
|
return 1;
|
|
124329
124968
|
}
|
|
124330
124969
|
let ctx;
|
|
@@ -124334,7 +124973,7 @@ async function runCloudLink(opts = {}) {
|
|
|
124334
124973
|
return reportCloudError(err2);
|
|
124335
124974
|
}
|
|
124336
124975
|
const remote = detectGitRemote(root);
|
|
124337
|
-
if (remote) console.log(
|
|
124976
|
+
if (remote) console.log(import_picocolors54.default.dim(`Detected git remote: ${remote.remoteUrl}`));
|
|
124338
124977
|
let resolved = null;
|
|
124339
124978
|
let target = opts.project;
|
|
124340
124979
|
if (!target) {
|
|
@@ -124350,7 +124989,7 @@ async function runCloudLink(opts = {}) {
|
|
|
124350
124989
|
const org = ctx.organizations.find((o5) => o5.id === match.organizationId);
|
|
124351
124990
|
if (ws && org) {
|
|
124352
124991
|
target = `${org.slug}/${ws.slug}/${match.slug}`;
|
|
124353
|
-
console.log(
|
|
124992
|
+
console.log(import_picocolors54.default.dim(`Matched existing project by remote: ${import_picocolors54.default.bold(target)}`));
|
|
124354
124993
|
}
|
|
124355
124994
|
}
|
|
124356
124995
|
}
|
|
@@ -124359,8 +124998,8 @@ async function runCloudLink(opts = {}) {
|
|
|
124359
124998
|
if (created === "aborted") return 1;
|
|
124360
124999
|
if (!created) {
|
|
124361
125000
|
console.error(
|
|
124362
|
-
|
|
124363
|
-
Run ${
|
|
125001
|
+
import_picocolors54.default.red("No project to link.") + `
|
|
125002
|
+
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")}.`
|
|
124364
125003
|
);
|
|
124365
125004
|
return 1;
|
|
124366
125005
|
}
|
|
@@ -124370,8 +125009,8 @@ async function runCloudLink(opts = {}) {
|
|
|
124370
125009
|
resolved = resolveTriple(ctx, target);
|
|
124371
125010
|
if (!resolved) {
|
|
124372
125011
|
console.error(
|
|
124373
|
-
|
|
124374
|
-
Run ${
|
|
125012
|
+
import_picocolors54.default.red(`You don't have access to ${import_picocolors54.default.bold(target)}.`) + `
|
|
125013
|
+
Run ${import_picocolors54.default.bold("horus context list")} to see available projects.`
|
|
124375
125014
|
);
|
|
124376
125015
|
return 1;
|
|
124377
125016
|
}
|
|
@@ -124384,10 +125023,10 @@ async function runCloudLink(opts = {}) {
|
|
|
124384
125023
|
project: resolved.project
|
|
124385
125024
|
});
|
|
124386
125025
|
console.log(
|
|
124387
|
-
`${
|
|
125026
|
+
`${import_picocolors54.default.green("\u2713")} Linked. Context for this repo is now ${import_picocolors54.default.bold(label)} ${import_picocolors54.default.dim("(cloud)")}.`
|
|
124388
125027
|
);
|
|
124389
125028
|
console.log(
|
|
124390
|
-
|
|
125029
|
+
import_picocolors54.default.dim(` Investigations here save to Horus Cloud. ${import_picocolors54.default.bold("horus context use local")} to switch back.`)
|
|
124391
125030
|
);
|
|
124392
125031
|
return 0;
|
|
124393
125032
|
}
|
|
@@ -124395,11 +125034,11 @@ async function runCloudUnlink(opts = {}) {
|
|
|
124395
125034
|
const root = repoRootOrCwd(opts.cwd);
|
|
124396
125035
|
const cfg = readCloudConfig(root);
|
|
124397
125036
|
if (!cfg || cfg.context !== "cloud") {
|
|
124398
|
-
console.log(
|
|
125037
|
+
console.log(import_picocolors54.default.dim("This repo isn't linked to a cloud project."));
|
|
124399
125038
|
return 0;
|
|
124400
125039
|
}
|
|
124401
125040
|
clearCloudConfig(root);
|
|
124402
|
-
console.log(`${
|
|
125041
|
+
console.log(`${import_picocolors54.default.green("\u2713")} Unlinked. This repo is back to ${import_picocolors54.default.bold("local")} mode.`);
|
|
124403
125042
|
return 0;
|
|
124404
125043
|
}
|
|
124405
125044
|
async function runCloudStatus(opts = {}) {
|
|
@@ -124407,18 +125046,18 @@ async function runCloudStatus(opts = {}) {
|
|
|
124407
125046
|
const cfg = readCloudConfig(root);
|
|
124408
125047
|
const session = authedClient();
|
|
124409
125048
|
if (!isCloudActive(cfg) || !cfg?.project) {
|
|
124410
|
-
console.log(`${
|
|
124411
|
-
console.log(`${
|
|
125049
|
+
console.log(`${import_picocolors54.default.bold("Context:")} local`);
|
|
125050
|
+
console.log(`${import_picocolors54.default.bold("Storage:")} local Postgres (~/.horus)`);
|
|
124412
125051
|
console.log(
|
|
124413
|
-
|
|
125052
|
+
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.`)
|
|
124414
125053
|
);
|
|
124415
125054
|
return 0;
|
|
124416
125055
|
}
|
|
124417
125056
|
const triple = `${cfg.organization?.slug}/${cfg.workspace?.slug}/${cfg.project.slug}`;
|
|
124418
|
-
console.log(`${
|
|
125057
|
+
console.log(`${import_picocolors54.default.bold("Context:")} ${triple} ${import_picocolors54.default.dim("(cloud)")}`);
|
|
124419
125058
|
let projectLine = `${cfg.project.slug}`;
|
|
124420
125059
|
let metaLines = [];
|
|
124421
|
-
let account =
|
|
125060
|
+
let account = import_picocolors54.default.dim("not logged in");
|
|
124422
125061
|
if (session) {
|
|
124423
125062
|
account = session.auth.account.email;
|
|
124424
125063
|
try {
|
|
@@ -124433,9 +125072,9 @@ async function runCloudStatus(opts = {}) {
|
|
|
124433
125072
|
} catch {
|
|
124434
125073
|
}
|
|
124435
125074
|
}
|
|
124436
|
-
console.log(`${
|
|
125075
|
+
console.log(`${import_picocolors54.default.bold("Project:")} ${projectLine}`);
|
|
124437
125076
|
for (const line2 of metaLines) console.log(line2);
|
|
124438
|
-
console.log(`${
|
|
125077
|
+
console.log(`${import_picocolors54.default.bold("Account:")} ${account}`);
|
|
124439
125078
|
return 0;
|
|
124440
125079
|
}
|
|
124441
125080
|
async function runCloudSync(opts = {}) {
|
|
@@ -124443,13 +125082,13 @@ async function runCloudSync(opts = {}) {
|
|
|
124443
125082
|
const cfg = readCloudConfig(root);
|
|
124444
125083
|
if (!isCloudActive(cfg) || !cfg.project) {
|
|
124445
125084
|
console.error(
|
|
124446
|
-
|
|
125085
|
+
import_picocolors54.default.red("This repo isn't linked to a cloud project.") + ` Run ${import_picocolors54.default.bold("horus cloud link")} first.`
|
|
124447
125086
|
);
|
|
124448
125087
|
return 1;
|
|
124449
125088
|
}
|
|
124450
125089
|
const session = authedClient();
|
|
124451
125090
|
if (!session) {
|
|
124452
|
-
console.error(
|
|
125091
|
+
console.error(import_picocolors54.default.red(`Not logged in. Run ${import_picocolors54.default.bold("horus login")} first.`));
|
|
124453
125092
|
return 1;
|
|
124454
125093
|
}
|
|
124455
125094
|
const { db, sql: sql2 } = await openDb(await resolveDbUrl(opts.config));
|
|
@@ -124467,26 +125106,26 @@ async function runCloudSync(opts = {}) {
|
|
|
124467
125106
|
const target = `${cfg.organization?.slug}/${cfg.workspace?.slug}/${cfg.project.slug}`;
|
|
124468
125107
|
if (uploadable.length === 0) {
|
|
124469
125108
|
console.log(
|
|
124470
|
-
|
|
125109
|
+
import_picocolors54.default.dim(
|
|
124471
125110
|
`No local investigations with reports to upload.` + (skippedNoReport ? ` (${skippedNoReport} without a report skipped)` : "")
|
|
124472
125111
|
)
|
|
124473
125112
|
);
|
|
124474
125113
|
return 0;
|
|
124475
125114
|
}
|
|
124476
|
-
console.log(
|
|
125115
|
+
console.log(import_picocolors54.default.bold(`Will upload ${uploadable.length} investigation(s) to ${target} ${import_picocolors54.default.dim("(cloud)")}:`));
|
|
124477
125116
|
for (const c4 of uploadable.slice(0, 20)) {
|
|
124478
|
-
console.log(` ${
|
|
125117
|
+
console.log(` ${import_picocolors54.default.dim(c4.id.slice(0, 8))} ${(c4.title ?? "untitled").slice(0, 70)}`);
|
|
124479
125118
|
}
|
|
124480
|
-
if (uploadable.length > 20) console.log(
|
|
124481
|
-
if (skippedNoReport) console.log(
|
|
125119
|
+
if (uploadable.length > 20) console.log(import_picocolors54.default.dim(` \u2026and ${uploadable.length - 20} more`));
|
|
125120
|
+
if (skippedNoReport) console.log(import_picocolors54.default.dim(` (${skippedNoReport} local investigation(s) without a report will be skipped)`));
|
|
124482
125121
|
if (opts.dryRun) {
|
|
124483
|
-
console.log(
|
|
125122
|
+
console.log(import_picocolors54.default.dim("Dry run \u2014 nothing uploaded. Re-run without --dry-run to upload."));
|
|
124484
125123
|
return 0;
|
|
124485
125124
|
}
|
|
124486
125125
|
if (!opts.yes) {
|
|
124487
125126
|
if (!process.stdin.isTTY) {
|
|
124488
125127
|
console.error(
|
|
124489
|
-
|
|
125128
|
+
import_picocolors54.default.yellow(`Re-run with ${import_picocolors54.default.bold("--yes")} to upload, or ${import_picocolors54.default.bold("--dry-run")} to preview only.`)
|
|
124490
125129
|
);
|
|
124491
125130
|
return 1;
|
|
124492
125131
|
}
|
|
@@ -124494,7 +125133,7 @@ async function runCloudSync(opts = {}) {
|
|
|
124494
125133
|
try {
|
|
124495
125134
|
const answer = (await rl.question(`Upload ${uploadable.length} investigation(s) to ${target}? (y/N) `)).trim().toLowerCase();
|
|
124496
125135
|
if (answer !== "y" && answer !== "yes") {
|
|
124497
|
-
console.log(
|
|
125136
|
+
console.log(import_picocolors54.default.dim("Aborted. Nothing uploaded."));
|
|
124498
125137
|
return 0;
|
|
124499
125138
|
}
|
|
124500
125139
|
} finally {
|
|
@@ -124507,18 +125146,18 @@ async function runCloudSync(opts = {}) {
|
|
|
124507
125146
|
try {
|
|
124508
125147
|
const refs = await uploadInvestigationToCloud(session.client, cfg, c4.report, { db });
|
|
124509
125148
|
created++;
|
|
124510
|
-
console.log(`${
|
|
125149
|
+
console.log(`${import_picocolors54.default.green("\u2713")} ${import_picocolors54.default.dim(c4.id.slice(0, 8))} \u2192 ${refs.investigationId}`);
|
|
124511
125150
|
} catch (err2) {
|
|
124512
125151
|
failed++;
|
|
124513
|
-
console.error(`${
|
|
125152
|
+
console.error(`${import_picocolors54.default.red("\u2717")} ${import_picocolors54.default.dim(c4.id.slice(0, 8))} ${err2.message}`);
|
|
124514
125153
|
}
|
|
124515
125154
|
}
|
|
124516
125155
|
console.log("");
|
|
124517
125156
|
console.log(
|
|
124518
|
-
`${
|
|
125157
|
+
`${import_picocolors54.default.bold("Sync complete:")} ${import_picocolors54.default.green(`${created} uploaded`)}, ${skippedNoReport} skipped, ` + (failed ? import_picocolors54.default.red(`${failed} failed`) : "0 failed") + "."
|
|
124519
125158
|
);
|
|
124520
125159
|
console.log(
|
|
124521
|
-
|
|
125160
|
+
import_picocolors54.default.dim("Local data was not modified. Re-running is safe \u2014 duplicates are deduped by idempotency key.")
|
|
124522
125161
|
);
|
|
124523
125162
|
return failed > 0 ? 1 : 0;
|
|
124524
125163
|
} finally {
|
|
@@ -124529,8 +125168,8 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
|
|
|
124529
125168
|
if (!process.stdin.isTTY && !yes) return null;
|
|
124530
125169
|
if (ctx.organizations.length === 0) {
|
|
124531
125170
|
console.error(
|
|
124532
|
-
|
|
124533
|
-
Create one at ${
|
|
125171
|
+
import_picocolors54.default.red("You're not a member of any organization yet.") + `
|
|
125172
|
+
Create one at ${import_picocolors54.default.bold("https://cloud.horus.sh")} first.`
|
|
124534
125173
|
);
|
|
124535
125174
|
return null;
|
|
124536
125175
|
}
|
|
@@ -124555,9 +125194,9 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
|
|
|
124555
125194
|
const wsName = await ask2("New workspace name", repoName || "default");
|
|
124556
125195
|
const ws = await client.createWorkspace(org.id, { name: wsName });
|
|
124557
125196
|
workspace = { id: ws.id, slug: ws.slug };
|
|
124558
|
-
console.log(
|
|
125197
|
+
console.log(import_picocolors54.default.dim(`Created workspace ${import_picocolors54.default.bold(ws.slug)}.`));
|
|
124559
125198
|
} else {
|
|
124560
|
-
console.log(`Workspaces in ${
|
|
125199
|
+
console.log(`Workspaces in ${import_picocolors54.default.bold(org.slug)}:`);
|
|
124561
125200
|
orgWorkspaces.forEach((w4, i3) => console.log(` ${i3 + 1}) ${w4.slug}`));
|
|
124562
125201
|
console.log(` ${orgWorkspaces.length + 1}) + create a new workspace`);
|
|
124563
125202
|
const pick2 = Number(await ask2("Workspace number", "1"));
|
|
@@ -124565,7 +125204,7 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
|
|
|
124565
125204
|
const wsName = await ask2("New workspace name", repoName || "default");
|
|
124566
125205
|
const ws = await client.createWorkspace(org.id, { name: wsName });
|
|
124567
125206
|
workspace = { id: ws.id, slug: ws.slug };
|
|
124568
|
-
console.log(
|
|
125207
|
+
console.log(import_picocolors54.default.dim(`Created workspace ${import_picocolors54.default.bold(ws.slug)}.`));
|
|
124569
125208
|
} else {
|
|
124570
125209
|
const chosen = orgWorkspaces[pick2 - 1] ?? orgWorkspaces[0];
|
|
124571
125210
|
workspace = { id: chosen.id, slug: chosen.slug };
|
|
@@ -124577,7 +125216,7 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
|
|
|
124577
125216
|
remoteUrl: remote?.remoteUrl,
|
|
124578
125217
|
provider: remote ? inferProvider(remote.remoteUrl) : void 0
|
|
124579
125218
|
});
|
|
124580
|
-
console.log(
|
|
125219
|
+
console.log(import_picocolors54.default.dim(`Created project ${import_picocolors54.default.bold(project.slug)}.`));
|
|
124581
125220
|
return {
|
|
124582
125221
|
organization: { id: org.id, slug: org.slug },
|
|
124583
125222
|
workspace,
|
|
@@ -124593,8 +125232,8 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
|
|
|
124593
125232
|
|
|
124594
125233
|
// ../../packages/cli/src/commands/telemetry.ts
|
|
124595
125234
|
init_cjs_shims();
|
|
124596
|
-
var
|
|
124597
|
-
var
|
|
125235
|
+
var import_picocolors56 = __toESM(require_picocolors(), 1);
|
|
125236
|
+
var import_node_crypto11 = require("crypto");
|
|
124598
125237
|
|
|
124599
125238
|
// ../../packages/cli/src/lib/telemetry/transport.ts
|
|
124600
125239
|
init_cjs_shims();
|
|
@@ -124654,7 +125293,7 @@ async function deleteRemoteTelemetry(installId, opts = {}) {
|
|
|
124654
125293
|
|
|
124655
125294
|
// ../../packages/cli/src/lib/telemetry/notice.ts
|
|
124656
125295
|
init_cjs_shims();
|
|
124657
|
-
var
|
|
125296
|
+
var import_picocolors55 = __toESM(require_picocolors(), 1);
|
|
124658
125297
|
var PRIVACY_URL = "https://horus.sh/privacy";
|
|
124659
125298
|
var SUPPRESS_FIRST_TOKEN = /* @__PURE__ */ new Set(["telemetry", "help"]);
|
|
124660
125299
|
var SUPPRESS_FLAGS = /* @__PURE__ */ new Set(["-V", "--version", "-h", "--help"]);
|
|
@@ -124666,11 +125305,11 @@ function shouldSuppressFor(argv) {
|
|
|
124666
125305
|
return firstToken != null && SUPPRESS_FIRST_TOKEN.has(firstToken);
|
|
124667
125306
|
}
|
|
124668
125307
|
function banner() {
|
|
124669
|
-
const b5 =
|
|
124670
|
-
const dim =
|
|
125308
|
+
const b5 = import_picocolors55.default.bold;
|
|
125309
|
+
const dim = import_picocolors55.default.dim;
|
|
124671
125310
|
return [
|
|
124672
125311
|
"",
|
|
124673
|
-
|
|
125312
|
+
import_picocolors55.default.cyan(b5("Horus collects anonymous usage data to improve the tool.")),
|
|
124674
125313
|
dim(" \u2022 On by default: command names, timings, success/failure, and where the"),
|
|
124675
125314
|
dim(" engine ran out of evidence. No file contents, queries, or secrets."),
|
|
124676
125315
|
dim(" \u2022 Off by default: your investigation inputs/outputs (opt in to help train"),
|
|
@@ -124678,7 +125317,7 @@ function banner() {
|
|
|
124678
125317
|
dim(" \u2022 If you use Horus Cloud, linked investigations sync to your workspace."),
|
|
124679
125318
|
"",
|
|
124680
125319
|
` ${dim("Opt out anytime:")} ${b5("horus telemetry disable")} ${dim("\xB7")} ${b5("HORUS_TELEMETRY=0")} ${dim("\xB7")} ${b5("DO_NOT_TRACK=1")}`,
|
|
124681
|
-
` ${dim("Details:")} ${
|
|
125320
|
+
` ${dim("Details:")} ${import_picocolors55.default.underline(PRIVACY_URL)}`,
|
|
124682
125321
|
""
|
|
124683
125322
|
].join("\n");
|
|
124684
125323
|
}
|
|
@@ -124701,45 +125340,45 @@ function maybeShowFirstRunNotice(argv = process.argv) {
|
|
|
124701
125340
|
|
|
124702
125341
|
// ../../packages/cli/src/commands/telemetry.ts
|
|
124703
125342
|
function onOff(enabled) {
|
|
124704
|
-
return enabled ?
|
|
125343
|
+
return enabled ? import_picocolors56.default.green("on") : import_picocolors56.default.dim("off");
|
|
124705
125344
|
}
|
|
124706
125345
|
function warnIfEnvOverrides() {
|
|
124707
125346
|
const decision = resolveConsent();
|
|
124708
125347
|
if (decision.forcedOff) {
|
|
124709
125348
|
console.log(
|
|
124710
|
-
|
|
125349
|
+
import_picocolors56.default.yellow(
|
|
124711
125350
|
`
|
|
124712
125351
|
Note: telemetry is currently forced off by your environment (${decision.reason}).`
|
|
124713
125352
|
)
|
|
124714
125353
|
);
|
|
124715
|
-
console.log(
|
|
125354
|
+
console.log(import_picocolors56.default.dim("Your saved preference will apply once that override is removed."));
|
|
124716
125355
|
} else if (decision.source === "ci") {
|
|
124717
125356
|
console.log(
|
|
124718
|
-
|
|
125357
|
+
import_picocolors56.default.yellow("\nNote: CI environment detected \u2014 telemetry stays off here regardless.")
|
|
124719
125358
|
);
|
|
124720
125359
|
}
|
|
124721
125360
|
}
|
|
124722
125361
|
async function runTelemetryStatus() {
|
|
124723
125362
|
const state = readTelemetryState();
|
|
124724
125363
|
const decision = resolveConsent({ state });
|
|
124725
|
-
console.log(
|
|
125364
|
+
console.log(import_picocolors56.default.bold("Horus telemetry"));
|
|
124726
125365
|
console.log(
|
|
124727
|
-
` Usage metadata (Tier A): ${onOff(decision.tierA)} ${
|
|
125366
|
+
` Usage metadata (Tier A): ${onOff(decision.tierA)} ${import_picocolors56.default.dim(`[${decision.source}]`)}`
|
|
124728
125367
|
);
|
|
124729
125368
|
console.log(` Content sharing (Tier B): ${onOff(decision.tierB)}`);
|
|
124730
|
-
console.log(
|
|
125369
|
+
console.log(import_picocolors56.default.dim(` Reason: ${decision.reason}`));
|
|
124731
125370
|
if (state) {
|
|
124732
|
-
console.log(
|
|
125371
|
+
console.log(import_picocolors56.default.dim(` Install ID: ${state.installId}`));
|
|
124733
125372
|
console.log(
|
|
124734
|
-
|
|
125373
|
+
import_picocolors56.default.dim(
|
|
124735
125374
|
` Saved: Tier A ${state.tierA.enabled ? "on" : "off"}, Tier B ${state.tierB.enabled ? "on" : "off"}`
|
|
124736
125375
|
)
|
|
124737
125376
|
);
|
|
124738
125377
|
} else {
|
|
124739
|
-
console.log(
|
|
125378
|
+
console.log(import_picocolors56.default.dim(" No saved preference yet (defaults apply)."));
|
|
124740
125379
|
}
|
|
124741
|
-
console.log(
|
|
124742
|
-
console.log(
|
|
125380
|
+
console.log(import_picocolors56.default.dim(` Config: ${telemetryPath()}`));
|
|
125381
|
+
console.log(import_picocolors56.default.dim(` Privacy: ${PRIVACY_URL}`));
|
|
124743
125382
|
if (!state || decision.source === "env" || decision.source === "ci") {
|
|
124744
125383
|
warnIfEnvOverrides();
|
|
124745
125384
|
}
|
|
@@ -124750,7 +125389,7 @@ async function runTelemetryEnable() {
|
|
|
124750
125389
|
s5.tierA.enabled = true;
|
|
124751
125390
|
if (!s5.tierA.noticeShownAt) s5.tierA.noticeShownAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
124752
125391
|
});
|
|
124753
|
-
console.log(
|
|
125392
|
+
console.log(import_picocolors56.default.green("Anonymous usage metadata (Tier A) is now ON. Thank you!"));
|
|
124754
125393
|
warnIfEnvOverrides();
|
|
124755
125394
|
return 0;
|
|
124756
125395
|
}
|
|
@@ -124760,7 +125399,7 @@ async function runTelemetryDisable() {
|
|
|
124760
125399
|
s5.tierB.enabled = false;
|
|
124761
125400
|
if (!s5.tierA.noticeShownAt) s5.tierA.noticeShownAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
124762
125401
|
});
|
|
124763
|
-
console.log(
|
|
125402
|
+
console.log(import_picocolors56.default.yellow("All telemetry is now OFF (Tier A and Tier B)."));
|
|
124764
125403
|
return 0;
|
|
124765
125404
|
}
|
|
124766
125405
|
async function runTelemetryEnableContent() {
|
|
@@ -124771,10 +125410,10 @@ async function runTelemetryEnableContent() {
|
|
|
124771
125410
|
if (!s5.tierA.noticeShownAt) s5.tierA.noticeShownAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
124772
125411
|
});
|
|
124773
125412
|
console.log(
|
|
124774
|
-
|
|
125413
|
+
import_picocolors56.default.green("Content sharing (Tier B) is now ON \u2014 redacted inputs/outputs help improve Horus.")
|
|
124775
125414
|
);
|
|
124776
|
-
console.log(
|
|
124777
|
-
console.log(
|
|
125415
|
+
console.log(import_picocolors56.default.dim("Content is scrubbed of secrets/PII before it ever leaves your machine."));
|
|
125416
|
+
console.log(import_picocolors56.default.dim(`What this means: ${PRIVACY_URL}`));
|
|
124778
125417
|
warnIfEnvOverrides();
|
|
124779
125418
|
return 0;
|
|
124780
125419
|
}
|
|
@@ -124782,16 +125421,16 @@ async function runTelemetryDisableContent() {
|
|
|
124782
125421
|
updateTelemetryState((s5) => {
|
|
124783
125422
|
s5.tierB.enabled = false;
|
|
124784
125423
|
});
|
|
124785
|
-
console.log(
|
|
125424
|
+
console.log(import_picocolors56.default.yellow("Content sharing (Tier B) is now OFF. Usage metadata is unchanged."));
|
|
124786
125425
|
return 0;
|
|
124787
125426
|
}
|
|
124788
125427
|
async function runTelemetryResetId() {
|
|
124789
|
-
const next = (0,
|
|
125428
|
+
const next = (0, import_node_crypto11.randomUUID)();
|
|
124790
125429
|
updateTelemetryState((s5) => {
|
|
124791
125430
|
s5.installId = next;
|
|
124792
125431
|
});
|
|
124793
|
-
console.log(
|
|
124794
|
-
console.log(
|
|
125432
|
+
console.log(import_picocolors56.default.green("Install ID reset."));
|
|
125433
|
+
console.log(import_picocolors56.default.dim(` New install ID: ${next}`));
|
|
124795
125434
|
return 0;
|
|
124796
125435
|
}
|
|
124797
125436
|
async function runTelemetryDelete() {
|
|
@@ -124799,9 +125438,9 @@ async function runTelemetryDelete() {
|
|
|
124799
125438
|
if (installId) await deleteRemoteTelemetry(installId);
|
|
124800
125439
|
deleteTelemetryState();
|
|
124801
125440
|
clearSpool();
|
|
124802
|
-
console.log(
|
|
125441
|
+
console.log(import_picocolors56.default.green("Telemetry deleted \u2014 local state cleared and a server purge requested."));
|
|
124803
125442
|
console.log(
|
|
124804
|
-
|
|
125443
|
+
import_picocolors56.default.dim(
|
|
124805
125444
|
"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."
|
|
124806
125445
|
)
|
|
124807
125446
|
);
|
|
@@ -124845,8 +125484,8 @@ function installCommandTelemetry(program2) {
|
|
|
124845
125484
|
// ../../packages/cli/src/commands/eval.ts
|
|
124846
125485
|
init_cjs_shims();
|
|
124847
125486
|
var import_promises5 = require("fs/promises");
|
|
124848
|
-
var
|
|
124849
|
-
var
|
|
125487
|
+
var import_node_path28 = require("path");
|
|
125488
|
+
var import_picocolors57 = __toESM(require_picocolors(), 1);
|
|
124850
125489
|
function resolveProject2(config2, repo) {
|
|
124851
125490
|
let project;
|
|
124852
125491
|
try {
|
|
@@ -124854,7 +125493,7 @@ function resolveProject2(config2, repo) {
|
|
|
124854
125493
|
} catch {
|
|
124855
125494
|
}
|
|
124856
125495
|
if (!project) {
|
|
124857
|
-
console.error(
|
|
125496
|
+
console.error(import_picocolors57.default.red("Could not resolve a project \u2014 pass --repo <name> or run inside a repo."));
|
|
124858
125497
|
return null;
|
|
124859
125498
|
}
|
|
124860
125499
|
return project;
|
|
@@ -124863,7 +125502,7 @@ function readSlice(opts) {
|
|
|
124863
125502
|
let source;
|
|
124864
125503
|
if (opts.source !== void 0) {
|
|
124865
125504
|
if (!isOutcomeSource(opts.source)) {
|
|
124866
|
-
console.error(
|
|
125505
|
+
console.error(import_picocolors57.default.red(`Unknown --source "${opts.source}" (one of: feedback, confirm).`));
|
|
124867
125506
|
return null;
|
|
124868
125507
|
}
|
|
124869
125508
|
source = opts.source;
|
|
@@ -124871,7 +125510,7 @@ function readSlice(opts) {
|
|
|
124871
125510
|
let since;
|
|
124872
125511
|
if (opts.days !== void 0) {
|
|
124873
125512
|
if (!Number.isFinite(opts.days) || opts.days <= 0) {
|
|
124874
|
-
console.error(
|
|
125513
|
+
console.error(import_picocolors57.default.red("--days must be a positive number."));
|
|
124875
125514
|
return null;
|
|
124876
125515
|
}
|
|
124877
125516
|
since = new Date(Date.now() - opts.days * 24 * 60 * 60 * 1e3);
|
|
@@ -124895,7 +125534,7 @@ async function runEvalBuild(opts) {
|
|
|
124895
125534
|
const project = resolveProject2(config2, opts.repo);
|
|
124896
125535
|
if (!project) return 1;
|
|
124897
125536
|
const version3 = opts.version ?? CORPUS_VERSION;
|
|
124898
|
-
const outDir = opts.out ? (0,
|
|
125537
|
+
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");
|
|
124899
125538
|
const { db, sql: sql2 } = await openDb(config2.database.url);
|
|
124900
125539
|
try {
|
|
124901
125540
|
const labels = await listOutcomeLabels(db, {
|
|
@@ -124911,34 +125550,34 @@ async function runEvalBuild(opts) {
|
|
|
124911
125550
|
const build = buildCorpus(labels, resolveReport);
|
|
124912
125551
|
const artifact = serializeCorpus(build, version3);
|
|
124913
125552
|
await (0, import_promises5.mkdir)(outDir, { recursive: true });
|
|
124914
|
-
const corpusPath = (0,
|
|
124915
|
-
const manifestPath = (0,
|
|
125553
|
+
const corpusPath = (0, import_node_path28.join)(outDir, artifact.filename);
|
|
125554
|
+
const manifestPath = (0, import_node_path28.join)(outDir, `corpus-${version3}.manifest.json`);
|
|
124916
125555
|
const manifest = { ...artifact.manifest, generatedAt: (/* @__PURE__ */ new Date()).toISOString(), project };
|
|
124917
125556
|
await (0, import_promises5.writeFile)(corpusPath, artifact.jsonl, "utf8");
|
|
124918
125557
|
await (0, import_promises5.writeFile)(manifestPath, JSON.stringify(manifest, null, 2) + "\n", "utf8");
|
|
124919
125558
|
if (opts.json) {
|
|
124920
125559
|
console.log(JSON.stringify({ project, corpusPath, manifestPath, manifest }, null, 2));
|
|
124921
125560
|
} else {
|
|
124922
|
-
console.log(
|
|
125561
|
+
console.log(import_picocolors57.default.bold(`Eval corpus \u2014 ${project}`));
|
|
124923
125562
|
console.log(
|
|
124924
|
-
` Rows: ${
|
|
125563
|
+
` Rows: ${import_picocolors57.default.green(String(build.rows.length))} ` + import_picocolors57.default.dim(
|
|
124925
125564
|
`(evaluated ${build.evaluated}, quarantined ${build.quarantined.length}, unjoinable ${build.unjoinable.length})`
|
|
124926
125565
|
)
|
|
124927
125566
|
);
|
|
124928
125567
|
console.log(
|
|
124929
|
-
|
|
125568
|
+
import_picocolors57.default.dim(
|
|
124930
125569
|
` Class balance: ${build.classBalance.yes} yes, ${build.classBalance.partly} partly, ${build.classBalance.no} no \xB7 source: ${build.bySource.feedback} feedback, ${build.bySource.confirm} confirm`
|
|
124931
125570
|
)
|
|
124932
125571
|
);
|
|
124933
|
-
console.log(` Corpus: ${
|
|
124934
|
-
console.log(` Manifest: ${
|
|
125572
|
+
console.log(` Corpus: ${import_picocolors57.default.cyan(corpusPath)}`);
|
|
125573
|
+
console.log(` Manifest: ${import_picocolors57.default.cyan(manifestPath)}`);
|
|
124935
125574
|
}
|
|
124936
125575
|
return 0;
|
|
124937
125576
|
} finally {
|
|
124938
125577
|
await sql2.end();
|
|
124939
125578
|
}
|
|
124940
125579
|
} catch (err2) {
|
|
124941
|
-
console.error(
|
|
125580
|
+
console.error(import_picocolors57.default.red(err2.message));
|
|
124942
125581
|
return 1;
|
|
124943
125582
|
}
|
|
124944
125583
|
}
|
|
@@ -124968,31 +125607,31 @@ async function runEvalBaseline(opts) {
|
|
|
124968
125607
|
console.log(JSON.stringify({ project, baseline, separation }, null, 2));
|
|
124969
125608
|
} else {
|
|
124970
125609
|
const pct2 = (n4) => `${(n4 * 100).toFixed(0)}%`;
|
|
124971
|
-
console.log(
|
|
125610
|
+
console.log(import_picocolors57.default.bold(`Eval baseline \u2014 ${project}`));
|
|
124972
125611
|
if (baseline.n === 0) {
|
|
124973
125612
|
console.log(
|
|
124974
|
-
|
|
125613
|
+
import_picocolors57.default.dim(
|
|
124975
125614
|
"No outcome labels yet. Leave feedback (`horus feedback`) or confirm an investigation (`horus memory confirm`) to seed the eval set."
|
|
124976
125615
|
)
|
|
124977
125616
|
);
|
|
124978
125617
|
} else {
|
|
124979
125618
|
console.log(
|
|
124980
|
-
` Strict hit-rate: ${
|
|
125619
|
+
` Strict hit-rate: ${import_picocolors57.default.green(pct2(baseline.strictHitRate))} ` + import_picocolors57.default.dim(`(weighted ${pct2(baseline.weightedHitRate)}) over ${baseline.n} investigation(s)`)
|
|
124981
125620
|
);
|
|
124982
125621
|
console.log(
|
|
124983
|
-
` Class balance: ${
|
|
125622
|
+
` 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`)
|
|
124984
125623
|
);
|
|
124985
125624
|
if (separation.factors.length === 0) {
|
|
124986
125625
|
console.log(
|
|
124987
|
-
|
|
125626
|
+
import_picocolors57.default.dim(
|
|
124988
125627
|
` Feature separation: no discriminative sample yet (needs feedback rows with yes AND no verdicts and a ranked cause).`
|
|
124989
125628
|
)
|
|
124990
125629
|
);
|
|
124991
125630
|
} else {
|
|
124992
|
-
console.log(
|
|
125631
|
+
console.log(import_picocolors57.default.dim(` Feature separation (yes vs no, ${separation.evaluated} row(s)):`));
|
|
124993
125632
|
for (const f5 of separation.factors.slice(0, 10)) {
|
|
124994
125633
|
console.log(
|
|
124995
|
-
|
|
125634
|
+
import_picocolors57.default.dim(
|
|
124996
125635
|
` ${f5.factor}: \u0394 ${f5.separation.toFixed(3)} (yes ${f5.meanYes.toFixed(3)} vs no ${f5.meanNo.toFixed(3)}, effect ${f5.effectSize.toFixed(2)})`
|
|
124997
125636
|
)
|
|
124998
125637
|
);
|
|
@@ -125005,7 +125644,7 @@ async function runEvalBaseline(opts) {
|
|
|
125005
125644
|
await sql2.end();
|
|
125006
125645
|
}
|
|
125007
125646
|
} catch (err2) {
|
|
125008
|
-
console.error(
|
|
125647
|
+
console.error(import_picocolors57.default.red(err2.message));
|
|
125009
125648
|
return 1;
|
|
125010
125649
|
}
|
|
125011
125650
|
}
|
|
@@ -125013,10 +125652,10 @@ async function runEvalBaseline(opts) {
|
|
|
125013
125652
|
// ../../packages/cli/src/commands/train.ts
|
|
125014
125653
|
init_cjs_shims();
|
|
125015
125654
|
var import_promises6 = require("fs/promises");
|
|
125016
|
-
var
|
|
125017
|
-
var
|
|
125018
|
-
var
|
|
125019
|
-
var RERANKER_MODEL_PATH = (0,
|
|
125655
|
+
var import_node_path29 = require("path");
|
|
125656
|
+
var import_node_os11 = require("os");
|
|
125657
|
+
var import_picocolors58 = __toESM(require_picocolors(), 1);
|
|
125658
|
+
var RERANKER_MODEL_PATH = (0, import_node_path29.join)((0, import_node_os11.homedir)(), ".horus", "reranker.json");
|
|
125020
125659
|
function candidatesFromReport(blob) {
|
|
125021
125660
|
if (blob === null || typeof blob !== "object") return null;
|
|
125022
125661
|
const causes = blob.suspectedCauses;
|
|
@@ -125030,7 +125669,7 @@ async function runTrain(opts) {
|
|
|
125030
125669
|
let source;
|
|
125031
125670
|
if (opts.source !== void 0) {
|
|
125032
125671
|
if (!isOutcomeSource(opts.source)) {
|
|
125033
|
-
console.error(
|
|
125672
|
+
console.error(import_picocolors58.default.red(`Unknown --source "${opts.source}" (one of: feedback, confirm).`));
|
|
125034
125673
|
return 1;
|
|
125035
125674
|
}
|
|
125036
125675
|
source = opts.source;
|
|
@@ -125038,7 +125677,7 @@ async function runTrain(opts) {
|
|
|
125038
125677
|
let since;
|
|
125039
125678
|
if (opts.days !== void 0) {
|
|
125040
125679
|
if (!Number.isFinite(opts.days) || opts.days <= 0) {
|
|
125041
|
-
console.error(
|
|
125680
|
+
console.error(import_picocolors58.default.red("--days must be a positive number."));
|
|
125042
125681
|
return 1;
|
|
125043
125682
|
}
|
|
125044
125683
|
since = new Date(Date.now() - opts.days * 24 * 60 * 60 * 1e3);
|
|
@@ -125074,7 +125713,7 @@ async function runTrain(opts) {
|
|
|
125074
125713
|
await sql2.end();
|
|
125075
125714
|
}
|
|
125076
125715
|
} catch (err2) {
|
|
125077
|
-
console.error(
|
|
125716
|
+
console.error(import_picocolors58.default.red(`Could not read the local corpus: ${err2.message}`));
|
|
125078
125717
|
return 1;
|
|
125079
125718
|
}
|
|
125080
125719
|
const split = holdoutSplit(investigations2);
|
|
@@ -125082,48 +125721,48 @@ async function runTrain(opts) {
|
|
|
125082
125721
|
if (!result.ok) {
|
|
125083
125722
|
if (result.reason === "insufficient-corpus") {
|
|
125084
125723
|
console.log(
|
|
125085
|
-
|
|
125724
|
+
import_picocolors58.default.yellow(
|
|
125086
125725
|
`Not enough labeled investigations to train yet (have ${result.labeledInvestigations} with a known-correct cause; need \u2265${MIN_TRAIN_INVESTIGATIONS}).`
|
|
125087
125726
|
)
|
|
125088
125727
|
);
|
|
125089
|
-
console.log(
|
|
125728
|
+
console.log(import_picocolors58.default.dim(" Keep labeling outcomes with `horus feedback` \u2014 the reranker trains once the corpus is large enough."));
|
|
125090
125729
|
} else {
|
|
125091
|
-
console.log(
|
|
125730
|
+
console.log(import_picocolors58.default.yellow(`Cannot train a meaningful model yet: ${result.detail}.`));
|
|
125092
125731
|
}
|
|
125093
125732
|
return 0;
|
|
125094
125733
|
}
|
|
125095
125734
|
const { baselineHitRate, rerankedHitRate, delta, n: n4 } = result.holdout;
|
|
125096
|
-
console.log(
|
|
125735
|
+
console.log(import_picocolors58.default.bold("\nReranker training (local, per-tenant)\n"));
|
|
125097
125736
|
console.log(` Holdout investigations: ${n4}`);
|
|
125098
125737
|
console.log(` Baseline top-1 hit-rate: ${pct(baselineHitRate)}`);
|
|
125099
125738
|
console.log(` Reranked top-1 hit-rate: ${pct(rerankedHitRate)}`);
|
|
125100
125739
|
console.log(` Delta: ${delta >= 0 ? "+" : ""}${pct(delta)}`);
|
|
125101
125740
|
console.log("");
|
|
125102
125741
|
if (delta <= 0) {
|
|
125103
|
-
console.log(
|
|
125104
|
-
console.log(
|
|
125742
|
+
console.log(import_picocolors58.default.yellow(" The reranker did NOT beat the deterministic baseline \u2014 not saving a model."));
|
|
125743
|
+
console.log(import_picocolors58.default.dim(" Horus stays on its hand-tuned ranking. Re-run as more labels accumulate."));
|
|
125105
125744
|
return 0;
|
|
125106
125745
|
}
|
|
125107
125746
|
try {
|
|
125108
|
-
await (0, import_promises6.mkdir)((0,
|
|
125747
|
+
await (0, import_promises6.mkdir)((0, import_node_path29.join)((0, import_node_os11.homedir)(), ".horus"), { recursive: true });
|
|
125109
125748
|
const { ok: _ok, ...model } = result;
|
|
125110
125749
|
void _ok;
|
|
125111
125750
|
await (0, import_promises6.writeFile)(RERANKER_MODEL_PATH, JSON.stringify(model, null, 2) + "\n", "utf8");
|
|
125112
125751
|
} catch (err2) {
|
|
125113
|
-
console.error(
|
|
125752
|
+
console.error(import_picocolors58.default.red(`Trained, but could not write the model: ${err2.message}`));
|
|
125114
125753
|
return 1;
|
|
125115
125754
|
}
|
|
125116
|
-
console.log(
|
|
125117
|
-
console.log(
|
|
125755
|
+
console.log(import_picocolors58.default.green(` \u2713 Reranker beats baseline by +${pct(delta)} \u2014 saved to ${RERANKER_MODEL_PATH}`));
|
|
125756
|
+
console.log(import_picocolors58.default.dim(" It ships OFF by default. Enable it with `HORUS_RERANK=1 horus investigate \u2026`."));
|
|
125118
125757
|
return 0;
|
|
125119
125758
|
}
|
|
125120
125759
|
|
|
125121
125760
|
// ../../packages/cli/src/lib/report-crash.ts
|
|
125122
125761
|
init_cjs_shims();
|
|
125123
|
-
var
|
|
125762
|
+
var import_picocolors59 = __toESM(require_picocolors(), 1);
|
|
125124
125763
|
function reportCrash(err2, log = console.error) {
|
|
125125
125764
|
log(err2);
|
|
125126
|
-
log(
|
|
125765
|
+
log(import_picocolors59.default.dim("\n Looks like a Horus bug or a missing capability? Report it: horus report"));
|
|
125127
125766
|
}
|
|
125128
125767
|
|
|
125129
125768
|
// ../../packages/cli/src/index.ts
|
|
@@ -125211,6 +125850,16 @@ Examples:
|
|
|
125211
125850
|
});
|
|
125212
125851
|
}
|
|
125213
125852
|
);
|
|
125853
|
+
const secrets = program2.command("secrets").description("Manage encrypted connector credentials (.horus/secrets.local.json) \u2014 HOR-452");
|
|
125854
|
+
secrets.command("status").description("Show the master key source, stored secrets, plaintext in config, and gitignore state").action(() => {
|
|
125855
|
+
process.exitCode = runSecretsStatus();
|
|
125856
|
+
});
|
|
125857
|
+
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) => {
|
|
125858
|
+
process.exitCode = runSecretsMigrate({ dryRun: opts.dryRun });
|
|
125859
|
+
});
|
|
125860
|
+
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) => {
|
|
125861
|
+
process.exitCode = runSecretsKey({ show: opts.show });
|
|
125862
|
+
});
|
|
125214
125863
|
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) => {
|
|
125215
125864
|
process.exitCode = await runStop(opts);
|
|
125216
125865
|
});
|