refactor: extract shellEscape to @agent-orchestrator/core

Move the duplicated POSIX shell-escaping utility from all three agent
plugins into packages/core/src/utils.ts and re-export from the package
entry point. Plugins now import { shellEscape } from the shared package.

Addresses Bugbot review comment on PR #5.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Prateek 2026-02-13 18:56:02 +05:30
parent a82737f2bd
commit f3151c2004
5 changed files with 44 additions and 53 deletions

View File

@ -43,3 +43,6 @@ export type { SessionManagerDeps } from "./session-manager.js";
// Lifecycle manager — state machine + reaction engine
export { createLifecycleManager } from "./lifecycle-manager.js";
export type { LifecycleManagerDeps } from "./lifecycle-manager.js";
// Shared utilities
export { shellEscape } from "./utils.js";

View File

@ -0,0 +1,13 @@
/**
* Shared utility functions for agent-orchestrator plugins.
*/
/**
* POSIX-safe shell escaping: wraps value in single quotes,
* escaping any embedded single quotes as '\\'' .
*
* Safe for use in both `sh -c` and `execFile` contexts.
*/
export function shellEscape(arg: string): string {
return "'" + arg.replace(/'/g, "'\\''") + "'";
}

View File

@ -1,11 +1,12 @@
import type {
Agent,
AgentIntrospection,
AgentLaunchConfig,
ActivityState,
PluginModule,
RuntimeHandle,
Session,
import {
shellEscape,
type Agent,
type AgentIntrospection,
type AgentLaunchConfig,
type ActivityState,
type PluginModule,
type RuntimeHandle,
type Session,
} from "@agent-orchestrator/core";
import { execFile } from "node:child_process";
import { promisify } from "node:util";
@ -27,14 +28,6 @@ export const manifest = {
// Agent Implementation
// =============================================================================
/**
* POSIX-safe shell escaping: wraps value in single quotes,
* escaping any embedded single quotes as '\'' .
*/
function shellEscape(arg: string): string {
return "'" + arg.replace(/'/g, "'\\''") + "'";
}
function createAiderAgent(): Agent {
return {
name: "aider",

View File

@ -1,12 +1,13 @@
import type {
Agent,
AgentIntrospection,
AgentLaunchConfig,
ActivityState,
CostEstimate,
PluginModule,
RuntimeHandle,
Session,
import {
shellEscape,
type Agent,
type AgentIntrospection,
type AgentLaunchConfig,
type ActivityState,
type CostEstimate,
type PluginModule,
type RuntimeHandle,
type Session,
} from "@agent-orchestrator/core";
import { execFile } from "node:child_process";
import { readdir, readFile, stat } from "node:fs/promises";
@ -197,18 +198,6 @@ function extractCost(lines: JsonlLine[]): CostEstimate | undefined {
return { inputTokens, outputTokens, estimatedCostUsd: totalCost };
}
// =============================================================================
// Shell Escaping
// =============================================================================
/**
* POSIX-safe shell escaping: wraps value in single quotes,
* escaping any embedded single quotes as '\'' .
*/
function shellEscape(arg: string): string {
return "'" + arg.replace(/'/g, "'\\''") + "'";
}
// =============================================================================
// Activity Detection Patterns
// =============================================================================

View File

@ -1,11 +1,12 @@
import type {
Agent,
AgentIntrospection,
AgentLaunchConfig,
ActivityState,
PluginModule,
RuntimeHandle,
Session,
import {
shellEscape,
type Agent,
type AgentIntrospection,
type AgentLaunchConfig,
type ActivityState,
type PluginModule,
type RuntimeHandle,
type Session,
} from "@agent-orchestrator/core";
import { execFile } from "node:child_process";
import { promisify } from "node:util";
@ -27,14 +28,6 @@ export const manifest = {
// Agent Implementation
// =============================================================================
/**
* POSIX-safe shell escaping: wraps value in single quotes,
* escaping any embedded single quotes as '\'' .
*/
function shellEscape(arg: string): string {
return "'" + arg.replace(/'/g, "'\\''") + "'";
}
function createCodexAgent(): Agent {
return {
name: "codex",