mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-05 05:05:08 +02:00
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:
+72
-19
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user