Improve pull request flow, add branch selection for worktree creation, fix auto-mode concurrency count (#787)

* Changes from fix/fetch-before-pull-fetch

* feat: Improve pull request flow, add branch selection for worktree creation, fix for automode concurrency count

* feat: Add validation for remote names and improve error handling

* Address PR comments and mobile layout fixes

* ```
refactor: Extract PR target resolution logic into dedicated service
```

* feat: Add app shell UI and improve service imports. Address PR comments

* fix: Improve security validation and cache handling in git operations

* feat: Add GET /list endpoint and improve parameter handling

* chore: Improve validation, accessibility, and error handling across apps

* chore: Format vite server port configuration

* fix: Add error handling for gh pr list command and improve offline fallbacks

* fix: Preserve existing PR creation time and improve remote handling
This commit is contained in:
gsxdsm
2026-02-19 21:55:12 -08:00
committed by GitHub
parent ee52333636
commit 7df2182818
80 changed files with 4729 additions and 1107 deletions

View File

@@ -36,7 +36,7 @@ const buildHash = getBuildHash();
/**
* Vite plugin to inject the build hash into sw.js for cache busting.
*
* Problem: CACHE_NAME = 'automaker-v3' is hardcoded in the service worker.
* Problem: CACHE_NAME is hardcoded in the service worker.
* After a deployment, users may continue getting stale HTML from the SW cache
* if someone forgets to manually bump the version.
*
@@ -44,7 +44,10 @@ const buildHash = getBuildHash();
* SW cache is automatically invalidated on each deployment.
*/
function swCacheBuster(): Plugin {
const CACHE_NAME_PATTERN = /const CACHE_NAME = 'automaker-v3';/;
// Single constant for the cache name prefix — bump this when changing the SW cache version.
const CACHE_NAME_BASE = 'automaker-v5';
const CACHE_NAME_PATTERN = new RegExp(`const CACHE_NAME = '${CACHE_NAME_BASE}';`);
const CRITICAL_ASSETS_PATTERN = /const CRITICAL_ASSETS = \[\];/;
return {
name: 'sw-cache-buster',
// In build mode: copy sw.js to output with hash injected
@@ -56,21 +59,65 @@ function swCacheBuster(): Plugin {
console.warn('[sw-cache-buster] sw.js not found in dist/ — skipping cache bust');
return;
}
const swContent = fs.readFileSync(swPath, 'utf-8');
let swContent = fs.readFileSync(swPath, 'utf-8');
if (!CACHE_NAME_PATTERN.test(swContent)) {
console.error(
'[sw-cache-buster] Could not find CACHE_NAME declaration in sw.js. ' +
'The service worker cache will NOT be busted on this deploy! ' +
"Check that public/sw.js still contains: const CACHE_NAME = 'automaker-v3';"
`Check that public/sw.js still contains: const CACHE_NAME = '${CACHE_NAME_BASE}';`
);
return;
}
const updated = swContent.replace(
swContent = swContent.replace(
CACHE_NAME_PATTERN,
`const CACHE_NAME = 'automaker-v3-${buildHash}';`
`const CACHE_NAME = '${CACHE_NAME_BASE}-${buildHash}';`
);
fs.writeFileSync(swPath, updated, 'utf-8');
console.log(`[sw-cache-buster] Injected build hash: automaker-v3-${buildHash}`);
console.log(`[sw-cache-buster] Injected build hash: ${CACHE_NAME_BASE}-${buildHash}`);
// Extract critical asset URLs from the built index.html and inject them
// into the SW so it can precache them on install (not just after the main
// thread sends PRECACHE_ASSETS). This ensures the very first visit populates
// the immutable cache, so PWA cold starts after memory eviction serve from cache.
const indexHtmlPath = path.resolve(__dirname, 'dist', 'index.html');
if (fs.existsSync(indexHtmlPath)) {
if (!CRITICAL_ASSETS_PATTERN.test(swContent)) {
console.warn(
'[sw-cache-buster] CRITICAL_ASSETS placeholder not found in sw.js — ' +
'precaching of critical assets was not injected. ' +
'Check that public/sw.js still contains: const CRITICAL_ASSETS = [];'
);
} else {
const indexHtml = fs.readFileSync(indexHtmlPath, 'utf-8');
// Use a Set to deduplicate — assetRegex may match the same path in both href and src.
const criticalAssetsSet = new Set<string>();
// Extract hashed asset URLs from all link and script tags.
// These are the JS/CSS bundles Vite produces with content hashes.
// Match: href="./assets/..." or src="./assets/..."
const assetRegex = /(?:href|src)="(\.\/(assets\/[^"]+))"/g;
let match;
while ((match = assetRegex.exec(indexHtml)) !== null) {
const assetPath = '/' + match[2]; // Convert ./assets/... to /assets/...
// Only include JS and CSS — skip images, fonts, etc. to keep cache small
if (assetPath.endsWith('.js') || assetPath.endsWith('.css')) {
criticalAssetsSet.add(assetPath);
}
}
const criticalAssets = Array.from(criticalAssetsSet);
if (criticalAssets.length > 0) {
swContent = swContent.replace(
CRITICAL_ASSETS_PATTERN,
`const CRITICAL_ASSETS = ${JSON.stringify(criticalAssets)};`
);
console.log(
`[sw-cache-buster] Injected ${criticalAssets.length} critical assets for install-time precaching`
);
}
}
}
fs.writeFileSync(swPath, swContent, 'utf-8');
},
};
}
@@ -97,11 +144,16 @@ function mobilePreloadOptimizer(): Plugin {
// - vendor-xterm: /terminal route only
// - vendor-codemirror: spec/XML editor routes only
// - vendor-markdown: agent view, wiki, and other markdown-rendering routes
// - vendor-icons: lucide-react icons (587 KB) — not needed before React mounts.
// The !authChecked loading state uses a pure CSS spinner instead of a Lucide icon,
// so icons are not required until the authenticated UI renders (by which time this
// prefetch has usually completed on typical connections).
const deferredChunks = [
'vendor-reactflow',
'vendor-xterm',
'vendor-codemirror',
'vendor-markdown',
'vendor-icons',
];
return {
@@ -193,11 +245,11 @@ export default defineConfig(({ command }) => {
},
server: {
host: process.env.HOST || '0.0.0.0',
port: parseInt(process.env.TEST_PORT || '3007', 10),
port: parseInt(process.env.TEST_PORT || process.env.AUTOMAKER_WEB_PORT || '3007', 10),
allowedHosts: true,
proxy: {
'/api': {
target: 'http://localhost:3008',
target: 'http://localhost:' + (process.env.AUTOMAKER_SERVER_PORT ?? '5008'),
changeOrigin: true,
ws: true,
},