mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-18 19:02:18 +02:00
fix(setup-gbrain): invoke gstack-memory-ingest/gstack-gbrain-sync via bun run + .ts
/setup-gbrain's transcript-ingest steps told the agent to run bin/gstack-memory-ingest and bin/gstack-gbrain-sync by BARE name. Neither exists — only the .ts files ship (mode 644, no bin alias) — so the agent dutifully reported 'script missing at install root' and the ingest/full- sync steps dead-ended on every host (hit live under Codex; the Claude render carries the same text). All four template sites (probe, silent-bulk, post-answer full sync, the preamble-hook incremental mention) and the four memory.md reference-doc sites now use the repo's established form: 'bun run <path>/gstack-memory- ingest.ts …' / 'bun run <path>/gstack-gbrain-sync.ts …' — matching what sync-gbrain already does. Generated SKILL.md regenerated from the template in the same commit. Re-derived from PR #2409 by @SomSamantray per the wave's screening rule (the PR edited the generated SKILL.md directly; the generated file must come from gen:skill-docs). The contributor's structural test rides along as-is: bare-invocation regexes with negative .ts lookahead and backslash- continuation coverage pin every site, so the drift can't return. The referenced-paths ratchet in test/setup-claude-skill-assets.test.ts drops its two #2250 known-broken entries — the class-2 assertion now guards these paths again. Verified against #2250's site list (template lines 690/735/784-area, all covered) plus a fresh grep: zero bare invocations remain in the template or memory.md; the one prose mention ('gstack-memory-ingest now persists…') is not an invocation and stays. Fixes #2250 Fixes #2393 Co-authored-by: SomSamantray <SomSamantray@users.noreply.github.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
SomSamantray
Claude Fable 5
parent
e20c29f5c2
commit
d889453686
@@ -1503,7 +1503,7 @@ curated `~/.gstack/` artifacts into gbrain so the retrieval surface
|
|||||||
|
|
||||||
Run the probe to size the operation:
|
Run the probe to size the operation:
|
||||||
```bash
|
```bash
|
||||||
~/.claude/skills/gstack/bin/gstack-memory-ingest --probe
|
bun run ~/.claude/skills/gstack/bin/gstack-memory-ingest.ts --probe
|
||||||
```
|
```
|
||||||
|
|
||||||
Read the output. If `Total files in window: 0`, skip — there's nothing
|
Read the output. If `Total files in window: 0`, skip — there's nothing
|
||||||
@@ -1511,7 +1511,7 @@ to ingest. Set `gstack-config set transcript_ingest_mode incremental`
|
|||||||
silently and continue to Step 8.
|
silently and continue to Step 8.
|
||||||
|
|
||||||
If `New (never ingested)` is < 200 AND total bytes are < 100MB: silent
|
If `New (never ingested)` is < 200 AND total bytes are < 100MB: silent
|
||||||
bulk via `gstack-memory-ingest --bulk --quiet`. Set
|
bulk via `bun run ~/.claude/skills/gstack/bin/gstack-memory-ingest.ts --bulk --quiet`. Set
|
||||||
`transcript_ingest_mode=incremental` and continue.
|
`transcript_ingest_mode=incremental` and continue.
|
||||||
|
|
||||||
Otherwise (the "many transcripts on disk" path): AskUserQuestion with
|
Otherwise (the "many transcripts on disk" path): AskUserQuestion with
|
||||||
@@ -1548,14 +1548,14 @@ Options:
|
|||||||
After answer:
|
After answer:
|
||||||
```bash
|
```bash
|
||||||
~/.claude/skills/gstack/bin/gstack-config set transcript_ingest_mode <choice>
|
~/.claude/skills/gstack/bin/gstack-config set transcript_ingest_mode <choice>
|
||||||
~/.claude/skills/gstack/bin/gstack-gbrain-sync --full --no-brain-sync
|
bun run ~/.claude/skills/gstack/bin/gstack-gbrain-sync.ts --full --no-brain-sync
|
||||||
```
|
```
|
||||||
(`--no-brain-sync` because Step 7 already wired that path; this just
|
(`--no-brain-sync` because Step 7 already wired that path; this just
|
||||||
runs the code import + memory ingest stages. Brain-sync will run on the
|
runs the code import + memory ingest stages. Brain-sync will run on the
|
||||||
next preamble hook.)
|
next preamble hook.)
|
||||||
|
|
||||||
If A/D/E, ingest is incremental from this point on; preamble-boundary
|
If A/D/E, ingest is incremental from this point on; preamble-boundary
|
||||||
hook runs `gstack-gbrain-sync --incremental --quiet` on every skill
|
hook runs `bun run ~/.claude/skills/gstack/bin/gstack-gbrain-sync.ts --incremental --quiet` on every skill
|
||||||
start (cheap mtime fast-path).
|
start (cheap mtime fast-path).
|
||||||
|
|
||||||
Reference doc for users: `setup-gbrain/memory.md` (linked from CLAUDE.md
|
Reference doc for users: `setup-gbrain/memory.md` (linked from CLAUDE.md
|
||||||
|
|||||||
@@ -736,7 +736,7 @@ curated `~/.gstack/` artifacts into gbrain so the retrieval surface
|
|||||||
|
|
||||||
Run the probe to size the operation:
|
Run the probe to size the operation:
|
||||||
```bash
|
```bash
|
||||||
~/.claude/skills/gstack/bin/gstack-memory-ingest --probe
|
bun run ~/.claude/skills/gstack/bin/gstack-memory-ingest.ts --probe
|
||||||
```
|
```
|
||||||
|
|
||||||
Read the output. If `Total files in window: 0`, skip — there's nothing
|
Read the output. If `Total files in window: 0`, skip — there's nothing
|
||||||
@@ -744,7 +744,7 @@ to ingest. Set `gstack-config set transcript_ingest_mode incremental`
|
|||||||
silently and continue to Step 8.
|
silently and continue to Step 8.
|
||||||
|
|
||||||
If `New (never ingested)` is < 200 AND total bytes are < 100MB: silent
|
If `New (never ingested)` is < 200 AND total bytes are < 100MB: silent
|
||||||
bulk via `gstack-memory-ingest --bulk --quiet`. Set
|
bulk via `bun run ~/.claude/skills/gstack/bin/gstack-memory-ingest.ts --bulk --quiet`. Set
|
||||||
`transcript_ingest_mode=incremental` and continue.
|
`transcript_ingest_mode=incremental` and continue.
|
||||||
|
|
||||||
Otherwise (the "many transcripts on disk" path): AskUserQuestion with
|
Otherwise (the "many transcripts on disk" path): AskUserQuestion with
|
||||||
@@ -781,14 +781,14 @@ Options:
|
|||||||
After answer:
|
After answer:
|
||||||
```bash
|
```bash
|
||||||
~/.claude/skills/gstack/bin/gstack-config set transcript_ingest_mode <choice>
|
~/.claude/skills/gstack/bin/gstack-config set transcript_ingest_mode <choice>
|
||||||
~/.claude/skills/gstack/bin/gstack-gbrain-sync --full --no-brain-sync
|
bun run ~/.claude/skills/gstack/bin/gstack-gbrain-sync.ts --full --no-brain-sync
|
||||||
```
|
```
|
||||||
(`--no-brain-sync` because Step 7 already wired that path; this just
|
(`--no-brain-sync` because Step 7 already wired that path; this just
|
||||||
runs the code import + memory ingest stages. Brain-sync will run on the
|
runs the code import + memory ingest stages. Brain-sync will run on the
|
||||||
next preamble hook.)
|
next preamble hook.)
|
||||||
|
|
||||||
If A/D/E, ingest is incremental from this point on; preamble-boundary
|
If A/D/E, ingest is incremental from this point on; preamble-boundary
|
||||||
hook runs `gstack-gbrain-sync --incremental --quiet` on every skill
|
hook runs `bun run ~/.claude/skills/gstack/bin/gstack-gbrain-sync.ts --incremental --quiet` on every skill
|
||||||
start (cheap mtime fast-path).
|
start (cheap mtime fast-path).
|
||||||
|
|
||||||
Reference doc for users: `setup-gbrain/memory.md` (linked from CLAUDE.md
|
Reference doc for users: `setup-gbrain/memory.md` (linked from CLAUDE.md
|
||||||
|
|||||||
@@ -47,9 +47,9 @@ v1.33.0.0 — off by default. To re-enable it (adds ~4-8 min to cold runs
|
|||||||
on a large transcript corpus), use either:
|
on a large transcript corpus), use either:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
gstack-memory-ingest --bulk --scan-secrets
|
bun run bin/gstack-memory-ingest.ts --bulk --scan-secrets
|
||||||
# or
|
# or
|
||||||
GSTACK_MEMORY_INGEST_SCAN_SECRETS=1 gstack-memory-ingest --bulk
|
GSTACK_MEMORY_INGEST_SCAN_SECRETS=1 bun run bin/gstack-memory-ingest.ts --bulk
|
||||||
```
|
```
|
||||||
|
|
||||||
When enabled, gitleaks covers:
|
When enabled, gitleaks covers:
|
||||||
@@ -155,7 +155,7 @@ verdict block. If a row is RED, the row tells you what to do.
|
|||||||
Common cases:
|
Common cases:
|
||||||
|
|
||||||
- **Salience block is empty** — your transcripts may not be ingested
|
- **Salience block is empty** — your transcripts may not be ingested
|
||||||
yet. Run `gstack-gbrain-sync --full` to do a full pass.
|
yet. Run `bun run bin/gstack-gbrain-sync.ts --full` to do a full pass.
|
||||||
|
|
||||||
- **"gbrain CLI missing" in the preamble output** — gbrain isn't on
|
- **"gbrain CLI missing" in the preamble output** — gbrain isn't on
|
||||||
your PATH. Run `/setup-gbrain` to install/wire it.
|
your PATH. Run `/setup-gbrain` to install/wire it.
|
||||||
@@ -166,7 +166,7 @@ Common cases:
|
|||||||
--pglite && gbrain import <brain-remote-clone-dir>`.
|
--pglite && gbrain import <brain-remote-clone-dir>`.
|
||||||
|
|
||||||
- **A page has stale or wrong content** — `gbrain delete_page <slug>`,
|
- **A page has stale or wrong content** — `gbrain delete_page <slug>`,
|
||||||
then re-run `gstack-gbrain-sync --incremental` to re-ingest from
|
then re-run `bun run bin/gstack-gbrain-sync.ts --incremental` to re-ingest from
|
||||||
source if the source file is still on disk and unchanged.
|
source if the source file is still on disk and unchanged.
|
||||||
|
|
||||||
## Privacy + audit
|
## Privacy + audit
|
||||||
|
|||||||
@@ -43,11 +43,7 @@ const BUILT_ARTIFACT_ALLOWLIST = [
|
|||||||
* do not add entries without an issue + a scheduled fix.
|
* do not add entries without an issue + a scheduled fix.
|
||||||
*/
|
*/
|
||||||
const KNOWN_BROKEN_CLASS2: Record<string, string> = {
|
const KNOWN_BROKEN_CLASS2: Record<string, string> = {
|
||||||
// #2250: setup-gbrain's docs call both scripts by bare name; only the .ts
|
// (empty — #2250's bare bin names were the last entries; keep it that way)
|
||||||
// files exist. Fixed by the wave's c24 (PR #2409 re-derive) — remove these
|
|
||||||
// entries in that commit.
|
|
||||||
'bin/gstack-memory-ingest': '#2250 — fixed by setup-gbrain .ts invocation-path commit',
|
|
||||||
'bin/gstack-gbrain-sync': '#2250 — fixed by setup-gbrain .ts invocation-path commit',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Extract a named shell function body (through its closing brace) from setup. */
|
/** Extract a named shell function body (through its closing brace) from setup. */
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
// setup-gbrain bin invocation path lint.
|
||||||
|
//
|
||||||
|
// Pins the correct bun-run + .ts invocation form for gstack-memory-ingest
|
||||||
|
// and gstack-gbrain-sync wherever setup-gbrain's docs instruct the agent
|
||||||
|
// to run them. Regression coverage for #2393 / #2250: both scripts are
|
||||||
|
// .ts files with no package.json bin alias stripping the extension, so a
|
||||||
|
// bare name (no `bun run` prefix, no `.ts` suffix) fails with "No such
|
||||||
|
// file or directory" the moment an agent follows the doc literally.
|
||||||
|
//
|
||||||
|
// Why a structural test instead of a full Agent SDK E2E:
|
||||||
|
// - The failure is entirely in the prose an agent reads, not in
|
||||||
|
// runtime behavior a service test could exercise. A grep-based
|
||||||
|
// regression on the template/reference-doc text is fast (<200ms),
|
||||||
|
// free, and catches the same drift a full E2E would, without the
|
||||||
|
// token cost. Same rationale as test/setup-gbrain-path4-structure.test.ts.
|
||||||
|
// - The correct invocation form and the stale one differ only by
|
||||||
|
// `bun run ` + `.ts`, right next to each other in the same files —
|
||||||
|
// exactly the kind of drift a cheap structural check exists to catch,
|
||||||
|
// matching this repo's convention (e.g. test/memory-ingest-no-put_page.test.ts
|
||||||
|
// pinning fix #1346).
|
||||||
|
|
||||||
|
import { describe, test, expect } from 'bun:test';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
const ROOT = path.resolve(import.meta.dir, '..');
|
||||||
|
const TMPL = path.join(ROOT, 'setup-gbrain', 'SKILL.md.tmpl');
|
||||||
|
const MEMORY_DOC = path.join(ROOT, 'setup-gbrain', 'memory.md');
|
||||||
|
|
||||||
|
const tmpl = fs.readFileSync(TMPL, 'utf-8');
|
||||||
|
const memoryDoc = fs.readFileSync(MEMORY_DOC, 'utf-8');
|
||||||
|
|
||||||
|
// A "bare invocation" is the tool name immediately followed by a flag/arg
|
||||||
|
// with no `.ts` in between — the exact stale shape #2393/#2250 reported.
|
||||||
|
// The negative lookahead means `gstack-memory-ingest.ts --probe` (correct)
|
||||||
|
// does NOT match, while `gstack-memory-ingest --probe` (stale) does.
|
||||||
|
// `(?:\s|\\\r?\n)+` also spans a backslash line-continuation between the
|
||||||
|
// name and its flag (e.g. `gstack-memory-ingest \` newline ` --probe`),
|
||||||
|
// a style this same template already uses for other commands (see the
|
||||||
|
// read_secret_to_env invocation a few hundred lines up) — a plain `\s+`
|
||||||
|
// would miss a stale invocation reintroduced in that form.
|
||||||
|
const bareMemoryIngest = /\bgstack-memory-ingest\b(?!\.ts)(?:\s|\\\r?\n)+--/;
|
||||||
|
const bareGbrainSync = /\bgstack-gbrain-sync\b(?!\.ts)(?:\s|\\\r?\n)+--/;
|
||||||
|
|
||||||
|
describe('setup-gbrain/SKILL.md.tmpl — bin invocation paths', () => {
|
||||||
|
test('no bare gstack-memory-ingest invocation remains', () => {
|
||||||
|
expect(tmpl).not.toMatch(bareMemoryIngest);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('no bare gstack-gbrain-sync invocation remains', () => {
|
||||||
|
expect(tmpl).not.toMatch(bareGbrainSync);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('the probe step uses bun run + .ts (R1)', () => {
|
||||||
|
expect(tmpl).toContain(
|
||||||
|
'bun run ~/.claude/skills/gstack/bin/gstack-memory-ingest.ts --probe'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('the silent-bulk mention uses bun run + .ts (R2)', () => {
|
||||||
|
expect(tmpl).toContain(
|
||||||
|
'bun run ~/.claude/skills/gstack/bin/gstack-memory-ingest.ts --bulk --quiet'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('the post-answer full-sync step uses bun run + .ts (R3)', () => {
|
||||||
|
expect(tmpl).toContain(
|
||||||
|
'bun run ~/.claude/skills/gstack/bin/gstack-gbrain-sync.ts --full --no-brain-sync'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('the preamble-hook incremental-sync mention uses bun run + .ts (R4)', () => {
|
||||||
|
expect(tmpl).toContain(
|
||||||
|
'bun run ~/.claude/skills/gstack/bin/gstack-gbrain-sync.ts --incremental --quiet'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('the neighboring gstack-config line in the post-answer block is untouched (bash script, no extension)', () => {
|
||||||
|
expect(tmpl).toContain(
|
||||||
|
'~/.claude/skills/gstack/bin/gstack-config set transcript_ingest_mode <choice>'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('the prose-only mention naming the tool as a sentence subject is left unchanged (KTD4 — not a literal invocation)', () => {
|
||||||
|
expect(tmpl).toContain('gstack-memory-ingest now persists staged transcripts to');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('setup-gbrain/memory.md — bin invocation paths', () => {
|
||||||
|
test('no bare gstack-memory-ingest invocation remains', () => {
|
||||||
|
expect(memoryDoc).not.toMatch(bareMemoryIngest);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('no bare gstack-gbrain-sync invocation remains', () => {
|
||||||
|
expect(memoryDoc).not.toMatch(bareGbrainSync);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('the secret-scanning example uses bun run + .ts (R5)', () => {
|
||||||
|
expect(memoryDoc).toContain('bun run bin/gstack-memory-ingest.ts --bulk --scan-secrets');
|
||||||
|
expect(memoryDoc).toContain(
|
||||||
|
'GSTACK_MEMORY_INGEST_SCAN_SECRETS=1 bun run bin/gstack-memory-ingest.ts --bulk'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('the troubleshooting full-pass mention uses bun run + .ts (R5)', () => {
|
||||||
|
expect(memoryDoc).toContain('Run `bun run bin/gstack-gbrain-sync.ts --full` to do a full pass.');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('the troubleshooting incremental-reingest mention uses bun run + .ts (R5)', () => {
|
||||||
|
expect(memoryDoc).toContain(
|
||||||
|
're-run `bun run bin/gstack-gbrain-sync.ts --incremental` to re-ingest from'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('the already-correct reference line at the top of the file is unchanged', () => {
|
||||||
|
expect(memoryDoc).toContain('bun run bin/gstack-memory-ingest.ts --probe` (which');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('bare-invocation regex — backslash line-continuation coverage', () => {
|
||||||
|
// This template writes multi-line commands with a trailing backslash
|
||||||
|
// continuation elsewhere (e.g. the read_secret_to_env invocation), so a
|
||||||
|
// stale invocation reintroduced in that same style must still be caught.
|
||||||
|
test('catches a bare invocation split across a backslash continuation', () => {
|
||||||
|
const staleContinuation = 'gstack-memory-ingest \\\n --probe';
|
||||||
|
expect(staleContinuation).toMatch(bareMemoryIngest);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('does not flag a correct invocation split across a backslash continuation', () => {
|
||||||
|
const fixedContinuation = 'bun run bin/gstack-gbrain-sync.ts \\\n --incremental';
|
||||||
|
expect(fixedContinuation).not.toMatch(bareGbrainSync);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user