@xaccefy/pi-casefile 0.1.8 → 0.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xaccefy/pi-casefile",
3
- "version": "0.1.8",
3
+ "version": "0.2.0",
4
4
  "description": "Offensive security case tracker for Pi Agent — bug bounties, CTFs, security audits",
5
5
  "keywords": [
6
6
  "pi-package",
package/src/index.ts CHANGED
@@ -241,15 +241,15 @@ function renderCaseResult(
241
241
  theme: Theme,
242
242
  successPrefix = "✓ ",
243
243
  failPrefix = "✗ ",
244
- ): Text {
244
+ ): string {
245
245
  const details = result.details as { record?: CaseRecord; changed?: boolean } | undefined;
246
246
  if (!details?.record) {
247
- return new Text(theme.fg("error", "✗ Failed"), 0, 0);
247
+ return theme.fg("error", "✗ Failed");
248
248
  }
249
249
  const success = details.changed !== false;
250
250
  const prefix = success ? successPrefix : failPrefix;
251
251
  const color = success ? "success" : "warning";
252
- return new Text(theme.fg(color, prefix) + renderOneLine(details.record, theme), 0, 0);
252
+ return theme.fg(color, prefix) + renderOneLine(details.record, theme);
253
253
  }
254
254
 
255
255
  // ── Dashboard component ──────────────────────────────────────────────
@@ -409,7 +409,7 @@ function buildCaseContext(records: CaseRecord[]): string {
409
409
  if (records.length === 0) return "";
410
410
 
411
411
  const safe = (v?: string, max = 160) => {
412
- const controlChars = new RegExp("[\r\n\t\\u0000-\\u001F\\u007F\\u2028\\u2029]+", "g");
412
+ const controlChars = /[\r\n\t\u0000-\u001F\u007F\u2028\u2029]+/g;
413
413
  const s = v
414
414
  ?.replace(controlChars, " ")
415
415
  .replace(/[<>]/g, (c) => (c === "<" ? "‹" : "›"))
@@ -547,8 +547,7 @@ export default function casefileExtension(pi: ExtensionAPI) {
547
547
  renderResult(result, { expanded }, theme) {
548
548
  const details = result.details as { created?: boolean; record?: CaseRecord };
549
549
  const created = details?.created;
550
- const baseText = renderCaseResult(result, theme, created === false ? "↻ " : "✓ ");
551
- let line = baseText.toString();
550
+ let line = renderCaseResult(result, theme, created === false ? "↻ " : "✓ ");
552
551
  if (expanded && details?.record) {
553
552
  line += `\n${theme.fg("dim", ` ${details.record.id} → ${details.record.nextStep ?? "no next step"}`)}`;
554
553
  }
@@ -603,8 +602,7 @@ export default function casefileExtension(pi: ExtensionAPI) {
603
602
  renderResult(result, { expanded }, theme) {
604
603
  const details = result.details as { changed?: boolean; record?: CaseRecord; reason?: string };
605
604
  const unchanged = details?.changed === false;
606
- const baseText = renderCaseResult(result, theme, unchanged ? "↷ " : "✓ ");
607
- let line = baseText.toString();
605
+ let line = renderCaseResult(result, theme, unchanged ? "↷ " : "✓ ");
608
606
  if (expanded && details?.record) {
609
607
  line +=
610
608
  "\n" +
@@ -672,7 +670,7 @@ export default function casefileExtension(pi: ExtensionAPI) {
672
670
  renderResult(result, _options, theme) {
673
671
  const details = result.details as { run?: { exitCode: number } } | undefined;
674
672
  const success = details?.run?.exitCode === 0;
675
- return renderCaseResult(result, theme, success ? "✓ " : "✗ ", "✗ ");
673
+ return new Text(renderCaseResult(result, theme, success ? "✓ " : "✗ ", "✗ "), 0, 0);
676
674
  },
677
675
  });
678
676
 
@@ -705,7 +703,7 @@ export default function casefileExtension(pi: ExtensionAPI) {
705
703
  },
706
704
 
707
705
  renderResult(result, _options, theme) {
708
- return renderCaseResult(result, theme, "", "");
706
+ return new Text(renderCaseResult(result, theme, "", ""), 0, 0);
709
707
  },
710
708
  });
711
709
 
package/src/ledger.ts CHANGED
@@ -724,10 +724,18 @@ export function promoteFindingResult(id: string, verification: PocVerification):
724
724
  );
725
725
  }
726
726
 
727
+ const newEvidence =
728
+ (current.evidence ? current.evidence + "\n\n" : "") +
729
+ `### PoC Execution Capture (${verification.ranAt})\n` +
730
+ `- **Exit Code:** ${verification.exitCode}\n` +
731
+ `- **Sandbox:** ${verification.sandbox ? "yes" : "no"}\n` +
732
+ `#### Execution Output\n\`\`\`\n${verification.output ?? ""}\n\`\`\``;
733
+
727
734
  const next = buildRecord(
728
735
  {
729
736
  status: "confirmed",
730
737
  pocVerified: verification,
738
+ evidence: newEvidence,
731
739
  },
732
740
  current,
733
741
  );
@@ -958,6 +966,12 @@ export function writeCaseReport(id: string): { path: string; record: CaseRecord
958
966
  mdSection("Summary", current.summary),
959
967
  mdSection("Steps to Reproduce / Evidence", current.evidence),
960
968
  mdSection("Proof of Concept", current.poc),
969
+ current.pocVerified
970
+ ? mdSection(
971
+ "PoC Verification Log",
972
+ `### PoC Run Verification\n- **Timestamp:** ${current.pocVerified.ranAt}\n- **Path:** \`${current.pocVerified.path}\`\n- **Sandbox:** ${current.pocVerified.sandbox ? "yes" : "no"}\n- **Exit Code:** ${current.pocVerified.exitCode}\n\n#### Output\n\`\`\`\n${current.pocVerified.output ?? ""}\n\`\`\``,
973
+ )
974
+ : undefined,
961
975
  mdSection("Impact", current.impact),
962
976
  mdSection("Remediation", current.remediation),
963
977
  mdSection("Assumptions and Uncertainty", assumptions),
@@ -1,5 +1,30 @@
1
- // ponytail: thin re-export with any cast to match node:sqlite API
2
- import { Database } from "bun:sqlite";
3
- const instance = Database as any;
4
- export { instance as DatabaseSync };
5
- export type DatabaseSync = any;
1
+ import { createRequire } from "node:module";
2
+
3
+ const _require = createRequire(import.meta.url);
4
+
5
+ // biome-ignore lint/suspicious/noExplicitAny: Runtime module swappability requires any casting
6
+ let DatabaseSyncConstructor: any;
7
+ try {
8
+ // biome-ignore lint/suspicious/noExplicitAny: Runtime module swappability
9
+ DatabaseSyncConstructor = _require("bun:sqlite").Database as any;
10
+ } catch {
11
+ // biome-ignore lint/suspicious/noExplicitAny: Runtime module swappability
12
+ DatabaseSyncConstructor = (_require("node:sqlite") as any).DatabaseSync;
13
+ }
14
+
15
+ // biome-ignore lint/suspicious/noExplicitAny: Standard SQLite API returns any
16
+ export interface StatementSync {
17
+ run(...args: unknown[]): { lastInsertRowid: number; changes: number };
18
+ // biome-ignore lint/suspicious/noExplicitAny: Standard SQLite API returns any
19
+ get(...args: unknown[]): any;
20
+ // biome-ignore lint/suspicious/noExplicitAny: Standard SQLite API returns any
21
+ all(...args: unknown[]): any[];
22
+ }
23
+
24
+ export interface DatabaseSync {
25
+ prepare(sql: string): StatementSync;
26
+ exec(sql: string): void;
27
+ close(): void;
28
+ }
29
+
30
+ export const DatabaseSync: new (path: string) => DatabaseSync = DatabaseSyncConstructor;