mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-09 22:48:57 +02:00
fix(preamble): quoted tilde made Artifacts Sync and telemetry-finalize dead code in 49 skills
A tilde inside double quotes never expands, so the generated `_BRAIN_SYNC_BIN="~/..."` assignments resolved to a literal ./~ path and the Artifacts Sync + telemetry-finalize blocks silently no-op'd in every skill that carried them (regression of #785). The preamble resolvers now emit $HOME-based paths; all generated SKILL.md files regenerate identically from the fixed templates, and a static tripwire fails the suite if a quoted-tilde assignment ever reappears in generated output. Fixes #1656, #1715. Contributed by @jawadakram20 (PR #2333). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
3e7251a2e6
commit
e6dfc46e7a
@@ -28,6 +28,7 @@
|
||||
* to `gstack-brain-sync --discover-new` + `--once`.
|
||||
*/
|
||||
import type { TemplateContext } from '../types';
|
||||
import { quoteSafePath } from '../types';
|
||||
|
||||
export function generateBrainSyncBlock(ctx: TemplateContext): string {
|
||||
const isBrainHost = ctx.host === 'gbrain' || ctx.host === 'hermes';
|
||||
@@ -42,8 +43,8 @@ if [ -f "$HOME/.gstack-artifacts-remote.txt" ]; then
|
||||
else
|
||||
_BRAIN_REMOTE_FILE="$HOME/.gstack-brain-remote.txt"
|
||||
fi
|
||||
_BRAIN_SYNC_BIN="${ctx.paths.binDir}/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="${ctx.paths.binDir}/gstack-config"
|
||||
_BRAIN_SYNC_BIN="${quoteSafePath(ctx.paths.binDir)}/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="${quoteSafePath(ctx.paths.binDir)}/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style \`.gbrain-source\` in the
|
||||
@@ -152,8 +153,8 @@ If A/B and \`~/.gstack/.git\` is missing, ask whether to run \`gstack-artifacts-
|
||||
At skill END before telemetry:
|
||||
|
||||
\`\`\`bash
|
||||
"${ctx.paths.binDir}/gstack-brain-sync" --discover-new 2>/dev/null || true
|
||||
"${ctx.paths.binDir}/gstack-brain-sync" --once 2>/dev/null || true
|
||||
"${quoteSafePath(ctx.paths.binDir)}/gstack-brain-sync" --discover-new 2>/dev/null || true
|
||||
"${quoteSafePath(ctx.paths.binDir)}/gstack-brain-sync" --once 2>/dev/null || true
|
||||
\`\`\`
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { TemplateContext } from '../types';
|
||||
import { quoteSafePath } from '../types';
|
||||
import { getHostConfig } from '../../../hosts/index';
|
||||
|
||||
export function generatePreambleBash(ctx: TemplateContext): string {
|
||||
@@ -73,7 +74,7 @@ echo '{"skill":"${ctx.skillName}","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo"
|
||||
fi
|
||||
for _PF in $(find ~/.gstack/analytics -maxdepth 1 -name '.pending-*' 2>/dev/null); do
|
||||
if [ -f "$_PF" ]; then
|
||||
if [ "$_TEL" != "off" ] && [ -x "${ctx.paths.binDir}/gstack-telemetry-log" ]; then
|
||||
if [ "$_TEL" != "off" ] && [ -x "${quoteSafePath(ctx.paths.binDir)}/gstack-telemetry-log" ]; then
|
||||
${ctx.paths.binDir}/gstack-telemetry-log --event-type skill_run --skill _pending_finalize --outcome unknown --session-id "$_SESSION_ID" 2>/dev/null || true
|
||||
fi
|
||||
rm -f "$_PF" 2>/dev/null || true
|
||||
|
||||
@@ -16,6 +16,27 @@ export interface HostPaths {
|
||||
makePdfDir: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a host path safe to interpolate INSIDE DOUBLE QUOTES in generated bash.
|
||||
*
|
||||
* Tilde-based hosts (Claude, factory) resolve to paths like
|
||||
* `~/.claude/skills/gstack/bin`. Bash only performs tilde expansion when the
|
||||
* `~` is UNQUOTED, so `"~/.claude/..."` is a literal relative path that never
|
||||
* resolves. A `[ -x "~/..." ]` test is therefore always false and a
|
||||
* `"~/..." --flag` invocation always fails — the surrounding block silently
|
||||
* becomes dead code rather than erroring.
|
||||
*
|
||||
* Env-var hosts already use `$GSTACK_BIN`, which expands correctly when
|
||||
* quoted, so they pass through untouched.
|
||||
*
|
||||
* Use this ONLY where the path lands inside double quotes. Unquoted
|
||||
* interpolations (`${ctx.paths.binDir}/gstack-slug`) expand fine as-is and are
|
||||
* left alone so generated docs keep the more readable `~`.
|
||||
*/
|
||||
export function quoteSafePath(hostPath: string): string {
|
||||
return hostPath.startsWith('~/') ? `$HOME/${hostPath.slice(2)}` : hostPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* HOST_PATHS — derived from host configs.
|
||||
* Each config's globalRoot/localSkillRoot determines the path structure.
|
||||
|
||||
Reference in New Issue
Block a user