Skip to content

feat(app): group Codex child sessions and resize sidebar - #463

Open
AmagiDDmxh wants to merge 1 commit into
paperboytm:mainfrom
AmagiDDmxh:feat/session-tree-resizable-sidebar
Open

feat(app): group Codex child sessions and resize sidebar#463
AmagiDDmxh wants to merge 1 commit into
paperboytm:mainfrom
AmagiDDmxh:feat/session-tree-resizable-sidebar

Conversation

@AmagiDDmxh

@AmagiDDmxhAmagiDDmxh commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • group Codex child sessions under their parent session in the desktop library instead of showing subagent runs as unrelated duplicate rows
  • add a persistent, resizable desktop sidebar with pointer, keyboard, and reset interactions
  • store Codex parent-session lineage in SQLite and reindex existing Codex sessions so the tree is populated for existing libraries

Why

Codex records subagent work as separate session files and links each child to its parent through parent_thread_id. Spool previously discarded that relationship, so parent and child sessions appeared as independent entries with similar titles and timestamps. This made the library look as if it contained duplicate sessions.

Preserving the lineage lets the desktop app present those records as a tree while keeping every child session individually accessible. The sidebar resize control also brings the desktop shell in line with the dimensions and behavior documented in DESIGN.md.

Implementation

  • add nullable parent_session_uuid storage and an index in schema migration v16
  • parse parent_thread_id in the shared session-kit Codex parser and propagate it through core session models and sync writes
  • bump the Codex index version to codex-v7-parent-session-tree so existing records are refreshed
  • page by root sessions, then load their descendants with a recursive CTE so children do not consume root pagination slots
  • build cycle-safe session forests in the renderer and render nested rows with expand/collapse controls
  • keep tree context in library, virtualized, and share-editor session lists
  • add a 200-360 px sidebar resize separator, persist the selected width, support arrow/Home/End keys, and reset to 240 px on double-click
  • update localized accessibility labels and the desktop layout guidance in DESIGN.md

Verification

  • pnpm exec vp run --no-cache -r build
  • pnpm typecheck
  • pnpm exec vp check
  • focused core parser, migration, query, and project-session tests: 40 passed
  • renderer session-tree and resize-handle tests: 3 passed
  • Electron E2E coverage for tree interaction and sidebar resize persistence: 2 passed

Known upstream test issue

The full pnpm test run reaches an existing failure in packages/session-view/src/build-output.test.ts. That test invokes pnpm exec vite build, but the current Vite+ workspace does not expose a vite binary (Command "vite" not found). The package's normal vp build path succeeds, including in the full no-cache build above.

@AmagiDDmxh
AmagiDDmxhforce-pushed the feat/session-tree-resizable-sidebar branch from ae2ed0a to 9dd13d5CompareJuly 18, 2026 18:49
@AmagiDDmxhAmagiDDmxh changed the title Feat/session tree resizable sidebarfeat(app): group Codex child sessions and resize sidebarJul 18, 2026
bet4it added a commit to bet4it/spool that referenced this pull request Aug 30, 2026
Cherry-pick of paperboytm#463, adapted for our repo layout
(packages/app instead of apps/app, schema v17 instead of v16, and
codex-v10 instead of codex-v7 to avoid version collisions).
Core changes:
- Add parentSessionUuid to ParsedSession and Session types
- Parse parent_thread_id from Codex session_meta records
- Store parent_session_uuid in SQLite (migration v17) with an index
- Page by root sessions in listRecentSessionsPage, then load
descendants via recursive CTE so children don't consume pagination
- Bump CODEX_INDEX_VERSION to codex-v10-parent-session-tree
Renderer changes:
- buildSessionForest creates cycle-safe trees from flat session lists
- SessionRow renders tree depth indentation, expand/collapse toggle,
and child-session count
- VirtualSessionList filters tree rows by ancestor expansion state
- LibraryLanding buckets root sessions only and appends child rows
within each bucket
- SidebarResizeHandle: pointer-drag + keyboard resize (200-360px),
persisted to localStorage, double-click resets to 240px
- AppTopBar and SidebarRail use dynamic width instead of w-60
- Sidebar receives and applies the width prop
- DESIGN.md updated for resizable sidebar spec
Tests: 508 core + 485 app pass (2 pre-existing security IPC failures
unrelated to this change).
bet4it added a commit to bet4it/spool that referenced this pull request Aug 30, 2026
The cherry-pick of paperboytm#463 only wired tree grouping into the Library
landing; ProjectView still rendered children as flat rows mixed with
their parents.
Core:
- listSessionsByIdentity now pages by root sessions and loads
descendants via recursive CTE for sortOrder=recent, reusing
executeRecentTreePage. A root filter is added so children don't
appear in both the root page and the descendants query (duplicates).
- Descendants re-apply identity/source filters: a source-filtered
family hides together instead of leaving dangling orphans.
- '' parent_session_uuid (codex writes empty string, not NULL) is
treated as a root. listRecentSessionsPage didn't need this, but the
new shared path makes the contract explicit.
Renderer:
- ProjectView builds a session forest from the page and nests children
under their parent (chevron expand, depth indentation, child count),
matching LibraryLanding. Directory grouping builds one forest per
cwd; filtered-out parents orphan their children into roots so they
stay visible.
E2e:
- New project-view-session-tree.spec.ts with codex parent/child
fixtures: collapse by default, expand shows indented children at
depth 1, child rows open their own detail.
- launchApp now isolates SPOOL_GROK_DIR/GROK_HOME — grok was syncing
the developer's real ~/.grok/sessions during e2e, which made the
end-of-list footer assertion flaky.
Tests: 513 core + 490 app unit + tree/project-view/pin e2e pass.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AmagiDDmxh
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
feat(app): group Codex child sessions and resize sidebar by AmagiDDmxh · Pull Request #463 · paperboytm/spool · GitHub
Skip to content

feat(app): group Codex child sessions and resize sidebar - #463

Open
AmagiDDmxh wants to merge 1 commit into
paperboytm:mainfrom
AmagiDDmxh:feat/session-tree-resizable-sidebar
Open

feat(app): group Codex child sessions and resize sidebar#463
AmagiDDmxh wants to merge 1 commit into
paperboytm:mainfrom
AmagiDDmxh:feat/session-tree-resizable-sidebar

Conversation

@AmagiDDmxh

@AmagiDDmxhAmagiDDmxh commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • group Codex child sessions under their parent session in the desktop library instead of showing subagent runs as unrelated duplicate rows
  • add a persistent, resizable desktop sidebar with pointer, keyboard, and reset interactions
  • store Codex parent-session lineage in SQLite and reindex existing Codex sessions so the tree is populated for existing libraries

Why

Codex records subagent work as separate session files and links each child to its parent through parent_thread_id. Spool previously discarded that relationship, so parent and child sessions appeared as independent entries with similar titles and timestamps. This made the library look as if it contained duplicate sessions.

Preserving the lineage lets the desktop app present those records as a tree while keeping every child session individually accessible. The sidebar resize control also brings the desktop shell in line with the dimensions and behavior documented in DESIGN.md.

Implementation

  • add nullable parent_session_uuid storage and an index in schema migration v16
  • parse parent_thread_id in the shared session-kit Codex parser and propagate it through core session models and sync writes
  • bump the Codex index version to codex-v7-parent-session-tree so existing records are refreshed
  • page by root sessions, then load their descendants with a recursive CTE so children do not consume root pagination slots
  • build cycle-safe session forests in the renderer and render nested rows with expand/collapse controls
  • keep tree context in library, virtualized, and share-editor session lists
  • add a 200-360 px sidebar resize separator, persist the selected width, support arrow/Home/End keys, and reset to 240 px on double-click
  • update localized accessibility labels and the desktop layout guidance in DESIGN.md

Verification

  • pnpm exec vp run --no-cache -r build
  • pnpm typecheck
  • pnpm exec vp check
  • focused core parser, migration, query, and project-session tests: 40 passed
  • renderer session-tree and resize-handle tests: 3 passed
  • Electron E2E coverage for tree interaction and sidebar resize persistence: 2 passed

Known upstream test issue

The full pnpm test run reaches an existing failure in packages/session-view/src/build-output.test.ts. That test invokes pnpm exec vite build, but the current Vite+ workspace does not expose a vite binary (Command "vite" not found). The package's normal vp build path succeeds, including in the full no-cache build above.

@AmagiDDmxh
AmagiDDmxhforce-pushed the feat/session-tree-resizable-sidebar branch from ae2ed0a to 9dd13d5CompareJuly 18, 2026 18:49
@AmagiDDmxhAmagiDDmxh changed the title Feat/session tree resizable sidebarfeat(app): group Codex child sessions and resize sidebarJul 18, 2026
bet4it added a commit to bet4it/spool that referenced this pull request Aug 30, 2026
Cherry-pick of paperboytm#463, adapted for our repo layout
(packages/app instead of apps/app, schema v17 instead of v16, and
codex-v10 instead of codex-v7 to avoid version collisions).
Core changes:
- Add parentSessionUuid to ParsedSession and Session types
- Parse parent_thread_id from Codex session_meta records
- Store parent_session_uuid in SQLite (migration v17) with an index
- Page by root sessions in listRecentSessionsPage, then load
descendants via recursive CTE so children don't consume pagination
- Bump CODEX_INDEX_VERSION to codex-v10-parent-session-tree
Renderer changes:
- buildSessionForest creates cycle-safe trees from flat session lists
- SessionRow renders tree depth indentation, expand/collapse toggle,
and child-session count
- VirtualSessionList filters tree rows by ancestor expansion state
- LibraryLanding buckets root sessions only and appends child rows
within each bucket
- SidebarResizeHandle: pointer-drag + keyboard resize (200-360px),
persisted to localStorage, double-click resets to 240px
- AppTopBar and SidebarRail use dynamic width instead of w-60
- Sidebar receives and applies the width prop
- DESIGN.md updated for resizable sidebar spec
Tests: 508 core + 485 app pass (2 pre-existing security IPC failures
unrelated to this change).
bet4it added a commit to bet4it/spool that referenced this pull request Aug 30, 2026
The cherry-pick of paperboytm#463 only wired tree grouping into the Library
landing; ProjectView still rendered children as flat rows mixed with
their parents.
Core:
- listSessionsByIdentity now pages by root sessions and loads
descendants via recursive CTE for sortOrder=recent, reusing
executeRecentTreePage. A root filter is added so children don't
appear in both the root page and the descendants query (duplicates).
- Descendants re-apply identity/source filters: a source-filtered
family hides together instead of leaving dangling orphans.
- '' parent_session_uuid (codex writes empty string, not NULL) is
treated as a root. listRecentSessionsPage didn't need this, but the
new shared path makes the contract explicit.
Renderer:
- ProjectView builds a session forest from the page and nests children
under their parent (chevron expand, depth indentation, child count),
matching LibraryLanding. Directory grouping builds one forest per
cwd; filtered-out parents orphan their children into roots so they
stay visible.
E2e:
- New project-view-session-tree.spec.ts with codex parent/child
fixtures: collapse by default, expand shows indented children at
depth 1, child rows open their own detail.
- launchApp now isolates SPOOL_GROK_DIR/GROK_HOME — grok was syncing
the developer's real ~/.grok/sessions during e2e, which made the
end-of-list footer assertion flaky.
Tests: 513 core + 490 app unit + tree/project-view/pin e2e pass.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AmagiDDmxh
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(app): group Codex child sessions and resize sidebar by AmagiDDmxh · Pull Request #463 · paperboytm/spool · GitHub
Skip to content

feat(app): group Codex child sessions and resize sidebar - #463

Open
AmagiDDmxh wants to merge 1 commit into
paperboytm:mainfrom
AmagiDDmxh:feat/session-tree-resizable-sidebar
Open

feat(app): group Codex child sessions and resize sidebar#463
AmagiDDmxh wants to merge 1 commit into
paperboytm:mainfrom
AmagiDDmxh:feat/session-tree-resizable-sidebar

Conversation

@AmagiDDmxh

@AmagiDDmxhAmagiDDmxh commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • group Codex child sessions under their parent session in the desktop library instead of showing subagent runs as unrelated duplicate rows
  • add a persistent, resizable desktop sidebar with pointer, keyboard, and reset interactions
  • store Codex parent-session lineage in SQLite and reindex existing Codex sessions so the tree is populated for existing libraries

Why

Codex records subagent work as separate session files and links each child to its parent through parent_thread_id. Spool previously discarded that relationship, so parent and child sessions appeared as independent entries with similar titles and timestamps. This made the library look as if it contained duplicate sessions.

Preserving the lineage lets the desktop app present those records as a tree while keeping every child session individually accessible. The sidebar resize control also brings the desktop shell in line with the dimensions and behavior documented in DESIGN.md.

Implementation

  • add nullable parent_session_uuid storage and an index in schema migration v16
  • parse parent_thread_id in the shared session-kit Codex parser and propagate it through core session models and sync writes
  • bump the Codex index version to codex-v7-parent-session-tree so existing records are refreshed
  • page by root sessions, then load their descendants with a recursive CTE so children do not consume root pagination slots
  • build cycle-safe session forests in the renderer and render nested rows with expand/collapse controls
  • keep tree context in library, virtualized, and share-editor session lists
  • add a 200-360 px sidebar resize separator, persist the selected width, support arrow/Home/End keys, and reset to 240 px on double-click
  • update localized accessibility labels and the desktop layout guidance in DESIGN.md

Verification

  • pnpm exec vp run --no-cache -r build
  • pnpm typecheck
  • pnpm exec vp check
  • focused core parser, migration, query, and project-session tests: 40 passed
  • renderer session-tree and resize-handle tests: 3 passed
  • Electron E2E coverage for tree interaction and sidebar resize persistence: 2 passed

Known upstream test issue

The full pnpm test run reaches an existing failure in packages/session-view/src/build-output.test.ts. That test invokes pnpm exec vite build, but the current Vite+ workspace does not expose a vite binary (Command "vite" not found). The package's normal vp build path succeeds, including in the full no-cache build above.

@AmagiDDmxh
AmagiDDmxhforce-pushed the feat/session-tree-resizable-sidebar branch from ae2ed0a to 9dd13d5CompareJuly 18, 2026 18:49
@AmagiDDmxhAmagiDDmxh changed the title Feat/session tree resizable sidebarfeat(app): group Codex child sessions and resize sidebarJul 18, 2026
bet4it added a commit to bet4it/spool that referenced this pull request Aug 30, 2026
Cherry-pick of paperboytm#463, adapted for our repo layout
(packages/app instead of apps/app, schema v17 instead of v16, and
codex-v10 instead of codex-v7 to avoid version collisions).
Core changes:
- Add parentSessionUuid to ParsedSession and Session types
- Parse parent_thread_id from Codex session_meta records
- Store parent_session_uuid in SQLite (migration v17) with an index
- Page by root sessions in listRecentSessionsPage, then load
descendants via recursive CTE so children don't consume pagination
- Bump CODEX_INDEX_VERSION to codex-v10-parent-session-tree
Renderer changes:
- buildSessionForest creates cycle-safe trees from flat session lists
- SessionRow renders tree depth indentation, expand/collapse toggle,
and child-session count
- VirtualSessionList filters tree rows by ancestor expansion state
- LibraryLanding buckets root sessions only and appends child rows
within each bucket
- SidebarResizeHandle: pointer-drag + keyboard resize (200-360px),
persisted to localStorage, double-click resets to 240px
- AppTopBar and SidebarRail use dynamic width instead of w-60
- Sidebar receives and applies the width prop
- DESIGN.md updated for resizable sidebar spec
Tests: 508 core + 485 app pass (2 pre-existing security IPC failures
unrelated to this change).
bet4it added a commit to bet4it/spool that referenced this pull request Aug 30, 2026
The cherry-pick of paperboytm#463 only wired tree grouping into the Library
landing; ProjectView still rendered children as flat rows mixed with
their parents.
Core:
- listSessionsByIdentity now pages by root sessions and loads
descendants via recursive CTE for sortOrder=recent, reusing
executeRecentTreePage. A root filter is added so children don't
appear in both the root page and the descendants query (duplicates).
- Descendants re-apply identity/source filters: a source-filtered
family hides together instead of leaving dangling orphans.
- '' parent_session_uuid (codex writes empty string, not NULL) is
treated as a root. listRecentSessionsPage didn't need this, but the
new shared path makes the contract explicit.
Renderer:
- ProjectView builds a session forest from the page and nests children
under their parent (chevron expand, depth indentation, child count),
matching LibraryLanding. Directory grouping builds one forest per
cwd; filtered-out parents orphan their children into roots so they
stay visible.
E2e:
- New project-view-session-tree.spec.ts with codex parent/child
fixtures: collapse by default, expand shows indented children at
depth 1, child rows open their own detail.
- launchApp now isolates SPOOL_GROK_DIR/GROK_HOME — grok was syncing
the developer's real ~/.grok/sessions during e2e, which made the
end-of-list footer assertion flaky.
Tests: 513 core + 490 app unit + tree/project-view/pin e2e pass.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AmagiDDmxh
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(app): group Codex child sessions and resize sidebar by AmagiDDmxh · Pull Request #463 · paperboytm/spool · GitHub
Skip to content

feat(app): group Codex child sessions and resize sidebar - #463

Open
AmagiDDmxh wants to merge 1 commit into
paperboytm:mainfrom
AmagiDDmxh:feat/session-tree-resizable-sidebar
Open

feat(app): group Codex child sessions and resize sidebar#463
AmagiDDmxh wants to merge 1 commit into
paperboytm:mainfrom
AmagiDDmxh:feat/session-tree-resizable-sidebar

Conversation

@AmagiDDmxh

@AmagiDDmxhAmagiDDmxh commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • group Codex child sessions under their parent session in the desktop library instead of showing subagent runs as unrelated duplicate rows
  • add a persistent, resizable desktop sidebar with pointer, keyboard, and reset interactions
  • store Codex parent-session lineage in SQLite and reindex existing Codex sessions so the tree is populated for existing libraries

Why

Codex records subagent work as separate session files and links each child to its parent through parent_thread_id. Spool previously discarded that relationship, so parent and child sessions appeared as independent entries with similar titles and timestamps. This made the library look as if it contained duplicate sessions.

Preserving the lineage lets the desktop app present those records as a tree while keeping every child session individually accessible. The sidebar resize control also brings the desktop shell in line with the dimensions and behavior documented in DESIGN.md.

Implementation

  • add nullable parent_session_uuid storage and an index in schema migration v16
  • parse parent_thread_id in the shared session-kit Codex parser and propagate it through core session models and sync writes
  • bump the Codex index version to codex-v7-parent-session-tree so existing records are refreshed
  • page by root sessions, then load their descendants with a recursive CTE so children do not consume root pagination slots
  • build cycle-safe session forests in the renderer and render nested rows with expand/collapse controls
  • keep tree context in library, virtualized, and share-editor session lists
  • add a 200-360 px sidebar resize separator, persist the selected width, support arrow/Home/End keys, and reset to 240 px on double-click
  • update localized accessibility labels and the desktop layout guidance in DESIGN.md

Verification

  • pnpm exec vp run --no-cache -r build
  • pnpm typecheck
  • pnpm exec vp check
  • focused core parser, migration, query, and project-session tests: 40 passed
  • renderer session-tree and resize-handle tests: 3 passed
  • Electron E2E coverage for tree interaction and sidebar resize persistence: 2 passed

Known upstream test issue

The full pnpm test run reaches an existing failure in packages/session-view/src/build-output.test.ts. That test invokes pnpm exec vite build, but the current Vite+ workspace does not expose a vite binary (Command "vite" not found). The package's normal vp build path succeeds, including in the full no-cache build above.

@AmagiDDmxh
AmagiDDmxhforce-pushed the feat/session-tree-resizable-sidebar branch from ae2ed0a to 9dd13d5CompareJuly 18, 2026 18:49
@AmagiDDmxhAmagiDDmxh changed the title Feat/session tree resizable sidebarfeat(app): group Codex child sessions and resize sidebarJul 18, 2026
bet4it added a commit to bet4it/spool that referenced this pull request Aug 30, 2026
Cherry-pick of paperboytm#463, adapted for our repo layout
(packages/app instead of apps/app, schema v17 instead of v16, and
codex-v10 instead of codex-v7 to avoid version collisions).
Core changes:
- Add parentSessionUuid to ParsedSession and Session types
- Parse parent_thread_id from Codex session_meta records
- Store parent_session_uuid in SQLite (migration v17) with an index
- Page by root sessions in listRecentSessionsPage, then load
descendants via recursive CTE so children don't consume pagination
- Bump CODEX_INDEX_VERSION to codex-v10-parent-session-tree
Renderer changes:
- buildSessionForest creates cycle-safe trees from flat session lists
- SessionRow renders tree depth indentation, expand/collapse toggle,
and child-session count
- VirtualSessionList filters tree rows by ancestor expansion state
- LibraryLanding buckets root sessions only and appends child rows
within each bucket
- SidebarResizeHandle: pointer-drag + keyboard resize (200-360px),
persisted to localStorage, double-click resets to 240px
- AppTopBar and SidebarRail use dynamic width instead of w-60
- Sidebar receives and applies the width prop
- DESIGN.md updated for resizable sidebar spec
Tests: 508 core + 485 app pass (2 pre-existing security IPC failures
unrelated to this change).
bet4it added a commit to bet4it/spool that referenced this pull request Aug 30, 2026
The cherry-pick of paperboytm#463 only wired tree grouping into the Library
landing; ProjectView still rendered children as flat rows mixed with
their parents.
Core:
- listSessionsByIdentity now pages by root sessions and loads
descendants via recursive CTE for sortOrder=recent, reusing
executeRecentTreePage. A root filter is added so children don't
appear in both the root page and the descendants query (duplicates).
- Descendants re-apply identity/source filters: a source-filtered
family hides together instead of leaving dangling orphans.
- '' parent_session_uuid (codex writes empty string, not NULL) is
treated as a root. listRecentSessionsPage didn't need this, but the
new shared path makes the contract explicit.
Renderer:
- ProjectView builds a session forest from the page and nests children
under their parent (chevron expand, depth indentation, child count),
matching LibraryLanding. Directory grouping builds one forest per
cwd; filtered-out parents orphan their children into roots so they
stay visible.
E2e:
- New project-view-session-tree.spec.ts with codex parent/child
fixtures: collapse by default, expand shows indented children at
depth 1, child rows open their own detail.
- launchApp now isolates SPOOL_GROK_DIR/GROK_HOME — grok was syncing
the developer's real ~/.grok/sessions during e2e, which made the
end-of-list footer assertion flaky.
Tests: 513 core + 490 app unit + tree/project-view/pin e2e pass.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AmagiDDmxh
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' feat(app): group Codex child sessions and resize sidebar by AmagiDDmxh · Pull Request #463 · paperboytm/spool · GitHub
Skip to content

feat(app): group Codex child sessions and resize sidebar - #463

Open
AmagiDDmxh wants to merge 1 commit into
paperboytm:mainfrom
AmagiDDmxh:feat/session-tree-resizable-sidebar
Open

feat(app): group Codex child sessions and resize sidebar#463
AmagiDDmxh wants to merge 1 commit into
paperboytm:mainfrom
AmagiDDmxh:feat/session-tree-resizable-sidebar

Conversation

@AmagiDDmxh

@AmagiDDmxhAmagiDDmxh commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • group Codex child sessions under their parent session in the desktop library instead of showing subagent runs as unrelated duplicate rows
  • add a persistent, resizable desktop sidebar with pointer, keyboard, and reset interactions
  • store Codex parent-session lineage in SQLite and reindex existing Codex sessions so the tree is populated for existing libraries

Why

Codex records subagent work as separate session files and links each child to its parent through parent_thread_id. Spool previously discarded that relationship, so parent and child sessions appeared as independent entries with similar titles and timestamps. This made the library look as if it contained duplicate sessions.

Preserving the lineage lets the desktop app present those records as a tree while keeping every child session individually accessible. The sidebar resize control also brings the desktop shell in line with the dimensions and behavior documented in DESIGN.md.

Implementation

  • add nullable parent_session_uuid storage and an index in schema migration v16
  • parse parent_thread_id in the shared session-kit Codex parser and propagate it through core session models and sync writes
  • bump the Codex index version to codex-v7-parent-session-tree so existing records are refreshed
  • page by root sessions, then load their descendants with a recursive CTE so children do not consume root pagination slots
  • build cycle-safe session forests in the renderer and render nested rows with expand/collapse controls
  • keep tree context in library, virtualized, and share-editor session lists
  • add a 200-360 px sidebar resize separator, persist the selected width, support arrow/Home/End keys, and reset to 240 px on double-click
  • update localized accessibility labels and the desktop layout guidance in DESIGN.md

Verification

  • pnpm exec vp run --no-cache -r build
  • pnpm typecheck
  • pnpm exec vp check
  • focused core parser, migration, query, and project-session tests: 40 passed
  • renderer session-tree and resize-handle tests: 3 passed
  • Electron E2E coverage for tree interaction and sidebar resize persistence: 2 passed

Known upstream test issue

The full pnpm test run reaches an existing failure in packages/session-view/src/build-output.test.ts. That test invokes pnpm exec vite build, but the current Vite+ workspace does not expose a vite binary (Command "vite" not found). The package's normal vp build path succeeds, including in the full no-cache build above.

@AmagiDDmxh
AmagiDDmxhforce-pushed the feat/session-tree-resizable-sidebar branch from ae2ed0a to 9dd13d5CompareJuly 18, 2026 18:49
@AmagiDDmxhAmagiDDmxh changed the title Feat/session tree resizable sidebarfeat(app): group Codex child sessions and resize sidebarJul 18, 2026
bet4it added a commit to bet4it/spool that referenced this pull request Aug 30, 2026
Cherry-pick of paperboytm#463, adapted for our repo layout
(packages/app instead of apps/app, schema v17 instead of v16, and
codex-v10 instead of codex-v7 to avoid version collisions).
Core changes:
- Add parentSessionUuid to ParsedSession and Session types
- Parse parent_thread_id from Codex session_meta records
- Store parent_session_uuid in SQLite (migration v17) with an index
- Page by root sessions in listRecentSessionsPage, then load
descendants via recursive CTE so children don't consume pagination
- Bump CODEX_INDEX_VERSION to codex-v10-parent-session-tree
Renderer changes:
- buildSessionForest creates cycle-safe trees from flat session lists
- SessionRow renders tree depth indentation, expand/collapse toggle,
and child-session count
- VirtualSessionList filters tree rows by ancestor expansion state
- LibraryLanding buckets root sessions only and appends child rows
within each bucket
- SidebarResizeHandle: pointer-drag + keyboard resize (200-360px),
persisted to localStorage, double-click resets to 240px
- AppTopBar and SidebarRail use dynamic width instead of w-60
- Sidebar receives and applies the width prop
- DESIGN.md updated for resizable sidebar spec
Tests: 508 core + 485 app pass (2 pre-existing security IPC failures
unrelated to this change).
bet4it added a commit to bet4it/spool that referenced this pull request Aug 30, 2026
The cherry-pick of paperboytm#463 only wired tree grouping into the Library
landing; ProjectView still rendered children as flat rows mixed with
their parents.
Core:
- listSessionsByIdentity now pages by root sessions and loads
descendants via recursive CTE for sortOrder=recent, reusing
executeRecentTreePage. A root filter is added so children don't
appear in both the root page and the descendants query (duplicates).
- Descendants re-apply identity/source filters: a source-filtered
family hides together instead of leaving dangling orphans.
- '' parent_session_uuid (codex writes empty string, not NULL) is
treated as a root. listRecentSessionsPage didn't need this, but the
new shared path makes the contract explicit.
Renderer:
- ProjectView builds a session forest from the page and nests children
under their parent (chevron expand, depth indentation, child count),
matching LibraryLanding. Directory grouping builds one forest per
cwd; filtered-out parents orphan their children into roots so they
stay visible.
E2e:
- New project-view-session-tree.spec.ts with codex parent/child
fixtures: collapse by default, expand shows indented children at
depth 1, child rows open their own detail.
- launchApp now isolates SPOOL_GROK_DIR/GROK_HOME — grok was syncing
the developer's real ~/.grok/sessions during e2e, which made the
end-of-list footer assertion flaky.
Tests: 513 core + 490 app unit + tree/project-view/pin e2e pass.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AmagiDDmxh
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(app): group Codex child sessions and resize sidebar by AmagiDDmxh · Pull Request #463 · paperboytm/spool · GitHub
Skip to content

feat(app): group Codex child sessions and resize sidebar - #463

Open
AmagiDDmxh wants to merge 1 commit into
paperboytm:mainfrom
AmagiDDmxh:feat/session-tree-resizable-sidebar
Open

feat(app): group Codex child sessions and resize sidebar#463
AmagiDDmxh wants to merge 1 commit into
paperboytm:mainfrom
AmagiDDmxh:feat/session-tree-resizable-sidebar

Conversation

@AmagiDDmxh

@AmagiDDmxhAmagiDDmxh commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • group Codex child sessions under their parent session in the desktop library instead of showing subagent runs as unrelated duplicate rows
  • add a persistent, resizable desktop sidebar with pointer, keyboard, and reset interactions
  • store Codex parent-session lineage in SQLite and reindex existing Codex sessions so the tree is populated for existing libraries

Why

Codex records subagent work as separate session files and links each child to its parent through parent_thread_id. Spool previously discarded that relationship, so parent and child sessions appeared as independent entries with similar titles and timestamps. This made the library look as if it contained duplicate sessions.

Preserving the lineage lets the desktop app present those records as a tree while keeping every child session individually accessible. The sidebar resize control also brings the desktop shell in line with the dimensions and behavior documented in DESIGN.md.

Implementation

  • add nullable parent_session_uuid storage and an index in schema migration v16
  • parse parent_thread_id in the shared session-kit Codex parser and propagate it through core session models and sync writes
  • bump the Codex index version to codex-v7-parent-session-tree so existing records are refreshed
  • page by root sessions, then load their descendants with a recursive CTE so children do not consume root pagination slots
  • build cycle-safe session forests in the renderer and render nested rows with expand/collapse controls
  • keep tree context in library, virtualized, and share-editor session lists
  • add a 200-360 px sidebar resize separator, persist the selected width, support arrow/Home/End keys, and reset to 240 px on double-click
  • update localized accessibility labels and the desktop layout guidance in DESIGN.md

Verification

  • pnpm exec vp run --no-cache -r build
  • pnpm typecheck
  • pnpm exec vp check
  • focused core parser, migration, query, and project-session tests: 40 passed
  • renderer session-tree and resize-handle tests: 3 passed
  • Electron E2E coverage for tree interaction and sidebar resize persistence: 2 passed

Known upstream test issue

The full pnpm test run reaches an existing failure in packages/session-view/src/build-output.test.ts. That test invokes pnpm exec vite build, but the current Vite+ workspace does not expose a vite binary (Command "vite" not found). The package's normal vp build path succeeds, including in the full no-cache build above.

@AmagiDDmxh
AmagiDDmxhforce-pushed the feat/session-tree-resizable-sidebar branch from ae2ed0a to 9dd13d5CompareJuly 18, 2026 18:49
@AmagiDDmxhAmagiDDmxh changed the title Feat/session tree resizable sidebarfeat(app): group Codex child sessions and resize sidebarJul 18, 2026
bet4it added a commit to bet4it/spool that referenced this pull request Aug 30, 2026
Cherry-pick of paperboytm#463, adapted for our repo layout
(packages/app instead of apps/app, schema v17 instead of v16, and
codex-v10 instead of codex-v7 to avoid version collisions).
Core changes:
- Add parentSessionUuid to ParsedSession and Session types
- Parse parent_thread_id from Codex session_meta records
- Store parent_session_uuid in SQLite (migration v17) with an index
- Page by root sessions in listRecentSessionsPage, then load
descendants via recursive CTE so children don't consume pagination
- Bump CODEX_INDEX_VERSION to codex-v10-parent-session-tree
Renderer changes:
- buildSessionForest creates cycle-safe trees from flat session lists
- SessionRow renders tree depth indentation, expand/collapse toggle,
and child-session count
- VirtualSessionList filters tree rows by ancestor expansion state
- LibraryLanding buckets root sessions only and appends child rows
within each bucket
- SidebarResizeHandle: pointer-drag + keyboard resize (200-360px),
persisted to localStorage, double-click resets to 240px
- AppTopBar and SidebarRail use dynamic width instead of w-60
- Sidebar receives and applies the width prop
- DESIGN.md updated for resizable sidebar spec
Tests: 508 core + 485 app pass (2 pre-existing security IPC failures
unrelated to this change).
bet4it added a commit to bet4it/spool that referenced this pull request Aug 30, 2026
The cherry-pick of paperboytm#463 only wired tree grouping into the Library
landing; ProjectView still rendered children as flat rows mixed with
their parents.
Core:
- listSessionsByIdentity now pages by root sessions and loads
descendants via recursive CTE for sortOrder=recent, reusing
executeRecentTreePage. A root filter is added so children don't
appear in both the root page and the descendants query (duplicates).
- Descendants re-apply identity/source filters: a source-filtered
family hides together instead of leaving dangling orphans.
- '' parent_session_uuid (codex writes empty string, not NULL) is
treated as a root. listRecentSessionsPage didn't need this, but the
new shared path makes the contract explicit.
Renderer:
- ProjectView builds a session forest from the page and nests children
under their parent (chevron expand, depth indentation, child count),
matching LibraryLanding. Directory grouping builds one forest per
cwd; filtered-out parents orphan their children into roots so they
stay visible.
E2e:
- New project-view-session-tree.spec.ts with codex parent/child
fixtures: collapse by default, expand shows indented children at
depth 1, child rows open their own detail.
- launchApp now isolates SPOOL_GROK_DIR/GROK_HOME — grok was syncing
the developer's real ~/.grok/sessions during e2e, which made the
end-of-list footer assertion flaky.
Tests: 513 core + 490 app unit + tree/project-view/pin e2e pass.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AmagiDDmxh
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(app): group Codex child sessions and resize sidebar by AmagiDDmxh · Pull Request #463 · paperboytm/spool · GitHub
Skip to content

feat(app): group Codex child sessions and resize sidebar - #463

Open
AmagiDDmxh wants to merge 1 commit into
paperboytm:mainfrom
AmagiDDmxh:feat/session-tree-resizable-sidebar
Open

feat(app): group Codex child sessions and resize sidebar#463
AmagiDDmxh wants to merge 1 commit into
paperboytm:mainfrom
AmagiDDmxh:feat/session-tree-resizable-sidebar

Conversation

@AmagiDDmxh

@AmagiDDmxhAmagiDDmxh commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • group Codex child sessions under their parent session in the desktop library instead of showing subagent runs as unrelated duplicate rows
  • add a persistent, resizable desktop sidebar with pointer, keyboard, and reset interactions
  • store Codex parent-session lineage in SQLite and reindex existing Codex sessions so the tree is populated for existing libraries

Why

Codex records subagent work as separate session files and links each child to its parent through parent_thread_id. Spool previously discarded that relationship, so parent and child sessions appeared as independent entries with similar titles and timestamps. This made the library look as if it contained duplicate sessions.

Preserving the lineage lets the desktop app present those records as a tree while keeping every child session individually accessible. The sidebar resize control also brings the desktop shell in line with the dimensions and behavior documented in DESIGN.md.

Implementation

  • add nullable parent_session_uuid storage and an index in schema migration v16
  • parse parent_thread_id in the shared session-kit Codex parser and propagate it through core session models and sync writes
  • bump the Codex index version to codex-v7-parent-session-tree so existing records are refreshed
  • page by root sessions, then load their descendants with a recursive CTE so children do not consume root pagination slots
  • build cycle-safe session forests in the renderer and render nested rows with expand/collapse controls
  • keep tree context in library, virtualized, and share-editor session lists
  • add a 200-360 px sidebar resize separator, persist the selected width, support arrow/Home/End keys, and reset to 240 px on double-click
  • update localized accessibility labels and the desktop layout guidance in DESIGN.md

Verification

  • pnpm exec vp run --no-cache -r build
  • pnpm typecheck
  • pnpm exec vp check
  • focused core parser, migration, query, and project-session tests: 40 passed
  • renderer session-tree and resize-handle tests: 3 passed
  • Electron E2E coverage for tree interaction and sidebar resize persistence: 2 passed

Known upstream test issue

The full pnpm test run reaches an existing failure in packages/session-view/src/build-output.test.ts. That test invokes pnpm exec vite build, but the current Vite+ workspace does not expose a vite binary (Command "vite" not found). The package's normal vp build path succeeds, including in the full no-cache build above.

@AmagiDDmxh
AmagiDDmxhforce-pushed the feat/session-tree-resizable-sidebar branch from ae2ed0a to 9dd13d5CompareJuly 18, 2026 18:49
@AmagiDDmxhAmagiDDmxh changed the title Feat/session tree resizable sidebarfeat(app): group Codex child sessions and resize sidebarJul 18, 2026
bet4it added a commit to bet4it/spool that referenced this pull request Aug 30, 2026
Cherry-pick of paperboytm#463, adapted for our repo layout
(packages/app instead of apps/app, schema v17 instead of v16, and
codex-v10 instead of codex-v7 to avoid version collisions).
Core changes:
- Add parentSessionUuid to ParsedSession and Session types
- Parse parent_thread_id from Codex session_meta records
- Store parent_session_uuid in SQLite (migration v17) with an index
- Page by root sessions in listRecentSessionsPage, then load
descendants via recursive CTE so children don't consume pagination
- Bump CODEX_INDEX_VERSION to codex-v10-parent-session-tree
Renderer changes:
- buildSessionForest creates cycle-safe trees from flat session lists
- SessionRow renders tree depth indentation, expand/collapse toggle,
and child-session count
- VirtualSessionList filters tree rows by ancestor expansion state
- LibraryLanding buckets root sessions only and appends child rows
within each bucket
- SidebarResizeHandle: pointer-drag + keyboard resize (200-360px),
persisted to localStorage, double-click resets to 240px
- AppTopBar and SidebarRail use dynamic width instead of w-60
- Sidebar receives and applies the width prop
- DESIGN.md updated for resizable sidebar spec
Tests: 508 core + 485 app pass (2 pre-existing security IPC failures
unrelated to this change).
bet4it added a commit to bet4it/spool that referenced this pull request Aug 30, 2026
The cherry-pick of paperboytm#463 only wired tree grouping into the Library
landing; ProjectView still rendered children as flat rows mixed with
their parents.
Core:
- listSessionsByIdentity now pages by root sessions and loads
descendants via recursive CTE for sortOrder=recent, reusing
executeRecentTreePage. A root filter is added so children don't
appear in both the root page and the descendants query (duplicates).
- Descendants re-apply identity/source filters: a source-filtered
family hides together instead of leaving dangling orphans.
- '' parent_session_uuid (codex writes empty string, not NULL) is
treated as a root. listRecentSessionsPage didn't need this, but the
new shared path makes the contract explicit.
Renderer:
- ProjectView builds a session forest from the page and nests children
under their parent (chevron expand, depth indentation, child count),
matching LibraryLanding. Directory grouping builds one forest per
cwd; filtered-out parents orphan their children into roots so they
stay visible.
E2e:
- New project-view-session-tree.spec.ts with codex parent/child
fixtures: collapse by default, expand shows indented children at
depth 1, child rows open their own detail.
- launchApp now isolates SPOOL_GROK_DIR/GROK_HOME — grok was syncing
the developer's real ~/.grok/sessions during e2e, which made the
end-of-list footer assertion flaky.
Tests: 513 core + 490 app unit + tree/project-view/pin e2e pass.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AmagiDDmxh
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); feat(app): group Codex child sessions and resize sidebar by AmagiDDmxh · Pull Request #463 · paperboytm/spool · GitHub
Skip to content

feat(app): group Codex child sessions and resize sidebar - #463

Open
AmagiDDmxh wants to merge 1 commit into
paperboytm:mainfrom
AmagiDDmxh:feat/session-tree-resizable-sidebar
Open

feat(app): group Codex child sessions and resize sidebar#463
AmagiDDmxh wants to merge 1 commit into
paperboytm:mainfrom
AmagiDDmxh:feat/session-tree-resizable-sidebar

Conversation

@AmagiDDmxh

@AmagiDDmxhAmagiDDmxh commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • group Codex child sessions under their parent session in the desktop library instead of showing subagent runs as unrelated duplicate rows
  • add a persistent, resizable desktop sidebar with pointer, keyboard, and reset interactions
  • store Codex parent-session lineage in SQLite and reindex existing Codex sessions so the tree is populated for existing libraries

Why

Codex records subagent work as separate session files and links each child to its parent through parent_thread_id. Spool previously discarded that relationship, so parent and child sessions appeared as independent entries with similar titles and timestamps. This made the library look as if it contained duplicate sessions.

Preserving the lineage lets the desktop app present those records as a tree while keeping every child session individually accessible. The sidebar resize control also brings the desktop shell in line with the dimensions and behavior documented in DESIGN.md.

Implementation

  • add nullable parent_session_uuid storage and an index in schema migration v16
  • parse parent_thread_id in the shared session-kit Codex parser and propagate it through core session models and sync writes
  • bump the Codex index version to codex-v7-parent-session-tree so existing records are refreshed
  • page by root sessions, then load their descendants with a recursive CTE so children do not consume root pagination slots
  • build cycle-safe session forests in the renderer and render nested rows with expand/collapse controls
  • keep tree context in library, virtualized, and share-editor session lists
  • add a 200-360 px sidebar resize separator, persist the selected width, support arrow/Home/End keys, and reset to 240 px on double-click
  • update localized accessibility labels and the desktop layout guidance in DESIGN.md

Verification

  • pnpm exec vp run --no-cache -r build
  • pnpm typecheck
  • pnpm exec vp check
  • focused core parser, migration, query, and project-session tests: 40 passed
  • renderer session-tree and resize-handle tests: 3 passed
  • Electron E2E coverage for tree interaction and sidebar resize persistence: 2 passed

Known upstream test issue

The full pnpm test run reaches an existing failure in packages/session-view/src/build-output.test.ts. That test invokes pnpm exec vite build, but the current Vite+ workspace does not expose a vite binary (Command "vite" not found). The package's normal vp build path succeeds, including in the full no-cache build above.

@AmagiDDmxh
AmagiDDmxhforce-pushed the feat/session-tree-resizable-sidebar branch from ae2ed0a to 9dd13d5CompareJuly 18, 2026 18:49
@AmagiDDmxhAmagiDDmxh changed the title Feat/session tree resizable sidebarfeat(app): group Codex child sessions and resize sidebarJul 18, 2026
bet4it added a commit to bet4it/spool that referenced this pull request Aug 30, 2026
Cherry-pick of paperboytm#463, adapted for our repo layout
(packages/app instead of apps/app, schema v17 instead of v16, and
codex-v10 instead of codex-v7 to avoid version collisions).
Core changes:
- Add parentSessionUuid to ParsedSession and Session types
- Parse parent_thread_id from Codex session_meta records
- Store parent_session_uuid in SQLite (migration v17) with an index
- Page by root sessions in listRecentSessionsPage, then load
descendants via recursive CTE so children don't consume pagination
- Bump CODEX_INDEX_VERSION to codex-v10-parent-session-tree
Renderer changes:
- buildSessionForest creates cycle-safe trees from flat session lists
- SessionRow renders tree depth indentation, expand/collapse toggle,
and child-session count
- VirtualSessionList filters tree rows by ancestor expansion state
- LibraryLanding buckets root sessions only and appends child rows
within each bucket
- SidebarResizeHandle: pointer-drag + keyboard resize (200-360px),
persisted to localStorage, double-click resets to 240px
- AppTopBar and SidebarRail use dynamic width instead of w-60
- Sidebar receives and applies the width prop
- DESIGN.md updated for resizable sidebar spec
Tests: 508 core + 485 app pass (2 pre-existing security IPC failures
unrelated to this change).
bet4it added a commit to bet4it/spool that referenced this pull request Aug 30, 2026
The cherry-pick of paperboytm#463 only wired tree grouping into the Library
landing; ProjectView still rendered children as flat rows mixed with
their parents.
Core:
- listSessionsByIdentity now pages by root sessions and loads
descendants via recursive CTE for sortOrder=recent, reusing
executeRecentTreePage. A root filter is added so children don't
appear in both the root page and the descendants query (duplicates).
- Descendants re-apply identity/source filters: a source-filtered
family hides together instead of leaving dangling orphans.
- '' parent_session_uuid (codex writes empty string, not NULL) is
treated as a root. listRecentSessionsPage didn't need this, but the
new shared path makes the contract explicit.
Renderer:
- ProjectView builds a session forest from the page and nests children
under their parent (chevron expand, depth indentation, child count),
matching LibraryLanding. Directory grouping builds one forest per
cwd; filtered-out parents orphan their children into roots so they
stay visible.
E2e:
- New project-view-session-tree.spec.ts with codex parent/child
fixtures: collapse by default, expand shows indented children at
depth 1, child rows open their own detail.
- launchApp now isolates SPOOL_GROK_DIR/GROK_HOME — grok was syncing
the developer's real ~/.grok/sessions during e2e, which made the
end-of-list footer assertion flaky.
Tests: 513 core + 490 app unit + tree/project-view/pin e2e pass.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AmagiDDmxh