Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 15be750b5c | |||
| 25291b2ba4 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1 @@
|
|||||||
/dist
|
|
||||||
/node_modules
|
/node_modules
|
||||||
|
|||||||
5
build.sh
Executable file
5
build.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
bun build src/index.ts --outdir dist --target bun --format esm --external @ast-grep/napi
|
||||||
|
tsc --emitDeclarationOnly
|
||||||
4
clean.sh
Executable file
4
clean.sh
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
rm -rf dist
|
||||||
39
dist/config/schema.d.ts
vendored
Normal file
39
dist/config/schema.d.ts
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
export declare const TmuxLayoutSchema: z.ZodEnum<{
|
||||||
|
"main-horizontal": "main-horizontal";
|
||||||
|
"main-vertical": "main-vertical";
|
||||||
|
tiled: "tiled";
|
||||||
|
"even-horizontal": "even-horizontal";
|
||||||
|
"even-vertical": "even-vertical";
|
||||||
|
}>;
|
||||||
|
export declare const TmuxConfigSchema: z.ZodObject<{
|
||||||
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
||||||
|
layout: z.ZodDefault<z.ZodEnum<{
|
||||||
|
"main-horizontal": "main-horizontal";
|
||||||
|
"main-vertical": "main-vertical";
|
||||||
|
tiled: "tiled";
|
||||||
|
"even-horizontal": "even-horizontal";
|
||||||
|
"even-vertical": "even-vertical";
|
||||||
|
}>>;
|
||||||
|
main_pane_size: z.ZodDefault<z.ZodNumber>;
|
||||||
|
main_pane_min_width: z.ZodDefault<z.ZodNumber>;
|
||||||
|
agent_pane_min_width: z.ZodDefault<z.ZodNumber>;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
export type TmuxConfig = z.infer<typeof TmuxConfigSchema>;
|
||||||
|
export type TmuxLayout = z.infer<typeof TmuxLayoutSchema>;
|
||||||
|
export declare const PluginConfigSchema: z.ZodObject<{
|
||||||
|
tmux: z.ZodOptional<z.ZodObject<{
|
||||||
|
enabled: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
|
||||||
|
layout: z.ZodOptional<z.ZodDefault<z.ZodEnum<{
|
||||||
|
"main-horizontal": "main-horizontal";
|
||||||
|
"main-vertical": "main-vertical";
|
||||||
|
tiled: "tiled";
|
||||||
|
"even-horizontal": "even-horizontal";
|
||||||
|
"even-vertical": "even-vertical";
|
||||||
|
}>>>;
|
||||||
|
main_pane_size: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
||||||
|
main_pane_min_width: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
||||||
|
agent_pane_min_width: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
|
||||||
|
}, z.core.$strip>>;
|
||||||
|
}, z.core.$strip>;
|
||||||
|
export type TmuxUtilsConfig = z.infer<typeof PluginConfigSchema>;
|
||||||
21
dist/features/tmux-subagent/action-executor-core.d.ts
vendored
Normal file
21
dist/features/tmux-subagent/action-executor-core.d.ts
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import type { TmuxConfig } from "../../config/schema";
|
||||||
|
import type { applyLayout, closeTmuxPane, enforceMainPaneWidth, replaceTmuxPane, spawnTmuxPane } from "../../shared/tmux";
|
||||||
|
import type { PaneAction, WindowState } from "./types";
|
||||||
|
export interface ActionResult {
|
||||||
|
success: boolean;
|
||||||
|
paneId?: string;
|
||||||
|
error?: string;
|
||||||
|
}
|
||||||
|
export interface ExecuteContext {
|
||||||
|
config: TmuxConfig;
|
||||||
|
serverUrl: string;
|
||||||
|
windowState: WindowState;
|
||||||
|
}
|
||||||
|
export interface ActionExecutorDeps {
|
||||||
|
spawnTmuxPane: typeof spawnTmuxPane;
|
||||||
|
closeTmuxPane: typeof closeTmuxPane;
|
||||||
|
replaceTmuxPane: typeof replaceTmuxPane;
|
||||||
|
applyLayout: typeof applyLayout;
|
||||||
|
enforceMainPaneWidth: typeof enforceMainPaneWidth;
|
||||||
|
}
|
||||||
|
export declare function executeActionWithDeps(action: PaneAction, ctx: ExecuteContext, deps: ActionExecutorDeps): Promise<ActionResult>;
|
||||||
20
dist/features/tmux-subagent/action-executor.d.ts
vendored
Normal file
20
dist/features/tmux-subagent/action-executor.d.ts
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import type { TmuxConfig } from "../../config/schema";
|
||||||
|
import type { PaneAction, WindowState } from "./types";
|
||||||
|
import type { ActionResult } from "./action-executor-core";
|
||||||
|
export type { ActionExecutorDeps, ActionResult } from "./action-executor-core";
|
||||||
|
export interface ExecuteActionsResult {
|
||||||
|
success: boolean;
|
||||||
|
spawnedPaneId?: string;
|
||||||
|
results: Array<{
|
||||||
|
action: PaneAction;
|
||||||
|
result: ActionResult;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
export interface ExecuteContext {
|
||||||
|
config: TmuxConfig;
|
||||||
|
serverUrl: string;
|
||||||
|
windowState: WindowState;
|
||||||
|
sourcePaneId?: string;
|
||||||
|
}
|
||||||
|
export declare function executeAction(action: PaneAction, ctx: ExecuteContext): Promise<ActionResult>;
|
||||||
|
export declare function executeActions(actions: PaneAction[], ctx: ExecuteContext): Promise<ExecuteActionsResult>;
|
||||||
9
dist/features/tmux-subagent/cleanup.d.ts
vendored
Normal file
9
dist/features/tmux-subagent/cleanup.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import type { TmuxConfig } from "../../config/schema";
|
||||||
|
import type { TrackedSession } from "./types";
|
||||||
|
export declare function cleanupTmuxSessions(params: {
|
||||||
|
tmuxConfig: TmuxConfig;
|
||||||
|
serverUrl: string;
|
||||||
|
sourcePaneId: string | undefined;
|
||||||
|
sessions: Map<string, TrackedSession>;
|
||||||
|
stopPolling: () => void;
|
||||||
|
}): Promise<void>;
|
||||||
7
dist/features/tmux-subagent/decision-engine.d.ts
vendored
Normal file
7
dist/features/tmux-subagent/decision-engine.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export type { SessionMapping } from "./oldest-agent-pane";
|
||||||
|
export type { GridCapacity, GridPlan, GridSlot } from "./grid-planning";
|
||||||
|
export type { SpawnTarget } from "./spawn-target-finder";
|
||||||
|
export { calculateCapacity, computeGridPlan, mapPaneToSlot, } from "./grid-planning";
|
||||||
|
export { canSplitPane, canSplitPaneAnyDirection, findMinimalEvictions, getBestSplitDirection, getColumnCount, getColumnWidth, isSplittableAtCount, } from "./pane-split-availability";
|
||||||
|
export { findSpawnTarget } from "./spawn-target-finder";
|
||||||
|
export { decideCloseAction, decideSpawnActions } from "./spawn-action-decider";
|
||||||
6
dist/features/tmux-subagent/event-handlers.d.ts
vendored
Normal file
6
dist/features/tmux-subagent/event-handlers.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export { coerceSessionCreatedEvent } from "./session-created-event";
|
||||||
|
export type { SessionCreatedEvent } from "./session-created-event";
|
||||||
|
export { handleSessionCreated } from "./session-created-handler";
|
||||||
|
export type { SessionCreatedHandlerDeps } from "./session-created-handler";
|
||||||
|
export { handleSessionDeleted } from "./session-deleted-handler";
|
||||||
|
export type { SessionDeletedHandlerDeps } from "./session-deleted-handler";
|
||||||
21
dist/features/tmux-subagent/grid-planning.d.ts
vendored
Normal file
21
dist/features/tmux-subagent/grid-planning.d.ts
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import type { CapacityConfig, TmuxPaneInfo } from "./types";
|
||||||
|
export interface GridCapacity {
|
||||||
|
cols: number;
|
||||||
|
rows: number;
|
||||||
|
total: number;
|
||||||
|
}
|
||||||
|
export interface GridSlot {
|
||||||
|
row: number;
|
||||||
|
col: number;
|
||||||
|
}
|
||||||
|
export interface GridPlan {
|
||||||
|
cols: number;
|
||||||
|
rows: number;
|
||||||
|
slotWidth: number;
|
||||||
|
slotHeight: number;
|
||||||
|
}
|
||||||
|
type CapacityOptions = CapacityConfig | number | undefined;
|
||||||
|
export declare function calculateCapacity(windowWidth: number, windowHeight: number, options?: CapacityOptions, mainPaneWidth?: number): GridCapacity;
|
||||||
|
export declare function computeGridPlan(windowWidth: number, windowHeight: number, paneCount: number, options?: CapacityOptions, mainPaneWidth?: number): GridPlan;
|
||||||
|
export declare function mapPaneToSlot(pane: TmuxPaneInfo, plan: GridPlan, mainPaneWidth: number): GridSlot;
|
||||||
|
export {};
|
||||||
16
dist/features/tmux-subagent/index.d.ts
vendored
Normal file
16
dist/features/tmux-subagent/index.d.ts
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
export * from "./manager";
|
||||||
|
export * from "./event-handlers";
|
||||||
|
export * from "./polling";
|
||||||
|
export * from "./cleanup";
|
||||||
|
export * from "./session-created-event";
|
||||||
|
export * from "./session-created-handler";
|
||||||
|
export * from "./session-deleted-handler";
|
||||||
|
export * from "./polling-constants";
|
||||||
|
export * from "./session-status-parser";
|
||||||
|
export * from "./session-message-count";
|
||||||
|
export * from "./session-ready-waiter";
|
||||||
|
export * from "./types";
|
||||||
|
export * from "./pane-state-parser";
|
||||||
|
export * from "./pane-state-querier";
|
||||||
|
export * from "./decision-engine";
|
||||||
|
export * from "./action-executor";
|
||||||
61
dist/features/tmux-subagent/manager.d.ts
vendored
Normal file
61
dist/features/tmux-subagent/manager.d.ts
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import type { PluginInput } from "@opencode-ai/plugin";
|
||||||
|
import type { TmuxConfig } from "../../config/schema";
|
||||||
|
interface SessionCreatedEvent {
|
||||||
|
type: string;
|
||||||
|
properties?: {
|
||||||
|
info?: {
|
||||||
|
id?: string;
|
||||||
|
parentID?: string;
|
||||||
|
title?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export interface TmuxUtilDeps {
|
||||||
|
isInsideTmux: () => boolean;
|
||||||
|
getCurrentPaneId: () => string | undefined;
|
||||||
|
}
|
||||||
|
export declare class TmuxSessionManager {
|
||||||
|
private client;
|
||||||
|
private tmuxConfig;
|
||||||
|
private serverUrl;
|
||||||
|
private sourcePaneId;
|
||||||
|
private sessions;
|
||||||
|
private pendingSessions;
|
||||||
|
private spawnQueue;
|
||||||
|
private deferredSessions;
|
||||||
|
private deferredQueue;
|
||||||
|
private deferredAttachInterval?;
|
||||||
|
private deferredAttachTickScheduled;
|
||||||
|
private nullStateCount;
|
||||||
|
private deps;
|
||||||
|
private pollingManager;
|
||||||
|
constructor(ctx: PluginInput, tmuxConfig: TmuxConfig, deps?: TmuxUtilDeps);
|
||||||
|
private isEnabled;
|
||||||
|
private getCapacityConfig;
|
||||||
|
private getSessionMappings;
|
||||||
|
private removeTrackedSession;
|
||||||
|
private markSessionClosePending;
|
||||||
|
private queryWindowStateSafely;
|
||||||
|
private tryCloseTrackedSession;
|
||||||
|
private retryPendingCloses;
|
||||||
|
private enqueueDeferredSession;
|
||||||
|
private removeDeferredSession;
|
||||||
|
private startDeferredAttachLoop;
|
||||||
|
private stopDeferredAttachLoop;
|
||||||
|
private tryAttachDeferredSession;
|
||||||
|
private waitForSessionReady;
|
||||||
|
onSessionCreated(event: SessionCreatedEvent): Promise<void>;
|
||||||
|
private enqueueSpawn;
|
||||||
|
onSessionDeleted(event: {
|
||||||
|
sessionID: string;
|
||||||
|
}): Promise<void>;
|
||||||
|
private closeSessionById;
|
||||||
|
createEventHandler(): (input: {
|
||||||
|
event: {
|
||||||
|
type: string;
|
||||||
|
properties?: unknown;
|
||||||
|
};
|
||||||
|
}) => Promise<void>;
|
||||||
|
cleanup(): Promise<void>;
|
||||||
|
}
|
||||||
|
export {};
|
||||||
7
dist/features/tmux-subagent/oldest-agent-pane.d.ts
vendored
Normal file
7
dist/features/tmux-subagent/oldest-agent-pane.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import type { TmuxPaneInfo } from "./types";
|
||||||
|
export interface SessionMapping {
|
||||||
|
sessionId: string;
|
||||||
|
paneId: string;
|
||||||
|
createdAt: Date;
|
||||||
|
}
|
||||||
|
export declare function findOldestAgentPane(agentPanes: TmuxPaneInfo[], sessionMappings: SessionMapping[]): TmuxPaneInfo | null;
|
||||||
8
dist/features/tmux-subagent/pane-split-availability.d.ts
vendored
Normal file
8
dist/features/tmux-subagent/pane-split-availability.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import type { SplitDirection, TmuxPaneInfo } from "./types";
|
||||||
|
export declare function getColumnCount(paneCount: number): number;
|
||||||
|
export declare function getColumnWidth(agentAreaWidth: number, paneCount: number): number;
|
||||||
|
export declare function isSplittableAtCount(agentAreaWidth: number, paneCount: number, minPaneWidth?: number): boolean;
|
||||||
|
export declare function findMinimalEvictions(agentAreaWidth: number, currentCount: number, minPaneWidth?: number): number | null;
|
||||||
|
export declare function canSplitPane(pane: TmuxPaneInfo, direction: SplitDirection, minPaneWidth?: number): boolean;
|
||||||
|
export declare function canSplitPaneAnyDirection(pane: TmuxPaneInfo, minPaneWidth?: number): boolean;
|
||||||
|
export declare function getBestSplitDirection(pane: TmuxPaneInfo, minPaneWidth?: number): SplitDirection | null;
|
||||||
8
dist/features/tmux-subagent/pane-state-parser.d.ts
vendored
Normal file
8
dist/features/tmux-subagent/pane-state-parser.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import type { TmuxPaneInfo } from "./types";
|
||||||
|
type ParsedPaneState = {
|
||||||
|
windowWidth: number;
|
||||||
|
windowHeight: number;
|
||||||
|
panes: TmuxPaneInfo[];
|
||||||
|
};
|
||||||
|
export declare function parsePaneStateOutput(stdout: string): ParsedPaneState | null;
|
||||||
|
export {};
|
||||||
2
dist/features/tmux-subagent/pane-state-querier.d.ts
vendored
Normal file
2
dist/features/tmux-subagent/pane-state-querier.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
import type { WindowState } from "./types";
|
||||||
|
export declare function queryWindowState(sourcePaneId: string): Promise<WindowState | null>;
|
||||||
3
dist/features/tmux-subagent/polling-constants.d.ts
vendored
Normal file
3
dist/features/tmux-subagent/polling-constants.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export declare const SESSION_TIMEOUT_MS: number;
|
||||||
|
export declare const MIN_STABILITY_TIME_MS: number;
|
||||||
|
export declare const STABLE_POLLS_REQUIRED = 3;
|
||||||
15
dist/features/tmux-subagent/polling-manager.d.ts
vendored
Normal file
15
dist/features/tmux-subagent/polling-manager.d.ts
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import type { PluginInput } from "@opencode-ai/plugin";
|
||||||
|
import type { TrackedSession } from "./types";
|
||||||
|
type OpencodeClient = PluginInput["client"];
|
||||||
|
export declare class TmuxPollingManager {
|
||||||
|
private client;
|
||||||
|
private sessions;
|
||||||
|
private closeSessionById;
|
||||||
|
private pollInterval?;
|
||||||
|
private pollingInFlight;
|
||||||
|
constructor(client: OpencodeClient, sessions: Map<string, TrackedSession>, closeSessionById: (sessionId: string) => Promise<void>);
|
||||||
|
startPolling(): void;
|
||||||
|
stopPolling(): void;
|
||||||
|
private pollSessions;
|
||||||
|
}
|
||||||
|
export {};
|
||||||
19
dist/features/tmux-subagent/polling.d.ts
vendored
Normal file
19
dist/features/tmux-subagent/polling.d.ts
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import type { PluginInput } from "@opencode-ai/plugin";
|
||||||
|
import type { TmuxConfig } from "../../config/schema";
|
||||||
|
import type { TrackedSession } from "./types";
|
||||||
|
type OpencodeClient = PluginInput["client"];
|
||||||
|
export interface SessionPollingController {
|
||||||
|
startPolling: () => void;
|
||||||
|
stopPolling: () => void;
|
||||||
|
closeSessionById: (sessionId: string) => Promise<void>;
|
||||||
|
waitForSessionReady: (sessionId: string) => Promise<boolean>;
|
||||||
|
pollSessions: () => Promise<void>;
|
||||||
|
}
|
||||||
|
export declare function createSessionPollingController(params: {
|
||||||
|
client: OpencodeClient;
|
||||||
|
tmuxConfig: TmuxConfig;
|
||||||
|
serverUrl: string;
|
||||||
|
sourcePaneId: string | undefined;
|
||||||
|
sessions: Map<string, TrackedSession>;
|
||||||
|
}): SessionPollingController;
|
||||||
|
export {};
|
||||||
14
dist/features/tmux-subagent/session-created-event.d.ts
vendored
Normal file
14
dist/features/tmux-subagent/session-created-event.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
export interface SessionCreatedEvent {
|
||||||
|
type: string;
|
||||||
|
properties?: {
|
||||||
|
info?: {
|
||||||
|
id?: string;
|
||||||
|
parentID?: string;
|
||||||
|
title?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export declare function coerceSessionCreatedEvent(input: {
|
||||||
|
type: string;
|
||||||
|
properties?: unknown;
|
||||||
|
}): SessionCreatedEvent;
|
||||||
22
dist/features/tmux-subagent/session-created-handler.d.ts
vendored
Normal file
22
dist/features/tmux-subagent/session-created-handler.d.ts
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import type { PluginInput } from "@opencode-ai/plugin";
|
||||||
|
import type { TmuxConfig } from "../../config/schema";
|
||||||
|
import type { CapacityConfig, TrackedSession } from "./types";
|
||||||
|
import { type SessionMapping } from "./decision-engine";
|
||||||
|
import type { SessionCreatedEvent } from "./session-created-event";
|
||||||
|
type OpencodeClient = PluginInput["client"];
|
||||||
|
export interface SessionCreatedHandlerDeps {
|
||||||
|
client: OpencodeClient;
|
||||||
|
tmuxConfig: TmuxConfig;
|
||||||
|
serverUrl: string;
|
||||||
|
sourcePaneId: string | undefined;
|
||||||
|
sessions: Map<string, TrackedSession>;
|
||||||
|
pendingSessions: Set<string>;
|
||||||
|
isInsideTmux: () => boolean;
|
||||||
|
isEnabled: () => boolean;
|
||||||
|
getCapacityConfig: () => CapacityConfig;
|
||||||
|
getSessionMappings: () => SessionMapping[];
|
||||||
|
waitForSessionReady: (sessionId: string) => Promise<boolean>;
|
||||||
|
startPolling: () => void;
|
||||||
|
}
|
||||||
|
export declare function handleSessionCreated(deps: SessionCreatedHandlerDeps, event: SessionCreatedEvent): Promise<void>;
|
||||||
|
export {};
|
||||||
15
dist/features/tmux-subagent/session-deleted-handler.d.ts
vendored
Normal file
15
dist/features/tmux-subagent/session-deleted-handler.d.ts
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import type { TmuxConfig } from "../../config/schema";
|
||||||
|
import type { TrackedSession } from "./types";
|
||||||
|
import { type SessionMapping } from "./decision-engine";
|
||||||
|
export interface SessionDeletedHandlerDeps {
|
||||||
|
tmuxConfig: TmuxConfig;
|
||||||
|
serverUrl: string;
|
||||||
|
sourcePaneId: string | undefined;
|
||||||
|
sessions: Map<string, TrackedSession>;
|
||||||
|
isEnabled: () => boolean;
|
||||||
|
getSessionMappings: () => SessionMapping[];
|
||||||
|
stopPolling: () => void;
|
||||||
|
}
|
||||||
|
export declare function handleSessionDeleted(deps: SessionDeletedHandlerDeps, event: {
|
||||||
|
sessionID: string;
|
||||||
|
}): Promise<void>;
|
||||||
1
dist/features/tmux-subagent/session-message-count.d.ts
vendored
Normal file
1
dist/features/tmux-subagent/session-message-count.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export declare function getMessageCount(data: unknown): number;
|
||||||
7
dist/features/tmux-subagent/session-ready-waiter.d.ts
vendored
Normal file
7
dist/features/tmux-subagent/session-ready-waiter.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import type { PluginInput } from "@opencode-ai/plugin";
|
||||||
|
type OpencodeClient = PluginInput["client"];
|
||||||
|
export declare function waitForSessionReady(params: {
|
||||||
|
client: OpencodeClient;
|
||||||
|
sessionId: string;
|
||||||
|
}): Promise<boolean>;
|
||||||
|
export {};
|
||||||
5
dist/features/tmux-subagent/session-status-parser.d.ts
vendored
Normal file
5
dist/features/tmux-subagent/session-status-parser.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
type SessionStatus = {
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
export declare function parseSessionStatusMap(data: unknown): Record<string, SessionStatus>;
|
||||||
|
export {};
|
||||||
4
dist/features/tmux-subagent/spawn-action-decider.d.ts
vendored
Normal file
4
dist/features/tmux-subagent/spawn-action-decider.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import type { CapacityConfig, PaneAction, SpawnDecision, WindowState } from "./types";
|
||||||
|
import { type SessionMapping } from "./oldest-agent-pane";
|
||||||
|
export declare function decideSpawnActions(state: WindowState, sessionId: string, description: string, config: CapacityConfig, sessionMappings: SessionMapping[]): SpawnDecision;
|
||||||
|
export declare function decideCloseAction(state: WindowState, sessionId: string, sessionMappings: SessionMapping[]): PaneAction | null;
|
||||||
6
dist/features/tmux-subagent/spawn-target-finder.d.ts
vendored
Normal file
6
dist/features/tmux-subagent/spawn-target-finder.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import type { CapacityConfig, SplitDirection, WindowState } from "./types";
|
||||||
|
export interface SpawnTarget {
|
||||||
|
targetPaneId: string;
|
||||||
|
splitDirection: SplitDirection;
|
||||||
|
}
|
||||||
|
export declare function findSpawnTarget(state: WindowState, config: CapacityConfig): SpawnTarget | null;
|
||||||
11
dist/features/tmux-subagent/tmux-grid-constants.d.ts
vendored
Normal file
11
dist/features/tmux-subagent/tmux-grid-constants.d.ts
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import type { CapacityConfig } from "./types";
|
||||||
|
export declare const MAIN_PANE_RATIO = 0.5;
|
||||||
|
export declare const MAX_COLS = 2;
|
||||||
|
export declare const MAX_ROWS = 3;
|
||||||
|
export declare const MAX_GRID_SIZE = 4;
|
||||||
|
export declare const DIVIDER_SIZE = 1;
|
||||||
|
export declare const MIN_SPLIT_WIDTH: number;
|
||||||
|
export declare const MIN_SPLIT_HEIGHT: number;
|
||||||
|
export declare function getMainPaneSizePercent(config?: CapacityConfig): number;
|
||||||
|
export declare function computeMainPaneWidth(windowWidth: number, config?: CapacityConfig): number;
|
||||||
|
export declare function computeAgentAreaWidth(windowWidth: number, config?: CapacityConfig): number;
|
||||||
8
dist/features/tmux-subagent/tracked-session-state.d.ts
vendored
Normal file
8
dist/features/tmux-subagent/tracked-session-state.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import type { TrackedSession } from "./types";
|
||||||
|
export declare function createTrackedSession(params: {
|
||||||
|
sessionId: string;
|
||||||
|
paneId: string;
|
||||||
|
description: string;
|
||||||
|
now?: Date;
|
||||||
|
}): TrackedSession;
|
||||||
|
export declare function markTrackedSessionClosePending(tracked: TrackedSession): TrackedSession;
|
||||||
57
dist/features/tmux-subagent/types.d.ts
vendored
Normal file
57
dist/features/tmux-subagent/types.d.ts
vendored
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
export interface TrackedSession {
|
||||||
|
sessionId: string;
|
||||||
|
paneId: string;
|
||||||
|
description: string;
|
||||||
|
createdAt: Date;
|
||||||
|
lastSeenAt: Date;
|
||||||
|
closePending: boolean;
|
||||||
|
closeRetryCount: number;
|
||||||
|
lastMessageCount?: number;
|
||||||
|
stableIdlePolls?: number;
|
||||||
|
}
|
||||||
|
export declare const MIN_PANE_WIDTH = 52;
|
||||||
|
export declare const MIN_PANE_HEIGHT = 11;
|
||||||
|
export interface TmuxPaneInfo {
|
||||||
|
paneId: string;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
left: number;
|
||||||
|
top: number;
|
||||||
|
title: string;
|
||||||
|
isActive: boolean;
|
||||||
|
}
|
||||||
|
export interface WindowState {
|
||||||
|
windowWidth: number;
|
||||||
|
windowHeight: number;
|
||||||
|
mainPane: TmuxPaneInfo | null;
|
||||||
|
agentPanes: TmuxPaneInfo[];
|
||||||
|
}
|
||||||
|
export type SplitDirection = "-h" | "-v";
|
||||||
|
export type PaneAction = {
|
||||||
|
type: "close";
|
||||||
|
paneId: string;
|
||||||
|
sessionId: string;
|
||||||
|
} | {
|
||||||
|
type: "spawn";
|
||||||
|
sessionId: string;
|
||||||
|
description: string;
|
||||||
|
targetPaneId: string;
|
||||||
|
splitDirection: SplitDirection;
|
||||||
|
} | {
|
||||||
|
type: "replace";
|
||||||
|
paneId: string;
|
||||||
|
oldSessionId: string;
|
||||||
|
newSessionId: string;
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
|
export interface SpawnDecision {
|
||||||
|
canSpawn: boolean;
|
||||||
|
actions: PaneAction[];
|
||||||
|
reason?: string;
|
||||||
|
}
|
||||||
|
export interface CapacityConfig {
|
||||||
|
layout?: string;
|
||||||
|
mainPaneSize?: number;
|
||||||
|
mainPaneMinWidth: number;
|
||||||
|
agentPaneWidth: number;
|
||||||
|
}
|
||||||
3
dist/index.d.ts
vendored
Normal file
3
dist/index.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import type { Plugin } from "@opencode-ai/plugin";
|
||||||
|
declare const TmuxUtilsPlugin: Plugin;
|
||||||
|
export default TmuxUtilsPlugin;
|
||||||
28744
dist/index.js
vendored
Normal file
28744
dist/index.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4
dist/plugin-config.d.ts
vendored
Normal file
4
dist/plugin-config.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import { type TmuxUtilsConfig } from "./config/schema";
|
||||||
|
export declare function loadConfigFromPath(configPath: string): TmuxUtilsConfig | null;
|
||||||
|
export declare function mergeConfigs(base: TmuxUtilsConfig, override: TmuxUtilsConfig): TmuxUtilsConfig;
|
||||||
|
export declare function loadPluginConfig(directory: string): TmuxUtilsConfig;
|
||||||
6
dist/shared/index.d.ts
vendored
Normal file
6
dist/shared/index.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export { log, getLogFilePath } from "./logger";
|
||||||
|
export { normalizeSDKResponse } from "./normalize-sdk-response";
|
||||||
|
export { parseJsonc, parseJsoncSafe, readJsoncFile, detectConfigFile } from "./jsonc-parser";
|
||||||
|
export { getOpenCodeConfigDir, getOpenCodeConfigPaths, detectExistingConfigDir, isDevBuild, TAURI_APP_IDENTIFIER, TAURI_APP_IDENTIFIER_DEV, } from "./opencode-config-dir";
|
||||||
|
export type { OpenCodeBinaryType, OpenCodeConfigDirOptions, OpenCodeConfigPaths, } from "./opencode-config-dir";
|
||||||
|
export * from "./tmux";
|
||||||
15
dist/shared/jsonc-parser.d.ts
vendored
Normal file
15
dist/shared/jsonc-parser.d.ts
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
export interface JsoncParseResult<T> {
|
||||||
|
data: T | null;
|
||||||
|
errors: Array<{
|
||||||
|
message: string;
|
||||||
|
offset: number;
|
||||||
|
length: number;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
export declare function parseJsonc<T = unknown>(content: string): T;
|
||||||
|
export declare function parseJsoncSafe<T = unknown>(content: string): JsoncParseResult<T>;
|
||||||
|
export declare function readJsoncFile<T = unknown>(filePath: string): T | null;
|
||||||
|
export declare function detectConfigFile(basePath: string): {
|
||||||
|
format: "json" | "jsonc" | "none";
|
||||||
|
path: string;
|
||||||
|
};
|
||||||
2
dist/shared/logger.d.ts
vendored
Normal file
2
dist/shared/logger.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export declare function log(message: string, data?: unknown): void;
|
||||||
|
export declare function getLogFilePath(): string;
|
||||||
4
dist/shared/normalize-sdk-response.d.ts
vendored
Normal file
4
dist/shared/normalize-sdk-response.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export interface NormalizeSDKResponseOptions {
|
||||||
|
preferResponseOnMissingData?: boolean;
|
||||||
|
}
|
||||||
|
export declare function normalizeSDKResponse<TData>(response: unknown, fallback: TData, options?: NormalizeSDKResponseOptions): TData;
|
||||||
13
dist/shared/opencode-config-dir-types.d.ts
vendored
Normal file
13
dist/shared/opencode-config-dir-types.d.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
export type OpenCodeBinaryType = "opencode" | "opencode-desktop";
|
||||||
|
export type OpenCodeConfigDirOptions = {
|
||||||
|
binary: OpenCodeBinaryType;
|
||||||
|
version?: string | null;
|
||||||
|
checkExisting?: boolean;
|
||||||
|
};
|
||||||
|
export type OpenCodeConfigPaths = {
|
||||||
|
configDir: string;
|
||||||
|
configJson: string;
|
||||||
|
configJsonc: string;
|
||||||
|
packageJson: string;
|
||||||
|
omoConfig: string;
|
||||||
|
};
|
||||||
8
dist/shared/opencode-config-dir.d.ts
vendored
Normal file
8
dist/shared/opencode-config-dir.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import type { OpenCodeBinaryType, OpenCodeConfigDirOptions, OpenCodeConfigPaths } from "./opencode-config-dir-types";
|
||||||
|
export type { OpenCodeBinaryType, OpenCodeConfigDirOptions, OpenCodeConfigPaths, } from "./opencode-config-dir-types";
|
||||||
|
export declare const TAURI_APP_IDENTIFIER = "ai.opencode.desktop";
|
||||||
|
export declare const TAURI_APP_IDENTIFIER_DEV = "ai.opencode.desktop.dev";
|
||||||
|
export declare function isDevBuild(version: string | null | undefined): boolean;
|
||||||
|
export declare function getOpenCodeConfigDir(options: OpenCodeConfigDirOptions): string;
|
||||||
|
export declare function getOpenCodeConfigPaths(options: OpenCodeConfigDirOptions): OpenCodeConfigPaths;
|
||||||
|
export declare function detectExistingConfigDir(binary: OpenCodeBinaryType, version?: string | null): string | null;
|
||||||
5
dist/shared/shell-env.d.ts
vendored
Normal file
5
dist/shared/shell-env.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export type ShellType = "unix" | "powershell" | "cmd";
|
||||||
|
export declare function detectShellType(): ShellType;
|
||||||
|
export declare function shellEscape(value: string, shellType: ShellType): string;
|
||||||
|
export declare function buildEnvPrefix(env: Record<string, string>, shellType: ShellType): string;
|
||||||
|
export declare function shellEscapeForDoubleQuotedCommand(value: string): string;
|
||||||
15
dist/shared/spawn-with-windows-hide.d.ts
vendored
Normal file
15
dist/shared/spawn-with-windows-hide.d.ts
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
export interface SpawnOptions {
|
||||||
|
cwd?: string;
|
||||||
|
env?: Record<string, string | undefined>;
|
||||||
|
stdin?: "pipe" | "inherit" | "ignore";
|
||||||
|
stdout?: "pipe" | "inherit" | "ignore";
|
||||||
|
stderr?: "pipe" | "inherit" | "ignore";
|
||||||
|
}
|
||||||
|
export interface SpawnedProcess {
|
||||||
|
readonly exitCode: number | null;
|
||||||
|
readonly exited: Promise<number>;
|
||||||
|
readonly stdout: ReadableStream<Uint8Array> | undefined;
|
||||||
|
readonly stderr: ReadableStream<Uint8Array> | undefined;
|
||||||
|
kill(signal?: NodeJS.Signals): void;
|
||||||
|
}
|
||||||
|
export declare function spawnWithWindowsHide(command: string[], options: SpawnOptions): SpawnedProcess;
|
||||||
5
dist/shared/tmux/constants.d.ts
vendored
Normal file
5
dist/shared/tmux/constants.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export declare const POLL_INTERVAL_BACKGROUND_MS = 2000;
|
||||||
|
export declare const SESSION_TIMEOUT_MS: number;
|
||||||
|
export declare const SESSION_MISSING_GRACE_MS = 6000;
|
||||||
|
export declare const SESSION_READY_POLL_INTERVAL_MS = 500;
|
||||||
|
export declare const SESSION_READY_TIMEOUT_MS = 10000;
|
||||||
3
dist/shared/tmux/index.d.ts
vendored
Normal file
3
dist/shared/tmux/index.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export * from "./tmux-utils";
|
||||||
|
export * from "./constants";
|
||||||
|
export * from "./types";
|
||||||
9
dist/shared/tmux/tmux-utils.d.ts
vendored
Normal file
9
dist/shared/tmux/tmux-utils.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export { isInsideTmux, getCurrentPaneId } from "./tmux-utils/environment";
|
||||||
|
export type { SplitDirection } from "./tmux-utils/environment";
|
||||||
|
export { isServerRunning, resetServerCheck } from "./tmux-utils/server-health";
|
||||||
|
export { getPaneDimensions } from "./tmux-utils/pane-dimensions";
|
||||||
|
export type { PaneDimensions } from "./tmux-utils/pane-dimensions";
|
||||||
|
export { spawnTmuxPane } from "./tmux-utils/pane-spawn";
|
||||||
|
export { closeTmuxPane } from "./tmux-utils/pane-close";
|
||||||
|
export { replaceTmuxPane } from "./tmux-utils/pane-replace";
|
||||||
|
export { applyLayout, enforceMainPaneWidth } from "./tmux-utils/layout";
|
||||||
4
dist/shared/tmux/tmux-utils/environment.d.ts
vendored
Normal file
4
dist/shared/tmux/tmux-utils/environment.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export type SplitDirection = "-h" | "-v";
|
||||||
|
export declare function isInsideTmuxEnvironment(environment: Record<string, string | undefined>): boolean;
|
||||||
|
export declare function isInsideTmux(): boolean;
|
||||||
|
export declare function getCurrentPaneId(): string | undefined;
|
||||||
18
dist/shared/tmux/tmux-utils/layout.d.ts
vendored
Normal file
18
dist/shared/tmux/tmux-utils/layout.d.ts
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import type { TmuxLayout } from "../../../config/schema";
|
||||||
|
type TmuxSpawnCommand = (args: string[], options: {
|
||||||
|
stdout: "ignore";
|
||||||
|
stderr: "ignore";
|
||||||
|
}) => {
|
||||||
|
exited: Promise<number>;
|
||||||
|
};
|
||||||
|
interface LayoutDeps {
|
||||||
|
spawnCommand?: TmuxSpawnCommand;
|
||||||
|
}
|
||||||
|
interface MainPaneWidthOptions {
|
||||||
|
mainPaneSize?: number;
|
||||||
|
mainPaneMinWidth?: number;
|
||||||
|
agentPaneMinWidth?: number;
|
||||||
|
}
|
||||||
|
export declare function applyLayout(tmux: string, layout: TmuxLayout, mainPaneSize: number, deps?: LayoutDeps): Promise<void>;
|
||||||
|
export declare function enforceMainPaneWidth(mainPaneId: string, windowWidth: number, mainPaneSizeOrOptions?: number | MainPaneWidthOptions): Promise<void>;
|
||||||
|
export {};
|
||||||
1
dist/shared/tmux/tmux-utils/pane-close.d.ts
vendored
Normal file
1
dist/shared/tmux/tmux-utils/pane-close.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export declare function closeTmuxPane(paneId: string): Promise<boolean>;
|
||||||
5
dist/shared/tmux/tmux-utils/pane-dimensions.d.ts
vendored
Normal file
5
dist/shared/tmux/tmux-utils/pane-dimensions.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export interface PaneDimensions {
|
||||||
|
paneWidth: number;
|
||||||
|
windowWidth: number;
|
||||||
|
}
|
||||||
|
export declare function getPaneDimensions(paneId: string): Promise<PaneDimensions | null>;
|
||||||
3
dist/shared/tmux/tmux-utils/pane-replace.d.ts
vendored
Normal file
3
dist/shared/tmux/tmux-utils/pane-replace.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import type { TmuxConfig } from "../../../config/schema";
|
||||||
|
import type { SpawnPaneResult } from "../types";
|
||||||
|
export declare function replaceTmuxPane(paneId: string, sessionId: string, description: string, config: TmuxConfig, serverUrl: string): Promise<SpawnPaneResult>;
|
||||||
4
dist/shared/tmux/tmux-utils/pane-spawn.d.ts
vendored
Normal file
4
dist/shared/tmux/tmux-utils/pane-spawn.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import type { TmuxConfig } from "../../../config/schema";
|
||||||
|
import type { SpawnPaneResult } from "../types";
|
||||||
|
import type { SplitDirection } from "./environment";
|
||||||
|
export declare function spawnTmuxPane(sessionId: string, description: string, config: TmuxConfig, serverUrl: string, targetPaneId?: string, splitDirection?: SplitDirection): Promise<SpawnPaneResult>;
|
||||||
2
dist/shared/tmux/tmux-utils/server-health.d.ts
vendored
Normal file
2
dist/shared/tmux/tmux-utils/server-health.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export declare function isServerRunning(serverUrl: string): Promise<boolean>;
|
||||||
|
export declare function resetServerCheck(): void;
|
||||||
4
dist/shared/tmux/types.d.ts
vendored
Normal file
4
dist/shared/tmux/types.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export interface SpawnPaneResult {
|
||||||
|
success: boolean;
|
||||||
|
paneId?: string;
|
||||||
|
}
|
||||||
1
dist/tools/index.d.ts
vendored
Normal file
1
dist/tools/index.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export { interactive_bash, startBackgroundCheck as startTmuxCheck } from "./interactive-bash";
|
||||||
3
dist/tools/interactive-bash/constants.d.ts
vendored
Normal file
3
dist/tools/interactive-bash/constants.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export declare const DEFAULT_TIMEOUT_MS = 60000;
|
||||||
|
export declare const BLOCKED_TMUX_SUBCOMMANDS: string[];
|
||||||
|
export declare const INTERACTIVE_BASH_DESCRIPTION = "WARNING: This is TMUX ONLY. Pass tmux subcommands directly (without 'tmux' prefix).\n\nExamples: new-session -d -s omo-dev, send-keys -t omo-dev \"vim\" Enter\n\nFor TUI apps needing ongoing interaction (vim, htop, pudb). One-shot commands -> use Bash with &.";
|
||||||
3
dist/tools/interactive-bash/index.d.ts
vendored
Normal file
3
dist/tools/interactive-bash/index.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { interactive_bash } from "./tools";
|
||||||
|
import { startBackgroundCheck } from "./tmux-path-resolver";
|
||||||
|
export { interactive_bash, startBackgroundCheck };
|
||||||
3
dist/tools/interactive-bash/tmux-path-resolver.d.ts
vendored
Normal file
3
dist/tools/interactive-bash/tmux-path-resolver.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export declare function getTmuxPath(): Promise<string | null>;
|
||||||
|
export declare function getCachedTmuxPath(): string | null;
|
||||||
|
export declare function startBackgroundCheck(): void;
|
||||||
3
dist/tools/interactive-bash/tools.d.ts
vendored
Normal file
3
dist/tools/interactive-bash/tools.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { type ToolDefinition } from "@opencode-ai/plugin/tool";
|
||||||
|
export declare function tokenizeCommand(cmd: string): string[];
|
||||||
|
export declare const interactive_bash: ToolDefinition;
|
||||||
11
package.json
11
package.json
@@ -18,12 +18,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "bun build src/index.ts --outdir dist --target bun --format esm --external @ast-grep/napi && tsc --emitDeclarationOnly",
|
"bundle": "./build.sh",
|
||||||
"clean": "rm -rf dist",
|
"clean": "./clean.sh",
|
||||||
"prepare": "bun run build",
|
"prepublishOnly": "./prepublish.sh",
|
||||||
"prepublishOnly": "bun run clean && bun run build",
|
"typecheck": "./typecheck.sh",
|
||||||
"typecheck": "tsc --noEmit",
|
"test": "./test.sh"
|
||||||
"test": "bun test"
|
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"opencode",
|
"opencode",
|
||||||
|
|||||||
5
prepublish.sh
Executable file
5
prepublish.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
./clean.sh
|
||||||
|
./build.sh
|
||||||
4
typecheck.sh
Executable file
4
typecheck.sh
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
tsc --noEmit
|
||||||
Reference in New Issue
Block a user