@pensar/apex 0.0.103 → 0.0.104-canary.8c0adce3

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/bin/pensar.js CHANGED
@@ -73,6 +73,26 @@ if (command === "benchmark") {
73
73
  process.argv = [process.argv[0], uninstallPath, ...args.slice(1)];
74
74
 
75
75
  await import(uninstallPath);
76
+ } else if (command === "projects") {
77
+ const p = join(__dirname, "..", "build", "projects.js");
78
+ process.argv = [process.argv[0], p, ...args.slice(1)];
79
+ await import(p);
80
+ } else if (command === "pentests") {
81
+ const p = join(__dirname, "..", "build", "pentests.js");
82
+ process.argv = [process.argv[0], p, ...args.slice(1)];
83
+ await import(p);
84
+ } else if (command === "issues") {
85
+ const p = join(__dirname, "..", "build", "issues.js");
86
+ process.argv = [process.argv[0], p, ...args.slice(1)];
87
+ await import(p);
88
+ } else if (command === "fixes") {
89
+ const p = join(__dirname, "..", "build", "fixes.js");
90
+ process.argv = [process.argv[0], p, ...args.slice(1)];
91
+ await import(p);
92
+ } else if (command === "logs") {
93
+ const p = join(__dirname, "..", "build", "logs.js");
94
+ process.argv = [process.argv[0], p, ...args.slice(1)];
95
+ await import(p);
76
96
  } else if (command === "upgrade" || command === "update") {
77
97
  const currentVersion = getCurrentVersion();
78
98
  console.log(`Current version: v${currentVersion}`);
@@ -109,6 +129,21 @@ if (command === "benchmark") {
109
129
  console.log(
110
130
  " pensar auth Connect to Pensar Console for managed inference"
111
131
  );
132
+ console.log(
133
+ " pensar projects List workspace projects"
134
+ );
135
+ console.log(
136
+ " pensar pentests List and manage pentests"
137
+ );
138
+ console.log(
139
+ " pensar issues List and manage security issues"
140
+ );
141
+ console.log(
142
+ " pensar fixes View security fixes"
143
+ );
144
+ console.log(
145
+ " pensar logs View agent execution logs"
146
+ );
112
147
  console.log();
113
148
  console.log("Options:");
114
149
  console.log(" -h, --help Show this help message");
@@ -226,6 +261,14 @@ if (command === "benchmark") {
226
261
  console.log(" pensar auth");
227
262
  console.log(" pensar auth status");
228
263
  console.log(" pensar auth logout");
264
+ console.log();
265
+ console.log("Console API:");
266
+ console.log(" pensar projects");
267
+ console.log(" pensar pentests <projectId>");
268
+ console.log(" pensar issues <projectId>");
269
+ console.log(" pensar issues get <issueId>");
270
+ console.log(" pensar fixes <issueId>");
271
+ console.log(" pensar logs <issueId>");
229
272
  } else if (args.length === 0) {
230
273
  // No command specified, run the TUI
231
274
  const appPath = join(__dirname, "..", "build", "index.js");
package/build/auth.js CHANGED
@@ -8,7 +8,7 @@ import fs from "fs/promises";
8
8
  // package.json
9
9
  var package_default = {
10
10
  name: "@pensar/apex",
11
- version: "0.0.103",
11
+ version: "0.0.104-canary.8c0adce3",
12
12
  description: "AI-powered penetration testing CLI tool with terminal UI",
13
13
  module: "src/tui/index.tsx",
14
14
  main: "build/index.js",
@@ -557,14 +557,31 @@ async function status() {
557
557
  console.log("\nRun `pensar auth login` to connect.");
558
558
  return;
559
559
  }
560
- console.log("\u2713 Connected to Pensar Console");
561
- if (appConfig.workspaceSlug) {
562
- console.log(` Workspace: ${appConfig.workspaceSlug}`);
560
+ if (!appConfig.accessToken && appConfig.pensarAPIKey && !appConfig.workspaceSlug) {
561
+ try {
562
+ const apiUrl = getPensarApiUrl();
563
+ const res = await fetch(`${apiUrl}/auth/validate`, {
564
+ headers: { Authorization: `Bearer ${appConfig.pensarAPIKey}` }
565
+ });
566
+ if (res.ok) {
567
+ const data = await res.json();
568
+ if (data.workspace) {
569
+ await config.update({
570
+ workspaceId: data.workspace.id,
571
+ workspaceSlug: data.workspace.slug
572
+ });
573
+ appConfig.workspaceId = data.workspace.id;
574
+ appConfig.workspaceSlug = data.workspace.slug;
575
+ }
576
+ }
577
+ } catch {}
563
578
  }
579
+ console.log("\u2713 Connected to Pensar Console");
580
+ console.log(` Workspace: ${appConfig.workspaceSlug ?? "not set"}`);
564
581
  if (appConfig.accessToken) {
565
- console.log(" Auth: WorkOS (modern)");
582
+ console.log(" Auth: WorkOS");
566
583
  } else {
567
- console.log(" Auth: API key (legacy)");
584
+ console.log(" Auth: API key");
568
585
  }
569
586
  }
570
587
  function showHelp() {
package/build/index.js CHANGED
@@ -31880,12 +31880,6 @@ var init_openrouter = __esm(() => {
31880
31880
  var PENSAR_MODELS;
31881
31881
  var init_pensar = __esm(() => {
31882
31882
  PENSAR_MODELS = [
31883
- {
31884
- id: "pensar:anthropic.claude-opus-4-6-v1",
31885
- name: "Claude Opus 4.6 (Pensar)",
31886
- provider: "pensar",
31887
- contextLength: 200000
31888
- },
31889
31883
  {
31890
31884
  id: "pensar:anthropic.claude-sonnet-4-5-20250929-v1:0",
31891
31885
  name: "Claude Sonnet 4.5 (Pensar)",
@@ -31977,7 +31971,7 @@ var package_default2;
31977
31971
  var init_package = __esm(() => {
31978
31972
  package_default2 = {
31979
31973
  name: "@pensar/apex",
31980
- version: "0.0.103",
31974
+ version: "0.0.104-canary.8c0adce3",
31981
31975
  description: "AI-powered penetration testing CLI tool with terminal UI",
31982
31976
  module: "src/tui/index.tsx",
31983
31977
  main: "build/index.js",
@@ -273074,7 +273068,7 @@ var useTerminalDimensions = () => {
273074
273068
  };
273075
273069
 
273076
273070
  // src/tui/index.tsx
273077
- var import_react88 = __toESM(require_react(), 1);
273071
+ var import_react90 = __toESM(require_react(), 1);
273078
273072
 
273079
273073
  // src/tui/components/footer.tsx
273080
273074
  import os6 from "os";
@@ -281225,6 +281219,98 @@ var actionsByKey = new Map(allActions.map((action) => [action.key, action]));
281225
281219
  var actionsById = new Map(allActions.map((action) => [action.id, action]));
281226
281220
  // src/tui/keybindings/keybind.tsx
281227
281221
  var LeaderKeyContext = import_react62.createContext(null);
281222
+ // src/tui/terminal-focus.ts
281223
+ var bracketedFocusModeEnabled = false;
281224
+ function setupTerminalFocusHandling(renderer, options = {}) {
281225
+ const { onTerminalFocus, debug = false } = options;
281226
+ const log2 = (...args) => {
281227
+ if (debug)
281228
+ console.error("[TerminalFocus]", ...args);
281229
+ };
281230
+ const enableBracketedFocus = () => {
281231
+ if (process.stdout.isTTY) {
281232
+ process.stdout.write("\x1B[?1004h");
281233
+ bracketedFocusModeEnabled = true;
281234
+ log2("Enabled bracketed focus mode");
281235
+ }
281236
+ };
281237
+ const disableBracketedFocus = () => {
281238
+ if (process.stdout.isTTY && bracketedFocusModeEnabled) {
281239
+ process.stdout.write("\x1B[?1004l");
281240
+ bracketedFocusModeEnabled = false;
281241
+ log2("Disabled bracketed focus mode");
281242
+ }
281243
+ };
281244
+ const showCursor = () => {
281245
+ if (process.stdout.isTTY) {
281246
+ process.stdout.write("\x1B[?25h");
281247
+ log2("Showed cursor");
281248
+ }
281249
+ };
281250
+ const handleFocusIn = () => {
281251
+ log2("Terminal gained focus");
281252
+ showCursor();
281253
+ renderer.requestRender();
281254
+ if (onTerminalFocus) {
281255
+ setTimeout(() => {
281256
+ onTerminalFocus();
281257
+ log2("Re-focused prompt input");
281258
+ }, 10);
281259
+ }
281260
+ };
281261
+ const handleFocusOut = () => {
281262
+ log2("Terminal lost focus");
281263
+ };
281264
+ const handleSigCont = () => {
281265
+ log2("Received SIGCONT (terminal resumed)");
281266
+ showCursor();
281267
+ renderer.requestRender();
281268
+ if (onTerminalFocus) {
281269
+ setTimeout(() => {
281270
+ onTerminalFocus();
281271
+ log2("Re-focused prompt input after SIGCONT");
281272
+ }, 10);
281273
+ }
281274
+ };
281275
+ let stdinListenerActive = false;
281276
+ const handleStdinData = (data) => {
281277
+ const str = data.toString();
281278
+ if (str.includes("\x1B[I")) {
281279
+ handleFocusIn();
281280
+ }
281281
+ if (str.includes("\x1B[O")) {
281282
+ handleFocusOut();
281283
+ }
281284
+ };
281285
+ const setupListeners = () => {
281286
+ enableBracketedFocus();
281287
+ showCursor();
281288
+ process.on("SIGCONT", handleSigCont);
281289
+ if (process.stdin.isTTY && !stdinListenerActive) {
281290
+ process.stdin.on("data", handleStdinData);
281291
+ stdinListenerActive = true;
281292
+ log2("Set up stdin listener for bracketed focus events");
281293
+ }
281294
+ };
281295
+ const cleanup = () => {
281296
+ log2("Cleaning up terminal focus handling");
281297
+ disableBracketedFocus();
281298
+ process.off("SIGCONT", handleSigCont);
281299
+ if (stdinListenerActive) {
281300
+ process.stdin.off("data", handleStdinData);
281301
+ stdinListenerActive = false;
281302
+ }
281303
+ };
281304
+ setupListeners();
281305
+ return cleanup;
281306
+ }
281307
+ function cleanupTerminalFocusMode() {
281308
+ if (process.stdout.isTTY && bracketedFocusModeEnabled) {
281309
+ process.stdout.write("\x1B[?1004l");
281310
+ bracketedFocusModeEnabled = false;
281311
+ }
281312
+ }
281313
+
281228
281314
  // src/tui/keybindings/registry.ts
281229
281315
  function createKeybindings(deps) {
281230
281316
  const {
@@ -281253,6 +281339,7 @@ function createKeybindings(deps) {
281253
281339
  const now2 = Date.now();
281254
281340
  const lastPress = ctrlCPressTime;
281255
281341
  if (lastPress && now2 - lastPress < 1000) {
281342
+ cleanupTerminalFocusMode();
281256
281343
  renderer.destroy();
281257
281344
  process.exit(0);
281258
281345
  } else {
@@ -291109,74 +291196,92 @@ function setupAutoCopy(renderer, copyToClipboard) {
291109
291196
  });
291110
291197
  }
291111
291198
 
291199
+ // src/tui/components/terminal-focus-handler.tsx
291200
+ var import_react87 = __toESM(require_react(), 1);
291201
+ function TerminalFocusHandler() {
291202
+ const { refocusPrompt } = useFocus();
291203
+ const renderer = useRenderer();
291204
+ import_react87.useEffect(() => {
291205
+ const cleanup = setupTerminalFocusHandling(renderer, {
291206
+ onTerminalFocus: refocusPrompt,
291207
+ debug: false
291208
+ });
291209
+ return cleanup;
291210
+ }, [renderer, refocusPrompt]);
291211
+ return null;
291212
+ }
291213
+
291112
291214
  // src/tui/index.tsx
291113
291215
  function App({ appConfig }) {
291114
- const [focusIndex, setFocusIndex] = import_react88.useState(0);
291115
- const [cwd, setCwd] = import_react88.useState(process.cwd());
291116
- const [ctrlCPressTime, setCtrlCPressTime] = import_react88.useState(null);
291117
- const [showExitWarning, setShowExitWarning] = import_react88.useState(false);
291118
- const [inputKey, setInputKey] = import_react88.useState(0);
291119
- const [showSessionsDialog, setShowSessionsDialog] = import_react88.useState(false);
291120
- const [showShortcutsDialog, setShowShortcutsDialog] = import_react88.useState(false);
291121
- const [showThemeDialog, setShowThemeDialog] = import_react88.useState(false);
291122
- const [showAuthDialog, setShowAuthDialog] = import_react88.useState(false);
291123
- const [showPentestDialog, setShowPentestDialog] = import_react88.useState(false);
291124
- const [pendingPentestFlags, setPendingPentestFlags] = import_react88.useState(undefined);
291216
+ const [focusIndex, setFocusIndex] = import_react90.useState(0);
291217
+ const [cwd, setCwd] = import_react90.useState(process.cwd());
291218
+ const [ctrlCPressTime, setCtrlCPressTime] = import_react90.useState(null);
291219
+ const [showExitWarning, setShowExitWarning] = import_react90.useState(false);
291220
+ const [inputKey, setInputKey] = import_react90.useState(0);
291221
+ const [showSessionsDialog, setShowSessionsDialog] = import_react90.useState(false);
291222
+ const [showShortcutsDialog, setShowShortcutsDialog] = import_react90.useState(false);
291223
+ const [showThemeDialog, setShowThemeDialog] = import_react90.useState(false);
291224
+ const [showAuthDialog, setShowAuthDialog] = import_react90.useState(false);
291225
+ const [showPentestDialog, setShowPentestDialog] = import_react90.useState(false);
291226
+ const [pendingPentestFlags, setPendingPentestFlags] = import_react90.useState(undefined);
291125
291227
  const navigableItems = ["command-input"];
291126
291228
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ConfigProvider, {
291127
291229
  config: appConfig,
291128
291230
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(SessionProvider, {
291129
291231
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RouteProvider, {
291130
291232
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(FocusProvider, {
291131
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(InputProvider, {
291132
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(DialogProvider, {
291133
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(AgentProvider, {
291134
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(CommandProvider, {
291135
- onOpenSessionsDialog: () => setShowSessionsDialog(true),
291136
- onOpenThemeDialog: () => setShowThemeDialog(true),
291137
- onOpenAuthDialog: () => setShowAuthDialog(true),
291138
- onOpenPentestDialog: (flags) => {
291139
- setPendingPentestFlags(flags);
291140
- setShowPentestDialog(true);
291141
- },
291142
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(KeybindingProvider, {
291143
- deps: {
291144
- ctrlCPressTime,
291145
- setCtrlCPressTime,
291146
- setShowExitWarning,
291147
- setInputKey,
291148
- setShowSessionsDialog,
291149
- setShowShortcutsDialog,
291150
- setFocusIndex,
291151
- navigableItems
291233
+ children: [
291234
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(TerminalFocusHandler, {}, undefined, false, undefined, this),
291235
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(InputProvider, {
291236
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(DialogProvider, {
291237
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(AgentProvider, {
291238
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(CommandProvider, {
291239
+ onOpenSessionsDialog: () => setShowSessionsDialog(true),
291240
+ onOpenThemeDialog: () => setShowThemeDialog(true),
291241
+ onOpenAuthDialog: () => setShowAuthDialog(true),
291242
+ onOpenPentestDialog: (flags) => {
291243
+ setPendingPentestFlags(flags);
291244
+ setShowPentestDialog(true);
291152
291245
  },
291153
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(AppContent, {
291154
- focusIndex,
291155
- showSessionsDialog,
291156
- setShowSessionsDialog,
291157
- showShortcutsDialog,
291158
- setShowShortcutsDialog,
291159
- showThemeDialog,
291160
- setShowThemeDialog,
291161
- showAuthDialog,
291162
- setShowAuthDialog,
291163
- showPentestDialog,
291164
- setShowPentestDialog,
291165
- pendingPentestFlags,
291166
- setPendingPentestFlags,
291167
- cwd,
291168
- setCtrlCPressTime,
291169
- showExitWarning,
291170
- setShowExitWarning,
291171
- inputKey,
291172
- setInputKey
291246
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(KeybindingProvider, {
291247
+ deps: {
291248
+ ctrlCPressTime,
291249
+ setCtrlCPressTime,
291250
+ setShowExitWarning,
291251
+ setInputKey,
291252
+ setShowSessionsDialog,
291253
+ setShowShortcutsDialog,
291254
+ setFocusIndex,
291255
+ navigableItems
291256
+ },
291257
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(AppContent, {
291258
+ focusIndex,
291259
+ showSessionsDialog,
291260
+ setShowSessionsDialog,
291261
+ showShortcutsDialog,
291262
+ setShowShortcutsDialog,
291263
+ showThemeDialog,
291264
+ setShowThemeDialog,
291265
+ showAuthDialog,
291266
+ setShowAuthDialog,
291267
+ showPentestDialog,
291268
+ setShowPentestDialog,
291269
+ pendingPentestFlags,
291270
+ setPendingPentestFlags,
291271
+ cwd,
291272
+ setCtrlCPressTime,
291273
+ showExitWarning,
291274
+ setShowExitWarning,
291275
+ inputKey,
291276
+ setInputKey
291277
+ }, undefined, false, undefined, this)
291173
291278
  }, undefined, false, undefined, this)
291174
291279
  }, undefined, false, undefined, this)
291175
291280
  }, undefined, false, undefined, this)
291176
291281
  }, undefined, false, undefined, this)
291177
291282
  }, undefined, false, undefined, this)
291178
- }, undefined, false, undefined, this)
291179
- }, undefined, false, undefined, this)
291283
+ ]
291284
+ }, undefined, true, undefined, this)
291180
291285
  }, undefined, false, undefined, this)
291181
291286
  }, undefined, false, undefined, this)
291182
291287
  }, undefined, false, undefined, this);
@@ -291208,14 +291313,14 @@ function AppContent({
291208
291313
  const { toast } = useToast();
291209
291314
  const { refocusPrompt } = useFocus();
291210
291315
  const { setExternalDialogOpen } = useDialog();
291211
- import_react88.useEffect(() => {
291316
+ import_react90.useEffect(() => {
291212
291317
  checkForUpdate().then(({ updateAvailable, currentVersion, latestVersion }) => {
291213
291318
  if (!updateAvailable)
291214
291319
  return;
291215
291320
  toast(`Update available: v${currentVersion} → v${latestVersion}. Run: pensar upgrade`, "warn", 8000);
291216
291321
  });
291217
291322
  }, []);
291218
- import_react88.useEffect(() => {
291323
+ import_react90.useEffect(() => {
291219
291324
  if (route.data.type !== "base")
291220
291325
  return;
291221
291326
  if (!config3.data.responsibleUseAccepted && route.data.path !== "disclosure") {
@@ -291224,12 +291329,12 @@ function AppContent({
291224
291329
  route.navigate({ type: "base", path: "providers" });
291225
291330
  }
291226
291331
  }, [config3.data.responsibleUseAccepted, route.data]);
291227
- import_react88.useEffect(() => {
291332
+ import_react90.useEffect(() => {
291228
291333
  if (showThemeDialog || showAuthDialog || showPentestDialog) {
291229
291334
  setExternalDialogOpen(true);
291230
291335
  }
291231
291336
  }, [showThemeDialog, showAuthDialog, showPentestDialog]);
291232
- import_react88.useEffect(() => {
291337
+ import_react90.useEffect(() => {
291233
291338
  if (showExitWarning) {
291234
291339
  const timer = setTimeout(() => {
291235
291340
  setShowExitWarning(false);
@@ -291461,18 +291566,21 @@ async function main2() {
291461
291566
  const { copyToClipboard } = createClipboardManager(renderer);
291462
291567
  setupAutoCopy(renderer, copyToClipboard);
291463
291568
  const cleanup = () => {
291569
+ cleanupTerminalFocusMode();
291464
291570
  renderer.destroy();
291465
291571
  process.exit(0);
291466
291572
  };
291467
291573
  process.on("SIGINT", cleanup);
291468
291574
  process.on("SIGTERM", cleanup);
291469
291575
  process.on("uncaughtException", (err) => {
291576
+ cleanupTerminalFocusMode();
291470
291577
  renderer.destroy();
291471
291578
  console.error("Uncaught exception:", err);
291472
291579
  writeErrorLog(err, "UNCAUGHT");
291473
291580
  process.exit(1);
291474
291581
  });
291475
291582
  process.on("unhandledRejection", (reason) => {
291583
+ cleanupTerminalFocusMode();
291476
291584
  renderer.destroy();
291477
291585
  console.error("Unhandled rejection:", reason);
291478
291586
  writeErrorLog(reason, "UNHANDLED_REJECTION");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pensar/apex",
3
- "version": "0.0.103",
3
+ "version": "0.0.104-canary.8c0adce3",
4
4
  "description": "AI-powered penetration testing CLI tool with terminal UI",
5
5
  "module": "src/tui/index.tsx",
6
6
  "main": "build/index.js",