oh-my-opencode-slim 2.2.1 → 2.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,6 +5,7 @@ export type { CmuxClient, CommandRunner } from './cmux';
5
5
  export { CliCmuxClient, CmuxMultiplexer } from './cmux';
6
6
  export { getMultiplexer, startAvailabilityCheck, } from './factory';
7
7
  export { HerdrMultiplexer } from './herdr';
8
+ export { KittyMultiplexer } from './kitty';
8
9
  export { MultiplexerSessionManager, TmuxSessionManager, } from './session-manager';
9
10
  export { TmuxMultiplexer } from './tmux';
10
11
  export type { Multiplexer, PaneResult } from './types';
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Kitty multiplexer implementation
3
+ *
4
+ * Uses kitty's remote-control CLI (`kitten @`) to manage windows.
5
+ * A kitty WINDOW is the 1:1 equivalent of a tmux pane (full PTY).
6
+ *
7
+ * Requires `allow_remote_control` **and** `listen_on` in kitty.conf. When
8
+ * `listen_on` is set, kitty exports `KITTY_LISTEN_ON` to its child processes
9
+ * (including OpenCode). The plugin passes that env through to `kitten @` so
10
+ * remote control goes via the socket instead of the controlling terminal,
11
+ * because OpenCode spawns subagent commands in a process detached from the
12
+ * kitty window's tty, where the tty-based remote-control path does not work.
13
+ *
14
+ * Layout mapping:
15
+ * - main-vertical → tall layout (full-height main pane on left, side panes stacked on right)
16
+ * - main-horizontal → fat layout (full-width main pane on top, side panes tiled below)
17
+ * - tiled → grid layout (equal-sized cells)
18
+ * - even-horizontal → horizontal layout (all panes side-by-side)
19
+ * - even-vertical → vertical layout (all panes stacked)
20
+ *
21
+ * Maps each plugin layout to the closest kitty built-in layout. kitty has no
22
+ * per-window layout API, so the chosen layout is applied as a global change to
23
+ * the active tab (overriding whatever layout was active there).
24
+ */
25
+ import type { MultiplexerLayout } from '../../config/schema';
26
+ import type { Multiplexer, PaneResult } from '../types';
27
+ export declare class KittyMultiplexer implements Multiplexer {
28
+ readonly type: "kitty";
29
+ private binaryPath;
30
+ private hasChecked;
31
+ private storedLayout;
32
+ private appliedLayout;
33
+ constructor(layout?: MultiplexerLayout, mainPaneSize?: number);
34
+ isAvailable(): Promise<boolean>;
35
+ isInsideSession(): boolean;
36
+ /**
37
+ * The kitty multiplexer needs `listen_on` configured in kitty.conf so kitty
38
+ * exports `KITTY_LISTEN_ON` to its children. Without it, `kitten @` cannot
39
+ * reach kitty from OpenCode's detached subagent processes (the tty path does
40
+ * not work). Returns true when the socket env is present.
41
+ */
42
+ private hasListenOn;
43
+ spawnPane(sessionId: string, description: string, serverUrl: string, directory: string): Promise<PaneResult>;
44
+ closePane(paneId: string): Promise<boolean>;
45
+ applyLayout(layout: MultiplexerLayout, mainPaneSize: number): Promise<void>;
46
+ private runKitty;
47
+ private ensureLayout;
48
+ private getBinary;
49
+ /**
50
+ * Build the env for `kitten @` invocations. When kitty's `listen_on` socket
51
+ * is configured, kitty sets `KITTY_LISTEN_ON` in its child processes (which
52
+ * includes OpenCode). We pass that env through so remote control goes via the
53
+ * socket instead of the controlling terminal (required for the plugin's
54
+ * detached subagent processes). When the var is absent we return undefined
55
+ * and `kitten @` falls back to the tty path.
56
+ */
57
+ private kittyEnv;
58
+ }
@@ -8,6 +8,32 @@ export declare function quoteShellArg(value: string): string;
8
8
  /** Normalize Windows backslashes to / so sh -lc (MSYS2/Git Bash) doesn't treat them as escape chars. */
9
9
  export declare function normalizePathForShell(directory: string): string;
10
10
  export declare function buildOpencodeAttachCommand(sessionId: string, serverUrl: string, directory: string, executable?: string): string;
11
+ /**
12
+ * Resolve the absolute path to the running OpenCode binary so child shells
13
+ * (e.g. a kitty-launched window) don't need `opencode` on their PATH. Falls
14
+ * back to the bare `opencode` name when no absolute path can be determined.
15
+ */
16
+ export declare function resolveOpencodeExecutable(): string;
17
+ /**
18
+ * Build the `[shell, ...shellArgs, command]` array for launching a command in
19
+ * the user's interactive shell. OpenCode respects the user's shell when running
20
+ * commands; multiplexer panes must do the same, otherwise a hardcoded `sh -c`
21
+ * breaks under non-POSIX shells (fish, nu, powershell, ...) or misses login
22
+ * startup files (where `opencode` may be on PATH).
23
+ *
24
+ * Mirrors OpenCode's own `Shell.args()` resolution:
25
+ * - nu / fish: `<shell> -c <command>` (no login mode)
26
+ * - zsh: login mode; zsh sources ~/.zshenv automatically, then we source
27
+ * .zshrc before running the command
28
+ * - bash: login mode, sources bashrc, then runs command
29
+ * - cmd: `cmd /c <command>`
30
+ * - powershell: `pwsh -NoProfile -Command <command>`
31
+ * - default (sh/dash/elvish/xonsh/...): `<shell> -c <command>`
32
+ *
33
+ * Note: the working directory is supplied by the launcher (e.g. kitty's
34
+ * `--cwd`), not by a `cd` inside the shell command.
35
+ */
36
+ export declare function buildShellLaunchArgs(command: string): string[];
11
37
  export declare function resolveHostOpencodeBinary(options?: {
12
38
  override?: string;
13
39
  envOverride?: string;
@@ -27,5 +53,7 @@ export interface GracefulClosePaneOptions {
27
53
  acceptExitCode1?: boolean;
28
54
  /** Return true for empty/unknown paneId instead of false (zellij/herdr behavior). */
29
55
  emptyPaneReturnsTrue?: boolean;
56
+ /** Env to pass to the kitten/kitty invocations (e.g. KITTY_LISTEN_ON). */
57
+ env?: Record<string, string | undefined>;
30
58
  }
31
59
  export declare function gracefulClosePane(binary: string | null, paneId: string, options: GracefulClosePaneOptions): Promise<boolean>;
@@ -14,10 +14,10 @@ export interface PaneResult {
14
14
  /**
15
15
  * Core multiplexer interface
16
16
  * Implementations: TmuxMultiplexer, ZellijMultiplexer, HerdrMultiplexer,
17
- * CmuxMultiplexer
17
+ * CmuxMultiplexer, KittyMultiplexer
18
18
  */
19
19
  export interface Multiplexer {
20
- readonly type: 'tmux' | 'zellij' | 'herdr' | 'cmux';
20
+ readonly type: 'tmux' | 'zellij' | 'herdr' | 'cmux' | 'kitty';
21
21
  /**
22
22
  * Check if the multiplexer binary is available on the system
23
23
  */
package/dist/tui.js CHANGED
@@ -129,7 +129,6 @@ var DEFAULT_MODELS = {
129
129
  };
130
130
  var POLL_INTERVAL_BACKGROUND_MS = 2000;
131
131
  var MAX_POLL_TIME_MS = 5 * 60 * 1000;
132
- var DEFAULT_MAX_SUBAGENT_DEPTH = 3;
133
132
  var PHASE_REMINDER_TEXT = `!IMPORTANT! Scheduler workflow: First choose the lightest workflow that fits the work. If direct execution is justified, complete it and verify proportionately. Otherwise: plan lanes/dependencies → dispatch background specialists → track task IDs → wait for hook-driven completion → reconcile terminal results → verify. Do not poll running jobs, consume running-job output, or advance dependent work. !END!`;
134
133
  function formatSystemReminder(text) {
135
134
  return `<system-reminder>
@@ -367,6 +366,7 @@ var MultiplexerTypeSchema = z2.enum([
367
366
  "tmux",
368
367
  "zellij",
369
368
  "herdr",
369
+ "kitty",
370
370
  "cmux",
371
371
  "none"
372
372
  ]);
@@ -95,7 +95,7 @@ export declare class BackgroundJobBoard implements BackgroundJobStore {
95
95
  hasRunning(parentSessionID: string): boolean;
96
96
  hasTerminalUnreconciled(parentSessionID: string): boolean;
97
97
  hasConvergenceSignals(taskID: string, threshold?: number): boolean;
98
- formatForPrompt(parentSessionID: string, now?: number): string | undefined;
98
+ formatForPrompt(parentSessionID: string, _now?: number): string | undefined;
99
99
  clearParent(parentSessionID: string): void;
100
100
  drop(taskID: string): void;
101
101
  deferIfRunning(_sessionId: string): boolean;
@@ -941,6 +941,7 @@
941
941
  "tmux",
942
942
  "zellij",
943
943
  "herdr",
944
+ "kitty",
944
945
  "cmux",
945
946
  "none"
946
947
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-opencode-slim",
3
- "version": "2.2.1",
3
+ "version": "2.2.3",
4
4
  "description": "Lightweight agent orchestration plugin for OpenCode - a slimmed-down fork of oh-my-opencode",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -61,6 +61,7 @@
61
61
  "generate-schema": "bun run scripts/generate-schema.ts",
62
62
  "verify:release": "bun run scripts/verify-release-artifact.ts",
63
63
  "verify:host-smoke": "bun run scripts/verify-opencode-host-smoke.ts",
64
+ "verify:cache-stability": "bun run scripts/verify-opencode-cache-stability.ts",
64
65
  "typecheck": "tsc --noEmit",
65
66
  "test": "bun test",
66
67
  "lint": "biome lint .",
@@ -27,6 +27,8 @@ Required behavior:
27
27
  `!.slim/deepwork/` and `!.slim/deepwork/**`;
28
28
  - keep OpenCode todos aligned with the active deepwork phase;
29
29
  - create and maintain a local markdown progress file under `.slim/deepwork/`;
30
+ - save code/doc deliverables to project paths (e.g. `src/`, `docs/`); reserve
31
+ `.slim/deepwork/` strictly for progress files;
30
32
  - write valuable research findings into that file as confirmed research context
31
33
  when they are received and reconciled;
32
34
  - draft a plan before implementation;
@@ -1,35 +0,0 @@
1
- /**
2
- * Tracks subagent spawn depth to prevent excessive nesting.
3
- *
4
- * Depth 0 = root session (user's main conversation)
5
- * Depth 1 = agent spawned by root (e.g., explorer, council)
6
- * Depth 2 = agent spawned by depth-1 agent (e.g., councillor spawned by council)
7
- * Depth 3 = agent spawned by depth-2 agent (max depth by default)
8
- *
9
- * When max depth is exceeded, the spawn is blocked.
10
- */
11
- export declare class SubagentDepthTracker {
12
- private depthBySession;
13
- private readonly _maxDepth;
14
- constructor(maxDepth?: number);
15
- /** Maximum allowed depth. */
16
- get maxDepth(): number;
17
- /**
18
- * Get the current depth of a session.
19
- * Root sessions (not tracked) have depth 0.
20
- */
21
- getDepth(sessionId: string): number;
22
- /**
23
- * Register a child session and check if the spawn is allowed.
24
- * @returns true if allowed, false if max depth exceeded
25
- */
26
- registerChild(parentSessionId: string, childSessionId: string): boolean;
27
- /**
28
- * Clean up session tracking when a session is deleted.
29
- */
30
- cleanup(sessionId: string): void;
31
- /**
32
- * Clean up all tracking data.
33
- */
34
- cleanupAll(): void;
35
- }