Dashboard › craft › Session 0KwOn8srOYSu
0KwOn8srOYSuylGb8Read-only research only. Inspect /home/byk/Code/getsentry/cli for its directory-walking and workspace-discovery implementation suitable for reuse by Craft PR #872. Identify exact modules, algorithms/contracts (globs, ignores, symlink handling, path normalization, validation), dependencies, public APIs, and test coverage, with file:line citations. Compare conceptually to Craft's current workspace resolver only if you need to read it; do not modify either repository. Return concise recommendation: directly reuse/extract/adapt vs keep Craft implementation, including compatibility/security risks.
<path>/home/byk/Code/getsentry/cli</path> <type>directory</type> <entries> .craft.yml .env.local .git/ .github/ .gitignore .lore.md .node-cache/ .nojekyll .npmrc .opencode/ .ruff_cache/ AGENTS.md apps/ CHANGELOG.md codemods/ coverage-isolated/ coverage/ dist-bin/ dist-build/ dist/ docs/ LICENSE.md node_modules/ package.json packages/ pnpm-lock.yaml pnpm-workspace.yaml README.md test-results.junit.xml test/ (30 entries) </entries>
<path>/home/byk/Code/getsentry/cli/AGENTS.md</path> <type>file</type> <content> 1: # Jared (Outpost agent) 2: 3: Autonomous GitHub coding agent. Work in `/workspace/repo`. 4: 5: ## Model tiers 6: 7: The primary model is chosen per event (see `src/agents/models.ts`): heavy for 8: code-producing situations, cheaper for lightweight ones. 9: 10: | Role | Subagent | Model | 11: | --- | --- | --- | 12: | Triage / plan / review (heavy) | (primary Jared) | Claude Opus 4.8 | 13: | Triage / plan / review (light) | (primary Jared) | xAI Grok 4.3 | 14: | Explore | `explore` | OpenAI gpt-5-mini | 15: | Implement | `implement` | Moonshot kimi-k2.7-code | 16: | Ship (commit/push/PR) | `ship` | xAI Grok (`grok-build-0.1`) | 17: 18: Pipeline: triage → explore → plan → implement → review → ship. 19: (`worker` is a deprecated alias of `implement`.) 20: 21: Operators also talk to Jared directly from the Outpost dashboard. ...
/home/byk/Code/getsentry/cli/.gitignore /home/byk/Code/getsentry/cli/pnpm-workspace.yaml /home/byk/Code/getsentry/cli/packages/cli/.gitignore /home/byk/Code/getsentry/cli/codemods/sentry-v3-to-v4/.gitignore /home/byk/Code/getsentry/cli/packages/cli/test/init-eval/templates/sveltekit-app/.gitignore /home/byk/Code/getsentry/cli/packages/cli/test/init-eval/templates/react-vite-app/.gitignore /home/byk/Code/getsentry/cli/packages/cli/test/init-eval/templates/python-flask-app/.gitignore /home/byk/Code/getsentry/cli/packages/cli/test/init-eval/templates/python-fastapi-app/.gitignore /home/byk/Code/getsentry/cli/packages/cli/src/lib/global-flags.ts /home/byk/Code/getsentry/cli/packages/cli/src/lib/walk-up.ts /home/byk/Code/getsentry/cli/packages/cli/test/init-eval/templates/nextjs-app/.gitignore /home/byk/Code/getsentry/cli/packages/cli/test/lib/global-flags.test.ts /home/byk/Code/getsentry/cli/packages/cli/src/lib/scan/glob.ts /home/byk/Code/getsentry/cli/packages/cli/src/lib/scan/walker.ts ...
<path>/home/byk/Code/getsentry/cli/packages/cli/src/lib/scan/walker.ts</path> <type>file</type> <content> 1: /** 2: * Streaming DFS directory walker with time-budgeted exploration. 3: * 4: * ### Contract 5: * 6: * `walkFiles(opts)` returns an `AsyncIterable<WalkEntry>` yielding one 7: * entry per regular file under `opts.cwd`. Directories are traversed 8: * but never yielded. Symbolic links are skipped unless 9: * `followSymlinks: true`. Paths are POSIX-normalized. 10: * 11: * ### Depth + time budget 12: * 13: * The walker visits every directory at depth ≤ `minDepth` regardless 14: * of wall-clock — that's the exhaustive-scan guarantee. Beyond 15: * `minDepth`, each candidate descent is gated on 16: * `clock() - startedAt ≤ timeBudgetMs`. When the budget is blown, 17: * already-queued directories at any depth still drain (their contents 18: * are yielded) but no new dirs at `depth > minDepth` are pushed. 19: * 20: * Traversal is DFS. ...
<path>/home/byk/Code/getsentry/cli/packages/cli/src/lib/scan/walker.ts</path>
<type>file</type>
<content>
225: async function* walkFilesImpl(opts: WalkOptions): AsyncGenerator<WalkEntry> {
226: const cfg = normalizeOptions(opts);
227: const matcher = await buildMatcher(cfg);
228: const stats: WalkStats = {
229: filesYielded: 0,
230: dirsVisited: 0,
231: filesSkippedBySize: 0,
232: filesSkippedByBinary: 0,
233: hitTimeBudget: false,
234: maxDepthReached: 0,
235: };
236: const startedAt = cfg.clock();
237: const visitedInodes = new Set<string>();
238: // Seed the root's inode so a descendant symlink pointing back at the scan
239: // root is treated as a cycle. The root frame is pushed directly (below)
240: // rather than through `maybeDescend`, which is the only place inodes are
241: // otherwise recorded — so without this seed a symlink → root would re-list
242: // the root's entire subtree under a second path prefix. ...
<path>/home/byk/Code/getsentry/cli/packages/cli/src/lib/scan/walker.ts</path>
<type>file</type>
<content>
540: /**
541: * Process a single directory entry: skip / descend / yield.
542: *
543: * Extracted from the generator body purely to keep cognitive complexity
544: * under Biome's ceiling. Mutates `ctx.stats`, pushes directories onto
545: * `ctx.stack`, and returns a `WalkEntry` when a file should be yielded.
546: */
547: // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: filter cascade (hidden, symlink, dir, file, ignore, ext) is inherently branchy
548: async function processEntry(
549: entry: Dirent,
550: frame: DirFrame,
551: ctx: WalkContext
552: ): Promise<WalkEntry | null> {
553: const { cfg, matcher } = ctx;
554: if (!cfg.hidden && entry.name.startsWith(".")) {
555: return null;
556: }
557: if (entry.isSymbolicLink() && !cfg.followSymlinks) {
558: return null;
559: }
560: // String-concat `abs` rather than `path.join` — measured ...
<path>/home/byk/Code/getsentry/cli/packages/cli/src/lib/scan/ignore.ts</path> <type>file</type> <content> 1: /** 2: * IgnoreStack — per-directory `.gitignore` aggregation for the scanner. 3: * 4: * ### Why a stack of instances 5: * 6: * The `ignore` npm package implements one `.gitignore`-file's semantics 7: * (last-matching rule wins inside that file, negations with `!`, etc.). 8: * It does NOT know about nested `.gitignore` files. 9: * 10: * Real git treats nested `.gitignore` files cumulatively: parent rules 11: * apply inside every subtree, and child `.gitignore` files can add new 12: * rules that apply only in their subtree (including negations that 13: * un-ignore something a parent had ignored). See `gitignore(5)`. 14: * 15: * To match that semantics we keep a `Map<relDir, Ignore>` of per-dir 16: * `.gitignore` contents. ...
<path>/home/byk/Code/getsentry/cli/packages/cli/src/lib/scan/glob.ts</path>
<type>file</type>
<content>
1: /**
2: * Pure-TS glob engine built on top of `walkFiles`.
3: *
4: * Accepts one or more glob patterns (picomatch syntax) and yields
5: * files under `cwd` matching at least one `patterns` entry and no
6: * `exclude` entry. Matching uses the `picomatch` package.
7: *
8: * ### Pattern semantics
9: *
10: * - Patterns with a `/` are matched against the POSIX-normalized
11: * relative path (e.g., `src/*.ts` only matches files directly in
12: * `src/`).
13: * - Patterns without a `/` are matched against just the basename
14: * (e.g., `*.ts` matches `any/dir/x.ts`).
15: * - `dot: true` — the matcher accepts dotfiles, matching the
16: * walker's default `hidden: true`.
17: * - `**` spans directory boundaries.
18: *
19: * Uses picomatch's full grammar: extglobs (`+(a|b)`), braces
20: * (`{a,b}`), negation (`!pattern`), etc. ...
/home/byk/Code/getsentry/cli/packages/cli/src/lib/scan/types.ts /home/byk/Code/getsentry/cli/packages/cli/src/lib/scan/path-utils.ts /home/byk/Code/getsentry/cli/packages/cli/src/lib/scan/index.ts /home/byk/Code/getsentry/cli/packages/cli/src/lib/scan/constants.ts
<path>/home/byk/Code/getsentry/cli/packages/cli/src/lib/scan/types.ts</path>
<type>file</type>
<content>
1: /**
2: * Public types for the scan module.
3: *
4: * The walker and ignore stack share a small contract defined here; the
5: * types are intentionally narrow for PR 1 (walker-only). PR 2 will add
6: * `GrepOptions` / `GrepMatch` / `GrepResult` on top.
7: */
8:
9: /**
10: * A single filesystem entry yielded by `walkFiles`. Always a regular file —
11: * directories are traversed but never yielded, and symbolic links are
12: * skipped unless `followSymlinks: true` is set on the walker.
13: *
14: * Paths are POSIX-normalized (`/`-separated) on all platforms.
15: */
16: export type WalkEntry = {
17: /** Absolute path on disk. Native separators. */
18: absolutePath: string;
19: /**
20: * POSIX-normalized path relative to `WalkOptions.cwd`.
21: * Does not start with `./`. Does not end with `/`.
22: */
23: relativePath: string;
24: /** Size in bytes. ...
<path>/home/byk/Code/getsentry/cli/packages/cli/src/lib/scan/path-utils.ts</path>
<type>file</type>
<content>
1: /**
2: * Internal path + pattern utilities shared by the grep and glob
3: * engines. Not part of the public barrel — implementation details
4: * factored out to prevent drift between the two engines.
5: */
6:
7: import path from "node:path";
8: import picomatch from "picomatch";
9:
10: /**
11: * A precompiled glob matcher. We cache whether the pattern is
12: * "path-mode" (tested against the relative path, e.g. `src/*.ts`)
13: * vs "basename-mode" (tested against just the file's basename, e.g.
14: * `*.ts`) so the per-file call skips the `pattern.includes("/")` check
15: * every time.
16: *
17: * Matches the init-wizard's fs-fallback heuristic and ripgrep's
18: * `--glob` semantics: patterns with `/` anchor to the relative path
19: * from cwd, patterns without `/` match the basename anywhere. ...
<path>/home/byk/Code/getsentry/cli/packages/cli/src/lib/scan/index.ts</path>
<type>file</type>
<content>
1: // biome-ignore-all lint/performance/noBarrelFile: intentional public API
2: /**
3: * Scan module — pure-TS ripgrep-compatible file scanner.
4: *
5: * PR 1 exports the file-walking foundation. PR 2 adds the grep and
6: * glob engines (`grepFiles`, `globFiles` + collect helpers). PR 3
7: * will migrate the DSN scanner to this module.
8: *
9: * @example
10: * ```ts
11: * import { walkFiles, TEXT_EXTENSIONS } from "./lib/scan/index.js";
12: *
13: * for await (const entry of walkFiles({ cwd, extensions: TEXT_EXTENSIONS })) {
14: * if (!entry.isBinary) console.log(entry.relativePath);
15: * }
16: * ```
17: *
18: * @example
19: * ```ts
20: * import { collectGrep } from "./lib/scan/index.js";
21: *
22: * const { matches, stats } = await collectGrep({
23: * cwd: "/path/to/repo",
24: * pattern: "(?i)TODO",
25: * include: "*.ts",
26: * maxResults: ...
<path>/home/byk/Code/getsentry/cli/packages/cli/src/lib/scan/constants.ts</path>
<type>file</type>
<content>
1: /**
2: * Shared constants for the `scan` module.
3: *
4: * These values are deliberately policy-free defaults for a general-purpose
5: * scanner. Callers that need stricter DSN-style filtering should spread
6: * `DSN_ADDITIONAL_SKIP_DIRS` into their `alwaysSkipDirs` option.
7: *
8: * Single source of truth: `src/lib/dsn/code-scanner.ts` previously owned
9: * `TEXT_EXTENSIONS`, `MAX_FILE_SIZE`, `CONCURRENCY_LIMIT`, `normalizePath`,
10: * and `isMonorepoPackageDir`. Once PR 3 lands, `code-scanner.ts` re-imports
11: * from here instead of duplicating.
12: */
13:
14: import { availableParallelism } from "node:os";
15: import path from "node:path";
16: // Re-exported below so scan callers don't have to reach into `dsn/`.
17: import { MONOREPO_ROOTS as DSN_MONOREPO_ROOTS } from "../dsn/types.js";
18:
19: /**
20: * File extensions the walker classifies as text without ...
<path>/home/byk/Code/getsentry/cli/packages/cli/package.json</path>
<type>file</type>
<content>
1: {
2: "name": "sentry",
3: "version": "0.44.0-dev.0",
4: "description": "Sentry CLI - A command-line interface for using Sentry built by robots and humans for robots and humans",
5: "repository": {
6: "type": "git",
7: "url": "git+https://github.com/getsentry/cli.git"
8: },
9: "main": "./dist/index.cjs",
10: "type": "module",
11: "types": "./dist/index.d.cts",
12: "exports": {
13: ".": {
14: "import": {
15: "types": "./dist/index.d.mts",
16: "default": "./dist/index.mjs"
17: },
18: "require": {
19: "types": "./dist/index.d.cts",
20: "default": "./dist/index.cjs"
21: }
22: }
23: },
24: "bin": {
25: "sentry": "./dist/bin.cjs"
26: },
27: "files": [
28: "dist/bin.cjs",
29: "dist/index.cjs",
30: "dist/index.mjs",
31: "dist/index.d.cts",
32: "dist/index.d.mts",
33: ...
Found 3 matches /home/byk/Code/getsentry/cli/packages/cli/src/lib/dsn/parser.ts: Line 222: * The fingerprint uniquely identifies the set of projects detected in a workspace. /home/byk/Code/getsentry/cli/packages/cli/src/lib/dsn/env-file.ts: Line 216: // symlinks too — pnpm/Yarn workspaces can symlink packages, and /home/byk/Code/getsentry/cli/packages/cli/src/lib/detect-agent.ts: Line 135: // workspaces, not just when the AI agent is driving the CLI
<path>/home/byk/Code/getsentry/cli/packages/cli/test/lib/scan/walker.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Unit tests for `walkFiles` in `src/lib/scan/walker.ts`.
3: *
4: * Each test builds a small sandbox under `tmpdir()`, runs the walker
5: * with specific options, and asserts the yielded relative paths (order
6: * doesn't matter — we compare via Set).
7: *
8: * Time-budget tests inject a mock clock so we can verify the min-depth
9: * guarantee without flaky wall-clock dependencies.
10: */
11:
12: import {
13: mkdirSync,
14: mkdtempSync,
15: rmSync,
16: symlinkSync,
17: writeFileSync,
18: } from "node:fs";
19: import { tmpdir } from "node:os";
20: import { join } from "node:path";
21: import { afterAll, describe, expect, test } from "vitest";
22: import type { WalkEntry } from "../../../src/lib/scan/types.js";
23: import { walkFiles } from "../../../src/lib/scan/walker.js";
24:
25: const ROOT = mkdtempSync(join(tmpdir(), ...
<path>/home/byk/Code/getsentry/cli/packages/cli/test/lib/scan/glob.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Unit tests for `src/lib/scan/glob.ts` (`globFiles`, `collectGlob`).
3: *
4: * Pin down the picomatch-backed semantics the init wizard's
5: * fs-fallback (and rg) expose:
6: *
7: * - `*.ts` (no `/`) matches basename anywhere in tree.
8: * - `src/*.ts` (with `/`) matches against the relative path.
9: * - `**\/*.ts` matches `.ts` anywhere.
10: * - Multiple patterns OR.
11: * - `exclude` suppresses.
12: * - `maxResults` caps + sets `truncated: true`.
13: * - `path` narrows the walk root and yields cwd-relative paths.
14: */
15:
16: import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
17: import { tmpdir } from "node:os";
18: import { join } from "node:path";
19: import { afterAll, describe, expect, test } from "vitest";
20: import { collectGlob } from "../../../src/lib/scan/glob.js";
21:
22: const ROOT = ...
<path>/home/byk/Code/getsentry/cli/packages/cli/test/lib/scan/ignore.test.ts</path> <type>file</type> <content> 1: /** 2: * Unit tests for `src/lib/scan/ignore.ts` (IgnoreStack). 3: * 4: * Pins the semantics we care about most: 5: * 6: * 1. A single root `.gitignore` behaves like a plain `ignore` instance. 7: * 2. `alwaysSkipDirs` basenames are skipped even when no `.gitignore` 8: * mentions them (basename-anywhere semantics). 9: * 3. Nested `.gitignore` files apply ON TOP OF parent patterns — 10: * cumulative, root→leaf, with child negations overriding parents. 11: * 4. `.git/info/exclude` is treated as an additional root `.gitignore` 12: * when requested. 13: * 5. Malformed inputs (absolute paths, empty relPath) are handled 14: * gracefully. ...
<path>/home/byk/Code/getsentry/cli/packages/cli/test/lib/scan/walker.property.test.ts</path> <type>file</type> <content> 1: /** 2: * Property tests for `walkFiles`. 3: * 4: * Two invariants we want to hold for any randomly generated tree: 5: * 6: * 1. Descent cap: no file yielded beyond `maxDepth + 1`. The walker 7: * caps directory *descent* at `maxDepth` — files inside those 8: * last-entered dirs still yield (they sit at parent_depth + 1). 9: * 2. minDepth guarantee: for any tree, with `timeBudgetMs: 0` and a 10: * fixed `minDepth = N`, every file at depth ≤ N is yielded 11: * regardless of budget. 12: * 13: * Trees are built from a flat `(path, kind)` list. Generation is 14: * constrained to ASCII alphanumerics + `_` to avoid tripping over the 15: * `ignore` package's pattern escaping quirks. ...
<path>/home/byk/Code/getsentry/cli/packages/cli/test/lib/scan/ignore.property.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Property test: a root-only IgnoreStack behaves identically to a
3: * plain `ignore` instance.
4: *
5: * This isn't a full cumulative-semantics test (the nested case is
6: * covered by the unit tests) — it's a round-trip anchor so refactors
7: * to the stack's root path can't silently diverge from the upstream
8: * package.
9: */
10:
11: import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
12: import { tmpdir } from "node:os";
13: import { join } from "node:path";
14: import {
15: array,
16: asyncProperty,
17: constantFrom,
18: assert as fcAssert,
19: } from "fast-check";
20: import ignore from "ignore";
21: import { afterAll, describe, expect, test } from "vitest";
22: import { IgnoreStack } from "../../../src/lib/scan/ignore.js";
23: import { DEFAULT_NUM_RUNS } from "../../model-based/helpers.js";
24:
25: const ROOT = ...
/home/byk/Code/getsentry/craft/src/utils/workspaces.ts /home/byk/Code/getsentry/craft/src/utils/__tests__/workspaces.test.ts /home/byk/Code/getsentry/craft/src/utils/__fixtures__/workspaces/pnpm-workspace/pnpm-workspace.yaml
<path>/home/byk/Code/getsentry/craft/src/utils/workspaces.ts</path>
<type>file</type>
<content>
1: import { readFileSync } from 'fs';
2: import * as path from 'path';
3: import { load } from 'js-yaml';
4: import { glob } from 'glob';
5:
6: import { logger } from '../logger';
7:
8: /**
9: * Check if an error is a "file not found" error
10: */
11: function isNotFoundError(err: unknown): boolean {
12: return err instanceof Error && 'code' in err && err.code === 'ENOENT';
13: }
14:
15: /** Information about a workspace package */
16: export interface WorkspacePackage {
17: /** The package name from package.json */
18: name: string;
19: /** Absolute path to the package directory */
20: location: string;
21: /** Whether the package is private */
22: private: boolean;
23: /** Whether the package has publishConfig.access set to 'public' */
24: hasPublicAccess: boolean;
25: /** Dependencies that are also workspace packages */
26: workspaceDependencies: string[];
27: ...
Found 6 matches
/home/byk/Code/getsentry/craft/src/utils/workspaces.ts:
Line 111: async function resolveWorkspaceGlobs(
Line 173: const workspacesGlobs = extractWorkspacesGlobs(packageJson.workspaces);
Line 174: if (workspacesGlobs.length === 0) {
Line 181: const packages = await resolveWorkspaceGlobs(rootDir, workspacesGlobs);
Line 186: } ${type} workspace packages from ${workspacesGlobs.join(', ')}`,
Line 216: const packages = await resolveWorkspaceGlobs(rootDir, patterns);
<path>/home/byk/Code/getsentry/craft/src/utils/__tests__/workspaces.test.ts</path>
<type>file</type>
<content>
1: import { resolve } from 'path';
2:
3: import {
4: discoverWorkspaces,
5: filterWorkspacePackages,
6: packageNameToArtifactPattern,
7: packageNameToArtifactFromTemplate,
8: topologicalSortPackages,
9: WorkspacePackage,
10: } from '../workspaces';
11:
12: const fixturesDir = resolve(__dirname, '../__fixtures__/workspaces');
13:
14: describe('discoverWorkspaces', () => {
15: test('discovers npm workspaces', async () => {
16: const result = await discoverWorkspaces(
17: resolve(fixturesDir, 'npm-workspace'),
18: );
19:
20: expect(result.type).toBe('npm');
21: expect(result.packages).toHaveLength(2);
22:
23: const packageNames = result.packages.map(p => p.name).sort();
24: expect(packageNames).toEqual(['@test/pkg-a', '@test/pkg-b']);
25:
26: // Check that pkg-b is marked as private
27: const pkgB = result.packages.find(p ...
Found 29 matches /home/byk/Code/getsentry/cli/packages/cli/src/lib/dsn/parser.ts: Line 15: MONOREPO_ROOTS, Line 211: MONOREPO_ROOTS.includes(root as (typeof MONOREPO_ROOTS)[number]) /home/byk/Code/getsentry/cli/packages/cli/src/lib/dsn/types.ts: Line 138: export const MONOREPO_ROOTS = [ /home/byk/Code/getsentry/cli/packages/cli/src/lib/dsn/scan-options.ts: Line 17: isMonorepoPackageDir, Line 51: return isMonorepoPackageDir(relPath) ? 0 : currentDepth + 1; /home/byk/Code/getsentry/cli/packages/cli/src/lib/dsn/project-root.ts: Line 92: "package.json", /home/byk/Code/getsentry/cli/packages/cli/src/lib/dev-script.ts: Line 10: /** Human label for what was detected (e.g., "package.json scripts.dev"). */ Line 14: /** Ordered list of npm script names to look for in package.json. */ Line 31: * 1. package.json scripts (dev > develop > serve > start) Line 69: /** Try to detect a dev command from package.json scripts. ...
<path>/home/byk/Code/getsentry/cli/packages/cli/src/lib/dsn/types.ts</path> <type>file</type> <content> 110: resolved: optional(ResolvedProjectInfoSchema), 111: allResolved: optional(array(ResolvedProjectInfoSchema)), 112: cachedAt: number(), 113: }); 114: 115: /** 116: * Result of DSN detection with support for monorepos. 117: * 118: * In monorepos, multiple DSNs are valid (different packages/apps may have different Sentry projects). 119: * The `primary` DSN is always the first one found, and `all` contains every detected DSN. ...
<path>/home/byk/Code/getsentry/cli/packages/cli/src/lib/dsn/scan-options.ts</path>
<type>file</type>
<content>
1: /**
2: * DSN scanner preset for `walkFiles`.
3: *
4: * Expresses the policy the DSN scanner applies: a depth-3 cap, full
5: * DSN skip list (including test/fixture dirs), monorepo-boundary
6: * depth reset, and the `TEXT_EXTENSIONS` allowlist.
7: *
8: * Lives in `dsn/` rather than `scan/` so the core scanner module
9: * stays policy-free. Other callers (the init wizard, future features)
10: * bring their own presets.
11: */
12:
13: import type { WalkOptions } from "../scan/index.js";
14: import {
15: DEFAULT_SKIP_DIRS,
16: DSN_ADDITIONAL_SKIP_DIRS,
17: isMonorepoPackageDir,
18: TEXT_EXTENSIONS,
19: } from "../scan/index.js";
20:
21: /**
22: * DSN scanner depth limit. `maxDepth` caps directory descent; files
23: * inside the last-entered directory are still yielded regardless. ...
Found 16 matches
/home/byk/Code/getsentry/cli/packages/cli/src/lib/init/tools/shared.ts:
Line 9: export function safePath(cwd: string, relative: string): string {
/home/byk/Code/getsentry/cli/packages/cli/src/lib/init/tools/project-file.ts:
Line 4: import { safePath } from "./shared.js";
Line 75: const absPath = safePath(cwd, filePath);
/home/byk/Code/getsentry/cli/packages/cli/src/lib/init/tools/list-dir.ts:
Line 5: import { safePath } from "./shared.js";
Line 25: const targetPath = safePath(cwd, params.path);
Line 98: safePath(state.cwd, relNative);
/home/byk/Code/getsentry/cli/packages/cli/src/lib/init/tools/file-changes/prepare.ts:
Line 10: import { safePath } from "../shared.js";
Line 234: absolutePath = safePath(cwd, change.path);
/home/byk/Code/getsentry/cli/packages/cli/src/lib/init/tools/file-changes/apply.ts:
Line 11: import { safePath } from "../shared.js";
Line 45: safePath(change.root, change.path) !== ...
<path>/home/byk/Code/getsentry/cli/packages/cli/src/lib/init/tools/shared.ts</path>
<type>file</type>
<content>
1: import fs from "node:fs";
2: import path from "node:path";
3: import { ApiError } from "../../errors.js";
4: import type { ToolPayload, ToolResult } from "../types.js";
5:
6: /**
7: * Resolve a path relative to cwd and verify it stays inside the project root.
8: */
9: export function safePath(cwd: string, relative: string): string {
10: const resolved = path.resolve(cwd, relative);
11: const normalizedCwd = path.resolve(cwd);
12: if (
13: !resolved.startsWith(normalizedCwd + path.sep) &&
14: resolved !== normalizedCwd
15: ) {
16: throw new Error(`Path "${relative}" resolves outside project directory`);
17: }
18:
19: let realCwd: string;
20: try {
21: realCwd = fs.realpathSync(normalizedCwd);
22: } catch {
23: return resolved;
24: }
25:
26: let checkPath = resolved;
27: for (;;) {
28: try {
29: const real = ...
Found 1 matches /home/byk/Code/getsentry/craft/src/config.ts: Line 571: * to implement their own expansion logic (e.g., npm workspace expansion).
<path>/home/byk/Code/getsentry/craft/src/config.ts</path>
<type>file</type>
<content>
500:
501: /**
502: * Returns whether the release branch should be merged after publishing.
503: *
504: * Resolution order:
505: * 1. Explicit `noMerge` value in .craft.yml takes precedence
506: * 2. Auto-detect compiled GitHub Actions (Node.js actions with dist/ folder)
507: * 3. Default to false (merge the branch)
508: *
509: * Compiled GitHub Actions typically have their `dist/` folder gitignored on
510: * main/master but need it in release branches for the action to work. Merging
511: * the release branch back would overwrite the clean main branch with compiled
512: * artifacts.
513: *
514: * @returns Configuration object with noMerge value and its source
515: */
516: export function getNoMergeConfig(): NoMergeConfig {
517: const config = getConfiguration();
518:
519: // Explicit config takes precedence
520: if (config.noMerge !== undefined) {
521: return {
522: ...
No files found
Found 5 matches
/home/byk/Code/getsentry/cli/packages/cli/test/lib/init/tools/filesystem-tools.test.ts:
Line 1152: const unsafePaths: unknown[] = [
Line 1163: for (const unsafePath of unsafePaths) {
Line 1172: path: unsafePath as never,
/home/byk/Code/getsentry/cli/packages/cli/test/lib/init/tools/search-tools.test.ts:
Line 13: * - The sandbox guard — `safePath` at the adapter boundary must
/home/byk/Code/getsentry/cli/packages/cli/test/lib/init/tools/list-dir.test.ts:
Line 296: // `safePath` allows nonexistent paths under the sandbox; `readdir`
Date: Sep 8, 2026 * 🟡 (13:35) Source artifact `packages/cli/test/lib/scan/ignore.property.test.ts:1-125`: Property suite uses `fast-check`, Vitest, and isolated filesystem directories under `ROOT = mkdtempSync(join(tmpdir(), "scan-ignore-prop-"))`, removed in `afterAll()` via `rmSync(ROOT, { recursive: true, force: true })`. * 🟡 (13:35) Source artifact `ignore.property.test.ts:34-63`: `segmentA…
Date: Sep 8, 2026 * 🟡 (13:34) Source artifact `packages/cli/test/lib/scan/walker.test.ts:1-878`: Vitest unit suite creates isolated `tmpdir()` sandboxes and compares sorted yielded `WalkEntry.relativePath` sets. It verifies basic traversal of all depths; nonexistent `cwd` and empty directories yield `[]`; relative `cwd: "./relative"` throws an error matching `/absolute/`. * 🟡 (13:34) Source art…
Date: Sep 8, 2026 * 🔴 (13:32) User stated `WalkEntry` yielded by `walkFiles` is always a regular file; directories are traversed but never yielded, and symlinks are skipped unless `followSymlinks: true`. * 🔴 (13:32) User stated `WalkEntry.isBinary` uses `TEXT_EXTENSIONS` as an always-text extension fast path; other extensions are classified by reading the first 8 KB and detecting a NUL byte. UT…
Date: Sep 8, 2026 * 🔴 (13:32) User stated `globFiles` public output is always relative to the caller's `cwd`. * 🟡 (13:32) Source artifact `packages/cli/src/lib/scan/glob.ts:1-28`: pure-TypeScript glob engine layers on `walkFiles`; accepts picomatch-syntax `patterns` and optional `exclude`, yielding files under `cwd` that match at least one include and no exclusion. Slash-containing patterns mat…
Date: Sep 8, 2026 * 🔴 [requested-read-only-research] (13:30) User directed read-only research only: inspect `/home/byk/Code/getsentry/cli` for directory-walking and workspace-discovery implementation potentially reusable by Craft PR #872; do not modify either repository. * 🟡 (13:30) User requested identification with file:line citations of exact modules, algorithms/contracts (globs, ignores, sy…