Improve `sentry init` runtime harness with Dirac-inspired patterns
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 25/100
- Tipo de issue
- Nueva funcionalidad
- Claridad
- Bastante claro
- Estado de actividad
- Tranquilo
- Stack tecnológico
- bun, typescript
- Área
- cli, developer-experience, tooling
Línea de trabajo
Empieza con el orden de build recomendado, comenzando por src/lib/init/local-ops.ts y src/lib/init/types.ts, y ejecuta las pruebas específicas de cada fase indicadas en Verification. Revisa los archivos AST mencionados y wizard-runner.ts antes de abordar las fases posteriores. Se considera terminado cuando pasan las pruebas de fase, el comando de integración, build, typecheck, lint y la suite completa.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Summary
Adopt three patterns from the Dirac coding agent to strengthen the sentry init local runtime:
- Content hashing (from
line-hashing.ts) — FNV-1a file hashing for stale-read detection - Atomic patchsets with rollback (simplified from
CheckpointTracker) — in-memory backup before writes - Tree-sitter AST infrastructure (from
services/tree-sitter/) — WASM-based code parsing for local framework detection, entry point discovery, and post-patch syntax validation
What We're NOT Picking
- Hash-anchored line edits: Requires Mastra protocol changes (server must produce hash-referenced diffs). Out of scope.
- React Ink TUI: We use Stricli + @clack/prompts. Different paradigm.
- Full eval harness: The Dirac eval system is benchmark-focused, not applicable.
Phase 1: Content Hashing & Staleness Detection (no new deps)
Goal: Detect when files change between read-files and apply-patchset operations.
New file: src/lib/init/content-hash.ts
fnv1a(content: string): string— FNV-1a 32-bit hash → 8-char hex (5 lines, from Dirac'sline-hashing.ts)FileSnapshottype —Map<string, string>of path→hashcreateSnapshot(),recordFile(),isStale()helpers
Modify: src/lib/init/local-ops.ts
- Add module-scoped
FileSnapshotinstance, reset per wizard run - In
readFiles(): record content hash for each file after reading - In
applyEdits(): before applying edits, re-read the file and check staleness. If stale,log.warn()but continue (the fuzzy replacer may still succeed) - Return
contentHashesin theread-filesresult data so the Mastra workflow can optionally use it later
Modify: src/lib/init/types.ts
- Add optional
contentHashes?: Record<string, string>to read-files result shape
New tests
test/lib/init/content-hash.test.ts— basic hash consistencytest/lib/init/content-hash.property.test.ts— determinism, collision resistance
Phase 2: Atomic Patchsets with Rollback (no new deps)
Goal: If any patch in a patchset fails, restore all previously-applied files.
Modify: src/lib/init/local-ops.ts
Restructure applyPatchset() with in-memory backup:
type FileBackup =
| { type: 'existed'; path: string; absPath: string; content: string }
| { type: 'created'; path: string; absPath: string };
- Before each patch: snapshot the file's current content (or record it as nonexistent)
- On failure: restore all backups in reverse order (write-back for modify/delete, unlink for create)
- On success: discard backups
Why in-memory, not git stash?
git stashhas side effects on user's stash stack- The wizard already checks for clean git state in
git.ts— users cangit checkout .for ultimate recovery - Patchsets are small (typically <10 files, <100KB total)
Modify: src/lib/init/types.ts
- Add
rolledBack?: booleanandrollbackErrors?: string[]toLocalOpResult
New test: test/lib/init/local-ops-rollback.test.ts
- 3-patch patchset where patch #3 fails → verify patches #1 and #2 rolled back
- Modify + rollback restores original content
- Create + rollback deletes the file
Phase 3: Tree-sitter AST Infrastructure
Goal: Add WASM-based tree-sitter parsing, lazy-loaded and cached.
New dependency
bun add -d web-tree-sitter
NOT adding tree-sitter-wasms as a dependency. Grammar WASMs downloaded on demand (~250-810KB each, cached in ~/.sentry/grammars/). The web-tree-sitter JS runtime (~60KB) bundles via esbuild. Its WASM runtime (~2.5MB) is also downloaded on demand alongside grammars.
New file: src/lib/ast/parser.ts
Adapted from Dirac's languageParser.ts:
EXTENSION_TO_LANGUAGEmap —.js→javascript,.ts→typescript,.tsx→tsx,.py→python,.go→go,.rb→ruby,.php→php,.java→javagetParser(language)— lazy init of web-tree-sitter, loads grammar WASM on demandparseFile(content, filePath)— returnsParser.Tree | nullisAstSupported(filePath)— extension check- Two-level cache: language→Parser cache + grammar→WASM cache (same as Dirac)
New file: src/lib/ast/grammar-loader.ts
ensureGrammar(language)— checks~/.sentry/grammars/<version>/, downloads from CDN if missingensureRuntime()— same for thetree-sitter.wasmruntime- CDN source: unpkg.com or GitHub-hosted (configurable)
- Downloads use
fetch()with timeout, write viaBun.write()
New file: src/lib/ast/queries.ts
S-expression queries per language, inspired by Dirac's queries/ directory:
type FrameworkSignal = {
framework: string; // 'nextjs', 'express', 'django', etc.
confidence: number; // 0.0–1.0
evidence: string; // human-readable
file: string;
line: number;
};
type EntryPoint = {
file: string;
line: number;
kind: 'server-start' | 'app-export' | 'main-function' | 'sdk-init';
pattern: string;
};
Functions: detectFramework(), findEntryPoints(), findSentryConfig(), generateOutline()
New file: src/lib/ast/errors.ts
AstError extends CliError— for grammar load failures, parse errors
New file: src/lib/ast/index.ts
Barrel re-export.
Build impact
web-tree-sitterJS: ~60KB bundled (esbuild handles it)- WASM runtime: NOT bundled, downloaded on demand (~2.5MB, cached)
- Grammar WASMs: NOT bundled, downloaded on demand (~250-810KB each, cached)
- Net binary size increase: ~60KB (just the JS loader)
New test: test/lib/ast/parser.test.ts
- Mock grammar download, parse a JS fixture, verify tree exists
- Unsupported extension returns null
Phase 4: AST-Based Intelligence for Init
Goal: Use tree-sitter to send richer context to the Mastra workflow.
New file: src/lib/init/ast-context.ts
type ProjectAstContext = {
frameworks: FrameworkSignal[];
entryPoints: EntryPoint[];
existingSentry: SentryConfig[];
fileOutlines: Record<string, string>;
};
async function buildProjectAstContext(
cwd: string,
dirListing: DirEntry[]
): Promise<ProjectAstContext | null>
File selection heuristic (scan a targeted subset, not the whole tree):
- Known entry point filenames:
src/index.ts,src/app.ts,app.py,manage.py,main.go,pages/_app.tsx,app/layout.tsx,next.config.js, etc. - Files matching
*sentry* - Fallback: first 5 source files in
dirListing
Modify: src/lib/init/wizard-runner.ts
After precomputeDirListing(), before run.startAsync():
let astContext = null;
try {
const { buildProjectAstContext } = await import("./ast-context.js");
astContext = await buildProjectAstContext(directory, dirListing);
} catch {
// AST unavailable — continue without it
}
Pass astContext in inputData to the workflow.
New local-op: parse-files
Register as a new operation type in local-ops.ts for the Mastra workflow to request on-demand AST analysis.
Modify: src/lib/init/types.ts
- Add
ParseFilesPayloadtype - Add to
LocalOpPayloadunion
Phase 5: AST Validation of Applied Patches
Goal: Verify modified files are syntactically valid after patching.
New file: src/lib/init/ast-validation.ts
type ValidationResult = {
valid: boolean;
errors: Array<{ line: number; column: number; message: string }>;
};
async function validateSyntax(content: string, filePath: string): Promise<ValidationResult>
Implementation: parse with tree-sitter, walk CST for ERROR/MISSING nodes.
Modify: src/lib/init/local-ops.ts
In applySinglePatch() after writing a modify patch:
const result = await validateSyntax(content, patch.path);
if (!result.valid) {
log.warn(`Syntax issues in ${patch.path}: ${result.errors.length} error(s)`);
}
Advisory only (warn, don't fail). Validation errors are included in the patchset result metadata so the Mastra workflow can decide whether to retry.
Recommended Build Order
Phase 1 (content hashing) ─── 1 day, no deps, immediate value
↓
Phase 2 (atomic rollback) ─── 1.5 days, no deps, immediate value
↓
Phase 3 (tree-sitter infra) ─── 3-4 days, adds web-tree-sitter
↓
Phase 4 (AST intelligence) ─── 3-4 days, uses Phase 3
↓
Phase 5 (AST validation) ─── 2 days, uses Phase 3
Phases 1-2 are dependency-free quick wins. Phase 3 is the risky foundation. Phases 4-5 build on it.
Total: ~11-13 days
Key Files Modified
| File | Phase | Change |
|---|---|---|
src/lib/init/local-ops.ts |
1,2,4 | Content hashing, atomic rollback, parse-files handler |
src/lib/init/types.ts |
1,2,4 | New payload types, result fields |
src/lib/init/wizard-runner.ts |
4 | Pass astContext to workflow |
package.json |
3 | Add web-tree-sitter devDependency |
Key Files Created
| File | Phase |
|---|---|
src/lib/init/content-hash.ts |
1 |
src/lib/ast/parser.ts |
3 |
src/lib/ast/grammar-loader.ts |
3 |
src/lib/ast/queries.ts |
3 |
src/lib/ast/errors.ts |
3 |
src/lib/ast/index.ts |
3 |
src/lib/init/ast-context.ts |
4 |
src/lib/init/ast-validation.ts |
5 |
Risks
| Risk | Level | Mitigation |
|---|---|---|
web-tree-sitter WASM loading in Bun compiled binary |
High | Download WASM on demand (not embedded). Test early in Phase 3. |
| Grammar CDN unreliable | Medium | Host grammars on GitHub Releases or bundle JS/TS grammars as fallback (~2MB) |
| Tree-sitter adds complexity for limited init-specific value | Medium | Phases 1-2 deliver value without tree-sitter. AST phases are additive, not critical path. |
Mastra workflow ignores astContext initially |
Low | Context is advisory — server can adopt it incrementally. Local value (validation) is standalone. |
Verification
- Phase 1:
bun test test/lib/init/content-hash— property tests pass - Phase 2:
bun test test/lib/init/local-ops-rollback— rollback tests pass - Phase 3:
bun test test/lib/ast/parser— JS/TS parsing works - Phase 4:
bun test test/lib/init/ast-context— framework detection returns signals - Phase 5:
bun test test/lib/init/ast-validation— catches broken syntax - Integration:
bun run dev -- init ./test-project --dry-run— wizard completes with AST context - Build:
bun run build— binary size increase < 100KB (only JS loader bundled) - Full suite:
bun run typecheck && bun run lint && bun test
- Lenguaje dominante
- TypeScript
- Estrellas
- 121
- Forks
- 14
- Merge medio
- 22 h 3 min
- PR fusionados (30 d)
- 94
Guía de contribución
No hay ninguna guía de contribución indexada para este repositorio
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de getsentry/cli
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
-
Dificultad 3/5 1-2 días Aptitud para principiantes 68/100
-
Dificultad 3/5 1-2 días Aptitud para principiantes 65/100
-
bug jared
-
jared
Dificultad 4/5 3-5 días Aptitud para principiantes 52/100
Todos los issues de getsentry/cli
Issues similares
-
S: triage
Dificultad 1/5 Menos de una hora Aptitud para principiantes 85/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
-
fix(errors): EHOSTUNREACH from a happy-eyeballs connect is reported as a resolver error (STAMP-80) Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 90/100
snapshot-labs/stamp#666 ·
-
fix(api): prevent leaderboard SSE heartbeat from starting after disconnect during initial load Abiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
GauravKarakoti/SecureFlow#1070 · 1 comentario ·
-
comp/desktop P3 type/bug
Dificultad 1/5 Menos de una hora Aptitud para principiantes 92/100
NousResearch/hermes-agent#118866 ·