diff --git a/.github/workflows/pr-gate.yml b/.github/workflows/pr-gate.yml index 439fc726..43949422 100644 --- a/.github/workflows/pr-gate.yml +++ b/.github/workflows/pr-gate.yml @@ -54,34 +54,4 @@ jobs: - run: npm ci - run: npm run build - - # Guards the evals/jumbo CLI contract: builds jumbo from THIS commit's source - # and runs the evals against it (not a published binary), so a primitive - # refactor that breaks the CLI surface the evals depend on fails the PR here. - evals: - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - with: - node-version: '22' - cache: 'npm' - - # Build jumbo from source → dist/cli.js (the binary the evals will exercise). - - run: npm ci - - run: npm run build - - # Evals as an independent nested project, run against the freshly-built jumbo. - - run: npm ci - working-directory: evals - # Eval self-consistency (does not invoke jumbo). - - run: npm test - working-directory: evals - # The evals/jumbo CLI contract guard — exercises real jumbo (from source) - # through the surface the evals depend on. This is what catches a primitive - # refactor that would otherwise silently rot the evals. - - run: npm run smoke:jumbo - working-directory: evals + \ No newline at end of file diff --git a/src/infrastructure/context/project/init/AntigravityConfigurer.ts b/src/infrastructure/context/project/init/AntigravityConfigurer.ts index 6fbb97ae..b888d975 100644 --- a/src/infrastructure/context/project/init/AntigravityConfigurer.ts +++ b/src/infrastructure/context/project/init/AntigravityConfigurer.ts @@ -219,25 +219,32 @@ export class AntigravityConfigurer implements IConfigurer { try { const content = await fs.readFile(settingsPath, "utf-8"); if (content.trim()) { - const settings = JSON.parse(content); + const parsedSettings = JSON.parse(content) as unknown; + if (!AntigravityConfigurer.isObject(parsedSettings)) { + return; + } + const settings = parsedSettings; // Remove jumbo-specific hooks - if (settings.hooks) { + if (AntigravityConfigurer.isObject(settings.hooks)) { for (const eventType of Object.keys(settings.hooks)) { const matchers = settings.hooks[eventType]; if (Array.isArray(matchers)) { - settings.hooks[eventType] = matchers - .map((matcher: any) => { - if (matcher && Array.isArray(matcher.hooks)) { - matcher.hooks = matcher.hooks.filter((hook: any) => { - return hook && !(typeof hook.command === "string" && hook.command.includes("jumbo")); + const cleanedMatchers = matchers + .map((matcher: unknown) => { + if (AntigravityConfigurer.isObject(matcher) && Array.isArray(matcher.hooks)) { + matcher.hooks = matcher.hooks.filter((hook: unknown) => { + return AntigravityConfigurer.shouldKeepLegacyHook(hook); }); } return matcher; }) - .filter((matcher: any) => matcher && Array.isArray(matcher.hooks) && matcher.hooks.length > 0); + .filter((matcher: unknown) => { + return AntigravityConfigurer.isObject(matcher) && Array.isArray(matcher.hooks) && matcher.hooks.length > 0; + }); + settings.hooks[eventType] = cleanedMatchers; - if (settings.hooks[eventType].length === 0) { + if (cleanedMatchers.length === 0) { delete settings.hooks[eventType]; } } @@ -248,11 +255,12 @@ export class AntigravityConfigurer implements IConfigurer { } // Remove jumbo-specific allowed tools - if (settings.tools && Array.isArray(settings.tools.allowed)) { - settings.tools.allowed = settings.tools.allowed.filter((tool: string) => { + if (AntigravityConfigurer.isObject(settings.tools) && Array.isArray(settings.tools.allowed)) { + const allowedTools = settings.tools.allowed.filter((tool: unknown) => { return typeof tool === "string" && !tool.includes("jumbo") && !tool.includes("antigravity-hook.mjs"); }); - if (settings.tools.allowed.length === 0) { + settings.tools.allowed = allowedTools; + if (allowedTools.length === 0) { delete settings.tools.allowed; } } @@ -323,4 +331,20 @@ export class AntigravityConfigurer implements IConfigurer { private getHookRunnerPath(projectRoot: string): string { return path.join(projectRoot, ".agents", "jumbo", "antigravity-hook.mjs"); } + + private static isObject(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value); + } + + private static shouldKeepLegacyHook(hook: unknown): boolean { + if (!hook) { + return false; + } + + if (AntigravityConfigurer.isObject(hook) && typeof hook.command === "string") { + return !hook.command.includes("jumbo"); + } + + return true; + } } diff --git a/src/presentation/cli/commands/goals/list/GoalListOutputBuilder.ts b/src/presentation/cli/commands/goals/list/GoalListOutputBuilder.ts index fedbbea6..2fddd786 100644 --- a/src/presentation/cli/commands/goals/list/GoalListOutputBuilder.ts +++ b/src/presentation/cli/commands/goals/list/GoalListOutputBuilder.ts @@ -128,7 +128,7 @@ export class GoalListOutputBuilder { } } - let output = lines.join("\n"); + const output = lines.join("\n"); this.builder.addPrompt(output); return this.builder.build(); diff --git a/src/presentation/cli/commands/project/init/project.init.ts b/src/presentation/cli/commands/project/init/project.init.ts index 439e565c..bb809d73 100644 --- a/src/presentation/cli/commands/project/init/project.init.ts +++ b/src/presentation/cli/commands/project/init/project.init.ts @@ -559,7 +559,7 @@ export async function projectInit( // Determine project details and primitives based on mode let projectDetails: ProjectInitOptions; - let primitives: PrimitiveOptions = { + const primitives: PrimitiveOptions = { audiences: [], audiencePains: [], valuePropositions: [], diff --git a/tui-dev.tsx b/tui-dev.tsx deleted file mode 100644 index 01ba82e7..00000000 --- a/tui-dev.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import React from "react"; -import { render } from "ink"; -import { TuiApp } from "./src/presentation/tui/TuiApp.js"; - -render();