Skip to content

test(e2e): sandbox HOME and cover user-scope skill deletion - #1530

Merged
jackwener merged 1 commit into
mainfrom
claude/e2e-home-sandbox
Jul 27, 2026
Merged

test(e2e): sandbox HOME and cover user-scope skill deletion#1530
jackwener merged 1 commit into
mainfrom
claude/e2e-home-sandbox

Conversation

@jackwener

Copy link
Copy Markdown
Member

Why

#1517 let the Skills panel delete from ~/.maka/skills and ~/.agents/skills. buildE2eEnv never overrode HOME, so an E2E run enumerated the developer's real user-scope skills — and any spec that exercised the delete button would have removed one for real.

That is exactly why #1517 shipped without an e2e for its own destructive path. This closes that gap.

How

Set HOME (and USERPROFILE) to a directory inside the throwaway userData dir that teardown already removes — no second path to leak.

Overriding the home dir sandboxes every consumer at once, rather than threading a homeDir option through each skills API and hoping none is missed. That distinction matters here: if skills:list and skills:delete ever disagreed about which directories they mean, the bug would be both invisible and destructive.

userData is pinned separately via app.setPath, so this does not move the app's data dir.

e2eHomeDir(), not a fixture

The sandbox path is exposed as a plain accessor read from the test body. A fixture would have no declared dependency on the window fixture, so Playwright could resolve it before the window is set up and hand back a stale path.

New coverage

The invocable-skills seeder gains one user-scope skill under the sandbox, which is what makes the journey assertable. The spec covers what the unit tests in skills.test.ts cannot — the renderer sending a scope-aware ref through IPC, and the list agreeing afterwards:

  • a user-scope skill is removed from disk and drops out of the list — with the directory still intact after the first of the two confirm clicks, so a single stray click provably cannot delete;
  • a project-scope skill offers no delete button at all.

Verification

The disk assertion is not vacuous. Inverted it to expect 'present' after the delete; it fails with Received: "gone". (The original form used expect(promise).rejects, which I could not convince myself wasn't passing for the wrong reason — replaced with an explicit expect.poll.)

The sandbox introduces no new failures. Full e2e on this branch: 69 passed, 3 failed. All three baselined with the change stashed and the app rebuilt:

specwith sandboxstashed baseline
settings.spec.ts:141✘ pre-existing
sidebar-navigation.spec.ts:10✘ pre-existing
sidebar-navigation.spec.ts:30✓ flaky (flips both ways)

The first two fail identically without this change — local-environment issues on my machine, green in CI.

Gates: desktop test and typecheck exit 0 · format:check clean · knip --workspace apps/desktop clean.

#1517 let the Skills panel delete from `~/.maka/skills` and
`~/.agents/skills`. `buildE2eEnv` never overrode HOME, so an E2E run
enumerated the developer's real user-scope skills — and a spec that
exercised the delete button would have removed one of them for real. That
is why #1517 shipped without an e2e for its own destructive path.
Set HOME (and USERPROFILE) to a directory inside the throwaway userData dir
that teardown already removes. Overriding the home dir sandboxes every
consumer at once, rather than threading a `homeDir` option through each
skills API and hoping none is missed — if list and delete disagreed about
which directories they mean, the bug would be invisible and destructive.
userData is pinned separately via app.setPath, so this does not move the
app's data dir.
`e2eHomeDir()` exposes the sandbox to specs. It is a plain accessor read
from the test body, deliberately not a fixture: a fixture would have no
declared dependency on the window fixture, so Playwright could resolve it
first and hand back a stale path.
The invocable-skills seeder gains one user-scope skill under the sandbox,
which is what makes the journey assertable.
New spec covers what the unit tests cannot — the renderer sending a
scope-aware ref through IPC and the list agreeing afterwards:
- a user-scope skill is removed from disk and drops out of the list, with
the disk still intact after the FIRST of the two confirm clicks;
- a project-scope skill offers no delete button at all.
Verified the disk assertion is not vacuous: inverting it to expect
'present' fails with `Received: "gone"`.
Verified the sandbox introduces no new failures. Full e2e: 69 passed, 3
failed — `settings.spec.ts:141` and `sidebar-navigation.spec.ts:10` fail
identically with this change stashed (pre-existing on this machine, green
in CI), and `sidebar-navigation.spec.ts:30` is flaky, passing on the
stashed baseline in the same session.
Gates: desktop test + typecheck exit 0, format:check and knip clean.
@jackwener
jackwener merged commit 072094d into mainJul 27, 2026
3 checks passed
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

@jackwener
, '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" + '
test(e2e): sandbox HOME and cover user-scope skill deletion by jackwener · Pull Request #1530 · apache/maka · GitHub
Skip to content

test(e2e): sandbox HOME and cover user-scope skill deletion - #1530

Merged
jackwener merged 1 commit into
mainfrom
claude/e2e-home-sandbox
Jul 27, 2026
Merged

test(e2e): sandbox HOME and cover user-scope skill deletion#1530
jackwener merged 1 commit into
mainfrom
claude/e2e-home-sandbox

Conversation

@jackwener

Copy link
Copy Markdown
Member

Why

#1517 let the Skills panel delete from ~/.maka/skills and ~/.agents/skills. buildE2eEnv never overrode HOME, so an E2E run enumerated the developer's real user-scope skills — and any spec that exercised the delete button would have removed one for real.

That is exactly why #1517 shipped without an e2e for its own destructive path. This closes that gap.

How

Set HOME (and USERPROFILE) to a directory inside the throwaway userData dir that teardown already removes — no second path to leak.

Overriding the home dir sandboxes every consumer at once, rather than threading a homeDir option through each skills API and hoping none is missed. That distinction matters here: if skills:list and skills:delete ever disagreed about which directories they mean, the bug would be both invisible and destructive.

userData is pinned separately via app.setPath, so this does not move the app's data dir.

e2eHomeDir(), not a fixture

The sandbox path is exposed as a plain accessor read from the test body. A fixture would have no declared dependency on the window fixture, so Playwright could resolve it before the window is set up and hand back a stale path.

New coverage

The invocable-skills seeder gains one user-scope skill under the sandbox, which is what makes the journey assertable. The spec covers what the unit tests in skills.test.ts cannot — the renderer sending a scope-aware ref through IPC, and the list agreeing afterwards:

  • a user-scope skill is removed from disk and drops out of the list — with the directory still intact after the first of the two confirm clicks, so a single stray click provably cannot delete;
  • a project-scope skill offers no delete button at all.

Verification

The disk assertion is not vacuous. Inverted it to expect 'present' after the delete; it fails with Received: "gone". (The original form used expect(promise).rejects, which I could not convince myself wasn't passing for the wrong reason — replaced with an explicit expect.poll.)

The sandbox introduces no new failures. Full e2e on this branch: 69 passed, 3 failed. All three baselined with the change stashed and the app rebuilt:

specwith sandboxstashed baseline
settings.spec.ts:141✘ pre-existing
sidebar-navigation.spec.ts:10✘ pre-existing
sidebar-navigation.spec.ts:30✓ flaky (flips both ways)

The first two fail identically without this change — local-environment issues on my machine, green in CI.

Gates: desktop test and typecheck exit 0 · format:check clean · knip --workspace apps/desktop clean.

#1517 let the Skills panel delete from `~/.maka/skills` and
`~/.agents/skills`. `buildE2eEnv` never overrode HOME, so an E2E run
enumerated the developer's real user-scope skills — and a spec that
exercised the delete button would have removed one of them for real. That
is why #1517 shipped without an e2e for its own destructive path.
Set HOME (and USERPROFILE) to a directory inside the throwaway userData dir
that teardown already removes. Overriding the home dir sandboxes every
consumer at once, rather than threading a `homeDir` option through each
skills API and hoping none is missed — if list and delete disagreed about
which directories they mean, the bug would be invisible and destructive.
userData is pinned separately via app.setPath, so this does not move the
app's data dir.
`e2eHomeDir()` exposes the sandbox to specs. It is a plain accessor read
from the test body, deliberately not a fixture: a fixture would have no
declared dependency on the window fixture, so Playwright could resolve it
first and hand back a stale path.
The invocable-skills seeder gains one user-scope skill under the sandbox,
which is what makes the journey assertable.
New spec covers what the unit tests cannot — the renderer sending a
scope-aware ref through IPC and the list agreeing afterwards:
- a user-scope skill is removed from disk and drops out of the list, with
the disk still intact after the FIRST of the two confirm clicks;
- a project-scope skill offers no delete button at all.
Verified the disk assertion is not vacuous: inverting it to expect
'present' fails with `Received: "gone"`.
Verified the sandbox introduces no new failures. Full e2e: 69 passed, 3
failed — `settings.spec.ts:141` and `sidebar-navigation.spec.ts:10` fail
identically with this change stashed (pre-existing on this machine, green
in CI), and `sidebar-navigation.spec.ts:30` is flaky, passing on the
stashed baseline in the same session.
Gates: desktop test + typecheck exit 0, format:check and knip clean.
@jackwener
jackwener merged commit 072094d into mainJul 27, 2026
3 checks passed
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

@jackwener
, '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('^' + ".*" + ' test(e2e): sandbox HOME and cover user-scope skill deletion by jackwener · Pull Request #1530 · apache/maka · GitHub
Skip to content

test(e2e): sandbox HOME and cover user-scope skill deletion - #1530

Merged
jackwener merged 1 commit into
mainfrom
claude/e2e-home-sandbox
Jul 27, 2026
Merged

test(e2e): sandbox HOME and cover user-scope skill deletion#1530
jackwener merged 1 commit into
mainfrom
claude/e2e-home-sandbox

Conversation

@jackwener

Copy link
Copy Markdown
Member

Why

#1517 let the Skills panel delete from ~/.maka/skills and ~/.agents/skills. buildE2eEnv never overrode HOME, so an E2E run enumerated the developer's real user-scope skills — and any spec that exercised the delete button would have removed one for real.

That is exactly why #1517 shipped without an e2e for its own destructive path. This closes that gap.

How

Set HOME (and USERPROFILE) to a directory inside the throwaway userData dir that teardown already removes — no second path to leak.

Overriding the home dir sandboxes every consumer at once, rather than threading a homeDir option through each skills API and hoping none is missed. That distinction matters here: if skills:list and skills:delete ever disagreed about which directories they mean, the bug would be both invisible and destructive.

userData is pinned separately via app.setPath, so this does not move the app's data dir.

e2eHomeDir(), not a fixture

The sandbox path is exposed as a plain accessor read from the test body. A fixture would have no declared dependency on the window fixture, so Playwright could resolve it before the window is set up and hand back a stale path.

New coverage

The invocable-skills seeder gains one user-scope skill under the sandbox, which is what makes the journey assertable. The spec covers what the unit tests in skills.test.ts cannot — the renderer sending a scope-aware ref through IPC, and the list agreeing afterwards:

  • a user-scope skill is removed from disk and drops out of the list — with the directory still intact after the first of the two confirm clicks, so a single stray click provably cannot delete;
  • a project-scope skill offers no delete button at all.

Verification

The disk assertion is not vacuous. Inverted it to expect 'present' after the delete; it fails with Received: "gone". (The original form used expect(promise).rejects, which I could not convince myself wasn't passing for the wrong reason — replaced with an explicit expect.poll.)

The sandbox introduces no new failures. Full e2e on this branch: 69 passed, 3 failed. All three baselined with the change stashed and the app rebuilt:

specwith sandboxstashed baseline
settings.spec.ts:141✘ pre-existing
sidebar-navigation.spec.ts:10✘ pre-existing
sidebar-navigation.spec.ts:30✓ flaky (flips both ways)

The first two fail identically without this change — local-environment issues on my machine, green in CI.

Gates: desktop test and typecheck exit 0 · format:check clean · knip --workspace apps/desktop clean.

#1517 let the Skills panel delete from `~/.maka/skills` and
`~/.agents/skills`. `buildE2eEnv` never overrode HOME, so an E2E run
enumerated the developer's real user-scope skills — and a spec that
exercised the delete button would have removed one of them for real. That
is why #1517 shipped without an e2e for its own destructive path.
Set HOME (and USERPROFILE) to a directory inside the throwaway userData dir
that teardown already removes. Overriding the home dir sandboxes every
consumer at once, rather than threading a `homeDir` option through each
skills API and hoping none is missed — if list and delete disagreed about
which directories they mean, the bug would be invisible and destructive.
userData is pinned separately via app.setPath, so this does not move the
app's data dir.
`e2eHomeDir()` exposes the sandbox to specs. It is a plain accessor read
from the test body, deliberately not a fixture: a fixture would have no
declared dependency on the window fixture, so Playwright could resolve it
first and hand back a stale path.
The invocable-skills seeder gains one user-scope skill under the sandbox,
which is what makes the journey assertable.
New spec covers what the unit tests cannot — the renderer sending a
scope-aware ref through IPC and the list agreeing afterwards:
- a user-scope skill is removed from disk and drops out of the list, with
the disk still intact after the FIRST of the two confirm clicks;
- a project-scope skill offers no delete button at all.
Verified the disk assertion is not vacuous: inverting it to expect
'present' fails with `Received: "gone"`.
Verified the sandbox introduces no new failures. Full e2e: 69 passed, 3
failed — `settings.spec.ts:141` and `sidebar-navigation.spec.ts:10` fail
identically with this change stashed (pre-existing on this machine, green
in CI), and `sidebar-navigation.spec.ts:30` is flaky, passing on the
stashed baseline in the same session.
Gates: desktop test + typecheck exit 0, format:check and knip clean.
@jackwener
jackwener merged commit 072094d into mainJul 27, 2026
3 checks passed
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

@jackwener
, '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('^' + ".*" + ' test(e2e): sandbox HOME and cover user-scope skill deletion by jackwener · Pull Request #1530 · apache/maka · GitHub
Skip to content

test(e2e): sandbox HOME and cover user-scope skill deletion - #1530

Merged
jackwener merged 1 commit into
mainfrom
claude/e2e-home-sandbox
Jul 27, 2026
Merged

test(e2e): sandbox HOME and cover user-scope skill deletion#1530
jackwener merged 1 commit into
mainfrom
claude/e2e-home-sandbox

Conversation

@jackwener

Copy link
Copy Markdown
Member

Why

#1517 let the Skills panel delete from ~/.maka/skills and ~/.agents/skills. buildE2eEnv never overrode HOME, so an E2E run enumerated the developer's real user-scope skills — and any spec that exercised the delete button would have removed one for real.

That is exactly why #1517 shipped without an e2e for its own destructive path. This closes that gap.

How

Set HOME (and USERPROFILE) to a directory inside the throwaway userData dir that teardown already removes — no second path to leak.

Overriding the home dir sandboxes every consumer at once, rather than threading a homeDir option through each skills API and hoping none is missed. That distinction matters here: if skills:list and skills:delete ever disagreed about which directories they mean, the bug would be both invisible and destructive.

userData is pinned separately via app.setPath, so this does not move the app's data dir.

e2eHomeDir(), not a fixture

The sandbox path is exposed as a plain accessor read from the test body. A fixture would have no declared dependency on the window fixture, so Playwright could resolve it before the window is set up and hand back a stale path.

New coverage

The invocable-skills seeder gains one user-scope skill under the sandbox, which is what makes the journey assertable. The spec covers what the unit tests in skills.test.ts cannot — the renderer sending a scope-aware ref through IPC, and the list agreeing afterwards:

  • a user-scope skill is removed from disk and drops out of the list — with the directory still intact after the first of the two confirm clicks, so a single stray click provably cannot delete;
  • a project-scope skill offers no delete button at all.

Verification

The disk assertion is not vacuous. Inverted it to expect 'present' after the delete; it fails with Received: "gone". (The original form used expect(promise).rejects, which I could not convince myself wasn't passing for the wrong reason — replaced with an explicit expect.poll.)

The sandbox introduces no new failures. Full e2e on this branch: 69 passed, 3 failed. All three baselined with the change stashed and the app rebuilt:

specwith sandboxstashed baseline
settings.spec.ts:141✘ pre-existing
sidebar-navigation.spec.ts:10✘ pre-existing
sidebar-navigation.spec.ts:30✓ flaky (flips both ways)

The first two fail identically without this change — local-environment issues on my machine, green in CI.

Gates: desktop test and typecheck exit 0 · format:check clean · knip --workspace apps/desktop clean.

#1517 let the Skills panel delete from `~/.maka/skills` and
`~/.agents/skills`. `buildE2eEnv` never overrode HOME, so an E2E run
enumerated the developer's real user-scope skills — and a spec that
exercised the delete button would have removed one of them for real. That
is why #1517 shipped without an e2e for its own destructive path.
Set HOME (and USERPROFILE) to a directory inside the throwaway userData dir
that teardown already removes. Overriding the home dir sandboxes every
consumer at once, rather than threading a `homeDir` option through each
skills API and hoping none is missed — if list and delete disagreed about
which directories they mean, the bug would be invisible and destructive.
userData is pinned separately via app.setPath, so this does not move the
app's data dir.
`e2eHomeDir()` exposes the sandbox to specs. It is a plain accessor read
from the test body, deliberately not a fixture: a fixture would have no
declared dependency on the window fixture, so Playwright could resolve it
first and hand back a stale path.
The invocable-skills seeder gains one user-scope skill under the sandbox,
which is what makes the journey assertable.
New spec covers what the unit tests cannot — the renderer sending a
scope-aware ref through IPC and the list agreeing afterwards:
- a user-scope skill is removed from disk and drops out of the list, with
the disk still intact after the FIRST of the two confirm clicks;
- a project-scope skill offers no delete button at all.
Verified the disk assertion is not vacuous: inverting it to expect
'present' fails with `Received: "gone"`.
Verified the sandbox introduces no new failures. Full e2e: 69 passed, 3
failed — `settings.spec.ts:141` and `sidebar-navigation.spec.ts:10` fail
identically with this change stashed (pre-existing on this machine, green
in CI), and `sidebar-navigation.spec.ts:30` is flaky, passing on the
stashed baseline in the same session.
Gates: desktop test + typecheck exit 0, format:check and knip clean.
@jackwener
jackwener merged commit 072094d into mainJul 27, 2026
3 checks passed
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

@jackwener
, '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" + ' test(e2e): sandbox HOME and cover user-scope skill deletion by jackwener · Pull Request #1530 · apache/maka · GitHub
Skip to content

test(e2e): sandbox HOME and cover user-scope skill deletion - #1530

Merged
jackwener merged 1 commit into
mainfrom
claude/e2e-home-sandbox
Jul 27, 2026
Merged

test(e2e): sandbox HOME and cover user-scope skill deletion#1530
jackwener merged 1 commit into
mainfrom
claude/e2e-home-sandbox

Conversation

@jackwener

Copy link
Copy Markdown
Member

Why

#1517 let the Skills panel delete from ~/.maka/skills and ~/.agents/skills. buildE2eEnv never overrode HOME, so an E2E run enumerated the developer's real user-scope skills — and any spec that exercised the delete button would have removed one for real.

That is exactly why #1517 shipped without an e2e for its own destructive path. This closes that gap.

How

Set HOME (and USERPROFILE) to a directory inside the throwaway userData dir that teardown already removes — no second path to leak.

Overriding the home dir sandboxes every consumer at once, rather than threading a homeDir option through each skills API and hoping none is missed. That distinction matters here: if skills:list and skills:delete ever disagreed about which directories they mean, the bug would be both invisible and destructive.

userData is pinned separately via app.setPath, so this does not move the app's data dir.

e2eHomeDir(), not a fixture

The sandbox path is exposed as a plain accessor read from the test body. A fixture would have no declared dependency on the window fixture, so Playwright could resolve it before the window is set up and hand back a stale path.

New coverage

The invocable-skills seeder gains one user-scope skill under the sandbox, which is what makes the journey assertable. The spec covers what the unit tests in skills.test.ts cannot — the renderer sending a scope-aware ref through IPC, and the list agreeing afterwards:

  • a user-scope skill is removed from disk and drops out of the list — with the directory still intact after the first of the two confirm clicks, so a single stray click provably cannot delete;
  • a project-scope skill offers no delete button at all.

Verification

The disk assertion is not vacuous. Inverted it to expect 'present' after the delete; it fails with Received: "gone". (The original form used expect(promise).rejects, which I could not convince myself wasn't passing for the wrong reason — replaced with an explicit expect.poll.)

The sandbox introduces no new failures. Full e2e on this branch: 69 passed, 3 failed. All three baselined with the change stashed and the app rebuilt:

specwith sandboxstashed baseline
settings.spec.ts:141✘ pre-existing
sidebar-navigation.spec.ts:10✘ pre-existing
sidebar-navigation.spec.ts:30✓ flaky (flips both ways)

The first two fail identically without this change — local-environment issues on my machine, green in CI.

Gates: desktop test and typecheck exit 0 · format:check clean · knip --workspace apps/desktop clean.

#1517 let the Skills panel delete from `~/.maka/skills` and
`~/.agents/skills`. `buildE2eEnv` never overrode HOME, so an E2E run
enumerated the developer's real user-scope skills — and a spec that
exercised the delete button would have removed one of them for real. That
is why #1517 shipped without an e2e for its own destructive path.
Set HOME (and USERPROFILE) to a directory inside the throwaway userData dir
that teardown already removes. Overriding the home dir sandboxes every
consumer at once, rather than threading a `homeDir` option through each
skills API and hoping none is missed — if list and delete disagreed about
which directories they mean, the bug would be invisible and destructive.
userData is pinned separately via app.setPath, so this does not move the
app's data dir.
`e2eHomeDir()` exposes the sandbox to specs. It is a plain accessor read
from the test body, deliberately not a fixture: a fixture would have no
declared dependency on the window fixture, so Playwright could resolve it
first and hand back a stale path.
The invocable-skills seeder gains one user-scope skill under the sandbox,
which is what makes the journey assertable.
New spec covers what the unit tests cannot — the renderer sending a
scope-aware ref through IPC and the list agreeing afterwards:
- a user-scope skill is removed from disk and drops out of the list, with
the disk still intact after the FIRST of the two confirm clicks;
- a project-scope skill offers no delete button at all.
Verified the disk assertion is not vacuous: inverting it to expect
'present' fails with `Received: "gone"`.
Verified the sandbox introduces no new failures. Full e2e: 69 passed, 3
failed — `settings.spec.ts:141` and `sidebar-navigation.spec.ts:10` fail
identically with this change stashed (pre-existing on this machine, green
in CI), and `sidebar-navigation.spec.ts:30` is flaky, passing on the
stashed baseline in the same session.
Gates: desktop test + typecheck exit 0, format:check and knip clean.
@jackwener
jackwener merged commit 072094d into mainJul 27, 2026
3 checks passed
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

@jackwener
, '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('^' + ".*" + ' test(e2e): sandbox HOME and cover user-scope skill deletion by jackwener · Pull Request #1530 · apache/maka · GitHub
Skip to content

test(e2e): sandbox HOME and cover user-scope skill deletion - #1530

Merged
jackwener merged 1 commit into
mainfrom
claude/e2e-home-sandbox
Jul 27, 2026
Merged

test(e2e): sandbox HOME and cover user-scope skill deletion#1530
jackwener merged 1 commit into
mainfrom
claude/e2e-home-sandbox

Conversation

@jackwener

Copy link
Copy Markdown
Member

Why

#1517 let the Skills panel delete from ~/.maka/skills and ~/.agents/skills. buildE2eEnv never overrode HOME, so an E2E run enumerated the developer's real user-scope skills — and any spec that exercised the delete button would have removed one for real.

That is exactly why #1517 shipped without an e2e for its own destructive path. This closes that gap.

How

Set HOME (and USERPROFILE) to a directory inside the throwaway userData dir that teardown already removes — no second path to leak.

Overriding the home dir sandboxes every consumer at once, rather than threading a homeDir option through each skills API and hoping none is missed. That distinction matters here: if skills:list and skills:delete ever disagreed about which directories they mean, the bug would be both invisible and destructive.

userData is pinned separately via app.setPath, so this does not move the app's data dir.

e2eHomeDir(), not a fixture

The sandbox path is exposed as a plain accessor read from the test body. A fixture would have no declared dependency on the window fixture, so Playwright could resolve it before the window is set up and hand back a stale path.

New coverage

The invocable-skills seeder gains one user-scope skill under the sandbox, which is what makes the journey assertable. The spec covers what the unit tests in skills.test.ts cannot — the renderer sending a scope-aware ref through IPC, and the list agreeing afterwards:

  • a user-scope skill is removed from disk and drops out of the list — with the directory still intact after the first of the two confirm clicks, so a single stray click provably cannot delete;
  • a project-scope skill offers no delete button at all.

Verification

The disk assertion is not vacuous. Inverted it to expect 'present' after the delete; it fails with Received: "gone". (The original form used expect(promise).rejects, which I could not convince myself wasn't passing for the wrong reason — replaced with an explicit expect.poll.)

The sandbox introduces no new failures. Full e2e on this branch: 69 passed, 3 failed. All three baselined with the change stashed and the app rebuilt:

specwith sandboxstashed baseline
settings.spec.ts:141✘ pre-existing
sidebar-navigation.spec.ts:10✘ pre-existing
sidebar-navigation.spec.ts:30✓ flaky (flips both ways)

The first two fail identically without this change — local-environment issues on my machine, green in CI.

Gates: desktop test and typecheck exit 0 · format:check clean · knip --workspace apps/desktop clean.

#1517 let the Skills panel delete from `~/.maka/skills` and
`~/.agents/skills`. `buildE2eEnv` never overrode HOME, so an E2E run
enumerated the developer's real user-scope skills — and a spec that
exercised the delete button would have removed one of them for real. That
is why #1517 shipped without an e2e for its own destructive path.
Set HOME (and USERPROFILE) to a directory inside the throwaway userData dir
that teardown already removes. Overriding the home dir sandboxes every
consumer at once, rather than threading a `homeDir` option through each
skills API and hoping none is missed — if list and delete disagreed about
which directories they mean, the bug would be invisible and destructive.
userData is pinned separately via app.setPath, so this does not move the
app's data dir.
`e2eHomeDir()` exposes the sandbox to specs. It is a plain accessor read
from the test body, deliberately not a fixture: a fixture would have no
declared dependency on the window fixture, so Playwright could resolve it
first and hand back a stale path.
The invocable-skills seeder gains one user-scope skill under the sandbox,
which is what makes the journey assertable.
New spec covers what the unit tests cannot — the renderer sending a
scope-aware ref through IPC and the list agreeing afterwards:
- a user-scope skill is removed from disk and drops out of the list, with
the disk still intact after the FIRST of the two confirm clicks;
- a project-scope skill offers no delete button at all.
Verified the disk assertion is not vacuous: inverting it to expect
'present' fails with `Received: "gone"`.
Verified the sandbox introduces no new failures. Full e2e: 69 passed, 3
failed — `settings.spec.ts:141` and `sidebar-navigation.spec.ts:10` fail
identically with this change stashed (pre-existing on this machine, green
in CI), and `sidebar-navigation.spec.ts:30` is flaky, passing on the
stashed baseline in the same session.
Gates: desktop test + typecheck exit 0, format:check and knip clean.
@jackwener
jackwener merged commit 072094d into mainJul 27, 2026
3 checks passed
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

@jackwener
, '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); } })(); })(); test(e2e): sandbox HOME and cover user-scope skill deletion by jackwener · Pull Request #1530 · apache/maka · GitHub
Skip to content

test(e2e): sandbox HOME and cover user-scope skill deletion - #1530

Merged
jackwener merged 1 commit into
mainfrom
claude/e2e-home-sandbox
Jul 27, 2026
Merged

test(e2e): sandbox HOME and cover user-scope skill deletion#1530
jackwener merged 1 commit into
mainfrom
claude/e2e-home-sandbox

Conversation

@jackwener

Copy link
Copy Markdown
Member

Why

#1517 let the Skills panel delete from ~/.maka/skills and ~/.agents/skills. buildE2eEnv never overrode HOME, so an E2E run enumerated the developer's real user-scope skills — and any spec that exercised the delete button would have removed one for real.

That is exactly why #1517 shipped without an e2e for its own destructive path. This closes that gap.

How

Set HOME (and USERPROFILE) to a directory inside the throwaway userData dir that teardown already removes — no second path to leak.

Overriding the home dir sandboxes every consumer at once, rather than threading a homeDir option through each skills API and hoping none is missed. That distinction matters here: if skills:list and skills:delete ever disagreed about which directories they mean, the bug would be both invisible and destructive.

userData is pinned separately via app.setPath, so this does not move the app's data dir.

e2eHomeDir(), not a fixture

The sandbox path is exposed as a plain accessor read from the test body. A fixture would have no declared dependency on the window fixture, so Playwright could resolve it before the window is set up and hand back a stale path.

New coverage

The invocable-skills seeder gains one user-scope skill under the sandbox, which is what makes the journey assertable. The spec covers what the unit tests in skills.test.ts cannot — the renderer sending a scope-aware ref through IPC, and the list agreeing afterwards:

  • a user-scope skill is removed from disk and drops out of the list — with the directory still intact after the first of the two confirm clicks, so a single stray click provably cannot delete;
  • a project-scope skill offers no delete button at all.

Verification

The disk assertion is not vacuous. Inverted it to expect 'present' after the delete; it fails with Received: "gone". (The original form used expect(promise).rejects, which I could not convince myself wasn't passing for the wrong reason — replaced with an explicit expect.poll.)

The sandbox introduces no new failures. Full e2e on this branch: 69 passed, 3 failed. All three baselined with the change stashed and the app rebuilt:

specwith sandboxstashed baseline
settings.spec.ts:141✘ pre-existing
sidebar-navigation.spec.ts:10✘ pre-existing
sidebar-navigation.spec.ts:30✓ flaky (flips both ways)

The first two fail identically without this change — local-environment issues on my machine, green in CI.

Gates: desktop test and typecheck exit 0 · format:check clean · knip --workspace apps/desktop clean.

#1517 let the Skills panel delete from `~/.maka/skills` and
`~/.agents/skills`. `buildE2eEnv` never overrode HOME, so an E2E run
enumerated the developer's real user-scope skills — and a spec that
exercised the delete button would have removed one of them for real. That
is why #1517 shipped without an e2e for its own destructive path.
Set HOME (and USERPROFILE) to a directory inside the throwaway userData dir
that teardown already removes. Overriding the home dir sandboxes every
consumer at once, rather than threading a `homeDir` option through each
skills API and hoping none is missed — if list and delete disagreed about
which directories they mean, the bug would be invisible and destructive.
userData is pinned separately via app.setPath, so this does not move the
app's data dir.
`e2eHomeDir()` exposes the sandbox to specs. It is a plain accessor read
from the test body, deliberately not a fixture: a fixture would have no
declared dependency on the window fixture, so Playwright could resolve it
first and hand back a stale path.
The invocable-skills seeder gains one user-scope skill under the sandbox,
which is what makes the journey assertable.
New spec covers what the unit tests cannot — the renderer sending a
scope-aware ref through IPC and the list agreeing afterwards:
- a user-scope skill is removed from disk and drops out of the list, with
the disk still intact after the FIRST of the two confirm clicks;
- a project-scope skill offers no delete button at all.
Verified the disk assertion is not vacuous: inverting it to expect
'present' fails with `Received: "gone"`.
Verified the sandbox introduces no new failures. Full e2e: 69 passed, 3
failed — `settings.spec.ts:141` and `sidebar-navigation.spec.ts:10` fail
identically with this change stashed (pre-existing on this machine, green
in CI), and `sidebar-navigation.spec.ts:30` is flaky, passing on the
stashed baseline in the same session.
Gates: desktop test + typecheck exit 0, format:check and knip clean.
@jackwener
jackwener merged commit 072094d into mainJul 27, 2026
3 checks passed
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

@jackwener