New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

@agenteract/core

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@agenteract/core - npm Package Compare versions

Comparing version
0.0.3
to
0.1.0
+29
dist/cjs/src/config-types.d.ts
export interface DevServerConfig {
command: string;
port: number;
cwd?: string;
env?: Record<string, string>;
validation?: {
fileExists?: string[];
commandInPath?: string;
errorHints?: Record<string, string>;
};
keyCommands?: Record<string, string>;
}
export interface ProjectConfig {
name: string;
path: string;
type?: 'expo' | 'vite' | 'flutter' | 'native' | 'auto';
ptyPort?: number;
devServer?: DevServerConfig;
scheme?: string;
}
export interface AgenteractConfig {
server?: {
port?: number;
wsPort?: number;
logPort?: number;
};
port?: number;
projects: ProjectConfig[];
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
import { AgenteractConfig, DevServerConfig, ProjectConfig } from '../config-types.js';
export interface RuntimeConfig {
host: string;
port: number;
token: string;
defaultDevices?: Record<string, string>;
}
export declare function getRuntimeConfigPath(cwd?: string): string;
export declare function saveRuntimeConfig(config: RuntimeConfig, cwd?: string): Promise<void>;
export declare function loadRuntimeConfig(cwd?: string): Promise<RuntimeConfig | null>;
export declare function deleteRuntimeConfig(cwd?: string): Promise<void>;
export declare function generateAuthToken(): string;
/**
* Set the default device for a project
*/
export declare function setDefaultDevice(projectName: string, deviceId: string, cwd?: string): Promise<void>;
/**
* Get the default device for a project
*/
export declare function getDefaultDevice(projectName: string, cwd?: string): Promise<string | undefined>;
export declare class MissingConfigError extends Error {
constructor(message: string);
}
export declare function loadConfig(rootDir: string): Promise<AgenteractConfig>;
/**
* Find the root directory containing agenteract.config.js
* Searches upward from the current working directory
*/
export declare function findConfigRoot(startDir?: string): Promise<string | null>;
/**
* Get the URL for the agent server
*/
export declare function getAgentServerUrl(config: AgenteractConfig): string;
/**
* Get the URL for a project's dev server
*/
export declare function getProjectServerUrl(config: AgenteractConfig, projectName: string): string | null;
/**
* Get the URL for a dev server by type
*/
export declare function getDevServerUrlByType(config: AgenteractConfig, type: 'expo' | 'vite' | 'flutter'): string | null;
/**
* Type presets for backward compatibility
* Maps old 'type' field to new devServer configuration
*/
export declare const TYPE_PRESETS: Record<string, Omit<DevServerConfig, 'port'>>;
export declare function addConfig(rootDir: string, projectPath: string, name: string, typeOrCommand: string, port?: number, scheme?: string): Promise<void>;
/**
* Normalize project config: migrate old format to new format
* Logs deprecation warnings when using old 'type' field
*/
export declare function normalizeProjectConfig(project: ProjectConfig, rootDir: string): ProjectConfig;
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TYPE_PRESETS = exports.MissingConfigError = void 0;
exports.getRuntimeConfigPath = getRuntimeConfigPath;
exports.saveRuntimeConfig = saveRuntimeConfig;
exports.loadRuntimeConfig = loadRuntimeConfig;
exports.deleteRuntimeConfig = deleteRuntimeConfig;
exports.generateAuthToken = generateAuthToken;
exports.setDefaultDevice = setDefaultDevice;
exports.getDefaultDevice = getDefaultDevice;
exports.loadConfig = loadConfig;
exports.findConfigRoot = findConfigRoot;
exports.getAgentServerUrl = getAgentServerUrl;
exports.getProjectServerUrl = getProjectServerUrl;
exports.getDevServerUrlByType = getDevServerUrlByType;
exports.addConfig = addConfig;
exports.normalizeProjectConfig = normalizeProjectConfig;
const promises_1 = __importDefault(require("fs/promises"));
const path_1 = __importDefault(require("path"));
const crypto_1 = require("crypto");
function getRuntimeConfigPath(cwd = process.cwd()) {
return path_1.default.join(cwd, '.agenteract-runtime.json');
}
async function saveRuntimeConfig(config, cwd = process.cwd()) {
await promises_1.default.writeFile(getRuntimeConfigPath(cwd), JSON.stringify(config, null, 2));
}
async function loadRuntimeConfig(cwd = process.cwd()) {
try {
const content = await promises_1.default.readFile(getRuntimeConfigPath(cwd), 'utf-8');
return JSON.parse(content);
}
catch {
return null;
}
}
async function deleteRuntimeConfig(cwd = process.cwd()) {
try {
await promises_1.default.unlink(getRuntimeConfigPath(cwd));
}
catch {
// Ignore if file doesn't exist
}
}
function generateAuthToken() {
return (0, crypto_1.randomUUID)();
}
/**
* Set the default device for a project
*/
async function setDefaultDevice(projectName, deviceId, cwd = process.cwd()) {
const config = await loadRuntimeConfig(cwd);
if (!config) {
throw new Error('Runtime config not found. Is the server running?');
}
if (!config.defaultDevices) {
config.defaultDevices = {};
}
config.defaultDevices[projectName] = deviceId;
await saveRuntimeConfig(config, cwd);
}
/**
* Get the default device for a project
*/
async function getDefaultDevice(projectName, cwd = process.cwd()) {
const config = await loadRuntimeConfig(cwd);
return config?.defaultDevices?.[projectName];
}
class MissingConfigError extends Error {
constructor(message) {
super(message);
this.name = 'MissingConfigError';
}
}
exports.MissingConfigError = MissingConfigError;
async function loadConfig(rootDir) {
const configPath = path_1.default.join(rootDir, 'agenteract.config.js');
try {
await promises_1.default.access(configPath);
}
catch (error) {
throw new MissingConfigError('Agenteract config file not found');
}
// In a Jest environment, dynamic import() of file URLs can be tricky.
// A simple and effective workaround is to read the file and evaluate it.
// This avoids the module resolution issues within the test runner.
const configContent = await promises_1.default.readFile(configPath, 'utf-8');
// A simple regex to extract the default export object.
// This is not a full parser, but it's robust enough for our config file format.
const match = configContent.match(/export default (\{[\s\S]*\});/);
if (!match) {
console.error(`configContent: ${configContent}`);
throw new Error('Could not parse agenteract.config.js. Make sure it has a default export.');
}
// We can use Function to evaluate the object literal.
// It's safer than eval() because it doesn't have access to the outer scope.
return new Function(`return ${match[1]}`)();
}
/**
* Find the root directory containing agenteract.config.js
* Searches upward from the current working directory
*/
async function findConfigRoot(startDir = process.cwd()) {
let currentDir = startDir;
const root = path_1.default.parse(currentDir).root;
while (currentDir !== root) {
const configPath = path_1.default.join(currentDir, 'agenteract.config.js');
try {
await promises_1.default.access(configPath);
return currentDir;
}
catch {
currentDir = path_1.default.dirname(currentDir);
}
}
return null;
}
/**
* Get the URL for the agent server
*/
function getAgentServerUrl(config) {
return `http://localhost:${config.port || 8766}`;
}
/**
* Get the URL for a project's dev server
*/
function getProjectServerUrl(config, projectName) {
const project = config.projects.find(p => p.name === projectName);
if (!project)
return null;
// Check new devServer format first, then legacy ptyPort
const port = project.devServer?.port || project.ptyPort;
if (!port) {
return null;
}
return `http://localhost:${port}`;
}
/**
* Get the URL for a dev server by type
*/
function getDevServerUrlByType(config, type) {
const project = config.projects.find(p => p.type === type && (p.ptyPort || p.devServer?.port));
if (!project) {
return null;
}
const port = project.devServer?.port || project.ptyPort;
return `http://localhost:${port}`;
}
/**
* Type presets for backward compatibility
* Maps old 'type' field to new devServer configuration
*/
exports.TYPE_PRESETS = {
expo: {
command: 'npx expo start',
keyCommands: { reload: 'r', ios: 'i', android: 'a' }
},
vite: {
command: 'npx vite',
keyCommands: { reload: 'r', quit: 'q' }
},
flutter: {
command: 'flutter run',
validation: {
fileExists: ['pubspec.yaml'],
commandInPath: 'flutter',
errorHints: {
'command not found': 'Install Flutter: https://flutter.dev/docs/get-started/install',
'No pubspec.yaml': 'Flutter projects require a pubspec.yaml file in the project directory'
}
},
keyCommands: { reload: 'r', restart: 'R', quit: 'q', help: 'h' }
}
};
/**
* Get default PTY port for a given type
*/
function getDefaultPortForType(type) {
const defaults = {
expo: 8790,
vite: 8791,
flutter: 8792
};
return defaults[type] || 8790;
}
async function addConfig(rootDir, projectPath, name, typeOrCommand, port, scheme) {
const configPath = path_1.default.join(rootDir, 'agenteract.config.js');
let config;
try {
config = await loadConfig(rootDir);
}
catch (error) {
if (error instanceof MissingConfigError) {
config = { port: 8766, projects: [] };
}
else {
// For other errors (like parsing), we should not proceed.
throw error;
}
}
config.projects = config.projects || [];
let nameExists = config.projects.find((p) => p.name === name);
let pathExists = config.projects.find((p) => p.path === projectPath);
if ((nameExists || pathExists) && nameExists !== pathExists) {
console.error('project name and path exist across multiple projects. Please use a different name or path.');
console.error(`name: ${name}, path: ${projectPath}`);
return;
}
let update = nameExists || pathExists;
// Determine if this is legacy format (type) or new format (command)
const LEGACY_TYPES = ['expo', 'vite', 'flutter', 'native'];
const isLegacyFormat = LEGACY_TYPES.includes(typeOrCommand);
// Allocate a port if not provided
let ptyPort;
if (port) {
// Explicit port provided
ptyPort = port;
}
else if (update) {
// Reuse existing port when updating
ptyPort = update.ptyPort || update.devServer?.port || 8790;
}
else {
// Find next available port for new project
ptyPort = 8790;
while (config.projects.some((p) => (p.ptyPort === ptyPort) || (p.devServer?.port === ptyPort))) {
ptyPort++;
}
}
let newProjectConfig;
if (isLegacyFormat) {
// Legacy format: use old 'type' field for backwards compatibility
// Native apps don't have dev servers
if (typeOrCommand === 'native') {
newProjectConfig = {
name,
path: projectPath,
type: 'native',
...(scheme && { scheme })
};
}
else {
// For non-native legacy types, create with new devServer format
const preset = exports.TYPE_PRESETS[typeOrCommand];
if (!preset) {
console.error(`Unknown type '${typeOrCommand}'`);
return;
}
newProjectConfig = {
name,
path: projectPath,
devServer: {
...preset,
port: ptyPort
},
...(scheme && { scheme })
};
console.log(`ℹ️ Creating config with new devServer format (migrated from legacy type '${typeOrCommand}')`);
}
}
else {
// New format: generic dev server command
newProjectConfig = {
name,
path: projectPath,
devServer: {
command: typeOrCommand,
port: ptyPort
},
...(scheme && { scheme })
};
}
// If the project already exists, replace it completely
if (update) {
// Find the index and replace the entire object to avoid keeping old fields
const index = config.projects.indexOf(update);
config.projects[index] = newProjectConfig;
}
else {
config.projects.push(newProjectConfig);
}
await promises_1.default.writeFile(configPath, `export default ${JSON.stringify(config, null, 2)};`);
console.log(`✅ Config updated: ${name} at ${projectPath}`);
if (newProjectConfig.devServer) {
console.log(` Dev server: ${newProjectConfig.devServer.command} (port: ${newProjectConfig.devServer.port})`);
}
if (scheme) {
console.log(` URL scheme: ${scheme}`);
}
}
/**
* Normalize project config: migrate old format to new format
* Logs deprecation warnings when using old 'type' field
*/
function normalizeProjectConfig(project, rootDir) {
// Already using new format
if (project.devServer) {
return project;
}
// Native type has no dev server
if (project.type === 'native') {
return project;
}
// Auto-migrate from old type-based format
if (project.type && project.type !== 'auto') {
console.warn(`⚠️ [${project.name}] Using deprecated 'type' field. ` +
`Migrate to 'devServer' config. See docs/MIGRATION_V2.md`);
const preset = exports.TYPE_PRESETS[project.type];
if (!preset) {
console.error(`Unknown type '${project.type}' for project '${project.name}'`);
return project;
}
return {
...project,
devServer: {
...preset,
port: project.ptyPort || getDefaultPortForType(project.type)
}
};
}
return project;
}
export * from './config.js';
export * from './pnpm.js';
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
__exportStar(require("./config.js"), exports);
__exportStar(require("./pnpm.js"), exports);
/**
* if we're running in the agenteract monorepo, set node's CWD back to the original working directory
* otherwise pnpm commands have CWD set to the monorepo root
*/
export declare function resetPNPMWorkspaceCWD(): void;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.resetPNPMWorkspaceCWD = resetPNPMWorkspaceCWD;
/**
* if we're running in the agenteract monorepo, set node's CWD back to the original working directory
* otherwise pnpm commands have CWD set to the monorepo root
*/
function resetPNPMWorkspaceCWD() {
if (process.env.PNPM_PACKAGE_NAME == 'agenteract' && process.env.PWD && process.env.PWD !== process.cwd()) {
process.chdir(process.env.PWD);
}
}
export interface DevServerConfig {
command: string;
port: number;
cwd?: string;
env?: Record<string, string>;
validation?: {
fileExists?: string[];
commandInPath?: string;
errorHints?: Record<string, string>;
};
keyCommands?: Record<string, string>;
}
export interface ProjectConfig {
name: string;
path: string;
type?: 'expo' | 'vite' | 'flutter' | 'native' | 'auto';
ptyPort?: number;
devServer?: DevServerConfig;
scheme?: string;
}
export interface AgenteractConfig {
server?: {
port?: number;
wsPort?: number;
logPort?: number;
};
port?: number;
projects: ProjectConfig[];
}
import { AgenteractConfig, DevServerConfig, ProjectConfig } from '../config-types.js';
export interface RuntimeConfig {
host: string;
port: number;
token: string;
defaultDevices?: Record<string, string>;
}
export declare function getRuntimeConfigPath(cwd?: string): string;
export declare function saveRuntimeConfig(config: RuntimeConfig, cwd?: string): Promise<void>;
export declare function loadRuntimeConfig(cwd?: string): Promise<RuntimeConfig | null>;
export declare function deleteRuntimeConfig(cwd?: string): Promise<void>;
export declare function generateAuthToken(): string;
/**
* Set the default device for a project
*/
export declare function setDefaultDevice(projectName: string, deviceId: string, cwd?: string): Promise<void>;
/**
* Get the default device for a project
*/
export declare function getDefaultDevice(projectName: string, cwd?: string): Promise<string | undefined>;
export declare class MissingConfigError extends Error {
constructor(message: string);
}
export declare function loadConfig(rootDir: string): Promise<AgenteractConfig>;
/**
* Find the root directory containing agenteract.config.js
* Searches upward from the current working directory
*/
export declare function findConfigRoot(startDir?: string): Promise<string | null>;
/**
* Get the URL for the agent server
*/
export declare function getAgentServerUrl(config: AgenteractConfig): string;
/**
* Get the URL for a project's dev server
*/
export declare function getProjectServerUrl(config: AgenteractConfig, projectName: string): string | null;
/**
* Get the URL for a dev server by type
*/
export declare function getDevServerUrlByType(config: AgenteractConfig, type: 'expo' | 'vite' | 'flutter'): string | null;
/**
* Type presets for backward compatibility
* Maps old 'type' field to new devServer configuration
*/
export declare const TYPE_PRESETS: Record<string, Omit<DevServerConfig, 'port'>>;
export declare function addConfig(rootDir: string, projectPath: string, name: string, typeOrCommand: string, port?: number, scheme?: string): Promise<void>;
/**
* Normalize project config: migrate old format to new format
* Logs deprecation warnings when using old 'type' field
*/
export declare function normalizeProjectConfig(project: ProjectConfig, rootDir: string): ProjectConfig;
import fs from 'fs/promises';
import path from 'path';
import { randomUUID } from 'crypto';
export function getRuntimeConfigPath(cwd = process.cwd()) {
return path.join(cwd, '.agenteract-runtime.json');
}
export async function saveRuntimeConfig(config, cwd = process.cwd()) {
await fs.writeFile(getRuntimeConfigPath(cwd), JSON.stringify(config, null, 2));
}
export async function loadRuntimeConfig(cwd = process.cwd()) {
try {
const content = await fs.readFile(getRuntimeConfigPath(cwd), 'utf-8');
return JSON.parse(content);
}
catch {
return null;
}
}
export async function deleteRuntimeConfig(cwd = process.cwd()) {
try {
await fs.unlink(getRuntimeConfigPath(cwd));
}
catch {
// Ignore if file doesn't exist
}
}
export function generateAuthToken() {
return randomUUID();
}
/**
* Set the default device for a project
*/
export async function setDefaultDevice(projectName, deviceId, cwd = process.cwd()) {
const config = await loadRuntimeConfig(cwd);
if (!config) {
throw new Error('Runtime config not found. Is the server running?');
}
if (!config.defaultDevices) {
config.defaultDevices = {};
}
config.defaultDevices[projectName] = deviceId;
await saveRuntimeConfig(config, cwd);
}
/**
* Get the default device for a project
*/
export async function getDefaultDevice(projectName, cwd = process.cwd()) {
const config = await loadRuntimeConfig(cwd);
return config?.defaultDevices?.[projectName];
}
export class MissingConfigError extends Error {
constructor(message) {
super(message);
this.name = 'MissingConfigError';
}
}
export async function loadConfig(rootDir) {
const configPath = path.join(rootDir, 'agenteract.config.js');
try {
await fs.access(configPath);
}
catch (error) {
throw new MissingConfigError('Agenteract config file not found');
}
// In a Jest environment, dynamic import() of file URLs can be tricky.
// A simple and effective workaround is to read the file and evaluate it.
// This avoids the module resolution issues within the test runner.
const configContent = await fs.readFile(configPath, 'utf-8');
// A simple regex to extract the default export object.
// This is not a full parser, but it's robust enough for our config file format.
const match = configContent.match(/export default (\{[\s\S]*\});/);
if (!match) {
console.error(`configContent: ${configContent}`);
throw new Error('Could not parse agenteract.config.js. Make sure it has a default export.');
}
// We can use Function to evaluate the object literal.
// It's safer than eval() because it doesn't have access to the outer scope.
return new Function(`return ${match[1]}`)();
}
/**
* Find the root directory containing agenteract.config.js
* Searches upward from the current working directory
*/
export async function findConfigRoot(startDir = process.cwd()) {
let currentDir = startDir;
const root = path.parse(currentDir).root;
while (currentDir !== root) {
const configPath = path.join(currentDir, 'agenteract.config.js');
try {
await fs.access(configPath);
return currentDir;
}
catch {
currentDir = path.dirname(currentDir);
}
}
return null;
}
/**
* Get the URL for the agent server
*/
export function getAgentServerUrl(config) {
return `http://localhost:${config.port || 8766}`;
}
/**
* Get the URL for a project's dev server
*/
export function getProjectServerUrl(config, projectName) {
const project = config.projects.find(p => p.name === projectName);
if (!project)
return null;
// Check new devServer format first, then legacy ptyPort
const port = project.devServer?.port || project.ptyPort;
if (!port) {
return null;
}
return `http://localhost:${port}`;
}
/**
* Get the URL for a dev server by type
*/
export function getDevServerUrlByType(config, type) {
const project = config.projects.find(p => p.type === type && (p.ptyPort || p.devServer?.port));
if (!project) {
return null;
}
const port = project.devServer?.port || project.ptyPort;
return `http://localhost:${port}`;
}
/**
* Type presets for backward compatibility
* Maps old 'type' field to new devServer configuration
*/
export const TYPE_PRESETS = {
expo: {
command: 'npx expo start',
keyCommands: { reload: 'r', ios: 'i', android: 'a' }
},
vite: {
command: 'npx vite',
keyCommands: { reload: 'r', quit: 'q' }
},
flutter: {
command: 'flutter run',
validation: {
fileExists: ['pubspec.yaml'],
commandInPath: 'flutter',
errorHints: {
'command not found': 'Install Flutter: https://flutter.dev/docs/get-started/install',
'No pubspec.yaml': 'Flutter projects require a pubspec.yaml file in the project directory'
}
},
keyCommands: { reload: 'r', restart: 'R', quit: 'q', help: 'h' }
}
};
/**
* Get default PTY port for a given type
*/
function getDefaultPortForType(type) {
const defaults = {
expo: 8790,
vite: 8791,
flutter: 8792
};
return defaults[type] || 8790;
}
export async function addConfig(rootDir, projectPath, name, typeOrCommand, port, scheme) {
const configPath = path.join(rootDir, 'agenteract.config.js');
let config;
try {
config = await loadConfig(rootDir);
}
catch (error) {
if (error instanceof MissingConfigError) {
config = { port: 8766, projects: [] };
}
else {
// For other errors (like parsing), we should not proceed.
throw error;
}
}
config.projects = config.projects || [];
let nameExists = config.projects.find((p) => p.name === name);
let pathExists = config.projects.find((p) => p.path === projectPath);
if ((nameExists || pathExists) && nameExists !== pathExists) {
console.error('project name and path exist across multiple projects. Please use a different name or path.');
console.error(`name: ${name}, path: ${projectPath}`);
return;
}
let update = nameExists || pathExists;
// Determine if this is legacy format (type) or new format (command)
const LEGACY_TYPES = ['expo', 'vite', 'flutter', 'native'];
const isLegacyFormat = LEGACY_TYPES.includes(typeOrCommand);
// Allocate a port if not provided
let ptyPort;
if (port) {
// Explicit port provided
ptyPort = port;
}
else if (update) {
// Reuse existing port when updating
ptyPort = update.ptyPort || update.devServer?.port || 8790;
}
else {
// Find next available port for new project
ptyPort = 8790;
while (config.projects.some((p) => (p.ptyPort === ptyPort) || (p.devServer?.port === ptyPort))) {
ptyPort++;
}
}
let newProjectConfig;
if (isLegacyFormat) {
// Legacy format: use old 'type' field for backwards compatibility
// Native apps don't have dev servers
if (typeOrCommand === 'native') {
newProjectConfig = {
name,
path: projectPath,
type: 'native',
...(scheme && { scheme })
};
}
else {
// For non-native legacy types, create with new devServer format
const preset = TYPE_PRESETS[typeOrCommand];
if (!preset) {
console.error(`Unknown type '${typeOrCommand}'`);
return;
}
newProjectConfig = {
name,
path: projectPath,
devServer: {
...preset,
port: ptyPort
},
...(scheme && { scheme })
};
console.log(`ℹ️ Creating config with new devServer format (migrated from legacy type '${typeOrCommand}')`);
}
}
else {
// New format: generic dev server command
newProjectConfig = {
name,
path: projectPath,
devServer: {
command: typeOrCommand,
port: ptyPort
},
...(scheme && { scheme })
};
}
// If the project already exists, replace it completely
if (update) {
// Find the index and replace the entire object to avoid keeping old fields
const index = config.projects.indexOf(update);
config.projects[index] = newProjectConfig;
}
else {
config.projects.push(newProjectConfig);
}
await fs.writeFile(configPath, `export default ${JSON.stringify(config, null, 2)};`);
console.log(`✅ Config updated: ${name} at ${projectPath}`);
if (newProjectConfig.devServer) {
console.log(` Dev server: ${newProjectConfig.devServer.command} (port: ${newProjectConfig.devServer.port})`);
}
if (scheme) {
console.log(` URL scheme: ${scheme}`);
}
}
/**
* Normalize project config: migrate old format to new format
* Logs deprecation warnings when using old 'type' field
*/
export function normalizeProjectConfig(project, rootDir) {
// Already using new format
if (project.devServer) {
return project;
}
// Native type has no dev server
if (project.type === 'native') {
return project;
}
// Auto-migrate from old type-based format
if (project.type && project.type !== 'auto') {
console.warn(`⚠️ [${project.name}] Using deprecated 'type' field. ` +
`Migrate to 'devServer' config. See docs/MIGRATION_V2.md`);
const preset = TYPE_PRESETS[project.type];
if (!preset) {
console.error(`Unknown type '${project.type}' for project '${project.name}'`);
return project;
}
return {
...project,
devServer: {
...preset,
port: project.ptyPort || getDefaultPortForType(project.type)
}
};
}
return project;
}
export * from './config.js';
export * from './pnpm.js';
export * from './config.js';
export * from './pnpm.js';
/**
* if we're running in the agenteract monorepo, set node's CWD back to the original working directory
* otherwise pnpm commands have CWD set to the monorepo root
*/
export declare function resetPNPMWorkspaceCWD(): void;
/**
* if we're running in the agenteract monorepo, set node's CWD back to the original working directory
* otherwise pnpm commands have CWD set to the monorepo root
*/
export function resetPNPMWorkspaceCWD() {
if (process.env.PNPM_PACKAGE_NAME == 'agenteract' && process.env.PWD && process.env.PWD !== process.cwd()) {
process.chdir(process.env.PWD);
}
}
export interface DevServerConfig {
command: string;
port: number;
cwd?: string;
env?: Record<string, string>;
validation?: {
fileExists?: string[];
commandInPath?: string;
errorHints?: Record<string, string>;
};
keyCommands?: Record<string, string>;
}
export interface ProjectConfig {
name: string;
path: string;
type?: 'expo' | 'vite' | 'flutter' | 'native' | 'auto';
ptyPort?: number;
devServer?: DevServerConfig;
scheme?: string;
}
export interface AgenteractConfig {
server?: {
port?: number;
wsPort?: number;
logPort?: number;
};
port?: number;
projects: ProjectConfig[];
}
import { AgenteractConfig, DevServerConfig, ProjectConfig } from '../config-types.js';
export interface RuntimeConfig {
host: string;
port: number;
token: string;
defaultDevices?: Record<string, string>;
}
export declare function getRuntimeConfigPath(cwd?: string): string;
export declare function saveRuntimeConfig(config: RuntimeConfig, cwd?: string): Promise<void>;
export declare function loadRuntimeConfig(cwd?: string): Promise<RuntimeConfig | null>;
export declare function deleteRuntimeConfig(cwd?: string): Promise<void>;
export declare function generateAuthToken(): string;
/**
* Set the default device for a project
*/
export declare function setDefaultDevice(projectName: string, deviceId: string, cwd?: string): Promise<void>;
/**
* Get the default device for a project
*/
export declare function getDefaultDevice(projectName: string, cwd?: string): Promise<string | undefined>;
export declare class MissingConfigError extends Error {
constructor(message: string);
}
export declare function loadConfig(rootDir: string): Promise<AgenteractConfig>;
/**
* Find the root directory containing agenteract.config.js
* Searches upward from the current working directory
*/
export declare function findConfigRoot(startDir?: string): Promise<string | null>;
/**
* Get the URL for the agent server
*/
export declare function getAgentServerUrl(config: AgenteractConfig): string;
/**
* Get the URL for a project's dev server
*/
export declare function getProjectServerUrl(config: AgenteractConfig, projectName: string): string | null;
/**
* Get the URL for a dev server by type
*/
export declare function getDevServerUrlByType(config: AgenteractConfig, type: 'expo' | 'vite' | 'flutter'): string | null;
/**
* Type presets for backward compatibility
* Maps old 'type' field to new devServer configuration
*/
export declare const TYPE_PRESETS: Record<string, Omit<DevServerConfig, 'port'>>;
export declare function addConfig(rootDir: string, projectPath: string, name: string, typeOrCommand: string, port?: number, scheme?: string): Promise<void>;
/**
* Normalize project config: migrate old format to new format
* Logs deprecation warnings when using old 'type' field
*/
export declare function normalizeProjectConfig(project: ProjectConfig, rootDir: string): ProjectConfig;
import fs from 'fs/promises';
import path from 'path';
import { randomUUID } from 'crypto';
export function getRuntimeConfigPath(cwd = process.cwd()) {
return path.join(cwd, '.agenteract-runtime.json');
}
export async function saveRuntimeConfig(config, cwd = process.cwd()) {
await fs.writeFile(getRuntimeConfigPath(cwd), JSON.stringify(config, null, 2));
}
export async function loadRuntimeConfig(cwd = process.cwd()) {
try {
const content = await fs.readFile(getRuntimeConfigPath(cwd), 'utf-8');
return JSON.parse(content);
}
catch {
return null;
}
}
export async function deleteRuntimeConfig(cwd = process.cwd()) {
try {
await fs.unlink(getRuntimeConfigPath(cwd));
}
catch {
// Ignore if file doesn't exist
}
}
export function generateAuthToken() {
return randomUUID();
}
/**
* Set the default device for a project
*/
export async function setDefaultDevice(projectName, deviceId, cwd = process.cwd()) {
const config = await loadRuntimeConfig(cwd);
if (!config) {
throw new Error('Runtime config not found. Is the server running?');
}
if (!config.defaultDevices) {
config.defaultDevices = {};
}
config.defaultDevices[projectName] = deviceId;
await saveRuntimeConfig(config, cwd);
}
/**
* Get the default device for a project
*/
export async function getDefaultDevice(projectName, cwd = process.cwd()) {
const config = await loadRuntimeConfig(cwd);
return config?.defaultDevices?.[projectName];
}
export class MissingConfigError extends Error {
constructor(message) {
super(message);
this.name = 'MissingConfigError';
}
}
export async function loadConfig(rootDir) {
const configPath = path.join(rootDir, 'agenteract.config.js');
try {
await fs.access(configPath);
}
catch (error) {
throw new MissingConfigError('Agenteract config file not found');
}
// In a Jest environment, dynamic import() of file URLs can be tricky.
// A simple and effective workaround is to read the file and evaluate it.
// This avoids the module resolution issues within the test runner.
const configContent = await fs.readFile(configPath, 'utf-8');
// A simple regex to extract the default export object.
// This is not a full parser, but it's robust enough for our config file format.
const match = configContent.match(/export default (\{[\s\S]*\});/);
if (!match) {
console.error(`configContent: ${configContent}`);
throw new Error('Could not parse agenteract.config.js. Make sure it has a default export.');
}
// We can use Function to evaluate the object literal.
// It's safer than eval() because it doesn't have access to the outer scope.
return new Function(`return ${match[1]}`)();
}
/**
* Find the root directory containing agenteract.config.js
* Searches upward from the current working directory
*/
export async function findConfigRoot(startDir = process.cwd()) {
let currentDir = startDir;
const root = path.parse(currentDir).root;
while (currentDir !== root) {
const configPath = path.join(currentDir, 'agenteract.config.js');
try {
await fs.access(configPath);
return currentDir;
}
catch {
currentDir = path.dirname(currentDir);
}
}
return null;
}
/**
* Get the URL for the agent server
*/
export function getAgentServerUrl(config) {
return `http://localhost:${config.port || 8766}`;
}
/**
* Get the URL for a project's dev server
*/
export function getProjectServerUrl(config, projectName) {
const project = config.projects.find(p => p.name === projectName);
if (!project)
return null;
// Check new devServer format first, then legacy ptyPort
const port = project.devServer?.port || project.ptyPort;
if (!port) {
return null;
}
return `http://localhost:${port}`;
}
/**
* Get the URL for a dev server by type
*/
export function getDevServerUrlByType(config, type) {
const project = config.projects.find(p => p.type === type && (p.ptyPort || p.devServer?.port));
if (!project) {
return null;
}
const port = project.devServer?.port || project.ptyPort;
return `http://localhost:${port}`;
}
/**
* Type presets for backward compatibility
* Maps old 'type' field to new devServer configuration
*/
export const TYPE_PRESETS = {
expo: {
command: 'npx expo start',
keyCommands: { reload: 'r', ios: 'i', android: 'a' }
},
vite: {
command: 'npx vite',
keyCommands: { reload: 'r', quit: 'q' }
},
flutter: {
command: 'flutter run',
validation: {
fileExists: ['pubspec.yaml'],
commandInPath: 'flutter',
errorHints: {
'command not found': 'Install Flutter: https://flutter.dev/docs/get-started/install',
'No pubspec.yaml': 'Flutter projects require a pubspec.yaml file in the project directory'
}
},
keyCommands: { reload: 'r', restart: 'R', quit: 'q', help: 'h' }
}
};
/**
* Get default PTY port for a given type
*/
function getDefaultPortForType(type) {
const defaults = {
expo: 8790,
vite: 8791,
flutter: 8792
};
return defaults[type] || 8790;
}
export async function addConfig(rootDir, projectPath, name, typeOrCommand, port, scheme) {
const configPath = path.join(rootDir, 'agenteract.config.js');
let config;
try {
config = await loadConfig(rootDir);
}
catch (error) {
if (error instanceof MissingConfigError) {
config = { port: 8766, projects: [] };
}
else {
// For other errors (like parsing), we should not proceed.
throw error;
}
}
config.projects = config.projects || [];
let nameExists = config.projects.find((p) => p.name === name);
let pathExists = config.projects.find((p) => p.path === projectPath);
if ((nameExists || pathExists) && nameExists !== pathExists) {
console.error('project name and path exist across multiple projects. Please use a different name or path.');
console.error(`name: ${name}, path: ${projectPath}`);
return;
}
let update = nameExists || pathExists;
// Determine if this is legacy format (type) or new format (command)
const LEGACY_TYPES = ['expo', 'vite', 'flutter', 'native'];
const isLegacyFormat = LEGACY_TYPES.includes(typeOrCommand);
// Allocate a port if not provided
let ptyPort;
if (port) {
// Explicit port provided
ptyPort = port;
}
else if (update) {
// Reuse existing port when updating
ptyPort = update.ptyPort || update.devServer?.port || 8790;
}
else {
// Find next available port for new project
ptyPort = 8790;
while (config.projects.some((p) => (p.ptyPort === ptyPort) || (p.devServer?.port === ptyPort))) {
ptyPort++;
}
}
let newProjectConfig;
if (isLegacyFormat) {
// Legacy format: use old 'type' field for backwards compatibility
// Native apps don't have dev servers
if (typeOrCommand === 'native') {
newProjectConfig = {
name,
path: projectPath,
type: 'native',
...(scheme && { scheme })
};
}
else {
// For non-native legacy types, create with new devServer format
const preset = TYPE_PRESETS[typeOrCommand];
if (!preset) {
console.error(`Unknown type '${typeOrCommand}'`);
return;
}
newProjectConfig = {
name,
path: projectPath,
devServer: {
...preset,
port: ptyPort
},
...(scheme && { scheme })
};
console.log(`ℹ️ Creating config with new devServer format (migrated from legacy type '${typeOrCommand}')`);
}
}
else {
// New format: generic dev server command
newProjectConfig = {
name,
path: projectPath,
devServer: {
command: typeOrCommand,
port: ptyPort
},
...(scheme && { scheme })
};
}
// If the project already exists, replace it completely
if (update) {
// Find the index and replace the entire object to avoid keeping old fields
const index = config.projects.indexOf(update);
config.projects[index] = newProjectConfig;
}
else {
config.projects.push(newProjectConfig);
}
await fs.writeFile(configPath, `export default ${JSON.stringify(config, null, 2)};`);
console.log(`✅ Config updated: ${name} at ${projectPath}`);
if (newProjectConfig.devServer) {
console.log(` Dev server: ${newProjectConfig.devServer.command} (port: ${newProjectConfig.devServer.port})`);
}
if (scheme) {
console.log(` URL scheme: ${scheme}`);
}
}
/**
* Normalize project config: migrate old format to new format
* Logs deprecation warnings when using old 'type' field
*/
export function normalizeProjectConfig(project, rootDir) {
// Already using new format
if (project.devServer) {
return project;
}
// Native type has no dev server
if (project.type === 'native') {
return project;
}
// Auto-migrate from old type-based format
if (project.type && project.type !== 'auto') {
console.warn(`⚠️ [${project.name}] Using deprecated 'type' field. ` +
`Migrate to 'devServer' config. See docs/MIGRATION_V2.md`);
const preset = TYPE_PRESETS[project.type];
if (!preset) {
console.error(`Unknown type '${project.type}' for project '${project.name}'`);
return project;
}
return {
...project,
devServer: {
...preset,
port: project.ptyPort || getDefaultPortForType(project.type)
}
};
}
return project;
}
export * from './config.js';
export * from './pnpm.js';
export * from './config.js';
export * from './pnpm.js';
/**
* if we're running in the agenteract monorepo, set node's CWD back to the original working directory
* otherwise pnpm commands have CWD set to the monorepo root
*/
export declare function resetPNPMWorkspaceCWD(): void;
/**
* if we're running in the agenteract monorepo, set node's CWD back to the original working directory
* otherwise pnpm commands have CWD set to the monorepo root
*/
export function resetPNPMWorkspaceCWD() {
if (process.env.PNPM_PACKAGE_NAME == 'agenteract' && process.env.PWD && process.env.PWD !== process.cwd()) {
process.chdir(process.env.PWD);
}
}
+3
-1

@@ -1,1 +0,3 @@

{"type":"commonjs"}
{
"type": "commonjs"
}

@@ -19,1 +19,2 @@ export interface AgentCommand {

};
export * from './config-types.js';
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -33,1 +47,2 @@ exports.AGENTERACT_PROTOCOL_VERSION = void 0;

}
__exportStar(require("./config-types.js"), exports);

@@ -1,1 +0,3 @@

{"type":"module"}
{
"type": "module"
}

@@ -19,1 +19,2 @@ export interface AgentCommand {

};
export * from './config-types.js';

@@ -25,1 +25,2 @@ export const AGENTERACT_PROTOCOL_VERSION = '1.0.0';

}
export * from './config-types.js';

@@ -19,1 +19,2 @@ export interface AgentCommand {

};
export * from './config-types.js';

@@ -25,1 +25,2 @@ export const AGENTERACT_PROTOCOL_VERSION = '1.0.0';

}
export * from './config-types.js';
{
"name": "@agenteract/core",
"version": "0.0.3",
"version": "0.1.0",
"description": "Core message schema, bridge protocol, and shared utilities for Agenteract",

@@ -8,2 +8,8 @@ "main": "./dist/cjs/src/index.js",

"types": "./dist/cjs/src/index.d.ts",
"files": [
"dist/**/*.js",
"dist/**/*.d.ts",
"dist/**/package.json",
"!dist/**/*.tsbuildinfo"
],
"repository": {

@@ -31,2 +37,7 @@ "type": "git",

},
"./node": {
"import": "./dist/esm/src/node/index.js",
"require": "./dist/cjs/src/node/index.js",
"types": "./dist/cjs/src/node/index.d.ts"
},
"./package.json": "./package.json"

@@ -39,8 +50,9 @@ },

"scripts": {
"build": "npm run build:types && npm run build:cjs && npm run build:esm && npm run build:post",
"build": "pnpm run build:types && pnpm run build:cjs && pnpm run build:esm && pnpm run build:post",
"build:types": "tsc -p tsconfig.json",
"build:cjs": "tsc -p tsconfig.cjs.json",
"build:esm": "tsc -p tsconfig.esm.json",
"build:post": "echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json && echo '{\"type\":\"module\"}' > dist/esm/package.json"
"build:post": "shx mkdir -p dist/cjs dist/esm && node ../../scripts/write-package-json.js commonjs dist/cjs/package.json && node ../../scripts/write-package-json.js module dist/esm/package.json",
"clean": "shx rm -rf dist .tsbuildinfo*"
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Agenteract
Copyright 2025 Michael Ribbons
This product includes software developed by the Agenteract project (https://github.com/agenteract).
export interface AgentCommand {
action: string;
[key: string]: any;
}
export interface AgentResponse {
status: 'success' | 'error' | 'received';
[key: string]: any;
}
export const AGENTERACT_PROTOCOL_VERSION = '1.0.0';
export function encodeMessage(obj: object): string {
return JSON.stringify({ ...obj, _v: AGENTERACT_PROTOCOL_VERSION });
}
export function decodeMessage<T>(json: string): T {
return JSON.parse(json) as unknown as T;
}
export function sendCommand(command: AgentCommand): Promise<AgentResponse> {
return Promise.resolve({ status: 'success', response: 'Command sent' });
}
export function receiveResponse(response: AgentResponse): Promise<AgentCommand> {
return Promise.resolve({ action: 'response', response: response });
}
export function detectInvoker(): { pkgManager: string, isNpx: boolean, isPnpmDlx: boolean } {
const ua = process.env.npm_config_user_agent || '';
const execPath = process.env.npm_execpath || '';
const pkgManager =
ua.startsWith('pnpm/') ? 'pnpm' :
ua.startsWith('yarn/') ? 'yarn' :
ua.startsWith('npm/') ? 'npm' :
'unknown';
const isNpx = execPath.includes('npx-cli.js');
const isPnpmDlx = pkgManager === 'pnpm' && process.argv[1]?.includes('dlx');
return { pkgManager, isNpx, isPnpmDlx };
}
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "CommonJS",
"outDir": "dist/cjs"
}
}
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "ES2022",
"outDir": "dist/esm"
}
}
{
"extends": "../../tsconfig.base.json",
"exclude": ["node_modules", "dist"],
"include": ["src"],
"compilerOptions": {
"outDir": "dist",
"declaration": true,
"composite": true,
},
}