erosolar-cli 1.7.393 → 1.7.394
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/dist/core/offsecAlphaZero.d.ts +56 -0
- package/dist/core/offsecAlphaZero.d.ts.map +1 -0
- package/dist/core/offsecAlphaZero.js +395 -0
- package/dist/core/offsecAlphaZero.js.map +1 -0
- package/dist/shell/interactiveShell.d.ts +6 -5
- package/dist/shell/interactiveShell.d.ts.map +1 -1
- package/dist/shell/interactiveShell.js +174 -47
- package/dist/shell/interactiveShell.js.map +1 -1
- package/dist/shell/keyboardShortcuts.d.ts.map +1 -1
- package/dist/shell/keyboardShortcuts.js +11 -8
- package/dist/shell/keyboardShortcuts.js.map +1 -1
- package/dist/shell/liveStatus.d.ts +1 -0
- package/dist/shell/liveStatus.d.ts.map +1 -1
- package/dist/shell/liveStatus.js +32 -7
- package/dist/shell/liveStatus.js.map +1 -1
- package/dist/shell/terminalInput.d.ts +8 -2
- package/dist/shell/terminalInput.d.ts.map +1 -1
- package/dist/shell/terminalInput.js +154 -55
- package/dist/shell/terminalInput.js.map +1 -1
- package/dist/ui/ShellUIAdapter.d.ts +0 -11
- package/dist/ui/ShellUIAdapter.d.ts.map +1 -1
- package/dist/ui/ShellUIAdapter.js +0 -32
- package/dist/ui/ShellUIAdapter.js.map +1 -1
- package/dist/ui/shortcutsHelp.js +21 -21
- package/dist/ui/shortcutsHelp.js.map +1 -1
- package/dist/ui/unified/layout.d.ts.map +1 -1
- package/dist/ui/unified/layout.js +31 -25
- package/dist/ui/unified/layout.js.map +1 -1
- package/package.json +1 -1
|
@@ -30,6 +30,7 @@ import { analyzeImprovementOpportunities, runSelfImprovementCycle, getImprovemen
|
|
|
30
30
|
import { listAvailablePlugins } from '../plugins/index.js';
|
|
31
31
|
import { isErosolarRepo, isValidSourceRepo, getRepoName, analyzeSource, runSelfEvolution, stopEvolution, getEvolutionStatus, emergencyEvolutionRollback, learnSourcePatterns, generateFix, } from '../core/selfEvolution.js';
|
|
32
32
|
import { analyzeTokenUsage, discoverModularTargets, getModularStatusDisplay, generateContextOptimizations, getGuidelines, deleteGuideline, getPendingActions, executeModularAction, } from '../core/alphaZeroModular.js';
|
|
33
|
+
import { startOffsecRun, resumeOffsecRun, recordOffsecOutcome, getOffsecNextActions, simulateOffsecRollout, formatOffsecStatus, listOffsecRuns, } from '../core/offsecAlphaZero.js';
|
|
33
34
|
import { generateTestFlows, detectBugs, detectUIUpdates, saveTestFlows, saveBugReports, saveUIUpdates, getTestFlowStatus, } from '../core/intelligentTestFlows.js';
|
|
34
35
|
import { TerminalInputAdapter } from './terminalInputAdapter.js';
|
|
35
36
|
import { renderSessionFrame } from '../ui/unified/layout.js';
|
|
@@ -101,7 +102,6 @@ export class InteractiveShell {
|
|
|
101
102
|
ctrlCHandledThisPress = false;
|
|
102
103
|
pendingCleanup = null;
|
|
103
104
|
cleanupInProgress = false;
|
|
104
|
-
slashPreviewVisible = false;
|
|
105
105
|
lastLoggedPrompt = null;
|
|
106
106
|
lastLoggedPromptAt = 0;
|
|
107
107
|
skillRepository;
|
|
@@ -152,6 +152,8 @@ export class InteractiveShell {
|
|
|
152
152
|
// Auto-build tracking
|
|
153
153
|
autoBuildInFlight = false;
|
|
154
154
|
lastAutoBuildRun = null;
|
|
155
|
+
// Offsec AlphaZero tracking
|
|
156
|
+
offsecRunId = null;
|
|
155
157
|
// Streaming UX tracking
|
|
156
158
|
streamingHeartbeatStart = null;
|
|
157
159
|
streamingHeartbeatFrame = 0;
|
|
@@ -224,6 +226,11 @@ export class InteractiveShell {
|
|
|
224
226
|
description: 'Show available and loaded plugins',
|
|
225
227
|
category: 'configuration',
|
|
226
228
|
});
|
|
229
|
+
this.slashCommands.push({
|
|
230
|
+
command: '/offsec',
|
|
231
|
+
description: 'AlphaZero offensive security run (start/status/next)',
|
|
232
|
+
category: 'automation',
|
|
233
|
+
});
|
|
227
234
|
this.statusTracker = config.statusTracker;
|
|
228
235
|
this.ui = config.ui;
|
|
229
236
|
this.uiAdapter = config.ui.adapter;
|
|
@@ -478,6 +485,7 @@ export class InteractiveShell {
|
|
|
478
485
|
// Discovery and plugins
|
|
479
486
|
'/local', '/discover',
|
|
480
487
|
'/plugins',
|
|
488
|
+
'/offsec',
|
|
481
489
|
'/skills',
|
|
482
490
|
// Self-improvement
|
|
483
491
|
'/evolve', '/modular', '/a0',
|
|
@@ -507,7 +515,6 @@ export class InteractiveShell {
|
|
|
507
515
|
if (text.length > 0) {
|
|
508
516
|
this.resetCtrlCSequence();
|
|
509
517
|
}
|
|
510
|
-
this.handleSlashCommandPreviewChange();
|
|
511
518
|
}
|
|
512
519
|
/**
|
|
513
520
|
* Edit guard mode change handler (Shift+Tab from terminal input)
|
|
@@ -539,8 +546,8 @@ export class InteractiveShell {
|
|
|
539
546
|
return;
|
|
540
547
|
}
|
|
541
548
|
const message = enabled
|
|
542
|
-
? '✅ Verification on. Auto-tests will run after edits. (
|
|
543
|
-
: '⏭️ Verification off. Skipping auto-tests until re-enabled. (
|
|
549
|
+
? '✅ Verification on. Auto-tests will run after edits. (Ctrl+Shift+V to toggle)'
|
|
550
|
+
: '⏭️ Verification off. Skipping auto-tests until re-enabled. (Ctrl+Shift+V to toggle)';
|
|
544
551
|
display.showSystemMessage(message);
|
|
545
552
|
}
|
|
546
553
|
toggleAutoContinueMode() {
|
|
@@ -561,10 +568,10 @@ export class InteractiveShell {
|
|
|
561
568
|
(this.autoContinueEnabled
|
|
562
569
|
? 'The model will be auto-prompted to continue when it expresses intent but does not use tools.'
|
|
563
570
|
: 'The model will not be auto-prompted to continue.') +
|
|
564
|
-
' Toggle with
|
|
571
|
+
' Toggle with Ctrl+Shift+C.');
|
|
565
572
|
}
|
|
566
573
|
/**
|
|
567
|
-
* Cycle through thinking modes (
|
|
574
|
+
* Cycle through thinking modes (Ctrl+Shift+T keyboard shortcut).
|
|
568
575
|
*/
|
|
569
576
|
cycleThinkingMode() {
|
|
570
577
|
const modes = ['concise', 'balanced', 'extended'];
|
|
@@ -1106,7 +1113,16 @@ export class InteractiveShell {
|
|
|
1106
1113
|
const parts = detail?.trim() ? [detail.trim()] : [];
|
|
1107
1114
|
const queued = this.followUpQueue.length;
|
|
1108
1115
|
if (queued > 0) {
|
|
1109
|
-
|
|
1116
|
+
const nextText = this.followUpQueue[0]?.text ?? '';
|
|
1117
|
+
const normalized = nextText.replace(/\s+/g, ' ').trim();
|
|
1118
|
+
const previewLimit = 48;
|
|
1119
|
+
const preview = normalized
|
|
1120
|
+
? normalized.length > previewLimit
|
|
1121
|
+
? `${normalized.slice(0, previewLimit - 1)}…`
|
|
1122
|
+
: normalized
|
|
1123
|
+
: '';
|
|
1124
|
+
const suffix = preview ? ` (next: ${preview})` : '';
|
|
1125
|
+
parts.push(`${queued} follow-up${queued === 1 ? '' : 's'} queued${suffix}`);
|
|
1110
1126
|
}
|
|
1111
1127
|
return parts.join(' • ');
|
|
1112
1128
|
}
|
|
@@ -1133,10 +1149,10 @@ export class InteractiveShell {
|
|
|
1133
1149
|
this.terminalInput.setModeToggles({
|
|
1134
1150
|
verificationEnabled: this.verificationEnabled,
|
|
1135
1151
|
autoContinueEnabled: this.autoContinueEnabled,
|
|
1136
|
-
verificationHotkey: '
|
|
1137
|
-
autoContinueHotkey: '
|
|
1152
|
+
verificationHotkey: 'ctrl+shift+v',
|
|
1153
|
+
autoContinueHotkey: 'ctrl+shift+c',
|
|
1138
1154
|
thinkingModeLabel: this.thinkingMode,
|
|
1139
|
-
thinkingHotkey: '
|
|
1155
|
+
thinkingHotkey: 'ctrl+shift+t',
|
|
1140
1156
|
});
|
|
1141
1157
|
this.refreshStatusLine();
|
|
1142
1158
|
this.terminalInput.render();
|
|
@@ -1232,40 +1248,6 @@ export class InteractiveShell {
|
|
|
1232
1248
|
}
|
|
1233
1249
|
return parts.join(' • ');
|
|
1234
1250
|
}
|
|
1235
|
-
handleSlashCommandPreviewChange() {
|
|
1236
|
-
if (this.pendingInteraction) {
|
|
1237
|
-
this.slashPreviewVisible = false;
|
|
1238
|
-
return;
|
|
1239
|
-
}
|
|
1240
|
-
const shouldShow = this.shouldShowSlashCommandPreview();
|
|
1241
|
-
if (shouldShow && !this.slashPreviewVisible) {
|
|
1242
|
-
this.slashPreviewVisible = true;
|
|
1243
|
-
this.showSlashCommandPreview();
|
|
1244
|
-
return;
|
|
1245
|
-
}
|
|
1246
|
-
if (!shouldShow && this.slashPreviewVisible) {
|
|
1247
|
-
this.slashPreviewVisible = false;
|
|
1248
|
-
this.uiAdapter.hideSlashCommandPreview();
|
|
1249
|
-
}
|
|
1250
|
-
}
|
|
1251
|
-
shouldShowSlashCommandPreview() {
|
|
1252
|
-
const line = this.currentInput ?? '';
|
|
1253
|
-
if (!line.trim()) {
|
|
1254
|
-
return false;
|
|
1255
|
-
}
|
|
1256
|
-
const trimmed = line.trimStart();
|
|
1257
|
-
return trimmed.startsWith('/');
|
|
1258
|
-
}
|
|
1259
|
-
showSlashCommandPreview() {
|
|
1260
|
-
// Filter commands based on current input
|
|
1261
|
-
const line = this.currentInput ?? '';
|
|
1262
|
-
const trimmed = line.trimStart();
|
|
1263
|
-
// Filter commands that match the current input
|
|
1264
|
-
const filtered = this.slashCommands.filter(cmd => cmd.command.startsWith(trimmed) || trimmed === '/');
|
|
1265
|
-
// Show in the unified UI with dynamic overlay
|
|
1266
|
-
this.uiAdapter.showSlashCommandPreview(filtered);
|
|
1267
|
-
// Don't reprompt - this causes flickering
|
|
1268
|
-
}
|
|
1269
1251
|
/**
|
|
1270
1252
|
* Ensure the terminal input is ready for interactive input.
|
|
1271
1253
|
*/
|
|
@@ -1449,8 +1431,6 @@ export class InteractiveShell {
|
|
|
1449
1431
|
}
|
|
1450
1432
|
}
|
|
1451
1433
|
async processInputBlock(line, _wasRapidMultiLine = false) {
|
|
1452
|
-
this.slashPreviewVisible = false;
|
|
1453
|
-
this.uiAdapter.hideSlashCommandPreview();
|
|
1454
1434
|
const trimmed = line.trim();
|
|
1455
1435
|
if (await this.handlePendingInteraction(trimmed)) {
|
|
1456
1436
|
return;
|
|
@@ -1646,6 +1626,9 @@ export class InteractiveShell {
|
|
|
1646
1626
|
case '/a0':
|
|
1647
1627
|
void this.handleModularCommand(input);
|
|
1648
1628
|
break;
|
|
1629
|
+
case '/offsec':
|
|
1630
|
+
void this.handleOffsecCommand(input);
|
|
1631
|
+
break;
|
|
1649
1632
|
case '/test':
|
|
1650
1633
|
case '/tests':
|
|
1651
1634
|
void this.handleTestCommand(input);
|
|
@@ -2907,6 +2890,150 @@ export class InteractiveShell {
|
|
|
2907
2890
|
display.showInfo('Note: /modular is now part of /evolve. Use /evolve tokens, /evolve targets, etc.');
|
|
2908
2891
|
await this.handleEvolveCommand(evolveInput);
|
|
2909
2892
|
}
|
|
2893
|
+
/**
|
|
2894
|
+
* Handle /offsec command - AlphaZero offensive security run helper
|
|
2895
|
+
*/
|
|
2896
|
+
async handleOffsecCommand(input) {
|
|
2897
|
+
const args = input.trim().split(/\s+/).slice(1);
|
|
2898
|
+
const sub = (args[0]?.toLowerCase() ?? 'status');
|
|
2899
|
+
const usage = 'Usage: /offsec start <objective> [--scope target1,target2]\n' +
|
|
2900
|
+
' /offsec status [runId]\n' +
|
|
2901
|
+
' /offsec next [count]\n' +
|
|
2902
|
+
' /offsec auto [steps]\n' +
|
|
2903
|
+
' /offsec win|fail|detect <actionId> [note]\n' +
|
|
2904
|
+
' /offsec resume <runId>\n' +
|
|
2905
|
+
' /offsec runs';
|
|
2906
|
+
const loadRun = (explicitId) => {
|
|
2907
|
+
const run = resumeOffsecRun(explicitId ?? this.offsecRunId);
|
|
2908
|
+
if (!run) {
|
|
2909
|
+
display.showWarning('No offsec run found. Start one with /offsec start "<objective>".');
|
|
2910
|
+
}
|
|
2911
|
+
return run;
|
|
2912
|
+
};
|
|
2913
|
+
if (sub === 'start') {
|
|
2914
|
+
const rest = args.slice(1);
|
|
2915
|
+
const scope = [];
|
|
2916
|
+
const objectiveParts = [];
|
|
2917
|
+
for (let i = 0; i < rest.length; i++) {
|
|
2918
|
+
if (rest[i]?.toLowerCase() === '--scope') {
|
|
2919
|
+
const scopeArg = rest[i + 1];
|
|
2920
|
+
if (scopeArg) {
|
|
2921
|
+
scope.push(...scopeArg.split(',').map((s) => s.trim()).filter(Boolean));
|
|
2922
|
+
}
|
|
2923
|
+
i += 1;
|
|
2924
|
+
continue;
|
|
2925
|
+
}
|
|
2926
|
+
objectiveParts.push(rest[i]);
|
|
2927
|
+
}
|
|
2928
|
+
const objective = objectiveParts.join(' ').trim();
|
|
2929
|
+
if (!objective) {
|
|
2930
|
+
display.showWarning('Provide an objective. Example: /offsec start gain shell on api.example.com --scope api.example.com');
|
|
2931
|
+
display.showInfo(usage);
|
|
2932
|
+
return;
|
|
2933
|
+
}
|
|
2934
|
+
const run = startOffsecRun(objective, scope);
|
|
2935
|
+
this.offsecRunId = run.id;
|
|
2936
|
+
const next = getOffsecNextActions(run.id, 3);
|
|
2937
|
+
display.showSystemMessage(theme.gradient.primary('🛡️ Offsec AlphaZero run started'));
|
|
2938
|
+
display.showSystemMessage(formatOffsecStatus(run, next));
|
|
2939
|
+
return;
|
|
2940
|
+
}
|
|
2941
|
+
if (sub === 'resume') {
|
|
2942
|
+
const targetRun = args[1] ?? this.offsecRunId;
|
|
2943
|
+
const run = resumeOffsecRun(targetRun);
|
|
2944
|
+
if (!run) {
|
|
2945
|
+
display.showWarning(`No offsec run found for id ${targetRun ?? '<unset>'}`);
|
|
2946
|
+
return;
|
|
2947
|
+
}
|
|
2948
|
+
this.offsecRunId = run.id;
|
|
2949
|
+
display.showSystemMessage(theme.gradient.primary(`Resumed offsec run ${run.id}`));
|
|
2950
|
+
display.showSystemMessage(formatOffsecStatus(run, getOffsecNextActions(run.id, 3)));
|
|
2951
|
+
return;
|
|
2952
|
+
}
|
|
2953
|
+
if (sub === 'runs') {
|
|
2954
|
+
const runs = listOffsecRuns();
|
|
2955
|
+
if (runs.length === 0) {
|
|
2956
|
+
display.showInfo('No offsec runs recorded yet.');
|
|
2957
|
+
return;
|
|
2958
|
+
}
|
|
2959
|
+
const lines = [];
|
|
2960
|
+
lines.push(theme.gradient.primary('Recorded offsec runs'));
|
|
2961
|
+
for (const run of runs.slice(0, 10)) {
|
|
2962
|
+
lines.push(`- ${run.id} :: ${run.objective} (updated ${run.updatedAt})`);
|
|
2963
|
+
}
|
|
2964
|
+
if (runs.length > 10) {
|
|
2965
|
+
lines.push(`...and ${runs.length - 10} more`);
|
|
2966
|
+
}
|
|
2967
|
+
display.showSystemMessage(lines.join('\n'));
|
|
2968
|
+
return;
|
|
2969
|
+
}
|
|
2970
|
+
const run = resumeOffsecRun(args[1] ?? this.offsecRunId);
|
|
2971
|
+
if (!run) {
|
|
2972
|
+
return;
|
|
2973
|
+
}
|
|
2974
|
+
this.offsecRunId = run.id;
|
|
2975
|
+
if (sub === 'status' || sub === 'help') {
|
|
2976
|
+
const next = getOffsecNextActions(run.id, 3);
|
|
2977
|
+
display.showSystemMessage(formatOffsecStatus(run, next));
|
|
2978
|
+
if (next.length === 0) {
|
|
2979
|
+
display.showInfo('No pending actions. Mark outcomes or start a new run.');
|
|
2980
|
+
}
|
|
2981
|
+
return;
|
|
2982
|
+
}
|
|
2983
|
+
if (sub === 'next') {
|
|
2984
|
+
const count = Number.isFinite(Number(args[1])) ? Math.max(1, parseInt(args[1], 10)) : 3;
|
|
2985
|
+
const next = getOffsecNextActions(run.id, count);
|
|
2986
|
+
if (next.length === 0) {
|
|
2987
|
+
display.showInfo('No pending actions to suggest.');
|
|
2988
|
+
return;
|
|
2989
|
+
}
|
|
2990
|
+
const lines = [];
|
|
2991
|
+
lines.push(theme.gradient.primary(`Top ${next.length} actions`));
|
|
2992
|
+
for (const action of next) {
|
|
2993
|
+
lines.push(`- [${action.id}] ${action.label} (${action.category}) score=${action.score}`);
|
|
2994
|
+
lines.push(` cmd: ${action.command}`);
|
|
2995
|
+
lines.push(` path: ${action.path.join(' -> ')}`);
|
|
2996
|
+
}
|
|
2997
|
+
lines.push('Mark progress with /offsec win|fail|detect <actionId> [note]');
|
|
2998
|
+
display.showSystemMessage(lines.join('\n'));
|
|
2999
|
+
return;
|
|
3000
|
+
}
|
|
3001
|
+
if (sub === 'auto') {
|
|
3002
|
+
const steps = Number.isFinite(Number(args[1])) ? Math.max(1, parseInt(args[1], 10)) : 5;
|
|
3003
|
+
const plan = simulateOffsecRollout(run.id, steps);
|
|
3004
|
+
if (plan.length === 0) {
|
|
3005
|
+
display.showInfo('No pending actions to simulate.');
|
|
3006
|
+
return;
|
|
3007
|
+
}
|
|
3008
|
+
const lines = [];
|
|
3009
|
+
lines.push(theme.gradient.primary(`Simulated ${plan.length} steps (AlphaZero-style rollout)`));
|
|
3010
|
+
for (const action of plan) {
|
|
3011
|
+
lines.push(`- [${action.id}] ${action.label} (${action.category}) score=${action.score}`);
|
|
3012
|
+
}
|
|
3013
|
+
lines.push('Use /offsec next to view updated ranking.');
|
|
3014
|
+
display.showSystemMessage(lines.join('\n'));
|
|
3015
|
+
return;
|
|
3016
|
+
}
|
|
3017
|
+
if (sub === 'win' || sub === 'fail' || sub === 'detect') {
|
|
3018
|
+
const actionId = args[1];
|
|
3019
|
+
if (!actionId) {
|
|
3020
|
+
display.showWarning('Specify an action id. Example: /offsec win a3 "got shell via RCE"');
|
|
3021
|
+
return;
|
|
3022
|
+
}
|
|
3023
|
+
const note = args.slice(2).join(' ').trim();
|
|
3024
|
+
const outcome = sub === 'win' ? 'success' : sub === 'fail' ? 'fail' : 'detected';
|
|
3025
|
+
const updated = recordOffsecOutcome(run.id, actionId, outcome, note);
|
|
3026
|
+
if (!updated) {
|
|
3027
|
+
display.showWarning(`Action ${actionId} not found in run ${run.id}.`);
|
|
3028
|
+
return;
|
|
3029
|
+
}
|
|
3030
|
+
const next = getOffsecNextActions(run.id, 3);
|
|
3031
|
+
display.showSystemMessage(theme.success(`Recorded ${outcome} for ${actionId} in run ${run.id}`));
|
|
3032
|
+
display.showSystemMessage(formatOffsecStatus(updated, next));
|
|
3033
|
+
return;
|
|
3034
|
+
}
|
|
3035
|
+
display.showInfo(usage);
|
|
3036
|
+
}
|
|
2910
3037
|
/**
|
|
2911
3038
|
* Handle /test command for intelligent test flows
|
|
2912
3039
|
*/
|
|
@@ -3222,7 +3349,7 @@ export class InteractiveShell {
|
|
|
3222
3349
|
if (!value) {
|
|
3223
3350
|
// Show current status
|
|
3224
3351
|
display.showInfo(`Auto-continue is ${this.autoContinueEnabled ? 'enabled' : 'disabled'}. ` +
|
|
3225
|
-
`Use /autocontinue on|off or
|
|
3352
|
+
`Use /autocontinue on|off or Ctrl+Shift+C to toggle.`);
|
|
3226
3353
|
return;
|
|
3227
3354
|
}
|
|
3228
3355
|
if (value !== 'on' && value !== 'off') {
|