export interface ProjectMetadata { gameId: string; engineVersion: string; genre: string; template: string; /** See the same field in scaffold/project-files.ts. Absent on projects scaffolded before it. */ agentsMdHash?: string; /** * Which api-server this project belongs to. Absent on projects scaffolded before the field * existed, which is why nothing may require it. * * Typed `string` rather than `EnvironmentName` on purpose, and NOT validated by * findMissingField: this file is hand-editable, so a narrow type here would be a claim the * parser cannot back, and the only honest way to keep it would be a cast. Validation against the * environment table belongs to config/environments.ts — the same split credentials.ts already * documents for `defaultEnvironment`, and the reason this module must not import that table. */ environment?: string; /** * Which agent tools this project is set up for. Absent on projects scaffolded before the field * existed, which reads as the always-present set — see scaffold/agent-targets.ts. * * Typed `string[]` rather than `AgentId[]` for the same reason `environment` is typed `string`: * this file is hand-editable, so a narrow type here would be a claim the parser cannot back. * `readRecordedAgents` does the narrowing, and reports what it dropped. */ agents?: string[]; } export interface ProjectContext { root: string; metadata: ProjectMetadata; } /** * The nearest ancestor of `startDir` (itself included) holding `fileName`, or null at the root. * * `startDir` does NOT have to exist. `fs.existsSync` on a path under a missing directory is simply * false, so the walk falls through to the nearest ancestor that does exist — which is what lets * `bitmagic init ` ask about a target directory it has not created yet. * * Shared rather than written twice: the loop is four lines and two of them are easy to get wrong * (resolving `startDir` on the way in, and stopping when `path.dirname` stops moving), so a second * copy would drift. Config markers live above this module — see config/folder-environment.ts. */ export declare function findDirWithFileUpwards(fileName: string, startDir?: string): string | null; /** * Like findProjectRoot, but answers "is there one?" instead of insisting there is. * * Environment resolution runs on EVERY command, including the ones that legitimately have no * project — `login`, `logout`, `whoami`, `usage`, `subscribe`, and `init`, which creates one. */ export declare function findProjectRootOrNull(startDir?: string): string | null; /** Walks up from `startDir` looking for bitmagic.json, so commands work from any subdirectory. */ export declare function findProjectRoot(startDir?: string): string; export declare function loadProjectContext(startDir?: string): ProjectContext; /** * The environment this project is pinned to, or undefined when there is no project — and for every * project scaffolded before the field existed. "No project" is an answer here, not an error. * * Deliberately does NOT run findMissingField. `login` and `whoami` do not operate on the project, * and refusing to log in because a bitmagic.json two directories up is missing `genre` would be a * brand new failure for commands that never needed a project at all. A marker that cannot be * PARSED still throws: that is not a "no project" answer, and swallowing it would point the user * at `bitmagic init` when their file is merely malformed. * * Returns the raw string. Checking it against the environment table is config/environments.ts's * job — see the note on ProjectMetadata.environment. */ export declare function readProjectEnvironment(startDir?: string): string | undefined; /** * The project's game id, or undefined when there is no project here or its marker does not name * one — for the command beacon, which reports which game a command was run against. * * Never throws, unlike `readProjectEnvironment` and `loadProjectContext`. Those are read by * commands doing their work, where a malformed marker must surface; this is read by telemetry * after the command has already finished, where the only honest answer to a broken file is to * say nothing about the game. A beacon is never a reason to fail a command that worked. */ export declare function readProjectGameIdOrNull(startDir?: string): string | undefined; /** * Resolves a tool from the PROJECT's node_modules, never the CLI's. The scaffold pins its own * typescript and vite; running a different copy would type-check against the wrong compiler. * * Windows gets `.cmd` (or a real `.exe`) rather than the extensionless file, which is * a POSIX shell script there and spawns ENOENT. Run whatever this returns through * `spawn-bin.ts` — a `.cmd` additionally needs a shell, and that is the one place that knows it. */ export declare function projectBin(root: string, name: string, platform?: string): string;