This commit is contained in:
mant1st 2026-07-14 19:16:22 -07:00 committed by GitHub
commit 4331ae6d96
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
64 changed files with 438 additions and 146 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 <title-fragment-or-number>` → 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.

View File

@ -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 <title-fragment-or-number>` → 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.

View File

@ -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`, чтобы сохранить текущее рабочее состояние."
---

View File

@ -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`, чтобы сохранить текущее рабочее состояние."
---

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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": {

View File

@ -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

23
setup
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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('ВОССТАНОВЛЕНИЕ КОНТЕКСТА');
});
}
});

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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', () => {

View File

@ -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".