kifaru 1.0.169 → 1.0.170
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/kifaru-pi.js +96 -20
- package/package.json +2 -2
package/kifaru-pi.js
CHANGED
|
@@ -16476,7 +16476,7 @@ var init_installation = __esm(async () => {
|
|
|
16476
16476
|
});
|
|
16477
16477
|
}
|
|
16478
16478
|
Installation.upgrade = upgrade;
|
|
16479
|
-
Installation.VERSION = "1.0.
|
|
16479
|
+
Installation.VERSION = "1.0.170";
|
|
16480
16480
|
Installation.CHANNEL = typeof KIFARU_CHANNEL === "string" ? KIFARU_CHANNEL : "local";
|
|
16481
16481
|
Installation.USER_AGENT = `kifaru/${Installation.CHANNEL}/${Installation.VERSION}`;
|
|
16482
16482
|
async function latest() {
|
|
@@ -127710,6 +127710,63 @@ ${await capturePythonPrompt(ctx.cwd)}`
|
|
|
127710
127710
|
};
|
|
127711
127711
|
}
|
|
127712
127712
|
|
|
127713
|
+
// src/tui-logger.ts
|
|
127714
|
+
import fs14 from "fs";
|
|
127715
|
+
import os10 from "os";
|
|
127716
|
+
import path21 from "path";
|
|
127717
|
+
function kifaruDataDir() {
|
|
127718
|
+
if (process.env.KIFARU_XDG_DATA_HOME)
|
|
127719
|
+
return process.env.KIFARU_XDG_DATA_HOME;
|
|
127720
|
+
if (os10.platform() === "win32") {
|
|
127721
|
+
return path21.join(process.env.LOCALAPPDATA || path21.join(os10.homedir(), "AppData", "Local"), "kifaru", "data");
|
|
127722
|
+
}
|
|
127723
|
+
return path21.join(process.env.XDG_DATA_HOME || path21.join(os10.homedir(), ".local", "share"), "kifaru");
|
|
127724
|
+
}
|
|
127725
|
+
function resolveLogFilePath() {
|
|
127726
|
+
if (process.env.KIFARU_LOG_FILE)
|
|
127727
|
+
return path21.resolve(process.env.KIFARU_LOG_FILE);
|
|
127728
|
+
return path21.join(kifaruDataDir(), "log", "dev.log");
|
|
127729
|
+
}
|
|
127730
|
+
var initialized = false;
|
|
127731
|
+
var activeLogPath = "";
|
|
127732
|
+
function ensureLogDir() {
|
|
127733
|
+
if (!initialized) {
|
|
127734
|
+
activeLogPath = resolveLogFilePath();
|
|
127735
|
+
try {
|
|
127736
|
+
fs14.mkdirSync(path21.dirname(activeLogPath), { recursive: true });
|
|
127737
|
+
} catch {}
|
|
127738
|
+
initialized = true;
|
|
127739
|
+
}
|
|
127740
|
+
return activeLogPath;
|
|
127741
|
+
}
|
|
127742
|
+
function writeLog(level, category, message2, extra) {
|
|
127743
|
+
try {
|
|
127744
|
+
const file3 = ensureLogDir();
|
|
127745
|
+
const ts = new Date().toISOString();
|
|
127746
|
+
const extraStr = extra !== undefined ? ` ${typeof extra === "object" ? JSON.stringify(extra) : String(extra)}` : "";
|
|
127747
|
+
const line = `${ts} [${level}] [${category}] ${message2}${extraStr}
|
|
127748
|
+
`;
|
|
127749
|
+
fs14.appendFileSync(file3, line, "utf8");
|
|
127750
|
+
} catch {}
|
|
127751
|
+
}
|
|
127752
|
+
var tuiLog = {
|
|
127753
|
+
get filePath() {
|
|
127754
|
+
return ensureLogDir();
|
|
127755
|
+
},
|
|
127756
|
+
debug(category, message2, extra) {
|
|
127757
|
+
writeLog("DEBUG", category, message2, extra);
|
|
127758
|
+
},
|
|
127759
|
+
info(category, message2, extra) {
|
|
127760
|
+
writeLog("INFO", category, message2, extra);
|
|
127761
|
+
},
|
|
127762
|
+
warn(category, message2, extra) {
|
|
127763
|
+
writeLog("WARN", category, message2, extra);
|
|
127764
|
+
},
|
|
127765
|
+
error(category, message2, extra) {
|
|
127766
|
+
writeLog("ERROR", category, message2, extra);
|
|
127767
|
+
}
|
|
127768
|
+
};
|
|
127769
|
+
|
|
127713
127770
|
// src/pi-platform-client.ts
|
|
127714
127771
|
function trimSlash(value) {
|
|
127715
127772
|
return value.replace(/\/+$/, "");
|
|
@@ -127738,10 +127795,15 @@ function createPiPlatformClient(options2 = {}) {
|
|
|
127738
127795
|
const env2 = options2.env ?? process.env;
|
|
127739
127796
|
const fetchImpl = options2.fetchImpl ?? fetch;
|
|
127740
127797
|
const config4 = resolveConfig(env2);
|
|
127741
|
-
if (!config4)
|
|
127798
|
+
if (!config4) {
|
|
127799
|
+
tuiLog.info("platform", "Platform ingestion disabled: KIFARU_PLATFORM_INTERNAL_TOKEN is not set. Runs and findings will remain host-local.");
|
|
127742
127800
|
return disabledClient;
|
|
127743
|
-
|
|
127744
|
-
|
|
127801
|
+
}
|
|
127802
|
+
tuiLog.info("platform", `Platform ingestion enabled -> ${config4.baseURL}`);
|
|
127803
|
+
async function request(path22, method, body) {
|
|
127804
|
+
const url3 = `${config4.baseURL}/api/v1/${path22}`;
|
|
127805
|
+
tuiLog.debug("platform:http", `-> ${method} ${url3}`);
|
|
127806
|
+
const response = await fetchImpl(url3, {
|
|
127745
127807
|
method,
|
|
127746
127808
|
headers: {
|
|
127747
127809
|
Authorization: `Bearer ${config4.token}`,
|
|
@@ -127750,9 +127812,11 @@ function createPiPlatformClient(options2 = {}) {
|
|
|
127750
127812
|
signal: AbortSignal.timeout(1e4),
|
|
127751
127813
|
...body === undefined ? {} : { body: JSON.stringify(body) }
|
|
127752
127814
|
});
|
|
127815
|
+
tuiLog.debug("platform:http", `<- ${response.status} ${method} ${url3}`);
|
|
127753
127816
|
if (!response.ok) {
|
|
127754
127817
|
const detail = await response.text().catch(() => "");
|
|
127755
127818
|
const code = response.status === 404 && /was not found/i.test(detail) ? "KIFARU_RUN_MISSING" : `KIFARU_HTTP_${response.status}`;
|
|
127819
|
+
tuiLog.error("platform:http", `Request failed (${response.status}): ${detail || response.statusText}`);
|
|
127756
127820
|
throw Object.assign(new Error(`Kifaru platform request failed (${response.status}): ${detail || response.statusText}`), { code });
|
|
127757
127821
|
}
|
|
127758
127822
|
return response;
|
|
@@ -127765,6 +127829,7 @@ function createPiPlatformClient(options2 = {}) {
|
|
|
127765
127829
|
const result = await response.json();
|
|
127766
127830
|
if (!result.result?.recorded)
|
|
127767
127831
|
throw Object.assign(new Error("Platform operation was not linked to a run"), { code: "KIFARU_RUN_UNLINKED" });
|
|
127832
|
+
tuiLog.debug("platform:operation", `Recorded operation ${input.toolCallID} (${input.tool}) -> ${input.status}`);
|
|
127768
127833
|
},
|
|
127769
127834
|
async createRun(input) {
|
|
127770
127835
|
const response = await request("runs", "POST", {
|
|
@@ -127777,17 +127842,23 @@ function createPiPlatformClient(options2 = {}) {
|
|
|
127777
127842
|
...input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : {}
|
|
127778
127843
|
});
|
|
127779
127844
|
const parsed = await response.json();
|
|
127780
|
-
|
|
127845
|
+
const runID = parsed.run?.id ?? null;
|
|
127846
|
+
tuiLog.info("platform:run", `Created platform run: ${runID}`, { title: input.title, target: input.targetID });
|
|
127847
|
+
return runID;
|
|
127781
127848
|
},
|
|
127782
127849
|
async ingestFindings(runID, findings) {
|
|
127783
127850
|
if (findings.length === 0)
|
|
127784
127851
|
return { created: 0, updated: 0 };
|
|
127785
127852
|
const response = await request(`runs/${encodeURIComponent(runID)}/findings`, "POST", { findings });
|
|
127786
127853
|
const parsed = await response.json();
|
|
127787
|
-
|
|
127854
|
+
const created = parsed.result?.created ?? 0;
|
|
127855
|
+
const updated = parsed.result?.updated ?? 0;
|
|
127856
|
+
tuiLog.info("platform:finding", `Ingested ${findings.length} finding(s) into run ${runID} (created=${created}, updated=${updated})`);
|
|
127857
|
+
return { created, updated };
|
|
127788
127858
|
},
|
|
127789
127859
|
async transitionRun(runID, status, details = {}) {
|
|
127790
127860
|
await request(`runs/${encodeURIComponent(runID)}/status`, "POST", { status, ...details });
|
|
127861
|
+
tuiLog.info("platform:run", `Transitioned run ${runID} to ${status}`, details);
|
|
127791
127862
|
}
|
|
127792
127863
|
};
|
|
127793
127864
|
}
|
|
@@ -132179,6 +132250,7 @@ ${p2.statutoryObligations.map((o2) => `\u2022 ${o2}`).join(`
|
|
|
132179
132250
|
remediation: p2.remediation?.slice(0, 20000)
|
|
132180
132251
|
};
|
|
132181
132252
|
if (!client.enabled) {
|
|
132253
|
+
tuiLog.warn("report_finding", `Finding recorded locally ONLY (Platform ingestion disabled): "${finding.title}"`);
|
|
132182
132254
|
return {
|
|
132183
132255
|
content: [
|
|
132184
132256
|
{
|
|
@@ -132195,6 +132267,7 @@ ${p2.statutoryObligations.map((o2) => `\u2022 ${o2}`).join(`
|
|
|
132195
132267
|
}
|
|
132196
132268
|
try {
|
|
132197
132269
|
const result = await withPiPlatformRun(client, ctx, () => client.ingestFindings(ctx.runID, [finding]));
|
|
132270
|
+
tuiLog.info("report_finding", `Finding recorded to platform: [${finding.severity.toUpperCase()}] "${finding.title}" -> run ${ctx.runID}`, { file: finding.file, category, cvssScore: finding.cvssScore });
|
|
132198
132271
|
ctx.findingCount += 1;
|
|
132199
132272
|
if (!ctx.worstSeverity || SEVERITY_RANK[finding.severity] > SEVERITY_RANK[ctx.worstSeverity]) {
|
|
132200
132273
|
ctx.worstSeverity = finding.severity;
|
|
@@ -132247,7 +132320,7 @@ function createReportFindingExtension(deps2) {
|
|
|
132247
132320
|
|
|
132248
132321
|
// src/pi-dossier-sync.ts
|
|
132249
132322
|
import { readFile } from "fs/promises";
|
|
132250
|
-
import
|
|
132323
|
+
import path22 from "path";
|
|
132251
132324
|
var severityWords = [
|
|
132252
132325
|
[/critical|account takeover|authentication bypass|sql injection|arbitrary query/i, "critical"],
|
|
132253
132326
|
[/high|privilege escalation|ssrf|credential|idor|authorization|sensitive/i, "high"],
|
|
@@ -132307,7 +132380,7 @@ async function syncPiDossier(client, context3, cwd, read = readFile) {
|
|
|
132307
132380
|
return { ...NOTHING, skipped: "unparseable-target" };
|
|
132308
132381
|
let raw;
|
|
132309
132382
|
try {
|
|
132310
|
-
raw = await read(
|
|
132383
|
+
raw = await read(path22.join(cwd, ".kifaru", "dossiers", `${name21}.json`), "utf8");
|
|
132311
132384
|
} catch (error92) {
|
|
132312
132385
|
if (error92.code === "ENOENT")
|
|
132313
132386
|
return { ...NOTHING, skipped: "no-dossier-file" };
|
|
@@ -132367,6 +132440,7 @@ function createKifaruExtension(state2, cwd, deps2) {
|
|
|
132367
132440
|
pi.on("session_start", (_event, ctx) => updateStatus(ctx));
|
|
132368
132441
|
const toolStarts = new Map;
|
|
132369
132442
|
pi.on("agent_start", async (_event, ctx) => {
|
|
132443
|
+
tuiLog.info("agent", `Agent turn starting: workflow=${state2.agentKey}, target=${state2.target}`);
|
|
132370
132444
|
try {
|
|
132371
132445
|
await ensurePiPlatformRun(deps2.client, deps2.runContext);
|
|
132372
132446
|
} catch (error92) {
|
|
@@ -132381,6 +132455,7 @@ function createKifaruExtension(state2, cwd, deps2) {
|
|
|
132381
132455
|
const startedAt = start?.startedAt ?? Date.now();
|
|
132382
132456
|
const args = start?.args;
|
|
132383
132457
|
toolStarts.delete(event.toolCallId);
|
|
132458
|
+
tuiLog.info("agent:tool", `Tool call finished: ${event.toolName} (status: ${event.isError ? "error" : "ok"}, duration: ${Date.now() - startedAt}ms)`);
|
|
132384
132459
|
if (!deps2.client.enabled || !deps2.client.recordOperation)
|
|
132385
132460
|
return;
|
|
132386
132461
|
let outputPreview;
|
|
@@ -132413,6 +132488,7 @@ function createKifaruExtension(state2, cwd, deps2) {
|
|
|
132413
132488
|
}
|
|
132414
132489
|
});
|
|
132415
132490
|
pi.on("agent_settled", async () => {
|
|
132491
|
+
tuiLog.info("agent", `Agent turn settled: findings=${deps2.runContext.findingCount}, worstSeverity=${deps2.runContext.worstSeverity ?? "none"}`);
|
|
132416
132492
|
if (!deps2.client.enabled)
|
|
132417
132493
|
return;
|
|
132418
132494
|
await completePiPlatformRun(deps2.client, deps2.runContext, {
|
|
@@ -132581,14 +132657,14 @@ async function runKifaruTui(options2) {
|
|
|
132581
132657
|
}
|
|
132582
132658
|
|
|
132583
132659
|
// src/session-client.ts
|
|
132584
|
-
import
|
|
132585
|
-
import
|
|
132586
|
-
import
|
|
132660
|
+
import fs15 from "fs/promises";
|
|
132661
|
+
import os11 from "os";
|
|
132662
|
+
import path23 from "path";
|
|
132587
132663
|
function sessionFile() {
|
|
132588
132664
|
if (process.env.KIFARU_SESSION_FILE)
|
|
132589
132665
|
return process.env.KIFARU_SESSION_FILE;
|
|
132590
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
132591
|
-
return
|
|
132666
|
+
const xdg = process.env.XDG_DATA_HOME || path23.join(os11.homedir(), ".local", "share");
|
|
132667
|
+
return path23.join(xdg, "kifaru", "data", "auth", "session.json");
|
|
132592
132668
|
}
|
|
132593
132669
|
async function resolveGatewayOrigin(explicitOrigin) {
|
|
132594
132670
|
if (explicitOrigin && explicitOrigin.trim()) {
|
|
@@ -132610,7 +132686,7 @@ async function resolveGatewayOrigin(explicitOrigin) {
|
|
|
132610
132686
|
return "https://kifaru.bastco.org";
|
|
132611
132687
|
}
|
|
132612
132688
|
async function readSession() {
|
|
132613
|
-
const raw = await
|
|
132689
|
+
const raw = await fs15.readFile(sessionFile(), "utf8").catch(() => null);
|
|
132614
132690
|
if (!raw)
|
|
132615
132691
|
return null;
|
|
132616
132692
|
try {
|
|
@@ -132631,10 +132707,10 @@ async function readSession() {
|
|
|
132631
132707
|
}
|
|
132632
132708
|
async function writeSession(session) {
|
|
132633
132709
|
const file3 = sessionFile();
|
|
132634
|
-
await
|
|
132710
|
+
await fs15.mkdir(path23.dirname(file3), { recursive: true });
|
|
132635
132711
|
const tmp = `${file3}.tmp`;
|
|
132636
|
-
await
|
|
132637
|
-
await
|
|
132712
|
+
await fs15.writeFile(tmp, JSON.stringify(session, null, 2), "utf8");
|
|
132713
|
+
await fs15.rename(tmp, file3);
|
|
132638
132714
|
}
|
|
132639
132715
|
function mask(token) {
|
|
132640
132716
|
return token.length > 12 ? `${token.slice(0, 6)}\u2026${token.slice(-4)}` : "\u2026";
|
|
@@ -132752,8 +132828,8 @@ async function executeSessionLogout() {
|
|
|
132752
132828
|
signal: AbortSignal.timeout(3000)
|
|
132753
132829
|
}).catch(() => null);
|
|
132754
132830
|
} catch {}
|
|
132755
|
-
await
|
|
132756
|
-
await
|
|
132831
|
+
await fs15.rm(sessionFile(), { force: true }).catch(() => null);
|
|
132832
|
+
await fs15.rm(`${sessionFile()}.tmp`, { force: true }).catch(() => null);
|
|
132757
132833
|
}
|
|
132758
132834
|
return { ok: true, text: "\u2713 Successfully logged out. Session removed." };
|
|
132759
132835
|
}
|
|
@@ -132781,7 +132857,7 @@ Interactive TUI Commands:
|
|
|
132781
132857
|
async function handleCli() {
|
|
132782
132858
|
const args = process.argv.slice(2);
|
|
132783
132859
|
if (args.includes("--version") || args.includes("-v")) {
|
|
132784
|
-
console.log("1.0.
|
|
132860
|
+
console.log("1.0.170");
|
|
132785
132861
|
process.exit(0);
|
|
132786
132862
|
}
|
|
132787
132863
|
if (args.includes("--help") || args.includes("-h")) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kifaru",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"gitHead": "
|
|
3
|
+
"version": "1.0.170",
|
|
4
|
+
"gitHead": "4afa42479180899946162c56cf0badb9ff08b05c",
|
|
5
5
|
"description": "Kifaru security agent on the Pi runtime",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|