diff --git a/SKILL.md b/SKILL.md index aaa5612dd..402d68511 100644 --- a/SKILL.md +++ b/SKILL.md @@ -68,10 +68,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/autoplan/SKILL.md b/autoplan/SKILL.md index 5346f1d43..ff25fa206 100644 --- a/autoplan/SKILL.md +++ b/autoplan/SKILL.md @@ -78,10 +78,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/benchmark-models/SKILL.md b/benchmark-models/SKILL.md index 6a9d62616..f3d98e027 100644 --- a/benchmark-models/SKILL.md +++ b/benchmark-models/SKILL.md @@ -72,10 +72,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/benchmark/SKILL.md b/benchmark/SKILL.md index 9451d2d4f..2aff1fe7c 100644 --- a/benchmark/SKILL.md +++ b/benchmark/SKILL.md @@ -72,10 +72,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/bin/gstack-relink b/bin/gstack-relink index dd2a681fa..ea2483da0 100755 --- a/bin/gstack-relink +++ b/bin/gstack-relink @@ -35,6 +35,7 @@ SKILLS_DIR="${GSTACK_SKILLS_DIR:-$(dirname "$INSTALL_DIR")}" # Read prefix setting PREFIX=$("$GSTACK_CONFIG" get skill_prefix 2>/dev/null || echo "false") +GSTACK_HIDDEN_SKILLS_FILE="${GSTACK_HIDDEN_SKILLS_FILE:-$HOME/.gstack/hidden-skills}" # Helper: remove old skill entry (symlink or real directory with symlinked SKILL.md) _cleanup_skill_entry() { @@ -46,6 +47,17 @@ _cleanup_skill_entry() { fi } +_skill_hidden() { + local source_name="$1" projected_name="$2" + [ -f "$GSTACK_HIDDEN_SKILLS_FILE" ] || return 1 + grep -Fqx "$source_name" "$GSTACK_HIDDEN_SKILLS_FILE" 2>/dev/null && return 0 + case "$source_name" in + gstack-*) ;; + *) grep -Fqx "gstack-$source_name" "$GSTACK_HIDDEN_SKILLS_FILE" 2>/dev/null && return 0 ;; + esac + grep -Fqx "$projected_name" "$GSTACK_HIDDEN_SKILLS_FILE" 2>/dev/null +} + _link_root_skill_alias() { local target="$SKILLS_DIR/_gstack-command" @@ -82,6 +94,12 @@ for skill_dir in "$INSTALL_DIR"/*/; do *) _cleanup_skill_entry "$SKILLS_DIR/gstack-$skill" ;; esac fi + if _skill_hidden "$skill" "$link_name"; then + _cleanup_skill_entry "$SKILLS_DIR/$skill" + _cleanup_skill_entry "$SKILLS_DIR/gstack-$skill" + _cleanup_skill_entry "$SKILLS_DIR/$link_name" + continue + fi target="$SKILLS_DIR/$link_name" # Upgrade old directory symlinks to real directories [ -L "$target" ] && rm -f "$target" diff --git a/browse/SKILL.md b/browse/SKILL.md index a8138dbbc..babe627b5 100644 --- a/browse/SKILL.md +++ b/browse/SKILL.md @@ -70,10 +70,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/canary/SKILL.md b/canary/SKILL.md index 08d4d7369..21b7ff0ce 100644 --- a/canary/SKILL.md +++ b/canary/SKILL.md @@ -70,10 +70,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/codex/SKILL.md b/codex/SKILL.md index 33228ff9b..edb29ef91 100644 --- a/codex/SKILL.md +++ b/codex/SKILL.md @@ -73,10 +73,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/context-restore/SKILL.md b/context-restore/SKILL.md index 59b40e82c..63ba32719 100644 --- a/context-restore/SKILL.md +++ b/context-restore/SKILL.md @@ -2,7 +2,7 @@ name: context-restore preamble-tier: 2 version: 1.0.0 -description: Restore working context saved earlier by /context-save. (gstack) +description: Restore working context saved earlier by /save or legacy /context-save. (gstack) allowed-tools: - Bash - Read @@ -26,7 +26,7 @@ Loads the most recent saved state (across all branches by default) so you can pick up where you left off — even across Conductor workspace handoffs. Use when asked to "resume", "restore context", "where was I", or -"pick up where I left off". Pair with /context-save. +"pick up where I left off". Pair with /save. Formerly /checkpoint resume — renamed because Claude Code treats /checkpoint as a native rewind alias in current environments. @@ -74,10 +74,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi @@ -807,8 +808,8 @@ Parse the user's input: - `/context-restore` → load the most recent saved context (any branch) - `/context-restore ` → load a specific saved context -- `/context-restore list` → tell the user "Use `/context-save list` — listing - lives on the save side" and exit. No mode detection here. +- `/context-restore list` → display the same cross-branch candidate list from + Step 1 and exit without loading a file. --- @@ -852,23 +853,60 @@ enables Conductor workspace handoff. Read the chosen file and present a summary: +Then inspect the sibling Universal Save receipt without writing anything: + +```bash +# Set CHOSEN_FILE to the exact checkpoint selected above. +RECEIPT_FILE="${CHOSEN_FILE%.md}.receipt.json" +if [ -f "$RECEIPT_FILE" ]; then + echo "RECEIPT_FILE=$RECEIPT_FILE" +else + echo "LEGACY_CHECKPOINT_NO_RECEIPT" +fi ``` -RESUMING CONTEXT + +If `RECEIPT_FILE` exists, read it and include: + +- `receipt_schema_version` (`missing` means supported legacy v0; versions above + `1` are unsupported and must produce a warning rather than a green claim); +- `verification.layers` statuses for working checkpoint, Codex Brain, Obsidian + bridge and QMD; +- exact `receipt_path` and `restore.command`; +- the first item under `### Что осталось` / `### Remaining Work` as the next + action. + +If any layer is absent or not `ok`, start the result with +`ВОССТАНОВЛЕНИЕ С ПРЕДУПРЕЖДЕНИЕМ` and name the exact layer. Do not run save, +resume, QMD update/embed or any write from this read-only skill. A legacy +checkpoint without a receipt remains restorable, but label its four-layer status +as `не подтверждён`. + +Present the human-facing result in Russian: + +``` +ВОССТАНОВЛЕНИЕ КОНТЕКСТА ════════════════════════════════════════ -Title: {title} -Branch: {branch from frontmatter} -Saved: {timestamp, human-readable} -Duration: Last session was {formatted duration} (if available) -Status: {status} +Название: {title} +Ветка: {branch from frontmatter} +Сохранено: {timestamp, human-readable} +Длительность:{formatted duration, if available} +Статус: {status} +Квитанция: {receipt path or legacy} ════════════════════════════════════════ -### Summary +### Кратко {summary from saved file} -### Remaining Work +### Состояние четырёх слоёв +Checkpoint: {status} +Codex Brain: {status} +Obsidian: {status} +QMD: {status} + +### Что осталось {remaining work items} -### Notes +### Примечания {notes} ``` @@ -892,14 +930,16 @@ If A, summarize the first remaining work item and suggest starting there. If Step 1 printed `NO_CHECKPOINTS`, tell the user: -"No saved contexts yet. Run `/context-save` first to save your current working -state, then `/context-restore` will find it." +"Сохранённых контекстов пока нет. Запустите `/save`, затем +`/context-restore` найдёт сохранение." --- ## Important Rules - **Never modify code.** This skill only reads saved files and presents them. +- **Never mutate a receipt.** Receipt inspection and four-layer verification + display are read-only; repair belongs to `/save` resume flow. - **Always search across all branches by default.** Cross-branch resume is the whole point. Only filter by branch if the user explicitly asks via a title-fragment match that happens to be branch-specific. diff --git a/context-restore/SKILL.md.tmpl b/context-restore/SKILL.md.tmpl index 55889f6e0..3b141208f 100644 --- a/context-restore/SKILL.md.tmpl +++ b/context-restore/SKILL.md.tmpl @@ -3,11 +3,11 @@ name: context-restore preamble-tier: 2 version: 1.0.0 description: | - Restore working context saved earlier by /context-save. Loads the most recent + Restore working context saved earlier by /save or legacy /context-save. Loads the most recent saved state (across all branches by default) so you can pick up where you left off — even across Conductor workspace handoffs. Use when asked to "resume", "restore context", "where was I", or - "pick up where I left off". Pair with /context-save. + "pick up where I left off". Pair with /save. Formerly /checkpoint resume — renamed because Claude Code treats /checkpoint as a native rewind alias in current environments. (gstack) allowed-tools: @@ -51,8 +51,8 @@ Parse the user's input: - `/context-restore` → load the most recent saved context (any branch) - `/context-restore ` → load a specific saved context -- `/context-restore list` → tell the user "Use `/context-save list` — listing - lives on the save side" and exit. No mode detection here. +- `/context-restore list` → display the same cross-branch candidate list from + Step 1 and exit without loading a file. --- @@ -96,23 +96,60 @@ enables Conductor workspace handoff. Read the chosen file and present a summary: +Then inspect the sibling Universal Save receipt without writing anything: + +```bash +# Set CHOSEN_FILE to the exact checkpoint selected above. +RECEIPT_FILE="${CHOSEN_FILE%.md}.receipt.json" +if [ -f "$RECEIPT_FILE" ]; then + echo "RECEIPT_FILE=$RECEIPT_FILE" +else + echo "LEGACY_CHECKPOINT_NO_RECEIPT" +fi ``` -RESUMING CONTEXT + +If `RECEIPT_FILE` exists, read it and include: + +- `receipt_schema_version` (`missing` means supported legacy v0; versions above + `1` are unsupported and must produce a warning rather than a green claim); +- `verification.layers` statuses for working checkpoint, Codex Brain, Obsidian + bridge and QMD; +- exact `receipt_path` and `restore.command`; +- the first item under `### Что осталось` / `### Remaining Work` as the next + action. + +If any layer is absent or not `ok`, start the result with +`ВОССТАНОВЛЕНИЕ С ПРЕДУПРЕЖДЕНИЕМ` and name the exact layer. Do not run save, +resume, QMD update/embed or any write from this read-only skill. A legacy +checkpoint without a receipt remains restorable, but label its four-layer status +as `не подтверждён`. + +Present the human-facing result in Russian: + +``` +ВОССТАНОВЛЕНИЕ КОНТЕКСТА ════════════════════════════════════════ -Title: {title} -Branch: {branch from frontmatter} -Saved: {timestamp, human-readable} -Duration: Last session was {formatted duration} (if available) -Status: {status} +Название: {title} +Ветка: {branch from frontmatter} +Сохранено: {timestamp, human-readable} +Длительность:{formatted duration, if available} +Статус: {status} +Квитанция: {receipt path or legacy} ════════════════════════════════════════ -### Summary +### Кратко {summary from saved file} -### Remaining Work +### Состояние четырёх слоёв +Checkpoint: {status} +Codex Brain: {status} +Obsidian: {status} +QMD: {status} + +### Что осталось {remaining work items} -### Notes +### Примечания {notes} ``` @@ -136,14 +173,16 @@ If A, summarize the first remaining work item and suggest starting there. If Step 1 printed `NO_CHECKPOINTS`, tell the user: -"No saved contexts yet. Run `/context-save` first to save your current working -state, then `/context-restore` will find it." +"Сохранённых контекстов пока нет. Запустите `/save`, затем +`/context-restore` найдёт сохранение." --- ## Important Rules - **Never modify code.** This skill only reads saved files and presents them. +- **Never mutate a receipt.** Receipt inspection and four-layer verification + display are read-only; repair belongs to `/save` resume flow. - **Always search across all branches by default.** Cross-branch resume is the whole point. Only filter by branch if the user explicitly asks via a title-fragment match that happens to be branch-specific. diff --git a/context-save/SKILL.md b/context-save/SKILL.md index a1eb24595..e0d413330 100644 --- a/context-save/SKILL.md +++ b/context-save/SKILL.md @@ -73,10 +73,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi @@ -790,6 +791,14 @@ can resume without losing a beat via `/context-restore`. **HARD GATE:** Do NOT implement code changes. This skill captures state only. +**EVGENIY LANGUAGE CONTRACT:** When the primary reader is Evgeniy, write the +entire human-facing checkpoint and confirmation in Russian: title, headings, +summary, decisions, risks, verification results, remaining work, notes, table +labels, and next steps. Keep English only for exact commands, paths, filenames, +code/API/schema fields, model/tool names, identifiers, immutable status literals, +and source quotes. Frontmatter keys remain machine-readable. Before confirming a +save, scan the checkpoint for leftover English prose and translate it. + --- ## Detect command @@ -915,23 +924,23 @@ files_modified: - path/to/file2 --- -## Working on: {title} +## Текущая работа: {title} -### Summary +### Кратко -{1-3 sentences describing the high-level goal and current progress} +{1-3 предложения с описанием общей цели и текущего прогресса} -### Decisions Made +### Принятые решения -{Bulleted list of architectural choices, trade-offs, and reasoning} +{Маркированный список архитектурных решений, компромиссов и причин} -### Remaining Work +### Что осталось -{Numbered list of concrete next steps, in priority order} +{Нумерованный список конкретных следующих шагов в порядке приоритета} -### Notes +### Примечания -{Gotchas, blocked items, open questions, things tried that didn't work} +{Подводные камни, блокеры, открытые вопросы и неудачные попытки} ``` The `files_modified` list comes from `git status --short` (both staged and unstaged @@ -940,16 +949,16 @@ modified files). Use relative paths from the repo root. After writing, confirm to the user: ``` -CONTEXT SAVED +КОНТЕКСТ СОХРАНЁН ════════════════════════════════════════ -Title: {title} -Branch: {branch} -File: {path to saved file} -Modified: {N} files -Duration: {duration or "unknown"} +Название: {title} +Ветка: {branch} +Файл: {path to saved file} +Изменено: {N} файлов +Длительность: {duration или "неизвестно"} ════════════════════════════════════════ -Restore later with /context-restore. +Позже восстановите контекст командой /context-restore. ``` --- @@ -986,9 +995,9 @@ Read the frontmatter of each file to extract `status`, `branch`, and Present as a table: ``` -SAVED CONTEXTS ({branch} branch) +СОХРАНЁННЫЕ КОНТЕКСТЫ (ветка {branch}) ════════════════════════════════════════ -# Date Title Status +# Дата Название Статус ─ ────────── ─────────────────────── ─────────── 1 2026-04-18 auth-refactor in-progress 2 2026-04-17 api-pagination completed @@ -999,9 +1008,9 @@ SAVED CONTEXTS ({branch} branch) If `--all` is used, add a Branch column: ``` -SAVED CONTEXTS (all branches) +СОХРАНЁННЫЕ КОНТЕКСТЫ (все ветки) ════════════════════════════════════════ -# Date Title Branch Status +# Дата Название Ветка Статус ─ ────────── ─────────────────────── ────────────────── ─────────── 1 2026-04-18 auth-refactor feat/auth in-progress 2 2026-04-17 api-pagination main completed @@ -1009,8 +1018,8 @@ SAVED CONTEXTS (all branches) ════════════════════════════════════════ ``` -If there are no saved contexts, tell the user: "No saved contexts yet. Run -`/context-save` to save your current working state." +If there are no saved contexts, tell Evgeniy: "Сохранённых контекстов пока нет. +Запустите `/context-save`, чтобы сохранить текущее рабочее состояние." --- diff --git a/context-save/SKILL.md.tmpl b/context-save/SKILL.md.tmpl index a3702bc95..28aa34005 100644 --- a/context-save/SKILL.md.tmpl +++ b/context-save/SKILL.md.tmpl @@ -35,6 +35,14 @@ can resume without losing a beat via `/context-restore`. **HARD GATE:** Do NOT implement code changes. This skill captures state only. +**EVGENIY LANGUAGE CONTRACT:** When the primary reader is Evgeniy, write the +entire human-facing checkpoint and confirmation in Russian: title, headings, +summary, decisions, risks, verification results, remaining work, notes, table +labels, and next steps. Keep English only for exact commands, paths, filenames, +code/API/schema fields, model/tool names, identifiers, immutable status literals, +and source quotes. Frontmatter keys remain machine-readable. Before confirming a +save, scan the checkpoint for leftover English prose and translate it. + --- ## Detect command @@ -160,23 +168,23 @@ files_modified: - path/to/file2 --- -## Working on: {title} +## Текущая работа: {title} -### Summary +### Кратко -{1-3 sentences describing the high-level goal and current progress} +{1-3 предложения с описанием общей цели и текущего прогресса} -### Decisions Made +### Принятые решения -{Bulleted list of architectural choices, trade-offs, and reasoning} +{Маркированный список архитектурных решений, компромиссов и причин} -### Remaining Work +### Что осталось -{Numbered list of concrete next steps, in priority order} +{Нумерованный список конкретных следующих шагов в порядке приоритета} -### Notes +### Примечания -{Gotchas, blocked items, open questions, things tried that didn't work} +{Подводные камни, блокеры, открытые вопросы и неудачные попытки} ``` The `files_modified` list comes from `git status --short` (both staged and unstaged @@ -185,16 +193,16 @@ modified files). Use relative paths from the repo root. After writing, confirm to the user: ``` -CONTEXT SAVED +КОНТЕКСТ СОХРАНЁН ════════════════════════════════════════ -Title: {title} -Branch: {branch} -File: {path to saved file} -Modified: {N} files -Duration: {duration or "unknown"} +Название: {title} +Ветка: {branch} +Файл: {path to saved file} +Изменено: {N} файлов +Длительность: {duration или "неизвестно"} ════════════════════════════════════════ -Restore later with /context-restore. +Позже восстановите контекст командой /context-restore. ``` --- @@ -231,9 +239,9 @@ Read the frontmatter of each file to extract `status`, `branch`, and Present as a table: ``` -SAVED CONTEXTS ({branch} branch) +СОХРАНЁННЫЕ КОНТЕКСТЫ (ветка {branch}) ════════════════════════════════════════ -# Date Title Status +# Дата Название Статус ─ ────────── ─────────────────────── ─────────── 1 2026-04-18 auth-refactor in-progress 2 2026-04-17 api-pagination completed @@ -244,9 +252,9 @@ SAVED CONTEXTS ({branch} branch) If `--all` is used, add a Branch column: ``` -SAVED CONTEXTS (all branches) +СОХРАНЁННЫЕ КОНТЕКСТЫ (все ветки) ════════════════════════════════════════ -# Date Title Branch Status +# Дата Название Ветка Статус ─ ────────── ─────────────────────── ────────────────── ─────────── 1 2026-04-18 auth-refactor feat/auth in-progress 2 2026-04-17 api-pagination main completed @@ -254,8 +262,8 @@ SAVED CONTEXTS (all branches) ════════════════════════════════════════ ``` -If there are no saved contexts, tell the user: "No saved contexts yet. Run -`/context-save` to save your current working state." +If there are no saved contexts, tell Evgeniy: "Сохранённых контекстов пока нет. +Запустите `/context-save`, чтобы сохранить текущее рабочее состояние." --- diff --git a/cso/SKILL.md b/cso/SKILL.md index a08d7e9fe..073b57119 100644 --- a/cso/SKILL.md +++ b/cso/SKILL.md @@ -76,10 +76,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/design-consultation/SKILL.md b/design-consultation/SKILL.md index 83eed0a2d..77fd0aceb 100644 --- a/design-consultation/SKILL.md +++ b/design-consultation/SKILL.md @@ -96,10 +96,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/design-html/SKILL.md b/design-html/SKILL.md index a480bd62c..848c9d645 100644 --- a/design-html/SKILL.md +++ b/design-html/SKILL.md @@ -77,10 +77,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/design-review/SKILL.md b/design-review/SKILL.md index 645453162..bd1feba23 100644 --- a/design-review/SKILL.md +++ b/design-review/SKILL.md @@ -74,10 +74,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/design-shotgun/SKILL.md b/design-shotgun/SKILL.md index 3386d18fa..b46890ccd 100644 --- a/design-shotgun/SKILL.md +++ b/design-shotgun/SKILL.md @@ -91,10 +91,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/devex-review/SKILL.md b/devex-review/SKILL.md index 7ef324b3e..ec583c4d7 100644 --- a/devex-review/SKILL.md +++ b/devex-review/SKILL.md @@ -76,10 +76,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/diagram/SKILL.md b/diagram/SKILL.md index 9e5a41066..549bd936c 100644 --- a/diagram/SKILL.md +++ b/diagram/SKILL.md @@ -71,10 +71,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/document-generate/SKILL.md b/document-generate/SKILL.md index 30846fc4d..aa5f3fa13 100644 --- a/document-generate/SKILL.md +++ b/document-generate/SKILL.md @@ -76,10 +76,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/document-release/SKILL.md b/document-release/SKILL.md index b95873625..9c233469c 100644 --- a/document-release/SKILL.md +++ b/document-release/SKILL.md @@ -74,10 +74,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/gstack-upgrade/SKILL.md b/gstack-upgrade/SKILL.md index 9f0f2f7ea..2a993982a 100644 --- a/gstack-upgrade/SKILL.md +++ b/gstack-upgrade/SKILL.md @@ -28,6 +28,22 @@ Voice triggers (speech-to-text aliases): "upgrade the tools", "update the tools" Upgrade gstack to the latest version and show what's new. +## Operating boundaries + +PRIORITY 1: preserve user work, credentials and current project state. +PRIORITY 2: upgrade only the detected gstack install and its documented +gstack state files. +PRIORITY 3: summarize the result and continue the original task. + +Each user message is an independent task. Do not carry repository state, +upgrade results or user preferences between unrelated tasks unless the user +explicitly asks. + +Persistence scope: this skill may write only gstack update state such as +`auto_upgrade`, `update_check`, `~/.gstack/update-snoozed`, +`~/.gstack/just-upgraded-from` and `~/.gstack/last-update-check`. Do not persist +unrelated conversation memory, project decisions, credentials or tool results. + ## Inline upgrade flow This section is referenced by all skill preambles when they detect `UPGRADE_AVAILABLE`. @@ -46,17 +62,17 @@ echo "AUTO_UPGRADE=$_AUTO" **Otherwise**, use AskUserQuestion: - Question: "gstack **v{new}** is available (you're on v{old}). Upgrade now?" -- Options: ["Yes, upgrade now", "Always keep me up to date", "Not now", "Never ask again"] +- Options: ["Yes, upgrade now", "Enable gstack auto-upgrade", "Snooze this gstack version", "Disable gstack update checks"] **If "Yes, upgrade now":** Proceed to Step 2. -**If "Always keep me up to date":** +**If "Enable gstack auto-upgrade":** ```bash ~/.claude/skills/gstack/bin/gstack-config set auto_upgrade true ``` -Tell user: "Auto-upgrade enabled. Future updates will install automatically." Then proceed to Step 2. +Tell user: "Gstack auto-upgrade enabled for this install. Future gstack updates will install automatically." Then proceed to Step 2. -**If "Not now":** Write snooze state with escalating backoff (first snooze = 24h, second = 48h, third+ = 1 week), then continue with the current skill. Do not mention the upgrade again. +**If "Snooze this gstack version":** Write snooze state for this gstack version with escalating backoff (first snooze = 24h, second = 48h, third+ = 1 week), then continue with the current skill. Do not mention this gstack version again until the snooze expires. ```bash _SNOOZE_FILE="$HOME/.gstack/update-snoozed" _REMOTE_VER="{new}" @@ -76,11 +92,11 @@ Note: `{new}` is the remote version from the `UPGRADE_AVAILABLE` output — subs Tell user the snooze duration: "Next reminder in 24h" (or 48h or 1 week, depending on level). Tip: "Set `auto_upgrade: true` in `~/.gstack/config.yaml` for automatic upgrades." -**If "Never ask again":** +**If "Disable gstack update checks":** ```bash ~/.claude/skills/gstack/bin/gstack-config set update_check false ``` -Tell user: "Update checks disabled. Run `~/.claude/skills/gstack/bin/gstack-config set update_check true` to re-enable." +Tell user: "Gstack update checks disabled for this install. Run `~/.claude/skills/gstack/bin/gstack-config set update_check true` to re-enable." Continue with the current skill. ### Step 2: Detect install type diff --git a/gstack-upgrade/SKILL.md.tmpl b/gstack-upgrade/SKILL.md.tmpl index 5402a1da3..e31e573f0 100644 --- a/gstack-upgrade/SKILL.md.tmpl +++ b/gstack-upgrade/SKILL.md.tmpl @@ -25,6 +25,22 @@ allowed-tools: Upgrade gstack to the latest version and show what's new. +## Operating boundaries + +PRIORITY 1: preserve user work, credentials and current project state. +PRIORITY 2: upgrade only the detected gstack install and its documented +gstack state files. +PRIORITY 3: summarize the result and continue the original task. + +Each user message is an independent task. Do not carry repository state, +upgrade results or user preferences between unrelated tasks unless the user +explicitly asks. + +Persistence scope: this skill may write only gstack update state such as +`auto_upgrade`, `update_check`, `~/.gstack/update-snoozed`, +`~/.gstack/just-upgraded-from` and `~/.gstack/last-update-check`. Do not persist +unrelated conversation memory, project decisions, credentials or tool results. + ## Inline upgrade flow This section is referenced by all skill preambles when they detect `UPGRADE_AVAILABLE`. @@ -43,17 +59,17 @@ echo "AUTO_UPGRADE=$_AUTO" **Otherwise**, use AskUserQuestion: - Question: "gstack **v{new}** is available (you're on v{old}). Upgrade now?" -- Options: ["Yes, upgrade now", "Always keep me up to date", "Not now", "Never ask again"] +- Options: ["Yes, upgrade now", "Enable gstack auto-upgrade", "Snooze this gstack version", "Disable gstack update checks"] **If "Yes, upgrade now":** Proceed to Step 2. -**If "Always keep me up to date":** +**If "Enable gstack auto-upgrade":** ```bash ~/.claude/skills/gstack/bin/gstack-config set auto_upgrade true ``` -Tell user: "Auto-upgrade enabled. Future updates will install automatically." Then proceed to Step 2. +Tell user: "Gstack auto-upgrade enabled for this install. Future gstack updates will install automatically." Then proceed to Step 2. -**If "Not now":** Write snooze state with escalating backoff (first snooze = 24h, second = 48h, third+ = 1 week), then continue with the current skill. Do not mention the upgrade again. +**If "Snooze this gstack version":** Write snooze state for this gstack version with escalating backoff (first snooze = 24h, second = 48h, third+ = 1 week), then continue with the current skill. Do not mention this gstack version again until the snooze expires. ```bash _SNOOZE_FILE="$HOME/.gstack/update-snoozed" _REMOTE_VER="{new}" @@ -73,11 +89,11 @@ Note: `{new}` is the remote version from the `UPGRADE_AVAILABLE` output — subs Tell user the snooze duration: "Next reminder in 24h" (or 48h or 1 week, depending on level). Tip: "Set `auto_upgrade: true` in `~/.gstack/config.yaml` for automatic upgrades." -**If "Never ask again":** +**If "Disable gstack update checks":** ```bash ~/.claude/skills/gstack/bin/gstack-config set update_check false ``` -Tell user: "Update checks disabled. Run `~/.claude/skills/gstack/bin/gstack-config set update_check true` to re-enable." +Tell user: "Gstack update checks disabled for this install. Run `~/.claude/skills/gstack/bin/gstack-config set update_check true` to re-enable." Continue with the current skill. ### Step 2: Detect install type diff --git a/gstack/llms.txt b/gstack/llms.txt index efe522f90..579b4be2a 100644 --- a/gstack/llms.txt +++ b/gstack/llms.txt @@ -18,7 +18,7 @@ Conventions: - [/careful](careful/SKILL.md): Safety guardrails for destructive commands. - [/claude](claude/SKILL.md): Claude Code CLI wrapper for non-Claude hosts - three modes. - [/codex](codex/SKILL.md): OpenAI Codex CLI wrapper — three modes. -- [/context-restore](context-restore/SKILL.md): Restore working context saved earlier by /context-save. +- [/context-restore](context-restore/SKILL.md): Restore working context saved earlier by /save or legacy /context-save. - [/context-save](context-save/SKILL.md): Save working context. - [/cso](cso/SKILL.md): Chief Security Officer mode. - [/design-consultation](design-consultation/SKILL.md): Design consultation: understands your product, researches the landscape, proposes a complete design system (aesthetic, typography, color, layout, spacing, motion), and generates font+color preview pages. diff --git a/health/SKILL.md b/health/SKILL.md index e68199dec..536a28f0c 100644 --- a/health/SKILL.md +++ b/health/SKILL.md @@ -72,10 +72,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/investigate/SKILL.md b/investigate/SKILL.md index 5d54b4256..d6bfbc5cd 100644 --- a/investigate/SKILL.md +++ b/investigate/SKILL.md @@ -111,10 +111,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/ios-clean/SKILL.md b/ios-clean/SKILL.md index 6c466896b..9d4d754ac 100644 --- a/ios-clean/SKILL.md +++ b/ios-clean/SKILL.md @@ -74,10 +74,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/ios-design-review/SKILL.md b/ios-design-review/SKILL.md index 904da7589..c46ca0947 100644 --- a/ios-design-review/SKILL.md +++ b/ios-design-review/SKILL.md @@ -76,10 +76,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/ios-fix/SKILL.md b/ios-fix/SKILL.md index 3ddae1ac0..2f6ec81e6 100644 --- a/ios-fix/SKILL.md +++ b/ios-fix/SKILL.md @@ -77,10 +77,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/ios-qa/SKILL.md b/ios-qa/SKILL.md index 24624be5f..58856c68b 100644 --- a/ios-qa/SKILL.md +++ b/ios-qa/SKILL.md @@ -80,10 +80,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/ios-sync/SKILL.md b/ios-sync/SKILL.md index 95e0bca0a..e76e0a19c 100644 --- a/ios-sync/SKILL.md +++ b/ios-sync/SKILL.md @@ -74,10 +74,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/land-and-deploy/SKILL.md b/land-and-deploy/SKILL.md index 54ebf52c0..da3396ecc 100644 --- a/land-and-deploy/SKILL.md +++ b/land-and-deploy/SKILL.md @@ -69,10 +69,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/landing-report/SKILL.md b/landing-report/SKILL.md index 8f7e6e210..20cb9b1d6 100644 --- a/landing-report/SKILL.md +++ b/landing-report/SKILL.md @@ -70,10 +70,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/learn/SKILL.md b/learn/SKILL.md index a0c6ae053..75b1296c1 100644 --- a/learn/SKILL.md +++ b/learn/SKILL.md @@ -72,10 +72,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/make-pdf/SKILL.md b/make-pdf/SKILL.md index 600eb47ca..d25512618 100644 --- a/make-pdf/SKILL.md +++ b/make-pdf/SKILL.md @@ -71,10 +71,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/office-hours/SKILL.md b/office-hours/SKILL.md index 83161b8ca..b33a31295 100644 --- a/office-hours/SKILL.md +++ b/office-hours/SKILL.md @@ -107,10 +107,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/open-gstack-browser/SKILL.md b/open-gstack-browser/SKILL.md index 28fb1ddb2..94a89a7d6 100644 --- a/open-gstack-browser/SKILL.md +++ b/open-gstack-browser/SKILL.md @@ -69,10 +69,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/pair-agent/SKILL.md b/pair-agent/SKILL.md index eed9d171a..c242e8b79 100644 --- a/pair-agent/SKILL.md +++ b/pair-agent/SKILL.md @@ -71,10 +71,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/plan-ceo-review/SKILL.md b/plan-ceo-review/SKILL.md index 3d3208bee..953726c82 100644 --- a/plan-ceo-review/SKILL.md +++ b/plan-ceo-review/SKILL.md @@ -101,10 +101,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/plan-design-review/SKILL.md b/plan-design-review/SKILL.md index e81f7f12a..4c40f58ae 100644 --- a/plan-design-review/SKILL.md +++ b/plan-design-review/SKILL.md @@ -73,10 +73,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/plan-devex-review/SKILL.md b/plan-devex-review/SKILL.md index 20a32da8b..b6e6e124f 100644 --- a/plan-devex-review/SKILL.md +++ b/plan-devex-review/SKILL.md @@ -79,10 +79,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/plan-eng-review/SKILL.md b/plan-eng-review/SKILL.md index 5557a33fa..6b4e419a2 100644 --- a/plan-eng-review/SKILL.md +++ b/plan-eng-review/SKILL.md @@ -77,10 +77,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/plan-tune/SKILL.md b/plan-tune/SKILL.md index f49b66fac..439dda3a3 100644 --- a/plan-tune/SKILL.md +++ b/plan-tune/SKILL.md @@ -82,10 +82,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/qa-only/SKILL.md b/qa-only/SKILL.md index 801a935c0..74cab5136 100644 --- a/qa-only/SKILL.md +++ b/qa-only/SKILL.md @@ -72,10 +72,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/qa/SKILL.md b/qa/SKILL.md index c1ac10253..0ef89007a 100644 --- a/qa/SKILL.md +++ b/qa/SKILL.md @@ -78,10 +78,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/retro/SKILL.md b/retro/SKILL.md index 3fbc44726..2574d0296 100644 --- a/retro/SKILL.md +++ b/retro/SKILL.md @@ -89,10 +89,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/review/SKILL.md b/review/SKILL.md index 5f26e2e42..cf4beab17 100644 --- a/review/SKILL.md +++ b/review/SKILL.md @@ -74,10 +74,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/scrape/SKILL.md b/scrape/SKILL.md index dc965ec5f..e7e2eb970 100644 --- a/scrape/SKILL.md +++ b/scrape/SKILL.md @@ -70,10 +70,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/scripts/proactive-suggestions.json b/scripts/proactive-suggestions.json index d08c60853..8a12780a8 100644 --- a/scripts/proactive-suggestions.json +++ b/scripts/proactive-suggestions.json @@ -39,8 +39,8 @@ "voice_line": "Voice triggers (speech-to-text aliases): \"code x\", \"code ex\", \"get another opinion\"." }, "context-restore": { - "lead": "Restore working context saved earlier by /context-save.", - "routing": "Loads the most recent\nsaved state (across all branches by default) so you can pick up where you\nleft off — even across Conductor workspace handoffs.\nUse when asked to \"resume\", \"restore context\", \"where was I\", or\n\"pick up where I left off\". Pair with /context-save.\nFormerly /checkpoint resume — renamed because Claude Code treats /checkpoint\nas a native rewind alias in current environments.", + "lead": "Restore working context saved earlier by /save or legacy /context-save.", + "routing": "Loads the most recent\nsaved state (across all branches by default) so you can pick up where you\nleft off — even across Conductor workspace handoffs.\nUse when asked to \"resume\", \"restore context\", \"where was I\", or\n\"pick up where I left off\". Pair with /save.\nFormerly /checkpoint resume — renamed because Claude Code treats /checkpoint\nas a native rewind alias in current environments.", "voice_line": null }, "context-save": { diff --git a/scripts/resolvers/preamble/generate-preamble-bash.ts b/scripts/resolvers/preamble/generate-preamble-bash.ts index f0bc57b4b..97909ca30 100644 --- a/scripts/resolvers/preamble/generate-preamble-bash.ts +++ b/scripts/resolvers/preamble/generate-preamble-bash.ts @@ -6,7 +6,7 @@ export function generatePreambleBash(ctx: TemplateContext): string { const runtimeRoot = hostConfig.usesEnvVars ? `_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) GSTACK_ROOT="$HOME/${hostConfig.globalRoot}" -[ -n "$_ROOT" ] && [ -d "$_ROOT/${ctx.paths.localSkillRoot}" ] && GSTACK_ROOT="$_ROOT/${ctx.paths.localSkillRoot}" +[ -n "$_ROOT" ] && [ -x "$_ROOT/${ctx.paths.localSkillRoot}/bin/gstack-config" ] && GSTACK_ROOT="$_ROOT/${ctx.paths.localSkillRoot}" GSTACK_BIN="$GSTACK_ROOT/bin" GSTACK_BROWSE="$GSTACK_ROOT/browse/dist" GSTACK_DESIGN="$GSTACK_ROOT/design/dist" @@ -57,10 +57,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(${ctx.paths.binDir}/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: \${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(${ctx.paths.binDir}/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/setup b/setup index 275236cd3..f823dab9b 100755 --- a/setup +++ b/setup @@ -531,6 +531,20 @@ fi # 3. Ensure ~/.gstack global state directory exists mkdir -p "$HOME/.gstack/projects" +# Optional user-level visibility denylist. One exact skill name per line; +# either source form (context-save) or projected form (gstack-context-save). +GSTACK_HIDDEN_SKILLS_FILE="${GSTACK_HIDDEN_SKILLS_FILE:-$HOME/.gstack/hidden-skills}" +_gstack_skill_hidden() { + local source_name="$1" projected_name="${2:-$1}" + [ -f "$GSTACK_HIDDEN_SKILLS_FILE" ] || return 1 + grep -Fqx "$source_name" "$GSTACK_HIDDEN_SKILLS_FILE" 2>/dev/null && return 0 + case "$source_name" in + gstack-*) ;; + *) grep -Fqx "gstack-$source_name" "$GSTACK_HIDDEN_SKILLS_FILE" 2>/dev/null && return 0 ;; + esac + grep -Fqx "$projected_name" "$GSTACK_HIDDEN_SKILLS_FILE" 2>/dev/null +} + # ─── Helper: link Claude skill subdirectories into a skills parent directory ── # Creates real directories (not symlinks) at the top level with a SKILL.md symlink # inside. This ensures Claude discovers them as top-level skills, not nested under @@ -559,6 +573,14 @@ link_claude_skill_dirs() { link_name="$skill_name" fi target="$skills_dir/$link_name" + if _gstack_skill_hidden "$dir_name" "$link_name"; then + if [ -L "$target" ]; then + rm -f "$target" + elif [ -d "$target" ] && [ -L "$target/SKILL.md" ]; then + rm -rf "$target" + fi + continue + fi # Upgrade old directory symlinks to real directories if [ -L "$target" ]; then rm -f "$target" @@ -726,6 +748,7 @@ link_codex_skill_dirs() { # browse/), not a skill. Linking it would overwrite the root gstack # symlink that Step 5 already pointed at the repo root. [ "$skill_name" = "gstack" ] && continue + _gstack_skill_hidden "$skill_name" "$skill_name" && continue target="$skills_dir/$skill_name" # Create or update symlink if [ -L "$target" ] || [ ! -e "$target" ]; then diff --git a/setup-browser-cookies/SKILL.md b/setup-browser-cookies/SKILL.md index 77df27da2..3145865e3 100644 --- a/setup-browser-cookies/SKILL.md +++ b/setup-browser-cookies/SKILL.md @@ -66,10 +66,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/setup-deploy/SKILL.md b/setup-deploy/SKILL.md index 3465dc564..ce9bfaca7 100644 --- a/setup-deploy/SKILL.md +++ b/setup-deploy/SKILL.md @@ -73,10 +73,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/setup-gbrain/SKILL.md b/setup-gbrain/SKILL.md index a3892f1c9..dd35db266 100644 --- a/setup-gbrain/SKILL.md +++ b/setup-gbrain/SKILL.md @@ -72,10 +72,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/ship/SKILL.md b/ship/SKILL.md index eadffaa8f..974b01e3f 100644 --- a/ship/SKILL.md +++ b/ship/SKILL.md @@ -74,10 +74,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/skillify/SKILL.md b/skillify/SKILL.md index 7cb434d0c..d0434ef4d 100644 --- a/skillify/SKILL.md +++ b/skillify/SKILL.md @@ -70,10 +70,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/spec/SKILL.md b/spec/SKILL.md index 0894e98d1..64b38bb52 100644 --- a/spec/SKILL.md +++ b/spec/SKILL.md @@ -71,10 +71,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi @@ -1141,10 +1142,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/sync-gbrain/SKILL.md b/sync-gbrain/SKILL.md index 02055bb6f..caca7d5a5 100644 --- a/sync-gbrain/SKILL.md +++ b/sync-gbrain/SKILL.md @@ -72,10 +72,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/test/context-restore-receipt.test.ts b/test/context-restore-receipt.test.ts new file mode 100644 index 000000000..a025e6ba6 --- /dev/null +++ b/test/context-restore-receipt.test.ts @@ -0,0 +1,26 @@ +import { describe, expect, test } from 'bun:test'; +import * as fs from 'fs'; +import * as path from 'path'; + +const ROOT = path.resolve(import.meta.dir, '..'); + +describe('context-restore Universal Save receipt contract', () => { + const sources = [ + 'context-restore/SKILL.md.tmpl', + 'context-restore/SKILL.md', + '.agents/skills/gstack-context-restore/SKILL.md', + ]; + + for (const relative of sources) { + test(`${relative} reads four-layer receipts without mutation`, () => { + const content = fs.readFileSync(path.join(ROOT, relative), 'utf-8'); + expect(content).toContain('RECEIPT_FILE="${CHOSEN_FILE%.md}.receipt.json"'); + expect(content).toContain('receipt_schema_version'); + expect(content).toContain('Codex Brain'); + expect(content).toContain('Obsidian'); + expect(content).toContain('QMD'); + expect(content).toContain('Never mutate a receipt'); + expect(content).toContain('ВОССТАНОВЛЕНИЕ КОНТЕКСТА'); + }); + } +}); diff --git a/test/fixtures/golden/claude-ship-SKILL.md b/test/fixtures/golden/claude-ship-SKILL.md index eadffaa8f..974b01e3f 100644 --- a/test/fixtures/golden/claude-ship-SKILL.md +++ b/test/fixtures/golden/claude-ship-SKILL.md @@ -74,10 +74,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$(~/.claude/skills/gstack/bin/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/test/fixtures/golden/codex-ship-SKILL.md b/test/fixtures/golden/codex-ship-SKILL.md index d99630c4b..2edcfca2b 100644 --- a/test/fixtures/golden/codex-ship-SKILL.md +++ b/test/fixtures/golden/codex-ship-SKILL.md @@ -15,7 +15,7 @@ description: | ```bash _ROOT=$(git rev-parse --show-toplevel 2>/dev/null) GSTACK_ROOT="$HOME/.codex/skills/gstack" -[ -n "$_ROOT" ] && [ -d "$_ROOT/.agents/skills/gstack" ] && GSTACK_ROOT="$_ROOT/.agents/skills/gstack" +[ -n "$_ROOT" ] && [ -x "$_ROOT/.agents/skills/gstack/bin/gstack-config" ] && GSTACK_ROOT="$_ROOT/.agents/skills/gstack" GSTACK_BIN="$GSTACK_ROOT/bin" GSTACK_BROWSE="$GSTACK_ROOT/browse/dist" GSTACK_DESIGN="$GSTACK_ROOT/design/dist" @@ -60,10 +60,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$($GSTACK_BIN/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$($GSTACK_BIN/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/test/fixtures/golden/factory-ship-SKILL.md b/test/fixtures/golden/factory-ship-SKILL.md index a2acad24f..33b1de65d 100644 --- a/test/fixtures/golden/factory-ship-SKILL.md +++ b/test/fixtures/golden/factory-ship-SKILL.md @@ -17,7 +17,7 @@ disable-model-invocation: true ```bash _ROOT=$(git rev-parse --show-toplevel 2>/dev/null) GSTACK_ROOT="$HOME/.factory/skills/gstack" -[ -n "$_ROOT" ] && [ -d "$_ROOT/.factory/skills/gstack" ] && GSTACK_ROOT="$_ROOT/.factory/skills/gstack" +[ -n "$_ROOT" ] && [ -x "$_ROOT/.factory/skills/gstack/bin/gstack-config" ] && GSTACK_ROOT="$_ROOT/.factory/skills/gstack" GSTACK_BIN="$GSTACK_ROOT/bin" GSTACK_BROWSE="$GSTACK_ROOT/browse/dist" GSTACK_DESIGN="$GSTACK_ROOT/design/dist" @@ -62,10 +62,11 @@ echo "FIRST_TASK: $_FIRST_TASK" _LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no") echo "LAKE_INTRO: $_LAKE_SEEN" _TEL=$($GSTACK_BIN/gstack-config get telemetry 2>/dev/null || true) +case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac _TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no") _TEL_START=$(date +%s) _SESSION_ID="$$-$(date +%s)" -echo "TELEMETRY: ${_TEL:-off}" +echo "TELEMETRY: $_TEL" echo "TEL_PROMPTED: $_TEL_PROMPTED" _EXPLAIN_LEVEL=$($GSTACK_BIN/gstack-config get explain_level 2>/dev/null || echo "default") if [ "$_EXPLAIN_LEVEL" != "default" ] && [ "$_EXPLAIN_LEVEL" != "terse" ]; then _EXPLAIN_LEVEL="default"; fi diff --git a/test/gen-skill-docs.test.ts b/test/gen-skill-docs.test.ts index 2fb783ffd..d034c80bf 100644 --- a/test/gen-skill-docs.test.ts +++ b/test/gen-skill-docs.test.ts @@ -1867,6 +1867,8 @@ describe('Codex generation (--host codex)', () => { const content = fs.readFileSync(path.join(AGENTS_DIR, 'gstack-review', 'SKILL.md'), 'utf-8'); expect(content).toContain('GSTACK_ROOT'); expect(content).toContain('$_ROOT/.agents/skills/gstack'); + expect(content).toContain('[ -x "$_ROOT/.agents/skills/gstack/bin/gstack-config" ]'); + expect(content).not.toContain('[ -d "$_ROOT/.agents/skills/gstack" ]'); expect(content).toContain('$GSTACK_BIN/gstack-config'); expect(content).toContain('$GSTACK_ROOT/gstack-upgrade/SKILL.md'); expect(content).not.toContain('~/.codex/skills/gstack/bin/gstack-config get telemetry'); @@ -2316,6 +2318,7 @@ describe('setup script validation', () => { const fnBody = setupContent.slice(fnStart, fnEnd); expect(fnBody).toContain('.agents/skills'); expect(fnBody).toContain('gstack*'); + expect(fnBody).toContain('_gstack_skill_hidden'); }); test('link_claude_skill_dirs creates real directories with absolute SKILL.md symlinks', () => { @@ -2327,6 +2330,7 @@ describe('setup script validation', () => { expect(fnBody).toContain('mkdir -p "$target"'); // v1.36.0.0: routes through _link_or_copy helper for Windows fallback (cp on MSYS2/Git Bash). expect(fnBody).toContain('_link_or_copy "$gstack_dir/$dir_name/SKILL.md" "$target/SKILL.md"'); + expect(fnBody).toContain('_gstack_skill_hidden'); }); // REGRESSION: cleanup functions must handle both old symlinks AND new real-directory pattern @@ -2582,6 +2586,9 @@ describe('telemetry', () => { expect(content).toContain('TELEMETRY:'); expect(content).toContain('TEL_PROMPTED:'); expect(content).toContain('gstack-config get telemetry'); + expect(content).toContain('case "$_TEL" in community|anonymous) ;; *) _TEL="off" ;; esac'); + expect(content).toContain('echo "TELEMETRY: $_TEL"'); + expect(content).not.toContain('echo "TELEMETRY: ${_TEL:-off}"'); }); test('generated SKILL.md contains telemetry opt-in prompt', () => { diff --git a/test/relink.test.ts b/test/relink.test.ts index d83c4cd37..fc9f69813 100644 --- a/test/relink.test.ts +++ b/test/relink.test.ts @@ -113,6 +113,44 @@ describe('gstack-relink (#578)', () => { expect(output).toContain('flat'); }); + test('does not relink a skill listed in the visibility denylist', () => { + setupMockInstall(['context-save', 'qa']); + const hiddenFile = path.join(tmpDir, 'hidden-skills'); + fs.writeFileSync(hiddenFile, 'gstack-context-save\n'); + run(`${path.join(installDir, 'bin', 'gstack-config')} set skill_prefix true`, { + GSTACK_INSTALL_DIR: installDir, + GSTACK_SKILLS_DIR: skillsDir, + }); + + run(`${path.join(installDir, 'bin', 'gstack-relink')}`, { + GSTACK_INSTALL_DIR: installDir, + GSTACK_SKILLS_DIR: skillsDir, + GSTACK_HIDDEN_SKILLS_FILE: hiddenFile, + }); + + expect(fs.existsSync(path.join(skillsDir, 'gstack-context-save'))).toBe(false); + expect(fs.existsSync(path.join(skillsDir, 'gstack-qa'))).toBe(true); + }); + + test('visibility denylist also applies in no-prefix mode', () => { + setupMockInstall(['context-save', 'qa']); + const hiddenFile = path.join(tmpDir, 'hidden-skills'); + fs.writeFileSync(hiddenFile, 'gstack-context-save\n'); + run(`${path.join(installDir, 'bin', 'gstack-config')} set skill_prefix false`, { + GSTACK_INSTALL_DIR: installDir, + GSTACK_SKILLS_DIR: skillsDir, + }); + + run(`${path.join(installDir, 'bin', 'gstack-relink')}`, { + GSTACK_INSTALL_DIR: installDir, + GSTACK_SKILLS_DIR: skillsDir, + GSTACK_HIDDEN_SKILLS_FILE: hiddenFile, + }); + + expect(fs.existsSync(path.join(skillsDir, 'context-save'))).toBe(false); + expect(fs.existsSync(path.join(skillsDir, 'qa'))).toBe(true); + }); + // REGRESSION: unprefixed skills must be real directories, not symlinks (#761) // Claude Code auto-prefixes skills nested under a parent dir symlink. // e.g., `qa -> gstack/qa` gets discovered as "gstack-qa", not "qa".