kifaru 1.0.168 → 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.
Files changed (2) hide show
  1. package/kifaru-pi.js +96 -20
  2. 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.168";
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
- async function request(path21, method, body) {
127744
- const response = await fetchImpl(`${config4.baseURL}/api/v1/${path21}`, {
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
- return parsed.run?.id ?? null;
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
- return { created: parsed.result?.created ?? 0, updated: parsed.result?.updated ?? 0 };
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 path21 from "path";
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(path21.join(cwd, ".kifaru", "dossiers", `${name21}.json`), "utf8");
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 fs14 from "fs/promises";
132585
- import os10 from "os";
132586
- import path22 from "path";
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 || path22.join(os10.homedir(), ".local", "share");
132591
- return path22.join(xdg, "kifaru", "data", "auth", "session.json");
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 fs14.readFile(sessionFile(), "utf8").catch(() => null);
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 fs14.mkdir(path22.dirname(file3), { recursive: true });
132710
+ await fs15.mkdir(path23.dirname(file3), { recursive: true });
132635
132711
  const tmp = `${file3}.tmp`;
132636
- await fs14.writeFile(tmp, JSON.stringify(session, null, 2), "utf8");
132637
- await fs14.rename(tmp, file3);
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 fs14.rm(sessionFile(), { force: true }).catch(() => null);
132756
- await fs14.rm(`${sessionFile()}.tmp`, { force: true }).catch(() => null);
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.168");
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.168",
4
- "gitHead": "2210a459d81a3b908dc188d2336831f0eaa4a6a6",
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",