Merge remote-tracking branch 'origin/garrytan/community-mode' into garrytan/persistent-docs

# Conflicts:
#	.agents/skills/gstack-browse/SKILL.md
#	.agents/skills/gstack-design-consultation/SKILL.md
#	.agents/skills/gstack-design-review/SKILL.md
#	.agents/skills/gstack-document-release/SKILL.md
#	.agents/skills/gstack-investigate/SKILL.md
#	.agents/skills/gstack-office-hours/SKILL.md
#	.agents/skills/gstack-plan-ceo-review/SKILL.md
#	.agents/skills/gstack-plan-design-review/SKILL.md
#	.agents/skills/gstack-plan-eng-review/SKILL.md
#	.agents/skills/gstack-qa-only/SKILL.md
#	.agents/skills/gstack-qa/SKILL.md
#	.agents/skills/gstack-retro/SKILL.md
#	.agents/skills/gstack-review/SKILL.md
#	.agents/skills/gstack-setup-browser-cookies/SKILL.md
#	.agents/skills/gstack-ship/SKILL.md
#	.agents/skills/gstack/SKILL.md
#	SKILL.md
#	browse/SKILL.md
#	codex/SKILL.md
#	design-consultation/SKILL.md
#	design-review/SKILL.md
#	document-release/SKILL.md
#	investigate/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/gen-skill-docs.ts
#	setup-browser-cookies/SKILL.md
#	ship/SKILL.md
This commit is contained in:
Garry Tan
2026-03-21 19:32:18 -07:00
48 changed files with 3646 additions and 3240 deletions
+72 -19
View File
@@ -160,6 +160,12 @@ _TEL_START=$(date +%s)
_SESSION_ID="$$-$(date +%s)"
echo "TELEMETRY: \${_TEL:-off}"
echo "TEL_PROMPTED: $_TEL_PROMPTED"
_EMAIL=$(${ctx.paths.binDir}/gstack-config get email 2>/dev/null || true)
_COMM_PROMPTED=$([ -f ~/.gstack/.community-prompted ] && echo "yes" || echo "no")
_AUTH_OK=$(${ctx.paths.binDir}/gstack-auth-refresh --check 2>/dev/null && echo "yes" || echo "no")
echo "EMAIL: \${_EMAIL:-none}"
echo "COMM_PROMPTED: $_COMM_PROMPTED"
echo "AUTH: $_AUTH_OK"
mkdir -p ~/.gstack/analytics
echo '{"skill":"${ctx.skillName}","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "unknown")'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true
for _PF in ~/.gstack/analytics/.pending-*; do [ -f "$_PF" ] && ${ctx.paths.binDir}/gstack-telemetry-log --event-type skill_run --skill _pending_finalize --outcome unknown --session-id "$_SESSION_ID" 2>/dev/null || true; break; done
@@ -191,28 +197,31 @@ function generateTelemetryPrompt(ctx: TemplateContext): string {
return `If \`TEL_PROMPTED\` is \`no\` AND \`LAKE_INTRO\` is \`yes\`: After the lake intro is handled,
ask the user about telemetry. Use AskUserQuestion:
> Help gstack get better! Community mode shares usage data (which skills you use, how long
> they take, crash info) with a stable device ID so we can track trends and fix bugs faster.
> No code, file paths, or repo names are ever sent.
> gstack can share usage data (which skills you use, how long they take, crash info)
> to help improve the project. No code, file paths, or repo names are ever sent.
>
> The **community tier** unlocks extra features:
> - **Cloud backup** of your gstack config + history (restore on new machines)
> - **Benchmarks**: see how your usage compares to other builders
> - **Skill recommendations** based on community patterns
>
> Change anytime with \`gstack-config set telemetry off\`.
Options:
- A) Help gstack get better! (recommended)
- B) No thanks
- A) Community — share data + email for backup, benchmarks & recommendations (recommended)
- B) Anonymous — share data only, no account
- C) No thanks
If A: run \`${ctx.paths.binDir}/gstack-config set telemetry community\`
If A: ask for their email via a follow-up AskUserQuestion, then run:
\`\`\`bash
${ctx.paths.binDir}/gstack-config set telemetry community
${ctx.paths.binDir}/gstack-auth <user-provided-email>
\`\`\`
The auth script will send a verification code to their email. Wait for them to enter the 6-digit code.
If auth succeeds, continue with the skill. If it fails, fall back to anonymous tier.
If B: ask a follow-up AskUserQuestion:
> How about anonymous mode? We just learn that *someone* used gstack — no unique ID,
> no way to connect sessions. Just a counter that helps us know if anyone's out there.
Options:
- A) Sure, anonymous is fine
- B) No thanks, fully off
If B→A: run \`${ctx.paths.binDir}/gstack-config set telemetry anonymous\`
If B→B: run \`${ctx.paths.binDir}/gstack-config set telemetry off\`
If B: run \`${ctx.paths.binDir}/gstack-config set telemetry anonymous\`
If C: run \`${ctx.paths.binDir}/gstack-config set telemetry off\`
Always run:
\`\`\`bash
@@ -222,6 +231,35 @@ touch ~/.gstack/.telemetry-prompted
This only happens once. If \`TEL_PROMPTED\` is \`yes\`, skip this entirely.`;
}
function generateCommunityUpgradePrompt(ctx: TemplateContext): string {
return `If \`TELEMETRY\` is \`anonymous\` AND \`COMM_PROMPTED\` is \`no\`: After the main skill workflow
begins (not during preamble), offer the community tier upgrade once. Use AskUserQuestion:
> You're already sharing anonymous usage data — nice! Want to unlock more?
>
> The **community tier** adds:
> - Cloud backup of your gstack config (restore on new machines)
> - Benchmarks: see how your /qa times compare to the community
> - Skill recommendations based on what other builders use
>
> Just needs your email (verified via a one-time code).
Options:
- A) Yes, join community (enter email)
- B) Not now
If A: ask for their email, then run \`${ctx.paths.binDir}/gstack-auth <email>\`.
Wait for the verification code. On success, run \`${ctx.paths.binDir}/gstack-config set telemetry community\`.
If B: do nothing.
Always run:
\`\`\`bash
touch ~/.gstack/.community-prompted
\`\`\`
This only happens once. If \`COMM_PROMPTED\` is \`yes\`, skip this entirely.`;
}
function generateAskUserFormat(_ctx: TemplateContext): string {
return `## AskUserQuestion Format
@@ -362,6 +400,16 @@ if it failed, abort if the user interrupted).
preamble already writes to the same directory — this is the same pattern.
Skipping this command loses session duration and outcome data.
**For errors:** Also determine:
- \`ERROR_CLASS\`: a short category — one of: \`timeout\`, \`test_failure\`, \`build_failure\`,
\`git_error\`, \`auth_error\`, \`network_error\`, \`browse_error\`, \`lint_error\`,
\`merge_conflict\`, \`permission_error\`, \`unknown_error\`. Pick the most specific match.
- \`ERROR_MESSAGE\`: a one-line summary of what went wrong (max 200 chars). Include the
command that failed and the key error text. Example: \`"bun test: 3 tests failed in
auth.test.ts — expected 200 got 401"\`. Never include file paths, secrets, or PII.
- \`FAILED_STEP\`: which step in the skill workflow failed. Example: \`"run_tests"\`,
\`"create_pr"\`, \`"merge_base"\`, \`"build"\`, \`"qa_browse"\`. Use snake_case, max 30 chars.
Run this bash:
\`\`\`bash
@@ -370,12 +418,16 @@ _TEL_DUR=$(( _TEL_END - _TEL_START ))
rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true
~/.claude/skills/gstack/bin/gstack-telemetry-log \\
--skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \\
--used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null &
--used-browse "USED_BROWSE" --session-id "$_SESSION_ID" \\
--error-class "ERROR_CLASS" --error-message "ERROR_MESSAGE" \\
--failed-step "FAILED_STEP" 2>/dev/null &
\`\`\`
Replace \`SKILL_NAME\` with the actual skill name from frontmatter, \`OUTCOME\` with
success/error/abort, and \`USED_BROWSE\` with true/false based on whether \`$B\` was used.
If you cannot determine the outcome, use "unknown". This runs in the background and
For \`ERROR_CLASS\`, \`ERROR_MESSAGE\`, and \`FAILED_STEP\`: use empty string \`""\` if the
outcome is not error. If the outcome is error but you cannot determine the details,
use \`"unknown_error"\`, \`""\`, and \`""\` respectively. This runs in the background and
never blocks the user.`;
}
@@ -385,6 +437,7 @@ function generatePreamble(ctx: TemplateContext): string {
generateUpgradeCheck(ctx),
generateLakeIntro(),
generateTelemetryPrompt(ctx),
generateCommunityUpgradePrompt(ctx),
generateAskUserFormat(ctx),
generateCompletenessSection(),
generateSearchBeforeBuildingSection(ctx),