feat: scaffold TypeScript monorepo with all plugin interfaces

Phase 0 complete. Establishes:
- pnpm workspace with 18 packages (core, cli, web, 15 plugins)
- Complete type definitions in packages/core/src/types.ts defining
  all 8 plugin slot interfaces (Runtime, Agent, Workspace, Tracker,
  SCM, Notifier, Terminal) + core service interfaces
- YAML config loader with Zod validation and sensible defaults
- Plugin registry with built-in discovery
- CLAUDE.md with conventions for spawned agents

All agents can now branch from main and implement their assigned
packages against the interfaces defined in types.ts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Prateek 2026-02-13 17:02:42 +05:30
parent 36b0792eb6
commit 5058c409d5
65 changed files with 3434 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
node_modules/
dist/
.next/
*.tsbuildinfo
.env
.env.local

132
CLAUDE.md Normal file
View File

@ -0,0 +1,132 @@
# CLAUDE.md — Agent Orchestrator
## What This Project Is
An open-source, agent-agnostic system for orchestrating parallel AI coding agents. Any coding agent, any repo, any issue tracker, any runtime. The system manages session lifecycle, tracks PR/CI/review state, auto-handles routine issues (CI failures, review comments), and pushes notifications to humans only when their judgment is needed.
**Core principle: Push, not pull.** The human spawns agents, walks away, and gets notified when needed.
## Tech Stack
- **Language**: TypeScript throughout (ESM, Node 20+)
- **Monorepo**: pnpm workspaces
- **Web**: Next.js 15 (App Router) + Tailwind CSS
- **CLI**: Commander.js
- **Config**: YAML + Zod validation
- **Real-time**: Server-Sent Events
- **State**: Flat metadata files + JSONL event log
## Architecture
8 plugin slots — every abstraction is swappable:
| Slot | Interface | Default Plugin |
|------|-----------|---------------|
| Runtime | `Runtime` | tmux |
| Agent | `Agent` | claude-code |
| Workspace | `Workspace` | worktree |
| Tracker | `Tracker` | github |
| SCM | `SCM` | github |
| Notifier | `Notifier` | desktop |
| Terminal | `Terminal` | iterm2 |
| Lifecycle | (core, not pluggable) | — |
All interfaces are defined in `packages/core/src/types.ts`. **Read this file first** — it is the source of truth for all abstractions.
## Directory Structure
```
packages/
core/ — @agent-orchestrator/core (types, config, services)
cli/ — @agent-orchestrator/cli (the `ao` command)
web/ — @agent-orchestrator/web (Next.js dashboard)
plugins/
runtime-tmux/ — tmux session runtime
runtime-process/ — child process runtime
agent-claude-code/ — Claude Code adapter
agent-codex/ — Codex CLI adapter
agent-aider/ — Aider adapter
workspace-worktree/ — git worktree isolation
workspace-clone/ — git clone isolation
tracker-github/ — GitHub Issues tracker
tracker-linear/ — Linear tracker
scm-github/ — GitHub PRs, CI, reviews
notifier-desktop/ — OS desktop notifications
notifier-slack/ — Slack notifications
notifier-webhook/ — Generic webhook notifications
terminal-iterm2/ — macOS iTerm2 tab management
terminal-web/ — xterm.js web terminal
```
## Conventions
### TypeScript
- ESM modules (`"type": "module"`)
- Use `.js` extensions in imports (TypeScript ESM requirement): `import { foo } from "./bar.js"`
- Strict mode enabled
- Use `node:` prefix for Node.js builtins: `import { readFileSync } from "node:fs"`
### Plugin Structure
Every plugin exports a `PluginModule`:
```typescript
import type { PluginModule, Runtime } from "@agent-orchestrator/core";
export const manifest = {
name: "tmux",
slot: "runtime" as const,
description: "Runtime plugin: tmux sessions",
version: "0.1.0",
};
export function create(): Runtime {
return {
name: "tmux",
// ... implement interface
};
}
```
### Shell Commands
When a plugin needs to run shell commands (git, tmux, gh, etc.), use `child_process.execFile` or `child_process.spawn` from `node:child_process`. Wrap them in async helpers.
### Error Handling
- Throw typed errors, don't return error codes
- Plugin methods should throw if they can't do their job
- The core services catch and handle plugin errors
### Config
- Config is loaded from `agent-orchestrator.yaml` (see `.yaml.example`)
- All paths support `~` expansion
- Per-project overrides for plugins and reactions
## Reference Implementation
The `scripts/` directory contains the original bash scripts that this TypeScript codebase replaces. Use them as specifications:
| Script | What It Specifies |
|--------|------------------|
| `claude-ao-session` | Session lifecycle (spawn, list, kill, cleanup) |
| `claude-dashboard` | Web dashboard, API, activity detection |
| `claude-batch-spawn` | Batch spawning with duplicate detection |
| `send-to-session` | Smart message delivery (busy detection, wait-for-idle) |
| `claude-status` | JSONL introspection, live branch detection |
| `claude-review-check` | PR review scanning, fix prompt generation |
| `claude-bugbot-fix` | Automated comment detection + fixes |
| `claude-session-status` | Activity classification (working/idle/blocked) |
| `get-claude-session-info` | Agent introspection (session ID, summary extraction) |
## Building
```bash
pnpm install
pnpm build # build all packages
pnpm typecheck # typecheck all packages
```
## Key Design Decisions
1. **Stateless orchestrator** — no database, just flat metadata files + event log
2. **Plugins implement interfaces** — every plugin is a pure implementation of an interface from `types.ts`
3. **Push notifications** — the Notifier is the primary human interface, not the dashboard
4. **Two-tier event handling** — auto-handle routine issues (CI, reviews), notify human only when judgment is needed
5. **Backwards-compatible metadata** — flat key=value files matching the existing bash script format

View File

@ -0,0 +1,86 @@
# Agent Orchestrator Configuration
# Copy to agent-orchestrator.yaml and customize.
# Where to store session metadata
dataDir: ~/.agent-orchestrator
# Where to create workspaces (git worktrees, clones)
worktreeDir: ~/.worktrees
# Web dashboard port
port: 3000
# Default plugins (these are the defaults — you can omit this section)
defaults:
runtime: tmux # tmux | process | docker | kubernetes | ssh | e2b
agent: claude-code # claude-code | codex | aider | goose | custom
workspace: worktree # worktree | clone | copy
notifiers: [desktop] # desktop | slack | discord | webhook | email
# Projects — at minimum, specify repo and path
projects:
my-app:
name: My App
repo: org/my-app
path: ~/my-app
defaultBranch: main
sessionPrefix: app
# Issue tracker (defaults to github issues)
# tracker:
# plugin: linear
# teamId: "your-team-id"
# Files to symlink into workspaces
# symlinks: [.env, .claude]
# Commands to run after workspace creation
# postCreate:
# - "pnpm install"
# Agent-specific config
# agentConfig:
# permissions: skip # --dangerously-skip-permissions
# model: opus
# Per-project reaction overrides
# reactions:
# approved-and-green:
# auto: true # enable auto-merge for this project
# Notification channels
# notifiers:
# slack:
# plugin: slack
# webhook: ${SLACK_WEBHOOK_URL}
# channel: "#agent-updates"
# Notification routing by priority
# notificationRouting:
# urgent: [desktop, slack] # agent stuck, needs input, errored
# action: [desktop, slack] # PR ready to merge
# warning: [slack] # auto-fix failed
# info: [slack] # summary, all done
# Reactions — auto-responses to events (these are the defaults)
# reactions:
# ci-failed:
# auto: true
# action: send-to-agent
# retries: 2
# escalateAfter: 2
#
# changes-requested:
# auto: true
# action: send-to-agent
# escalateAfter: 30m
#
# approved-and-green:
# auto: false # set to true for auto-merge
# action: notify
# priority: action
#
# agent-stuck:
# threshold: 10m
# action: notify
# priority: urgent

18
package.json Normal file
View File

@ -0,0 +1,18 @@
{
"name": "agent-orchestrator",
"version": "0.1.0",
"private": true,
"description": "Orchestrate parallel AI coding agents across any runtime, any repo, any issue tracker",
"license": "MIT",
"engines": {
"node": ">=20.0.0"
},
"packageManager": "pnpm@9.15.4",
"scripts": {
"build": "pnpm -r build",
"dev": "pnpm --filter @agent-orchestrator/web dev",
"lint": "pnpm -r lint",
"typecheck": "pnpm -r typecheck",
"clean": "pnpm -r clean"
}
}

27
packages/cli/package.json Normal file
View File

@ -0,0 +1,27 @@
{
"name": "@agent-orchestrator/cli",
"version": "0.1.0",
"description": "CLI for agent-orchestrator — the `ao` command",
"type": "module",
"bin": {
"ao": "dist/index.js"
},
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"dev": "tsx src/index.ts",
"typecheck": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"@agent-orchestrator/core": "workspace:*",
"chalk": "^5.4.0",
"commander": "^13.0.0",
"ora": "^8.1.0"
},
"devDependencies": {
"@types/node": "^25.2.3",
"tsx": "^4.19.0",
"typescript": "^5.7.0"
}
}

View File

@ -0,0 +1,2 @@
#!/usr/bin/env node
// CLI entry point — to be implemented

View File

@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

View File

@ -0,0 +1,31 @@
{
"name": "@agent-orchestrator/core",
"version": "0.1.0",
"description": "Core library — types, config, session manager, lifecycle manager, event bus",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"./types": {
"types": "./dist/types.d.ts",
"import": "./dist/types.js"
}
},
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"yaml": "^2.7.0",
"zod": "^3.24.0"
},
"devDependencies": {
"@types/node": "^25.2.3",
"typescript": "^5.7.0"
}
}

283
packages/core/src/config.ts Normal file
View File

@ -0,0 +1,283 @@
/**
* Configuration loader reads agent-orchestrator.yaml and validates with Zod.
*
* Minimal config that just works:
* projects:
* my-app:
* repo: org/repo
* path: ~/my-app
*
* Everything else has sensible defaults.
*/
import { readFileSync, existsSync } from "node:fs";
import { resolve, join } from "node:path";
import { homedir } from "node:os";
import { parse as parseYaml } from "yaml";
import { z } from "zod";
import type { OrchestratorConfig } from "./types.js";
// =============================================================================
// ZOD SCHEMAS
// =============================================================================
const ReactionConfigSchema = z.object({
auto: z.boolean().default(true),
action: z.enum(["send-to-agent", "notify", "auto-merge"]).default("notify"),
message: z.string().optional(),
priority: z.enum(["urgent", "action", "warning", "info"]).optional(),
retries: z.number().optional(),
escalateAfter: z.union([z.number(), z.string()]).optional(),
threshold: z.string().optional(),
includeSummary: z.boolean().optional(),
});
const TrackerConfigSchema = z
.object({
plugin: z.string(),
})
.passthrough();
const SCMConfigSchema = z
.object({
plugin: z.string(),
})
.passthrough();
const NotifierConfigSchema = z
.object({
plugin: z.string(),
})
.passthrough();
const AgentSpecificConfigSchema = z
.object({
permissions: z.enum(["skip", "default"]).optional(),
model: z.string().optional(),
})
.passthrough();
const ProjectConfigSchema = z.object({
name: z.string().optional(),
repo: z.string(),
path: z.string(),
defaultBranch: z.string().default("main"),
sessionPrefix: z.string().optional(),
runtime: z.string().optional(),
agent: z.string().optional(),
workspace: z.string().optional(),
tracker: TrackerConfigSchema.optional(),
scm: SCMConfigSchema.optional(),
symlinks: z.array(z.string()).optional(),
postCreate: z.array(z.string()).optional(),
agentConfig: AgentSpecificConfigSchema.optional(),
reactions: z.record(ReactionConfigSchema.partial()).optional(),
});
const DefaultPluginsSchema = z.object({
runtime: z.string().default("tmux"),
agent: z.string().default("claude-code"),
workspace: z.string().default("worktree"),
notifiers: z.array(z.string()).default(["desktop"]),
});
const OrchestratorConfigSchema = z.object({
dataDir: z.string().default("~/.agent-orchestrator"),
worktreeDir: z.string().default("~/.worktrees"),
port: z.number().default(3000),
defaults: DefaultPluginsSchema.default({}),
projects: z.record(ProjectConfigSchema),
notifiers: z.record(NotifierConfigSchema).default({}),
notificationRouting: z
.record(z.array(z.string()))
.default({
urgent: ["desktop", "slack"],
action: ["desktop", "slack"],
warning: ["slack"],
info: ["slack"],
}),
reactions: z.record(ReactionConfigSchema).default({}),
});
// =============================================================================
// CONFIG LOADING
// =============================================================================
/** Expand ~ to home directory */
function expandHome(filepath: string): string {
if (filepath.startsWith("~/")) {
return join(homedir(), filepath.slice(2));
}
return filepath;
}
/** Expand all path fields in the config */
function expandPaths(config: OrchestratorConfig): OrchestratorConfig {
config.dataDir = expandHome(config.dataDir);
config.worktreeDir = expandHome(config.worktreeDir);
for (const project of Object.values(config.projects)) {
project.path = expandHome(project.path);
}
return config;
}
/** Apply defaults to project configs */
function applyProjectDefaults(
config: OrchestratorConfig
): OrchestratorConfig {
for (const [id, project] of Object.entries(config.projects)) {
// Derive name from project ID if not set
if (!project.name) {
project.name = id;
}
// Derive session prefix from project ID if not set
if (!project.sessionPrefix) {
project.sessionPrefix = id;
}
// Infer SCM from repo if not set
if (!project.scm && project.repo.includes("/")) {
project.scm = { plugin: "github" };
}
// Infer tracker from repo if not set (default to github issues)
if (!project.tracker) {
project.tracker = { plugin: "github" };
}
}
return config;
}
/** Apply default reactions */
function applyDefaultReactions(
config: OrchestratorConfig
): OrchestratorConfig {
const defaults: Record<string, typeof config.reactions[string]> = {
"ci-failed": {
auto: true,
action: "send-to-agent",
message:
"CI is failing on your PR. Run `gh pr checks` to see the failures, fix them, and push.",
retries: 2,
escalateAfter: 2,
},
"changes-requested": {
auto: true,
action: "send-to-agent",
message:
"There are review comments on your PR. Check with `gh pr view --comments` and `gh api` for inline comments. Address each one, push fixes, and reply.",
escalateAfter: "30m",
},
"bugbot-comments": {
auto: true,
action: "send-to-agent",
message:
"Automated review comments found on your PR. Fix the issues flagged by the bot.",
escalateAfter: "30m",
},
"merge-conflicts": {
auto: true,
action: "send-to-agent",
message:
"Your branch has merge conflicts. Rebase on the default branch and resolve them.",
escalateAfter: "15m",
},
"approved-and-green": {
auto: false,
action: "notify",
priority: "action",
message: "PR is ready to merge",
},
"agent-stuck": {
auto: true,
action: "notify",
priority: "urgent",
threshold: "10m",
},
"agent-needs-input": {
auto: true,
action: "notify",
priority: "urgent",
},
"agent-exited": {
auto: true,
action: "notify",
priority: "urgent",
},
"all-complete": {
auto: true,
action: "notify",
priority: "info",
includeSummary: true,
},
};
// Merge defaults with user-specified reactions (user wins)
config.reactions = { ...defaults, ...config.reactions };
return config;
}
/** Search for config file in standard locations */
function findConfigFile(startDir?: string): string | null {
const searchPaths = [
startDir ? resolve(startDir, "agent-orchestrator.yaml") : null,
startDir ? resolve(startDir, "agent-orchestrator.yml") : null,
resolve(process.cwd(), "agent-orchestrator.yaml"),
resolve(process.cwd(), "agent-orchestrator.yml"),
resolve(homedir(), ".agent-orchestrator.yaml"),
resolve(homedir(), ".agent-orchestrator.yml"),
resolve(homedir(), ".config", "agent-orchestrator", "config.yaml"),
].filter((p): p is string => p !== null);
for (const path of searchPaths) {
if (existsSync(path)) {
return path;
}
}
return null;
}
// =============================================================================
// PUBLIC API
// =============================================================================
/** Load and validate config from a YAML file */
export function loadConfig(configPath?: string): OrchestratorConfig {
const path = configPath ?? findConfigFile();
if (!path) {
throw new Error(
"No agent-orchestrator.yaml found. Run `ao init` to create one."
);
}
const raw = readFileSync(path, "utf-8");
const parsed = parseYaml(raw);
return validateConfig(parsed);
}
/** Validate a raw config object */
export function validateConfig(raw: unknown): OrchestratorConfig {
const validated = OrchestratorConfigSchema.parse(raw);
let config = validated as OrchestratorConfig;
config = expandPaths(config);
config = applyProjectDefaults(config);
config = applyDefaultReactions(config);
return config;
}
/** Get the default config (useful for `ao init`) */
export function getDefaultConfig(): OrchestratorConfig {
return validateConfig({
projects: {},
});
}

View File

@ -0,0 +1,15 @@
/**
* @agent-orchestrator/core
*
* Core library for the Agent Orchestrator.
* Exports all types, config loader, and service implementations.
*/
// Types — everything plugins and consumers need
export * from "./types.js";
// Config — YAML loader + validation
export { loadConfig, validateConfig, getDefaultConfig } from "./config.js";
// Plugin registry
export { createPluginRegistry } from "./plugin-registry.js";

View File

@ -0,0 +1,98 @@
/**
* Plugin Registry discovers and loads plugins.
*
* Plugins can be:
* 1. Built-in (packages/plugins/*)
* 2. npm packages (@agent-orchestrator/plugin-*)
* 3. Local file paths specified in config
*/
import type {
PluginSlot,
PluginManifest,
PluginModule,
PluginRegistry,
OrchestratorConfig,
} from "./types.js";
/** Map from "slot:name" → plugin instance */
type PluginMap = Map<string, { manifest: PluginManifest; instance: unknown }>;
function makeKey(slot: PluginSlot, name: string): string {
return `${slot}:${name}`;
}
/** Built-in plugin package names, mapped to their npm package */
const BUILTIN_PLUGINS: Array<{ slot: PluginSlot; name: string; pkg: string }> = [
// Runtimes
{ slot: "runtime", name: "tmux", pkg: "@agent-orchestrator/plugin-runtime-tmux" },
{ slot: "runtime", name: "process", pkg: "@agent-orchestrator/plugin-runtime-process" },
// Agents
{ slot: "agent", name: "claude-code", pkg: "@agent-orchestrator/plugin-agent-claude-code" },
{ slot: "agent", name: "codex", pkg: "@agent-orchestrator/plugin-agent-codex" },
{ slot: "agent", name: "aider", pkg: "@agent-orchestrator/plugin-agent-aider" },
// Workspaces
{ slot: "workspace", name: "worktree", pkg: "@agent-orchestrator/plugin-workspace-worktree" },
{ slot: "workspace", name: "clone", pkg: "@agent-orchestrator/plugin-workspace-clone" },
// Trackers
{ slot: "tracker", name: "github", pkg: "@agent-orchestrator/plugin-tracker-github" },
{ slot: "tracker", name: "linear", pkg: "@agent-orchestrator/plugin-tracker-linear" },
// SCM
{ slot: "scm", name: "github", pkg: "@agent-orchestrator/plugin-scm-github" },
// Notifiers
{ slot: "notifier", name: "desktop", pkg: "@agent-orchestrator/plugin-notifier-desktop" },
{ slot: "notifier", name: "slack", pkg: "@agent-orchestrator/plugin-notifier-slack" },
{ slot: "notifier", name: "webhook", pkg: "@agent-orchestrator/plugin-notifier-webhook" },
// Terminals
{ slot: "terminal", name: "iterm2", pkg: "@agent-orchestrator/plugin-terminal-iterm2" },
{ slot: "terminal", name: "web", pkg: "@agent-orchestrator/plugin-terminal-web" },
];
export function createPluginRegistry(): PluginRegistry {
const plugins: PluginMap = new Map();
return {
register(plugin: PluginModule): void {
const { manifest } = plugin;
const key = makeKey(manifest.slot, manifest.name);
const instance = plugin.create();
plugins.set(key, { manifest, instance });
},
get<T>(slot: PluginSlot, name: string): T | null {
const entry = plugins.get(makeKey(slot, name));
return entry ? (entry.instance as T) : null;
},
list(slot: PluginSlot): PluginManifest[] {
const result: PluginManifest[] = [];
for (const [key, entry] of plugins) {
if (key.startsWith(`${slot}:`)) {
result.push(entry.manifest);
}
}
return result;
},
async loadBuiltins(): Promise<void> {
for (const builtin of BUILTIN_PLUGINS) {
try {
const mod = (await import(builtin.pkg)) as PluginModule;
if (mod.manifest && typeof mod.create === "function") {
this.register(mod);
}
} catch {
// Plugin not installed — that's fine, only load what's available
}
}
},
async loadFromConfig(config: OrchestratorConfig): Promise<void> {
// First, load all built-ins
await this.loadBuiltins();
// Then, load any additional plugins specified in project configs
// (future: support npm package names and local file paths)
},
};
}

842
packages/core/src/types.ts Normal file
View File

@ -0,0 +1,842 @@
/**
* Agent Orchestrator Core Type Definitions
*
* This file defines ALL interfaces and types that the system uses.
* Every plugin, CLI command, and web API route builds against these.
*
* Architecture: 8 plugin slots + core services
* 1. Runtime where sessions execute (tmux, docker, k8s, process)
* 2. Agent AI coding tool (claude-code, codex, aider)
* 3. Workspace code isolation (worktree, clone)
* 4. Tracker issue tracking (github, linear, jira)
* 5. SCM source platform + PR/CI/reviews (github, gitlab)
* 6. Notifier push notifications (desktop, slack, webhook)
* 7. Terminal human interaction UI (iterm2, web, none)
* 8. Lifecycle Manager (core, not pluggable)
*/
// =============================================================================
// SESSION
// =============================================================================
/** Unique session identifier, e.g. "my-app-1", "backend-12" */
export type SessionId = string;
/** Session lifecycle states */
export type SessionStatus =
| "spawning"
| "working"
| "pr_open"
| "ci_failed"
| "review_pending"
| "changes_requested"
| "approved"
| "mergeable"
| "merged"
| "cleanup"
| "needs_input"
| "stuck"
| "errored"
| "killed";
/** Activity state as detected by the agent plugin */
export type ActivityState =
| "active" // agent is processing (thinking, writing code)
| "idle" // agent is at prompt, waiting for input
| "waiting_input" // agent is asking a question / permission prompt
| "blocked" // agent hit an error or is stuck
| "exited"; // agent process is no longer running
/** A running agent session */
export interface Session {
/** Unique session ID, e.g. "my-app-3" */
id: SessionId;
/** Which project this session belongs to */
projectId: string;
/** Current lifecycle status */
status: SessionStatus;
/** Activity state from agent plugin */
activity: ActivityState;
/** Git branch name */
branch: string | null;
/** Issue identifier (if working on an issue) */
issueId: string | null;
/** PR info (once PR is created) */
pr: PRInfo | null;
/** Workspace path on disk */
workspacePath: string | null;
/** Runtime handle for communicating with the session */
runtimeHandle: RuntimeHandle | null;
/** Agent introspection data (summary, cost, etc.) */
agentInfo: AgentIntrospection | null;
/** When the session was created */
createdAt: Date;
/** Last activity timestamp */
lastActivityAt: Date;
/** Metadata key-value pairs */
metadata: Record<string, string>;
}
/** Config for creating a new session */
export interface SessionSpawnConfig {
projectId: string;
issueId?: string;
branch?: string;
prompt?: string;
}
// =============================================================================
// RUNTIME — Plugin Slot 1
// =============================================================================
/**
* Runtime determines WHERE and HOW agent sessions execute.
* tmux, docker, kubernetes, child processes, SSH, cloud sandboxes, etc.
*/
export interface Runtime {
readonly name: string;
/** Create a new session environment and return a handle */
create(config: RuntimeCreateConfig): Promise<RuntimeHandle>;
/** Destroy a session environment */
destroy(handle: RuntimeHandle): Promise<void>;
/** Send a text message/prompt to the running agent */
sendMessage(handle: RuntimeHandle, message: string): Promise<void>;
/** Capture recent output from the session */
getOutput(handle: RuntimeHandle, lines?: number): Promise<string>;
/** Check if the session environment is still alive */
isAlive(handle: RuntimeHandle): Promise<boolean>;
/** Get resource metrics (uptime, memory, etc.) */
getMetrics?(handle: RuntimeHandle): Promise<RuntimeMetrics>;
/** Get info needed to attach a human to this session (for Terminal plugin) */
getAttachInfo?(handle: RuntimeHandle): Promise<AttachInfo>;
}
export interface RuntimeCreateConfig {
sessionId: SessionId;
workspacePath: string;
launchCommand: string;
environment: Record<string, string>;
}
/** Opaque handle returned by runtime.create() */
export interface RuntimeHandle {
/** Runtime-specific identifier (tmux session name, container ID, pod name, etc.) */
id: string;
/** Which runtime created this handle */
runtimeName: string;
/** Runtime-specific data */
data: Record<string, unknown>;
}
export interface RuntimeMetrics {
uptimeMs: number;
memoryMb?: number;
cpuPercent?: number;
}
export interface AttachInfo {
/** How to connect: tmux attach, docker exec, SSH, web URL, etc. */
type: "tmux" | "docker" | "ssh" | "web" | "process";
/** For tmux: session name. For docker: container ID. For web: URL. */
target: string;
/** Optional: command to run to attach */
command?: string;
}
// =============================================================================
// AGENT — Plugin Slot 2
// =============================================================================
/**
* Agent adapter for a specific AI coding tool.
* Knows how to launch, detect activity, and introspect the agent.
*/
export interface Agent {
readonly name: string;
/** Process name to look for (e.g. "claude", "codex", "aider") */
readonly processName: string;
/** Get the shell command to launch this agent */
getLaunchCommand(config: AgentLaunchConfig): string;
/** Get environment variables for the agent process */
getEnvironment(config: AgentLaunchConfig): Record<string, string>;
/** Detect what the agent is currently doing */
detectActivity(session: Session): Promise<ActivityState>;
/** Check if agent process is running (given runtime handle) */
isProcessRunning(handle: RuntimeHandle): Promise<boolean>;
/** Extract information from agent's internal data (summary, cost, session ID) */
introspect(session: Session): Promise<AgentIntrospection | null>;
/** Optional: run setup after agent is launched (e.g. configure MCP servers) */
postLaunchSetup?(session: Session): Promise<void>;
}
export interface AgentLaunchConfig {
sessionId: SessionId;
projectConfig: ProjectConfig;
issueId?: string;
prompt?: string;
permissions?: "skip" | "default";
model?: string;
}
export interface AgentIntrospection {
/** Agent's auto-generated summary of what it's working on */
summary: string | null;
/** Agent's internal session ID (for resume) */
agentSessionId: string | null;
/** Estimated cost so far */
cost?: CostEstimate;
/** Last message type in agent's log */
lastMessageType?: string;
/** When agent's log was last modified */
lastLogModified?: Date;
}
export interface CostEstimate {
inputTokens: number;
outputTokens: number;
estimatedCostUsd: number;
}
// =============================================================================
// WORKSPACE — Plugin Slot 3
// =============================================================================
/**
* Workspace manages code isolation how each session gets its own copy of the repo.
*/
export interface Workspace {
readonly name: string;
/** Create an isolated workspace for a session */
create(config: WorkspaceCreateConfig): Promise<WorkspaceInfo>;
/** Destroy a workspace */
destroy(workspacePath: string): Promise<void>;
/** List existing workspaces for a project */
list(projectId: string): Promise<WorkspaceInfo[]>;
/** Optional: run hooks after workspace creation (symlinks, installs, etc.) */
postCreate?(info: WorkspaceInfo, project: ProjectConfig): Promise<void>;
}
export interface WorkspaceCreateConfig {
projectId: string;
project: ProjectConfig;
sessionId: SessionId;
branch: string;
}
export interface WorkspaceInfo {
path: string;
branch: string;
sessionId: SessionId;
projectId: string;
}
// =============================================================================
// TRACKER — Plugin Slot 4
// =============================================================================
/**
* Issue/task tracker integration GitHub Issues, Linear, Jira, etc.
*/
export interface Tracker {
readonly name: string;
/** Fetch issue details */
getIssue(identifier: string, project: ProjectConfig): Promise<Issue>;
/** Check if issue is completed/closed */
isCompleted(identifier: string, project: ProjectConfig): Promise<boolean>;
/** Generate a URL for the issue */
issueUrl(identifier: string, project: ProjectConfig): string;
/** Generate a git branch name for the issue */
branchName(identifier: string, project: ProjectConfig): string;
/** Generate a prompt for the agent to work on this issue */
generatePrompt(identifier: string, project: ProjectConfig): Promise<string>;
/** Optional: list issues with filters */
listIssues?(filters: IssueFilters, project: ProjectConfig): Promise<Issue[]>;
/** Optional: update issue state */
updateIssue?(identifier: string, update: IssueUpdate, project: ProjectConfig): Promise<void>;
/** Optional: create a new issue */
createIssue?(input: CreateIssueInput, project: ProjectConfig): Promise<Issue>;
}
export interface Issue {
id: string;
title: string;
description: string;
url: string;
state: "open" | "in_progress" | "closed" | "cancelled";
labels: string[];
assignee?: string;
priority?: number;
}
export interface IssueFilters {
state?: "open" | "closed" | "all";
labels?: string[];
assignee?: string;
limit?: number;
}
export interface IssueUpdate {
state?: "open" | "in_progress" | "closed";
labels?: string[];
assignee?: string;
comment?: string;
}
export interface CreateIssueInput {
title: string;
description: string;
labels?: string[];
assignee?: string;
priority?: number;
}
// =============================================================================
// SCM — Plugin Slot 5
// =============================================================================
/**
* Source code management platform PR lifecycle, CI checks, code reviews.
* This is the richest plugin interface, covering the full PR pipeline.
*/
export interface SCM {
readonly name: string;
// --- PR Lifecycle ---
/** Detect if a session has an open PR (by branch name) */
detectPR(session: Session, project: ProjectConfig): Promise<PRInfo | null>;
/** Get current PR state */
getPRState(pr: PRInfo): Promise<PRState>;
/** Merge a PR */
mergePR(pr: PRInfo, method?: MergeMethod): Promise<void>;
/** Close a PR without merging */
closePR(pr: PRInfo): Promise<void>;
// --- CI Tracking ---
/** Get individual CI check statuses */
getCIChecks(pr: PRInfo): Promise<CICheck[]>;
/** Get overall CI summary */
getCISummary(pr: PRInfo): Promise<CIStatus>;
// --- Review Tracking ---
/** Get all reviews on a PR */
getReviews(pr: PRInfo): Promise<Review[]>;
/** Get the overall review decision */
getReviewDecision(pr: PRInfo): Promise<ReviewDecision>;
/** Get pending (unresolved) review comments */
getPendingComments(pr: PRInfo): Promise<ReviewComment[]>;
/** Get automated review comments (bots, linters, security scanners) */
getAutomatedComments(pr: PRInfo): Promise<AutomatedComment[]>;
// --- Merge Readiness ---
/** Check if PR is ready to merge */
getMergeability(pr: PRInfo): Promise<MergeReadiness>;
}
// --- PR Types ---
export interface PRInfo {
number: number;
url: string;
title: string;
owner: string;
repo: string;
branch: string;
baseBranch: string;
isDraft: boolean;
}
export type PRState = "open" | "merged" | "closed";
export type MergeMethod = "merge" | "squash" | "rebase";
// --- CI Types ---
export interface CICheck {
name: string;
status: "pending" | "running" | "passed" | "failed" | "skipped";
url?: string;
conclusion?: string;
startedAt?: Date;
completedAt?: Date;
}
export type CIStatus = "pending" | "passing" | "failing" | "none";
// --- Review Types ---
export interface Review {
author: string;
state: "approved" | "changes_requested" | "commented" | "dismissed" | "pending";
body?: string;
submittedAt: Date;
}
export type ReviewDecision = "approved" | "changes_requested" | "pending" | "none";
export interface ReviewComment {
id: string;
author: string;
body: string;
path?: string;
line?: number;
isResolved: boolean;
createdAt: Date;
url: string;
}
export interface AutomatedComment {
id: string;
botName: string;
body: string;
path?: string;
line?: number;
severity: "error" | "warning" | "info";
createdAt: Date;
url: string;
}
// --- Merge Readiness ---
export interface MergeReadiness {
mergeable: boolean;
ciPassing: boolean;
approved: boolean;
noConflicts: boolean;
blockers: string[];
}
// =============================================================================
// NOTIFIER — Plugin Slot 6 (PRIMARY INTERFACE)
// =============================================================================
/**
* Notifier is the PRIMARY interface between the orchestrator and the human.
* The human walks away after spawning agents. Notifications bring them back.
*
* Push, not pull. The human never polls.
*/
export interface Notifier {
readonly name: string;
/** Push a notification to the human */
notify(event: OrchestratorEvent): Promise<void>;
/** Push a notification with actionable buttons/links */
notifyWithActions?(event: OrchestratorEvent, actions: NotifyAction[]): Promise<void>;
/** Post a message to a channel (for team-visible notifiers like Slack) */
post?(message: string, context?: NotifyContext): Promise<string | null>;
}
export interface NotifyAction {
label: string;
url?: string;
callbackEndpoint?: string;
}
export interface NotifyContext {
sessionId?: SessionId;
projectId?: string;
prUrl?: string;
channel?: string;
}
// =============================================================================
// TERMINAL — Plugin Slot 7
// =============================================================================
/**
* Terminal manages how humans view/interact with running sessions.
* Opens IDE tabs, browser windows, or terminal sessions.
*/
export interface Terminal {
readonly name: string;
/** Open a session for human interaction */
openSession(session: Session): Promise<void>;
/** Open all sessions for a project */
openAll(sessions: Session[]): Promise<void>;
/** Check if a session is already open in a tab/window */
isSessionOpen?(session: Session): Promise<boolean>;
}
// =============================================================================
// EVENTS
// =============================================================================
/** Priority levels for events — determines notification routing */
export type EventPriority = "urgent" | "action" | "warning" | "info";
/** All orchestrator event types */
export type EventType =
// Session lifecycle
| "session.spawned"
| "session.working"
| "session.exited"
| "session.killed"
| "session.stuck"
| "session.needs_input"
| "session.errored"
// PR lifecycle
| "pr.created"
| "pr.updated"
| "pr.merged"
| "pr.closed"
// CI
| "ci.passing"
| "ci.failing"
| "ci.fix_sent"
| "ci.fix_failed"
// Reviews
| "review.pending"
| "review.approved"
| "review.changes_requested"
| "review.comments_sent"
| "review.comments_unresolved"
// Automated reviews
| "automated_review.found"
| "automated_review.fix_sent"
// Merge
| "merge.ready"
| "merge.conflicts"
| "merge.completed"
// Reactions
| "reaction.triggered"
| "reaction.escalated"
// Summary
| "summary.all_complete";
/** An event emitted by the orchestrator */
export interface OrchestratorEvent {
id: string;
type: EventType;
priority: EventPriority;
sessionId: SessionId;
projectId: string;
timestamp: Date;
message: string;
data: Record<string, unknown>;
}
// =============================================================================
// REACTIONS
// =============================================================================
/** A configured automatic reaction to an event */
export interface ReactionConfig {
/** Whether this reaction is enabled */
auto: boolean;
/** What to do: send message to agent, notify human, auto-merge */
action: "send-to-agent" | "notify" | "auto-merge";
/** Message to send (for send-to-agent) */
message?: string;
/** Priority for notifications */
priority?: EventPriority;
/** How many times to retry send-to-agent before escalating */
retries?: number;
/** Escalate to human notification after this many failures or this duration */
escalateAfter?: number | string;
/** Threshold duration for time-based triggers (e.g. "10m" for stuck detection) */
threshold?: string;
/** Whether to include a summary in the notification */
includeSummary?: boolean;
}
export interface ReactionResult {
reactionType: string;
success: boolean;
action: string;
message?: string;
escalated: boolean;
}
// =============================================================================
// CONFIGURATION
// =============================================================================
/** Top-level orchestrator configuration (from agent-orchestrator.yaml) */
export interface OrchestratorConfig {
/** Where to store session metadata */
dataDir: string;
/** Where to create workspaces (worktrees, clones) */
worktreeDir: string;
/** Web dashboard port */
port: number;
/** Default plugin selections */
defaults: DefaultPlugins;
/** Project configurations */
projects: Record<string, ProjectConfig>;
/** Notification channel configs */
notifiers: Record<string, NotifierConfig>;
/** Notification routing by priority */
notificationRouting: Record<EventPriority, string[]>;
/** Default reaction configs */
reactions: Record<string, ReactionConfig>;
}
export interface DefaultPlugins {
runtime: string;
agent: string;
workspace: string;
notifiers: string[];
}
export interface ProjectConfig {
/** Display name */
name: string;
/** GitHub repo in "owner/repo" format */
repo: string;
/** Local path to the repo */
path: string;
/** Default branch (main, master, next, develop, etc.) */
defaultBranch: string;
/** Session name prefix (e.g. "app" → "app-1", "app-2") */
sessionPrefix: string;
/** Override default runtime */
runtime?: string;
/** Override default agent */
agent?: string;
/** Override default workspace */
workspace?: string;
/** Issue tracker configuration */
tracker?: TrackerConfig;
/** SCM configuration (usually inferred from repo) */
scm?: SCMConfig;
/** Files/dirs to symlink into workspaces */
symlinks?: string[];
/** Commands to run after workspace creation */
postCreate?: string[];
/** Agent-specific configuration */
agentConfig?: AgentSpecificConfig;
/** Per-project reaction overrides */
reactions?: Record<string, Partial<ReactionConfig>>;
}
export interface TrackerConfig {
plugin: string;
/** Plugin-specific config (e.g. teamId for Linear) */
[key: string]: unknown;
}
export interface SCMConfig {
plugin: string;
[key: string]: unknown;
}
export interface NotifierConfig {
plugin: string;
[key: string]: unknown;
}
export interface AgentSpecificConfig {
permissions?: "skip" | "default";
model?: string;
[key: string]: unknown;
}
// =============================================================================
// PLUGIN SYSTEM
// =============================================================================
/** Plugin slot types */
export type PluginSlot =
| "runtime"
| "agent"
| "workspace"
| "tracker"
| "scm"
| "notifier"
| "terminal";
/** Plugin manifest — what every plugin exports */
export interface PluginManifest {
/** Plugin name (e.g. "tmux", "claude-code", "github") */
name: string;
/** Which slot this plugin fills */
slot: PluginSlot;
/** Human-readable description */
description: string;
/** Version */
version: string;
}
/** What a plugin module must export */
export interface PluginModule<T = unknown> {
manifest: PluginManifest;
create(config?: Record<string, unknown>): T;
}
// =============================================================================
// SESSION METADATA (flat file format)
// =============================================================================
/**
* Session metadata stored as flat key=value files.
* Matches the existing bash script format for backwards compatibility.
*/
export interface SessionMetadata {
worktree: string;
branch: string;
status: string;
issue?: string;
pr?: string;
summary?: string;
project?: string;
createdAt?: string;
runtimeHandle?: string;
}
// =============================================================================
// SERVICE INTERFACES (core, not pluggable)
// =============================================================================
/** Session manager — CRUD for sessions */
export interface SessionManager {
spawn(config: SessionSpawnConfig): Promise<Session>;
list(projectId?: string): Promise<Session[]>;
get(sessionId: SessionId): Promise<Session | null>;
kill(sessionId: SessionId): Promise<void>;
cleanup(projectId?: string): Promise<CleanupResult>;
send(sessionId: SessionId, message: string): Promise<void>;
}
export interface CleanupResult {
killed: string[];
skipped: string[];
errors: Array<{ sessionId: string; error: string }>;
}
/** Lifecycle manager — state machine + reaction engine */
export interface LifecycleManager {
/** Start the lifecycle polling loop */
start(intervalMs?: number): void;
/** Stop the lifecycle polling loop */
stop(): void;
/** Get current state for all sessions */
getStates(): Map<SessionId, SessionStatus>;
/** Force-check a specific session now */
check(sessionId: SessionId): Promise<void>;
/** Subscribe to lifecycle events */
on(event: EventType | "*", handler: (event: OrchestratorEvent) => void): void;
off(event: EventType | "*", handler: (event: OrchestratorEvent) => void): void;
}
/** Event bus — pub/sub + persistence */
export interface EventBus {
emit(event: OrchestratorEvent): void;
on(event: EventType | "*", handler: (event: OrchestratorEvent) => void): void;
off(event: EventType | "*", handler: (event: OrchestratorEvent) => void): void;
getHistory(filter?: EventFilter): OrchestratorEvent[];
}
export interface EventFilter {
sessionId?: SessionId;
projectId?: string;
type?: EventType;
priority?: EventPriority;
since?: Date;
limit?: number;
}
/** Plugin registry — discovery + loading */
export interface PluginRegistry {
/** Register a plugin */
register(plugin: PluginModule): void;
/** Get a plugin by slot and name */
get<T>(slot: PluginSlot, name: string): T | null;
/** List plugins for a slot */
list(slot: PluginSlot): PluginManifest[];
/** Load built-in plugins */
loadBuiltins(): Promise<void>;
/** Load plugins from config (npm packages, local paths) */
loadFromConfig(config: OrchestratorConfig): Promise<void>;
}

View File

@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

View File

@ -0,0 +1,26 @@
{
"name": "@agent-orchestrator/plugin-agent-aider",
"version": "0.1.0",
"description": "Agent plugin: Aider",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"@agent-orchestrator/core": "workspace:*"
},
"devDependencies": {
"@types/node": "^25.2.3",
"typescript": "^5.7.0"
}
}

View File

@ -0,0 +1 @@
// agent-aider plugin — to be implemented

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

View File

@ -0,0 +1,26 @@
{
"name": "@agent-orchestrator/plugin-agent-claude-code",
"version": "0.1.0",
"description": "Agent plugin: Claude Code",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"@agent-orchestrator/core": "workspace:*"
},
"devDependencies": {
"@types/node": "^25.2.3",
"typescript": "^5.7.0"
}
}

View File

@ -0,0 +1 @@
// agent-claude-code plugin — to be implemented

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

View File

@ -0,0 +1,26 @@
{
"name": "@agent-orchestrator/plugin-agent-codex",
"version": "0.1.0",
"description": "Agent plugin: OpenAI Codex CLI",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"@agent-orchestrator/core": "workspace:*"
},
"devDependencies": {
"@types/node": "^25.2.3",
"typescript": "^5.7.0"
}
}

View File

@ -0,0 +1 @@
// agent-codex plugin — to be implemented

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

View File

@ -0,0 +1,26 @@
{
"name": "@agent-orchestrator/plugin-notifier-desktop",
"version": "0.1.0",
"description": "Notifier plugin: OS desktop notifications",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"@agent-orchestrator/core": "workspace:*"
},
"devDependencies": {
"@types/node": "^25.2.3",
"typescript": "^5.7.0"
}
}

View File

@ -0,0 +1 @@
// notifier-desktop plugin — to be implemented

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

View File

@ -0,0 +1,26 @@
{
"name": "@agent-orchestrator/plugin-notifier-slack",
"version": "0.1.0",
"description": "Notifier plugin: Slack",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"@agent-orchestrator/core": "workspace:*"
},
"devDependencies": {
"@types/node": "^25.2.3",
"typescript": "^5.7.0"
}
}

View File

@ -0,0 +1 @@
// notifier-slack plugin — to be implemented

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

View File

@ -0,0 +1,26 @@
{
"name": "@agent-orchestrator/plugin-notifier-webhook",
"version": "0.1.0",
"description": "Notifier plugin: generic webhook",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"@agent-orchestrator/core": "workspace:*"
},
"devDependencies": {
"@types/node": "^25.2.3",
"typescript": "^5.7.0"
}
}

View File

@ -0,0 +1 @@
// notifier-webhook plugin — to be implemented

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

View File

@ -0,0 +1,26 @@
{
"name": "@agent-orchestrator/plugin-runtime-process",
"version": "0.1.0",
"description": "Runtime plugin: child processes",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"@agent-orchestrator/core": "workspace:*"
},
"devDependencies": {
"@types/node": "^25.2.3",
"typescript": "^5.7.0"
}
}

View File

@ -0,0 +1 @@
// runtime-process plugin — to be implemented

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

View File

@ -0,0 +1,26 @@
{
"name": "@agent-orchestrator/plugin-runtime-tmux",
"version": "0.1.0",
"description": "Runtime plugin: tmux sessions",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"@agent-orchestrator/core": "workspace:*"
},
"devDependencies": {
"@types/node": "^25.2.3",
"typescript": "^5.7.0"
}
}

View File

@ -0,0 +1 @@
// runtime-tmux plugin — to be implemented

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

View File

@ -0,0 +1,26 @@
{
"name": "@agent-orchestrator/plugin-scm-github",
"version": "0.1.0",
"description": "SCM plugin: GitHub (PRs, CI, reviews)",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"@agent-orchestrator/core": "workspace:*"
},
"devDependencies": {
"@types/node": "^25.2.3",
"typescript": "^5.7.0"
}
}

View File

@ -0,0 +1 @@
// scm-github plugin — to be implemented

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

View File

@ -0,0 +1,26 @@
{
"name": "@agent-orchestrator/plugin-terminal-iterm2",
"version": "0.1.0",
"description": "Terminal plugin: macOS iTerm2",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"@agent-orchestrator/core": "workspace:*"
},
"devDependencies": {
"@types/node": "^25.2.3",
"typescript": "^5.7.0"
}
}

View File

@ -0,0 +1 @@
// terminal-iterm2 plugin — to be implemented

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

View File

@ -0,0 +1,26 @@
{
"name": "@agent-orchestrator/plugin-terminal-web",
"version": "0.1.0",
"description": "Terminal plugin: xterm.js web terminal",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"@agent-orchestrator/core": "workspace:*"
},
"devDependencies": {
"@types/node": "^25.2.3",
"typescript": "^5.7.0"
}
}

View File

@ -0,0 +1 @@
// terminal-web plugin — to be implemented

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

View File

@ -0,0 +1,26 @@
{
"name": "@agent-orchestrator/plugin-tracker-github",
"version": "0.1.0",
"description": "Tracker plugin: GitHub Issues",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"@agent-orchestrator/core": "workspace:*"
},
"devDependencies": {
"@types/node": "^25.2.3",
"typescript": "^5.7.0"
}
}

View File

@ -0,0 +1 @@
// tracker-github plugin — to be implemented

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

View File

@ -0,0 +1,26 @@
{
"name": "@agent-orchestrator/plugin-tracker-linear",
"version": "0.1.0",
"description": "Tracker plugin: Linear",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"@agent-orchestrator/core": "workspace:*"
},
"devDependencies": {
"@types/node": "^25.2.3",
"typescript": "^5.7.0"
}
}

View File

@ -0,0 +1 @@
// tracker-linear plugin — to be implemented

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

View File

@ -0,0 +1,26 @@
{
"name": "@agent-orchestrator/plugin-workspace-clone",
"version": "0.1.0",
"description": "Workspace plugin: git clone",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"@agent-orchestrator/core": "workspace:*"
},
"devDependencies": {
"@types/node": "^25.2.3",
"typescript": "^5.7.0"
}
}

View File

@ -0,0 +1 @@
// workspace-clone plugin — to be implemented

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

View File

@ -0,0 +1,26 @@
{
"name": "@agent-orchestrator/plugin-workspace-worktree",
"version": "0.1.0",
"description": "Workspace plugin: git worktrees",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc",
"typecheck": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"@agent-orchestrator/core": "workspace:*"
},
"devDependencies": {
"@types/node": "^25.2.3",
"typescript": "^5.7.0"
}
}

View File

@ -0,0 +1 @@
// workspace-worktree plugin — to be implemented

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

26
packages/web/package.json Normal file
View File

@ -0,0 +1,26 @@
{
"name": "@agent-orchestrator/web",
"version": "0.1.0",
"description": "Web dashboard for agent-orchestrator",
"private": true,
"type": "module",
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"typecheck": "tsc --noEmit",
"clean": "rm -rf .next"
},
"dependencies": {
"@agent-orchestrator/core": "workspace:*",
"next": "^15.1.0",
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"tailwindcss": "^4.0.0",
"typescript": "^5.7.0"
}
}

View File

@ -0,0 +1,8 @@
// Web dashboard layout — to be implemented
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}

View File

@ -0,0 +1,4 @@
// Dashboard home — to be implemented
export default function Home() {
return <div>Agent Orchestrator Dashboard</div>;
}

View File

@ -0,0 +1,16 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src",
"jsx": "preserve",
"module": "ESNext",
"moduleResolution": "Bundler",
"plugins": [{ "name": "next" }],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src", "next-env.d.ts"],
"exclude": ["node_modules"]
}

1276
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

3
pnpm-workspace.yaml Normal file
View File

@ -0,0 +1,3 @@
packages:
- "packages/*"
- "packages/plugins/*"

20
tsconfig.base.json Normal file
View File

@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"lib": ["ES2022"],
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"outDir": "dist",
"rootDir": "src"
}
}