mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-09 08:59:40 +02:00
fix(cases): custom-folder create landing fixes (#535)
- Route test hygiene: each test works in its own mkdtemp folder, every deletion goes through safeRmHomeTree, and the suite refuses to start outside test/setup.ts's temp HOME, so a raw `npx vitest` can no longer delete a real ~/projects or the live linked-cases registry. - Path policy: the symlink-resolved target is also judged against the resolved home, data dir and system roots (home reached through a link, macOS /etc -> /private/etc); test expectations are realpath-safe. - Refuse a target equal to or inside the caller's or the shared cases directory, pointing at plain Create New (it would list twice, and deleting the local copy removes files). - The registry re-read comment no longer claims to prevent the lost-update race; documented as narrowing it, like /api/cases/link. - UI: the success toast names the folder the server created, the "under ~/codeman-cases" blurb and name hint change while a custom folder is ticked, a "/" parent previews and sends /<name> instead of an empty path, and the new labels have zh-CN entries. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3356,6 +3356,19 @@ Object.assign(CodemanApp.prototype, {
|
||||
const row = document.getElementById('newCaseCustomPathRow');
|
||||
if (!custom || !row) return;
|
||||
row.style.display = custom.checked ? '' : 'none';
|
||||
// The "under ~/codeman-cases" wording is wrong while a custom folder is picked.
|
||||
const blurb = document.getElementById('newCaseBlurb');
|
||||
if (blurb) {
|
||||
blurb.textContent = custom.checked
|
||||
? 'A fresh workspace in a folder you choose, scaffolded with its own CLAUDE.md.'
|
||||
: 'A fresh workspace under ~/codeman-cases, scaffolded with its own CLAUDE.md.';
|
||||
}
|
||||
const nameHint = document.getElementById('newCaseNameHint');
|
||||
if (nameHint) {
|
||||
nameHint.textContent = custom.checked
|
||||
? 'Letters, numbers, hyphens, underscores only. Created inside the parent folder below.'
|
||||
: 'Letters, numbers, hyphens, underscores only. Created in ~/codeman-cases/';
|
||||
}
|
||||
custom.disabled = !!docker?.checked;
|
||||
custom.title = docker?.checked ? 'Not available for a Docker case' : '';
|
||||
if (docker) {
|
||||
@@ -3367,9 +3380,12 @@ Object.assign(CodemanApp.prototype, {
|
||||
|
||||
/** The folder the case would be created in: the parent field plus the case name. */
|
||||
_newCaseTargetPath() {
|
||||
const parent = (document.getElementById('newCasePath')?.value || '').trim().replace(/\/+$/, '');
|
||||
const rawParent = (document.getElementById('newCasePath')?.value || '').trim();
|
||||
const name = (document.getElementById('newCaseName')?.value || '').trim();
|
||||
return parent && name ? `${parent}/${name}` : '';
|
||||
if (!rawParent || !name) return '';
|
||||
// Trailing slashes off, but `/` stays the root rather than becoming an empty path.
|
||||
const parent = rawParent.replace(/\/+$/, '');
|
||||
return `${parent}/${name}`;
|
||||
},
|
||||
|
||||
updateNewCasePathPreview() {
|
||||
@@ -3443,7 +3459,9 @@ Object.assign(CodemanApp.prototype, {
|
||||
// Start a session INSIDE the container (routes through quick-start).
|
||||
await this.runClaude();
|
||||
} else {
|
||||
this.showToast(customFolder ? `Case "${name}" created in ${payload.path}` : `Case "${name}" created`, 'success');
|
||||
// The server's path is the folder actually created (~ expanded, symlinks resolved).
|
||||
const createdIn = data.data?.case?.path || payload.path;
|
||||
this.showToast(customFolder ? `Case "${name}" created in ${createdIn}` : `Case "${name}" created`, 'success');
|
||||
}
|
||||
} else {
|
||||
this.showToast(data.error || 'Failed to create case', 'error');
|
||||
|
||||
Reference in New Issue
Block a user