From 6b938bb1fa0b9ff39549846c6f594b8939602a35 Mon Sep 17 00:00:00 2001
From: bubblegump30 <49097353+bubblegump30@users.noreply.github.com>
Date: Sun, 8 Nov 2026 03:41:42 -0330
Subject: [PATCH] feat: add account groups, reviewed bulk actions and session
history
---
.github/workflows/windows-release.yml | 32 ++++++------
CHANGELOG.md | 9 ++++
README.md | 25 ++++++---
VERSION | 2 +-
docs/ACCOUNT-SESSION-CENTER-v2.5.0.md | 2 +-
docs/ACCOUNT-WORKFLOWS-v2.6.0.md | 26 ++++++++++
docs/RELEASE-v2.6.0.md | 27 ++++++++++
package-lock.json | 4 +-
package.json | 2 +-
renderer/account-workspace.js | 68 +++++++++++++++++++++++++
renderer/index.html | 9 ++--
renderer/manager.css | 3 ++
renderer/manager.js | 20 ++++----
scripts/check-source.js | 2 +-
scripts/verify-manager-ui.js | 20 ++++++--
src/core/account-manager-ipc.js | 5 ++
src/services/account-manager-store.js | 23 +++++++--
src/services/account-session-service.js | 24 +++++++--
tests/account-manager.test.js | 24 +++++++++
19 files changed, 275 insertions(+), 52 deletions(-)
create mode 100644 docs/ACCOUNT-WORKFLOWS-v2.6.0.md
create mode 100644 docs/RELEASE-v2.6.0.md
create mode 100644 renderer/account-workspace.js
diff --git a/.github/workflows/windows-release.yml b/.github/workflows/windows-release.yml
index ebd91d0..dbf1883 100644
--- a/.github/workflows/windows-release.yml
+++ b/.github/workflows/windows-release.yml
@@ -3,7 +3,7 @@ name: DragonStrap Windows release
on:
push:
branches:
- - release/v2.5.1-windows
+ - release/v2.6.0-windows
permissions:
contents: write
@@ -32,7 +32,7 @@ jobs:
shell: pwsh
run: |
$version = (Get-Content VERSION -Raw).Trim()
- if ($version -ne '2.5.1') { throw "Unexpected release version: $version" }
+ if ($version -ne '2.6.0') { throw "Unexpected release version: $version" }
foreach ($name in @("DragonStrap-Portable-$version-x64.exe", "DragonStrap-Setup-$version-x64.exe", "DragonStrap-FastFolder-$version-x64.zip", "DragonStrap-v$version-Source.zip")) {
$file = Join-Path dist $name
if (-not (Test-Path $file)) { throw "Missing $file" }
@@ -44,12 +44,12 @@ jobs:
- name: Preserve release packages
uses: actions/upload-artifact@v6
with:
- name: DragonStrap-v2.5.1-Windows-x64
+ name: DragonStrap-v2.6.0-Windows-x64
path: |
- dist/DragonStrap-Portable-2.5.1-x64.exe
- dist/DragonStrap-Setup-2.5.1-x64.exe
- dist/DragonStrap-FastFolder-2.5.1-x64.zip
- dist/DragonStrap-v2.5.1-Source.zip
+ dist/DragonStrap-Portable-2.6.0-x64.exe
+ dist/DragonStrap-Setup-2.6.0-x64.exe
+ dist/DragonStrap-FastFolder-2.6.0-x64.zip
+ dist/DragonStrap-v2.6.0-Source.zip
dist/SHA256SUMS.txt
if-no-files-found: error
retention-days: 30
@@ -58,17 +58,17 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
run: |
- if (gh release view v2.5.1 --repo ${{ github.repository }} *> $null) {
- throw 'v2.5.1 already exists; refusing to overwrite it'
+ if (gh release view v2.6.0 --repo ${{ github.repository }} *> $null) {
+ throw 'v2.6.0 already exists; refusing to overwrite it'
}
- gh release create v2.5.1 `
- dist/DragonStrap-Portable-2.5.1-x64.exe `
- dist/DragonStrap-Setup-2.5.1-x64.exe `
- dist/DragonStrap-FastFolder-2.5.1-x64.zip `
- dist/DragonStrap-v2.5.1-Source.zip `
+ gh release create v2.6.0 `
+ dist/DragonStrap-Portable-2.6.0-x64.exe `
+ dist/DragonStrap-Setup-2.6.0-x64.exe `
+ dist/DragonStrap-FastFolder-2.6.0-x64.zip `
+ dist/DragonStrap-v2.6.0-Source.zip `
dist/SHA256SUMS.txt `
--repo ${{ github.repository }} `
--target ${{ github.sha }} `
- --title 'DragonStrap v2.5.1' `
- --notes-file docs/RELEASE-v2.5.1.md `
+ --title 'DragonStrap v2.6.0' `
+ --notes-file docs/RELEASE-v2.6.0.md `
--latest
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0e5af14..e0c80f5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,12 @@
+## v2.6.0 — Account groups, bulk actions and session history
+
+- Add optional local account groups with atomic create/rename/assignment/removal. Existing accounts load ungrouped; credentials remain in the separate encrypted vault.
+- Add retained multi-selection, visible-row selection, group filtering and serial bulk actions with per-account results.
+- Review favorite-game and managed-session targets before launch/stop; reject changed targets, require explicit concurrency for multi-account launches, and support cancelling remaining work.
+- Separate active Sessions from persisted History with search, account/outcome filters, 50-entry pages and truthful detached/exit labels.
+- Retain account labels in history and block removing an account while it is launching.
+- Add 16 backend regressions plus real renderer checks for groups, review/cancel, selection retention, bulk results, history pagination/privacy and dialog layouts.
+
## v2.5.1 — Account & Session Center reliability
- Keep newly restarted sessions out of the previous process snapshot scan, preventing false immediate exit reports.
diff --git a/README.md b/README.md
index b234ec4..fb6ab05 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# DragonStrap
-**v2.5.1 — Account & Session Center reliability · Windows stable release**
+**v2.6.0 — Account groups, bulk actions & session history · Windows stable release**
DragonStrap is a Windows Roblox bootstrapper and launcher with a custom Purple Dragon UI/UX. v2.4.1 adds Disable all flags, including locked Performance Center overrides, and Restore disabled flags. Disabling also turns off pre-launch auto-apply. Windows Setup and Portable x64 packages are available on GitHub Releases.
@@ -10,11 +10,21 @@ The Accounts sidebar entry opens saved accounts, per-account games and servers,
See [the feature and acceptance matrix](docs/ACCOUNT-SESSION-CENTER-v2.5.0.md) and [preview verification report](docs/PREVIEW-DEVELOPMENT.md). Normal saved-account game launching and live CPU/GPU/FPS readings were verified on the test PC, and the user accepted preview.6 as the baseline for stable v2.5.0. Private/specific-server joins, concurrency, anti-AFK, restart recovery and administrator tuning remain acceptance items. FPS targets remain legacy overrides; measured FPS is separate.
+## Account groups and bulk workflows
+
+Create or rename a group, then select accounts and use **Move accounts to group**. Each account belongs to one optional group; removing a group keeps its accounts and encrypted credentials. Older account files load as ungrouped without an automatic rewrite.
+
+Selection survives search/group filtering and refresh. The selected count includes hidden rows. Bulk actions refresh account details, mark accounts favorite, assign groups, launch each account’s favorite game, or stop selected managed sessions. Launch and stop actions have a review screen with account-specific targets. Changed favorites or replacement sessions are rejected instead of silently using a new target. **Cancel remaining** leaves the current request to finish and skips later accounts. Multiple launch attempts require the existing concurrent-launch preference; Roblox still decides which clients remain open.
+
+**Sessions** shows active managed clients. **History** retains the newest 1,000 completed/detached sessions, with account/game search, account/outcome filters, local timestamps, tracked duration and join-confirmation context. Pages contain 50 entries. Closing the manager is labeled as detaching, and an exit is not automatically called a crash.
+
+See [the v2.6 workflow guide](docs/ACCOUNT-WORKFLOWS-v2.6.0.md) for details.
+
## Monitoring requirements
The integrated CPU reader uses the bundled LibreHardwareMonitor library and an existing PawnIO driver. On the verified Ryzen PC, run DragonStrap as administrator for CPU sensor and PresentMon FPS access. No sensor driver is installed automatically. NVIDIA GPU temperature uses the driver sensor. Unsupported or inaccessible sensors show an explicit status. Sampling runs only while Monitoring is open.
-For fastest portable startup, extract the complete Fast Folder ZIP and run DragonStrap.exe. Keep all files together. Folder updates replace the complete extracted folder and retain the normal user-data directory. Stable update preferences remain the default; v2.5.1 is available on that channel.
+For fastest portable startup, extract the complete Fast Folder ZIP and run DragonStrap.exe. Keep all files together. Folder updates replace the complete extracted folder and retain the normal user-data directory. Stable update preferences remain the default; v2.6.0 is available on that channel.
## DragonStrap 2.0 architecture
@@ -51,18 +61,19 @@ Installation/update/recovery operations use one coordinated destructive-operatio
| Item | Version | Where |
| --- | --- | --- |
-| Latest stable Windows release | v2.5.1 | [Setup, Portable, Fast Folder and checksums](https://github.com/bubblegump30/DragonStrap/releases/tag/v2.5.1) |
+| Latest stable Windows release | v2.6.0 | [Setup, Portable, Fast Folder and checksums](https://github.com/bubblegump30/DragonStrap/releases/tag/v2.6.0) |
| Previous accepted prerelease | v2.5.0-preview.6 | [Preview archive](https://github.com/bubblegump30/DragonStrap/releases/tag/v2.5.0-preview.6) |
-| Current repository source | v2.5.1 | GitHub main; optional features retain documented limitations |
+| Current repository source | v2.6.0 | GitHub main; optional features retain documented limitations |
-Download the desired package from the v2.5.1 release and compare its SHA-256 hash with `SHA256SUMS.txt`.
+Download the desired package from the v2.6.0 release and compare its SHA-256 hash with `SHA256SUMS.txt`.
-The [VirusTotal report for the v2.4.0 Setup executable](https://www.virustotal.com/gui/file/3f016485826eb77591e8a616b27dbaa5706f4f59f2d25e4e84e546299e373930?nocache=1) corresponds to SHA-256 `3f016485826eb77591e8a616b27dbaa5706f4f59f2d25e4e84e546299e373930`. This report describes the previous v2.4.0 Setup file and does not cover v2.4.1, v2.5.0, or any v2.5.0 preview executable. Portable is a different file with a different hash. Source ZIPs and repository code are for development; they are not Windows installers or Update Center binaries. The Windows packages are unsigned, so Windows may display a SmartScreen warning.
+The [VirusTotal report for the v2.4.0 Setup executable](https://www.virustotal.com/gui/file/3f016485826eb77591e8a616b27dbaa5706f4f59f2d25e4e84e546299e373930?nocache=1) corresponds to SHA-256 `3f016485826eb77591e8a616b27dbaa5706f4f59f2d25e4e84e546299e373930`. This report describes the previous v2.4.0 Setup file and does not cover v2.4.1, v2.5.x, v2.6.0, or any preview executable. Portable is a different file with a different hash. Source ZIPs and repository code are for development; they are not Windows installers or Update Center binaries. The Windows packages are unsigned, so Windows may display a SmartScreen warning.
## What changed since v2.0.4
| Version | Milestone | Improvements |
| --- | --- | --- |
+| **v2.6.0** | Account workflows | Local groups, multi-select actions with reviewed targets and per-account results, cancellable remaining work, and searchable paginated session history. |
| **v2.5.1** | Session reliability | Cancel pending launches on closing/Stop all, retry failed Windows policies, release completed-session join tracking and preserve unfinished forms during refresh. |
| **v2.5.0** | Account & Session Center | Accepted saved-account launch and CPU/GPU/FPS telemetry, Fast Folder distribution, startup improvements and reliability fixes; see release notes for optional-feature limits. |
| **v2.4.1** | Disable all Player FastFlags | Removes every Player override, including locked keys, saves a restorable copy, and switches off pre-launch auto-apply. Restore brings back the complete set; restart Roblox for changes to take effect. |
@@ -120,7 +131,7 @@ Official releases should upload both Windows executables and the generated `dist
## Version
-`2.5.1`
+`2.6.0`
## Project links
diff --git a/VERSION b/VERSION
index 73462a5..e70b452 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.5.1
+2.6.0
diff --git a/docs/ACCOUNT-SESSION-CENTER-v2.5.0.md b/docs/ACCOUNT-SESSION-CENTER-v2.5.0.md
index 16526a9..40f7160 100644
--- a/docs/ACCOUNT-SESSION-CENTER-v2.5.0.md
+++ b/docs/ACCOUNT-SESSION-CENTER-v2.5.0.md
@@ -1,6 +1,6 @@
# DragonStrap Account & Session Center — v2.5.0 development
-Build version: **2.5.1** (accepted preview.6 functionality plus reliability fixes).
+Build version: **2.6.0**. See ACCOUNT-WORKFLOWS-v2.6.0.md for groups, bulk actions and session history.
This accepted preview extends the v2.4.1 baseline with account/session features, startup improvements and maintenance fixes. Stable v2.5.0 uses the accepted preview.6 implementation; the earlier preview remains available separately. New code is isolated in renderer/manager.js, renderer/manager.css, account/session services, a Windows helper and typed preload calls.
diff --git a/docs/ACCOUNT-WORKFLOWS-v2.6.0.md b/docs/ACCOUNT-WORKFLOWS-v2.6.0.md
new file mode 100644
index 0000000..4f0a607
--- /dev/null
+++ b/docs/ACCOUNT-WORKFLOWS-v2.6.0.md
@@ -0,0 +1,26 @@
+# Account workflows — v2.6.0
+
+## Groups
+
+Open Accounts. Use New group, or select a group in the filter before Rename group/Remove group. Group names are unique ignoring case, with a 40-character name and a maximum of 32 groups. Removing a group makes its accounts ungrouped; it does not delete accounts, games, schedules or credentials.
+
+To assign accounts, select their checkboxes, choose Move accounts to group, choose a destination (or Ungrouped), and Apply to selected. The change commits atomically for the whole selection. Existing account files need no manual migration; older accounts start ungrouped. Encryption remains in the existing account vault.
+
+## Bulk actions
+
+Select visible adds all currently filtered accounts to the selection. Search and group changes retain selection. Clear selection removes it. The selected count includes rows hidden by filters, so inspect it before applying an action.
+
+- Refresh Roblox details verifies each stored session and refreshes available profile data. An expired session fails that account without blocking later accounts.
+- Favorite/unfavorite applies to account ordering; a favorite saved game is a separate setting in each account editor.
+- Launch favorite games opens a review with each chosen game/Place ID. Missing favorites are reported without substituting a different game. A favorite changed after review is refused. More than one selected launch requires enabling concurrent launch attempts in Manager settings. Roblox may close another client; DragonStrap does not patch Roblox.
+- Stop selected managed sessions reviews the managed sessions for each account. Unmanaged Roblox Players are not targeted. A replacement session not included in the review is refused; review again to stop it.
+
+Remote/process actions run one at a time. A result table reports each account independently. Cancel remaining skips accounts not started yet; the current request may finish. Stop all also cancels remaining favorite launches. Closing DragonStrap stops later batch work and retains the existing detach behavior. Dispatched Windows protocol handoffs cannot be recalled.
+
+## History
+
+Sessions displays active managed clients. History retains the newest 1,000 ended records, while lifetime statistics retain their existing totals. Search games/accounts and filter by account/outcome. The view uses 50-entry pages and includes local start/end times, tracked time and join confirmation when available.
+
+Stopped means DragonStrap stopped the managed session. Exited means the process disappeared; it is not proof of a crash. Detached means the manager closed and left Roblox running. Historical account labels remain after account removal. Hide details masks account/game labels in the history view.
+
+History, groups and results contain metadata, not stored session cookies or authentication tickets. Older history without name/join fields remains readable. Group migration and synthetic test evidence are described in RELEASE-v2.6.0.md. Real multi-account compatibility remains dependent on Roblox and needs separate live acceptance.
diff --git a/docs/RELEASE-v2.6.0.md b/docs/RELEASE-v2.6.0.md
new file mode 100644
index 0000000..730c401
--- /dev/null
+++ b/docs/RELEASE-v2.6.0.md
@@ -0,0 +1,27 @@
+# DragonStrap v2.6.0 — Account groups, bulk actions and session history
+
+## New account workflows
+
+- Create/rename/remove local groups and move selected accounts between them. Each account has one optional group. Removing a group keeps its accounts, saved games and encrypted credentials.
+- Select accounts individually or select visible rows. Selection survives filters and refresh; selected counts include hidden rows.
+- Bulk refresh Roblox details, favorite/unfavorite accounts, assign groups, launch favorite games, or stop selected managed sessions. Remote/process operations run serially and report an outcome for every account.
+- Review account-specific favorite games and managed sessions before launching/stopping. The backend rejects changed favorite targets and replacement sessions outside the review. Multiple launches require explicit concurrency preference; Roblox controls concurrent-client compatibility.
+- Cancel remaining bulk work while the current request finishes. Stop all also invalidates remaining batch launches. Accounts cannot be removed while their launch is pending.
+
+## Session history
+
+Sessions now shows active managed clients. History shows retained completed/detached records with account and outcome filters, account/game search, local start/end timestamps, tracked duration and join-confirmation context. Entries use 50-row pages; the existing 1,000-entry retention and lifetime totals are preserved. New history records retain account labels after account removal. Exits are not classified as confirmed crashes; manager closure is described as detaching and leaving Roblox running.
+
+## Data and verification
+
+The account schema remains additive and backward compatible. Older records load as ungrouped without rewriting the file on read. Group and metadata batch writes are atomic. Credentials are not moved or included in history/results. Studio configuration, FastFlag behavior, presets, monitoring and v2.5.1 cancellation/retry fixes remain intact.
+
+239 automated tests passed locally. Coverage includes legacy-file preservation, group CRUD/atomic failures, invalid selections, serialized/partial batch results, overlap prevention, remaining-work cancellation, reviewed favorite/session changes and persisted history labels. Electron interaction/layout checks cover group creation/assignment, review and cancellation, selection retention, per-account results, history pagination/privacy and account/group/bulk dialogs across supported sizes/scales. Hosted Windows CI repeats source, test, release and UI checks before publication.
+
+These checks use synthetic accounts/providers/processes. They do not establish new live multi-account/concurrency acceptance or authorize changing real Roblox sessions. The existing normal-game launch and telemetry acceptance is retained; private/specific-server behavior, concurrency, anti-AFK, process-policy compatibility, recovery and admin tuning retain documented limits.
+
+## Packages
+
+Setup x64, single-file Portable x64, Fast Folder x64, source archive and SHA256SUMS.txt. Extract every Fast Folder file and keep the complete folder together; replace the complete folder for future updates. Existing settings and accounts remain in the normal user-data directory.
+
+Direct CPU temperature and FPS still require their documented sensor/Windows permissions. No driver is installed automatically. Packages remain unsigned. No VirusTotal scan was performed for these newly built files; older reports apply only to their exact hashes.
diff --git a/package-lock.json b/package-lock.json
index 6175c83..a38a9ea 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "dragonstrap",
- "version": "2.5.1",
+ "version": "2.6.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "dragonstrap",
- "version": "2.5.1",
+ "version": "2.6.0",
"devDependencies": {
"electron": "45.2.3",
"electron-builder": "26.18.0"
diff --git a/package.json b/package.json
index 1ed5fd4..b695707 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "dragonstrap",
"productName": "DragonStrap",
- "version": "2.5.1",
+ "version": "2.6.0",
"private": true,
"description": "DragonStrap 2.0 Windows Roblox bootstrapper with consolidated service architecture, coordinated bootstrap/update pipeline, plugin-ready contracts, lazy-loaded UI centers, recovery, profiles, and verified updates",
"main": "main.js",
diff --git a/renderer/account-workspace.js b/renderer/account-workspace.js
new file mode 100644
index 0000000..2332935
--- /dev/null
+++ b/renderer/account-workspace.js
@@ -0,0 +1,68 @@
+'use strict';
+(() => {
+ const escape=value=>String(value??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
+ const selected=new Set();let search='',group='all',bulkAction='refresh',targetGroup='',busy=false,lastResults=[],historyAccount='all',historyStatus='all',historySearch='',page=0,context=null,groupDialog=null,editingGroup=null,bulkDialog=null,review=null;
+ const action=(label,name,attrs='',disabled=false)=>``;
+ const label=(account,data)=>data.options.hideDetails?'Hidden account':account?.alias||account?.username||'Removed account';
+ const options=data=>(data.groups||[]).map(g=>``).join('');
+ function visibleAccounts(data){return data.accounts.filter(a=>(group==='all'||(group==='ungrouped'?!a.groupId:a.groupId===group))&&[a.username,a.alias,...a.tags].join(' ').toLowerCase().includes(search.toLowerCase())).sort((a,b)=>Number(b.favorite)-Number(a.favorite)||a.username.localeCompare(b.username));}
+ function accounts(data){
+ for(const id of selected)if(!data.accounts.some(a=>a.id===id))selected.delete(id);
+ if(!['all','ungrouped'].includes(group)&&!(data.groups||[]).some(g=>g.id===group))group='all';
+ if(targetGroup&&!(data.groups||[]).some(g=>g.id===targetGroup))targetGroup='';
+ const visible=visibleAccounts(data),blocked=busy||data.bulkBusy;const activeGroup=(data.groups||[]).find(g=>g.id===group);
+ return ` Groups organize saved accounts locally. Sign-in credentials remain encrypted separately. Removing a group keeps its accounts. Selection is retained across filters, including hidden rows. Bulk launches run one at a time and use each account’s favorite saved game. Concurrent launches still depend on Roblox. Cancelling a batch stops remaining accounts; the current request may finish. The newest 1,000 completed or detached sessions are retained. An exit is not automatically classified as a crash. Detaching records tracked time and leaves Roblox running. ${rows.length} matching entries · page ${page+1} of ${pages} ${visible.map(a=>{const running=data.sessions.some(s=>s.accountId===a.id&&s.status==='running');return `SELECT FAV ACCOUNT GROUP / TAGS GAMES FPS TARGET STATE R$ ACTIONS `;}).join('')}`:''}${escape(label(a,data))}${data.options.hideDetails?'':escape(a.username)+' · '}${a.connected?'Session saved':'Sign-in needed'}
${escape((data.groups||[]).find(g=>g.id===a.groupId)?.name||'Ungrouped')} ${a.games.length} ${a.policy.fpsCap||'Default'} ${running?'Running':'Not running'} ${data.options.hideDetails?'Hidden':Number.isSafeInteger(a.robux)&&a.robux>=0?a.robux:'Unavailable'} LAST BULK ACTION
${lastResults.map(r=>`ACCOUNT RESULT DETAIL `).join('')}${escape(label(data.accounts.find(a=>a.id===r.accountId),data))} ${r.ok?'Completed':'Not completed'} ${escape(r.message)} SESSION HISTORY
${current.map(h=>`ACCOUNT GAME STARTED ENDED TRACKED OUTCOME `).join('')||'${escape(data.options.hideDetails?'Hidden account':data.accounts.find(a=>a.id===h.accountId)?.alias||data.accounts.find(a=>a.id===h.accountId)?.username||h.accountName||'Removed account')} ${escape(data.options.hideDetails?'Hidden game':h.gameName||'Unknown game')} ${escape(date(h.startedAt))} ${escape(date(h.endedAt))} ${duration(h.durationSeconds)} ${escape(outcomes[h.status]||h.status||'Unknown')}${h.joinState==='joined'?'Game join was confirmed':h.joinState?'Game join was not confirmed':''} '}No session history matches these filters. ${item?'Rename group':'New account group'}
${ids.length} selected accounts, including any hidden by the account filter. Each result is reported separately. Roblox decides whether concurrent clients remain open.
| ACCOUNT | ${requestedAction==='stop'?'MANAGED SESSIONS':'FAVORITE GAME'} |
|---|---|
| ${escape(label(account,data))} | ${escape(target)} |