From cdd1030d8dbbfa9a8c6cb99c9188eb62af65844e Mon Sep 17 00:00:00 2001 From: yyovil Date: Sat, 23 May 2026 16:22:44 +0530 Subject: [PATCH] fix(agent-grok): use json import for manifest metadata (#2040) --- .changeset/clean-groks-smile.md | 8 ++ README.md | 2 +- docs/DEVELOPMENT.md | 2 +- package.json | 2 +- packages/ao/README.md | 2 +- packages/ao/package.json | 2 +- packages/cli/package.json | 2 +- packages/plugins/agent-grok/package.json | 2 +- .../agent-grok/src/__tests__/index.test.ts | 9 +- .../src/__tests__/metadata-import.test.ts | 101 ++++++++++++++++++ packages/plugins/agent-grok/src/index.ts | 8 +- packages/plugins/agent-grok/tsconfig.json | 2 + packages/web/package.json | 3 + 13 files changed, 124 insertions(+), 21 deletions(-) create mode 100644 .changeset/clean-groks-smile.md create mode 100644 packages/plugins/agent-grok/src/__tests__/metadata-import.test.ts diff --git a/.changeset/clean-groks-smile.md b/.changeset/clean-groks-smile.md new file mode 100644 index 000000000..a22f4771e --- /dev/null +++ b/.changeset/clean-groks-smile.md @@ -0,0 +1,8 @@ +--- +"@aoagents/ao": minor +"@aoagents/ao-cli": minor +"@aoagents/ao-web": minor +"@aoagents/ao-plugin-agent-grok": minor +--- + +Load agent-grok package metadata through JSON import attributes so packaged web and CLI runtimes do not keep a publish-host package.json lookup. This also raises the Node.js engine floor to 20.18.3+, where JSON modules with import attributes are non-experimental. diff --git a/README.md b/README.md index 966e02837..121c050c0 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Agent Orchestrator manages fleets of AI coding agents working in parallel on you ## Quick Start -> **Prerequisites:** [Node.js 20+](https://nodejs.org), [Git 2.25+](https://git-scm.com), [`gh` CLI](https://cli.github.com), and: +> **Prerequisites:** [Node.js 20.18.3+](https://nodejs.org), [Git 2.25+](https://git-scm.com), [`gh` CLI](https://cli.github.com), and: > - **macOS / Linux:** [tmux](https://github.com/tmux/tmux/wiki/Installing) — install via `brew install tmux` or `sudo apt install tmux`. > - **Windows:** PowerShell 7+ recommended. tmux is **not** required — AO uses native ConPTY via the `runtime-process` plugin (the default on Windows). Set `AO_SHELL=bash` if you have Git Bash and prefer it. diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 1b34d136f..9e140644f 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -87,7 +87,7 @@ For AI agent-specific guidance (including high-risk files like `types.ts`, `life ## Getting Started -**Prerequisites**: Node.js 20+, pnpm 9.15+, Git 2.25+ +**Prerequisites**: Node.js 20.18.3+, pnpm 9.15+, Git 2.25+ ```bash git clone https://github.com/ComposioHQ/agent-orchestrator.git diff --git a/package.json b/package.json index 23984e0dc..63b3413e5 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "description": "Orchestrate parallel AI coding agents across any runtime, any repo, any issue tracker", "license": "MIT", "engines": { - "node": ">=20.0.0" + "node": ">=20.18.3" }, "packageManager": "pnpm@9.15.4", "type": "module", diff --git a/packages/ao/README.md b/packages/ao/README.md index ad402d540..110cf5cee 100644 --- a/packages/ao/README.md +++ b/packages/ao/README.md @@ -25,7 +25,7 @@ npm install -g @aoagents/ao > **Nightly builds** (latest `main`): `npm install -g @aoagents/ao@nightly` — back to stable with `@latest`. -**Prerequisites:** [Node.js 20+](https://nodejs.org), [Git 2.25+](https://git-scm.com), the [`gh` CLI](https://cli.github.com), and at least one coding-agent CLI (e.g. [Claude Code](https://www.anthropic.com/claude-code)). +**Prerequisites:** [Node.js 20.18.3+](https://nodejs.org), [Git 2.25+](https://git-scm.com), the [`gh` CLI](https://cli.github.com), and at least one coding-agent CLI (e.g. [Claude Code](https://www.anthropic.com/claude-code)). - **macOS / Linux:** [tmux](https://github.com/tmux/tmux/wiki/Installing) — `brew install tmux` or `sudo apt install tmux`. - **Windows:** PowerShell 7+ recommended; tmux is **not** required (AO uses native ConPTY via the `process` runtime). diff --git a/packages/ao/package.json b/packages/ao/package.json index 037281e98..57b5eb4be 100644 --- a/packages/ao/package.json +++ b/packages/ao/package.json @@ -39,7 +39,7 @@ "url": "https://github.com/ComposioHQ/agent-orchestrator/issues" }, "engines": { - "node": ">=20.0.0" + "node": ">=20.18.3" }, "dependencies": { "@aoagents/ao-cli": "workspace:*" diff --git a/packages/cli/package.json b/packages/cli/package.json index bbb9b6adb..170924d74 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -22,7 +22,7 @@ "url": "https://github.com/ComposioHQ/agent-orchestrator/issues" }, "engines": { - "node": ">=20.0.0" + "node": ">=20.18.3" }, "scripts": { "build": "tsc && node --input-type=commonjs -e \"require('fs').cpSync('src/assets','dist/assets',{recursive:true})\"", diff --git a/packages/plugins/agent-grok/package.json b/packages/plugins/agent-grok/package.json index ba2e93aaa..342349a34 100644 --- a/packages/plugins/agent-grok/package.json +++ b/packages/plugins/agent-grok/package.json @@ -25,7 +25,7 @@ "url": "https://github.com/ComposioHQ/agent-orchestrator/issues" }, "engines": { - "node": ">=20.0.0" + "node": ">=20.18.3" }, "scripts": { "build": "tsc", diff --git a/packages/plugins/agent-grok/src/__tests__/index.test.ts b/packages/plugins/agent-grok/src/__tests__/index.test.ts index 6e181e7e3..e77436890 100644 --- a/packages/plugins/agent-grok/src/__tests__/index.test.ts +++ b/packages/plugins/agent-grok/src/__tests__/index.test.ts @@ -1,13 +1,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import type { AgentLaunchConfig, RuntimeHandle, Session } from "@aoagents/ao-core"; -import { createRequire } from "node:module"; +import packageJson from "../../package.json" with { type: "json" }; -const require = createRequire(import.meta.url); -const packageJson = require("../../package.json") as { - name: string; - version: string; - description: string; -}; const PACKAGE_NAME_PREFIX = "@aoagents/ao-plugin-agent-"; const pluginName = packageJson.name.startsWith(PACKAGE_NAME_PREFIX) ? packageJson.name.slice(PACKAGE_NAME_PREFIX.length) @@ -144,6 +138,7 @@ beforeEach(() => { describe("manifest", () => { it("has correct Grok manifest", () => { + expect(manifest.version).toBe(packageJson.version); expect(manifest).toEqual({ name: pluginName, slot: "agent", diff --git a/packages/plugins/agent-grok/src/__tests__/metadata-import.test.ts b/packages/plugins/agent-grok/src/__tests__/metadata-import.test.ts new file mode 100644 index 000000000..ff9c16b02 --- /dev/null +++ b/packages/plugins/agent-grok/src/__tests__/metadata-import.test.ts @@ -0,0 +1,101 @@ +import { mkdtemp, readFile, rm } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import ts from "typescript"; +import { describe, expect, it } from "vitest"; +import packageJson from "../../package.json" with { type: "json" }; +import { manifest } from "../index.js"; + +const testFilePath = fileURLToPath(import.meta.url); +const packageRoot = path.resolve(path.dirname(testFilePath), "../.."); +const sourcePath = path.join(packageRoot, "src/index.ts"); + +const forbiddenPackageMetadataLookups = [ + "createRequire(import.meta.url)", + 'require("../package.json")', + 'readFileSync(new URL("../package.json", import.meta.url))', +]; + +function assertPackageMetadataImportPattern(label: string, source: string): void { + for (const forbidden of forbiddenPackageMetadataLookups) { + expect(source, `${label} must not contain ${forbidden}`).not.toContain(forbidden); + } + + const packageJsonImports = [...source.matchAll(/from\s+["']\.\.\/package\.json["'][^;]*/g)].map( + (match) => match[0], + ); + + expect(packageJsonImports.length, `${label} imports ../package.json`).toBeGreaterThan(0); + for (const importStatement of packageJsonImports) { + expect( + importStatement, + `${label} package.json import must use a JSON import attribute`, + ).toMatch(/\swith\s*\{\s*type:\s*["']json["']\s*\}/); + } +} + +function compileAgentGrokTo(outDir: string): void { + const configPath = path.join(packageRoot, "tsconfig.json"); + const configFile = ts.readConfigFile(configPath, ts.sys.readFile); + if (configFile.error) { + throw new Error( + ts.formatDiagnosticsWithColorAndContext([configFile.error], { + getCanonicalFileName: (fileName) => fileName, + getCurrentDirectory: ts.sys.getCurrentDirectory, + getNewLine: () => ts.sys.newLine, + }), + ); + } + + const parsedConfig = ts.parseJsonConfigFileContent( + configFile.config, + ts.sys, + packageRoot, + { + declaration: false, + declarationMap: false, + outDir, + sourceMap: false, + }, + configPath, + ); + + const program = ts.createProgram(parsedConfig.fileNames, parsedConfig.options); + const emitResult = program.emit(); + const diagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics); + if (emitResult.emitSkipped || diagnostics.length > 0) { + const message = + diagnostics.length > 0 + ? ts.formatDiagnosticsWithColorAndContext(diagnostics, { + getCanonicalFileName: (fileName) => fileName, + getCurrentDirectory: ts.sys.getCurrentDirectory, + getNewLine: () => ts.sys.newLine, + }) + : "TypeScript emit skipped without diagnostics."; + throw new Error(message); + } +} + +describe("package metadata import", () => { + it("keeps manifest version in sync with package.json", () => { + expect(manifest.version).toBe(packageJson.version); + }); + + it("uses JSON import attributes in the source runtime module", async () => { + const source = await readFile(sourcePath, "utf8"); + assertPackageMetadataImportPattern("src/index.ts", source); + }); + + it("uses JSON import attributes in the compiled runtime module", async () => { + const outDir = await mkdtemp(path.join(tmpdir(), "ao-agent-grok-")); + + try { + compileAgentGrokTo(outDir); + const compiledSource = await readFile(path.join(outDir, "index.js"), "utf8"); + assertPackageMetadataImportPattern("compiled index.js", compiledSource); + } finally { + await rm(outDir, { force: true, recursive: true }); + } + }); +}); diff --git a/packages/plugins/agent-grok/src/index.ts b/packages/plugins/agent-grok/src/index.ts index 084fac296..080eed0fd 100644 --- a/packages/plugins/agent-grok/src/index.ts +++ b/packages/plugins/agent-grok/src/index.ts @@ -22,17 +22,11 @@ import { type WorkspaceHooksConfig, } from "@aoagents/ao-core"; import { execFile } from "node:child_process"; -import { createRequire } from "node:module"; import { setTimeout as sleep } from "node:timers/promises"; import { promisify } from "node:util"; import which from "which"; +import packageJson from "../package.json" with { type: "json" }; -const require = createRequire(import.meta.url); -const packageJson = require("../package.json") as { - name: string; - version: string; - description: string; -}; const PACKAGE_NAME_PREFIX = "@aoagents/ao-plugin-agent-"; const pluginName = packageJson.name.startsWith(PACKAGE_NAME_PREFIX) ? packageJson.name.slice(PACKAGE_NAME_PREFIX.length) diff --git a/packages/plugins/agent-grok/tsconfig.json b/packages/plugins/agent-grok/tsconfig.json index 556dd3e4e..a2ada8d5a 100644 --- a/packages/plugins/agent-grok/tsconfig.json +++ b/packages/plugins/agent-grok/tsconfig.json @@ -1,6 +1,8 @@ { "extends": "../../../tsconfig.node.json", "compilerOptions": { + "module": "NodeNext", + "moduleResolution": "NodeNext", "outDir": "dist", "rootDir": "src" }, diff --git a/packages/web/package.json b/packages/web/package.json index 47cfbc89a..bd10e9795 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -13,6 +13,9 @@ "bugs": { "url": "https://github.com/ComposioHQ/agent-orchestrator/issues" }, + "engines": { + "node": ">=20.18.3" + }, "publishConfig": { "access": "public", "provenance": true