@merittdev/horus 0.2.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1313 -569
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -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 = "" } of driverInfoList) {
|
|
23439
|
-
if (
|
|
23440
|
-
runtimeInfo = `${runtimeInfo}|${
|
|
23438
|
+
for (const { platform: platform2 = "" } of driverInfoList) {
|
|
23439
|
+
if (platform2.length > 0) {
|
|
23440
|
+
runtimeInfo = `${runtimeInfo}|${platform2}`;
|
|
23441
23441
|
}
|
|
23442
23442
|
}
|
|
23443
23443
|
if (!metadataDocument.ifItFitsItSits("platform", runtimeInfo)) {
|
|
@@ -43447,7 +43447,7 @@ var require_common3 = __commonJS({
|
|
|
43447
43447
|
function setup(env) {
|
|
43448
43448
|
createDebug.debug = createDebug;
|
|
43449
43449
|
createDebug.default = createDebug;
|
|
43450
|
-
createDebug.coerce =
|
|
43450
|
+
createDebug.coerce = coerce3;
|
|
43451
43451
|
createDebug.disable = disable;
|
|
43452
43452
|
createDebug.enable = enable;
|
|
43453
43453
|
createDebug.enabled = enabled;
|
|
@@ -43602,7 +43602,7 @@ var require_common3 = __commonJS({
|
|
|
43602
43602
|
}
|
|
43603
43603
|
return false;
|
|
43604
43604
|
}
|
|
43605
|
-
function
|
|
43605
|
+
function coerce3(val) {
|
|
43606
43606
|
if (val instanceof Error) {
|
|
43607
43607
|
return val.stack || val.message;
|
|
43608
43608
|
}
|
|
@@ -57239,9 +57239,8 @@ init_cjs_shims();
|
|
|
57239
57239
|
|
|
57240
57240
|
// ../../packages/core/src/version.ts
|
|
57241
57241
|
init_cjs_shims();
|
|
57242
|
-
var HORUS_VERSION = true ? "0.
|
|
57243
|
-
var
|
|
57244
|
-
var PINNED_SOURCE_VERSION = PINNED_AXON_VERSION;
|
|
57242
|
+
var HORUS_VERSION = true ? "0.3.0" : "dev";
|
|
57243
|
+
var PINNED_SOURCE_VERSION = "1.1.1";
|
|
57245
57244
|
|
|
57246
57245
|
// ../../packages/core/src/evidence.ts
|
|
57247
57246
|
init_cjs_shims();
|
|
@@ -61672,7 +61671,7 @@ var horusConfigSchema = external_exports.object({
|
|
|
61672
61671
|
projects: external_exports.array(projectSchema).default([]),
|
|
61673
61672
|
axon: external_exports.object({
|
|
61674
61673
|
/** Fail fast if the running Axon is not this version. */
|
|
61675
|
-
pinnedVersion: external_exports.string().default("1.
|
|
61674
|
+
pinnedVersion: external_exports.string().default("1.1.1")
|
|
61676
61675
|
}).default({}),
|
|
61677
61676
|
database: databaseSchema,
|
|
61678
61677
|
models: modelsSchema.default({}),
|
|
@@ -62052,6 +62051,73 @@ packages/core/src/git.ts @horus/core-team @horus/devex-team
|
|
|
62052
62051
|
`.trim();
|
|
62053
62052
|
var FIXTURE_CODEOWNERS_RULES = parseCodeowners(FIXTURE_CODEOWNERS);
|
|
62054
62053
|
|
|
62054
|
+
// ../../packages/core/src/redact.ts
|
|
62055
|
+
init_cjs_shims();
|
|
62056
|
+
var BASE_PATTERNS = [
|
|
62057
|
+
[/(authorization\s*[=:]\s*)(bearer\s+)[^\s,"')]+/gi, "$1$2[REDACTED]"],
|
|
62058
|
+
[/(authorization\s*[=:]\s*)(basic\s+)[^\s,"')]+/gi, "$1$2[REDACTED]"],
|
|
62059
|
+
[
|
|
62060
|
+
/("?(?:password|passwd|secret|token|api[_-]key|apikey|x-api-key)"?\s*[=:]\s*)"?[^"',\s)>]+/gi,
|
|
62061
|
+
"$1[REDACTED]"
|
|
62062
|
+
],
|
|
62063
|
+
[/((?:cookie|set-cookie)\s*[=:]\s*)[^\s"',;>]{4,}/gi, "$1[REDACTED]"],
|
|
62064
|
+
[
|
|
62065
|
+
/((?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis(?:s)?):\/\/)[^:@/\s]+:[^@\s]+@/gi,
|
|
62066
|
+
"$1[REDACTED]@"
|
|
62067
|
+
],
|
|
62068
|
+
[/\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b/g, "[REDACTED-CARD]"]
|
|
62069
|
+
];
|
|
62070
|
+
var EXTENDED_PATTERNS = [
|
|
62071
|
+
// PEM private key blocks (run first — multi-line, highest risk).
|
|
62072
|
+
[
|
|
62073
|
+
/-----BEGIN (?:[A-Z ]+ )?PRIVATE KEY-----[\s\S]*?-----END (?:[A-Z ]+ )?PRIVATE KEY-----/g,
|
|
62074
|
+
"[REDACTED-PRIVATE-KEY]"
|
|
62075
|
+
],
|
|
62076
|
+
// JSON Web Tokens (three base64url segments starting with the `{"` header).
|
|
62077
|
+
[/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g, "[REDACTED-JWT]"],
|
|
62078
|
+
// AWS access key ids.
|
|
62079
|
+
[/\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g, "[REDACTED-AWS-KEY]"],
|
|
62080
|
+
// Google API keys.
|
|
62081
|
+
[/\bAIza[0-9A-Za-z_-]{35}\b/g, "[REDACTED-GCP-KEY]"],
|
|
62082
|
+
// Slack tokens.
|
|
62083
|
+
[/\bxox[baprs]-[0-9A-Za-z-]{10,}\b/g, "[REDACTED-SLACK-TOKEN]"],
|
|
62084
|
+
// GitHub tokens.
|
|
62085
|
+
[/\bgh[pousr]_[0-9A-Za-z]{36,}\b/g, "[REDACTED-GH-TOKEN]"],
|
|
62086
|
+
// Emails.
|
|
62087
|
+
[/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g, "[REDACTED-EMAIL]"],
|
|
62088
|
+
// IPv4 addresses.
|
|
62089
|
+
[/\b(?:\d{1,3}\.){3}\d{1,3}\b/g, "[REDACTED-IP]"]
|
|
62090
|
+
];
|
|
62091
|
+
var RESIDUAL_HIGH_RISK = [
|
|
62092
|
+
/-----BEGIN (?:[A-Z ]+ )?PRIVATE KEY-----/,
|
|
62093
|
+
/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/,
|
|
62094
|
+
/\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/
|
|
62095
|
+
];
|
|
62096
|
+
function apply(patterns, input) {
|
|
62097
|
+
let out = input;
|
|
62098
|
+
for (const [pattern, replacement] of patterns) {
|
|
62099
|
+
out = out.replace(pattern, replacement);
|
|
62100
|
+
}
|
|
62101
|
+
return out;
|
|
62102
|
+
}
|
|
62103
|
+
function redactSecrets(input) {
|
|
62104
|
+
return apply(BASE_PATTERNS, input);
|
|
62105
|
+
}
|
|
62106
|
+
function redactContent(input) {
|
|
62107
|
+
return apply(EXTENDED_PATTERNS, apply(BASE_PATTERNS, input));
|
|
62108
|
+
}
|
|
62109
|
+
function redactOrDrop(input) {
|
|
62110
|
+
try {
|
|
62111
|
+
const value = redactContent(input);
|
|
62112
|
+
if (RESIDUAL_HIGH_RISK.some((p) => p.test(value))) {
|
|
62113
|
+
return { value: null, dropped: true };
|
|
62114
|
+
}
|
|
62115
|
+
return { value, dropped: false };
|
|
62116
|
+
} catch {
|
|
62117
|
+
return { value: null, dropped: true };
|
|
62118
|
+
}
|
|
62119
|
+
}
|
|
62120
|
+
|
|
62055
62121
|
// ../../packages/cli/src/commands/status.ts
|
|
62056
62122
|
init_cjs_shims();
|
|
62057
62123
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
@@ -63135,25 +63201,8 @@ function annotateAgainstBaseline(current, baseline) {
|
|
|
63135
63201
|
current.newSignatures = newSignatures;
|
|
63136
63202
|
return current;
|
|
63137
63203
|
}
|
|
63138
|
-
var REDACTION_PATTERNS = [
|
|
63139
|
-
// Authorization headers (Bearer / Basic / API-key tokens)
|
|
63140
|
-
[/(authorization\s*[=:]\s*)(bearer\s+)[^\s,"')]+/gi, "$1$2[REDACTED]"],
|
|
63141
|
-
[/(authorization\s*[=:]\s*)(basic\s+)[^\s,"')]+/gi, "$1$2[REDACTED]"],
|
|
63142
|
-
// Standalone password/token/secret keys in KV strings, query params, JSON
|
|
63143
|
-
[/("?(?:password|passwd|secret|token|api[_-]key|apikey|x-api-key)"?\s*[=:]\s*)"?[^"',\s)>]+/gi, "$1[REDACTED]"],
|
|
63144
|
-
// Cookie / set-cookie header values
|
|
63145
|
-
[/((?:cookie|set-cookie)\s*[=:]\s*)[^\s"',;>]{4,}/gi, "$1[REDACTED]"],
|
|
63146
|
-
// Database / service connection strings with embedded credentials
|
|
63147
|
-
[/((?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis(?:s)?):\/\/)[^:@/\s]+:[^@\s]+@/gi, "$1[REDACTED]@"],
|
|
63148
|
-
// 16-digit card-number-like sequences (PCIDSS)
|
|
63149
|
-
[/\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b/g, "[REDACTED-CARD]"]
|
|
63150
|
-
];
|
|
63151
63204
|
function redactSensitiveString(s) {
|
|
63152
|
-
|
|
63153
|
-
for (const [pattern, replacement] of REDACTION_PATTERNS) {
|
|
63154
|
-
out = out.replace(pattern, replacement);
|
|
63155
|
-
}
|
|
63156
|
-
return out;
|
|
63205
|
+
return redactSecrets(s);
|
|
63157
63206
|
}
|
|
63158
63207
|
function redactErrorSignature(sig) {
|
|
63159
63208
|
if (sig.sampleMessage === void 0) return sig;
|
|
@@ -66196,7 +66245,7 @@ function sql(strings, ...params) {
|
|
|
66196
66245
|
return new SQL([new StringChunk(str3)]);
|
|
66197
66246
|
}
|
|
66198
66247
|
sql2.raw = raw;
|
|
66199
|
-
function
|
|
66248
|
+
function join13(chunks, separator) {
|
|
66200
66249
|
const result = [];
|
|
66201
66250
|
for (const [i, chunk] of chunks.entries()) {
|
|
66202
66251
|
if (i > 0 && separator !== void 0) {
|
|
@@ -66206,7 +66255,7 @@ function sql(strings, ...params) {
|
|
|
66206
66255
|
}
|
|
66207
66256
|
return new SQL(result);
|
|
66208
66257
|
}
|
|
66209
|
-
sql2.join =
|
|
66258
|
+
sql2.join = join13;
|
|
66210
66259
|
function identifier(value) {
|
|
66211
66260
|
return new Name(value);
|
|
66212
66261
|
}
|
|
@@ -69797,7 +69846,7 @@ var PgSelectQueryBuilderBase = class extends TypedQueryBuilder {
|
|
|
69797
69846
|
return (table, on) => {
|
|
69798
69847
|
const baseTableName = this.tableName;
|
|
69799
69848
|
const tableName = getTableLikeName(table);
|
|
69800
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
69849
|
+
if (typeof tableName === "string" && this.config.joins?.some((join13) => join13.alias === tableName)) {
|
|
69801
69850
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
69802
69851
|
}
|
|
69803
69852
|
if (!this.isPartialSelect) {
|
|
@@ -70809,7 +70858,7 @@ var PgUpdateBase = class extends QueryPromise {
|
|
|
70809
70858
|
createJoin(joinType) {
|
|
70810
70859
|
return (table, on) => {
|
|
70811
70860
|
const tableName = getTableLikeName(table);
|
|
70812
|
-
if (typeof tableName === "string" && this.config.joins.some((
|
|
70861
|
+
if (typeof tableName === "string" && this.config.joins.some((join13) => join13.alias === tableName)) {
|
|
70813
70862
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
70814
70863
|
}
|
|
70815
70864
|
if (typeof on === "function") {
|
|
@@ -70905,10 +70954,10 @@ var PgUpdateBase = class extends QueryPromise {
|
|
|
70905
70954
|
const fromFields = this.getTableLikeFields(this.config.from);
|
|
70906
70955
|
fields[tableName] = fromFields;
|
|
70907
70956
|
}
|
|
70908
|
-
for (const
|
|
70909
|
-
const tableName2 = getTableLikeName(
|
|
70910
|
-
if (typeof tableName2 === "string" && !is(
|
|
70911
|
-
const fromFields = this.getTableLikeFields(
|
|
70957
|
+
for (const join13 of this.config.joins) {
|
|
70958
|
+
const tableName2 = getTableLikeName(join13.table);
|
|
70959
|
+
if (typeof tableName2 === "string" && !is(join13.table, SQL)) {
|
|
70960
|
+
const fromFields = this.getTableLikeFields(join13.table);
|
|
70912
70961
|
fields[tableName2] = fromFields;
|
|
70913
70962
|
}
|
|
70914
70963
|
}
|
|
@@ -77143,7 +77192,12 @@ async function investigate(input, deps) {
|
|
|
77143
77192
|
code.impact(top.id, 2),
|
|
77144
77193
|
code.flowsFor(top.id)
|
|
77145
77194
|
]);
|
|
77146
|
-
|
|
77195
|
+
let edges = [];
|
|
77196
|
+
try {
|
|
77197
|
+
edges = await listQueueEdges(db, { project: input.repo });
|
|
77198
|
+
} catch {
|
|
77199
|
+
edges = [];
|
|
77200
|
+
}
|
|
77147
77201
|
const symbolNames = /* @__PURE__ */ new Set([
|
|
77148
77202
|
top.name,
|
|
77149
77203
|
...ctx.callers.map((s) => s.name),
|
|
@@ -77826,9 +77880,9 @@ async function investigate(input, deps) {
|
|
|
77826
77880
|
const confidence = clamp015(0.5 * evidenceConfidence + 0.5 * seedResolved);
|
|
77827
77881
|
const area = ctx?.community?.name ?? top?.filePath ?? (input.service ?? "runtime evidence");
|
|
77828
77882
|
const topCause = rankedCauses[0];
|
|
77829
|
-
const
|
|
77883
|
+
const banner2 = degradedNoSource ? "Runtime-only (source intelligence unavailable). " : "";
|
|
77830
77884
|
const scope = top ? `resolved to ${label} (${area})` : `over runtime evidence (${area})`;
|
|
77831
|
-
const summary = topCause ? `${
|
|
77885
|
+
const summary = topCause ? `${banner2}Investigation of "${hint}" ${scope}. Top suspected cause: ${topCause.title}.` : `${banner2}Investigation of "${hint}" ${scope}. No dominant suspected cause emerged from the available ${degradedNoSource ? "runtime" : "structural"} evidence.`;
|
|
77832
77886
|
const nextActions = buildNextActions(top, ctx, impact, queueHits, changes, input);
|
|
77833
77887
|
if (degradedNoSource) {
|
|
77834
77888
|
nextActions.unshift(
|
|
@@ -77889,6 +77943,7 @@ async function investigate(input, deps) {
|
|
|
77889
77943
|
report.sourceStatus = buildRuntimeSourceStatus(evidence2, connectorFlags);
|
|
77890
77944
|
const persistedId = await persist(db, input, report);
|
|
77891
77945
|
if (persistedId) report.id = persistedId;
|
|
77946
|
+
report.persisted = persistedId !== null;
|
|
77892
77947
|
if (persistedId !== null) {
|
|
77893
77948
|
const tags = deriveTags(report);
|
|
77894
77949
|
report.similarIncidents = await recallSimilar(db, tags, persistedId, input.repo ?? null);
|
|
@@ -80983,22 +81038,22 @@ function extractQueueGraph(input) {
|
|
|
80983
81038
|
}
|
|
80984
81039
|
}
|
|
80985
81040
|
const producers = [];
|
|
80986
|
-
for (const
|
|
80987
|
-
for (const m of
|
|
81041
|
+
for (const pc47 of input.producerClasses) {
|
|
81042
|
+
for (const m of pc47.content.matchAll(INJECT_QUEUE_RE)) {
|
|
80988
81043
|
const queue = m[1] ?? "";
|
|
80989
|
-
if (queue) producers.push({ queue, symbol:
|
|
81044
|
+
if (queue) producers.push({ queue, symbol: pc47.name, file: pc47.filePath });
|
|
80990
81045
|
}
|
|
80991
|
-
for (const m of
|
|
81046
|
+
for (const m of pc47.content.matchAll(NEW_BULL_RE)) {
|
|
80992
81047
|
if (m[2] !== "Queue") continue;
|
|
80993
81048
|
const queue = resolveArg(m[3] ?? "", constMap);
|
|
80994
81049
|
if (queue) {
|
|
80995
|
-
producers.push({ queue, symbol: (m[1] ??
|
|
81050
|
+
producers.push({ queue, symbol: (m[1] ?? pc47.name) || baseName(pc47.filePath), file: pc47.filePath });
|
|
80996
81051
|
}
|
|
80997
81052
|
}
|
|
80998
|
-
for (const m of
|
|
81053
|
+
for (const m of pc47.content.matchAll(QUEUE_NAME_CONST_RE)) {
|
|
80999
81054
|
const ident = m[1] ?? "";
|
|
81000
81055
|
const queue = m[2] ?? "";
|
|
81001
|
-
if (queue) producers.push({ queue, symbol: ident || baseName(
|
|
81056
|
+
if (queue) producers.push({ queue, symbol: ident || baseName(pc47.filePath), file: pc47.filePath });
|
|
81002
81057
|
}
|
|
81003
81058
|
}
|
|
81004
81059
|
const workers = [];
|
|
@@ -90068,21 +90123,21 @@ var Protocol = class {
|
|
|
90068
90123
|
* the error appropriately (e.g., by failing the task, logging, etc.). The Protocol layer
|
|
90069
90124
|
* simply propagates the error.
|
|
90070
90125
|
*/
|
|
90071
|
-
async _enqueueTaskMessage(taskId, message,
|
|
90126
|
+
async _enqueueTaskMessage(taskId, message, sessionId2) {
|
|
90072
90127
|
if (!this._taskStore || !this._taskMessageQueue) {
|
|
90073
90128
|
throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");
|
|
90074
90129
|
}
|
|
90075
90130
|
const maxQueueSize = this._options?.maxTaskQueueSize;
|
|
90076
|
-
await this._taskMessageQueue.enqueue(taskId, message,
|
|
90131
|
+
await this._taskMessageQueue.enqueue(taskId, message, sessionId2, maxQueueSize);
|
|
90077
90132
|
}
|
|
90078
90133
|
/**
|
|
90079
90134
|
* Clears the message queue for a task and rejects any pending request resolvers.
|
|
90080
90135
|
* @param taskId The task ID whose queue should be cleared
|
|
90081
90136
|
* @param sessionId Optional session ID for binding the operation to a specific session
|
|
90082
90137
|
*/
|
|
90083
|
-
async _clearTaskQueue(taskId,
|
|
90138
|
+
async _clearTaskQueue(taskId, sessionId2) {
|
|
90084
90139
|
if (this._taskMessageQueue) {
|
|
90085
|
-
const messages2 = await this._taskMessageQueue.dequeueAll(taskId,
|
|
90140
|
+
const messages2 = await this._taskMessageQueue.dequeueAll(taskId, sessionId2);
|
|
90086
90141
|
for (const message of messages2) {
|
|
90087
90142
|
if (message.type === "request" && isJSONRPCRequest(message.message)) {
|
|
90088
90143
|
const requestId = message.message.id;
|
|
@@ -90125,7 +90180,7 @@ var Protocol = class {
|
|
|
90125
90180
|
}, { once: true });
|
|
90126
90181
|
});
|
|
90127
90182
|
}
|
|
90128
|
-
requestTaskStore(request,
|
|
90183
|
+
requestTaskStore(request, sessionId2) {
|
|
90129
90184
|
const taskStore = this._taskStore;
|
|
90130
90185
|
if (!taskStore) {
|
|
90131
90186
|
throw new Error("No task store configured");
|
|
@@ -90138,18 +90193,18 @@ var Protocol = class {
|
|
|
90138
90193
|
return await taskStore.createTask(taskParams, request.id, {
|
|
90139
90194
|
method: request.method,
|
|
90140
90195
|
params: request.params
|
|
90141
|
-
},
|
|
90196
|
+
}, sessionId2);
|
|
90142
90197
|
},
|
|
90143
90198
|
getTask: async (taskId) => {
|
|
90144
|
-
const task = await taskStore.getTask(taskId,
|
|
90199
|
+
const task = await taskStore.getTask(taskId, sessionId2);
|
|
90145
90200
|
if (!task) {
|
|
90146
90201
|
throw new McpError(ErrorCode.InvalidParams, "Failed to retrieve task: Task not found");
|
|
90147
90202
|
}
|
|
90148
90203
|
return task;
|
|
90149
90204
|
},
|
|
90150
90205
|
storeTaskResult: async (taskId, status, result) => {
|
|
90151
|
-
await taskStore.storeTaskResult(taskId, status, result,
|
|
90152
|
-
const task = await taskStore.getTask(taskId,
|
|
90206
|
+
await taskStore.storeTaskResult(taskId, status, result, sessionId2);
|
|
90207
|
+
const task = await taskStore.getTask(taskId, sessionId2);
|
|
90153
90208
|
if (task) {
|
|
90154
90209
|
const notification = TaskStatusNotificationSchema.parse({
|
|
90155
90210
|
method: "notifications/tasks/status",
|
|
@@ -90162,18 +90217,18 @@ var Protocol = class {
|
|
|
90162
90217
|
}
|
|
90163
90218
|
},
|
|
90164
90219
|
getTaskResult: (taskId) => {
|
|
90165
|
-
return taskStore.getTaskResult(taskId,
|
|
90220
|
+
return taskStore.getTaskResult(taskId, sessionId2);
|
|
90166
90221
|
},
|
|
90167
90222
|
updateTaskStatus: async (taskId, status, statusMessage) => {
|
|
90168
|
-
const task = await taskStore.getTask(taskId,
|
|
90223
|
+
const task = await taskStore.getTask(taskId, sessionId2);
|
|
90169
90224
|
if (!task) {
|
|
90170
90225
|
throw new McpError(ErrorCode.InvalidParams, `Task "${taskId}" not found - it may have been cleaned up`);
|
|
90171
90226
|
}
|
|
90172
90227
|
if (isTerminal(task.status)) {
|
|
90173
90228
|
throw new McpError(ErrorCode.InvalidParams, `Cannot update task "${taskId}" from terminal status "${task.status}" to "${status}". Terminal states (completed, failed, cancelled) cannot transition to other states.`);
|
|
90174
90229
|
}
|
|
90175
|
-
await taskStore.updateTaskStatus(taskId, status, statusMessage,
|
|
90176
|
-
const updatedTask = await taskStore.getTask(taskId,
|
|
90230
|
+
await taskStore.updateTaskStatus(taskId, status, statusMessage, sessionId2);
|
|
90231
|
+
const updatedTask = await taskStore.getTask(taskId, sessionId2);
|
|
90177
90232
|
if (updatedTask) {
|
|
90178
90233
|
const notification = TaskStatusNotificationSchema.parse({
|
|
90179
90234
|
method: "notifications/tasks/status",
|
|
@@ -90186,7 +90241,7 @@ var Protocol = class {
|
|
|
90186
90241
|
}
|
|
90187
90242
|
},
|
|
90188
90243
|
listTasks: (cursor) => {
|
|
90189
|
-
return taskStore.listTasks(cursor,
|
|
90244
|
+
return taskStore.listTasks(cursor, sessionId2);
|
|
90190
90245
|
}
|
|
90191
90246
|
};
|
|
90192
90247
|
}
|
|
@@ -90540,8 +90595,8 @@ var Server = class extends Protocol {
|
|
|
90540
90595
|
this._serverInfo = _serverInfo;
|
|
90541
90596
|
this._loggingLevels = /* @__PURE__ */ new Map();
|
|
90542
90597
|
this.LOG_LEVEL_SEVERITY = new Map(LoggingLevelSchema.options.map((level, index2) => [level, index2]));
|
|
90543
|
-
this.isMessageIgnored = (level,
|
|
90544
|
-
const currentLevel = this._loggingLevels.get(
|
|
90598
|
+
this.isMessageIgnored = (level, sessionId2) => {
|
|
90599
|
+
const currentLevel = this._loggingLevels.get(sessionId2);
|
|
90545
90600
|
return currentLevel ? this.LOG_LEVEL_SEVERITY.get(level) < this.LOG_LEVEL_SEVERITY.get(currentLevel) : false;
|
|
90546
90601
|
};
|
|
90547
90602
|
this._capabilities = options?.capabilities ?? {};
|
|
@@ -90884,9 +90939,9 @@ var Server = class extends Protocol {
|
|
|
90884
90939
|
* @param params
|
|
90885
90940
|
* @param sessionId optional for stateless and backward compatibility
|
|
90886
90941
|
*/
|
|
90887
|
-
async sendLoggingMessage(params,
|
|
90942
|
+
async sendLoggingMessage(params, sessionId2) {
|
|
90888
90943
|
if (this._capabilities.logging) {
|
|
90889
|
-
if (!this.isMessageIgnored(params.level,
|
|
90944
|
+
if (!this.isMessageIgnored(params.level, sessionId2)) {
|
|
90890
90945
|
return this.notification({ method: "notifications/message", params });
|
|
90891
90946
|
}
|
|
90892
90947
|
}
|
|
@@ -91691,8 +91746,8 @@ var McpServer = class {
|
|
|
91691
91746
|
* @param params
|
|
91692
91747
|
* @param sessionId optional for stateless and backward compatibility
|
|
91693
91748
|
*/
|
|
91694
|
-
async sendLoggingMessage(params,
|
|
91695
|
-
return this.server.sendLoggingMessage(params,
|
|
91749
|
+
async sendLoggingMessage(params, sessionId2) {
|
|
91750
|
+
return this.server.sendLoggingMessage(params, sessionId2);
|
|
91696
91751
|
}
|
|
91697
91752
|
/**
|
|
91698
91753
|
* Sends a resource list changed event to the client, if connected.
|
|
@@ -93743,7 +93798,7 @@ function formatAge(ms) {
|
|
|
93743
93798
|
|
|
93744
93799
|
// ../../packages/cli/src/commands/investigate.ts
|
|
93745
93800
|
init_cjs_shims();
|
|
93746
|
-
var
|
|
93801
|
+
var import_picocolors9 = __toESM(require_picocolors(), 1);
|
|
93747
93802
|
|
|
93748
93803
|
// ../../packages/cli/src/lib/cloud/investigation-sync.ts
|
|
93749
93804
|
init_cjs_shims();
|
|
@@ -93820,6 +93875,345 @@ async function listCloudInvestigations(client, cfg) {
|
|
|
93820
93875
|
return result.investigations;
|
|
93821
93876
|
}
|
|
93822
93877
|
|
|
93878
|
+
// ../../packages/cli/src/lib/telemetry/client.ts
|
|
93879
|
+
init_cjs_shims();
|
|
93880
|
+
var import_node_crypto6 = require("crypto");
|
|
93881
|
+
var import_node_os3 = require("os");
|
|
93882
|
+
|
|
93883
|
+
// ../../packages/cli/src/lib/telemetry/consent.ts
|
|
93884
|
+
init_cjs_shims();
|
|
93885
|
+
|
|
93886
|
+
// ../../packages/cli/src/lib/telemetry/store.ts
|
|
93887
|
+
init_cjs_shims();
|
|
93888
|
+
var import_node_fs13 = require("fs");
|
|
93889
|
+
var import_node_crypto5 = require("crypto");
|
|
93890
|
+
|
|
93891
|
+
// ../../packages/cli/src/lib/telemetry/paths.ts
|
|
93892
|
+
init_cjs_shims();
|
|
93893
|
+
var import_node_path14 = require("path");
|
|
93894
|
+
var TELEMETRY_FILE = "telemetry.json";
|
|
93895
|
+
var TELEMETRY_QUEUE_DIR = "telemetry-queue";
|
|
93896
|
+
function telemetryPath() {
|
|
93897
|
+
return (0, import_node_path14.join)(horusHome(), TELEMETRY_FILE);
|
|
93898
|
+
}
|
|
93899
|
+
function telemetryQueueDir() {
|
|
93900
|
+
return (0, import_node_path14.join)(horusHome(), TELEMETRY_QUEUE_DIR);
|
|
93901
|
+
}
|
|
93902
|
+
|
|
93903
|
+
// ../../packages/cli/src/lib/telemetry/store.ts
|
|
93904
|
+
var TELEMETRY_SCHEMA_VERSION = 1;
|
|
93905
|
+
function nowIso() {
|
|
93906
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
93907
|
+
}
|
|
93908
|
+
function defaultTelemetryState(installId = (0, import_node_crypto5.randomUUID)()) {
|
|
93909
|
+
const now = nowIso();
|
|
93910
|
+
return {
|
|
93911
|
+
schemaVersion: TELEMETRY_SCHEMA_VERSION,
|
|
93912
|
+
installId,
|
|
93913
|
+
tierA: { enabled: true, noticeShownAt: null },
|
|
93914
|
+
tierB: { enabled: false, enabledAt: null },
|
|
93915
|
+
createdAt: now,
|
|
93916
|
+
updatedAt: now
|
|
93917
|
+
};
|
|
93918
|
+
}
|
|
93919
|
+
function coerce2(raw) {
|
|
93920
|
+
if (!raw || typeof raw !== "object") return null;
|
|
93921
|
+
const r = raw;
|
|
93922
|
+
if (typeof r.installId !== "string" || r.installId.length === 0) return null;
|
|
93923
|
+
const tierA = r.tierA ?? {};
|
|
93924
|
+
const tierB = r.tierB ?? {};
|
|
93925
|
+
return {
|
|
93926
|
+
schemaVersion: typeof r.schemaVersion === "number" ? r.schemaVersion : TELEMETRY_SCHEMA_VERSION,
|
|
93927
|
+
installId: r.installId,
|
|
93928
|
+
tierA: {
|
|
93929
|
+
enabled: typeof tierA.enabled === "boolean" ? tierA.enabled : true,
|
|
93930
|
+
noticeShownAt: typeof tierA.noticeShownAt === "string" ? tierA.noticeShownAt : null
|
|
93931
|
+
},
|
|
93932
|
+
tierB: {
|
|
93933
|
+
enabled: typeof tierB.enabled === "boolean" ? tierB.enabled : false,
|
|
93934
|
+
enabledAt: typeof tierB.enabledAt === "string" ? tierB.enabledAt : null
|
|
93935
|
+
},
|
|
93936
|
+
createdAt: typeof r.createdAt === "string" ? r.createdAt : nowIso(),
|
|
93937
|
+
updatedAt: typeof r.updatedAt === "string" ? r.updatedAt : nowIso()
|
|
93938
|
+
};
|
|
93939
|
+
}
|
|
93940
|
+
function readTelemetryState() {
|
|
93941
|
+
const p = telemetryPath();
|
|
93942
|
+
if (!(0, import_node_fs13.existsSync)(p)) return null;
|
|
93943
|
+
try {
|
|
93944
|
+
return coerce2(JSON.parse((0, import_node_fs13.readFileSync)(p, "utf8")));
|
|
93945
|
+
} catch {
|
|
93946
|
+
return null;
|
|
93947
|
+
}
|
|
93948
|
+
}
|
|
93949
|
+
function writeTelemetryState(state) {
|
|
93950
|
+
(0, import_node_fs13.mkdirSync)(horusHome(), { recursive: true });
|
|
93951
|
+
const p = telemetryPath();
|
|
93952
|
+
const tmp = `${p}.${process.pid}.tmp`;
|
|
93953
|
+
(0, import_node_fs13.writeFileSync)(tmp, JSON.stringify(state, null, 2) + "\n", { mode: 384 });
|
|
93954
|
+
try {
|
|
93955
|
+
(0, import_node_fs13.renameSync)(tmp, p);
|
|
93956
|
+
} catch (err) {
|
|
93957
|
+
try {
|
|
93958
|
+
(0, import_node_fs13.rmSync)(tmp);
|
|
93959
|
+
} catch {
|
|
93960
|
+
}
|
|
93961
|
+
throw err;
|
|
93962
|
+
}
|
|
93963
|
+
try {
|
|
93964
|
+
(0, import_node_fs13.chmodSync)(p, 384);
|
|
93965
|
+
} catch {
|
|
93966
|
+
}
|
|
93967
|
+
}
|
|
93968
|
+
function loadOrInitTelemetryState() {
|
|
93969
|
+
const existing = readTelemetryState();
|
|
93970
|
+
if (existing) return existing;
|
|
93971
|
+
const created = defaultTelemetryState();
|
|
93972
|
+
writeTelemetryState(created);
|
|
93973
|
+
return created;
|
|
93974
|
+
}
|
|
93975
|
+
function updateTelemetryState(mutate) {
|
|
93976
|
+
const state = loadOrInitTelemetryState();
|
|
93977
|
+
mutate(state);
|
|
93978
|
+
state.updatedAt = nowIso();
|
|
93979
|
+
writeTelemetryState(state);
|
|
93980
|
+
return state;
|
|
93981
|
+
}
|
|
93982
|
+
function deleteTelemetryState() {
|
|
93983
|
+
const p = telemetryPath();
|
|
93984
|
+
if ((0, import_node_fs13.existsSync)(p)) (0, import_node_fs13.rmSync)(p);
|
|
93985
|
+
}
|
|
93986
|
+
|
|
93987
|
+
// ../../packages/cli/src/lib/telemetry/consent.ts
|
|
93988
|
+
var OFF_VALUES = /* @__PURE__ */ new Set(["0", "false", "off", "no", "disable", "disabled"]);
|
|
93989
|
+
var ON_VALUES = /* @__PURE__ */ new Set(["1", "true", "on", "yes", "enable", "enabled", "all"]);
|
|
93990
|
+
var CI_ENV_VARS = [
|
|
93991
|
+
"CI",
|
|
93992
|
+
"CONTINUOUS_INTEGRATION",
|
|
93993
|
+
"GITHUB_ACTIONS",
|
|
93994
|
+
"GITLAB_CI",
|
|
93995
|
+
"BUILDKITE",
|
|
93996
|
+
"CIRCLECI",
|
|
93997
|
+
"TRAVIS",
|
|
93998
|
+
"JENKINS_URL",
|
|
93999
|
+
"TEAMCITY_VERSION"
|
|
94000
|
+
];
|
|
94001
|
+
function doNotTrack(env) {
|
|
94002
|
+
const v = env.DO_NOT_TRACK;
|
|
94003
|
+
if (v == null || v === "") return false;
|
|
94004
|
+
return !OFF_VALUES.has(v.trim().toLowerCase());
|
|
94005
|
+
}
|
|
94006
|
+
function parseEnvFlag(value) {
|
|
94007
|
+
if (value == null || value === "") return void 0;
|
|
94008
|
+
const v = value.trim().toLowerCase();
|
|
94009
|
+
if (OFF_VALUES.has(v)) return "off";
|
|
94010
|
+
if (ON_VALUES.has(v)) return "on";
|
|
94011
|
+
return void 0;
|
|
94012
|
+
}
|
|
94013
|
+
function isCI(env = process.env) {
|
|
94014
|
+
return CI_ENV_VARS.some((key) => {
|
|
94015
|
+
const v = env[key];
|
|
94016
|
+
return v != null && v !== "" && !OFF_VALUES.has(v.trim().toLowerCase());
|
|
94017
|
+
});
|
|
94018
|
+
}
|
|
94019
|
+
function off(source, reason) {
|
|
94020
|
+
return { tierA: false, tierB: false, forcedOff: source === "env", source, reason };
|
|
94021
|
+
}
|
|
94022
|
+
function resolveConsent(opts = {}) {
|
|
94023
|
+
const env = opts.env ?? process.env;
|
|
94024
|
+
if (doNotTrack(env)) return off("env", "DO_NOT_TRACK is set");
|
|
94025
|
+
const envFlag = parseEnvFlag(env.HORUS_TELEMETRY);
|
|
94026
|
+
if (envFlag === "off") return off("env", "HORUS_TELEMETRY disables telemetry");
|
|
94027
|
+
const state = opts.state !== void 0 ? opts.state : readTelemetryState();
|
|
94028
|
+
const storedTierA = state?.tierA.enabled ?? true;
|
|
94029
|
+
const storedTierB = state?.tierB.enabled ?? false;
|
|
94030
|
+
if (isCI(env) && envFlag !== "on") {
|
|
94031
|
+
return {
|
|
94032
|
+
tierA: false,
|
|
94033
|
+
tierB: false,
|
|
94034
|
+
forcedOff: false,
|
|
94035
|
+
source: "ci",
|
|
94036
|
+
reason: "CI environment detected \u2014 telemetry off by default"
|
|
94037
|
+
};
|
|
94038
|
+
}
|
|
94039
|
+
if (envFlag === "on") {
|
|
94040
|
+
return {
|
|
94041
|
+
tierA: true,
|
|
94042
|
+
tierB: storedTierB,
|
|
94043
|
+
forcedOff: false,
|
|
94044
|
+
source: "env",
|
|
94045
|
+
reason: "HORUS_TELEMETRY enables usage metadata"
|
|
94046
|
+
};
|
|
94047
|
+
}
|
|
94048
|
+
return {
|
|
94049
|
+
tierA: storedTierA,
|
|
94050
|
+
tierB: storedTierB,
|
|
94051
|
+
forcedOff: false,
|
|
94052
|
+
source: state ? "state" : "default",
|
|
94053
|
+
reason: state ? "from ~/.horus/telemetry.json" : "default settings (no saved preference)"
|
|
94054
|
+
};
|
|
94055
|
+
}
|
|
94056
|
+
function isContentSharingEnabled(env = process.env) {
|
|
94057
|
+
return resolveConsent({ env }).tierB;
|
|
94058
|
+
}
|
|
94059
|
+
|
|
94060
|
+
// ../../packages/cli/src/lib/telemetry/spool.ts
|
|
94061
|
+
init_cjs_shims();
|
|
94062
|
+
var import_node_fs14 = require("fs");
|
|
94063
|
+
var import_node_path15 = require("path");
|
|
94064
|
+
var SPOOL_FILE = "events.jsonl";
|
|
94065
|
+
var MAX_SPOOL_BYTES = 256 * 1024;
|
|
94066
|
+
function spoolFilePath() {
|
|
94067
|
+
return (0, import_node_path15.join)(telemetryQueueDir(), SPOOL_FILE);
|
|
94068
|
+
}
|
|
94069
|
+
function spoolEvent(event) {
|
|
94070
|
+
try {
|
|
94071
|
+
(0, import_node_fs14.mkdirSync)(telemetryQueueDir(), { recursive: true });
|
|
94072
|
+
const file = spoolFilePath();
|
|
94073
|
+
let size2 = 0;
|
|
94074
|
+
try {
|
|
94075
|
+
size2 = (0, import_node_fs14.statSync)(file).size;
|
|
94076
|
+
} catch {
|
|
94077
|
+
}
|
|
94078
|
+
if (size2 >= MAX_SPOOL_BYTES) return;
|
|
94079
|
+
(0, import_node_fs14.appendFileSync)(file, JSON.stringify(event) + "\n", { mode: 384 });
|
|
94080
|
+
} catch {
|
|
94081
|
+
}
|
|
94082
|
+
}
|
|
94083
|
+
function readSpooledEvents() {
|
|
94084
|
+
try {
|
|
94085
|
+
const file = spoolFilePath();
|
|
94086
|
+
if (!(0, import_node_fs14.existsSync)(file)) return [];
|
|
94087
|
+
return (0, import_node_fs14.readFileSync)(file, "utf8").split("\n").filter((line2) => line2.trim().length > 0).map((line2) => {
|
|
94088
|
+
try {
|
|
94089
|
+
return JSON.parse(line2);
|
|
94090
|
+
} catch {
|
|
94091
|
+
return null;
|
|
94092
|
+
}
|
|
94093
|
+
}).filter((e) => e !== null);
|
|
94094
|
+
} catch {
|
|
94095
|
+
return [];
|
|
94096
|
+
}
|
|
94097
|
+
}
|
|
94098
|
+
function clearSpool() {
|
|
94099
|
+
try {
|
|
94100
|
+
const file = spoolFilePath();
|
|
94101
|
+
if ((0, import_node_fs14.existsSync)(file)) (0, import_node_fs14.rmSync)(file);
|
|
94102
|
+
} catch {
|
|
94103
|
+
}
|
|
94104
|
+
}
|
|
94105
|
+
|
|
94106
|
+
// ../../packages/cli/src/lib/telemetry/events.ts
|
|
94107
|
+
init_cjs_shims();
|
|
94108
|
+
var TELEMETRY_EVENT_SCHEMA_VERSION = 1;
|
|
94109
|
+
var TIER_B_EVENT_TYPES = /* @__PURE__ */ new Set(["investigation.content"]);
|
|
94110
|
+
function tierForEventType(type) {
|
|
94111
|
+
return TIER_B_EVENT_TYPES.has(type) ? "B" : "A";
|
|
94112
|
+
}
|
|
94113
|
+
function extractFlagNames(argv) {
|
|
94114
|
+
const names = /* @__PURE__ */ new Set();
|
|
94115
|
+
for (const token of argv.slice(2)) {
|
|
94116
|
+
if (token.startsWith("--") && token.length > 2) {
|
|
94117
|
+
const name = token.slice(2).split("=")[0];
|
|
94118
|
+
if (name) names.add(name);
|
|
94119
|
+
}
|
|
94120
|
+
}
|
|
94121
|
+
return [...names];
|
|
94122
|
+
}
|
|
94123
|
+
|
|
94124
|
+
// ../../packages/cli/src/lib/telemetry/client.ts
|
|
94125
|
+
var sessionId = null;
|
|
94126
|
+
function getSessionId() {
|
|
94127
|
+
if (!sessionId) sessionId = (0, import_node_crypto6.randomUUID)();
|
|
94128
|
+
return sessionId;
|
|
94129
|
+
}
|
|
94130
|
+
function track(input) {
|
|
94131
|
+
try {
|
|
94132
|
+
const state = readTelemetryState();
|
|
94133
|
+
if (!state) return;
|
|
94134
|
+
const tier = tierForEventType(input.type);
|
|
94135
|
+
const decision = resolveConsent({ state });
|
|
94136
|
+
if (tier === "A" ? !decision.tierA : !decision.tierB) return;
|
|
94137
|
+
const event = {
|
|
94138
|
+
schemaVersion: TELEMETRY_EVENT_SCHEMA_VERSION,
|
|
94139
|
+
tier,
|
|
94140
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
94141
|
+
installId: state.installId,
|
|
94142
|
+
sessionId: getSessionId(),
|
|
94143
|
+
cliVersion: HORUS_VERSION,
|
|
94144
|
+
os: (0, import_node_os3.platform)(),
|
|
94145
|
+
arch: (0, import_node_os3.arch)(),
|
|
94146
|
+
...input
|
|
94147
|
+
};
|
|
94148
|
+
spoolEvent(event);
|
|
94149
|
+
} catch {
|
|
94150
|
+
}
|
|
94151
|
+
}
|
|
94152
|
+
|
|
94153
|
+
// ../../packages/cli/src/lib/telemetry/feedback.ts
|
|
94154
|
+
init_cjs_shims();
|
|
94155
|
+
var import_promises = require("readline/promises");
|
|
94156
|
+
var import_picocolors8 = __toESM(require_picocolors(), 1);
|
|
94157
|
+
var MANUAL_MINUTES = {
|
|
94158
|
+
"1": 5,
|
|
94159
|
+
// < 5 min
|
|
94160
|
+
"2": 30,
|
|
94161
|
+
// ~30 min
|
|
94162
|
+
"3": 120,
|
|
94163
|
+
// ~2 h
|
|
94164
|
+
"4": 480,
|
|
94165
|
+
// half-day+
|
|
94166
|
+
"5": null
|
|
94167
|
+
// unsure
|
|
94168
|
+
};
|
|
94169
|
+
function parseResolved(raw) {
|
|
94170
|
+
const v = raw.trim().toLowerCase();
|
|
94171
|
+
if (v.startsWith("y")) return "yes";
|
|
94172
|
+
if (v.startsWith("p")) return "partly";
|
|
94173
|
+
if (v.startsWith("n")) return "no";
|
|
94174
|
+
return null;
|
|
94175
|
+
}
|
|
94176
|
+
function parseManualEstimate(raw) {
|
|
94177
|
+
return MANUAL_MINUTES[raw.trim()] ?? null;
|
|
94178
|
+
}
|
|
94179
|
+
function submitFeedback(input) {
|
|
94180
|
+
track({ type: "feedback.submitted", ...input });
|
|
94181
|
+
}
|
|
94182
|
+
async function runFeedbackPrompt(investigationId, horusSeconds) {
|
|
94183
|
+
const rl = (0, import_promises.createInterface)({ input: process.stdin, output: process.stdout });
|
|
94184
|
+
try {
|
|
94185
|
+
console.log(import_picocolors8.default.dim("\nQuick feedback to improve Horus (press Enter to skip):"));
|
|
94186
|
+
const a1 = await rl.question(
|
|
94187
|
+
import_picocolors8.default.bold(" Did this point you at the cause? ") + import_picocolors8.default.dim("[y / partly / n] ")
|
|
94188
|
+
);
|
|
94189
|
+
if (a1.trim() === "") return false;
|
|
94190
|
+
const a2 = await rl.question(
|
|
94191
|
+
import_picocolors8.default.bold(" Manually, finding this would have taken? ") + import_picocolors8.default.dim("[1:<5m 2:~30m 3:~2h 4:half-day+ 5:unsure] ")
|
|
94192
|
+
);
|
|
94193
|
+
submitFeedback({
|
|
94194
|
+
investigationId,
|
|
94195
|
+
resolved: parseResolved(a1),
|
|
94196
|
+
manualEstimateMinutes: parseManualEstimate(a2),
|
|
94197
|
+
horusSeconds
|
|
94198
|
+
});
|
|
94199
|
+
console.log(import_picocolors8.default.dim(" Thanks \u2014 recorded."));
|
|
94200
|
+
return true;
|
|
94201
|
+
} finally {
|
|
94202
|
+
rl.close();
|
|
94203
|
+
}
|
|
94204
|
+
}
|
|
94205
|
+
async function maybePromptFeedback(opts) {
|
|
94206
|
+
try {
|
|
94207
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) return;
|
|
94208
|
+
if (!resolveConsent().tierA) return;
|
|
94209
|
+
const rate = opts.sampleRate ?? 0.25;
|
|
94210
|
+
const rand = (opts.random ?? Math.random)();
|
|
94211
|
+
if (rand > rate) return;
|
|
94212
|
+
await runFeedbackPrompt(opts.investigationId, opts.horusSeconds ?? null);
|
|
94213
|
+
} catch {
|
|
94214
|
+
}
|
|
94215
|
+
}
|
|
94216
|
+
|
|
93823
94217
|
// ../../packages/cli/src/lib/ensure-host.ts
|
|
93824
94218
|
init_cjs_shims();
|
|
93825
94219
|
function parseHostPort(hostUrl) {
|
|
@@ -93912,37 +94306,37 @@ function renderStoredAIJudgment(judgment, write = (l) => console.log(l)) {
|
|
|
93912
94306
|
const sep = "\u2500".repeat(60);
|
|
93913
94307
|
write(`
|
|
93914
94308
|
${sep}`);
|
|
93915
|
-
write(
|
|
94309
|
+
write(import_picocolors9.default.bold("AI Judgment") + import_picocolors9.default.dim(` (confidence: ${(judgment.confidence * 100).toFixed(0)}%, provider: ${judgment.provider})`));
|
|
93916
94310
|
write(sep);
|
|
93917
94311
|
if (judgment.hypothesisJudgments && judgment.hypothesisJudgments.length > 0) {
|
|
93918
|
-
write(
|
|
94312
|
+
write(import_picocolors9.default.bold("Hypothesis verdicts:"));
|
|
93919
94313
|
for (const j of judgment.hypothesisJudgments) {
|
|
93920
|
-
const verdictColor = j.verdict === "supported" ?
|
|
93921
|
-
write(` ${verdictColor(`[${j.verdict}]`)} ${j.category}` +
|
|
93922
|
-
write(
|
|
94314
|
+
const verdictColor = j.verdict === "supported" ? import_picocolors9.default.green : j.verdict === "weakened" ? import_picocolors9.default.yellow : j.verdict === "eliminated" ? import_picocolors9.default.red : import_picocolors9.default.dim;
|
|
94315
|
+
write(` ${verdictColor(`[${j.verdict}]`)} ${j.category}` + import_picocolors9.default.dim(` (${(j.confidence * 100).toFixed(0)}%)`));
|
|
94316
|
+
write(import_picocolors9.default.dim(` ${j.rationale}`));
|
|
93923
94317
|
}
|
|
93924
94318
|
write("");
|
|
93925
94319
|
}
|
|
93926
94320
|
if (judgment.rootCauseAssessment) {
|
|
93927
94321
|
const rca = judgment.rootCauseAssessment;
|
|
93928
|
-
const uncertaintyColor = rca.uncertainty === "low" ?
|
|
93929
|
-
write(
|
|
94322
|
+
const uncertaintyColor = rca.uncertainty === "low" ? import_picocolors9.default.green : rca.uncertainty === "medium" ? import_picocolors9.default.yellow : import_picocolors9.default.red;
|
|
94323
|
+
write(import_picocolors9.default.bold("Root cause assessment:") + import_picocolors9.default.dim(` uncertainty: ${uncertaintyColor(rca.uncertainty)}`));
|
|
93930
94324
|
write(rca.summary);
|
|
93931
94325
|
if (rca.citedEvidenceIds.length > 0) {
|
|
93932
|
-
write(
|
|
94326
|
+
write(import_picocolors9.default.dim(` Cited: ${rca.citedEvidenceIds.join(", ")}`));
|
|
93933
94327
|
}
|
|
93934
94328
|
write("");
|
|
93935
94329
|
}
|
|
93936
|
-
write(
|
|
93937
|
-
write(
|
|
94330
|
+
write(import_picocolors9.default.bold("What:") + " " + judgment.what);
|
|
94331
|
+
write(import_picocolors9.default.bold("Why:") + " " + judgment.why);
|
|
93938
94332
|
if (judgment.whereNext.length > 0) {
|
|
93939
|
-
write(
|
|
94333
|
+
write(import_picocolors9.default.bold("Next steps:"));
|
|
93940
94334
|
for (const step of judgment.whereNext) {
|
|
93941
94335
|
write(` \u2022 ${step}`);
|
|
93942
94336
|
}
|
|
93943
94337
|
}
|
|
93944
94338
|
if (judgment.citations.length > 0) {
|
|
93945
|
-
write(
|
|
94339
|
+
write(import_picocolors9.default.dim(`
|
|
93946
94340
|
Cited evidence: ${judgment.citations.map((c) => c.evidenceId).join(", ")}`));
|
|
93947
94341
|
}
|
|
93948
94342
|
}
|
|
@@ -93960,6 +94354,7 @@ function classifyAIFailure(firstError) {
|
|
|
93960
94354
|
return firstError;
|
|
93961
94355
|
}
|
|
93962
94356
|
async function runInvestigate(hint, opts) {
|
|
94357
|
+
const startedAtMs = Date.now();
|
|
93963
94358
|
try {
|
|
93964
94359
|
const config2 = await loadConfig(opts.config, { name: opts.name });
|
|
93965
94360
|
const projectName = opts.project ?? opts.repo;
|
|
@@ -93967,7 +94362,7 @@ async function runInvestigate(hint, opts) {
|
|
|
93967
94362
|
try {
|
|
93968
94363
|
renv = resolveEnvironment(config2, { project: projectName, env: opts.env });
|
|
93969
94364
|
} catch (err) {
|
|
93970
|
-
console.error(
|
|
94365
|
+
console.error(import_picocolors9.default.red(err.message));
|
|
93971
94366
|
return 1;
|
|
93972
94367
|
}
|
|
93973
94368
|
const repoRoot = repoRootOrCwd(renv.path);
|
|
@@ -93976,16 +94371,15 @@ async function runInvestigate(hint, opts) {
|
|
|
93976
94371
|
const cloudSession = cloudActive ? authedClient() : null;
|
|
93977
94372
|
if (cloudActive && !cloudSession) {
|
|
93978
94373
|
console.error(
|
|
93979
|
-
|
|
93980
|
-
`This repo is linked to Horus Cloud but you are not logged in. Run ${
|
|
94374
|
+
import_picocolors9.default.yellow(
|
|
94375
|
+
`This repo is linked to Horus Cloud but you are not logged in \u2014 running locally only. Run ${import_picocolors9.default.bold("horus login")} to also sync results to the cloud.`
|
|
93981
94376
|
)
|
|
93982
94377
|
);
|
|
93983
|
-
return 1;
|
|
93984
94378
|
}
|
|
93985
94379
|
const code = codeForEnv(renv);
|
|
93986
94380
|
if (!code) {
|
|
93987
94381
|
console.error(
|
|
93988
|
-
|
|
94382
|
+
import_picocolors9.default.red(
|
|
93989
94383
|
`No source-intelligence connector configured for project "${renv.project}" / env "${renv.env}".`
|
|
93990
94384
|
)
|
|
93991
94385
|
);
|
|
@@ -93995,21 +94389,21 @@ async function runInvestigate(hint, opts) {
|
|
|
93995
94389
|
let health = await code.health();
|
|
93996
94390
|
if (!health.ok && sourceUrl) {
|
|
93997
94391
|
console.error(
|
|
93998
|
-
|
|
94392
|
+
import_picocolors9.default.yellow(`Source-intelligence host unreachable (${sourceUrl}) \u2014 attempting to start it\u2026`)
|
|
93999
94393
|
);
|
|
94000
94394
|
const healed = await ensureSourceHost(renv.path, sourceUrl);
|
|
94001
94395
|
if (healed.ok) {
|
|
94002
|
-
console.error(
|
|
94396
|
+
console.error(import_picocolors9.default.green(`Source-intelligence host is up at ${healed.hostUrl}.`));
|
|
94003
94397
|
health = await code.health();
|
|
94004
94398
|
} else {
|
|
94005
|
-
console.error(
|
|
94399
|
+
console.error(import_picocolors9.default.dim(` ${ensureHostReasonHint(healed.reason)}`));
|
|
94006
94400
|
}
|
|
94007
94401
|
}
|
|
94008
94402
|
const runtimeOnly = !health.ok;
|
|
94009
94403
|
if (runtimeOnly) {
|
|
94010
94404
|
console.error(
|
|
94011
|
-
|
|
94012
|
-
`Proceeding in runtime-only mode \u2014 no source intelligence. Run ${
|
|
94405
|
+
import_picocolors9.default.yellow(
|
|
94406
|
+
`Proceeding in runtime-only mode \u2014 no source intelligence. Run ${import_picocolors9.default.bold("horus index")} for a full (code-aware) investigation.`
|
|
94013
94407
|
)
|
|
94014
94408
|
);
|
|
94015
94409
|
}
|
|
@@ -94054,7 +94448,7 @@ async function runInvestigate(hint, opts) {
|
|
|
94054
94448
|
model,
|
|
94055
94449
|
...ai.anthropicApiKey !== void 0 ? { apiKey: ai.anthropicApiKey } : {}
|
|
94056
94450
|
});
|
|
94057
|
-
console.log(
|
|
94451
|
+
console.log(import_picocolors9.default.dim(`[ai] model: ${model}`));
|
|
94058
94452
|
const narrativeInput = buildNarrativeInput(report);
|
|
94059
94453
|
const { output, fromProvider, degraded, validationErrors } = await renderNarrative(
|
|
94060
94454
|
narrativeInput,
|
|
@@ -94070,37 +94464,78 @@ async function runInvestigate(hint, opts) {
|
|
|
94070
94464
|
renderStoredAIJudgment(stored);
|
|
94071
94465
|
} else if (degraded) {
|
|
94072
94466
|
if (validationErrors && validationErrors.length > 0) {
|
|
94073
|
-
console.error(
|
|
94467
|
+
console.error(import_picocolors9.default.yellow(`[ai] structured validation incomplete \u2014 showing raw AI narrative`));
|
|
94074
94468
|
}
|
|
94075
94469
|
console.log("");
|
|
94076
|
-
console.log(
|
|
94077
|
-
console.log(
|
|
94470
|
+
console.log(import_picocolors9.default.dim("\u2500".repeat(60)));
|
|
94471
|
+
console.log(import_picocolors9.default.bold("AI narrative ") + import_picocolors9.default.yellow("(unstructured \u2014 not validated)"));
|
|
94078
94472
|
if (output.what?.trim()) {
|
|
94079
|
-
console.log(
|
|
94473
|
+
console.log(import_picocolors9.default.bold("\nWhat:"), output.what.trim());
|
|
94080
94474
|
}
|
|
94081
94475
|
if (output.why?.trim()) {
|
|
94082
|
-
console.log(
|
|
94476
|
+
console.log(import_picocolors9.default.bold("\nWhy:"), output.why.trim());
|
|
94083
94477
|
}
|
|
94084
94478
|
if (output.whereNext.length > 0) {
|
|
94085
|
-
console.log(
|
|
94479
|
+
console.log(import_picocolors9.default.bold("\nNext:"));
|
|
94086
94480
|
for (const a of output.whereNext) console.log(` - ${a}`);
|
|
94087
94481
|
}
|
|
94088
94482
|
} else {
|
|
94089
94483
|
const reason = classifyAIFailure(validationErrors?.[0]);
|
|
94090
|
-
console.error(
|
|
94484
|
+
console.error(import_picocolors9.default.yellow(`[ai] fallback to deterministic \u2014 ${reason}`));
|
|
94485
|
+
}
|
|
94486
|
+
}
|
|
94487
|
+
track({
|
|
94488
|
+
type: "investigation.completed",
|
|
94489
|
+
investigationId: report.id,
|
|
94490
|
+
confidence: typeof report.confidence === "number" ? report.confidence : null,
|
|
94491
|
+
evidenceCount: report.evidence?.length ?? 0,
|
|
94492
|
+
findingCount: report.findings?.length ?? 0,
|
|
94493
|
+
suspectedCauseCount: report.suspectedCauses?.length ?? 0,
|
|
94494
|
+
degraded: Boolean(report.degraded),
|
|
94495
|
+
gapCount: report.gapAnalysis?.gaps?.length ?? 0,
|
|
94496
|
+
hasAi: Boolean(report.aiJudgment)
|
|
94497
|
+
});
|
|
94498
|
+
if (isContentSharingEnabled()) {
|
|
94499
|
+
const hint2 = redactOrDrop(report.input.hint ?? "");
|
|
94500
|
+
if (!hint2.dropped) {
|
|
94501
|
+
track({
|
|
94502
|
+
type: "investigation.content",
|
|
94503
|
+
investigationId: report.id,
|
|
94504
|
+
hint: hint2.value ?? "",
|
|
94505
|
+
summary: redactContent(report.summary ?? ""),
|
|
94506
|
+
findingTitles: (report.findings ?? []).slice(0, 20).map((f) => redactContent(f.title ?? "")),
|
|
94507
|
+
suspectedCauseTitles: (report.suspectedCauses ?? []).slice(0, 20).map((c) => redactContent(c.title ?? "")),
|
|
94508
|
+
confidence: typeof report.confidence === "number" ? report.confidence : null
|
|
94509
|
+
});
|
|
94091
94510
|
}
|
|
94092
94511
|
}
|
|
94093
94512
|
if (cloudActive && cloudSession && cloudCfg) {
|
|
94094
94513
|
try {
|
|
94095
94514
|
const refs = await uploadInvestigationToCloud(cloudSession.client, cloudCfg, report);
|
|
94096
|
-
console.log(
|
|
94515
|
+
console.log(import_picocolors9.default.dim(`[cloud] investigation saved: ${refs.investigationId}`));
|
|
94097
94516
|
} catch (err) {
|
|
94098
94517
|
return reportCloudError(err);
|
|
94099
94518
|
}
|
|
94100
94519
|
}
|
|
94101
94520
|
if (format !== "json") {
|
|
94102
|
-
|
|
94521
|
+
if (report.persisted === false) {
|
|
94522
|
+
console.error(
|
|
94523
|
+
import_picocolors9.default.yellow(`
|
|
94524
|
+
\u26A0 Results were not saved \u2014 the investigation database was unreachable.`)
|
|
94525
|
+
);
|
|
94526
|
+
console.error(
|
|
94527
|
+
import_picocolors9.default.dim(
|
|
94528
|
+
` This report is display-only; \`horus ask\` won't find it. Start the database and re-run to persist.`
|
|
94529
|
+
)
|
|
94530
|
+
);
|
|
94531
|
+
} else {
|
|
94532
|
+
console.log(import_picocolors9.default.dim(`
|
|
94103
94533
|
Ask a follow-up: horus ask ${report.id} "<question>"`));
|
|
94534
|
+
}
|
|
94535
|
+
await maybePromptFeedback({
|
|
94536
|
+
investigationId: report.id,
|
|
94537
|
+
horusSeconds: (Date.now() - startedAtMs) / 1e3
|
|
94538
|
+
});
|
|
94104
94539
|
}
|
|
94105
94540
|
} finally {
|
|
94106
94541
|
await sql2.end();
|
|
@@ -94109,14 +94544,16 @@ Ask a follow-up: horus ask ${report.id} "<question>"`));
|
|
|
94109
94544
|
}
|
|
94110
94545
|
return 0;
|
|
94111
94546
|
} catch (err) {
|
|
94112
|
-
|
|
94547
|
+
const msg = err?.message || String(err);
|
|
94548
|
+
console.error(import_picocolors9.default.red(msg.trim() ? msg : "Investigation failed (unknown error)."));
|
|
94549
|
+
if (process.env.HORUS_DEBUG) console.error(import_picocolors9.default.dim(err?.stack ?? String(err)));
|
|
94113
94550
|
return 1;
|
|
94114
94551
|
}
|
|
94115
94552
|
}
|
|
94116
94553
|
|
|
94117
94554
|
// ../../packages/cli/src/commands/changes.ts
|
|
94118
94555
|
init_cjs_shims();
|
|
94119
|
-
var
|
|
94556
|
+
var import_picocolors10 = __toESM(require_picocolors(), 1);
|
|
94120
94557
|
var CHANGES_AI_CONTRACT = `Provide a clearly separated AI change-impact review with:
|
|
94121
94558
|
|
|
94122
94559
|
Highest-risk changes
|
|
@@ -94141,7 +94578,7 @@ async function runChanges(base2, compare, opts) {
|
|
|
94141
94578
|
const health = await code.health();
|
|
94142
94579
|
if (!health.ok) {
|
|
94143
94580
|
console.error(
|
|
94144
|
-
|
|
94581
|
+
import_picocolors10.default.red("Source-intelligence host unreachable \u2014 run: horus index")
|
|
94145
94582
|
);
|
|
94146
94583
|
return 1;
|
|
94147
94584
|
}
|
|
@@ -94163,20 +94600,20 @@ async function runChanges(base2, compare, opts) {
|
|
|
94163
94600
|
});
|
|
94164
94601
|
console.log("\n" + renderInterpretation(result));
|
|
94165
94602
|
if (!result.ok) {
|
|
94166
|
-
console.error(
|
|
94603
|
+
console.error(import_picocolors10.default.yellow(`[ai] ${result.warning}`));
|
|
94167
94604
|
}
|
|
94168
94605
|
}
|
|
94169
94606
|
}
|
|
94170
94607
|
return 0;
|
|
94171
94608
|
} catch (err) {
|
|
94172
|
-
console.error(
|
|
94609
|
+
console.error(import_picocolors10.default.red(err.message));
|
|
94173
94610
|
return 1;
|
|
94174
94611
|
}
|
|
94175
94612
|
}
|
|
94176
94613
|
|
|
94177
94614
|
// ../../packages/cli/src/commands/timeline.ts
|
|
94178
94615
|
init_cjs_shims();
|
|
94179
|
-
var
|
|
94616
|
+
var import_picocolors11 = __toESM(require_picocolors(), 1);
|
|
94180
94617
|
var DEFAULT_SINCE = "7 days ago";
|
|
94181
94618
|
function resolveTimelineWindow(opts) {
|
|
94182
94619
|
const usingDefault = !opts.all && opts.since === void 0;
|
|
@@ -94206,7 +94643,7 @@ async function runTimeline(service, opts) {
|
|
|
94206
94643
|
try {
|
|
94207
94644
|
renv = resolveEnvironment(config2, { project: opts.repo });
|
|
94208
94645
|
} catch (err) {
|
|
94209
|
-
console.error(
|
|
94646
|
+
console.error(import_picocolors11.default.red(err.message));
|
|
94210
94647
|
return 1;
|
|
94211
94648
|
}
|
|
94212
94649
|
const { code } = createConnectors(config2);
|
|
@@ -94221,9 +94658,9 @@ async function runTimeline(service, opts) {
|
|
|
94221
94658
|
console.log(renderChangeTimeline(t));
|
|
94222
94659
|
if (usingDefaultWindow) {
|
|
94223
94660
|
console.log(
|
|
94224
|
-
|
|
94661
|
+
import_picocolors11.default.dim(
|
|
94225
94662
|
`
|
|
94226
|
-
Showing the last 7 days (default). Widen with ${
|
|
94663
|
+
Showing the last 7 days (default). Widen with ${import_picocolors11.default.bold('--since "30 days ago"')}, pin a range with ${import_picocolors11.default.bold("--since <when> --until <when>")}, or see everything with ${import_picocolors11.default.bold("--all")}.`
|
|
94227
94664
|
)
|
|
94228
94665
|
);
|
|
94229
94666
|
}
|
|
@@ -94240,20 +94677,20 @@ async function runTimeline(service, opts) {
|
|
|
94240
94677
|
});
|
|
94241
94678
|
console.log("\n" + renderInterpretation(result));
|
|
94242
94679
|
if (!result.ok) {
|
|
94243
|
-
console.error(
|
|
94680
|
+
console.error(import_picocolors11.default.yellow(`[ai] ${result.warning}`));
|
|
94244
94681
|
}
|
|
94245
94682
|
}
|
|
94246
94683
|
}
|
|
94247
94684
|
return 0;
|
|
94248
94685
|
} catch (err) {
|
|
94249
|
-
console.error(
|
|
94686
|
+
console.error(import_picocolors11.default.red(err.message));
|
|
94250
94687
|
return 1;
|
|
94251
94688
|
}
|
|
94252
94689
|
}
|
|
94253
94690
|
|
|
94254
94691
|
// ../../packages/cli/src/commands/what-changed.ts
|
|
94255
94692
|
init_cjs_shims();
|
|
94256
|
-
var
|
|
94693
|
+
var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
94257
94694
|
var DEFAULT_SINCE2 = "7 days ago";
|
|
94258
94695
|
var WHAT_CHANGED_AI_CONTRACT = `Provide a clearly separated AI interpretation section with:
|
|
94259
94696
|
|
|
@@ -94277,7 +94714,7 @@ async function runWhatChanged(service, opts) {
|
|
|
94277
94714
|
try {
|
|
94278
94715
|
renv = resolveEnvironment(config2, { project: opts.repo });
|
|
94279
94716
|
} catch (err) {
|
|
94280
|
-
console.error(
|
|
94717
|
+
console.error(import_picocolors12.default.red(err.message));
|
|
94281
94718
|
return 1;
|
|
94282
94719
|
}
|
|
94283
94720
|
const { code } = createConnectors(config2);
|
|
@@ -94300,19 +94737,19 @@ async function runWhatChanged(service, opts) {
|
|
|
94300
94737
|
});
|
|
94301
94738
|
console.log("\n" + renderInterpretation(result));
|
|
94302
94739
|
if (!result.ok) {
|
|
94303
|
-
console.error(
|
|
94740
|
+
console.error(import_picocolors12.default.yellow(`[ai] ${result.warning}`));
|
|
94304
94741
|
}
|
|
94305
94742
|
}
|
|
94306
94743
|
return 0;
|
|
94307
94744
|
} catch (err) {
|
|
94308
|
-
console.error(
|
|
94745
|
+
console.error(import_picocolors12.default.red(err.message));
|
|
94309
94746
|
return 1;
|
|
94310
94747
|
}
|
|
94311
94748
|
}
|
|
94312
94749
|
|
|
94313
94750
|
// ../../packages/cli/src/commands/architecture.ts
|
|
94314
94751
|
init_cjs_shims();
|
|
94315
|
-
var
|
|
94752
|
+
var import_picocolors13 = __toESM(require_picocolors(), 1);
|
|
94316
94753
|
var ARCHITECTURE_AI_CONTRACT = `Provide a clearly separated AI interpretation section with:
|
|
94317
94754
|
|
|
94318
94755
|
System summary
|
|
@@ -94341,7 +94778,7 @@ async function runArchitecture(opts) {
|
|
|
94341
94778
|
const health = await code.health();
|
|
94342
94779
|
if (!health.ok) {
|
|
94343
94780
|
console.error(
|
|
94344
|
-
|
|
94781
|
+
import_picocolors13.default.red("Source-intelligence host unreachable \u2014 run: horus index")
|
|
94345
94782
|
);
|
|
94346
94783
|
return 1;
|
|
94347
94784
|
}
|
|
@@ -94369,7 +94806,7 @@ async function runArchitecture(opts) {
|
|
|
94369
94806
|
});
|
|
94370
94807
|
console.log("\n" + renderInterpretation(result));
|
|
94371
94808
|
if (!result.ok) {
|
|
94372
|
-
console.error(
|
|
94809
|
+
console.error(import_picocolors13.default.yellow(`[ai] ${result.warning}`));
|
|
94373
94810
|
}
|
|
94374
94811
|
}
|
|
94375
94812
|
}
|
|
@@ -94378,14 +94815,14 @@ async function runArchitecture(opts) {
|
|
|
94378
94815
|
}
|
|
94379
94816
|
return 0;
|
|
94380
94817
|
} catch (err) {
|
|
94381
|
-
console.error(
|
|
94818
|
+
console.error(import_picocolors13.default.red(err.message));
|
|
94382
94819
|
return 1;
|
|
94383
94820
|
}
|
|
94384
94821
|
}
|
|
94385
94822
|
|
|
94386
94823
|
// ../../packages/cli/src/commands/blast-radius.ts
|
|
94387
94824
|
init_cjs_shims();
|
|
94388
|
-
var
|
|
94825
|
+
var import_picocolors14 = __toESM(require_picocolors(), 1);
|
|
94389
94826
|
var BLAST_RADIUS_AI_CONTRACT = `Provide a clearly separated AI interpretation section with:
|
|
94390
94827
|
|
|
94391
94828
|
Evidence used
|
|
@@ -94412,7 +94849,7 @@ async function runBlastRadius(query, opts) {
|
|
|
94412
94849
|
const { code } = createConnectors(config2);
|
|
94413
94850
|
const health = await code.health();
|
|
94414
94851
|
if (!health.ok) {
|
|
94415
|
-
console.error(
|
|
94852
|
+
console.error(import_picocolors14.default.red("Source-intelligence host unreachable \u2014 run: horus index"));
|
|
94416
94853
|
return 1;
|
|
94417
94854
|
}
|
|
94418
94855
|
let project;
|
|
@@ -94425,12 +94862,12 @@ async function runBlastRadius(query, opts) {
|
|
|
94425
94862
|
const r = await analyzeBlastRadius(query, { code, db, project }, opts.depth ?? 3);
|
|
94426
94863
|
if (!r) {
|
|
94427
94864
|
console.log(`No symbol found for: ${query}`);
|
|
94428
|
-
console.log(
|
|
94865
|
+
console.log(import_picocolors14.default.dim(` Tip: use an exact class or function name, e.g. "MyService"`));
|
|
94429
94866
|
return 1;
|
|
94430
94867
|
}
|
|
94431
94868
|
if (r.seed.name.toLowerCase() !== query.toLowerCase()) {
|
|
94432
94869
|
console.log(
|
|
94433
|
-
|
|
94870
|
+
import_picocolors14.default.yellow(` No exact match for "${query}"`) + import_picocolors14.default.dim(` \u2014 showing closest: "${r.seed.name}" (fuzzy match)`)
|
|
94434
94871
|
);
|
|
94435
94872
|
}
|
|
94436
94873
|
if (opts.json) {
|
|
@@ -94450,7 +94887,7 @@ async function runBlastRadius(query, opts) {
|
|
|
94450
94887
|
});
|
|
94451
94888
|
console.log("\n" + renderInterpretation(result));
|
|
94452
94889
|
if (!result.ok) {
|
|
94453
|
-
console.error(
|
|
94890
|
+
console.error(import_picocolors14.default.yellow(`[ai] ${result.warning}`));
|
|
94454
94891
|
}
|
|
94455
94892
|
}
|
|
94456
94893
|
}
|
|
@@ -94459,28 +94896,28 @@ async function runBlastRadius(query, opts) {
|
|
|
94459
94896
|
}
|
|
94460
94897
|
return 0;
|
|
94461
94898
|
} catch (err) {
|
|
94462
|
-
console.error(
|
|
94899
|
+
console.error(import_picocolors14.default.red(err.message));
|
|
94463
94900
|
return 1;
|
|
94464
94901
|
}
|
|
94465
94902
|
}
|
|
94466
94903
|
|
|
94467
94904
|
// ../../packages/cli/src/commands/repos.ts
|
|
94468
94905
|
init_cjs_shims();
|
|
94469
|
-
var
|
|
94906
|
+
var import_picocolors15 = __toESM(require_picocolors(), 1);
|
|
94470
94907
|
async function runRepos(opts) {
|
|
94471
94908
|
const config2 = await loadConfig(opts.config);
|
|
94472
94909
|
const providers = repoProviders(config2);
|
|
94473
94910
|
if (providers.length === 0) {
|
|
94474
|
-
console.log(
|
|
94911
|
+
console.log(import_picocolors15.default.dim("No repositories configured."));
|
|
94475
94912
|
return 0;
|
|
94476
94913
|
}
|
|
94477
94914
|
const health = await reposHealth(providers);
|
|
94478
94915
|
for (const h of health) {
|
|
94479
|
-
const dot = h.reachable ?
|
|
94480
|
-
const name =
|
|
94481
|
-
const hostUrl =
|
|
94482
|
-
const path =
|
|
94483
|
-
const detail = h.detail ?
|
|
94916
|
+
const dot = h.reachable ? import_picocolors15.default.green("\u25CF") : import_picocolors15.default.red("\u25CF");
|
|
94917
|
+
const name = import_picocolors15.default.bold(h.repo.padEnd(20));
|
|
94918
|
+
const hostUrl = import_picocolors15.default.cyan(h.hostUrl.padEnd(30));
|
|
94919
|
+
const path = import_picocolors15.default.dim(h.path);
|
|
94920
|
+
const detail = h.detail ? import_picocolors15.default.dim(`(${h.detail})`) : "";
|
|
94484
94921
|
console.log(` ${dot} ${name} ${hostUrl} ${path} ${detail}`);
|
|
94485
94922
|
}
|
|
94486
94923
|
return 0;
|
|
@@ -94488,7 +94925,7 @@ async function runRepos(opts) {
|
|
|
94488
94925
|
|
|
94489
94926
|
// ../../packages/cli/src/commands/search.ts
|
|
94490
94927
|
init_cjs_shims();
|
|
94491
|
-
var
|
|
94928
|
+
var import_picocolors16 = __toESM(require_picocolors(), 1);
|
|
94492
94929
|
async function runSearch(query, opts) {
|
|
94493
94930
|
const config2 = await loadConfig(opts.config);
|
|
94494
94931
|
const providers = repoProviders(config2);
|
|
@@ -94499,16 +94936,16 @@ async function runSearch(query, opts) {
|
|
|
94499
94936
|
}
|
|
94500
94937
|
let totalMatches = 0;
|
|
94501
94938
|
for (const result of results) {
|
|
94502
|
-
const statusDot = result.reachable ?
|
|
94939
|
+
const statusDot = result.reachable ? import_picocolors16.default.green("\u25CF") : import_picocolors16.default.red("\u25CF");
|
|
94503
94940
|
console.log("");
|
|
94504
|
-
console.log(`${statusDot} ${
|
|
94941
|
+
console.log(`${statusDot} ${import_picocolors16.default.bold("## " + result.repo)} ${import_picocolors16.default.dim(result.hostUrl)}`);
|
|
94505
94942
|
if (!result.reachable) {
|
|
94506
|
-
console.log(
|
|
94943
|
+
console.log(import_picocolors16.default.dim(" (unreachable)"));
|
|
94507
94944
|
} else if (result.symbols.length === 0) {
|
|
94508
|
-
console.log(
|
|
94945
|
+
console.log(import_picocolors16.default.dim(" (no matches)"));
|
|
94509
94946
|
} else {
|
|
94510
94947
|
for (const sym of result.symbols) {
|
|
94511
|
-
console.log(` - ${
|
|
94948
|
+
console.log(` - ${import_picocolors16.default.bold(sym.name)} ${import_picocolors16.default.dim(sym.filePath)}`);
|
|
94512
94949
|
}
|
|
94513
94950
|
totalMatches += result.symbols.length;
|
|
94514
94951
|
}
|
|
@@ -94516,7 +94953,7 @@ async function runSearch(query, opts) {
|
|
|
94516
94953
|
console.log("");
|
|
94517
94954
|
const reachableCount = results.filter((r) => r.reachable).length;
|
|
94518
94955
|
console.log(
|
|
94519
|
-
|
|
94956
|
+
import_picocolors16.default.dim(
|
|
94520
94957
|
`${totalMatches} match(es) across ${reachableCount}/${results.length} reachable repo(s) for query: "${query}"`
|
|
94521
94958
|
)
|
|
94522
94959
|
);
|
|
@@ -94525,7 +94962,7 @@ async function runSearch(query, opts) {
|
|
|
94525
94962
|
|
|
94526
94963
|
// ../../packages/cli/src/commands/investigations.ts
|
|
94527
94964
|
init_cjs_shims();
|
|
94528
|
-
var
|
|
94965
|
+
var import_picocolors17 = __toESM(require_picocolors(), 1);
|
|
94529
94966
|
|
|
94530
94967
|
// ../../packages/cli/src/lib/format.ts
|
|
94531
94968
|
init_cjs_shims();
|
|
@@ -94568,8 +95005,8 @@ async function runInvestigations(opts) {
|
|
|
94568
95005
|
const session = authedClient();
|
|
94569
95006
|
if (!session) {
|
|
94570
95007
|
console.error(
|
|
94571
|
-
|
|
94572
|
-
`This repo is linked to Horus Cloud but you are not logged in. Run ${
|
|
95008
|
+
import_picocolors17.default.red(
|
|
95009
|
+
`This repo is linked to Horus Cloud but you are not logged in. Run ${import_picocolors17.default.bold("horus login")} first.`
|
|
94573
95010
|
)
|
|
94574
95011
|
);
|
|
94575
95012
|
return 1;
|
|
@@ -94610,18 +95047,18 @@ async function runInvestigations(opts) {
|
|
|
94610
95047
|
|
|
94611
95048
|
// ../../packages/cli/src/commands/replay.ts
|
|
94612
95049
|
init_cjs_shims();
|
|
94613
|
-
var
|
|
95050
|
+
var import_picocolors18 = __toESM(require_picocolors(), 1);
|
|
94614
95051
|
async function runReplay(id, opts) {
|
|
94615
95052
|
const { db, sql: sql2 } = createDb(await resolveDbUrl(opts.config));
|
|
94616
95053
|
try {
|
|
94617
95054
|
const row = await getInvestigation(db, id);
|
|
94618
95055
|
if (!row) {
|
|
94619
|
-
console.error(
|
|
95056
|
+
console.error(import_picocolors18.default.red("No investigation found: " + id));
|
|
94620
95057
|
return 1;
|
|
94621
95058
|
}
|
|
94622
95059
|
if (!row.report) {
|
|
94623
95060
|
console.error(
|
|
94624
|
-
|
|
95061
|
+
import_picocolors18.default.red(
|
|
94625
95062
|
"Investigation " + id + " has no stored report (run a newer investigation)."
|
|
94626
95063
|
)
|
|
94627
95064
|
);
|
|
@@ -94634,7 +95071,7 @@ async function runReplay(id, opts) {
|
|
|
94634
95071
|
if (opts.ai && fmt !== "json") {
|
|
94635
95072
|
if (report.aiJudgment && !opts.refreshAi) {
|
|
94636
95073
|
renderStoredAIJudgment(report.aiJudgment);
|
|
94637
|
-
console.log(
|
|
95074
|
+
console.log(import_picocolors18.default.dim("[ai] Stored judgment replayed. Use --refresh-ai to regenerate."));
|
|
94638
95075
|
} else {
|
|
94639
95076
|
const narrativeInput = buildNarrativeInput(report);
|
|
94640
95077
|
const { provider } = await buildNarrativeProvider({
|
|
@@ -94647,17 +95084,17 @@ async function runReplay(id, opts) {
|
|
|
94647
95084
|
);
|
|
94648
95085
|
if (!fromProvider && degraded) {
|
|
94649
95086
|
if (validationErrors?.length) {
|
|
94650
|
-
console.error(
|
|
95087
|
+
console.error(import_picocolors18.default.yellow("[ai] structured validation incomplete \u2014 showing raw AI narrative"));
|
|
94651
95088
|
}
|
|
94652
95089
|
console.log("");
|
|
94653
|
-
console.log(
|
|
94654
|
-
console.log(
|
|
94655
|
-
if (output.what?.trim()) console.log(
|
|
94656
|
-
if (output.why?.trim()) console.log(
|
|
95090
|
+
console.log(import_picocolors18.default.dim("\u2500".repeat(60)));
|
|
95091
|
+
console.log(import_picocolors18.default.bold("AI narrative ") + import_picocolors18.default.yellow("(unstructured \u2014 not validated)"));
|
|
95092
|
+
if (output.what?.trim()) console.log(import_picocolors18.default.bold("\nWhat:"), output.what.trim());
|
|
95093
|
+
if (output.why?.trim()) console.log(import_picocolors18.default.bold("\nWhy:"), output.why.trim());
|
|
94657
95094
|
} else if (!fromProvider) {
|
|
94658
|
-
console.error(
|
|
95095
|
+
console.error(import_picocolors18.default.yellow("[ai] Provider unavailable \u2014 deterministic output shown above."));
|
|
94659
95096
|
if (validationErrors?.length) {
|
|
94660
|
-
console.error(
|
|
95097
|
+
console.error(import_picocolors18.default.dim(` ${validationErrors[0]}`));
|
|
94661
95098
|
}
|
|
94662
95099
|
} else {
|
|
94663
95100
|
const stored = narrativeOutputToStoredJudgment(output, "anthropic");
|
|
@@ -94678,7 +95115,7 @@ async function runReplay(id, opts) {
|
|
|
94678
95115
|
|
|
94679
95116
|
// ../../packages/cli/src/commands/owner.ts
|
|
94680
95117
|
init_cjs_shims();
|
|
94681
|
-
var
|
|
95118
|
+
var import_picocolors19 = __toESM(require_picocolors(), 1);
|
|
94682
95119
|
async function runOwner(query, opts) {
|
|
94683
95120
|
try {
|
|
94684
95121
|
const config2 = await loadConfig(opts.config);
|
|
@@ -94686,7 +95123,7 @@ async function runOwner(query, opts) {
|
|
|
94686
95123
|
try {
|
|
94687
95124
|
renv = resolveEnvironment(config2, { project: opts.repo });
|
|
94688
95125
|
} catch (err) {
|
|
94689
|
-
console.error(
|
|
95126
|
+
console.error(import_picocolors19.default.red(err.message));
|
|
94690
95127
|
return 1;
|
|
94691
95128
|
}
|
|
94692
95129
|
const code = codeForRepo(config2, renv.project);
|
|
@@ -94694,16 +95131,16 @@ async function runOwner(query, opts) {
|
|
|
94694
95131
|
console.log(opts.json ? ownershipToJSON(o) : renderOwnership(o));
|
|
94695
95132
|
return 0;
|
|
94696
95133
|
} catch (err) {
|
|
94697
|
-
console.error(
|
|
95134
|
+
console.error(import_picocolors19.default.red(err.message));
|
|
94698
95135
|
return 1;
|
|
94699
95136
|
}
|
|
94700
95137
|
}
|
|
94701
95138
|
|
|
94702
95139
|
// ../../packages/cli/src/commands/postmortem.ts
|
|
94703
95140
|
init_cjs_shims();
|
|
94704
|
-
var
|
|
94705
|
-
var
|
|
94706
|
-
var
|
|
95141
|
+
var import_node_fs15 = require("fs");
|
|
95142
|
+
var import_node_path16 = require("path");
|
|
95143
|
+
var import_picocolors20 = __toESM(require_picocolors(), 1);
|
|
94707
95144
|
async function runPostmortem(id, opts) {
|
|
94708
95145
|
const log = opts.write ?? ((line2) => console.log(line2));
|
|
94709
95146
|
let sql2;
|
|
@@ -94717,11 +95154,11 @@ async function runPostmortem(id, opts) {
|
|
|
94717
95154
|
const { db } = conn;
|
|
94718
95155
|
const row = await getInvestigation(db, id);
|
|
94719
95156
|
if (!row) {
|
|
94720
|
-
log(
|
|
95157
|
+
log(import_picocolors20.default.red("No investigation found: " + id));
|
|
94721
95158
|
return 1;
|
|
94722
95159
|
}
|
|
94723
95160
|
if (!row.report) {
|
|
94724
|
-
log(
|
|
95161
|
+
log(import_picocolors20.default.red("Investigation " + id + " has no stored report."));
|
|
94725
95162
|
return 1;
|
|
94726
95163
|
}
|
|
94727
95164
|
report = migrateReport(row.report);
|
|
@@ -94813,25 +95250,25 @@ _AI summary unavailable: ${validationErrors?.[0] ?? "provider error"}_
|
|
|
94813
95250
|
}
|
|
94814
95251
|
}
|
|
94815
95252
|
if (opts.output) {
|
|
94816
|
-
const outputPath = (0,
|
|
94817
|
-
if ((0,
|
|
94818
|
-
log(
|
|
94819
|
-
log(
|
|
95253
|
+
const outputPath = (0, import_node_path16.resolve)(opts.output);
|
|
95254
|
+
if ((0, import_node_fs15.existsSync)(outputPath) && !opts.force) {
|
|
95255
|
+
log(import_picocolors20.default.red("\u2717") + " " + outputPath + " already exists");
|
|
95256
|
+
log(import_picocolors20.default.dim(" pass --force to overwrite"));
|
|
94820
95257
|
return 1;
|
|
94821
95258
|
}
|
|
94822
95259
|
try {
|
|
94823
|
-
(0,
|
|
95260
|
+
(0, import_node_fs15.writeFileSync)(outputPath, content, "utf8");
|
|
94824
95261
|
} catch (err) {
|
|
94825
|
-
log(
|
|
95262
|
+
log(import_picocolors20.default.red("\u2717 Could not write " + outputPath + ": ") + err.message);
|
|
94826
95263
|
return 1;
|
|
94827
95264
|
}
|
|
94828
|
-
log(
|
|
95265
|
+
log(import_picocolors20.default.green("\u2713") + " Saved postmortem to " + outputPath);
|
|
94829
95266
|
} else {
|
|
94830
95267
|
log(content);
|
|
94831
95268
|
}
|
|
94832
95269
|
} catch (err) {
|
|
94833
95270
|
const message = err instanceof Error ? err.message : String(err);
|
|
94834
|
-
log(
|
|
95271
|
+
log(import_picocolors20.default.red("postmortem failed: " + message));
|
|
94835
95272
|
return 1;
|
|
94836
95273
|
} finally {
|
|
94837
95274
|
if (sql2) {
|
|
@@ -94843,7 +95280,7 @@ _AI summary unavailable: ${validationErrors?.[0] ?? "provider error"}_
|
|
|
94843
95280
|
|
|
94844
95281
|
// ../../packages/cli/src/commands/score.ts
|
|
94845
95282
|
init_cjs_shims();
|
|
94846
|
-
var
|
|
95283
|
+
var import_picocolors21 = __toESM(require_picocolors(), 1);
|
|
94847
95284
|
var SCORE_AI_CONTRACT = `Provide a clearly separated AI score explanation with:
|
|
94848
95285
|
|
|
94849
95286
|
Why this scored this way
|
|
@@ -94862,11 +95299,11 @@ async function runScore(id, opts) {
|
|
|
94862
95299
|
try {
|
|
94863
95300
|
const row = await getInvestigation(db, id);
|
|
94864
95301
|
if (!row) {
|
|
94865
|
-
console.error(
|
|
95302
|
+
console.error(import_picocolors21.default.red("No investigation found: " + id));
|
|
94866
95303
|
return 1;
|
|
94867
95304
|
}
|
|
94868
95305
|
if (!row.report) {
|
|
94869
|
-
console.error(
|
|
95306
|
+
console.error(import_picocolors21.default.red("Investigation " + id + " has no stored report."));
|
|
94870
95307
|
return 1;
|
|
94871
95308
|
}
|
|
94872
95309
|
const s = scoreInvestigation(migrateReport(row.report));
|
|
@@ -94887,7 +95324,7 @@ async function runScore(id, opts) {
|
|
|
94887
95324
|
});
|
|
94888
95325
|
console.log("\n" + renderInterpretation(result));
|
|
94889
95326
|
if (!result.ok) {
|
|
94890
|
-
console.error(
|
|
95327
|
+
console.error(import_picocolors21.default.yellow(`[ai] ${result.warning}`));
|
|
94891
95328
|
}
|
|
94892
95329
|
}
|
|
94893
95330
|
}
|
|
@@ -94927,7 +95364,7 @@ async function runScores(opts) {
|
|
|
94927
95364
|
|
|
94928
95365
|
// ../../packages/cli/src/commands/ask.ts
|
|
94929
95366
|
init_cjs_shims();
|
|
94930
|
-
var
|
|
95367
|
+
var import_picocolors22 = __toESM(require_picocolors(), 1);
|
|
94931
95368
|
function renderAnswer(report, directive, opts) {
|
|
94932
95369
|
const answer = answerQuestion(report, directive);
|
|
94933
95370
|
if (answer) {
|
|
@@ -94939,13 +95376,13 @@ function renderAnswer(report, directive, opts) {
|
|
|
94939
95376
|
if (!opts.json && report.aiJudgment) {
|
|
94940
95377
|
const j = report.aiJudgment;
|
|
94941
95378
|
console.log("");
|
|
94942
|
-
console.log(
|
|
94943
|
-
console.log(
|
|
95379
|
+
console.log(import_picocolors22.default.dim("\u2500".repeat(60)));
|
|
95380
|
+
console.log(import_picocolors22.default.dim(`Stored AI judgment (${j.provider}, ${j.generatedAt}):`));
|
|
94944
95381
|
if (j.rootCauseAssessment) {
|
|
94945
|
-
console.log(
|
|
94946
|
-
console.log(
|
|
95382
|
+
console.log(import_picocolors22.default.bold("Root cause (AI):"), j.rootCauseAssessment.summary);
|
|
95383
|
+
console.log(import_picocolors22.default.dim(`Uncertainty: ${j.rootCauseAssessment.uncertainty}`));
|
|
94947
95384
|
} else {
|
|
94948
|
-
console.log(
|
|
95385
|
+
console.log(import_picocolors22.default.bold("AI Why:"), j.why);
|
|
94949
95386
|
}
|
|
94950
95387
|
}
|
|
94951
95388
|
return 0;
|
|
@@ -94974,8 +95411,8 @@ async function runAsk(id, directive, opts) {
|
|
|
94974
95411
|
const session = authedClient();
|
|
94975
95412
|
if (!session) {
|
|
94976
95413
|
console.error(
|
|
94977
|
-
|
|
94978
|
-
`This repo is linked to Horus Cloud but you are not logged in. Run ${
|
|
95414
|
+
import_picocolors22.default.red(
|
|
95415
|
+
`This repo is linked to Horus Cloud but you are not logged in. Run ${import_picocolors22.default.bold("horus login")} first.`
|
|
94979
95416
|
)
|
|
94980
95417
|
);
|
|
94981
95418
|
return 1;
|
|
@@ -94984,15 +95421,15 @@ async function runAsk(id, directive, opts) {
|
|
|
94984
95421
|
const report = await fetchInvestigationReportFromCloud(session.client, cloudCfg, id);
|
|
94985
95422
|
if (report) return renderAnswer(report, directive, opts);
|
|
94986
95423
|
console.error(
|
|
94987
|
-
|
|
94988
|
-
`Investigation ${id} has no saved report locally or in Horus Cloud. Run ${
|
|
95424
|
+
import_picocolors22.default.red(
|
|
95425
|
+
`Investigation ${id} has no saved report locally or in Horus Cloud. Run ${import_picocolors22.default.bold("horus investigate")} first.`
|
|
94989
95426
|
)
|
|
94990
95427
|
);
|
|
94991
95428
|
return 1;
|
|
94992
95429
|
} catch (err) {
|
|
94993
95430
|
if (err instanceof CloudError && err.status === 404) {
|
|
94994
95431
|
console.error(
|
|
94995
|
-
|
|
95432
|
+
import_picocolors22.default.red(
|
|
94996
95433
|
`No investigation found for "${id}" locally or in Horus Cloud. Use the id printed at the top of \`horus investigate\` output.`
|
|
94997
95434
|
)
|
|
94998
95435
|
);
|
|
@@ -95006,21 +95443,21 @@ async function runAsk(id, directive, opts) {
|
|
|
95006
95443
|
case "found":
|
|
95007
95444
|
return renderAnswer(local.report, directive, opts);
|
|
95008
95445
|
case "no-report":
|
|
95009
|
-
console.error(
|
|
95446
|
+
console.error(import_picocolors22.default.red("Investigation " + id + " has no stored report."));
|
|
95010
95447
|
return 1;
|
|
95011
95448
|
case "error":
|
|
95012
|
-
console.error(
|
|
95449
|
+
console.error(import_picocolors22.default.red(local.message));
|
|
95013
95450
|
return 1;
|
|
95014
95451
|
case "not-found":
|
|
95015
95452
|
default:
|
|
95016
|
-
console.error(
|
|
95453
|
+
console.error(import_picocolors22.default.red("No investigation found: " + id));
|
|
95017
95454
|
return 1;
|
|
95018
95455
|
}
|
|
95019
95456
|
}
|
|
95020
95457
|
|
|
95021
95458
|
// ../../packages/cli/src/commands/onboard.ts
|
|
95022
95459
|
init_cjs_shims();
|
|
95023
|
-
var
|
|
95460
|
+
var import_picocolors23 = __toESM(require_picocolors(), 1);
|
|
95024
95461
|
var ONBOARD_AI_CONTRACT = `Provide a clearly separated AI onboarding guide with:
|
|
95025
95462
|
|
|
95026
95463
|
Start here
|
|
@@ -95048,7 +95485,7 @@ async function runOnboard(area, opts) {
|
|
|
95048
95485
|
try {
|
|
95049
95486
|
renv = resolveEnvironment(config2, { project: opts.repo });
|
|
95050
95487
|
} catch (err) {
|
|
95051
|
-
console.error(
|
|
95488
|
+
console.error(import_picocolors23.default.red(err.message));
|
|
95052
95489
|
return 1;
|
|
95053
95490
|
}
|
|
95054
95491
|
const repo = { name: renv.project, path: renv.path };
|
|
@@ -95056,7 +95493,7 @@ async function runOnboard(area, opts) {
|
|
|
95056
95493
|
const health = await code.health();
|
|
95057
95494
|
if (!health.ok) {
|
|
95058
95495
|
console.error(
|
|
95059
|
-
|
|
95496
|
+
import_picocolors23.default.red("Source-intelligence host unreachable \u2014 run: horus index")
|
|
95060
95497
|
);
|
|
95061
95498
|
return 1;
|
|
95062
95499
|
}
|
|
@@ -95083,7 +95520,7 @@ async function runOnboard(area, opts) {
|
|
|
95083
95520
|
});
|
|
95084
95521
|
console.log("\n" + renderInterpretation(result));
|
|
95085
95522
|
if (!result.ok) {
|
|
95086
|
-
console.error(
|
|
95523
|
+
console.error(import_picocolors23.default.yellow(`[ai] ${result.warning}`));
|
|
95087
95524
|
}
|
|
95088
95525
|
}
|
|
95089
95526
|
}
|
|
@@ -95092,14 +95529,14 @@ async function runOnboard(area, opts) {
|
|
|
95092
95529
|
}
|
|
95093
95530
|
return 0;
|
|
95094
95531
|
} catch (err) {
|
|
95095
|
-
console.error(
|
|
95532
|
+
console.error(import_picocolors23.default.red(err.message));
|
|
95096
95533
|
return 1;
|
|
95097
95534
|
}
|
|
95098
95535
|
}
|
|
95099
95536
|
|
|
95100
95537
|
// ../../packages/cli/src/commands/simulate.ts
|
|
95101
95538
|
init_cjs_shims();
|
|
95102
|
-
var
|
|
95539
|
+
var import_picocolors24 = __toESM(require_picocolors(), 1);
|
|
95103
95540
|
async function runSimulate(scenarioId, opts) {
|
|
95104
95541
|
try {
|
|
95105
95542
|
if (scenarioId === void 0) {
|
|
@@ -95109,7 +95546,7 @@ async function runSimulate(scenarioId, opts) {
|
|
|
95109
95546
|
const scenario = getScenario(scenarioId);
|
|
95110
95547
|
if (scenario === null) {
|
|
95111
95548
|
console.error(
|
|
95112
|
-
|
|
95549
|
+
import_picocolors24.default.red(
|
|
95113
95550
|
`Unknown scenario: "${scenarioId}". Run horus simulate to list available scenarios.`
|
|
95114
95551
|
)
|
|
95115
95552
|
);
|
|
@@ -95120,14 +95557,14 @@ async function runSimulate(scenarioId, opts) {
|
|
|
95120
95557
|
try {
|
|
95121
95558
|
renv = resolveEnvironment(config2, { project: opts.repo });
|
|
95122
95559
|
} catch (err) {
|
|
95123
|
-
console.error(
|
|
95560
|
+
console.error(import_picocolors24.default.red(err.message));
|
|
95124
95561
|
return 1;
|
|
95125
95562
|
}
|
|
95126
95563
|
const code = codeForRepo(config2, renv.project);
|
|
95127
95564
|
const health = await code.health();
|
|
95128
95565
|
if (!health.ok) {
|
|
95129
95566
|
console.error(
|
|
95130
|
-
|
|
95567
|
+
import_picocolors24.default.red("Source-intelligence host unreachable \u2014 run: horus index")
|
|
95131
95568
|
);
|
|
95132
95569
|
return 1;
|
|
95133
95570
|
}
|
|
@@ -95144,14 +95581,14 @@ async function runSimulate(scenarioId, opts) {
|
|
|
95144
95581
|
}
|
|
95145
95582
|
return 0;
|
|
95146
95583
|
} catch (err) {
|
|
95147
|
-
console.error(
|
|
95584
|
+
console.error(import_picocolors24.default.red(err.message));
|
|
95148
95585
|
return 1;
|
|
95149
95586
|
}
|
|
95150
95587
|
}
|
|
95151
95588
|
|
|
95152
95589
|
// ../../packages/cli/src/commands/logs.ts
|
|
95153
95590
|
init_cjs_shims();
|
|
95154
|
-
var
|
|
95591
|
+
var import_picocolors25 = __toESM(require_picocolors(), 1);
|
|
95155
95592
|
var LOGS_AI_CONTRACT = `Provide a clearly separated AI evidence narration with:
|
|
95156
95593
|
|
|
95157
95594
|
Evidence used
|
|
@@ -95184,9 +95621,9 @@ function resolveRawLevel(opts) {
|
|
|
95184
95621
|
return opts.level ?? "error";
|
|
95185
95622
|
}
|
|
95186
95623
|
function levelColor(level, text2) {
|
|
95187
|
-
if (level === "error" || level === "fatal") return
|
|
95188
|
-
if (level === "warn") return
|
|
95189
|
-
return
|
|
95624
|
+
if (level === "error" || level === "fatal") return import_picocolors25.default.red(text2);
|
|
95625
|
+
if (level === "warn") return import_picocolors25.default.yellow(text2);
|
|
95626
|
+
return import_picocolors25.default.dim(text2);
|
|
95190
95627
|
}
|
|
95191
95628
|
function matchServiceLabel(requested, candidates) {
|
|
95192
95629
|
if (candidates.includes(requested)) return { kind: "unique", matched: requested };
|
|
@@ -95203,13 +95640,13 @@ async function runLogs(service, opts) {
|
|
|
95203
95640
|
try {
|
|
95204
95641
|
renv = resolveEnvironment(config2, { project: opts.project, env: opts.env });
|
|
95205
95642
|
} catch (err) {
|
|
95206
|
-
console.error(
|
|
95643
|
+
console.error(import_picocolors25.default.red(err.message));
|
|
95207
95644
|
return 1;
|
|
95208
95645
|
}
|
|
95209
95646
|
const logs = logsForEnv(renv);
|
|
95210
95647
|
if (logs === null) {
|
|
95211
95648
|
console.error(
|
|
95212
|
-
|
|
95649
|
+
import_picocolors25.default.red(
|
|
95213
95650
|
`No Elasticsearch connector configured for ${renv.project}/${renv.env} (set ES_URL / ES_USERNAME / ES_PASSWORD)`
|
|
95214
95651
|
)
|
|
95215
95652
|
);
|
|
@@ -95217,7 +95654,7 @@ async function runLogs(service, opts) {
|
|
|
95217
95654
|
}
|
|
95218
95655
|
const health = await logs.health();
|
|
95219
95656
|
if (!health.ok) {
|
|
95220
|
-
console.error(
|
|
95657
|
+
console.error(import_picocolors25.default.red(`Elasticsearch unreachable: ${health.detail}`));
|
|
95221
95658
|
return 1;
|
|
95222
95659
|
}
|
|
95223
95660
|
const resolvedService = service ?? renv.connectors.elasticsearch?.serviceName;
|
|
@@ -95230,21 +95667,21 @@ async function runLogs(service, opts) {
|
|
|
95230
95667
|
requiresEventCode: aggregatesEventCode
|
|
95231
95668
|
});
|
|
95232
95669
|
for (const w of compat.issues.filter((i) => i.severity === "warning")) {
|
|
95233
|
-
console.warn(
|
|
95670
|
+
console.warn(import_picocolors25.default.yellow(`[warn] ${w.field}: ${w.message}`));
|
|
95234
95671
|
}
|
|
95235
95672
|
const errors2 = compat.issues.filter((i) => i.severity === "error");
|
|
95236
95673
|
if (errors2.length > 0) {
|
|
95237
|
-
console.error(
|
|
95674
|
+
console.error(import_picocolors25.default.red("Elasticsearch field mapping is incompatible with the index:"));
|
|
95238
95675
|
for (const e of errors2) {
|
|
95239
|
-
console.error(
|
|
95676
|
+
console.error(import_picocolors25.default.red(` ${e.field}: ${e.message}`));
|
|
95240
95677
|
}
|
|
95241
95678
|
console.error(
|
|
95242
|
-
|
|
95679
|
+
import_picocolors25.default.dim("Fix fields.* overrides in your connector config or choose the correct preset.")
|
|
95243
95680
|
);
|
|
95244
95681
|
return 1;
|
|
95245
95682
|
}
|
|
95246
95683
|
} catch {
|
|
95247
|
-
console.warn(
|
|
95684
|
+
console.warn(import_picocolors25.default.dim("[warn] Elasticsearch compatibility check unavailable \u2014 proceeding."));
|
|
95248
95685
|
}
|
|
95249
95686
|
const from = sinceToIso(opts.since) ?? new Date(Date.now() - 7 * 864e5).toISOString();
|
|
95250
95687
|
const fromDisplay = from.slice(0, 16).replace("T", " ");
|
|
@@ -95295,7 +95732,7 @@ async function runLogs(service, opts) {
|
|
|
95295
95732
|
return 0;
|
|
95296
95733
|
}
|
|
95297
95734
|
if (records.length === 0) {
|
|
95298
|
-
console.log(
|
|
95735
|
+
console.log(import_picocolors25.default.dim("No logs matched."));
|
|
95299
95736
|
return 0;
|
|
95300
95737
|
}
|
|
95301
95738
|
for (const r of records) {
|
|
@@ -95305,7 +95742,7 @@ async function runLogs(service, opts) {
|
|
|
95305
95742
|
const line2 = `${ts} ${lvl} ${comp} ${r.message.slice(0, 120)}`;
|
|
95306
95743
|
console.log(levelColor(r.level, line2));
|
|
95307
95744
|
for (const { key, value } of extractContextFields(r)) {
|
|
95308
|
-
console.log(
|
|
95745
|
+
console.log(import_picocolors25.default.dim(` ${key}: ${value.slice(0, 200)}`));
|
|
95309
95746
|
}
|
|
95310
95747
|
}
|
|
95311
95748
|
return 0;
|
|
@@ -95344,22 +95781,22 @@ async function runLogs(service, opts) {
|
|
|
95344
95781
|
return 0;
|
|
95345
95782
|
}
|
|
95346
95783
|
console.log(
|
|
95347
|
-
|
|
95784
|
+
import_picocolors25.default.bold(`Top ${field}`) + import_picocolors25.default.dim(
|
|
95348
95785
|
` \u2014 ${renv.project}/${renv.env}` + (resolvedService ? ` \xB7 service ${resolvedService}` : "") + (opts.grep ? ` \xB7 grep "${opts.grep}"` : "")
|
|
95349
95786
|
)
|
|
95350
95787
|
);
|
|
95351
|
-
console.log(
|
|
95788
|
+
console.log(import_picocolors25.default.dim(` index: ${indexPattern} \xB7 from: ${fromDisplay} UTC \xB7 severity: error+`));
|
|
95352
95789
|
console.log("");
|
|
95353
95790
|
if (buckets.length === 0) {
|
|
95354
|
-
console.log(
|
|
95355
|
-
console.log(
|
|
95791
|
+
console.log(import_picocolors25.default.dim(` No error logs with field "${field}" in the window.`));
|
|
95792
|
+
console.log(import_picocolors25.default.dim(` Tip: ensure "${field}" is an aggregatable (keyword) field.`));
|
|
95356
95793
|
return 0;
|
|
95357
95794
|
}
|
|
95358
95795
|
for (const b2 of buckets) {
|
|
95359
|
-
console.log(` ${
|
|
95796
|
+
console.log(` ${import_picocolors25.default.red(String(b2.count).padStart(6))} ${b2.key}`);
|
|
95360
95797
|
}
|
|
95361
95798
|
console.log("");
|
|
95362
|
-
console.log(
|
|
95799
|
+
console.log(import_picocolors25.default.dim(` ${buckets.length} distinct ${field} value(s) shown (top by error count).`));
|
|
95363
95800
|
return 0;
|
|
95364
95801
|
}
|
|
95365
95802
|
let analysis = await logs.analyzeErrors({
|
|
@@ -95426,46 +95863,46 @@ async function runLogs(service, opts) {
|
|
|
95426
95863
|
return 0;
|
|
95427
95864
|
}
|
|
95428
95865
|
console.log(
|
|
95429
|
-
|
|
95866
|
+
import_picocolors25.default.bold(`Error analysis`) + import_picocolors25.default.dim(
|
|
95430
95867
|
` \u2014 ${renv.project}/${renv.env}` + (scopeService ? ` \xB7 service ${scopeService}` : "") + (opts.grep ? ` \xB7 grep "${opts.grep}"` : "")
|
|
95431
95868
|
)
|
|
95432
95869
|
);
|
|
95433
|
-
console.log(
|
|
95870
|
+
console.log(import_picocolors25.default.dim(` index: ${indexPattern} \xB7 from: ${fromDisplay} UTC \xB7 severity: error+`));
|
|
95434
95871
|
if (broadeningNote) {
|
|
95435
|
-
console.log(
|
|
95872
|
+
console.log(import_picocolors25.default.yellow(` ${broadeningNote}`));
|
|
95436
95873
|
}
|
|
95437
95874
|
console.log(
|
|
95438
|
-
` ${analysis.totalErrors} error(s) \xB7 ${analysis.signatures.length} signature(s) \xB7 ${
|
|
95875
|
+
` ${analysis.totalErrors} error(s) \xB7 ${analysis.signatures.length} signature(s) \xB7 ${import_picocolors25.default.yellow(String(analysis.newSignatures.length))} new`
|
|
95439
95876
|
);
|
|
95440
95877
|
console.log("");
|
|
95441
95878
|
if (analysis.signatures.length === 0) {
|
|
95442
|
-
console.log(
|
|
95879
|
+
console.log(import_picocolors25.default.dim(" No error-level logs in the window."));
|
|
95443
95880
|
console.log(
|
|
95444
|
-
|
|
95881
|
+
import_picocolors25.default.dim(
|
|
95445
95882
|
` Searched: ${scopeService ? `service "${scopeService}"` : "all services"} \xB7 index: ${indexPattern} \xB7 from: ${fromDisplay} UTC`
|
|
95446
95883
|
)
|
|
95447
95884
|
);
|
|
95448
|
-
console.log(
|
|
95885
|
+
console.log(import_picocolors25.default.dim(` Tip: use --since to widen the window (e.g. --since 30d).`));
|
|
95449
95886
|
return 0;
|
|
95450
95887
|
}
|
|
95451
95888
|
for (const s of analysis.signatures) {
|
|
95452
95889
|
const tags = [];
|
|
95453
|
-
if (s.isNew) tags.push(
|
|
95890
|
+
if (s.isNew) tags.push(import_picocolors25.default.red("NEW"));
|
|
95454
95891
|
else if (s.ratio !== void 0 && Number.isFinite(s.ratio) && s.ratio >= 1.5) {
|
|
95455
|
-
tags.push(
|
|
95892
|
+
tags.push(import_picocolors25.default.yellow(`spike x${s.ratio.toFixed(1)}`));
|
|
95456
95893
|
}
|
|
95457
|
-
const svc = s.services.length > 0 ?
|
|
95894
|
+
const svc = s.services.length > 0 ? import_picocolors25.default.dim(` \xB7 ${s.services.slice(0, 3).join(", ")}`) : "";
|
|
95458
95895
|
const tagStr = tags.length > 0 ? ` [${tags.join(", ")}]` : "";
|
|
95459
95896
|
console.log(
|
|
95460
|
-
` ${
|
|
95897
|
+
` ${import_picocolors25.default.red(String(s.count).padStart(6))} ${import_picocolors25.default.bold(s.key.padEnd(14).slice(0, 14))} ` + import_picocolors25.default.dim(`first ${shortTs(s.firstSeen)} \xB7 last ${shortTs(s.lastSeen)}`) + svc + tagStr
|
|
95461
95898
|
);
|
|
95462
95899
|
}
|
|
95463
95900
|
if (analysis.affectedServices.length > 0) {
|
|
95464
95901
|
console.log("");
|
|
95465
|
-
console.log(` ${
|
|
95902
|
+
console.log(` ${import_picocolors25.default.bold("Affected services:")} ${analysis.affectedServices.join(", ")}`);
|
|
95466
95903
|
}
|
|
95467
95904
|
console.log("");
|
|
95468
|
-
console.log(
|
|
95905
|
+
console.log(import_picocolors25.default.dim(" (use --raw to see individual log lines)"));
|
|
95469
95906
|
if (opts.ai) {
|
|
95470
95907
|
const result = await renderAiInterpretation({
|
|
95471
95908
|
command: "logs",
|
|
@@ -95484,19 +95921,19 @@ async function runLogs(service, opts) {
|
|
|
95484
95921
|
});
|
|
95485
95922
|
console.log("\n" + renderInterpretation(result));
|
|
95486
95923
|
if (!result.ok) {
|
|
95487
|
-
console.error(
|
|
95924
|
+
console.error(import_picocolors25.default.yellow(`[ai] ${result.warning}`));
|
|
95488
95925
|
}
|
|
95489
95926
|
}
|
|
95490
95927
|
return 0;
|
|
95491
95928
|
} catch (err) {
|
|
95492
|
-
console.error(
|
|
95929
|
+
console.error(import_picocolors25.default.red(err.message));
|
|
95493
95930
|
return 1;
|
|
95494
95931
|
}
|
|
95495
95932
|
}
|
|
95496
95933
|
|
|
95497
95934
|
// ../../packages/cli/src/commands/metrics.ts
|
|
95498
95935
|
init_cjs_shims();
|
|
95499
|
-
var
|
|
95936
|
+
var import_picocolors26 = __toESM(require_picocolors(), 1);
|
|
95500
95937
|
var METRICS_AI_CONTRACT = `Provide a clearly separated AI evidence narration with:
|
|
95501
95938
|
|
|
95502
95939
|
Evidence used
|
|
@@ -95541,10 +95978,10 @@ function anomalyColor(anomaly) {
|
|
|
95541
95978
|
case "latency-spike":
|
|
95542
95979
|
case "error-rate-change":
|
|
95543
95980
|
case "throughput-drop":
|
|
95544
|
-
return
|
|
95981
|
+
return import_picocolors26.default.red;
|
|
95545
95982
|
case "queue-growth":
|
|
95546
95983
|
case "change":
|
|
95547
|
-
return
|
|
95984
|
+
return import_picocolors26.default.yellow;
|
|
95548
95985
|
default:
|
|
95549
95986
|
return (s) => s;
|
|
95550
95987
|
}
|
|
@@ -95571,7 +96008,7 @@ async function runMetrics(hint, opts) {
|
|
|
95571
96008
|
const metrics = metricsProviderFromConfig(config2);
|
|
95572
96009
|
if (metrics === null) {
|
|
95573
96010
|
console.error(
|
|
95574
|
-
|
|
96011
|
+
import_picocolors26.default.red(
|
|
95575
96012
|
"Grafana not configured \u2014 set GRAFANA_URL + GRAFANA_USER + GRAFANA_PASSWORD"
|
|
95576
96013
|
)
|
|
95577
96014
|
);
|
|
@@ -95579,7 +96016,7 @@ async function runMetrics(hint, opts) {
|
|
|
95579
96016
|
}
|
|
95580
96017
|
const health = await metrics.health();
|
|
95581
96018
|
if (!health.ok) {
|
|
95582
|
-
console.error(
|
|
96019
|
+
console.error(import_picocolors26.default.red(`Grafana unreachable: ${health.detail}`));
|
|
95583
96020
|
return 1;
|
|
95584
96021
|
}
|
|
95585
96022
|
const stepNum = opts.step !== void 0 ? Number(opts.step) : void 0;
|
|
@@ -95608,14 +96045,14 @@ async function runMetrics(hint, opts) {
|
|
|
95608
96045
|
return 0;
|
|
95609
96046
|
}
|
|
95610
96047
|
if (series.length === 0) {
|
|
95611
|
-
console.log(
|
|
96048
|
+
console.log(import_picocolors26.default.dim("No series returned."));
|
|
95612
96049
|
return 0;
|
|
95613
96050
|
}
|
|
95614
96051
|
for (const s of series) {
|
|
95615
96052
|
const summary = summarize(s);
|
|
95616
96053
|
const label = labelStr(s.labels);
|
|
95617
96054
|
console.log(
|
|
95618
|
-
` ${
|
|
96055
|
+
` ${import_picocolors26.default.cyan(label || "(no labels)")} last=${import_picocolors26.default.bold(fmtNum(summary.last))} avg=${fmtNum(summary.avg)}`
|
|
95619
96056
|
);
|
|
95620
96057
|
}
|
|
95621
96058
|
return 0;
|
|
@@ -95630,36 +96067,36 @@ async function runMetrics(hint, opts) {
|
|
|
95630
96067
|
if (findings2.length === 0) {
|
|
95631
96068
|
if (hint !== void 0) {
|
|
95632
96069
|
const tokens = extractHintTokens(hint);
|
|
95633
|
-
console.log(
|
|
96070
|
+
console.log(import_picocolors26.default.dim(`No panels matched hint "${hint}".`));
|
|
95634
96071
|
if (tokens.length > 0) {
|
|
95635
|
-
console.log(
|
|
96072
|
+
console.log(import_picocolors26.default.dim(` Searched for panels containing: ${tokens.join(", ")}`));
|
|
95636
96073
|
}
|
|
95637
96074
|
console.log(
|
|
95638
|
-
|
|
95639
|
-
` Tip: run ${
|
|
96075
|
+
import_picocolors26.default.dim(
|
|
96076
|
+
` Tip: run ${import_picocolors26.default.bold("horus metrics")} (no hint) to see all available panels, then use a panel title or keyword directly.`
|
|
95640
96077
|
)
|
|
95641
96078
|
);
|
|
95642
96079
|
} else {
|
|
95643
|
-
console.log(
|
|
96080
|
+
console.log(import_picocolors26.default.dim("No panels found in configured Grafana dashboards."));
|
|
95644
96081
|
}
|
|
95645
96082
|
return 0;
|
|
95646
96083
|
}
|
|
95647
96084
|
const hintSuffix = hint !== void 0 ? ` (hint: "${hint}")` : "";
|
|
95648
96085
|
const matchSources = hint !== void 0 ? [...new Set(findings2.map((f) => f.matchSource).filter(Boolean))] : [];
|
|
95649
|
-
const matchSuffix = matchSources.length > 0 ?
|
|
96086
|
+
const matchSuffix = matchSources.length > 0 ? import_picocolors26.default.dim(` [matched via ${matchSources.join(", ")}]`) : "";
|
|
95650
96087
|
console.log(
|
|
95651
|
-
|
|
96088
|
+
import_picocolors26.default.bold(
|
|
95652
96089
|
`Grafana metrics${hintSuffix} \u2014 ${findings2.length} series across panels`
|
|
95653
96090
|
) + matchSuffix
|
|
95654
96091
|
);
|
|
95655
96092
|
console.log(
|
|
95656
|
-
|
|
96093
|
+
import_picocolors26.default.dim(
|
|
95657
96094
|
` window: ${new Date(from * 1e3).toISOString()} \u2013 ${new Date(to * 1e3).toISOString()}`
|
|
95658
96095
|
)
|
|
95659
96096
|
);
|
|
95660
96097
|
console.log("");
|
|
95661
96098
|
if (flagged.length === 0) {
|
|
95662
|
-
console.log(
|
|
96099
|
+
console.log(import_picocolors26.default.green(" No anomalies detected."));
|
|
95663
96100
|
} else {
|
|
95664
96101
|
for (const f of flagged) {
|
|
95665
96102
|
const color = anomalyColor(f.anomaly);
|
|
@@ -95668,14 +96105,14 @@ async function runMetrics(hint, opts) {
|
|
|
95668
96105
|
const lblStr = labelStr(f.labels);
|
|
95669
96106
|
console.log(
|
|
95670
96107
|
color(
|
|
95671
|
-
` ${label.padEnd(22)} ${f.panelTitle.padEnd(40).slice(0, 40)} ${fmtNum(f.baselineAvg)} -> ${fmtNum(f.currentAvg)} (${ratioStr})` + (lblStr !== "" ? ` ${
|
|
96108
|
+
` ${label.padEnd(22)} ${f.panelTitle.padEnd(40).slice(0, 40)} ${fmtNum(f.baselineAvg)} -> ${fmtNum(f.currentAvg)} (${ratioStr})` + (lblStr !== "" ? ` ${import_picocolors26.default.dim(lblStr)}` : "")
|
|
95672
96109
|
)
|
|
95673
96110
|
);
|
|
95674
96111
|
}
|
|
95675
96112
|
}
|
|
95676
96113
|
if (ok.length > 0) {
|
|
95677
96114
|
console.log("");
|
|
95678
|
-
console.log(
|
|
96115
|
+
console.log(import_picocolors26.default.dim(` ${ok.length} panel series with no anomaly.`));
|
|
95679
96116
|
}
|
|
95680
96117
|
if (opts.ai) {
|
|
95681
96118
|
const result = await renderAiInterpretation({
|
|
@@ -95690,19 +96127,19 @@ async function runMetrics(hint, opts) {
|
|
|
95690
96127
|
});
|
|
95691
96128
|
console.log("\n" + renderInterpretation(result));
|
|
95692
96129
|
if (!result.ok) {
|
|
95693
|
-
console.error(
|
|
96130
|
+
console.error(import_picocolors26.default.yellow(`[ai] ${result.warning}`));
|
|
95694
96131
|
}
|
|
95695
96132
|
}
|
|
95696
96133
|
return 0;
|
|
95697
96134
|
} catch (err) {
|
|
95698
|
-
console.error(
|
|
96135
|
+
console.error(import_picocolors26.default.red(err.message));
|
|
95699
96136
|
return 1;
|
|
95700
96137
|
}
|
|
95701
96138
|
}
|
|
95702
96139
|
|
|
95703
96140
|
// ../../packages/cli/src/commands/state.ts
|
|
95704
96141
|
init_cjs_shims();
|
|
95705
|
-
var
|
|
96142
|
+
var import_picocolors27 = __toESM(require_picocolors(), 1);
|
|
95706
96143
|
var STATE_AI_CONTRACT = `Provide a clearly separated AI evidence narration with:
|
|
95707
96144
|
|
|
95708
96145
|
Evidence used
|
|
@@ -95728,13 +96165,13 @@ async function runState(opts) {
|
|
|
95728
96165
|
try {
|
|
95729
96166
|
renv = resolveEnvironment(config2, { project: opts.project, env: opts.env });
|
|
95730
96167
|
} catch (err) {
|
|
95731
|
-
console.error(
|
|
96168
|
+
console.error(import_picocolors27.default.red(err.message));
|
|
95732
96169
|
return 1;
|
|
95733
96170
|
}
|
|
95734
96171
|
const mongo = mongoForEnv(renv);
|
|
95735
96172
|
if (mongo === null) {
|
|
95736
96173
|
console.error(
|
|
95737
|
-
|
|
96174
|
+
import_picocolors27.default.red(
|
|
95738
96175
|
`No MongoDB connector configured for ${renv.project}/${renv.env} (set the project's Mongo URL env var).`
|
|
95739
96176
|
)
|
|
95740
96177
|
);
|
|
@@ -95742,7 +96179,7 @@ async function runState(opts) {
|
|
|
95742
96179
|
}
|
|
95743
96180
|
const health = await mongo.health();
|
|
95744
96181
|
if (!health.ok) {
|
|
95745
|
-
console.error(
|
|
96182
|
+
console.error(import_picocolors27.default.red(`MongoDB unreachable: ${health.detail}`));
|
|
95746
96183
|
await mongo.close();
|
|
95747
96184
|
return 1;
|
|
95748
96185
|
}
|
|
@@ -95768,38 +96205,38 @@ async function runState(opts) {
|
|
|
95768
96205
|
);
|
|
95769
96206
|
return 0;
|
|
95770
96207
|
}
|
|
95771
|
-
const discoveryNote = analysis.autoDiscovered ?
|
|
96208
|
+
const discoveryNote = analysis.autoDiscovered ? import_picocolors27.default.dim(` (${analysis.collections.length} collections, auto-discovered)`) : "";
|
|
95772
96209
|
console.log(
|
|
95773
|
-
|
|
96210
|
+
import_picocolors27.default.bold("State analysis") + import_picocolors27.default.dim(` \u2014 ${renv.project}/${renv.env} \xB7 db ${analysis.database}`) + discoveryNote
|
|
95774
96211
|
);
|
|
95775
96212
|
console.log("");
|
|
95776
96213
|
let signals = 0;
|
|
95777
96214
|
for (const c of analysis.collections) {
|
|
95778
96215
|
const flags = [];
|
|
95779
96216
|
if (c.isStale === true) {
|
|
95780
|
-
flags.push(
|
|
96217
|
+
flags.push(import_picocolors27.default.yellow(`stale (last ${c.dateField}, ~${Math.round(c.ageHours ?? 0)}h)`));
|
|
95781
96218
|
}
|
|
95782
96219
|
for (const a of c.anomalies) {
|
|
95783
|
-
flags.push(
|
|
96220
|
+
flags.push(import_picocolors27.default.red(`${a.count}\xD7 "${a.value}"`));
|
|
95784
96221
|
signals += 1;
|
|
95785
96222
|
}
|
|
95786
96223
|
if (c.isStale === true) signals += 1;
|
|
95787
|
-
const head = ` ${
|
|
95788
|
-
console.log(flags.length > 0 ? `${head} ${flags.join(" ")}` :
|
|
96224
|
+
const head = ` ${import_picocolors27.default.bold(c.collection.padEnd(18).slice(0, 18))} ${import_picocolors27.default.dim(String(c.count).padStart(8) + " docs")}`;
|
|
96225
|
+
console.log(flags.length > 0 ? `${head} ${flags.join(" ")}` : import_picocolors27.default.dim(head));
|
|
95789
96226
|
}
|
|
95790
96227
|
console.log("");
|
|
95791
96228
|
if (analysis.collections.length === 0) {
|
|
95792
96229
|
console.log(
|
|
95793
|
-
|
|
96230
|
+
import_picocolors27.default.yellow(" No collections discovered in this database.") + import_picocolors27.default.dim(" Verify the database name in your MongoDB connector config.")
|
|
95794
96231
|
);
|
|
95795
96232
|
} else {
|
|
95796
96233
|
const scope = analysis.autoDiscovered ? "collection(s)" : "allowlisted collection(s)";
|
|
95797
96234
|
console.log(
|
|
95798
|
-
signals > 0 ? ` ${
|
|
96235
|
+
signals > 0 ? ` ${import_picocolors27.default.bold(String(signals))} state signal(s) across ${analysis.collections.length} ${scope}` : import_picocolors27.default.dim(` No state anomalies across ${analysis.collections.length} ${scope}.`)
|
|
95799
96236
|
);
|
|
95800
96237
|
if (analysis.autoDiscovered) {
|
|
95801
96238
|
console.log(
|
|
95802
|
-
|
|
96239
|
+
import_picocolors27.default.dim(
|
|
95803
96240
|
` Tip: add a "collections" list to your MongoDB connector config to restrict analysis.`
|
|
95804
96241
|
)
|
|
95805
96242
|
);
|
|
@@ -95817,7 +96254,7 @@ async function runState(opts) {
|
|
|
95817
96254
|
});
|
|
95818
96255
|
console.log("\n" + renderInterpretation(result));
|
|
95819
96256
|
if (!result.ok) {
|
|
95820
|
-
console.error(
|
|
96257
|
+
console.error(import_picocolors27.default.yellow(`[ai] ${result.warning}`));
|
|
95821
96258
|
}
|
|
95822
96259
|
}
|
|
95823
96260
|
return 0;
|
|
@@ -95825,20 +96262,20 @@ async function runState(opts) {
|
|
|
95825
96262
|
await mongo.close();
|
|
95826
96263
|
}
|
|
95827
96264
|
} catch (err) {
|
|
95828
|
-
console.error(
|
|
96265
|
+
console.error(import_picocolors27.default.red(err.message));
|
|
95829
96266
|
return 1;
|
|
95830
96267
|
}
|
|
95831
96268
|
}
|
|
95832
96269
|
|
|
95833
96270
|
// ../../packages/cli/src/commands/init.ts
|
|
95834
96271
|
init_cjs_shims();
|
|
95835
|
-
var
|
|
95836
|
-
var
|
|
96272
|
+
var import_picocolors28 = __toESM(require_picocolors(), 1);
|
|
96273
|
+
var import_node_path17 = require("path");
|
|
95837
96274
|
async function runInit(opts) {
|
|
95838
96275
|
try {
|
|
95839
96276
|
const cwd = process.cwd();
|
|
95840
|
-
const root = opts.path ? (0,
|
|
95841
|
-
const name = opts.name ?? (0,
|
|
96277
|
+
const root = opts.path ? (0, import_node_path17.resolve)(opts.path) : findRepoRoot(cwd) ?? cwd;
|
|
96278
|
+
const name = opts.name ?? (0, import_node_path17.basename)(root);
|
|
95842
96279
|
const envName = opts.env ?? "production";
|
|
95843
96280
|
const repo = { name, path: root };
|
|
95844
96281
|
if (opts.source) repo["source"] = { hostUrl: opts.source };
|
|
@@ -95853,65 +96290,65 @@ async function runInit(opts) {
|
|
|
95853
96290
|
const configPath = writeLocalConfig(root, file);
|
|
95854
96291
|
registerProject(name, root, configPath);
|
|
95855
96292
|
ensureProjectGitignore(root);
|
|
95856
|
-
console.log(`${
|
|
95857
|
-
console.log(
|
|
95858
|
-
console.log(
|
|
96293
|
+
console.log(`${import_picocolors28.default.green("\u2713")} Initialized Horus project ${import_picocolors28.default.bold(name)}`);
|
|
96294
|
+
console.log(import_picocolors28.default.dim(` config: ${configPath}`));
|
|
96295
|
+
console.log(import_picocolors28.default.dim(` registered: horus investigate --name ${name} "<hint>"`));
|
|
95859
96296
|
if (!opts.source) {
|
|
95860
96297
|
console.log(
|
|
95861
|
-
|
|
96298
|
+
import_picocolors28.default.dim(" no source-intelligence host set \u2014 run `horus index` to analyze + host, or pass --source <url>")
|
|
95862
96299
|
);
|
|
95863
96300
|
}
|
|
95864
96301
|
console.log(
|
|
95865
|
-
|
|
96302
|
+
import_picocolors28.default.dim(" add runtime connectors (elasticsearch/mongodb/grafana) to .horus/config.json")
|
|
95866
96303
|
);
|
|
95867
96304
|
console.log(
|
|
95868
|
-
|
|
96305
|
+
import_picocolors28.default.dim(" .horus/ is gitignored \u2014 local config and runtime state stay out of version control")
|
|
95869
96306
|
);
|
|
95870
96307
|
return 0;
|
|
95871
96308
|
} catch (err) {
|
|
95872
|
-
console.error(
|
|
96309
|
+
console.error(import_picocolors28.default.red(err.message));
|
|
95873
96310
|
return 1;
|
|
95874
96311
|
}
|
|
95875
96312
|
}
|
|
95876
96313
|
|
|
95877
96314
|
// ../../packages/cli/src/commands/projects.ts
|
|
95878
96315
|
init_cjs_shims();
|
|
95879
|
-
var
|
|
96316
|
+
var import_picocolors29 = __toESM(require_picocolors(), 1);
|
|
95880
96317
|
async function runProjects() {
|
|
95881
96318
|
const reg = readRegistry();
|
|
95882
96319
|
const names = Object.keys(reg.projects).sort();
|
|
95883
96320
|
if (names.length === 0) {
|
|
95884
96321
|
console.log(
|
|
95885
|
-
|
|
96322
|
+
import_picocolors29.default.dim("No registered projects. Run `horus index` (or `horus init`) inside a repo.")
|
|
95886
96323
|
);
|
|
95887
96324
|
return 0;
|
|
95888
96325
|
}
|
|
95889
|
-
console.log(
|
|
96326
|
+
console.log(import_picocolors29.default.bold("Registered Horus projects"));
|
|
95890
96327
|
console.log("");
|
|
95891
96328
|
for (const name of names) {
|
|
95892
96329
|
const entry2 = reg.projects[name];
|
|
95893
96330
|
if (entry2 === void 0) continue;
|
|
95894
|
-
console.log(` ${
|
|
96331
|
+
console.log(` ${import_picocolors29.default.bold(name.padEnd(22))} ${import_picocolors29.default.dim(entry2.root)}`);
|
|
95895
96332
|
}
|
|
95896
96333
|
console.log("");
|
|
95897
|
-
console.log(
|
|
96334
|
+
console.log(import_picocolors29.default.dim(' horus investigate --name <name> "<hint>"'));
|
|
95898
96335
|
return 0;
|
|
95899
96336
|
}
|
|
95900
96337
|
|
|
95901
96338
|
// ../../packages/cli/src/commands/setup.ts
|
|
95902
96339
|
init_cjs_shims();
|
|
95903
|
-
var
|
|
96340
|
+
var import_picocolors30 = __toESM(require_picocolors(), 1);
|
|
95904
96341
|
var DEFAULT_DB_URL3 = "postgresql://horus:horus@localhost:5433/horus";
|
|
95905
96342
|
async function runSetup(opts) {
|
|
95906
96343
|
const write = opts.write ?? ((line2) => console.log(line2));
|
|
95907
96344
|
let ok = true;
|
|
95908
|
-
write(
|
|
96345
|
+
write(import_picocolors30.default.bold("\nHorus setup\n"));
|
|
95909
96346
|
const backendVersion = await getSourceVersion();
|
|
95910
96347
|
if (backendVersion === null) {
|
|
95911
96348
|
ok = false;
|
|
95912
|
-
write(` ${
|
|
96349
|
+
write(` ${import_picocolors30.default.red("\u25CF")} Horus source-intelligence backend not found`);
|
|
95913
96350
|
write(
|
|
95914
|
-
|
|
96351
|
+
import_picocolors30.default.dim(
|
|
95915
96352
|
` install it (Python 3.11+ required):
|
|
95916
96353
|
pip install horus-source
|
|
95917
96354
|
ensure ~/.local/bin is on your PATH`
|
|
@@ -95920,17 +96357,17 @@ async function runSetup(opts) {
|
|
|
95920
96357
|
} else if (backendVersion !== PINNED_SOURCE_VERSION) {
|
|
95921
96358
|
ok = false;
|
|
95922
96359
|
write(
|
|
95923
|
-
` ${
|
|
96360
|
+
` ${import_picocolors30.default.yellow("\u25CF")} Horus source-intelligence backend version mismatch` + import_picocolors30.default.dim(` (installed: ${backendVersion}, required: ${PINNED_SOURCE_VERSION})`)
|
|
95924
96361
|
);
|
|
95925
96362
|
write(
|
|
95926
|
-
|
|
96363
|
+
import_picocolors30.default.dim(
|
|
95927
96364
|
` update it:
|
|
95928
96365
|
pip install --upgrade horus-source`
|
|
95929
96366
|
)
|
|
95930
96367
|
);
|
|
95931
96368
|
} else {
|
|
95932
96369
|
write(
|
|
95933
|
-
` ${
|
|
96370
|
+
` ${import_picocolors30.default.green("\u25CF")} Horus source-intelligence backend ` + import_picocolors30.default.dim(`(${backendVersion})`)
|
|
95934
96371
|
);
|
|
95935
96372
|
}
|
|
95936
96373
|
let dbUrl = process.env["DATABASE_URL"] ?? DEFAULT_DB_URL3;
|
|
@@ -95942,11 +96379,11 @@ async function runSetup(opts) {
|
|
|
95942
96379
|
}
|
|
95943
96380
|
const db = await checkDatabase(dbUrl);
|
|
95944
96381
|
if (db.reachable) {
|
|
95945
|
-
write(` ${
|
|
96382
|
+
write(` ${import_picocolors30.default.green("\u25CF")} Postgres reachable ${import_picocolors30.default.dim(`(${db.schemaDetail})`)}`);
|
|
95946
96383
|
if (!db.schemaReady) {
|
|
95947
96384
|
ok = false;
|
|
95948
96385
|
write(
|
|
95949
|
-
|
|
96386
|
+
import_picocolors30.default.dim(
|
|
95950
96387
|
` schema not applied \u2014 run migrations:
|
|
95951
96388
|
from the Horus repo: pnpm db migrate
|
|
95952
96389
|
or apply the schema directly: https://github.com/meritt-dev/horus/tree/master/packages/db/drizzle`
|
|
@@ -95955,9 +96392,9 @@ async function runSetup(opts) {
|
|
|
95955
96392
|
}
|
|
95956
96393
|
} else {
|
|
95957
96394
|
ok = false;
|
|
95958
|
-
write(` ${
|
|
96395
|
+
write(` ${import_picocolors30.default.red("\u25CF")} Postgres unreachable`);
|
|
95959
96396
|
write(
|
|
95960
|
-
|
|
96397
|
+
import_picocolors30.default.dim(
|
|
95961
96398
|
` start a local instance:
|
|
95962
96399
|
docker run -d --name horus-db \\
|
|
95963
96400
|
-e POSTGRES_USER=horus -e POSTGRES_PASSWORD=horus -e POSTGRES_DB=horus \\
|
|
@@ -95982,10 +96419,10 @@ async function runSetup(opts) {
|
|
|
95982
96419
|
if (!health.ok) {
|
|
95983
96420
|
ok = false;
|
|
95984
96421
|
write(
|
|
95985
|
-
` ${
|
|
96422
|
+
` ${import_picocolors30.default.red("\u25CF")} Source intelligence host unreachable for ${import_picocolors30.default.bold(repo.name)} ` + import_picocolors30.default.dim(`(${repoHostUrl})`)
|
|
95986
96423
|
);
|
|
95987
96424
|
write(
|
|
95988
|
-
|
|
96425
|
+
import_picocolors30.default.dim(
|
|
95989
96426
|
` start the source intelligence host:
|
|
95990
96427
|
cd ${repo.path}
|
|
95991
96428
|
horus index`
|
|
@@ -95996,10 +96433,10 @@ async function runSetup(opts) {
|
|
|
95996
96433
|
if (count === 0) {
|
|
95997
96434
|
ok = false;
|
|
95998
96435
|
write(
|
|
95999
|
-
` ${
|
|
96436
|
+
` ${import_picocolors30.default.yellow("\u25CF")} Source intelligence host running but ${import_picocolors30.default.bold(repo.name)} is not indexed`
|
|
96000
96437
|
);
|
|
96001
96438
|
write(
|
|
96002
|
-
|
|
96439
|
+
import_picocolors30.default.dim(
|
|
96003
96440
|
` index the repo:
|
|
96004
96441
|
cd ${repo.path}
|
|
96005
96442
|
horus index`
|
|
@@ -96007,7 +96444,7 @@ async function runSetup(opts) {
|
|
|
96007
96444
|
);
|
|
96008
96445
|
} else {
|
|
96009
96446
|
write(
|
|
96010
|
-
` ${
|
|
96447
|
+
` ${import_picocolors30.default.green("\u25CF")} ${import_picocolors30.default.bold(repo.name)} \u2014 ${count} nodes indexed ` + import_picocolors30.default.dim(`(${repoHostUrl})`)
|
|
96011
96448
|
);
|
|
96012
96449
|
}
|
|
96013
96450
|
}
|
|
@@ -96017,10 +96454,10 @@ async function runSetup(opts) {
|
|
|
96017
96454
|
write("");
|
|
96018
96455
|
if (ok) {
|
|
96019
96456
|
write(
|
|
96020
|
-
|
|
96457
|
+
import_picocolors30.default.green("Ready.") + ' Next: `cd` into a repo and run `horus index`, then `horus investigate "<hint>"`.'
|
|
96021
96458
|
);
|
|
96022
96459
|
} else {
|
|
96023
|
-
write(
|
|
96460
|
+
write(import_picocolors30.default.yellow("Resolve the items above, then re-run `horus setup`."));
|
|
96024
96461
|
}
|
|
96025
96462
|
return ok ? 0 : 1;
|
|
96026
96463
|
}
|
|
@@ -96029,12 +96466,12 @@ async function runSetup(opts) {
|
|
|
96029
96466
|
init_cjs_shims();
|
|
96030
96467
|
var import_node_readline = require("readline");
|
|
96031
96468
|
var import_node_child_process6 = require("child_process");
|
|
96032
|
-
var
|
|
96469
|
+
var import_picocolors33 = __toESM(require_picocolors(), 1);
|
|
96033
96470
|
|
|
96034
96471
|
// ../../packages/cli/src/lib/tty-selector.ts
|
|
96035
96472
|
init_cjs_shims();
|
|
96036
96473
|
var import_node_tty = require("tty");
|
|
96037
|
-
var
|
|
96474
|
+
var import_picocolors31 = __toESM(require_picocolors(), 1);
|
|
96038
96475
|
var ExitPromptError = class extends Error {
|
|
96039
96476
|
constructor(message = "Prompt was cancelled") {
|
|
96040
96477
|
super(message);
|
|
@@ -96090,7 +96527,7 @@ async function checkboxSearch(opts) {
|
|
|
96090
96527
|
clear();
|
|
96091
96528
|
const lines = [];
|
|
96092
96529
|
lines.push(
|
|
96093
|
-
`? ${
|
|
96530
|
+
`? ${import_picocolors31.default.bold(message)} ${import_picocolors31.default.dim("(\u2191\u2193 navigate \u2022 space toggle \u2022 enter confirm \u2022 type filter)")}`
|
|
96094
96531
|
);
|
|
96095
96532
|
const visible = filtered.slice(visibleOffset, visibleOffset + pageSize);
|
|
96096
96533
|
for (let i = 0; i < visible.length; i++) {
|
|
@@ -96098,29 +96535,29 @@ async function checkboxSearch(opts) {
|
|
|
96098
96535
|
const choice = visible[i];
|
|
96099
96536
|
const isCursor = idx === cursor;
|
|
96100
96537
|
const isSelected = selected.has(choice);
|
|
96101
|
-
const marker = isSelected ?
|
|
96538
|
+
const marker = isSelected ? import_picocolors31.default.green("\u25CF") : " ";
|
|
96102
96539
|
const prefix = `[${marker}]`;
|
|
96103
|
-
const label = isCursor ?
|
|
96104
|
-
const pointer = isCursor ?
|
|
96540
|
+
const label = isCursor ? import_picocolors31.default.cyan(choice) : choice;
|
|
96541
|
+
const pointer = isCursor ? import_picocolors31.default.cyan("\u276F") : " ";
|
|
96105
96542
|
lines.push(` ${pointer} ${prefix} ${label}`);
|
|
96106
96543
|
}
|
|
96107
96544
|
if (filtered.length === 0) {
|
|
96108
|
-
lines.push(
|
|
96545
|
+
lines.push(import_picocolors31.default.dim(" No matches"));
|
|
96109
96546
|
}
|
|
96110
96547
|
const statusParts = [
|
|
96111
96548
|
`${selected.size} selected`,
|
|
96112
96549
|
`${filtered.length}/${choices.length} matches`
|
|
96113
96550
|
];
|
|
96114
96551
|
if (filter) statusParts.push(`filter: ${filter}`);
|
|
96115
|
-
lines.push(
|
|
96552
|
+
lines.push(import_picocolors31.default.dim(` ${statusParts.join(" \xB7 ")}`));
|
|
96116
96553
|
output.write(lines.join("\n"));
|
|
96117
96554
|
lastRenderLines = lines.length;
|
|
96118
96555
|
}
|
|
96119
96556
|
function finish(values2) {
|
|
96120
96557
|
cleanup();
|
|
96121
|
-
const summary = values2.length > 0 ? values2.join(", ") :
|
|
96558
|
+
const summary = values2.length > 0 ? values2.join(", ") : import_picocolors31.default.dim("none");
|
|
96122
96559
|
output.write(`
|
|
96123
|
-
? ${
|
|
96560
|
+
? ${import_picocolors31.default.bold(message)} ${summary}
|
|
96124
96561
|
`);
|
|
96125
96562
|
resolve8(values2);
|
|
96126
96563
|
}
|
|
@@ -96212,7 +96649,7 @@ async function checkboxSearch(opts) {
|
|
|
96212
96649
|
// ../../packages/cli/src/commands/connect-ai.ts
|
|
96213
96650
|
init_cjs_shims();
|
|
96214
96651
|
var import_node_child_process5 = require("child_process");
|
|
96215
|
-
var
|
|
96652
|
+
var import_picocolors32 = __toESM(require_picocolors(), 1);
|
|
96216
96653
|
function cliInstalled(id) {
|
|
96217
96654
|
const r = (0, import_node_child_process5.spawnSync)(id, ["--version"], { stdio: "ignore", timeout: 2e3 });
|
|
96218
96655
|
return !r.error;
|
|
@@ -96240,13 +96677,13 @@ async function runConnectAi(opts) {
|
|
|
96240
96677
|
const root = findRepoRoot(cwd) ?? cwd;
|
|
96241
96678
|
const configPath = discoverLocalConfig(cwd) ?? localConfigPath(root);
|
|
96242
96679
|
const installed = LOCAL_PROVIDER_IDS.filter((id) => cliInstalled(id));
|
|
96243
|
-
console.log(
|
|
96680
|
+
console.log(import_picocolors32.default.bold("\nAI providers"));
|
|
96244
96681
|
console.log(
|
|
96245
|
-
|
|
96682
|
+
import_picocolors32.default.dim(
|
|
96246
96683
|
` Local CLIs on PATH: ${installed.length > 0 ? installed.join(", ") : "none detected"}`
|
|
96247
96684
|
)
|
|
96248
96685
|
);
|
|
96249
|
-
console.log(
|
|
96686
|
+
console.log(import_picocolors32.default.dim(" Cloud: anthropic (Anthropic Claude API \u2014 used by `investigate --ai`)\n"));
|
|
96250
96687
|
let provider = opts.provider;
|
|
96251
96688
|
if (provider === void 0) {
|
|
96252
96689
|
if (isInteractive()) {
|
|
@@ -96257,7 +96694,7 @@ async function runConnectAi(opts) {
|
|
|
96257
96694
|
}
|
|
96258
96695
|
}
|
|
96259
96696
|
if (!AI_PROVIDERS.includes(provider)) {
|
|
96260
|
-
console.error(
|
|
96697
|
+
console.error(import_picocolors32.default.red(`Unknown AI provider: ${provider}`) + import_picocolors32.default.dim(`
|
|
96261
96698
|
supported: ${AI_PROVIDERS.join(", ")}`));
|
|
96262
96699
|
return 1;
|
|
96263
96700
|
}
|
|
@@ -96270,7 +96707,7 @@ async function runConnectAi(opts) {
|
|
|
96270
96707
|
}
|
|
96271
96708
|
if (!apiKey) {
|
|
96272
96709
|
console.error(
|
|
96273
|
-
|
|
96710
|
+
import_picocolors32.default.red("No API key provided.") + import_picocolors32.default.dim("\n Pass --api-key sk-ant-\u2026 or set ANTHROPIC_API_KEY and re-run.")
|
|
96274
96711
|
);
|
|
96275
96712
|
return 1;
|
|
96276
96713
|
}
|
|
@@ -96278,28 +96715,28 @@ async function runConnectAi(opts) {
|
|
|
96278
96715
|
const probe2 = await probeAnthropic(apiKey);
|
|
96279
96716
|
if (!probe2.ok) {
|
|
96280
96717
|
console.error(`
|
|
96281
|
-
${
|
|
96282
|
-
console.error(
|
|
96718
|
+
${import_picocolors32.default.red("\u2717 Anthropic key check failed:")} ${probe2.detail}`);
|
|
96719
|
+
console.error(import_picocolors32.default.dim(" Fix the key and retry, or pass --no-test to skip."));
|
|
96283
96720
|
return 1;
|
|
96284
96721
|
}
|
|
96285
96722
|
console.log(`
|
|
96286
|
-
${
|
|
96723
|
+
${import_picocolors32.default.green("\u2713")} anthropic ${import_picocolors32.default.dim(`(${probe2.detail})`)}`);
|
|
96287
96724
|
}
|
|
96288
96725
|
if (opts.model) aiBlock["anthropic"] = { model: opts.model };
|
|
96289
96726
|
storedKey = apiKey;
|
|
96290
96727
|
} else {
|
|
96291
96728
|
if (!installed.includes(provider)) {
|
|
96292
96729
|
console.error(
|
|
96293
|
-
|
|
96730
|
+
import_picocolors32.default.red(`${provider} CLI not found on PATH.`) + import_picocolors32.default.dim(`
|
|
96294
96731
|
Install it first, or choose anthropic.`)
|
|
96295
96732
|
);
|
|
96296
96733
|
return 1;
|
|
96297
96734
|
}
|
|
96298
96735
|
const desc2 = DEFAULT_LOCAL_PROVIDER_REGISTRY.get(provider);
|
|
96299
96736
|
console.log(`
|
|
96300
|
-
${
|
|
96737
|
+
${import_picocolors32.default.green("\u2713")} ${desc2?.displayName ?? provider} ${import_picocolors32.default.dim("detected on PATH")}`);
|
|
96301
96738
|
console.log(
|
|
96302
|
-
|
|
96739
|
+
import_picocolors32.default.dim(
|
|
96303
96740
|
" Note: `investigate --ai` currently uses the Anthropic API for narrative.\n Local-CLI narrative generation is recorded as your preference for future use."
|
|
96304
96741
|
)
|
|
96305
96742
|
);
|
|
@@ -96317,15 +96754,15 @@ ${import_picocolors31.default.green("\u2713")} ${desc2?.displayName ?? provider}
|
|
|
96317
96754
|
});
|
|
96318
96755
|
}
|
|
96319
96756
|
console.log(`
|
|
96320
|
-
${
|
|
96321
|
-
console.log(
|
|
96757
|
+
${import_picocolors32.default.green("\u2713")} ${import_picocolors32.default.bold("ai")} provider saved \u2192 ${import_picocolors32.default.dim(configPath)}`);
|
|
96758
|
+
console.log(import_picocolors32.default.dim(` provider: ${provider}`));
|
|
96322
96759
|
if (storedKey && secretsPathStr) {
|
|
96323
|
-
console.log(
|
|
96760
|
+
console.log(import_picocolors32.default.dim(` anthropic key: ${redactKey(storedKey)} \u2192 ${secretsPathStr} (gitignored)`));
|
|
96324
96761
|
}
|
|
96325
|
-
console.log(
|
|
96762
|
+
console.log(import_picocolors32.default.dim(' run: horus investigate "<hint>" --ai'));
|
|
96326
96763
|
return 0;
|
|
96327
96764
|
} catch (err) {
|
|
96328
|
-
console.error(
|
|
96765
|
+
console.error(import_picocolors32.default.red(err instanceof Error ? err.message : String(err)));
|
|
96329
96766
|
return 1;
|
|
96330
96767
|
}
|
|
96331
96768
|
}
|
|
@@ -96357,7 +96794,7 @@ async function runConnect(type, opts) {
|
|
|
96357
96794
|
}
|
|
96358
96795
|
if (!SUPPORTED.includes(type)) {
|
|
96359
96796
|
console.error(
|
|
96360
|
-
|
|
96797
|
+
import_picocolors33.default.red(`Unknown connector type: ${type}`) + import_picocolors33.default.dim(`
|
|
96361
96798
|
supported: ${SUPPORTED.join(", ")}, ai`)
|
|
96362
96799
|
);
|
|
96363
96800
|
return 1;
|
|
@@ -96388,20 +96825,20 @@ async function runConnect(type, opts) {
|
|
|
96388
96825
|
if (!probeResult.ok) {
|
|
96389
96826
|
console.error(
|
|
96390
96827
|
`
|
|
96391
|
-
${
|
|
96828
|
+
${import_picocolors33.default.red(`\u2717 Could not reach ${connectorType}:`)} ${probeResult.detail}` + import_picocolors33.default.dim("\n Fix the connection and retry, or pass --no-test to skip.")
|
|
96392
96829
|
);
|
|
96393
96830
|
return 1;
|
|
96394
96831
|
}
|
|
96395
96832
|
console.log(
|
|
96396
96833
|
`
|
|
96397
|
-
${
|
|
96834
|
+
${import_picocolors33.default.green("\u2713")} ${connectorType} reachable ${import_picocolors33.default.dim(`(${probeResult.detail})`)}`
|
|
96398
96835
|
);
|
|
96399
96836
|
}
|
|
96400
96837
|
const hasLiteralCredentials = filled.url !== void 0 || filled.password !== void 0 || filled.username !== void 0;
|
|
96401
96838
|
if (hasLiteralCredentials) {
|
|
96402
96839
|
if (isGitTracked(configPath, root)) {
|
|
96403
96840
|
console.error(
|
|
96404
|
-
|
|
96841
|
+
import_picocolors33.default.red(".horus/config.json is already tracked by Git.") + "\nStoring credentials here would expose them in the repository.\n" + import_picocolors33.default.dim(
|
|
96405
96842
|
" Option A \u2014 remove from Git index then re-run:\n git rm --cached .horus/config.json\n horus connect " + type + " ...\n\n Option B \u2014 keep credentials in the environment and reference them:\n export ES_URL=https://...\n export ES_USERNAME=...\n export ES_PASSWORD=...\n Then edit .horus/config.json manually to use urlEnv/usernameEnv/passwordEnv."
|
|
96406
96843
|
)
|
|
96407
96844
|
);
|
|
@@ -96411,18 +96848,18 @@ ${import_picocolors32.default.green("\u2713")} ${connectorType} reachable ${impo
|
|
|
96411
96848
|
}
|
|
96412
96849
|
patchLocalConnector(configPath, connectorType, patch, filled.env);
|
|
96413
96850
|
console.log(
|
|
96414
|
-
`${
|
|
96851
|
+
`${import_picocolors33.default.green("\u2713")} ${import_picocolors33.default.bold(connectorType)} connector saved \u2192 ${import_picocolors33.default.dim(configPath)}`
|
|
96415
96852
|
);
|
|
96416
96853
|
printSummary(connectorType, filled);
|
|
96417
|
-
console.log(
|
|
96854
|
+
console.log(import_picocolors33.default.dim(`
|
|
96418
96855
|
run: horus investigate "<hint>"`));
|
|
96419
96856
|
return 0;
|
|
96420
96857
|
} catch (err) {
|
|
96421
96858
|
if (err instanceof ExitPromptError) {
|
|
96422
|
-
console.error(
|
|
96859
|
+
console.error(import_picocolors33.default.red("Cancelled."));
|
|
96423
96860
|
return 1;
|
|
96424
96861
|
}
|
|
96425
|
-
console.error(
|
|
96862
|
+
console.error(import_picocolors33.default.red(err.message));
|
|
96426
96863
|
return 1;
|
|
96427
96864
|
}
|
|
96428
96865
|
}
|
|
@@ -96431,7 +96868,7 @@ async function fillInteractive(type, opts) {
|
|
|
96431
96868
|
if (!needsInteraction) return opts;
|
|
96432
96869
|
console.log(
|
|
96433
96870
|
`
|
|
96434
|
-
${
|
|
96871
|
+
${import_picocolors33.default.bold(`Connect ${type}`)} ${import_picocolors33.default.dim("(press Enter to skip optional fields)")}
|
|
96435
96872
|
`
|
|
96436
96873
|
);
|
|
96437
96874
|
const filled = { ...opts };
|
|
@@ -96486,7 +96923,7 @@ ${import_picocolors32.default.bold(`Connect ${type}`)} ${import_picocolors32.def
|
|
|
96486
96923
|
break;
|
|
96487
96924
|
case "redis": {
|
|
96488
96925
|
console.log(
|
|
96489
|
-
|
|
96926
|
+
import_picocolors33.default.dim(
|
|
96490
96927
|
" Tip: embed credentials directly in the URL \u2014 redis://:password@host:6379\n or enter the URL and password separately below."
|
|
96491
96928
|
)
|
|
96492
96929
|
);
|
|
@@ -96524,8 +96961,8 @@ function missingRequired(type, opts) {
|
|
|
96524
96961
|
}
|
|
96525
96962
|
function ask(label, placeholder = "", required2 = true) {
|
|
96526
96963
|
return new Promise((resolve8) => {
|
|
96527
|
-
const hint = placeholder ?
|
|
96528
|
-
const suffix = required2 ? "" :
|
|
96964
|
+
const hint = placeholder ? import_picocolors33.default.dim(` (${placeholder})`) : "";
|
|
96965
|
+
const suffix = required2 ? "" : import_picocolors33.default.dim(" [optional]");
|
|
96529
96966
|
process.stdout.write(` ${label}${suffix}${hint}: `);
|
|
96530
96967
|
const rl = (0, import_node_readline.createInterface)({
|
|
96531
96968
|
input: process.stdin,
|
|
@@ -96542,7 +96979,7 @@ function askPassword(label) {
|
|
|
96542
96979
|
return new Promise((resolve8) => {
|
|
96543
96980
|
const stdin = process.stdin;
|
|
96544
96981
|
if (typeof stdin.setRawMode === "function") {
|
|
96545
|
-
process.stdout.write(` ${label}${
|
|
96982
|
+
process.stdout.write(` ${label}${import_picocolors33.default.dim(" [optional]")}: `);
|
|
96546
96983
|
stdin.setRawMode(true);
|
|
96547
96984
|
stdin.resume();
|
|
96548
96985
|
let value = "";
|
|
@@ -96642,15 +97079,15 @@ function describeProbe(p) {
|
|
|
96642
97079
|
return `${p.keyCount} keys \xB7 ${p.suggestedRoles.join("/")}${examples ? ` \xB7 ${examples}` : ""}`;
|
|
96643
97080
|
}
|
|
96644
97081
|
async function discoverAndSelectDbs(url, bullmqPrefix) {
|
|
96645
|
-
console.log(
|
|
97082
|
+
console.log(import_picocolors33.default.dim("\n Scanning DBs 0-15 (read-only, sampled)\u2026"));
|
|
96646
97083
|
const probes = await probeRedisDatabases(url, { bullmqPrefix });
|
|
96647
97084
|
const nonEmpty = probes.filter((p) => p.reachable && p.keyCount > 0);
|
|
96648
97085
|
if (nonEmpty.length === 0) {
|
|
96649
|
-
console.log(
|
|
97086
|
+
console.log(import_picocolors33.default.dim(" No populated DBs found."));
|
|
96650
97087
|
return [];
|
|
96651
97088
|
}
|
|
96652
97089
|
for (const p of nonEmpty) {
|
|
96653
|
-
console.log(` ${
|
|
97090
|
+
console.log(` ${import_picocolors33.default.bold(`DB ${p.db}`)} ${import_picocolors33.default.dim("\xB7 " + describeProbe(p))}`);
|
|
96654
97091
|
}
|
|
96655
97092
|
const byLabel = /* @__PURE__ */ new Map();
|
|
96656
97093
|
const choices = nonEmpty.map((p) => {
|
|
@@ -96761,7 +97198,7 @@ function printSummary(type, opts) {
|
|
|
96761
97198
|
} else if (opts.dashboard) {
|
|
96762
97199
|
lines.push(` dashboard: ${opts.dashboard}`);
|
|
96763
97200
|
}
|
|
96764
|
-
if (lines.length > 0) console.log(
|
|
97201
|
+
if (lines.length > 0) console.log(import_picocolors33.default.dim(lines.join("\n")));
|
|
96765
97202
|
}
|
|
96766
97203
|
function isGitTracked(filePath, cwd) {
|
|
96767
97204
|
try {
|
|
@@ -96800,11 +97237,11 @@ async function askIndexSelection(indices) {
|
|
|
96800
97237
|
const shown = indices.slice(0, MAX_DISPLAY);
|
|
96801
97238
|
console.log("\n Available Elasticsearch indexes/data streams:");
|
|
96802
97239
|
shown.forEach((name, i) => {
|
|
96803
|
-
console.log(` ${
|
|
97240
|
+
console.log(` ${import_picocolors33.default.dim(`[${i + 1}]`)} ${name}`);
|
|
96804
97241
|
});
|
|
96805
97242
|
if (indices.length > MAX_DISPLAY) {
|
|
96806
97243
|
console.log(
|
|
96807
|
-
|
|
97244
|
+
import_picocolors33.default.dim(
|
|
96808
97245
|
` \u2026 and ${indices.length - MAX_DISPLAY} more (type a pattern manually to match all)`
|
|
96809
97246
|
)
|
|
96810
97247
|
);
|
|
@@ -96848,11 +97285,11 @@ async function askDashboardSelection(dashboards) {
|
|
|
96848
97285
|
const shown = dashboards.slice(0, MAX_DISPLAY);
|
|
96849
97286
|
console.log("\n Available Grafana dashboards:");
|
|
96850
97287
|
shown.forEach((d, i) => {
|
|
96851
|
-
const folder = d.folderTitle ?
|
|
96852
|
-
console.log(` ${
|
|
97288
|
+
const folder = d.folderTitle ? import_picocolors33.default.dim(` (${d.folderTitle})`) : "";
|
|
97289
|
+
console.log(` ${import_picocolors33.default.dim(`[${i + 1}]`)} ${d.title}${folder}`);
|
|
96853
97290
|
});
|
|
96854
97291
|
if (dashboards.length > MAX_DISPLAY) {
|
|
96855
|
-
console.log(
|
|
97292
|
+
console.log(import_picocolors33.default.dim(` \u2026 and ${dashboards.length - MAX_DISPLAY} more`));
|
|
96856
97293
|
}
|
|
96857
97294
|
const input = (await ask(
|
|
96858
97295
|
` Select dashboards to use (e.g. 1,2 or Enter to type uid manually)`,
|
|
@@ -96903,12 +97340,12 @@ function redactUrl(raw) {
|
|
|
96903
97340
|
// ../../packages/cli/src/commands/stop.ts
|
|
96904
97341
|
init_cjs_shims();
|
|
96905
97342
|
var import_node_child_process7 = require("child_process");
|
|
96906
|
-
var
|
|
97343
|
+
var import_node_fs16 = require("fs");
|
|
96907
97344
|
var import_node_util4 = require("util");
|
|
96908
|
-
var
|
|
96909
|
-
var
|
|
97345
|
+
var import_node_path18 = require("path");
|
|
97346
|
+
var import_picocolors34 = __toESM(require_picocolors(), 1);
|
|
96910
97347
|
var execFileAsync = (0, import_node_util4.promisify)(import_node_child_process7.execFile);
|
|
96911
|
-
var unlinkAsync = (0, import_node_util4.promisify)(
|
|
97348
|
+
var unlinkAsync = (0, import_node_util4.promisify)(import_node_fs16.unlink);
|
|
96912
97349
|
var SPAWNED_HOST_FILE2 = "spawned-host.json";
|
|
96913
97350
|
var START_TIME_TOLERANCE_S = 60;
|
|
96914
97351
|
var STOP_WAIT_MS = 5e3;
|
|
@@ -96923,30 +97360,30 @@ async function runStop(opts) {
|
|
|
96923
97360
|
const root = findRepoRoot(cwd) ?? cwd;
|
|
96924
97361
|
const hostUrl = readSourceHostUrl(root);
|
|
96925
97362
|
if (!hostUrl) {
|
|
96926
|
-
console.log(
|
|
97363
|
+
console.log(import_picocolors34.default.dim("No source-intelligence host found for this repo (.horus/source/host.json absent)."));
|
|
96927
97364
|
return 0;
|
|
96928
97365
|
}
|
|
96929
97366
|
return await stopHost(root, hostUrl);
|
|
96930
97367
|
} catch (err) {
|
|
96931
|
-
console.error(
|
|
97368
|
+
console.error(import_picocolors34.default.red(err.message));
|
|
96932
97369
|
return 1;
|
|
96933
97370
|
}
|
|
96934
97371
|
}
|
|
96935
97372
|
async function stopHost(root, hostUrl) {
|
|
96936
97373
|
const alive = await isHostHealthy(hostUrl);
|
|
96937
97374
|
if (!alive) {
|
|
96938
|
-
console.log(
|
|
97375
|
+
console.log(import_picocolors34.default.dim(`Host ${hostUrl} is already stopped.`));
|
|
96939
97376
|
return 0;
|
|
96940
97377
|
}
|
|
96941
97378
|
const port = extractPort(hostUrl);
|
|
96942
97379
|
if (port === null) {
|
|
96943
|
-
console.error(
|
|
97380
|
+
console.error(import_picocolors34.default.red(`Cannot determine port from host URL: ${hostUrl}`));
|
|
96944
97381
|
return 1;
|
|
96945
97382
|
}
|
|
96946
97383
|
const spawned = readSpawnedHost(root);
|
|
96947
97384
|
if (spawned === null) {
|
|
96948
97385
|
console.error(
|
|
96949
|
-
|
|
97386
|
+
import_picocolors34.default.red(
|
|
96950
97387
|
`No ownership record found (.horus/${SPAWNED_HOST_FILE2} absent). Horus will not stop a host it did not spawn.`
|
|
96951
97388
|
)
|
|
96952
97389
|
);
|
|
@@ -96954,12 +97391,12 @@ async function stopHost(root, hostUrl) {
|
|
|
96954
97391
|
}
|
|
96955
97392
|
const recordError = validateSpawnedRecord(spawned);
|
|
96956
97393
|
if (recordError !== null) {
|
|
96957
|
-
console.error(
|
|
97394
|
+
console.error(import_picocolors34.default.red(`Ownership record is malformed: ${recordError}. Aborting for safety.`));
|
|
96958
97395
|
return 1;
|
|
96959
97396
|
}
|
|
96960
97397
|
if (spawned.port !== port) {
|
|
96961
97398
|
console.error(
|
|
96962
|
-
|
|
97399
|
+
import_picocolors34.default.red(
|
|
96963
97400
|
`Ownership record port (${spawned.port}) does not match host URL port (${port}). Record may be stale.`
|
|
96964
97401
|
)
|
|
96965
97402
|
);
|
|
@@ -96967,7 +97404,7 @@ async function stopHost(root, hostUrl) {
|
|
|
96967
97404
|
}
|
|
96968
97405
|
if (spawned.root !== root) {
|
|
96969
97406
|
console.error(
|
|
96970
|
-
|
|
97407
|
+
import_picocolors34.default.red(
|
|
96971
97408
|
`Ownership record root (${spawned.root}) does not match resolved root (${root}). Record may be stale.`
|
|
96972
97409
|
)
|
|
96973
97410
|
);
|
|
@@ -96975,9 +97412,9 @@ async function stopHost(root, hostUrl) {
|
|
|
96975
97412
|
}
|
|
96976
97413
|
const info = await getProcessInfo(spawned.pid);
|
|
96977
97414
|
if (info === null) {
|
|
96978
|
-
console.log(
|
|
97415
|
+
console.log(import_picocolors34.default.dim(`Process pid ${spawned.pid} is no longer running \u2014 already stopped.`));
|
|
96979
97416
|
try {
|
|
96980
|
-
await unlinkAsync((0,
|
|
97417
|
+
await unlinkAsync((0, import_node_path18.join)(root, HORUS_DIR, SPAWNED_HOST_FILE2));
|
|
96981
97418
|
} catch {
|
|
96982
97419
|
}
|
|
96983
97420
|
return 0;
|
|
@@ -96988,7 +97425,7 @@ async function stopHost(root, hostUrl) {
|
|
|
96988
97425
|
);
|
|
96989
97426
|
if (!hostPortRe.test(info.args)) {
|
|
96990
97427
|
console.error(
|
|
96991
|
-
|
|
97428
|
+
import_picocolors34.default.red(
|
|
96992
97429
|
`Pid ${spawned.pid} args do not match "horus-source host --port ${portStr}". Got: "${info.args.slice(0, 120)}". Aborting for safety.`
|
|
96993
97430
|
)
|
|
96994
97431
|
);
|
|
@@ -96997,12 +97434,12 @@ async function stopHost(root, hostUrl) {
|
|
|
96997
97434
|
const startTs = new Date(spawned.startedAt).getTime();
|
|
96998
97435
|
const recordedAgeS = Math.round((Date.now() - startTs) / 1e3);
|
|
96999
97436
|
if (!Number.isFinite(info.etimeSeconds)) {
|
|
97000
|
-
console.error(
|
|
97437
|
+
console.error(import_picocolors34.default.red(`Could not read elapsed time for pid ${spawned.pid}. Aborting for safety.`));
|
|
97001
97438
|
return 1;
|
|
97002
97439
|
}
|
|
97003
97440
|
if (Math.abs(info.etimeSeconds - recordedAgeS) > START_TIME_TOLERANCE_S) {
|
|
97004
97441
|
console.error(
|
|
97005
|
-
|
|
97442
|
+
import_picocolors34.default.red(
|
|
97006
97443
|
`Pid ${spawned.pid} age mismatch: record says ~${recordedAgeS}s, process reports ${info.etimeSeconds}s elapsed. Possible PID reuse \u2014 aborting for safety.`
|
|
97007
97444
|
)
|
|
97008
97445
|
);
|
|
@@ -97014,9 +97451,9 @@ async function stopHost(root, hostUrl) {
|
|
|
97014
97451
|
signaled = true;
|
|
97015
97452
|
} catch (err) {
|
|
97016
97453
|
if (err.code === "ESRCH") {
|
|
97017
|
-
console.log(
|
|
97454
|
+
console.log(import_picocolors34.default.dim(`Process pid ${spawned.pid} exited before signal \u2014 already stopped.`));
|
|
97018
97455
|
} else {
|
|
97019
|
-
console.error(
|
|
97456
|
+
console.error(import_picocolors34.default.red(`Failed to signal pid ${spawned.pid}: ${err.message}`));
|
|
97020
97457
|
return 1;
|
|
97021
97458
|
}
|
|
97022
97459
|
}
|
|
@@ -97032,18 +97469,18 @@ async function stopHost(root, hostUrl) {
|
|
|
97032
97469
|
}
|
|
97033
97470
|
if (!exited) {
|
|
97034
97471
|
console.error(
|
|
97035
|
-
|
|
97472
|
+
import_picocolors34.default.red(
|
|
97036
97473
|
`Host pid ${spawned.pid} did not exit within ${STOP_WAIT_MS / 1e3}s after SIGTERM.`
|
|
97037
97474
|
)
|
|
97038
97475
|
);
|
|
97039
97476
|
return 1;
|
|
97040
97477
|
}
|
|
97041
97478
|
console.log(
|
|
97042
|
-
`${
|
|
97479
|
+
`${import_picocolors34.default.green("\u2713")} Stopped source-intelligence host ` + import_picocolors34.default.dim(`(pid ${spawned.pid}, port ${port})`) + ` for ${root}`
|
|
97043
97480
|
);
|
|
97044
97481
|
}
|
|
97045
97482
|
try {
|
|
97046
|
-
await unlinkAsync((0,
|
|
97483
|
+
await unlinkAsync((0, import_node_path18.join)(root, HORUS_DIR, SPAWNED_HOST_FILE2));
|
|
97047
97484
|
} catch {
|
|
97048
97485
|
}
|
|
97049
97486
|
return 0;
|
|
@@ -97052,7 +97489,7 @@ async function stopAll() {
|
|
|
97052
97489
|
const registry2 = readRegistry();
|
|
97053
97490
|
const projects2 = Object.entries(registry2.projects);
|
|
97054
97491
|
if (projects2.length === 0) {
|
|
97055
|
-
console.log(
|
|
97492
|
+
console.log(import_picocolors34.default.dim("No registered projects."));
|
|
97056
97493
|
return 0;
|
|
97057
97494
|
}
|
|
97058
97495
|
let stopped = 0;
|
|
@@ -97062,17 +97499,17 @@ async function stopAll() {
|
|
|
97062
97499
|
if (!hostUrl) continue;
|
|
97063
97500
|
const alive = await isHostHealthy(hostUrl);
|
|
97064
97501
|
if (!alive) continue;
|
|
97065
|
-
console.log(` Stopping ${
|
|
97502
|
+
console.log(` Stopping ${import_picocolors34.default.bold(name)} ${import_picocolors34.default.dim(`(${hostUrl})`)}`);
|
|
97066
97503
|
const code = await stopHost(entry2.root, hostUrl);
|
|
97067
97504
|
if (code === 0) stopped++;
|
|
97068
97505
|
else failed++;
|
|
97069
97506
|
}
|
|
97070
97507
|
if (stopped === 0 && failed === 0) {
|
|
97071
|
-
console.log(
|
|
97508
|
+
console.log(import_picocolors34.default.dim("No running source-intelligence hosts found."));
|
|
97072
97509
|
} else {
|
|
97073
97510
|
console.log(
|
|
97074
97511
|
`
|
|
97075
|
-
Stopped ${stopped} host(s)${failed > 0 ?
|
|
97512
|
+
Stopped ${stopped} host(s)${failed > 0 ? import_picocolors34.default.red(`, ${failed} failed`) : ""}.`
|
|
97076
97513
|
);
|
|
97077
97514
|
}
|
|
97078
97515
|
return failed > 0 ? 1 : 0;
|
|
@@ -97124,12 +97561,12 @@ function extractPort(hostUrl) {
|
|
|
97124
97561
|
|
|
97125
97562
|
// ../../packages/cli/src/commands/hosts.ts
|
|
97126
97563
|
init_cjs_shims();
|
|
97127
|
-
var
|
|
97564
|
+
var import_picocolors35 = __toESM(require_picocolors(), 1);
|
|
97128
97565
|
async function runHosts() {
|
|
97129
97566
|
const registry2 = readRegistry();
|
|
97130
97567
|
const projects2 = Object.entries(registry2.projects);
|
|
97131
97568
|
if (projects2.length === 0) {
|
|
97132
|
-
console.log(
|
|
97569
|
+
console.log(import_picocolors35.default.dim("No registered projects. Run `horus index` in a repo first."));
|
|
97133
97570
|
return 0;
|
|
97134
97571
|
}
|
|
97135
97572
|
const rows = [];
|
|
@@ -97146,29 +97583,29 @@ async function runHosts() {
|
|
|
97146
97583
|
});
|
|
97147
97584
|
const anyHost = rows.some((r) => r.hostUrl !== null);
|
|
97148
97585
|
if (!anyHost) {
|
|
97149
|
-
console.log(
|
|
97586
|
+
console.log(import_picocolors35.default.dim("No source-intelligence hosts found. Run `horus index` to start one."));
|
|
97150
97587
|
return 0;
|
|
97151
97588
|
}
|
|
97152
97589
|
console.log("");
|
|
97153
97590
|
for (const row of rows) {
|
|
97154
97591
|
if (row.hostUrl === null) continue;
|
|
97155
|
-
const status = row.healthy ?
|
|
97592
|
+
const status = row.healthy ? import_picocolors35.default.green("\u25CF running") : import_picocolors35.default.red("\u25CF stopped");
|
|
97156
97593
|
const port = extractPort2(row.hostUrl) ?? "?";
|
|
97157
97594
|
console.log(
|
|
97158
|
-
` ${status} ${
|
|
97595
|
+
` ${status} ${import_picocolors35.default.bold(row.name.padEnd(24))} port ${String(port).padEnd(6)} ${import_picocolors35.default.dim(row.root)}`
|
|
97159
97596
|
);
|
|
97160
97597
|
}
|
|
97161
97598
|
console.log("");
|
|
97162
97599
|
const noHost = rows.filter((r) => r.hostUrl === null);
|
|
97163
97600
|
if (noHost.length > 0) {
|
|
97164
97601
|
for (const row of noHost) {
|
|
97165
|
-
console.log(` ${
|
|
97602
|
+
console.log(` ${import_picocolors35.default.dim("\u25CB no host")} ${import_picocolors35.default.dim(row.name)}`);
|
|
97166
97603
|
}
|
|
97167
97604
|
console.log("");
|
|
97168
97605
|
}
|
|
97169
97606
|
const running = rows.filter((r) => r.healthy).length;
|
|
97170
97607
|
console.log(
|
|
97171
|
-
|
|
97608
|
+
import_picocolors35.default.dim(
|
|
97172
97609
|
`${running} running \xB7 horus stop to reap \xB7 horus stop --all to stop everything`
|
|
97173
97610
|
)
|
|
97174
97611
|
);
|
|
@@ -97185,12 +97622,12 @@ function extractPort2(hostUrl) {
|
|
|
97185
97622
|
|
|
97186
97623
|
// ../../packages/cli/src/commands/doctor.ts
|
|
97187
97624
|
init_cjs_shims();
|
|
97188
|
-
var
|
|
97625
|
+
var import_picocolors36 = __toESM(require_picocolors(), 1);
|
|
97189
97626
|
var DEFAULT_DB_URL4 = "postgresql://horus:horus@localhost:5433/horus";
|
|
97190
97627
|
function mark2(status) {
|
|
97191
|
-
if (status === "pass") return
|
|
97192
|
-
if (status === "warn") return
|
|
97193
|
-
return
|
|
97628
|
+
if (status === "pass") return import_picocolors36.default.green("\u2713");
|
|
97629
|
+
if (status === "warn") return import_picocolors36.default.yellow("~");
|
|
97630
|
+
return import_picocolors36.default.red("\u2717");
|
|
97194
97631
|
}
|
|
97195
97632
|
async function runDoctor(opts) {
|
|
97196
97633
|
const cwd = opts?.cwd ?? process.cwd();
|
|
@@ -97417,11 +97854,11 @@ async function runDoctor(opts) {
|
|
|
97417
97854
|
write(JSON.stringify(output, null, 2));
|
|
97418
97855
|
return hasFailure ? 1 : 0;
|
|
97419
97856
|
}
|
|
97420
|
-
write(
|
|
97857
|
+
write(import_picocolors36.default.bold("\nHorus readiness check\n"));
|
|
97421
97858
|
for (const check2 of checks) {
|
|
97422
|
-
write(` ${mark2(check2.status)} ${
|
|
97859
|
+
write(` ${mark2(check2.status)} ${import_picocolors36.default.bold(check2.label.padEnd(26))} ${import_picocolors36.default.dim(check2.detail)}`);
|
|
97423
97860
|
if (check2.next) {
|
|
97424
|
-
write(` ${
|
|
97861
|
+
write(` ${import_picocolors36.default.dim("\u2192 " + check2.next)}`);
|
|
97425
97862
|
}
|
|
97426
97863
|
}
|
|
97427
97864
|
write("");
|
|
@@ -97431,16 +97868,16 @@ async function runDoctor(opts) {
|
|
|
97431
97868
|
// ../../packages/cli/src/commands/providers-doctor.ts
|
|
97432
97869
|
init_cjs_shims();
|
|
97433
97870
|
var import_node_child_process8 = require("child_process");
|
|
97434
|
-
var
|
|
97871
|
+
var import_picocolors37 = __toESM(require_picocolors(), 1);
|
|
97435
97872
|
function statusMark(status) {
|
|
97436
|
-
if (status === "ready") return
|
|
97437
|
-
if (status === "installed") return
|
|
97438
|
-
return
|
|
97873
|
+
if (status === "ready") return import_picocolors37.default.green("\u2713");
|
|
97874
|
+
if (status === "installed") return import_picocolors37.default.yellow("~");
|
|
97875
|
+
return import_picocolors37.default.red("\u2717");
|
|
97439
97876
|
}
|
|
97440
97877
|
function statusLabel(status) {
|
|
97441
|
-
if (status === "ready") return
|
|
97442
|
-
if (status === "installed") return
|
|
97443
|
-
return
|
|
97878
|
+
if (status === "ready") return import_picocolors37.default.green("ready");
|
|
97879
|
+
if (status === "installed") return import_picocolors37.default.yellow("installed (not configured)");
|
|
97880
|
+
return import_picocolors37.default.dim("not found on PATH");
|
|
97444
97881
|
}
|
|
97445
97882
|
function detectBinary(id) {
|
|
97446
97883
|
const result = (0, import_node_child_process8.spawnSync)(id, ["--version"], { stdio: "pipe", timeout: 2e3 });
|
|
@@ -97457,7 +97894,7 @@ async function runProvidersDoctorCommand(opts) {
|
|
|
97457
97894
|
const registry2 = opts?.registry ?? DEFAULT_LOCAL_PROVIDER_REGISTRY;
|
|
97458
97895
|
const write = opts?.write ?? ((line2) => console.log(line2));
|
|
97459
97896
|
const results = buildProviderResults(registry2, opts?._detect);
|
|
97460
|
-
write(
|
|
97897
|
+
write(import_picocolors37.default.bold("\nLocal AI providers\n"));
|
|
97461
97898
|
for (const result of results) {
|
|
97462
97899
|
const descriptor = registry2.get(result.id);
|
|
97463
97900
|
const name = descriptor?.displayName ?? result.id;
|
|
@@ -97465,11 +97902,11 @@ async function runProvidersDoctorCommand(opts) {
|
|
|
97465
97902
|
` ${statusMark(result.status)} ${result.id.padEnd(8)} ${name.padEnd(22)} ${statusLabel(result.status)}`
|
|
97466
97903
|
);
|
|
97467
97904
|
if (result.status !== "ready" && result.detail) {
|
|
97468
|
-
write(` ${
|
|
97905
|
+
write(` ${import_picocolors37.default.dim("\u2192 " + result.detail)}`);
|
|
97469
97906
|
}
|
|
97470
97907
|
}
|
|
97471
97908
|
write("");
|
|
97472
|
-
write(
|
|
97909
|
+
write(import_picocolors37.default.bold("Cloud AI providers\n"));
|
|
97473
97910
|
let source = null;
|
|
97474
97911
|
if (opts?._anthropicKey !== void 0) {
|
|
97475
97912
|
source = opts._anthropicKey ? "env" : null;
|
|
@@ -97484,18 +97921,18 @@ async function runProvidersDoctorCommand(opts) {
|
|
|
97484
97921
|
}
|
|
97485
97922
|
if (source === "config") {
|
|
97486
97923
|
write(
|
|
97487
|
-
` ${
|
|
97924
|
+
` ${import_picocolors37.default.green("\u2713")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors37.default.green("configured (local .horus config)")}`
|
|
97488
97925
|
);
|
|
97489
97926
|
} else if (source === "env") {
|
|
97490
97927
|
write(
|
|
97491
|
-
` ${
|
|
97928
|
+
` ${import_picocolors37.default.green("\u2713")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors37.default.green("configured (ANTHROPIC_API_KEY env)")}`
|
|
97492
97929
|
);
|
|
97493
97930
|
} else {
|
|
97494
97931
|
write(
|
|
97495
|
-
` ${
|
|
97932
|
+
` ${import_picocolors37.default.red("\u2717")} ${"anthropic".padEnd(8)} ${"Anthropic Claude API".padEnd(22)} ${import_picocolors37.default.dim("not configured")}`
|
|
97496
97933
|
);
|
|
97497
97934
|
write(
|
|
97498
|
-
` ${
|
|
97935
|
+
` ${import_picocolors37.default.dim("\u2192 run `horus connect ai` (or set ANTHROPIC_API_KEY) to enable `horus investigate --ai`")}`
|
|
97499
97936
|
);
|
|
97500
97937
|
}
|
|
97501
97938
|
write("");
|
|
@@ -97504,9 +97941,9 @@ async function runProvidersDoctorCommand(opts) {
|
|
|
97504
97941
|
|
|
97505
97942
|
// ../../packages/cli/src/commands/generate-config.ts
|
|
97506
97943
|
init_cjs_shims();
|
|
97507
|
-
var
|
|
97508
|
-
var
|
|
97509
|
-
var
|
|
97944
|
+
var import_node_fs17 = require("fs");
|
|
97945
|
+
var import_node_path19 = require("path");
|
|
97946
|
+
var import_picocolors38 = __toESM(require_picocolors(), 1);
|
|
97510
97947
|
function configTemplate(name, repoPath) {
|
|
97511
97948
|
return `export default {
|
|
97512
97949
|
database: {
|
|
@@ -97554,39 +97991,39 @@ async function runGenerateConfig(opts) {
|
|
|
97554
97991
|
const defaults = localConfigPath2 != null ? projectDefaults(localConfigPath2) : null;
|
|
97555
97992
|
const hasLocalConfig = defaults != null;
|
|
97556
97993
|
const defaultOut = hasLocalConfig ? "horus.config.example.js" : "horus.config.js";
|
|
97557
|
-
const outPath = (0,
|
|
97994
|
+
const outPath = (0, import_node_path19.resolve)(cwd, opts.out ?? defaultOut);
|
|
97558
97995
|
const name = opts.name ?? defaults?.name ?? "my-project";
|
|
97559
97996
|
const repoPath = opts.repo ?? defaults?.repoPath ?? `/path/to/${name}`;
|
|
97560
|
-
if ((0,
|
|
97561
|
-
log(`${
|
|
97562
|
-
log(
|
|
97997
|
+
if ((0, import_node_fs17.existsSync)(outPath) && !opts.force) {
|
|
97998
|
+
log(`${import_picocolors38.default.red("\u2717")} ${outPath} already exists`);
|
|
97999
|
+
log(import_picocolors38.default.dim(" pass --force to overwrite"));
|
|
97563
98000
|
return 1;
|
|
97564
98001
|
}
|
|
97565
98002
|
try {
|
|
97566
|
-
(0,
|
|
97567
|
-
(0,
|
|
98003
|
+
(0, import_node_fs17.mkdirSync)((0, import_node_path19.dirname)(outPath), { recursive: true });
|
|
98004
|
+
(0, import_node_fs17.writeFileSync)(outPath, configTemplate(name, repoPath), "utf8");
|
|
97568
98005
|
} catch (err) {
|
|
97569
|
-
log(`${
|
|
98006
|
+
log(`${import_picocolors38.default.red("\u2717")} Could not write ${outPath}: ${err.message}`);
|
|
97570
98007
|
return 1;
|
|
97571
98008
|
}
|
|
97572
|
-
log(`${
|
|
97573
|
-
log(
|
|
97574
|
-
log(
|
|
98009
|
+
log(`${import_picocolors38.default.green("\u2713")} Created ${outPath}`);
|
|
98010
|
+
log(import_picocolors38.default.dim(` project: ${name}`));
|
|
98011
|
+
log(import_picocolors38.default.dim(` repo: ${repoPath}`));
|
|
97575
98012
|
if (hasLocalConfig && localConfigPath2 != null) {
|
|
97576
98013
|
log("");
|
|
97577
|
-
log(
|
|
98014
|
+
log(import_picocolors38.default.yellow("Note:") + ` an initialized Horus project config exists at ${localConfigPath2}`);
|
|
97578
98015
|
log(" \u2022 .horus/config.json \u2014 project config used by `horus investigate` from this repo");
|
|
97579
98016
|
log(" \u2022 horus.config.js \u2014 standalone/global config used with `horus doctor --config <path>`");
|
|
97580
|
-
log(
|
|
98017
|
+
log(import_picocolors38.default.dim(` next: review ${outPath} and copy/adapt it as needed`));
|
|
97581
98018
|
} else {
|
|
97582
|
-
log(
|
|
98019
|
+
log(import_picocolors38.default.dim(` next: horus doctor --config ${outPath}`));
|
|
97583
98020
|
}
|
|
97584
98021
|
return 0;
|
|
97585
98022
|
}
|
|
97586
98023
|
|
|
97587
98024
|
// ../../packages/cli/src/commands/readiness.ts
|
|
97588
98025
|
init_cjs_shims();
|
|
97589
|
-
var
|
|
98026
|
+
var import_picocolors39 = __toESM(require_picocolors(), 1);
|
|
97590
98027
|
var READINESS_AI_CONTRACT = `Provide a clearly separated AI readiness summary with:
|
|
97591
98028
|
|
|
97592
98029
|
Overall assessment
|
|
@@ -97609,9 +98046,9 @@ Confidence / gaps
|
|
|
97609
98046
|
- Which checks Horus could verify vs. which require manual confirmation`;
|
|
97610
98047
|
var DEFAULT_DB_URL5 = "postgresql://horus:horus@localhost:5433/horus";
|
|
97611
98048
|
function mark3(status) {
|
|
97612
|
-
if (status === "pass") return
|
|
97613
|
-
if (status === "warn") return
|
|
97614
|
-
return
|
|
98049
|
+
if (status === "pass") return import_picocolors39.default.green("\u2713");
|
|
98050
|
+
if (status === "warn") return import_picocolors39.default.yellow("~");
|
|
98051
|
+
return import_picocolors39.default.red("\u2717");
|
|
97615
98052
|
}
|
|
97616
98053
|
async function runReadiness(opts) {
|
|
97617
98054
|
const cwd = opts?.cwd ?? process.cwd();
|
|
@@ -97766,20 +98203,20 @@ async function runReadiness(opts) {
|
|
|
97766
98203
|
}
|
|
97767
98204
|
const blockingChecks = checks.filter((c) => c.blocking);
|
|
97768
98205
|
const optionalChecks = checks.filter((c) => !c.blocking);
|
|
97769
|
-
write(
|
|
97770
|
-
write(
|
|
98206
|
+
write(import_picocolors39.default.bold("\nHorus release readiness\n"));
|
|
98207
|
+
write(import_picocolors39.default.bold(" Blocking"));
|
|
97771
98208
|
for (const check2 of blockingChecks) {
|
|
97772
|
-
write(` ${mark3(check2.status)} ${
|
|
98209
|
+
write(` ${mark3(check2.status)} ${import_picocolors39.default.bold(check2.label.padEnd(22))} ${import_picocolors39.default.dim(check2.detail)}`);
|
|
97773
98210
|
if (check2.next) {
|
|
97774
|
-
write(` ${
|
|
98211
|
+
write(` ${import_picocolors39.default.dim("\u2192 " + check2.next)}`);
|
|
97775
98212
|
}
|
|
97776
98213
|
}
|
|
97777
98214
|
write("");
|
|
97778
|
-
write(
|
|
98215
|
+
write(import_picocolors39.default.bold(" Optional"));
|
|
97779
98216
|
for (const check2 of optionalChecks) {
|
|
97780
|
-
write(` ${mark3(check2.status)} ${
|
|
98217
|
+
write(` ${mark3(check2.status)} ${import_picocolors39.default.bold(check2.label.padEnd(22))} ${import_picocolors39.default.dim(check2.detail)}`);
|
|
97781
98218
|
if (check2.next) {
|
|
97782
|
-
write(` ${
|
|
98219
|
+
write(` ${import_picocolors39.default.dim("\u2192 " + check2.next)}`);
|
|
97783
98220
|
}
|
|
97784
98221
|
}
|
|
97785
98222
|
write("");
|
|
@@ -97787,21 +98224,21 @@ async function runReadiness(opts) {
|
|
|
97787
98224
|
const optionalWarns = optionalChecks.filter((c) => c.status === "warn").length;
|
|
97788
98225
|
if (blockingFails.length === 0) {
|
|
97789
98226
|
if (optionalWarns === 0) {
|
|
97790
|
-
write(
|
|
98227
|
+
write(import_picocolors39.default.green(" Ready for demo/release."));
|
|
97791
98228
|
} else {
|
|
97792
98229
|
write(
|
|
97793
|
-
|
|
98230
|
+
import_picocolors39.default.yellow(
|
|
97794
98231
|
` Ready for a basic demo. ${optionalWarns} optional item(s) not configured \u2014 investigation evidence will be limited.`
|
|
97795
98232
|
)
|
|
97796
98233
|
);
|
|
97797
98234
|
}
|
|
97798
98235
|
} else {
|
|
97799
98236
|
write(
|
|
97800
|
-
|
|
98237
|
+
import_picocolors39.default.red(
|
|
97801
98238
|
` Not ready. ${blockingFails.length} blocking item(s) must be resolved before demo/release.`
|
|
97802
98239
|
)
|
|
97803
98240
|
);
|
|
97804
|
-
write(
|
|
98241
|
+
write(import_picocolors39.default.dim(" Re-run `horus readiness` after resolving the items above."));
|
|
97805
98242
|
}
|
|
97806
98243
|
write("");
|
|
97807
98244
|
if (opts?.ai) {
|
|
@@ -97816,7 +98253,7 @@ async function runReadiness(opts) {
|
|
|
97816
98253
|
});
|
|
97817
98254
|
console.log("\n" + renderInterpretation(result));
|
|
97818
98255
|
if (!result.ok) {
|
|
97819
|
-
console.error(
|
|
98256
|
+
console.error(import_picocolors39.default.yellow(`[ai] ${result.warning}`));
|
|
97820
98257
|
}
|
|
97821
98258
|
}
|
|
97822
98259
|
return blockingFails.length > 0 ? 1 : 0;
|
|
@@ -97824,33 +98261,33 @@ async function runReadiness(opts) {
|
|
|
97824
98261
|
|
|
97825
98262
|
// ../../packages/cli/src/commands/skill.ts
|
|
97826
98263
|
init_cjs_shims();
|
|
97827
|
-
var
|
|
97828
|
-
var
|
|
97829
|
-
var
|
|
97830
|
-
var
|
|
97831
|
-
var
|
|
98264
|
+
var import_node_fs18 = require("fs");
|
|
98265
|
+
var import_node_path20 = require("path");
|
|
98266
|
+
var import_node_os4 = require("os");
|
|
98267
|
+
var import_promises2 = require("readline/promises");
|
|
98268
|
+
var import_picocolors40 = __toESM(require_picocolors(), 1);
|
|
97832
98269
|
var SUPPORTED_TARGETS = ["claude", "codex", "gemini", "cursor", "generic"];
|
|
97833
98270
|
function isValidTarget(target) {
|
|
97834
98271
|
return SUPPORTED_TARGETS.includes(target);
|
|
97835
98272
|
}
|
|
97836
98273
|
function getLegacyClaudeSkillPath(opts) {
|
|
97837
|
-
const base2 = opts.global ? (0,
|
|
97838
|
-
return (0,
|
|
98274
|
+
const base2 = opts.global ? (0, import_node_os4.homedir)() : opts.cwd ?? process.cwd();
|
|
98275
|
+
return (0, import_node_path20.join)(base2, ".claude", "skills", "horus.md");
|
|
97839
98276
|
}
|
|
97840
98277
|
function getSkillInstallPath(target, opts) {
|
|
97841
|
-
const base2 = opts.global ? (0,
|
|
98278
|
+
const base2 = opts.global ? (0, import_node_os4.homedir)() : opts.cwd ?? process.cwd();
|
|
97842
98279
|
switch (target) {
|
|
97843
98280
|
case "claude":
|
|
97844
|
-
return (0,
|
|
98281
|
+
return (0, import_node_path20.join)(base2, ".claude", "skills", "horus", "SKILL.md");
|
|
97845
98282
|
case "gemini":
|
|
97846
|
-
return opts.global ? (0,
|
|
98283
|
+
return opts.global ? (0, import_node_path20.join)(base2, ".gemini", "GEMINI.md") : (0, import_node_path20.join)(base2, "GEMINI.md");
|
|
97847
98284
|
case "cursor":
|
|
97848
|
-
return opts.global ? (0,
|
|
98285
|
+
return opts.global ? (0, import_node_path20.join)(base2, ".cursorrules") : (0, import_node_path20.join)(base2, ".cursor", "rules", "horus.mdc");
|
|
97849
98286
|
case "codex":
|
|
97850
|
-
return opts.global ? (0,
|
|
98287
|
+
return opts.global ? (0, import_node_path20.join)(base2, ".codex", "AGENTS.md") : (0, import_node_path20.join)(base2, "AGENTS.md");
|
|
97851
98288
|
case "generic":
|
|
97852
98289
|
default:
|
|
97853
|
-
return (0,
|
|
98290
|
+
return (0, import_node_path20.join)(base2, ".horus", "skills", `horus-${target}.md`);
|
|
97854
98291
|
}
|
|
97855
98292
|
}
|
|
97856
98293
|
var BASE_SKILL = `# Horus Grounded Investigation Skill
|
|
@@ -98135,7 +98572,7 @@ async function confirm(message) {
|
|
|
98135
98572
|
if (!process.stdin.isTTY) {
|
|
98136
98573
|
return false;
|
|
98137
98574
|
}
|
|
98138
|
-
const rl = (0,
|
|
98575
|
+
const rl = (0, import_promises2.createInterface)({ input: process.stdin, output: process.stdout });
|
|
98139
98576
|
try {
|
|
98140
98577
|
const answer = await rl.question(`${message} [y/N] `);
|
|
98141
98578
|
return /^y(es)?$/i.test(answer.trim());
|
|
@@ -98146,66 +98583,66 @@ async function confirm(message) {
|
|
|
98146
98583
|
async function runSkillInstall(target, opts) {
|
|
98147
98584
|
const log = opts.write ?? ((line2) => console.log(line2));
|
|
98148
98585
|
if (!isValidTarget(target)) {
|
|
98149
|
-
log(`${
|
|
98150
|
-
log(
|
|
98586
|
+
log(`${import_picocolors40.default.red("\u2717")} Unknown target: ${import_picocolors40.default.bold(target)}`);
|
|
98587
|
+
log(import_picocolors40.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
|
|
98151
98588
|
return 1;
|
|
98152
98589
|
}
|
|
98153
98590
|
const outPath = getSkillInstallPath(target, { global: opts.global, cwd: opts.cwd });
|
|
98154
98591
|
const content = generateSkillContent(target);
|
|
98155
98592
|
if (target === "claude") {
|
|
98156
98593
|
const legacyPath = getLegacyClaudeSkillPath({ global: opts.global, cwd: opts.cwd });
|
|
98157
|
-
if ((0,
|
|
98594
|
+
if ((0, import_node_fs18.existsSync)(legacyPath)) {
|
|
98158
98595
|
if (!opts.force) {
|
|
98159
98596
|
const confirmed = await (opts.confirm ?? confirm)(
|
|
98160
98597
|
`Found old flat skill file at ${legacyPath}. Replace it with the new directory layout?`
|
|
98161
98598
|
);
|
|
98162
98599
|
if (!confirmed) {
|
|
98163
|
-
log(`${
|
|
98164
|
-
log(
|
|
98600
|
+
log(`${import_picocolors40.default.yellow("!")} Migration cancelled; existing skill left untouched.`);
|
|
98601
|
+
log(import_picocolors40.default.dim(" Pass --force to replace without prompting."));
|
|
98165
98602
|
return 1;
|
|
98166
98603
|
}
|
|
98167
98604
|
}
|
|
98168
98605
|
try {
|
|
98169
|
-
(0,
|
|
98170
|
-
log(`${
|
|
98606
|
+
(0, import_node_fs18.rmSync)(legacyPath);
|
|
98607
|
+
log(`${import_picocolors40.default.yellow("!")} Replaced old flat skill file: ${legacyPath}`);
|
|
98171
98608
|
} catch (err) {
|
|
98172
|
-
log(`${
|
|
98609
|
+
log(`${import_picocolors40.default.red("\u2717")} Could not remove legacy skill file ${legacyPath}: ${err.message}`);
|
|
98173
98610
|
return 1;
|
|
98174
98611
|
}
|
|
98175
98612
|
}
|
|
98176
98613
|
}
|
|
98177
|
-
if ((0,
|
|
98178
|
-
log(`${
|
|
98179
|
-
log(
|
|
98614
|
+
if ((0, import_node_fs18.existsSync)(outPath) && !opts.force) {
|
|
98615
|
+
log(`${import_picocolors40.default.red("\u2717")} ${outPath} already exists`);
|
|
98616
|
+
log(import_picocolors40.default.dim(" pass --force to overwrite"));
|
|
98180
98617
|
return 1;
|
|
98181
98618
|
}
|
|
98182
98619
|
try {
|
|
98183
|
-
(0,
|
|
98184
|
-
(0,
|
|
98620
|
+
(0, import_node_fs18.mkdirSync)((0, import_node_path20.dirname)(outPath), { recursive: true });
|
|
98621
|
+
(0, import_node_fs18.writeFileSync)(outPath, content, "utf8");
|
|
98185
98622
|
} catch (err) {
|
|
98186
|
-
log(`${
|
|
98623
|
+
log(`${import_picocolors40.default.red("\u2717")} Could not write ${outPath}: ${err.message}`);
|
|
98187
98624
|
return 1;
|
|
98188
98625
|
}
|
|
98189
|
-
log(`${
|
|
98626
|
+
log(`${import_picocolors40.default.green("\u2713")} Horus skill installed \u2192 ${outPath}`);
|
|
98190
98627
|
if (target === "claude") {
|
|
98191
|
-
log(
|
|
98192
|
-
log(
|
|
98628
|
+
log(import_picocolors40.default.dim(" Claude Code will load this skill automatically."));
|
|
98629
|
+
log(import_picocolors40.default.dim(" Invoke it with: /horus"));
|
|
98193
98630
|
} else if (target === "gemini") {
|
|
98194
|
-
log(
|
|
98631
|
+
log(import_picocolors40.default.dim(" Gemini CLI will load this context file automatically."));
|
|
98195
98632
|
} else if (target === "cursor") {
|
|
98196
|
-
log(
|
|
98633
|
+
log(import_picocolors40.default.dim(" Cursor will load this rule automatically."));
|
|
98197
98634
|
} else if (target === "codex") {
|
|
98198
|
-
log(
|
|
98635
|
+
log(import_picocolors40.default.dim(" Codex CLI will load this file automatically."));
|
|
98199
98636
|
} else {
|
|
98200
|
-
log(
|
|
98637
|
+
log(import_picocolors40.default.dim(` Copy or reference this file in your ${target} agent instructions.`));
|
|
98201
98638
|
}
|
|
98202
98639
|
return 0;
|
|
98203
98640
|
}
|
|
98204
98641
|
async function runSkillPrint(target, opts) {
|
|
98205
98642
|
const log = opts.write ?? ((line2) => console.log(line2));
|
|
98206
98643
|
if (!isValidTarget(target)) {
|
|
98207
|
-
log(`${
|
|
98208
|
-
log(
|
|
98644
|
+
log(`${import_picocolors40.default.red("\u2717")} Unknown target: ${import_picocolors40.default.bold(target)}`);
|
|
98645
|
+
log(import_picocolors40.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
|
|
98209
98646
|
return 1;
|
|
98210
98647
|
}
|
|
98211
98648
|
process.stdout.write(generateSkillContent(target));
|
|
@@ -98214,8 +98651,8 @@ async function runSkillPrint(target, opts) {
|
|
|
98214
98651
|
async function runSkillPath(target, opts) {
|
|
98215
98652
|
const log = opts.write ?? ((line2) => console.log(line2));
|
|
98216
98653
|
if (!isValidTarget(target)) {
|
|
98217
|
-
log(`${
|
|
98218
|
-
log(
|
|
98654
|
+
log(`${import_picocolors40.default.red("\u2717")} Unknown target: ${import_picocolors40.default.bold(target)}`);
|
|
98655
|
+
log(import_picocolors40.default.dim(` Supported targets: ${SUPPORTED_TARGETS.join(", ")}`));
|
|
98219
98656
|
return 1;
|
|
98220
98657
|
}
|
|
98221
98658
|
const outPath = getSkillInstallPath(target, { global: opts.global, cwd: opts.cwd });
|
|
@@ -98225,11 +98662,11 @@ async function runSkillPath(target, opts) {
|
|
|
98225
98662
|
|
|
98226
98663
|
// ../../packages/cli/src/commands/update.ts
|
|
98227
98664
|
init_cjs_shims();
|
|
98228
|
-
var
|
|
98229
|
-
var
|
|
98230
|
-
var
|
|
98231
|
-
var
|
|
98232
|
-
var
|
|
98665
|
+
var import_node_fs19 = require("fs");
|
|
98666
|
+
var import_node_path21 = require("path");
|
|
98667
|
+
var import_node_os5 = require("os");
|
|
98668
|
+
var import_node_crypto7 = require("crypto");
|
|
98669
|
+
var import_picocolors41 = __toESM(require_picocolors(), 1);
|
|
98233
98670
|
var RELEASES_API = "https://api.github.com/repos/meritt-dev/horus/releases/latest";
|
|
98234
98671
|
function parseVersion(v) {
|
|
98235
98672
|
const m = v.replace(/^v/, "").match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
@@ -98254,13 +98691,13 @@ async function fetchLatestRelease(_fetch = fetch) {
|
|
|
98254
98691
|
return res.json();
|
|
98255
98692
|
}
|
|
98256
98693
|
function sha256hex(buf) {
|
|
98257
|
-
return (0,
|
|
98694
|
+
return (0, import_node_crypto7.createHash)("sha256").update(buf).digest("hex");
|
|
98258
98695
|
}
|
|
98259
98696
|
function resolveBinaryPath() {
|
|
98260
98697
|
const raw = process.argv[1];
|
|
98261
98698
|
if (!raw) throw new Error("Cannot determine binary path from process.argv[1]");
|
|
98262
98699
|
try {
|
|
98263
|
-
return (0,
|
|
98700
|
+
return (0, import_node_fs19.realpathSync)(raw);
|
|
98264
98701
|
} catch {
|
|
98265
98702
|
return raw;
|
|
98266
98703
|
}
|
|
@@ -98270,33 +98707,33 @@ async function runUpdate(opts) {
|
|
|
98270
98707
|
const _fetch = opts._fetch ?? fetch;
|
|
98271
98708
|
const currentVersion = opts._currentVersion ?? HORUS_VERSION;
|
|
98272
98709
|
write(`
|
|
98273
|
-
${
|
|
98710
|
+
${import_picocolors41.default.bold("Horus update")}
|
|
98274
98711
|
`);
|
|
98275
|
-
write(` Current version: ${
|
|
98712
|
+
write(` Current version: ${import_picocolors41.default.cyan(currentVersion)}`);
|
|
98276
98713
|
let release;
|
|
98277
98714
|
try {
|
|
98278
98715
|
release = await fetchLatestRelease(_fetch);
|
|
98279
98716
|
} catch (e) {
|
|
98280
|
-
write(` ${
|
|
98717
|
+
write(` ${import_picocolors41.default.red("\u2717")} Could not reach GitHub: ${e.message}`);
|
|
98281
98718
|
return 1;
|
|
98282
98719
|
}
|
|
98283
98720
|
const latest = release.tag_name.replace(/^v/, "");
|
|
98284
|
-
write(` Latest version: ${
|
|
98721
|
+
write(` Latest version: ${import_picocolors41.default.cyan(latest)}`);
|
|
98285
98722
|
const newer = isNewer(latest, currentVersion);
|
|
98286
98723
|
if (opts.check) {
|
|
98287
98724
|
if (newer) {
|
|
98288
98725
|
write(`
|
|
98289
|
-
${
|
|
98290
|
-
write(` Run ${
|
|
98726
|
+
${import_picocolors41.default.yellow("\u2192")} ${import_picocolors41.default.bold(latest)} is available.`);
|
|
98727
|
+
write(` Run ${import_picocolors41.default.bold("horus update")} to upgrade.`);
|
|
98291
98728
|
} else {
|
|
98292
98729
|
write(`
|
|
98293
|
-
${
|
|
98730
|
+
${import_picocolors41.default.green("\u2713")} Already on the latest version.`);
|
|
98294
98731
|
}
|
|
98295
98732
|
return 0;
|
|
98296
98733
|
}
|
|
98297
98734
|
if (!newer && !opts.force) {
|
|
98298
98735
|
write(`
|
|
98299
|
-
${
|
|
98736
|
+
${import_picocolors41.default.green("\u2713")} Already on the latest version.`);
|
|
98300
98737
|
return 0;
|
|
98301
98738
|
}
|
|
98302
98739
|
const tag = release.tag_name;
|
|
@@ -98305,8 +98742,8 @@ ${import_picocolors40.default.bold("Horus update")}
|
|
|
98305
98742
|
const binaryAsset = release.assets.find((a) => a.name === assetName);
|
|
98306
98743
|
const checksumAsset = release.assets.find((a) => a.name === checksumName);
|
|
98307
98744
|
if (!binaryAsset) {
|
|
98308
|
-
write(` ${
|
|
98309
|
-
write(` Fallback: ${
|
|
98745
|
+
write(` ${import_picocolors41.default.red("\u2717")} Release ${tag} has no binary asset named '${assetName}'.`);
|
|
98746
|
+
write(` Fallback: ${import_picocolors41.default.dim("curl -fsSL https://horus.sh/install.sh | bash")}`);
|
|
98310
98747
|
return 1;
|
|
98311
98748
|
}
|
|
98312
98749
|
write(`
|
|
@@ -98316,7 +98753,7 @@ ${import_picocolors40.default.bold("Horus update")}
|
|
|
98316
98753
|
redirect: "follow"
|
|
98317
98754
|
});
|
|
98318
98755
|
if (!binRes.ok || !binRes.body) {
|
|
98319
|
-
write(` ${
|
|
98756
|
+
write(` ${import_picocolors41.default.red("\u2717")} Download failed: ${binRes.status}`);
|
|
98320
98757
|
return 1;
|
|
98321
98758
|
}
|
|
98322
98759
|
const binBuf = Buffer.from(await binRes.arrayBuffer());
|
|
@@ -98330,75 +98767,75 @@ ${import_picocolors40.default.bold("Horus update")}
|
|
|
98330
98767
|
const expectedHash = csText.trim().split(/\s+/)[0];
|
|
98331
98768
|
const actualHash = sha256hex(binBuf);
|
|
98332
98769
|
if (expectedHash !== actualHash) {
|
|
98333
|
-
write(` ${
|
|
98770
|
+
write(` ${import_picocolors41.default.red("\u2717")} Checksum mismatch \u2014 download may be corrupt.`);
|
|
98334
98771
|
write(` Expected: ${expectedHash}`);
|
|
98335
98772
|
write(` Got: ${actualHash}`);
|
|
98336
98773
|
return 1;
|
|
98337
98774
|
}
|
|
98338
|
-
write(` ${
|
|
98775
|
+
write(` ${import_picocolors41.default.green("\u2713")} Checksum verified.`);
|
|
98339
98776
|
}
|
|
98340
98777
|
}
|
|
98341
98778
|
let binaryPath;
|
|
98342
98779
|
try {
|
|
98343
98780
|
binaryPath = resolveBinaryPath();
|
|
98344
98781
|
} catch (e) {
|
|
98345
|
-
write(` ${
|
|
98782
|
+
write(` ${import_picocolors41.default.red("\u2717")} ${e.message}`);
|
|
98346
98783
|
return 1;
|
|
98347
98784
|
}
|
|
98348
|
-
if (!(0,
|
|
98349
|
-
write(` ${
|
|
98785
|
+
if (!(0, import_node_fs19.existsSync)(binaryPath)) {
|
|
98786
|
+
write(` ${import_picocolors41.default.red("\u2717")} Binary not found at ${binaryPath}`);
|
|
98350
98787
|
return 1;
|
|
98351
98788
|
}
|
|
98352
|
-
const tmpPath = (0,
|
|
98789
|
+
const tmpPath = (0, import_node_path21.join)((0, import_node_os5.tmpdir)(), `horus-update-${tag}-${process.pid}`);
|
|
98353
98790
|
const backupPath = `${binaryPath}.bak`;
|
|
98354
98791
|
try {
|
|
98355
|
-
(0,
|
|
98792
|
+
(0, import_node_fs19.writeFileSync)(tmpPath, binBuf, { mode: 493 });
|
|
98356
98793
|
} catch (e) {
|
|
98357
|
-
write(` ${
|
|
98794
|
+
write(` ${import_picocolors41.default.red("\u2717")} Could not write to temp dir: ${e.message}`);
|
|
98358
98795
|
return 1;
|
|
98359
98796
|
}
|
|
98360
98797
|
try {
|
|
98361
|
-
(0,
|
|
98798
|
+
(0, import_node_fs19.renameSync)(binaryPath, backupPath);
|
|
98362
98799
|
try {
|
|
98363
|
-
(0,
|
|
98364
|
-
(0,
|
|
98800
|
+
(0, import_node_fs19.renameSync)(tmpPath, binaryPath);
|
|
98801
|
+
(0, import_node_fs19.chmodSync)(binaryPath, 493);
|
|
98365
98802
|
} catch (e) {
|
|
98366
98803
|
try {
|
|
98367
|
-
(0,
|
|
98804
|
+
(0, import_node_fs19.renameSync)(backupPath, binaryPath);
|
|
98368
98805
|
} catch {
|
|
98369
98806
|
}
|
|
98370
98807
|
throw e;
|
|
98371
98808
|
}
|
|
98372
98809
|
try {
|
|
98373
|
-
(0,
|
|
98810
|
+
(0, import_node_fs19.unlinkSync)(backupPath);
|
|
98374
98811
|
} catch {
|
|
98375
98812
|
}
|
|
98376
98813
|
} catch (e) {
|
|
98377
98814
|
try {
|
|
98378
|
-
(0,
|
|
98815
|
+
(0, import_node_fs19.unlinkSync)(tmpPath);
|
|
98379
98816
|
} catch {
|
|
98380
98817
|
}
|
|
98381
98818
|
const msg = e.message ?? String(e);
|
|
98382
98819
|
const needsSudo = e.code === "EACCES" || e.code === "EPERM";
|
|
98383
|
-
write(` ${
|
|
98820
|
+
write(` ${import_picocolors41.default.red("\u2717")} Could not replace binary at ${binaryPath}: ${msg}`);
|
|
98384
98821
|
if (needsSudo) {
|
|
98385
98822
|
write(`
|
|
98386
98823
|
Try with sudo:`);
|
|
98387
98824
|
write(
|
|
98388
|
-
` ${
|
|
98825
|
+
` ${import_picocolors41.default.dim(`sudo curl -fsSL https://github.com/meritt-dev/horus/releases/download/${tag}/${assetName} -o ${binaryPath} && sudo chmod +x ${binaryPath}`)}`
|
|
98389
98826
|
);
|
|
98390
98827
|
}
|
|
98391
98828
|
return 1;
|
|
98392
98829
|
}
|
|
98393
|
-
write(` ${
|
|
98394
|
-
write(` ${
|
|
98830
|
+
write(` ${import_picocolors41.default.green("\u2713")} Updated: ${import_picocolors41.default.bold(currentVersion)} \u2192 ${import_picocolors41.default.bold(latest)}`);
|
|
98831
|
+
write(` ${import_picocolors41.default.dim(binaryPath)}`);
|
|
98395
98832
|
return 0;
|
|
98396
98833
|
}
|
|
98397
98834
|
|
|
98398
98835
|
// ../../packages/cli/src/commands/login.ts
|
|
98399
98836
|
init_cjs_shims();
|
|
98400
98837
|
var import_node_child_process9 = require("child_process");
|
|
98401
|
-
var
|
|
98838
|
+
var import_picocolors42 = __toESM(require_picocolors(), 1);
|
|
98402
98839
|
var sleep2 = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
|
|
98403
98840
|
function openBrowser(url) {
|
|
98404
98841
|
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
@@ -98423,19 +98860,19 @@ async function loginWithToken(apiBaseUrl, token) {
|
|
|
98423
98860
|
}
|
|
98424
98861
|
});
|
|
98425
98862
|
console.log(
|
|
98426
|
-
`${
|
|
98863
|
+
`${import_picocolors42.default.green("\u2713")} Logged in as ${import_picocolors42.default.bold(me.user.primaryEmail)}. Run ${import_picocolors42.default.bold("horus cloud link")} to connect this repo.`
|
|
98427
98864
|
);
|
|
98428
98865
|
return 0;
|
|
98429
98866
|
} catch (err) {
|
|
98430
98867
|
if (err instanceof CloudOfflineError) {
|
|
98431
|
-
console.error(
|
|
98868
|
+
console.error(import_picocolors42.default.red(err.message));
|
|
98432
98869
|
return 1;
|
|
98433
98870
|
}
|
|
98434
98871
|
if (err instanceof CloudError && err.status === 401) {
|
|
98435
|
-
console.error(
|
|
98872
|
+
console.error(import_picocolors42.default.red("That token is not valid. Create a fresh one in the dashboard and try again."));
|
|
98436
98873
|
return 1;
|
|
98437
98874
|
}
|
|
98438
|
-
console.error(
|
|
98875
|
+
console.error(import_picocolors42.default.red(`Login failed: ${err.message}`));
|
|
98439
98876
|
return 1;
|
|
98440
98877
|
}
|
|
98441
98878
|
}
|
|
@@ -98446,19 +98883,19 @@ async function loginWithBrowser(apiBaseUrl) {
|
|
|
98446
98883
|
session = await client.startCliSession();
|
|
98447
98884
|
} catch (err) {
|
|
98448
98885
|
if (err instanceof CloudOfflineError) {
|
|
98449
|
-
console.error(
|
|
98886
|
+
console.error(import_picocolors42.default.red(err.message));
|
|
98450
98887
|
return 1;
|
|
98451
98888
|
}
|
|
98452
|
-
console.error(
|
|
98889
|
+
console.error(import_picocolors42.default.red(`Could not start login: ${err.message}`));
|
|
98453
98890
|
return 1;
|
|
98454
98891
|
}
|
|
98455
98892
|
console.log("");
|
|
98456
98893
|
console.log(` To sign in, open this URL in your browser:`);
|
|
98457
|
-
console.log(` ${
|
|
98894
|
+
console.log(` ${import_picocolors42.default.cyan(import_picocolors42.default.bold(session.verificationUri))}`);
|
|
98458
98895
|
console.log("");
|
|
98459
|
-
console.log(` and enter the code: ${
|
|
98896
|
+
console.log(` and enter the code: ${import_picocolors42.default.bold(session.userCode)}`);
|
|
98460
98897
|
console.log("");
|
|
98461
|
-
console.log(
|
|
98898
|
+
console.log(import_picocolors42.default.dim(` Waiting for approval\u2026 (press Ctrl+C to cancel)`));
|
|
98462
98899
|
openBrowser(session.verificationUriComplete);
|
|
98463
98900
|
const deadline = Date.now() + session.expiresIn * 1e3;
|
|
98464
98901
|
let intervalMs = Math.max(session.interval, 1) * 1e3;
|
|
@@ -98469,7 +98906,7 @@ async function loginWithBrowser(apiBaseUrl) {
|
|
|
98469
98906
|
poll = await client.pollCliSession(session.deviceCode);
|
|
98470
98907
|
} catch (err) {
|
|
98471
98908
|
if (err instanceof CloudOfflineError) {
|
|
98472
|
-
console.error(
|
|
98909
|
+
console.error(import_picocolors42.default.red(`
|
|
98473
98910
|
${err.message}`));
|
|
98474
98911
|
return 1;
|
|
98475
98912
|
}
|
|
@@ -98482,14 +98919,14 @@ ${err.message}`));
|
|
|
98482
98919
|
intervalMs += 2e3;
|
|
98483
98920
|
break;
|
|
98484
98921
|
case "denied":
|
|
98485
|
-
console.error(
|
|
98922
|
+
console.error(import_picocolors42.default.red("\nLogin was denied in the browser."));
|
|
98486
98923
|
return 1;
|
|
98487
98924
|
case "expired":
|
|
98488
|
-
console.error(
|
|
98925
|
+
console.error(import_picocolors42.default.red("\nThis login request expired. Run `horus login` again."));
|
|
98489
98926
|
return 1;
|
|
98490
98927
|
case "approved":
|
|
98491
98928
|
if (!poll.token || !poll.account) {
|
|
98492
|
-
console.error(
|
|
98929
|
+
console.error(import_picocolors42.default.red("\nLogin approved but no token was returned. Try again."));
|
|
98493
98930
|
return 1;
|
|
98494
98931
|
}
|
|
98495
98932
|
writeAuth({
|
|
@@ -98499,12 +98936,12 @@ ${err.message}`));
|
|
|
98499
98936
|
});
|
|
98500
98937
|
console.log(
|
|
98501
98938
|
`
|
|
98502
|
-
${
|
|
98939
|
+
${import_picocolors42.default.green("\u2713")} Logged in as ${import_picocolors42.default.bold(poll.account.email)}. Run ${import_picocolors42.default.bold("horus cloud link")} to connect this repo.`
|
|
98503
98940
|
);
|
|
98504
98941
|
return 0;
|
|
98505
98942
|
}
|
|
98506
98943
|
}
|
|
98507
|
-
console.error(
|
|
98944
|
+
console.error(import_picocolors42.default.red("\nTimed out waiting for approval. Run `horus login` again."));
|
|
98508
98945
|
return 1;
|
|
98509
98946
|
}
|
|
98510
98947
|
async function runLogin(opts = {}) {
|
|
@@ -98518,7 +98955,7 @@ async function runLogin(opts = {}) {
|
|
|
98518
98955
|
async function runLogout() {
|
|
98519
98956
|
const auth = readAuth();
|
|
98520
98957
|
if (!auth) {
|
|
98521
|
-
console.log(
|
|
98958
|
+
console.log(import_picocolors42.default.dim("Not logged in."));
|
|
98522
98959
|
return 0;
|
|
98523
98960
|
}
|
|
98524
98961
|
const session = authedClient();
|
|
@@ -98532,14 +98969,14 @@ async function runLogout() {
|
|
|
98532
98969
|
}
|
|
98533
98970
|
}
|
|
98534
98971
|
clearAuth();
|
|
98535
|
-
console.log(`${
|
|
98972
|
+
console.log(`${import_picocolors42.default.green("\u2713")} Logged out. Local mode still works.`);
|
|
98536
98973
|
return 0;
|
|
98537
98974
|
}
|
|
98538
98975
|
|
|
98539
98976
|
// ../../packages/cli/src/commands/cloud.ts
|
|
98540
98977
|
init_cjs_shims();
|
|
98541
|
-
var
|
|
98542
|
-
var
|
|
98978
|
+
var import_picocolors43 = __toESM(require_picocolors(), 1);
|
|
98979
|
+
var import_promises3 = require("readline/promises");
|
|
98543
98980
|
|
|
98544
98981
|
// ../../packages/cli/src/lib/cloud/git.ts
|
|
98545
98982
|
init_cjs_shims();
|
|
@@ -98583,7 +99020,7 @@ async function runCloudLink(opts = {}) {
|
|
|
98583
99020
|
const root = repoRootOrCwd(opts.cwd);
|
|
98584
99021
|
const session = authedClient();
|
|
98585
99022
|
if (!session) {
|
|
98586
|
-
console.error(
|
|
99023
|
+
console.error(import_picocolors43.default.red(`Not logged in. Run ${import_picocolors43.default.bold("horus login")} first.`));
|
|
98587
99024
|
return 1;
|
|
98588
99025
|
}
|
|
98589
99026
|
let ctx;
|
|
@@ -98593,7 +99030,7 @@ async function runCloudLink(opts = {}) {
|
|
|
98593
99030
|
return reportCloudError(err);
|
|
98594
99031
|
}
|
|
98595
99032
|
const remote = detectGitRemote(root);
|
|
98596
|
-
if (remote) console.log(
|
|
99033
|
+
if (remote) console.log(import_picocolors43.default.dim(`Detected git remote: ${remote.remoteUrl}`));
|
|
98597
99034
|
let resolved = null;
|
|
98598
99035
|
let target = opts.project;
|
|
98599
99036
|
if (!target) {
|
|
@@ -98609,7 +99046,7 @@ async function runCloudLink(opts = {}) {
|
|
|
98609
99046
|
const org = ctx.organizations.find((o) => o.id === match.organizationId);
|
|
98610
99047
|
if (ws && org) {
|
|
98611
99048
|
target = `${org.slug}/${ws.slug}/${match.slug}`;
|
|
98612
|
-
console.log(
|
|
99049
|
+
console.log(import_picocolors43.default.dim(`Matched existing project by remote: ${import_picocolors43.default.bold(target)}`));
|
|
98613
99050
|
}
|
|
98614
99051
|
}
|
|
98615
99052
|
}
|
|
@@ -98618,8 +99055,8 @@ async function runCloudLink(opts = {}) {
|
|
|
98618
99055
|
if (created === "aborted") return 1;
|
|
98619
99056
|
if (!created) {
|
|
98620
99057
|
console.error(
|
|
98621
|
-
|
|
98622
|
-
Run ${
|
|
99058
|
+
import_picocolors43.default.red("No project to link.") + `
|
|
99059
|
+
Run ${import_picocolors43.default.bold("horus cloud link")} in a TTY to create one, pass ${import_picocolors43.default.bold("--project <org/workspace/project>")}, or create a project at ${import_picocolors43.default.bold("https://cloud.horus.sh")}.`
|
|
98623
99060
|
);
|
|
98624
99061
|
return 1;
|
|
98625
99062
|
}
|
|
@@ -98629,8 +99066,8 @@ async function runCloudLink(opts = {}) {
|
|
|
98629
99066
|
resolved = resolveTriple(ctx, target);
|
|
98630
99067
|
if (!resolved) {
|
|
98631
99068
|
console.error(
|
|
98632
|
-
|
|
98633
|
-
Run ${
|
|
99069
|
+
import_picocolors43.default.red(`You don't have access to ${import_picocolors43.default.bold(target)}.`) + `
|
|
99070
|
+
Run ${import_picocolors43.default.bold("horus context list")} to see available projects.`
|
|
98634
99071
|
);
|
|
98635
99072
|
return 1;
|
|
98636
99073
|
}
|
|
@@ -98643,10 +99080,10 @@ async function runCloudLink(opts = {}) {
|
|
|
98643
99080
|
project: resolved.project
|
|
98644
99081
|
});
|
|
98645
99082
|
console.log(
|
|
98646
|
-
`${
|
|
99083
|
+
`${import_picocolors43.default.green("\u2713")} Linked. Context for this repo is now ${import_picocolors43.default.bold(label)} ${import_picocolors43.default.dim("(cloud)")}.`
|
|
98647
99084
|
);
|
|
98648
99085
|
console.log(
|
|
98649
|
-
|
|
99086
|
+
import_picocolors43.default.dim(` Investigations here save to Horus Cloud. ${import_picocolors43.default.bold("horus context use local")} to switch back.`)
|
|
98650
99087
|
);
|
|
98651
99088
|
return 0;
|
|
98652
99089
|
}
|
|
@@ -98654,11 +99091,11 @@ async function runCloudUnlink(opts = {}) {
|
|
|
98654
99091
|
const root = repoRootOrCwd(opts.cwd);
|
|
98655
99092
|
const cfg = readCloudConfig(root);
|
|
98656
99093
|
if (!cfg || cfg.context !== "cloud") {
|
|
98657
|
-
console.log(
|
|
99094
|
+
console.log(import_picocolors43.default.dim("This repo isn't linked to a cloud project."));
|
|
98658
99095
|
return 0;
|
|
98659
99096
|
}
|
|
98660
99097
|
clearCloudConfig(root);
|
|
98661
|
-
console.log(`${
|
|
99098
|
+
console.log(`${import_picocolors43.default.green("\u2713")} Unlinked. This repo is back to ${import_picocolors43.default.bold("local")} mode.`);
|
|
98662
99099
|
return 0;
|
|
98663
99100
|
}
|
|
98664
99101
|
async function runCloudStatus(opts = {}) {
|
|
@@ -98666,18 +99103,18 @@ async function runCloudStatus(opts = {}) {
|
|
|
98666
99103
|
const cfg = readCloudConfig(root);
|
|
98667
99104
|
const session = authedClient();
|
|
98668
99105
|
if (!isCloudActive(cfg) || !cfg?.project) {
|
|
98669
|
-
console.log(`${
|
|
98670
|
-
console.log(`${
|
|
99106
|
+
console.log(`${import_picocolors43.default.bold("Context:")} local`);
|
|
99107
|
+
console.log(`${import_picocolors43.default.bold("Storage:")} local Postgres (~/.horus)`);
|
|
98671
99108
|
console.log(
|
|
98672
|
-
|
|
99109
|
+
import_picocolors43.default.dim(`Tip: ${import_picocolors43.default.bold("horus login")} then ${import_picocolors43.default.bold("horus cloud link")} to share investigations with your team.`)
|
|
98673
99110
|
);
|
|
98674
99111
|
return 0;
|
|
98675
99112
|
}
|
|
98676
99113
|
const triple = `${cfg.organization?.slug}/${cfg.workspace?.slug}/${cfg.project.slug}`;
|
|
98677
|
-
console.log(`${
|
|
99114
|
+
console.log(`${import_picocolors43.default.bold("Context:")} ${triple} ${import_picocolors43.default.dim("(cloud)")}`);
|
|
98678
99115
|
let projectLine = `${cfg.project.slug}`;
|
|
98679
99116
|
let metaLines = [];
|
|
98680
|
-
let account =
|
|
99117
|
+
let account = import_picocolors43.default.dim("not logged in");
|
|
98681
99118
|
if (session) {
|
|
98682
99119
|
account = session.auth.account.email;
|
|
98683
99120
|
try {
|
|
@@ -98692,9 +99129,9 @@ async function runCloudStatus(opts = {}) {
|
|
|
98692
99129
|
} catch {
|
|
98693
99130
|
}
|
|
98694
99131
|
}
|
|
98695
|
-
console.log(`${
|
|
99132
|
+
console.log(`${import_picocolors43.default.bold("Project:")} ${projectLine}`);
|
|
98696
99133
|
for (const line2 of metaLines) console.log(line2);
|
|
98697
|
-
console.log(`${
|
|
99134
|
+
console.log(`${import_picocolors43.default.bold("Account:")} ${account}`);
|
|
98698
99135
|
return 0;
|
|
98699
99136
|
}
|
|
98700
99137
|
async function runCloudSync(opts = {}) {
|
|
@@ -98702,13 +99139,13 @@ async function runCloudSync(opts = {}) {
|
|
|
98702
99139
|
const cfg = readCloudConfig(root);
|
|
98703
99140
|
if (!isCloudActive(cfg) || !cfg.project) {
|
|
98704
99141
|
console.error(
|
|
98705
|
-
|
|
99142
|
+
import_picocolors43.default.red("This repo isn't linked to a cloud project.") + ` Run ${import_picocolors43.default.bold("horus cloud link")} first.`
|
|
98706
99143
|
);
|
|
98707
99144
|
return 1;
|
|
98708
99145
|
}
|
|
98709
99146
|
const session = authedClient();
|
|
98710
99147
|
if (!session) {
|
|
98711
|
-
console.error(
|
|
99148
|
+
console.error(import_picocolors43.default.red(`Not logged in. Run ${import_picocolors43.default.bold("horus login")} first.`));
|
|
98712
99149
|
return 1;
|
|
98713
99150
|
}
|
|
98714
99151
|
const { db, sql: sql2 } = createDb(await resolveDbUrl(opts.config));
|
|
@@ -98729,34 +99166,34 @@ async function runCloudSync(opts = {}) {
|
|
|
98729
99166
|
const target = `${cfg.organization?.slug}/${cfg.workspace?.slug}/${cfg.project.slug}`;
|
|
98730
99167
|
if (uploadable.length === 0) {
|
|
98731
99168
|
console.log(
|
|
98732
|
-
|
|
99169
|
+
import_picocolors43.default.dim(
|
|
98733
99170
|
`No local investigations with reports to upload.` + (skippedNoReport ? ` (${skippedNoReport} without a report skipped)` : "")
|
|
98734
99171
|
)
|
|
98735
99172
|
);
|
|
98736
99173
|
return 0;
|
|
98737
99174
|
}
|
|
98738
|
-
console.log(
|
|
99175
|
+
console.log(import_picocolors43.default.bold(`Will upload ${uploadable.length} investigation(s) to ${target} ${import_picocolors43.default.dim("(cloud)")}:`));
|
|
98739
99176
|
for (const c of uploadable.slice(0, 20)) {
|
|
98740
|
-
console.log(` ${
|
|
99177
|
+
console.log(` ${import_picocolors43.default.dim(c.id.slice(0, 8))} ${(c.title ?? "untitled").slice(0, 70)}`);
|
|
98741
99178
|
}
|
|
98742
|
-
if (uploadable.length > 20) console.log(
|
|
98743
|
-
if (skippedNoReport) console.log(
|
|
99179
|
+
if (uploadable.length > 20) console.log(import_picocolors43.default.dim(` \u2026and ${uploadable.length - 20} more`));
|
|
99180
|
+
if (skippedNoReport) console.log(import_picocolors43.default.dim(` (${skippedNoReport} local investigation(s) without a report will be skipped)`));
|
|
98744
99181
|
if (opts.dryRun) {
|
|
98745
|
-
console.log(
|
|
99182
|
+
console.log(import_picocolors43.default.dim("Dry run \u2014 nothing uploaded. Re-run without --dry-run to upload."));
|
|
98746
99183
|
return 0;
|
|
98747
99184
|
}
|
|
98748
99185
|
if (!opts.yes) {
|
|
98749
99186
|
if (!process.stdin.isTTY) {
|
|
98750
99187
|
console.error(
|
|
98751
|
-
|
|
99188
|
+
import_picocolors43.default.yellow(`Re-run with ${import_picocolors43.default.bold("--yes")} to upload, or ${import_picocolors43.default.bold("--dry-run")} to preview only.`)
|
|
98752
99189
|
);
|
|
98753
99190
|
return 1;
|
|
98754
99191
|
}
|
|
98755
|
-
const rl = (0,
|
|
99192
|
+
const rl = (0, import_promises3.createInterface)({ input: process.stdin, output: process.stdout });
|
|
98756
99193
|
try {
|
|
98757
99194
|
const answer = (await rl.question(`Upload ${uploadable.length} investigation(s) to ${target}? (y/N) `)).trim().toLowerCase();
|
|
98758
99195
|
if (answer !== "y" && answer !== "yes") {
|
|
98759
|
-
console.log(
|
|
99196
|
+
console.log(import_picocolors43.default.dim("Aborted. Nothing uploaded."));
|
|
98760
99197
|
return 0;
|
|
98761
99198
|
}
|
|
98762
99199
|
} finally {
|
|
@@ -98769,18 +99206,18 @@ async function runCloudSync(opts = {}) {
|
|
|
98769
99206
|
try {
|
|
98770
99207
|
const refs = await uploadInvestigationToCloud(session.client, cfg, c.report);
|
|
98771
99208
|
created++;
|
|
98772
|
-
console.log(`${
|
|
99209
|
+
console.log(`${import_picocolors43.default.green("\u2713")} ${import_picocolors43.default.dim(c.id.slice(0, 8))} \u2192 ${refs.investigationId}`);
|
|
98773
99210
|
} catch (err) {
|
|
98774
99211
|
failed++;
|
|
98775
|
-
console.error(`${
|
|
99212
|
+
console.error(`${import_picocolors43.default.red("\u2717")} ${import_picocolors43.default.dim(c.id.slice(0, 8))} ${err.message}`);
|
|
98776
99213
|
}
|
|
98777
99214
|
}
|
|
98778
99215
|
console.log("");
|
|
98779
99216
|
console.log(
|
|
98780
|
-
`${
|
|
99217
|
+
`${import_picocolors43.default.bold("Sync complete:")} ${import_picocolors43.default.green(`${created} uploaded`)}, ${skippedNoReport} skipped, ` + (failed ? import_picocolors43.default.red(`${failed} failed`) : "0 failed") + "."
|
|
98781
99218
|
);
|
|
98782
99219
|
console.log(
|
|
98783
|
-
|
|
99220
|
+
import_picocolors43.default.dim("Local data was not modified. Re-running is safe \u2014 duplicates are deduped by idempotency key.")
|
|
98784
99221
|
);
|
|
98785
99222
|
return failed > 0 ? 1 : 0;
|
|
98786
99223
|
}
|
|
@@ -98788,12 +99225,12 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
|
|
|
98788
99225
|
if (!process.stdin.isTTY && !yes) return null;
|
|
98789
99226
|
if (ctx.organizations.length === 0) {
|
|
98790
99227
|
console.error(
|
|
98791
|
-
|
|
98792
|
-
Create one at ${
|
|
99228
|
+
import_picocolors43.default.red("You're not a member of any organization yet.") + `
|
|
99229
|
+
Create one at ${import_picocolors43.default.bold("https://cloud.horus.sh")} first.`
|
|
98793
99230
|
);
|
|
98794
99231
|
return null;
|
|
98795
99232
|
}
|
|
98796
|
-
const rl = (0,
|
|
99233
|
+
const rl = (0, import_promises3.createInterface)({ input: process.stdin, output: process.stdout });
|
|
98797
99234
|
const ask2 = async (q, def) => {
|
|
98798
99235
|
if (yes && def !== void 0) return def;
|
|
98799
99236
|
const a = (await rl.question(def ? `${q} (${def}): ` : `${q}: `)).trim();
|
|
@@ -98814,9 +99251,9 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
|
|
|
98814
99251
|
const wsName = await ask2("New workspace name", repoName || "default");
|
|
98815
99252
|
const ws = await client.createWorkspace(org.id, { name: wsName });
|
|
98816
99253
|
workspace = { id: ws.id, slug: ws.slug };
|
|
98817
|
-
console.log(
|
|
99254
|
+
console.log(import_picocolors43.default.dim(`Created workspace ${import_picocolors43.default.bold(ws.slug)}.`));
|
|
98818
99255
|
} else {
|
|
98819
|
-
console.log(`Workspaces in ${
|
|
99256
|
+
console.log(`Workspaces in ${import_picocolors43.default.bold(org.slug)}:`);
|
|
98820
99257
|
orgWorkspaces.forEach((w, i) => console.log(` ${i + 1}) ${w.slug}`));
|
|
98821
99258
|
console.log(` ${orgWorkspaces.length + 1}) + create a new workspace`);
|
|
98822
99259
|
const pick2 = Number(await ask2("Workspace number", "1"));
|
|
@@ -98824,7 +99261,7 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
|
|
|
98824
99261
|
const wsName = await ask2("New workspace name", repoName || "default");
|
|
98825
99262
|
const ws = await client.createWorkspace(org.id, { name: wsName });
|
|
98826
99263
|
workspace = { id: ws.id, slug: ws.slug };
|
|
98827
|
-
console.log(
|
|
99264
|
+
console.log(import_picocolors43.default.dim(`Created workspace ${import_picocolors43.default.bold(ws.slug)}.`));
|
|
98828
99265
|
} else {
|
|
98829
99266
|
const chosen = orgWorkspaces[pick2 - 1] ?? orgWorkspaces[0];
|
|
98830
99267
|
workspace = { id: chosen.id, slug: chosen.slug };
|
|
@@ -98836,7 +99273,7 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
|
|
|
98836
99273
|
remoteUrl: remote?.remoteUrl,
|
|
98837
99274
|
provider: remote ? inferProvider(remote.remoteUrl) : void 0
|
|
98838
99275
|
});
|
|
98839
|
-
console.log(
|
|
99276
|
+
console.log(import_picocolors43.default.dim(`Created project ${import_picocolors43.default.bold(project.slug)}.`));
|
|
98840
99277
|
return {
|
|
98841
99278
|
organization: { id: org.id, slug: org.slug },
|
|
98842
99279
|
workspace,
|
|
@@ -98850,6 +99287,274 @@ async function createProjectFromRepo(client, ctx, remote, yes) {
|
|
|
98850
99287
|
}
|
|
98851
99288
|
}
|
|
98852
99289
|
|
|
99290
|
+
// ../../packages/cli/src/commands/telemetry.ts
|
|
99291
|
+
init_cjs_shims();
|
|
99292
|
+
var import_picocolors45 = __toESM(require_picocolors(), 1);
|
|
99293
|
+
var import_node_crypto8 = require("crypto");
|
|
99294
|
+
|
|
99295
|
+
// ../../packages/cli/src/lib/telemetry/transport.ts
|
|
99296
|
+
init_cjs_shims();
|
|
99297
|
+
var CHUNK = 100;
|
|
99298
|
+
var DEFAULT_TIMEOUT_MS = 1500;
|
|
99299
|
+
function telemetryBaseUrl() {
|
|
99300
|
+
return process.env.HORUS_TELEMETRY_URL ?? process.env.HORUS_API_BASE_URL ?? readAuth()?.apiBaseUrl ?? DEFAULT_API_BASE_URL;
|
|
99301
|
+
}
|
|
99302
|
+
async function postBatch(url, events, signal) {
|
|
99303
|
+
const res = await fetch(url, {
|
|
99304
|
+
method: "POST",
|
|
99305
|
+
headers: { "content-type": "application/json" },
|
|
99306
|
+
body: JSON.stringify({ events }),
|
|
99307
|
+
signal
|
|
99308
|
+
});
|
|
99309
|
+
return res.ok;
|
|
99310
|
+
}
|
|
99311
|
+
async function flushTelemetry(opts = {}) {
|
|
99312
|
+
try {
|
|
99313
|
+
if (!resolveConsent().tierA) return;
|
|
99314
|
+
const events = readSpooledEvents();
|
|
99315
|
+
if (events.length === 0) return;
|
|
99316
|
+
const url = `${telemetryBaseUrl().replace(/\/$/, "")}/v1/telemetry`;
|
|
99317
|
+
const controller = new AbortController();
|
|
99318
|
+
const timer2 = setTimeout(() => controller.abort(), opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
99319
|
+
try {
|
|
99320
|
+
for (let i = 0; i < events.length; i += CHUNK) {
|
|
99321
|
+
const ok = await postBatch(url, events.slice(i, i + CHUNK), controller.signal);
|
|
99322
|
+
if (!ok) return;
|
|
99323
|
+
}
|
|
99324
|
+
clearSpool();
|
|
99325
|
+
} finally {
|
|
99326
|
+
clearTimeout(timer2);
|
|
99327
|
+
}
|
|
99328
|
+
} catch {
|
|
99329
|
+
}
|
|
99330
|
+
}
|
|
99331
|
+
async function deleteRemoteTelemetry(installId, opts = {}) {
|
|
99332
|
+
try {
|
|
99333
|
+
if (!installId) return;
|
|
99334
|
+
const url = `${telemetryBaseUrl().replace(/\/$/, "")}/v1/telemetry/delete`;
|
|
99335
|
+
const controller = new AbortController();
|
|
99336
|
+
const timer2 = setTimeout(() => controller.abort(), opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
99337
|
+
try {
|
|
99338
|
+
await fetch(url, {
|
|
99339
|
+
method: "POST",
|
|
99340
|
+
headers: { "content-type": "application/json" },
|
|
99341
|
+
body: JSON.stringify({ installId }),
|
|
99342
|
+
signal: controller.signal
|
|
99343
|
+
});
|
|
99344
|
+
} finally {
|
|
99345
|
+
clearTimeout(timer2);
|
|
99346
|
+
}
|
|
99347
|
+
} catch {
|
|
99348
|
+
}
|
|
99349
|
+
}
|
|
99350
|
+
|
|
99351
|
+
// ../../packages/cli/src/lib/telemetry/notice.ts
|
|
99352
|
+
init_cjs_shims();
|
|
99353
|
+
var import_picocolors44 = __toESM(require_picocolors(), 1);
|
|
99354
|
+
var PRIVACY_URL = "https://horus.sh/privacy";
|
|
99355
|
+
var SUPPRESS_FIRST_TOKEN = /* @__PURE__ */ new Set(["telemetry", "help"]);
|
|
99356
|
+
var SUPPRESS_FLAGS = /* @__PURE__ */ new Set(["-V", "--version", "-h", "--help"]);
|
|
99357
|
+
function shouldSuppressFor(argv) {
|
|
99358
|
+
const args = argv.slice(2);
|
|
99359
|
+
if (args.length === 0) return true;
|
|
99360
|
+
if (args.some((a) => SUPPRESS_FLAGS.has(a))) return true;
|
|
99361
|
+
const firstToken = args.find((a) => !a.startsWith("-"));
|
|
99362
|
+
return firstToken != null && SUPPRESS_FIRST_TOKEN.has(firstToken);
|
|
99363
|
+
}
|
|
99364
|
+
function banner() {
|
|
99365
|
+
const b2 = import_picocolors44.default.bold;
|
|
99366
|
+
const dim = import_picocolors44.default.dim;
|
|
99367
|
+
return [
|
|
99368
|
+
"",
|
|
99369
|
+
import_picocolors44.default.cyan(b2("Horus collects anonymous usage data to improve the tool.")),
|
|
99370
|
+
dim(" \u2022 On by default: command names, timings, success/failure, and where the"),
|
|
99371
|
+
dim(" engine ran out of evidence. No file contents, queries, or secrets."),
|
|
99372
|
+
dim(" \u2022 Off by default: your investigation inputs/outputs (opt in to help train"),
|
|
99373
|
+
` ${dim("Horus)")} ${dim("\u2014 run")} ${b2("horus telemetry enable-content")}`,
|
|
99374
|
+
dim(" \u2022 If you use Horus Cloud, linked investigations sync to your workspace."),
|
|
99375
|
+
"",
|
|
99376
|
+
` ${dim("Opt out anytime:")} ${b2("horus telemetry disable")} ${dim("\xB7")} ${b2("HORUS_TELEMETRY=0")} ${dim("\xB7")} ${b2("DO_NOT_TRACK=1")}`,
|
|
99377
|
+
` ${dim("Details:")} ${import_picocolors44.default.underline(PRIVACY_URL)}`,
|
|
99378
|
+
""
|
|
99379
|
+
].join("\n");
|
|
99380
|
+
}
|
|
99381
|
+
function maybeShowFirstRunNotice(argv = process.argv) {
|
|
99382
|
+
try {
|
|
99383
|
+
const env = process.env;
|
|
99384
|
+
if (resolveConsent({ env }).forcedOff) return;
|
|
99385
|
+
if (isCI(env)) return;
|
|
99386
|
+
const state = loadOrInitTelemetryState();
|
|
99387
|
+
if (state.tierA.noticeShownAt) return;
|
|
99388
|
+
if (shouldSuppressFor(argv)) return;
|
|
99389
|
+
if (!process.stderr.isTTY) return;
|
|
99390
|
+
process.stderr.write(banner() + "\n");
|
|
99391
|
+
updateTelemetryState((s) => {
|
|
99392
|
+
s.tierA.noticeShownAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
99393
|
+
});
|
|
99394
|
+
} catch {
|
|
99395
|
+
}
|
|
99396
|
+
}
|
|
99397
|
+
|
|
99398
|
+
// ../../packages/cli/src/commands/telemetry.ts
|
|
99399
|
+
function onOff(enabled) {
|
|
99400
|
+
return enabled ? import_picocolors45.default.green("on") : import_picocolors45.default.dim("off");
|
|
99401
|
+
}
|
|
99402
|
+
function warnIfEnvOverrides() {
|
|
99403
|
+
const decision = resolveConsent();
|
|
99404
|
+
if (decision.forcedOff) {
|
|
99405
|
+
console.log(
|
|
99406
|
+
import_picocolors45.default.yellow(
|
|
99407
|
+
`
|
|
99408
|
+
Note: telemetry is currently forced off by your environment (${decision.reason}).`
|
|
99409
|
+
)
|
|
99410
|
+
);
|
|
99411
|
+
console.log(import_picocolors45.default.dim("Your saved preference will apply once that override is removed."));
|
|
99412
|
+
} else if (decision.source === "ci") {
|
|
99413
|
+
console.log(
|
|
99414
|
+
import_picocolors45.default.yellow("\nNote: CI environment detected \u2014 telemetry stays off here regardless.")
|
|
99415
|
+
);
|
|
99416
|
+
}
|
|
99417
|
+
}
|
|
99418
|
+
async function runTelemetryStatus() {
|
|
99419
|
+
const state = readTelemetryState();
|
|
99420
|
+
const decision = resolveConsent({ state });
|
|
99421
|
+
console.log(import_picocolors45.default.bold("Horus telemetry"));
|
|
99422
|
+
console.log(
|
|
99423
|
+
` Usage metadata (Tier A): ${onOff(decision.tierA)} ${import_picocolors45.default.dim(`[${decision.source}]`)}`
|
|
99424
|
+
);
|
|
99425
|
+
console.log(` Content sharing (Tier B): ${onOff(decision.tierB)}`);
|
|
99426
|
+
console.log(import_picocolors45.default.dim(` Reason: ${decision.reason}`));
|
|
99427
|
+
if (state) {
|
|
99428
|
+
console.log(import_picocolors45.default.dim(` Install ID: ${state.installId}`));
|
|
99429
|
+
console.log(
|
|
99430
|
+
import_picocolors45.default.dim(
|
|
99431
|
+
` Saved: Tier A ${state.tierA.enabled ? "on" : "off"}, Tier B ${state.tierB.enabled ? "on" : "off"}`
|
|
99432
|
+
)
|
|
99433
|
+
);
|
|
99434
|
+
} else {
|
|
99435
|
+
console.log(import_picocolors45.default.dim(" No saved preference yet (defaults apply)."));
|
|
99436
|
+
}
|
|
99437
|
+
console.log(import_picocolors45.default.dim(` Config: ${telemetryPath()}`));
|
|
99438
|
+
console.log(import_picocolors45.default.dim(` Privacy: ${PRIVACY_URL}`));
|
|
99439
|
+
if (!state || decision.source === "env" || decision.source === "ci") {
|
|
99440
|
+
warnIfEnvOverrides();
|
|
99441
|
+
}
|
|
99442
|
+
return 0;
|
|
99443
|
+
}
|
|
99444
|
+
async function runTelemetryEnable() {
|
|
99445
|
+
updateTelemetryState((s) => {
|
|
99446
|
+
s.tierA.enabled = true;
|
|
99447
|
+
if (!s.tierA.noticeShownAt) s.tierA.noticeShownAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
99448
|
+
});
|
|
99449
|
+
console.log(import_picocolors45.default.green("Anonymous usage metadata (Tier A) is now ON. Thank you!"));
|
|
99450
|
+
warnIfEnvOverrides();
|
|
99451
|
+
return 0;
|
|
99452
|
+
}
|
|
99453
|
+
async function runTelemetryDisable() {
|
|
99454
|
+
updateTelemetryState((s) => {
|
|
99455
|
+
s.tierA.enabled = false;
|
|
99456
|
+
s.tierB.enabled = false;
|
|
99457
|
+
if (!s.tierA.noticeShownAt) s.tierA.noticeShownAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
99458
|
+
});
|
|
99459
|
+
console.log(import_picocolors45.default.yellow("All telemetry is now OFF (Tier A and Tier B)."));
|
|
99460
|
+
return 0;
|
|
99461
|
+
}
|
|
99462
|
+
async function runTelemetryEnableContent() {
|
|
99463
|
+
updateTelemetryState((s) => {
|
|
99464
|
+
s.tierA.enabled = true;
|
|
99465
|
+
s.tierB.enabled = true;
|
|
99466
|
+
s.tierB.enabledAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
99467
|
+
if (!s.tierA.noticeShownAt) s.tierA.noticeShownAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
99468
|
+
});
|
|
99469
|
+
console.log(
|
|
99470
|
+
import_picocolors45.default.green("Content sharing (Tier B) is now ON \u2014 redacted inputs/outputs help improve Horus.")
|
|
99471
|
+
);
|
|
99472
|
+
console.log(import_picocolors45.default.dim("Content is scrubbed of secrets/PII before it ever leaves your machine."));
|
|
99473
|
+
console.log(import_picocolors45.default.dim(`What this means: ${PRIVACY_URL}`));
|
|
99474
|
+
warnIfEnvOverrides();
|
|
99475
|
+
return 0;
|
|
99476
|
+
}
|
|
99477
|
+
async function runTelemetryDisableContent() {
|
|
99478
|
+
updateTelemetryState((s) => {
|
|
99479
|
+
s.tierB.enabled = false;
|
|
99480
|
+
});
|
|
99481
|
+
console.log(import_picocolors45.default.yellow("Content sharing (Tier B) is now OFF. Usage metadata is unchanged."));
|
|
99482
|
+
return 0;
|
|
99483
|
+
}
|
|
99484
|
+
async function runTelemetryResetId() {
|
|
99485
|
+
const next = (0, import_node_crypto8.randomUUID)();
|
|
99486
|
+
updateTelemetryState((s) => {
|
|
99487
|
+
s.installId = next;
|
|
99488
|
+
});
|
|
99489
|
+
console.log(import_picocolors45.default.green("Install ID reset."));
|
|
99490
|
+
console.log(import_picocolors45.default.dim(` New install ID: ${next}`));
|
|
99491
|
+
return 0;
|
|
99492
|
+
}
|
|
99493
|
+
async function runTelemetryDelete() {
|
|
99494
|
+
const installId = readTelemetryState()?.installId;
|
|
99495
|
+
if (installId) await deleteRemoteTelemetry(installId);
|
|
99496
|
+
deleteTelemetryState();
|
|
99497
|
+
clearSpool();
|
|
99498
|
+
console.log(import_picocolors45.default.green("Telemetry deleted \u2014 local state cleared and a server purge requested."));
|
|
99499
|
+
console.log(
|
|
99500
|
+
import_picocolors45.default.dim(
|
|
99501
|
+
"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."
|
|
99502
|
+
)
|
|
99503
|
+
);
|
|
99504
|
+
return 0;
|
|
99505
|
+
}
|
|
99506
|
+
|
|
99507
|
+
// ../../packages/cli/src/lib/telemetry/command-hooks.ts
|
|
99508
|
+
init_cjs_shims();
|
|
99509
|
+
function commandPath(cmd) {
|
|
99510
|
+
const parts = [];
|
|
99511
|
+
let current = cmd;
|
|
99512
|
+
while (current && current.parent) {
|
|
99513
|
+
parts.unshift(current.name());
|
|
99514
|
+
current = current.parent;
|
|
99515
|
+
}
|
|
99516
|
+
return parts.join(" ") || cmd.name();
|
|
99517
|
+
}
|
|
99518
|
+
function installCommandTelemetry(program2) {
|
|
99519
|
+
let startedAt = 0;
|
|
99520
|
+
program2.hook("preAction", (_thisCommand, actionCommand) => {
|
|
99521
|
+
startedAt = Date.now();
|
|
99522
|
+
track({
|
|
99523
|
+
type: "command.invoked",
|
|
99524
|
+
command: commandPath(actionCommand),
|
|
99525
|
+
flags: extractFlagNames(process.argv)
|
|
99526
|
+
});
|
|
99527
|
+
});
|
|
99528
|
+
program2.hook("postAction", (_thisCommand, actionCommand) => {
|
|
99529
|
+
const exitCode = typeof process.exitCode === "number" ? process.exitCode : 0;
|
|
99530
|
+
track({
|
|
99531
|
+
type: "command.completed",
|
|
99532
|
+
command: commandPath(actionCommand),
|
|
99533
|
+
flags: extractFlagNames(process.argv),
|
|
99534
|
+
durationMs: startedAt ? Date.now() - startedAt : 0,
|
|
99535
|
+
exitCode,
|
|
99536
|
+
ok: exitCode === 0
|
|
99537
|
+
});
|
|
99538
|
+
});
|
|
99539
|
+
}
|
|
99540
|
+
|
|
99541
|
+
// ../../packages/cli/src/commands/feedback.ts
|
|
99542
|
+
init_cjs_shims();
|
|
99543
|
+
var import_picocolors46 = __toESM(require_picocolors(), 1);
|
|
99544
|
+
async function runFeedback(investigationId) {
|
|
99545
|
+
if (!process.stdin.isTTY) {
|
|
99546
|
+
console.error(import_picocolors46.default.yellow("horus feedback needs an interactive terminal."));
|
|
99547
|
+
return 1;
|
|
99548
|
+
}
|
|
99549
|
+
const id = investigationId?.trim();
|
|
99550
|
+
if (!id) {
|
|
99551
|
+
console.error(import_picocolors46.default.red("Usage: horus feedback <investigationId>"));
|
|
99552
|
+
return 1;
|
|
99553
|
+
}
|
|
99554
|
+
await runFeedbackPrompt(id, null);
|
|
99555
|
+
return 0;
|
|
99556
|
+
}
|
|
99557
|
+
|
|
98853
99558
|
// ../../packages/cli/src/index.ts
|
|
98854
99559
|
function buildProgram() {
|
|
98855
99560
|
const program2 = new Command();
|
|
@@ -99271,11 +99976,50 @@ Examples:
|
|
|
99271
99976
|
horus cloud sync --dry-run # preview what would upload
|
|
99272
99977
|
horus cloud sync # confirm, then upload
|
|
99273
99978
|
horus cloud sync --yes # upload without prompting`);
|
|
99979
|
+
program2.command("feedback [investigationId]").description("Leave quick impact feedback on an investigation (helps improve Horus)").action(async (investigationId) => {
|
|
99980
|
+
process.exitCode = await runFeedback(investigationId);
|
|
99981
|
+
});
|
|
99982
|
+
const telemetry = program2.command("telemetry").description("Manage anonymous usage telemetry that helps improve Horus");
|
|
99983
|
+
telemetry.command("status").description("Show the effective telemetry decision, saved preferences, and install ID").action(async () => {
|
|
99984
|
+
process.exitCode = await runTelemetryStatus();
|
|
99985
|
+
});
|
|
99986
|
+
telemetry.command("enable").description("Turn on anonymous usage metadata (Tier A)").action(async () => {
|
|
99987
|
+
process.exitCode = await runTelemetryEnable();
|
|
99988
|
+
});
|
|
99989
|
+
telemetry.command("disable").description("Turn off all telemetry (Tier A and Tier B)").action(async () => {
|
|
99990
|
+
process.exitCode = await runTelemetryDisable();
|
|
99991
|
+
});
|
|
99992
|
+
telemetry.command("enable-content").description("Opt in to sharing redacted investigation inputs/outputs (Tier B)").action(async () => {
|
|
99993
|
+
process.exitCode = await runTelemetryEnableContent();
|
|
99994
|
+
});
|
|
99995
|
+
telemetry.command("disable-content").description("Stop sharing inputs/outputs; keep usage metadata (Tier B off)").action(async () => {
|
|
99996
|
+
process.exitCode = await runTelemetryDisableContent();
|
|
99997
|
+
});
|
|
99998
|
+
telemetry.command("reset-id").description("Generate a new random install ID").action(async () => {
|
|
99999
|
+
process.exitCode = await runTelemetryResetId();
|
|
100000
|
+
});
|
|
100001
|
+
telemetry.command("delete").description("Delete local telemetry state (install ID + saved preferences)").action(async () => {
|
|
100002
|
+
process.exitCode = await runTelemetryDelete();
|
|
100003
|
+
});
|
|
100004
|
+
telemetry.addHelpText(
|
|
100005
|
+
"after",
|
|
100006
|
+
`
|
|
100007
|
+
Defaults: usage metadata ON (with this notice), content sharing OFF.
|
|
100008
|
+
Hard opt-out via env: HORUS_TELEMETRY=0 or DO_NOT_TRACK=1.
|
|
100009
|
+
|
|
100010
|
+
Examples:
|
|
100011
|
+
horus telemetry status
|
|
100012
|
+
horus telemetry disable
|
|
100013
|
+
horus telemetry enable-content`
|
|
100014
|
+
);
|
|
99274
100015
|
return program2;
|
|
99275
100016
|
}
|
|
99276
100017
|
async function run(argv = process.argv) {
|
|
100018
|
+
maybeShowFirstRunNotice(argv);
|
|
99277
100019
|
const program2 = buildProgram();
|
|
100020
|
+
installCommandTelemetry(program2);
|
|
99278
100021
|
await program2.parseAsync(argv);
|
|
100022
|
+
await flushTelemetry();
|
|
99279
100023
|
}
|
|
99280
100024
|
|
|
99281
100025
|
// src/index.ts
|