@pensar/apex 2.6.1 → 2.7.0-canary.21cb83dc
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/build/{agent-yby11zaq.js → agent-68t2wzmc.js} +6 -6
- package/build/agent-jhekpern.js +13 -0
- package/build/{agent-ayreaj6z.js → agent-qvreg8a4.js} +5 -5
- package/build/{agent-runs-g37vkrjr.js → agent-runs-30dvbvmm.js} +18 -18
- package/build/agent-vybw255f.js +13 -0
- package/build/{apps-xn6km9yn.js → apps-na0y0992.js} +13 -13
- package/build/{auth-d105wc64.js → auth-dz2c5thx.js} +13 -13
- package/build/{blackboxAgent-s56sgx9b.js → blackboxAgent-2mwvaajb.js} +6 -6
- package/build/{blackboxPentest-ps78v3w7.js → blackboxPentest-s2mfze9p.js} +17 -12
- package/build/{cli-kb21qhvm.js → cli-1pmfnz1a.js} +4 -3
- package/build/{cli-ae8jqxqr.js → cli-563yntrb.js} +2 -2
- package/build/{cli-7eea4e2y.js → cli-5ab346kd.js} +6 -6
- package/build/{cli-1ve18npr.js → cli-72y76bpg.js} +3 -2
- package/build/{cli-fy6vh2a7.js → cli-98wmmphf.js} +1 -1
- package/build/{cli-c05y640n.js → cli-9jscnhtg.js} +1 -1
- package/build/{cli-3sp6nd8d.js → cli-9kk9tm58.js} +2 -2
- package/build/{cli-d37a42dc.js → cli-9pz9wjt2.js} +101 -18
- package/build/{cli-dpsw2fe6.js → cli-a6x4jm5a.js} +476 -193
- package/build/{cli-az3xq70v.js → cli-cfrdr25z.js} +1 -1
- package/build/{cli-ngq9dr8n.js → cli-fdrrbb9p.js} +3 -3
- package/build/{cli-k2nwxta0.js → cli-t09zj814.js} +2 -2
- package/build/{cli-qgz1q9g5.js → cli-t4q4t4dx.js} +223 -76
- package/build/{cli-xtc2t6me.js → cli-vdd1s3x9.js} +103 -39
- package/build/{cli-gx71jcke.js → cli-vn4cwac3.js} +1 -1
- package/build/{cli-65g6rcat.js → cli-w9nw2a4z.js} +1 -1
- package/build/{cli-n2en7j5b.js → cli-z7ysyrr4.js} +1 -1
- package/build/{cli-709rvekb.js → cli-zbbtr4sb.js} +4 -2
- package/build/cli.js +70 -40
- package/build/{config-zpqkd5cz.js → config-nkzm9arw.js} +1 -1
- package/build/{fastStrike-mcjdvwez.js → fastStrike-16jw1s61.js} +67 -15
- package/build/{fixes-kytx5dmj.js → fixes-6wxk22v5.js} +13 -13
- package/build/{index-4vqdgb42.js → index-36p56pcf.js} +1473 -1217
- package/build/{index-je6hcsqr.js → index-6nejymsc.js} +1 -1
- package/build/{index-fv64eb32.js → index-asm4y7e4.js} +2 -2
- package/build/{index-n65z6v7b.js → index-bfmn52za.js} +6 -6
- package/build/{index-qv4cc65p.js → index-bt4r13q7.js} +13 -13
- package/build/{index-dr3tg1w3.js → index-gfq1rp1q.js} +1 -1
- package/build/{index-wqetp6gq.js → index-j9pxgrzd.js} +12 -7
- package/build/{index-r9yjkfrv.js → index-n9kapn1x.js} +4 -4
- package/build/{index-ns4m4s01.js → index-tr6evhyg.js} +4 -4
- package/build/{issues-eb3q9d3a.js → issues-7rmf4ker.js} +13 -13
- package/build/{knowledge-fqsvtx0f.js → knowledge-s2sxh8nb.js} +13 -13
- package/build/lib/{chunk-1azdancq.js → chunk-0dnx79b1.js} +1 -1
- package/build/lib/{chunk-4hwzqthr.js → chunk-161ak2am.js} +3 -2
- package/build/lib/{chunk-z137x08b.js → chunk-1rqbhx4b.js} +7 -5
- package/build/lib/{chunk-1yct6cra.js → chunk-3hjvdf67.js} +1 -1
- package/build/lib/{chunk-r2dkp4tb.js → chunk-5j8pp0xf.js} +1 -1
- package/build/lib/{chunk-3c00n0cy.js → chunk-77se1d35.js} +8 -3
- package/build/lib/{chunk-yrnrbjes.js → chunk-7tft4b8b.js} +4 -2
- package/build/lib/{chunk-w66ce82a.js → chunk-8njjwwcw.js} +4 -2
- package/build/lib/{chunk-v3dk9j7k.js → chunk-aq9eyxas.js} +80 -21
- package/build/lib/{chunk-9tt2021m.js → chunk-d05cvnv8.js} +9 -9
- package/build/lib/{chunk-e8yy2k73.js → chunk-f3sq4896.js} +28 -2
- package/build/lib/{chunk-1fy8azee.js → chunk-fasqtjq1.js} +1 -1
- package/build/lib/{chunk-1jvwqnem.js → chunk-gm3b9j4y.js} +104 -40
- package/build/lib/{chunk-r4j8ybn9.js → chunk-hys7nemr.js} +87 -36
- package/build/lib/{chunk-7pwa92rn.js → chunk-j9668h16.js} +1 -1
- package/build/lib/{chunk-ba41jh41.js → chunk-kcw4cpr3.js} +418 -133
- package/build/lib/{chunk-z96pbjhd.js → chunk-m4swxy5r.js} +13 -6
- package/build/lib/{chunk-xhdpgpkm.js → chunk-mbsde9d0.js} +2 -2
- package/build/lib/{chunk-9yksqgzr.js → chunk-mpvjfvz0.js} +20 -13
- package/build/lib/{chunk-2qsq76xq.js → chunk-qkz5sm0d.js} +128 -34
- package/build/lib/{chunk-nhfax4gb.js → chunk-rfyjqybp.js} +1 -1
- package/build/lib/{chunk-mg03jdmt.js → chunk-vsnwzne5.js} +1 -1
- package/build/lib/{chunk-acgbyf5h.js → chunk-ydxhkgjw.js} +3 -2
- package/build/lib/{chunk-bb0ekhkw.js → chunk-z8kej0sp.js} +69 -18
- package/build/lib/core/agents/agentRuntime.d.ts +2 -1
- package/build/lib/core/agents/defineAgent.d.ts +3 -2
- package/build/lib/core/agents/offSecAgent/index.d.ts +3 -1
- package/build/lib/core/agents/offSecAgent/index.js +10 -8
- package/build/lib/core/agents/offSecAgent/prompt.d.ts +3 -1
- package/build/lib/core/agents/offSecAgent/subagentSpawner.d.ts +2 -1
- package/build/lib/core/agents/offSecAgent/subagentSpawner.js +5 -5
- package/build/lib/core/agents/offSecAgent/tools/index.js +4 -4
- package/build/lib/core/agents/offSecAgent/tools/listMemories.d.ts +11 -1
- package/build/lib/core/agents/offSecAgent/tools/reportError.d.ts +2 -1
- package/build/lib/core/agents/offSecAgent/tools/runPentestWorkflow.d.ts +20 -1
- package/build/lib/core/agents/offSecAgent/tools/spawnPentestAgent.d.ts +4 -7
- package/build/lib/core/agents/offSecAgent/tools/spawnPentestSwarm.d.ts +7 -1
- package/build/lib/core/agents/offSecAgent/tools/types.d.ts +2 -1
- package/build/lib/core/agents/offSecAgent/types.d.ts +7 -1
- package/build/lib/core/agents/specialized/attackSurface/blackboxAgent.js +9 -9
- package/build/lib/core/agents/specialized/attackSurface/schemas.js +9 -9
- package/build/lib/core/agents/specialized/authenticationAgent/index.js +10 -10
- package/build/lib/core/agents/specialized/codeAgent/agent.js +9 -9
- package/build/lib/core/agents/specialized/codeAgent/prompts.d.ts +1 -0
- package/build/lib/core/agents/specialized/findingJudge/agent.js +8 -8
- package/build/lib/core/agents/specialized/findingJudge/index.js +3 -3
- package/build/lib/core/agents/specialized/patching/index.js +10 -10
- package/build/lib/core/agents/specialized/pentest/agent.d.ts +18 -4
- package/build/lib/core/agents/specialized/pentest/agent.js +11 -9
- package/build/lib/core/agents/specialized/whiteboxAttackSurface/index.js +9 -9
- package/build/lib/core/ai/ai.d.ts +23 -6
- package/build/lib/core/ai/ai.js +2 -2
- package/build/lib/core/ai/index.js +2 -2
- package/build/lib/core/ai/models/claude-capabilities.d.ts +3 -2
- package/build/lib/core/ai/models/concentrate.d.ts +1 -0
- package/build/lib/core/ai/models/index.d.ts +1 -1
- package/build/lib/core/ai/providers/concentrate.d.ts +1 -0
- package/build/lib/core/ai/utils.d.ts +2 -0
- package/build/lib/core/ai/utils.js +4 -2
- package/build/lib/core/api/index.d.ts +3 -0
- package/build/lib/core/api/index.js +22 -19
- package/build/lib/core/api/targetedPentest.d.ts +1 -0
- package/build/lib/core/api/targetedPentest.js +10 -10
- package/build/lib/core/config/config.d.ts +3 -0
- package/build/lib/core/config/index.js +1 -1
- package/build/lib/core/findings/registry.js +3 -3
- package/build/lib/core/session/index.d.ts +12 -0
- package/build/lib/core/session/index.js +2 -2
- package/build/lib/core/session/persistence.d.ts +7 -0
- package/build/lib/core/session/persistence.js +7 -3
- package/build/lib/core/workflows/fastStrike.d.ts +3 -1
- package/build/lib/core/workflows/pentest.d.ts +8 -1
- package/build/lib/core/workflows/pentest.js +15 -15
- package/build/lib/core/workflows/seams.js +4 -4
- package/build/lib/core/workflows/whiteboxAttackSurface.js +11 -11
- package/build/lib/index.js +22 -22
- package/build/{logs-x62b7hk1.js → logs-70fyr848.js} +13 -13
- package/build/{native-rollout-evidence-c9yhfqcs.js → native-rollout-evidence-ntensvzb.js} +3 -3
- package/build/{offesecAgent-5whnpeta.js → offesecAgent-kk62tf60.js} +4 -4
- package/build/pentest-4jgznn7h.js +22 -0
- package/build/{pentests-e0f32aqx.js → pentests-3e41hj08.js} +13 -13
- package/build/recordedRunClient-w34kcch1.js +11 -0
- package/build/{targetedPentest-rcbs4nvp.js → targetedPentest-t9snxcj2.js} +18 -11
- package/build/{targets-xj9g3q0z.js → targets-1pyf21c7.js} +13 -13
- package/build/threatModel-48y5qjze.js +21 -0
- package/build/{uninstall-7s784q4a.js → uninstall-fbydd9t6.js} +1 -1
- package/build/{upload-4gvhwmvr.js → upload-sbhwe2fq.js} +4 -4
- package/build/{utils-cjrz64pc.js → utils-23903gcj.js} +3 -3
- package/package.json +1 -1
- package/src/cli.ts +48 -14
- package/src/core/agents/agentRuntime.test.ts +38 -0
- package/src/core/agents/agentRuntime.ts +5 -2
- package/src/core/agents/defineAgent.ts +3 -1
- package/src/core/agents/offSecAgent/index.ts +3 -0
- package/src/core/agents/offSecAgent/offensiveSecurityAgent.test.ts +92 -5
- package/src/core/agents/offSecAgent/offensiveSecurityAgent.ts +70 -31
- package/src/core/agents/offSecAgent/prompt.test.ts +46 -0
- package/src/core/agents/offSecAgent/prompt.ts +52 -8
- package/src/core/agents/offSecAgent/selectiveConstruction.publicPath.test.ts +38 -0
- package/src/core/agents/offSecAgent/selectiveConstruction.test.ts +64 -0
- package/src/core/agents/offSecAgent/subagentSpawner.ts +12 -1
- package/src/core/agents/offSecAgent/tools/delegateAuth.ts +1 -0
- package/src/core/agents/offSecAgent/tools/listMemories.test.ts +230 -0
- package/src/core/agents/offSecAgent/tools/listMemories.ts +73 -6
- package/src/core/agents/offSecAgent/tools/reportError.test.ts +6 -0
- package/src/core/agents/offSecAgent/tools/reportError.ts +10 -2
- package/src/core/agents/offSecAgent/tools/runAttackSurface.ts +2 -0
- package/src/core/agents/offSecAgent/tools/runPentestWorkflow.test.ts +57 -0
- package/src/core/agents/offSecAgent/tools/runPentestWorkflow.ts +19 -1
- package/src/core/agents/offSecAgent/tools/runWhiteboxScan.ts +5 -2
- package/src/core/agents/offSecAgent/tools/spawnCodingAgent.ts +1 -0
- package/src/core/agents/offSecAgent/tools/spawnPentestAgent.test.ts +72 -2
- package/src/core/agents/offSecAgent/tools/spawnPentestAgent.ts +32 -11
- package/src/core/agents/offSecAgent/tools/spawnPentestSwarm.ts +25 -5
- package/src/core/agents/offSecAgent/tools/threatModelGenerator.ts +1 -0
- package/src/core/agents/offSecAgent/tools/types.ts +6 -1
- package/src/core/agents/offSecAgent/tools/updateTask.ts +5 -1
- package/src/core/agents/offSecAgent/tools/whiteboxCandidates.ts +11 -4
- package/src/core/agents/offSecAgent/types.ts +9 -0
- package/src/core/agents/specialized/codeAgent/agent.test.ts +7 -0
- package/src/core/agents/specialized/codeAgent/agent.ts +9 -2
- package/src/core/agents/specialized/codeAgent/prompts.ts +6 -0
- package/src/core/agents/specialized/pentest/agent.test.ts +116 -0
- package/src/core/agents/specialized/pentest/agent.ts +178 -49
- package/src/core/agents/specialized/pentest/results.test.ts +59 -4
- package/src/core/agents/specialized/whiteboxAttackSurface/endpointDocumentationAgent.ts +1 -0
- package/src/core/ai/ai.operator-context.bench.test.ts +1408 -0
- package/src/core/ai/ai.recorded-context.test.ts +74 -0
- package/src/core/ai/ai.test.ts +54 -0
- package/src/core/ai/ai.ts +312 -82
- package/src/core/ai/compactionTelemetry.test.ts +2 -2
- package/src/core/ai/models/anthropic.ts +6 -0
- package/src/core/ai/models/bedrock.ts +18 -0
- package/src/core/ai/models/claude-capabilities.ts +29 -8
- package/src/core/ai/models/concentrate.ts +52 -0
- package/src/core/ai/models/index.ts +25 -4
- package/src/core/ai/models/models.test.ts +154 -0
- package/src/core/ai/models/openrouter.ts +43 -1
- package/src/core/ai/providers/anthropic-models.test.ts +60 -1
- package/src/core/ai/providers/bedrock-models.test.ts +81 -0
- package/src/core/ai/providers/concentrate.test.ts +31 -0
- package/src/core/ai/providers/concentrate.ts +11 -0
- package/src/core/ai/providers/gateway-models.test.ts +16 -6
- package/src/core/ai/utils.native-rollout-evidence.test.ts +1 -0
- package/src/core/ai/utils.ts +189 -143
- package/src/core/api/blackboxPentest.ts +9 -1
- package/src/core/api/index.ts +9 -0
- package/src/core/api/targetedPentest.ts +19 -5
- package/src/core/config/config.test.ts +35 -0
- package/src/core/config/config.ts +5 -0
- package/src/core/observability/telemetry.test.ts +2 -3
- package/src/core/session/index.ts +5 -0
- package/src/core/session/persistence.test.ts +62 -0
- package/src/core/session/persistence.ts +56 -0
- package/src/core/workflows/fastStrike.seams.test.ts +149 -0
- package/src/core/workflows/fastStrike.test.ts +18 -1
- package/src/core/workflows/fastStrike.ts +103 -11
- package/src/core/workflows/pentest.test.ts +104 -0
- package/src/core/workflows/pentest.ts +110 -7
- package/src/core/workflows/seams.test.ts +13 -0
- package/src/core/workflows/seams.ts +5 -1
- package/src/core/workflows/whiteboxAttackSurface.ts +1 -0
- package/src/tui/components/chat/loading-indicator.tsx +20 -4
- package/src/tui/components/chat/message-list.tsx +1 -0
- package/src/tui/components/commands/__tests__/advanced-settings-lifecycle.tsx +176 -0
- package/src/tui/components/commands/advanced-settings.test.ts +28 -0
- package/src/tui/components/commands/advanced-settings.tsx +237 -19
- package/src/tui/components/operator-dashboard/index.tsx +46 -9
- package/src/tui/components/operator-dashboard/logic.test.ts +106 -0
- package/src/tui/components/operator-dashboard/logic.ts +42 -2
- package/src/tui/components/operator-dashboard/run-events.test.ts +3 -1
- package/src/tui/components/shared/__tests__/tool-renderer-lifecycle.tsx +18 -0
- package/src/tui/components/shared/action-label.test.ts +9 -0
- package/src/tui/components/shared/compacting-icon.tsx +18 -0
- package/src/tui/components/shared/index.ts +1 -0
- package/src/tui/components/shared/tool-registry.ts +1 -0
- package/src/tui/components/shared/tool-renderer.tsx +21 -7
- package/src/tui/context/route.tsx +1 -0
- package/src/tui/keybindings/registry.ts +2 -0
- package/build/agent-6w7egcf1.js +0 -13
- package/build/agent-9zx75feh.js +0 -13
- package/build/pentest-e61hc38s.js +0 -22
- package/build/recordedRunClient-dp032c32.js +0 -11
- package/build/threatModel-jkxfa40s.js +0 -21
|
@@ -1,22 +1,88 @@
|
|
|
1
1
|
import { useKeyboard } from "@opentui/react";
|
|
2
2
|
import { useCallback, useState } from "react";
|
|
3
|
+
import type { FindingPolicy } from "../../../core/agents/offSecAgent";
|
|
3
4
|
import { useConfig } from "../../context/config";
|
|
4
5
|
import { Dialog } from "../../context/dialog";
|
|
6
|
+
import { useDimensions } from "../../context/dimensions";
|
|
5
7
|
import { useTheme } from "../../theme";
|
|
6
8
|
import DialogLayout from "../dialog-layout";
|
|
7
9
|
|
|
10
|
+
const FINDING_POLICIES: { value: FindingPolicy; label: string }[] = [
|
|
11
|
+
{ value: "native", label: "Apex judge (default)" },
|
|
12
|
+
{ value: "external", label: "Off (report findings only)" },
|
|
13
|
+
];
|
|
14
|
+
|
|
8
15
|
interface AdvancedSettingsProps {
|
|
9
16
|
onClose: () => void;
|
|
10
17
|
}
|
|
11
18
|
|
|
19
|
+
type FocusedSetting = "strike" | "judge" | "save";
|
|
20
|
+
|
|
12
21
|
export default function AdvancedSettings({ onClose }: AdvancedSettingsProps) {
|
|
13
22
|
const { colors } = useTheme();
|
|
23
|
+
const dimensions = useDimensions();
|
|
24
|
+
const compact = dimensions.width < 65 || dimensions.height < 24;
|
|
14
25
|
const config = useConfig();
|
|
15
26
|
const [saving, setSaving] = useState(false);
|
|
16
27
|
const [error, setError] = useState<string | null>(null);
|
|
17
28
|
const [draftStrikeMode, setDraftStrikeMode] = useState(
|
|
18
29
|
config.data.strikeMode ?? false,
|
|
19
30
|
);
|
|
31
|
+
const [draftFindingPolicy, setDraftFindingPolicy] = useState<FindingPolicy>(
|
|
32
|
+
config.data.strikeMode ? (config.data.findingPolicy ?? "native") : "native",
|
|
33
|
+
);
|
|
34
|
+
const [findingSelectOpen, setFindingSelectOpen] = useState(false);
|
|
35
|
+
const [highlightedFindingIndex, setHighlightedFindingIndex] = useState(0);
|
|
36
|
+
const [focusedSetting, setFocusedSetting] =
|
|
37
|
+
useState<FocusedSetting>("strike");
|
|
38
|
+
|
|
39
|
+
const openFindingSelect = useCallback(() => {
|
|
40
|
+
if (!draftStrikeMode) return;
|
|
41
|
+
setHighlightedFindingIndex(
|
|
42
|
+
Math.max(
|
|
43
|
+
0,
|
|
44
|
+
FINDING_POLICIES.findIndex(
|
|
45
|
+
(option) => option.value === draftFindingPolicy,
|
|
46
|
+
),
|
|
47
|
+
),
|
|
48
|
+
);
|
|
49
|
+
setFindingSelectOpen(true);
|
|
50
|
+
}, [draftFindingPolicy, draftStrikeMode]);
|
|
51
|
+
|
|
52
|
+
const toggleStrikeMode = useCallback(() => {
|
|
53
|
+
if (draftStrikeMode) {
|
|
54
|
+
setDraftFindingPolicy("native");
|
|
55
|
+
setFindingSelectOpen(false);
|
|
56
|
+
setFocusedSetting((focused) =>
|
|
57
|
+
focused === "judge" ? "strike" : focused,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
setDraftStrikeMode(!draftStrikeMode);
|
|
61
|
+
}, [draftStrikeMode]);
|
|
62
|
+
|
|
63
|
+
const toggleFindingPolicy = useCallback(() => {
|
|
64
|
+
if (!draftStrikeMode) return;
|
|
65
|
+
setDraftFindingPolicy((policy) =>
|
|
66
|
+
policy === "native" ? "external" : "native",
|
|
67
|
+
);
|
|
68
|
+
setFindingSelectOpen(false);
|
|
69
|
+
}, [draftStrikeMode]);
|
|
70
|
+
|
|
71
|
+
const moveFocus = useCallback(
|
|
72
|
+
(direction: number) => {
|
|
73
|
+
const visibleSettings: FocusedSetting[] = draftStrikeMode
|
|
74
|
+
? ["strike", "judge", "save"]
|
|
75
|
+
: ["strike", "save"];
|
|
76
|
+
setFocusedSetting((focused) => {
|
|
77
|
+
const currentIndex = Math.max(0, visibleSettings.indexOf(focused));
|
|
78
|
+
const nextIndex =
|
|
79
|
+
(currentIndex + direction + visibleSettings.length) %
|
|
80
|
+
visibleSettings.length;
|
|
81
|
+
return visibleSettings[nextIndex] ?? "strike";
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
[draftStrikeMode],
|
|
85
|
+
);
|
|
20
86
|
|
|
21
87
|
const saveSettings = useCallback(async () => {
|
|
22
88
|
if (saving) return;
|
|
@@ -24,34 +90,72 @@ export default function AdvancedSettings({ onClose }: AdvancedSettingsProps) {
|
|
|
24
90
|
setSaving(true);
|
|
25
91
|
setError(null);
|
|
26
92
|
try {
|
|
27
|
-
await config.update({
|
|
93
|
+
await config.update({
|
|
94
|
+
strikeMode: draftStrikeMode,
|
|
95
|
+
findingPolicy: draftStrikeMode ? draftFindingPolicy : "native",
|
|
96
|
+
});
|
|
28
97
|
onClose();
|
|
29
98
|
} catch (cause) {
|
|
30
99
|
setError(
|
|
31
100
|
cause instanceof Error
|
|
32
|
-
? `Could not save
|
|
33
|
-
: "Could not save
|
|
101
|
+
? `Could not save advanced settings: ${cause.message}`
|
|
102
|
+
: "Could not save advanced settings.",
|
|
34
103
|
);
|
|
35
104
|
setSaving(false);
|
|
36
105
|
}
|
|
37
|
-
}, [config, draftStrikeMode, onClose, saving]);
|
|
106
|
+
}, [config, draftFindingPolicy, draftStrikeMode, onClose, saving]);
|
|
38
107
|
|
|
39
108
|
useKeyboard((key) => {
|
|
109
|
+
if (key.name === "tab") {
|
|
110
|
+
key.preventDefault();
|
|
111
|
+
if (focusedSetting === "strike") toggleStrikeMode();
|
|
112
|
+
else if (focusedSetting === "judge") toggleFindingPolicy();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (findingSelectOpen) {
|
|
117
|
+
key.preventDefault();
|
|
118
|
+
|
|
119
|
+
if (key.name === "escape") {
|
|
120
|
+
setFindingSelectOpen(false);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (key.name === "up" || key.name === "down") {
|
|
125
|
+
const direction = key.name === "up" ? -1 : 1;
|
|
126
|
+
setHighlightedFindingIndex(
|
|
127
|
+
(index) =>
|
|
128
|
+
(index + direction + FINDING_POLICIES.length) %
|
|
129
|
+
FINDING_POLICIES.length,
|
|
130
|
+
);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (key.name === "return") {
|
|
135
|
+
const selected = FINDING_POLICIES[highlightedFindingIndex];
|
|
136
|
+
if (selected) setDraftFindingPolicy(selected.value);
|
|
137
|
+
setFindingSelectOpen(false);
|
|
138
|
+
}
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
40
142
|
if (key.name === "escape") {
|
|
41
143
|
key.preventDefault();
|
|
42
144
|
onClose();
|
|
43
145
|
return;
|
|
44
146
|
}
|
|
45
147
|
|
|
46
|
-
if (key.name === "
|
|
148
|
+
if (key.name === "up" || key.name === "down") {
|
|
47
149
|
key.preventDefault();
|
|
48
|
-
|
|
150
|
+
moveFocus(key.name === "up" ? -1 : 1);
|
|
49
151
|
return;
|
|
50
152
|
}
|
|
51
153
|
|
|
52
154
|
if (key.name === "return") {
|
|
53
155
|
key.preventDefault();
|
|
54
|
-
|
|
156
|
+
if (focusedSetting === "strike") toggleStrikeMode();
|
|
157
|
+
else if (focusedSetting === "judge") openFindingSelect();
|
|
158
|
+
else void saveSettings();
|
|
55
159
|
}
|
|
56
160
|
});
|
|
57
161
|
|
|
@@ -59,31 +163,145 @@ export default function AdvancedSettings({ onClose }: AdvancedSettingsProps) {
|
|
|
59
163
|
<Dialog size="medium" onClose={onClose}>
|
|
60
164
|
<DialogLayout
|
|
61
165
|
title="Advanced Settings"
|
|
166
|
+
escLabel={findingSelectOpen ? "back" : "close"}
|
|
62
167
|
footerActions={[
|
|
63
|
-
|
|
64
|
-
|
|
168
|
+
findingSelectOpen
|
|
169
|
+
? { key: "Enter", label: "Select", variant: "primary" }
|
|
170
|
+
: { key: "Enter", label: "Activate", variant: "primary" },
|
|
171
|
+
findingSelectOpen
|
|
172
|
+
? { key: "↑/↓", label: "Choose" }
|
|
173
|
+
: { key: "↑/↓", label: "Navigate" },
|
|
174
|
+
...(dimensions.width >= 60 && focusedSetting !== "save"
|
|
175
|
+
? [{ key: "Tab", label: "Toggle" }]
|
|
176
|
+
: []),
|
|
65
177
|
]}
|
|
66
178
|
>
|
|
67
|
-
<box flexDirection="column" gap={1} overflow="hidden">
|
|
179
|
+
<box flexDirection="column" gap={compact ? 0 : 1} overflow="hidden">
|
|
68
180
|
<box
|
|
69
181
|
flexDirection="row"
|
|
70
182
|
justifyContent="space-between"
|
|
71
183
|
overflow="hidden"
|
|
184
|
+
backgroundColor={
|
|
185
|
+
focusedSetting === "strike" && !findingSelectOpen
|
|
186
|
+
? colors.backgroundSelected
|
|
187
|
+
: undefined
|
|
188
|
+
}
|
|
189
|
+
onMouseDown={() => {
|
|
190
|
+
setFocusedSetting("strike");
|
|
191
|
+
toggleStrikeMode();
|
|
192
|
+
}}
|
|
72
193
|
>
|
|
73
|
-
<text
|
|
194
|
+
<text
|
|
195
|
+
fg={focusedSetting === "strike" ? colors.primary : colors.text}
|
|
196
|
+
>
|
|
197
|
+
{focusedSetting === "strike" ? "❯ " : " "}Strike Mode
|
|
198
|
+
</text>
|
|
74
199
|
<text fg={draftStrikeMode ? colors.warning : colors.textMuted}>
|
|
75
200
|
{draftStrikeMode ? "● Enabled" : "○ Disabled"}
|
|
76
201
|
</text>
|
|
77
202
|
</box>
|
|
78
203
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
204
|
+
{!compact && (
|
|
205
|
+
<text fg={colors.textMuted}>
|
|
206
|
+
Focused research; no auto-discovery or agent fan-out.
|
|
207
|
+
</text>
|
|
208
|
+
)}
|
|
209
|
+
|
|
210
|
+
{draftStrikeMode && (
|
|
211
|
+
<>
|
|
212
|
+
<box
|
|
213
|
+
flexDirection="row"
|
|
214
|
+
justifyContent="space-between"
|
|
215
|
+
overflow="hidden"
|
|
216
|
+
backgroundColor={
|
|
217
|
+
focusedSetting === "judge" && !findingSelectOpen
|
|
218
|
+
? colors.backgroundSelected
|
|
219
|
+
: undefined
|
|
220
|
+
}
|
|
221
|
+
onMouseDown={() => {
|
|
222
|
+
setFocusedSetting("judge");
|
|
223
|
+
openFindingSelect();
|
|
224
|
+
}}
|
|
225
|
+
>
|
|
226
|
+
<text
|
|
227
|
+
fg={focusedSetting === "judge" ? colors.primary : colors.text}
|
|
228
|
+
>
|
|
229
|
+
{focusedSetting === "judge" ? "❯ " : " "}Finding judge
|
|
230
|
+
</text>
|
|
231
|
+
<text
|
|
232
|
+
fg={
|
|
233
|
+
draftFindingPolicy === "native"
|
|
234
|
+
? colors.primary
|
|
235
|
+
: colors.warning
|
|
236
|
+
}
|
|
237
|
+
>
|
|
238
|
+
{draftFindingPolicy === "native" ? "Apex judge" : "Disabled"}
|
|
239
|
+
{" ▾"}
|
|
240
|
+
</text>
|
|
241
|
+
</box>
|
|
242
|
+
|
|
243
|
+
{findingSelectOpen && (
|
|
244
|
+
<box flexDirection="column" overflow="hidden">
|
|
245
|
+
{FINDING_POLICIES.map((option, index) => {
|
|
246
|
+
const highlighted = index === highlightedFindingIndex;
|
|
247
|
+
return (
|
|
248
|
+
<box
|
|
249
|
+
key={option.value}
|
|
250
|
+
flexDirection="row"
|
|
251
|
+
paddingLeft={1}
|
|
252
|
+
paddingRight={1}
|
|
253
|
+
overflow="hidden"
|
|
254
|
+
backgroundColor={
|
|
255
|
+
highlighted ? colors.backgroundSelected : undefined
|
|
256
|
+
}
|
|
257
|
+
onMouseDown={() => {
|
|
258
|
+
setDraftFindingPolicy(option.value);
|
|
259
|
+
setFindingSelectOpen(false);
|
|
260
|
+
}}
|
|
261
|
+
>
|
|
262
|
+
<text fg={highlighted ? colors.primary : colors.text}>
|
|
263
|
+
{highlighted ? "❯ " : " "}
|
|
264
|
+
{option.label}
|
|
265
|
+
</text>
|
|
266
|
+
{draftFindingPolicy === option.value && (
|
|
267
|
+
<text fg={colors.primary}> ✓</text>
|
|
268
|
+
)}
|
|
269
|
+
</box>
|
|
270
|
+
);
|
|
271
|
+
})}
|
|
272
|
+
</box>
|
|
273
|
+
)}
|
|
274
|
+
|
|
275
|
+
{!compact && (
|
|
276
|
+
<>
|
|
277
|
+
<text fg={colors.textMuted}>
|
|
278
|
+
Judge off skips in-run review and report.
|
|
279
|
+
</text>
|
|
280
|
+
<text fg={colors.textMuted}>
|
|
281
|
+
New sessions only; TUI has no external evaluator.
|
|
282
|
+
</text>
|
|
283
|
+
</>
|
|
284
|
+
)}
|
|
285
|
+
</>
|
|
286
|
+
)}
|
|
287
|
+
|
|
288
|
+
<box
|
|
289
|
+
flexDirection="row"
|
|
290
|
+
overflow="hidden"
|
|
291
|
+
backgroundColor={
|
|
292
|
+
focusedSetting === "save" && !findingSelectOpen
|
|
293
|
+
? colors.backgroundSelected
|
|
294
|
+
: undefined
|
|
295
|
+
}
|
|
296
|
+
onMouseDown={() => {
|
|
297
|
+
setFocusedSetting("save");
|
|
298
|
+
void saveSettings();
|
|
299
|
+
}}
|
|
300
|
+
>
|
|
301
|
+
<text fg={focusedSetting === "save" ? colors.primary : colors.text}>
|
|
302
|
+
{focusedSetting === "save" ? "❯ " : " "}Save settings
|
|
303
|
+
</text>
|
|
304
|
+
</box>
|
|
87
305
|
|
|
88
306
|
{saving && <text fg={colors.textMuted}>Saving…</text>}
|
|
89
307
|
{error && <text fg={colors.error}>{error}</text>}
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
type AgentMode,
|
|
30
30
|
ALL_TOOL_NAMES,
|
|
31
31
|
ASK_USER_QUESTIONS_TOOL_NAME,
|
|
32
|
+
type FindingPolicy,
|
|
32
33
|
PLAN_MODE_TOOL_NAMES,
|
|
33
34
|
SKILL_TOOL_NAMES,
|
|
34
35
|
} from "../../../core/agents/offSecAgent";
|
|
@@ -108,12 +109,15 @@ import {
|
|
|
108
109
|
type DashboardStatus,
|
|
109
110
|
filterOperatorAutocomplete,
|
|
110
111
|
resolveAbortAction,
|
|
112
|
+
resolveActiveFindingPolicy,
|
|
111
113
|
resolveInputFocused,
|
|
112
114
|
resolveKeyboardShortcut,
|
|
113
115
|
resolveOperatorAgentMode,
|
|
116
|
+
resolveOperatorFindingPolicy,
|
|
114
117
|
resolveOperatorStrikeMode,
|
|
115
118
|
resolveSubmit,
|
|
116
119
|
routeCommand,
|
|
120
|
+
shouldHandleQueuedMessageKey,
|
|
117
121
|
} from "./logic";
|
|
118
122
|
import {
|
|
119
123
|
createQueuedMessage,
|
|
@@ -159,6 +163,7 @@ export default function OperatorDashboard({
|
|
|
159
163
|
target?: string;
|
|
160
164
|
operatorMode?: OperatorMode;
|
|
161
165
|
strikeMode?: boolean;
|
|
166
|
+
findingPolicy?: FindingPolicy;
|
|
162
167
|
sandbox?: boolean;
|
|
163
168
|
taskDriven?: boolean;
|
|
164
169
|
headers?: Record<string, string>;
|
|
@@ -206,6 +211,17 @@ export default function OperatorDashboard({
|
|
|
206
211
|
}),
|
|
207
212
|
);
|
|
208
213
|
const [strikeMode, setStrikeMode] = useState(initialStrikeModeRef.current);
|
|
214
|
+
const initialFindingPolicyRef = useRef(
|
|
215
|
+
resolveOperatorFindingPolicy({
|
|
216
|
+
resuming: !!sessionId,
|
|
217
|
+
strikeMode: initialStrikeModeRef.current,
|
|
218
|
+
routeOverride: initialConfig?.findingPolicy,
|
|
219
|
+
persistedDefault: config.data.findingPolicy,
|
|
220
|
+
}),
|
|
221
|
+
);
|
|
222
|
+
const [findingPolicy, setFindingPolicy] = useState(
|
|
223
|
+
initialFindingPolicyRef.current,
|
|
224
|
+
);
|
|
209
225
|
|
|
210
226
|
// biome-ignore lint/correctness/useExhaustiveDependencies: `skillsVersion` is an intentional cache-buster — forces recomputation when skills are refreshed even though `skillsRegistry` (stable ref) hasn't changed.
|
|
211
227
|
const autocompleteOptions = useMemo(() => {
|
|
@@ -361,6 +377,10 @@ export default function OperatorDashboard({
|
|
|
361
377
|
operatorMode,
|
|
362
378
|
strikeMode,
|
|
363
379
|
);
|
|
380
|
+
const activeFindingPolicy = resolveActiveFindingPolicy(
|
|
381
|
+
agentMode,
|
|
382
|
+
findingPolicy,
|
|
383
|
+
);
|
|
364
384
|
const requireApproval = operatorMode === "manual";
|
|
365
385
|
// Plan mode review state
|
|
366
386
|
const [approvedPlanContent, setApprovedPlanContent] = useState<string | null>(
|
|
@@ -427,10 +447,16 @@ export default function OperatorDashboard({
|
|
|
427
447
|
const s = await sessions.get(sessionId);
|
|
428
448
|
setSession(s);
|
|
429
449
|
setSessionCwd(s.rootPath);
|
|
430
|
-
|
|
431
|
-
|
|
450
|
+
const resumedStrikeMode = resolveOperatorStrikeMode({
|
|
451
|
+
resuming: true,
|
|
452
|
+
savedSessionValue: s.config?.operatorSettings?.strikeMode,
|
|
453
|
+
});
|
|
454
|
+
setStrikeMode(resumedStrikeMode);
|
|
455
|
+
setFindingPolicy(
|
|
456
|
+
resolveOperatorFindingPolicy({
|
|
432
457
|
resuming: true,
|
|
433
|
-
|
|
458
|
+
strikeMode: resumedStrikeMode,
|
|
459
|
+
savedSessionValue: s.config?.operatorSettings?.findingPolicy,
|
|
434
460
|
}),
|
|
435
461
|
);
|
|
436
462
|
|
|
@@ -516,6 +542,7 @@ export default function OperatorDashboard({
|
|
|
516
542
|
// New session — just set up operator config; the agent creates the
|
|
517
543
|
// session on the first runAgent call.
|
|
518
544
|
setStrikeMode(initialStrikeModeRef.current);
|
|
545
|
+
setFindingPolicy(initialFindingPolicyRef.current);
|
|
519
546
|
const newMode = initialConfig?.operatorMode ?? "manual";
|
|
520
547
|
setOperatorMode(newMode);
|
|
521
548
|
const requireApproval = newMode === "manual";
|
|
@@ -871,6 +898,7 @@ export default function OperatorDashboard({
|
|
|
871
898
|
...SKILL_TOOL_NAMES,
|
|
872
899
|
] as string[],
|
|
873
900
|
mode: agentMode,
|
|
901
|
+
findingPolicy: activeFindingPolicy,
|
|
874
902
|
authConfig: buildAuthConfig(config.data),
|
|
875
903
|
approvalGate: approvalGateRef.current,
|
|
876
904
|
commandCancelHandle: cancelHandleRef.current,
|
|
@@ -926,6 +954,7 @@ export default function OperatorDashboard({
|
|
|
926
954
|
agentMode !== "plan" ? approvedPlanRef.current : null,
|
|
927
955
|
taskDriven:
|
|
928
956
|
session?.config?.taskDriven ?? initialConfig?.taskDriven,
|
|
957
|
+
findingPolicy: activeFindingPolicy,
|
|
929
958
|
},
|
|
930
959
|
);
|
|
931
960
|
|
|
@@ -945,6 +974,7 @@ export default function OperatorDashboard({
|
|
|
945
974
|
requireApproval,
|
|
946
975
|
enableSuggestions: true,
|
|
947
976
|
strikeMode,
|
|
977
|
+
findingPolicy,
|
|
948
978
|
},
|
|
949
979
|
agentCwd: initialConfig?.sandbox ? undefined : process.cwd(),
|
|
950
980
|
codebasePath: initialConfig?.sandbox ? undefined : process.cwd(),
|
|
@@ -1082,6 +1112,8 @@ export default function OperatorDashboard({
|
|
|
1082
1112
|
initialConfig?.headers,
|
|
1083
1113
|
initialConfig?.promptInjectionLibrarySource,
|
|
1084
1114
|
strikeMode,
|
|
1115
|
+
findingPolicy,
|
|
1116
|
+
activeFindingPolicy,
|
|
1085
1117
|
route.data,
|
|
1086
1118
|
setSessionCwd,
|
|
1087
1119
|
skillsRegistry.buildCatalog,
|
|
@@ -1634,11 +1666,16 @@ This three-phase flow is specific to the TUI \`/threat-model\` command. The same
|
|
|
1634
1666
|
|
|
1635
1667
|
// Keyboard shortcuts
|
|
1636
1668
|
useKeyboard((key) => {
|
|
1669
|
+
const dialogOpen =
|
|
1670
|
+
stack.length > 0 || externalDialogOpen || !!pendingQuestions;
|
|
1637
1671
|
// Queue navigation: handle before general shortcuts
|
|
1638
1672
|
if (
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1673
|
+
shouldHandleQueuedMessageKey(
|
|
1674
|
+
status,
|
|
1675
|
+
queuedMessages.length,
|
|
1676
|
+
inputValue,
|
|
1677
|
+
dialogOpen,
|
|
1678
|
+
)
|
|
1642
1679
|
) {
|
|
1643
1680
|
if (key.name === "up") {
|
|
1644
1681
|
key.preventDefault?.();
|
|
@@ -1765,9 +1802,6 @@ This three-phase flow is specific to the TUI \`/threat-model\` command. The same
|
|
|
1765
1802
|
|
|
1766
1803
|
// Treat the questions form as a dialog so that dashboard-level shortcuts
|
|
1767
1804
|
// (Shift+Tab cycle-mode, etc.) don't fire while the form owns the keyboard.
|
|
1768
|
-
const dialogOpen =
|
|
1769
|
-
stack.length > 0 || externalDialogOpen || !!pendingQuestions;
|
|
1770
|
-
|
|
1771
1805
|
// Ctrl+A to open subagent dialog (skip if another dialog is open)
|
|
1772
1806
|
if (
|
|
1773
1807
|
key.ctrl &&
|
|
@@ -1926,6 +1960,9 @@ This three-phase flow is specific to the TUI \`/threat-model\` command. The same
|
|
|
1926
1960
|
<box flexDirection="row" gap={2}>
|
|
1927
1961
|
<text fg={colors.text}>{session?.name ?? "New Session"}</text>
|
|
1928
1962
|
{strikeMode && <text fg={colors.warning}>STRIKE</text>}
|
|
1963
|
+
{activeFindingPolicy === "external" && (
|
|
1964
|
+
<text fg={colors.textMuted}>JUDGE OFF</text>
|
|
1965
|
+
)}
|
|
1929
1966
|
{(session?.targets[0] || initialConfig?.target) && (
|
|
1930
1967
|
<>
|
|
1931
1968
|
<text fg={colors.textMuted}>•</text>
|
|
@@ -6,12 +6,15 @@ import {
|
|
|
6
6
|
type DashboardStatus,
|
|
7
7
|
filterOperatorAutocomplete,
|
|
8
8
|
resolveAbortAction,
|
|
9
|
+
resolveActiveFindingPolicy,
|
|
9
10
|
resolveInputFocused,
|
|
10
11
|
resolveKeyboardShortcut,
|
|
11
12
|
resolveOperatorAgentMode,
|
|
13
|
+
resolveOperatorFindingPolicy,
|
|
12
14
|
resolveOperatorStrikeMode,
|
|
13
15
|
resolveSubmit,
|
|
14
16
|
routeCommand,
|
|
17
|
+
shouldHandleQueuedMessageKey,
|
|
15
18
|
} from "./logic";
|
|
16
19
|
|
|
17
20
|
// ---------------------------------------------------------------------------
|
|
@@ -130,6 +133,98 @@ describe("resolveOperatorStrikeMode", () => {
|
|
|
130
133
|
});
|
|
131
134
|
});
|
|
132
135
|
|
|
136
|
+
describe("resolveOperatorFindingPolicy", () => {
|
|
137
|
+
it("defaults new sessions to Apex finding review", () => {
|
|
138
|
+
expect(
|
|
139
|
+
resolveOperatorFindingPolicy({ resuming: false, strikeMode: true }),
|
|
140
|
+
).toBe("native");
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("uses the saved preference for new Strike sessions", () => {
|
|
144
|
+
expect(
|
|
145
|
+
resolveOperatorFindingPolicy({
|
|
146
|
+
resuming: false,
|
|
147
|
+
strikeMode: true,
|
|
148
|
+
persistedDefault: "external",
|
|
149
|
+
}),
|
|
150
|
+
).toBe("external");
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("lets an explicit workflow override the saved preference", () => {
|
|
154
|
+
expect(
|
|
155
|
+
resolveOperatorFindingPolicy({
|
|
156
|
+
resuming: false,
|
|
157
|
+
strikeMode: true,
|
|
158
|
+
routeOverride: "native",
|
|
159
|
+
persistedDefault: "external",
|
|
160
|
+
}),
|
|
161
|
+
).toBe("native");
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("restores the policy saved with a resumed Strike session", () => {
|
|
165
|
+
expect(
|
|
166
|
+
resolveOperatorFindingPolicy({
|
|
167
|
+
resuming: true,
|
|
168
|
+
strikeMode: true,
|
|
169
|
+
savedSessionValue: "external",
|
|
170
|
+
persistedDefault: "native",
|
|
171
|
+
}),
|
|
172
|
+
).toBe("external");
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("keeps legacy resumed sessions native despite a newer global preference", () => {
|
|
176
|
+
expect(
|
|
177
|
+
resolveOperatorFindingPolicy({
|
|
178
|
+
resuming: true,
|
|
179
|
+
strikeMode: true,
|
|
180
|
+
persistedDefault: "external",
|
|
181
|
+
}),
|
|
182
|
+
).toBe("native");
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("keeps standard sessions native despite external preferences or overrides", () => {
|
|
186
|
+
expect(
|
|
187
|
+
resolveOperatorFindingPolicy({
|
|
188
|
+
resuming: false,
|
|
189
|
+
strikeMode: false,
|
|
190
|
+
routeOverride: "external",
|
|
191
|
+
persistedDefault: "external",
|
|
192
|
+
}),
|
|
193
|
+
).toBe("native");
|
|
194
|
+
expect(
|
|
195
|
+
resolveOperatorFindingPolicy({
|
|
196
|
+
resuming: true,
|
|
197
|
+
strikeMode: false,
|
|
198
|
+
savedSessionValue: "external",
|
|
199
|
+
}),
|
|
200
|
+
).toBe("native");
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
describe("resolveActiveFindingPolicy", () => {
|
|
205
|
+
it("allows judge off only while the agent is in Fast Strike", () => {
|
|
206
|
+
expect(resolveActiveFindingPolicy("fast-strike", "external")).toBe(
|
|
207
|
+
"external",
|
|
208
|
+
);
|
|
209
|
+
expect(resolveActiveFindingPolicy("default", "external")).toBe("native");
|
|
210
|
+
expect(resolveActiveFindingPolicy("plan", "external")).toBe("native");
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// ---------------------------------------------------------------------------
|
|
215
|
+
// Queue navigation
|
|
216
|
+
// ---------------------------------------------------------------------------
|
|
217
|
+
|
|
218
|
+
describe("shouldHandleQueuedMessageKey", () => {
|
|
219
|
+
it("leaves queue navigation to the dashboard only when no dialog owns the keyboard", () => {
|
|
220
|
+
expect(shouldHandleQueuedMessageKey("running", 2, "", false)).toBe(true);
|
|
221
|
+
expect(shouldHandleQueuedMessageKey("running", 2, "", true)).toBe(false);
|
|
222
|
+
expect(
|
|
223
|
+
shouldHandleQueuedMessageKey("running", 2, " /advanced ", false),
|
|
224
|
+
).toBe(false);
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
133
228
|
// ---------------------------------------------------------------------------
|
|
134
229
|
// resolveSubmit
|
|
135
230
|
// ---------------------------------------------------------------------------
|
|
@@ -623,6 +718,17 @@ describe("buildOperatorSystemPrompt", () => {
|
|
|
623
718
|
expect(prompt).toContain("account for each viable primitive");
|
|
624
719
|
});
|
|
625
720
|
|
|
721
|
+
it("keeps Strike's research loop while leaving finding review to the caller", () => {
|
|
722
|
+
const prompt = buildOperatorSystemPrompt(target, state, "fast-strike", {
|
|
723
|
+
findingPolicy: "external",
|
|
724
|
+
});
|
|
725
|
+
expect(prompt).toContain("# Strike Mode");
|
|
726
|
+
expect(prompt).toContain("requested output format");
|
|
727
|
+
expect(prompt).not.toContain("document_vulnerability");
|
|
728
|
+
expect(prompt).not.toContain("document confirmed vulnerabilities");
|
|
729
|
+
expect(prompt).not.toContain("official report is generated automatically");
|
|
730
|
+
});
|
|
731
|
+
|
|
626
732
|
it("does not include Strike Mode instructions in the standard mode", () => {
|
|
627
733
|
const prompt = buildOperatorSystemPrompt(target, state, "default");
|
|
628
734
|
expect(prompt).not.toContain("# Strike Mode");
|