Merge remote-tracking branch 'origin/main' into garrytan/learn-from-reviews

# Conflicts:
#	SKILL.md
#	autoplan/SKILL.md
#	benchmark/SKILL.md
#	browse/SKILL.md
#	canary/SKILL.md
#	codex/SKILL.md
#	connect-chrome/SKILL.md
#	cso/SKILL.md
#	design-consultation/SKILL.md
#	design-review/SKILL.md
#	design-shotgun/SKILL.md
#	document-release/SKILL.md
#	investigate/SKILL.md
#	land-and-deploy/SKILL.md
#	learn/SKILL.md
#	office-hours/SKILL.md
#	plan-ceo-review/SKILL.md
#	plan-design-review/SKILL.md
#	plan-eng-review/SKILL.md
#	qa-only/SKILL.md
#	qa/SKILL.md
#	retro/SKILL.md
#	review/SKILL.md
#	scripts/resolvers/preamble.ts
#	setup-browser-cookies/SKILL.md
#	setup-deploy/SKILL.md
#	ship/SKILL.md
This commit is contained in:
Garry Tan
2026-03-29 21:22:56 -07:00
72 changed files with 528 additions and 98 deletions
+2 -2
View File
@@ -8,7 +8,7 @@ description: |
responsive layouts, test forms and uploads, handle dialogs, and assert element states.
~100ms per command. Use when you need to test a feature, verify a deployment, dogfood a
user flow, or file a bug with evidence. Use when asked to "open in browser", "test the
site", "take a screenshot", or "dogfood this".
site", "take a screenshot", or "dogfood this". (gstack)
allowed-tools:
- Bash
- Read
@@ -26,7 +26,7 @@ _UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/sk
mkdir -p ~/.gstack/sessions
touch ~/.gstack/sessions/"$PPID"
_SESSIONS=$(find ~/.gstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ')
find ~/.gstack/sessions -mmin +120 -type f -delete 2>/dev/null || true
find ~/.gstack/sessions -mmin +120 -type f -exec rm {} + 2>/dev/null || true
_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true")
_PROACTIVE_PROMPTED=$([ -f ~/.gstack/.proactive-prompted ] && echo "yes" || echo "no")
_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
+1 -1
View File
@@ -8,7 +8,7 @@ description: |
responsive layouts, test forms and uploads, handle dialogs, and assert element states.
~100ms per command. Use when you need to test a feature, verify a deployment, dogfood a
user flow, or file a bug with evidence. Use when asked to "open in browser", "test the
site", "take a screenshot", or "dogfood this".
site", "take a screenshot", or "dogfood this". (gstack)
allowed-tools:
- Bash
- Read
+1 -1
View File
@@ -430,7 +430,7 @@ function spawnClaude(userMessage: string, extensionUrl?: string | null): void {
const prompt = `${systemPrompt}\n\n<user-message>\n${escapedMessage}\n</user-message>`;
const args = ['-p', prompt, '--model', 'opus', '--output-format', 'stream-json', '--verbose',
'--allowedTools', 'Bash,Read,Glob,Grep'];
'--allowedTools', 'Bash,Read,Glob,Grep,Write'];
if (sidebarSession?.claudeSessionId) {
args.push('--resume', sidebarSession.claudeSessionId);
}
+20 -5
View File
@@ -161,8 +161,10 @@ async function askClaude(queueEntry: any): Promise<void> {
return new Promise((resolve) => {
// Use args from queue entry (server sets --model, --allowedTools, prompt framing).
// Fall back to defaults only if queue entry has no args (backward compat).
// Write doesn't expand attack surface beyond what Bash already provides.
// The security boundary is the localhost-only message path, not the tool allowlist.
let claudeArgs = args || ['-p', prompt, '--output-format', 'stream-json', '--verbose',
'--allowedTools', 'Bash,Read,Glob,Grep'];
'--allowedTools', 'Bash,Read,Glob,Grep,Write'];
// Validate cwd exists — queue may reference a stale worktree
let effectiveCwd = cwd || process.cwd();
@@ -188,20 +190,30 @@ async function askClaude(queueEntry: any): Promise<void> {
}
});
proc.stderr.on('data', () => {}); // Claude logs to stderr, ignore
let stderrBuffer = '';
proc.stderr.on('data', (data: Buffer) => {
stderrBuffer += data.toString();
});
proc.on('close', (code) => {
if (buffer.trim()) {
try { handleStreamEvent(JSON.parse(buffer)); } catch {}
}
sendEvent({ type: 'agent_done' }).then(() => {
const doneEvent: Record<string, any> = { type: 'agent_done' };
if (code !== 0 && stderrBuffer.trim()) {
doneEvent.stderr = stderrBuffer.trim().slice(-500);
}
sendEvent(doneEvent).then(() => {
isProcessing = false;
resolve();
});
});
proc.on('error', (err) => {
sendEvent({ type: 'agent_error', error: err.message }).then(() => {
const errorMsg = stderrBuffer.trim()
? `${err.message}\nstderr: ${stderrBuffer.trim().slice(-500)}`
: err.message;
sendEvent({ type: 'agent_error', error: errorMsg }).then(() => {
isProcessing = false;
resolve();
});
@@ -211,7 +223,10 @@ async function askClaude(queueEntry: any): Promise<void> {
const timeoutMs = parseInt(process.env.SIDEBAR_AGENT_TIMEOUT || '300000', 10);
setTimeout(() => {
try { proc.kill(); } catch {}
sendEvent({ type: 'agent_error', error: `Timed out after ${timeoutMs / 1000}s` }).then(() => {
const timeoutMsg = stderrBuffer.trim()
? `Timed out after ${timeoutMs / 1000}s\nstderr: ${stderrBuffer.trim().slice(-500)}`
: `Timed out after ${timeoutMs / 1000}s`;
sendEvent({ type: 'agent_error', error: timeoutMsg }).then(() => {
isProcessing = false;
resolve();
});
+1 -1
View File
@@ -115,6 +115,6 @@ describe('Sidebar prompt injection defense', () => {
test('sidebar-agent falls back to defaults if queue has no args', () => {
// Backward compatibility: if old queue entries lack args, use defaults
expect(AGENT_SRC).toContain("'--allowedTools', 'Bash,Read,Glob,Grep'");
expect(AGENT_SRC).toContain("'--allowedTools', 'Bash,Read,Glob,Grep,Write'");
});
});