oh-my-opencode-slim 2.0.0-beta.8 → 2.0.0

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.
Files changed (50) hide show
  1. package/README.ja-JP.md +86 -32
  2. package/README.ko-KR.md +690 -0
  3. package/README.md +118 -45
  4. package/README.zh-CN.md +97 -37
  5. package/dist/cli/background-subagents.d.ts +13 -0
  6. package/dist/cli/companion.d.ts +4 -0
  7. package/dist/cli/index.d.ts +2 -1
  8. package/dist/cli/index.js +624 -96
  9. package/dist/cli/install.d.ts +6 -1
  10. package/dist/cli/providers.d.ts +2 -1
  11. package/dist/cli/types.d.ts +8 -0
  12. package/dist/companion/manager.d.ts +38 -0
  13. package/dist/config/constants.d.ts +4 -1
  14. package/dist/config/fallback-chains.d.ts +1 -0
  15. package/dist/config/schema.d.ts +46 -40
  16. package/dist/hooks/auto-update-checker/checker.d.ts +7 -1
  17. package/dist/hooks/auto-update-checker/constants.d.ts +1 -0
  18. package/dist/hooks/auto-update-checker/types.d.ts +10 -0
  19. package/dist/hooks/index.d.ts +0 -2
  20. package/dist/hooks/json-error-recovery/hook.d.ts +1 -1
  21. package/dist/hooks/phase-reminder/index.d.ts +1 -1
  22. package/dist/index.js +1996 -2132
  23. package/dist/mcp/grep-app.d.ts +1 -1
  24. package/dist/multiplexer/zellij/index.d.ts +17 -3
  25. package/dist/tools/cancel-task.d.ts +16 -0
  26. package/dist/tools/index.d.ts +1 -0
  27. package/dist/tools/preset-manager.d.ts +6 -7
  28. package/dist/tui.js +71 -32
  29. package/dist/utils/background-job-board.d.ts +40 -0
  30. package/dist/utils/index.d.ts +0 -1
  31. package/dist/utils/task.d.ts +2 -0
  32. package/oh-my-opencode-slim.schema.json +34 -91
  33. package/package.json +4 -3
  34. package/src/skills/codemap.md +3 -1
  35. package/src/skills/deepwork/SKILL.md +25 -3
  36. package/src/skills/oh-my-opencode-slim/SKILL.md +326 -0
  37. package/dist/divoom/council.gif +0 -0
  38. package/dist/divoom/designer.gif +0 -0
  39. package/dist/divoom/explorer.gif +0 -0
  40. package/dist/divoom/fixer.gif +0 -0
  41. package/dist/divoom/input.gif +0 -0
  42. package/dist/divoom/intro.gif +0 -0
  43. package/dist/divoom/librarian.gif +0 -0
  44. package/dist/divoom/manager.d.ts +0 -57
  45. package/dist/divoom/oracle.gif +0 -0
  46. package/dist/divoom/orchestrator.gif +0 -0
  47. package/dist/hooks/goal/index.d.ts +0 -38
  48. package/dist/hooks/todo-continuation/index.d.ts +0 -55
  49. package/dist/hooks/todo-continuation/todo-hygiene.d.ts +0 -35
  50. package/dist/utils/session-manager.d.ts +0 -55
@@ -3,4 +3,4 @@ import type { RemoteMcpConfig } from './types';
3
3
  * grep.app - ultra-fast code search across GitHub repositories
4
4
  * @see https://grep.app
5
5
  */
6
- export declare const grep_app: RemoteMcpConfig;
6
+ export declare const gh_grep: RemoteMcpConfig;
@@ -1,24 +1,34 @@
1
1
  /**
2
2
  * Zellij multiplexer implementation
3
3
  *
4
- * Creates a dedicated "opencode-agents" tab for all sub-agent panes.
4
+ * Creates panes for sub-agent sessions in Zellij.
5
+ *
6
+ * The default mode creates a dedicated "opencode-agents" tab:
5
7
  * - First sub-agent uses the default pane from new-tab
6
8
  * - Subsequent sub-agents create new panes
7
9
  * - User stays in their original tab
10
+ *
11
+ * The optional "current-tab" mode creates panes in the tab containing the
12
+ * parent OpenCode pane instead.
8
13
  */
9
- import type { MultiplexerLayout } from '../../config/schema';
14
+ import type { MultiplexerLayout, ZellijPaneMode } from '../../config/schema';
10
15
  import type { Multiplexer, PaneResult } from '../types';
11
16
  export declare class ZellijMultiplexer implements Multiplexer {
17
+ private readonly paneMode;
12
18
  readonly type: "zellij";
13
19
  private binaryPath;
14
20
  private hasChecked;
15
21
  private agentTabId;
16
22
  private firstPaneId;
17
23
  private firstPaneUsed;
18
- constructor(layout?: MultiplexerLayout, mainPaneSize?: number);
24
+ private parentTabId;
25
+ private readonly parentPaneId;
26
+ private readonly paneDirection;
27
+ constructor(layout?: MultiplexerLayout, mainPaneSize?: number, paneMode?: ZellijPaneMode);
19
28
  isAvailable(): Promise<boolean>;
20
29
  isInsideSession(): boolean;
21
30
  spawnPane(sessionId: string, description: string, serverUrl: string, directory: string): Promise<PaneResult>;
31
+ private createPaneInCurrentTab;
22
32
  private createPaneInAgentTab;
23
33
  private runInPane;
24
34
  private ensureAgentTab;
@@ -29,6 +39,10 @@ export declare class ZellijMultiplexer implements Multiplexer {
29
39
  private listPanes;
30
40
  closePane(paneId: string): Promise<boolean>;
31
41
  applyLayout(_layout: MultiplexerLayout, _mainPaneSize: number): Promise<void>;
42
+ private directionArgs;
43
+ private tabIdArgs;
44
+ private getParentTabId;
45
+ private findTabIdForPane;
32
46
  private getBinary;
33
47
  private findBinary;
34
48
  }
@@ -0,0 +1,16 @@
1
+ import { type PluginInput, type ToolDefinition } from '@opencode-ai/plugin';
2
+ import type { BackgroundJobBoard } from '../utils/background-job-board';
3
+ interface CancelTaskToolOptions {
4
+ client: PluginInput['client'];
5
+ backgroundJobBoard: BackgroundJobBoard;
6
+ shouldManageSession: (sessionID: string) => boolean;
7
+ abortTimeoutMs?: number;
8
+ verifyAbortMs?: number;
9
+ abortRetryIntervalMs?: number;
10
+ stableStoppedMs?: number;
11
+ deleteTimeoutMs?: number;
12
+ deleteVerifyMs?: number;
13
+ deleteStableStoppedMs?: number;
14
+ }
15
+ export declare function createCancelTaskTool(options: CancelTaskToolOptions): Record<string, ToolDefinition>;
16
+ export {};
@@ -1,4 +1,5 @@
1
1
  export { ast_grep_replace, ast_grep_search } from './ast-grep';
2
+ export { createCancelTaskTool } from './cancel-task';
2
3
  export { createCouncilTool } from './council';
3
4
  export type { PresetManager } from './preset-manager';
4
5
  export { createPresetManager } from './preset-manager';
@@ -3,13 +3,12 @@ import type { PluginConfig } from '../config';
3
3
  /**
4
4
  * Creates a preset manager for the /preset slash command.
5
5
  *
6
- * Uses the OpenCode SDK's client.config.update() to change agent models
7
- * and temperatures without restarting. The server invalidates its agent
8
- * cache and re-reads config on the next prompt.
9
- *
10
- * Note: activePreset is tracked in-memory only and resets on plugin reload.
11
- * If the user manually edits config or another mechanism changes agents,
12
- * this tracker may become stale until the next /preset call.
6
+ * Stores the requested runtime preset in plugin memory and updates the
7
+ * plugin-facing TUI snapshot. It deliberately does not call OpenCode's
8
+ * client.config.update() or instance.dispose() from command hooks because
9
+ * OpenCode continues the same command into the prompt loop after
10
+ * command.execute.before, which can break the active conversation while
11
+ * the agent registry is changing.
13
12
  */
14
13
  export declare function createPresetManager(ctx: PluginInput, config: PluginConfig): {
15
14
  handleCommandExecuteBefore: (input: {
package/dist/tui.js CHANGED
@@ -4,15 +4,29 @@ var __getProtoOf = Object.getPrototypeOf;
4
4
  var __defProp = Object.defineProperty;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ function __accessProp(key) {
8
+ return this[key];
9
+ }
10
+ var __toESMCache_node;
11
+ var __toESMCache_esm;
7
12
  var __toESM = (mod, isNodeMode, target) => {
13
+ var canCache = mod != null && typeof mod === "object";
14
+ if (canCache) {
15
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
16
+ var cached = cache.get(mod);
17
+ if (cached)
18
+ return cached;
19
+ }
8
20
  target = mod != null ? __create(__getProtoOf(mod)) : {};
9
21
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
22
  for (let key of __getOwnPropNames(mod))
11
23
  if (!__hasOwnProp.call(to, key))
12
24
  __defProp(to, key, {
13
- get: () => mod[key],
25
+ get: __accessProp.bind(mod, key),
14
26
  enumerable: true
15
27
  });
28
+ if (canCache)
29
+ cache.set(mod, to);
16
30
  return to;
17
31
  };
18
32
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
@@ -54,7 +68,22 @@ var POLL_INTERVAL_BACKGROUND_MS = 2000;
54
68
  var DEFAULT_TIMEOUT_MS = 2 * 60 * 1000;
55
69
  var MAX_POLL_TIME_MS = 5 * 60 * 1000;
56
70
  var DEFAULT_MAX_SUBAGENT_DEPTH = 3;
57
- var PHASE_REMINDER_TEXT = `!IMPORTANT! Scheduler workflow: plan lanes/dependencies → dispatch background specialists → track task IDs → poll task_status → reconcile terminal results → verify. Do not consume running-job output or advance dependent work. !END!`;
71
+ var PHASE_REMINDER_TEXT = `!IMPORTANT! Scheduler workflow: 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!`;
72
+ var WRITABLE_FILE_OPERATIONS_RULES = `**File Operations Rules**:
73
+ - Prefer dedicated file tools for normal code work: glob/grep/ast_grep_search for discovery, read for file contents, and edit/write/apply_patch for targeted source changes.
74
+ - Use bash for execution and automation: git, package managers, tests, builds, scripts, diagnostics, and shell-native filesystem operations.
75
+ - Shell is acceptable for bulk or mechanical filesystem changes when it is clearer or safer than many individual edits (for example: truncate generated logs, remove build artifacts, batch rename/move files), especially when the user explicitly asks for that shell operation.
76
+ - Before destructive or broad shell operations, verify the target set and quote paths. Prefer a dry-run/listing first when practical.
77
+ - Do not use cat/head/tail/sed/awk only to read code into context; use read/grep unless a shell pipeline is genuinely the better diagnostic.`;
78
+ var READONLY_FILE_OPERATIONS_RULES = `**File Operations Rules**:
79
+ - READ-ONLY: inspect and report; do not modify files.
80
+ - Prefer dedicated file tools for codebase inspection: glob/grep/ast_grep_search for discovery and read for file contents.
81
+ - Bash is allowed for non-mutating diagnostics and shell-native inspection when it is the clearest tool, but not for modifying files.
82
+ - Do not use cat/head/tail/sed/awk only to read code into context; use read/grep unless a shell pipeline is genuinely the better diagnostic.`;
83
+ var NO_SHELL_READONLY_FILE_OPERATIONS_RULES = `**File Operations Rules**:
84
+ - READ-ONLY: inspect and report; do not modify files.
85
+ - Use glob/grep/ast_grep_search for discovery and read for file contents.
86
+ - Do not use bash or shell commands.`;
58
87
  var TMUX_SPAWN_DELAY_MS = 500;
59
88
  var COUNCILLOR_STAGGER_MS = 250;
60
89
  var DEFAULT_DISABLED_AGENTS = ["observer"];
@@ -124,6 +153,13 @@ function getCustomOpenCodeConfigDir() {
124
153
  const configDir = process.env.OPENCODE_CONFIG_DIR?.trim();
125
154
  return configDir || undefined;
126
155
  }
156
+ function getConfigDir() {
157
+ const customConfigDir = getCustomOpenCodeConfigDir();
158
+ if (customConfigDir) {
159
+ return customConfigDir;
160
+ }
161
+ return getDefaultOpenCodeConfigDir();
162
+ }
127
163
  function getConfigSearchDirs() {
128
164
  const dirs = [getCustomOpenCodeConfigDir(), getDefaultOpenCodeConfigDir()];
129
165
  return dirs.filter((dir, index) => {
@@ -131,7 +167,7 @@ function getConfigSearchDirs() {
131
167
  });
132
168
  }
133
169
  function getOpenCodeConfigPaths() {
134
- const configDir = getDefaultOpenCodeConfigDir();
170
+ const configDir = getConfigDir();
135
171
  return [join(configDir, "opencode.json"), join(configDir, "opencode.jsonc")];
136
172
  }
137
173
  // src/config/council-schema.ts
@@ -269,11 +305,13 @@ var MultiplexerLayoutSchema = z2.enum([
269
305
  "even-horizontal",
270
306
  "even-vertical"
271
307
  ]);
308
+ var ZellijPaneModeSchema = z2.enum(["agent-tab", "current-tab"]);
272
309
  var TmuxLayoutSchema = MultiplexerLayoutSchema;
273
310
  var MultiplexerConfigSchema = z2.object({
274
311
  type: MultiplexerTypeSchema.default("none"),
275
312
  layout: MultiplexerLayoutSchema.default("main-vertical"),
276
- main_pane_size: z2.number().min(20).max(80).default(60)
313
+ main_pane_size: z2.number().min(20).max(80).default(60),
314
+ zellij_pane_mode: ZellijPaneModeSchema.default("agent-tab")
277
315
  });
278
316
  var TmuxConfigSchema = z2.object({
279
317
  enabled: z2.boolean().default(false),
@@ -284,7 +322,7 @@ var PresetSchema = z2.record(z2.string(), AgentOverrideConfigSchema);
284
322
  var WebsearchConfigSchema = z2.object({
285
323
  provider: z2.enum(["exa", "tavily"]).default("exa")
286
324
  });
287
- var McpNameSchema = z2.enum(["websearch", "context7", "grep_app"]);
325
+ var McpNameSchema = z2.enum(["websearch", "context7", "gh_grep"]);
288
326
  var InterviewConfigSchema = z2.object({
289
327
  maxQuestions: z2.number().int().min(1).max(10).default(2),
290
328
  outputFolder: z2.string().min(1).default("interview"),
@@ -292,28 +330,11 @@ var InterviewConfigSchema = z2.object({
292
330
  port: z2.number().int().min(0).max(65535).default(0),
293
331
  dashboard: z2.boolean().default(false)
294
332
  });
295
- var SessionManagerConfigSchema = z2.object({
333
+ var BackgroundJobsConfigSchema = z2.object({
296
334
  maxSessionsPerAgent: z2.number().int().min(1).max(10).default(2),
297
335
  readContextMinLines: z2.number().int().min(0).max(1000).default(10),
298
336
  readContextMaxFiles: z2.number().int().min(0).max(50).default(8)
299
337
  });
300
- var DivoomConfigSchema = z2.object({
301
- enabled: z2.boolean().default(false),
302
- python: z2.string().min(1).default("/Applications/Divoom MiniToo.app/Contents/Resources/.venv/bin/python"),
303
- script: z2.string().min(1).default("/Applications/Divoom MiniToo.app/Contents/Resources/tools/divoom_send.py"),
304
- size: z2.number().int().min(1).max(1024).default(128),
305
- fps: z2.number().int().min(1).max(60).default(8),
306
- speed: z2.number().int().min(1).max(1e4).default(125),
307
- maxFrames: z2.number().int().min(1).max(500).default(24),
308
- posterizeBits: z2.number().int().min(1).max(8).default(3),
309
- gifs: z2.record(z2.string(), z2.string().min(1)).optional()
310
- });
311
- var TodoContinuationConfigSchema = z2.object({
312
- maxContinuations: z2.number().int().min(1).max(50).default(5).describe("Maximum consecutive auto-continuations before stopping to ask user"),
313
- cooldownMs: z2.number().int().min(0).max(30000).default(3000).describe("Delay in ms before auto-continuing (gives user time to abort)"),
314
- autoEnable: z2.boolean().default(false).describe("Automatically enable auto-continue when the orchestrator session has enough todos"),
315
- autoEnableThreshold: z2.number().int().min(1).max(50).default(4).describe("Number of todos that triggers auto-enable (only used when autoEnable is true)")
316
- });
317
338
  var FailoverConfigSchema = z2.object({
318
339
  enabled: z2.boolean().default(true),
319
340
  timeoutMs: z2.number().min(0).default(15000),
@@ -321,6 +342,11 @@ var FailoverConfigSchema = z2.object({
321
342
  chains: FallbackChainsSchema.default({}),
322
343
  retry_on_empty: z2.boolean().default(true).describe("When true (default), empty provider responses are treated as failures, " + "triggering fallback/retry. Set to false to treat them as successes.")
323
344
  });
345
+ var CompanionConfigSchema = z2.object({
346
+ enabled: z2.boolean().optional(),
347
+ position: z2.enum(["bottom-right", "bottom-left", "top-right", "top-left"]).optional(),
348
+ size: z2.enum(["small", "medium", "large"]).optional()
349
+ });
324
350
  function validateCustomOnlyPromptFields(overrides, ctx, pathPrefix) {
325
351
  for (const [name, override] of Object.entries(overrides)) {
326
352
  const isBuiltInOrAlias = ALL_AGENT_NAMES.includes(name) || AGENT_ALIASES[name] !== undefined;
@@ -358,11 +384,10 @@ var PluginConfigSchema = z2.object({
358
384
  tmux: TmuxConfigSchema.optional(),
359
385
  websearch: WebsearchConfigSchema.optional(),
360
386
  interview: InterviewConfigSchema.optional(),
361
- sessionManager: SessionManagerConfigSchema.optional(),
362
- divoom: DivoomConfigSchema.optional(),
363
- todoContinuation: TodoContinuationConfigSchema.optional(),
387
+ backgroundJobs: BackgroundJobsConfigSchema.optional(),
364
388
  fallback: FailoverConfigSchema.optional(),
365
- council: CouncilConfigSchema.optional()
389
+ council: CouncilConfigSchema.optional(),
390
+ companion: CompanionConfigSchema.optional()
366
391
  }).superRefine((value, ctx) => {
367
392
  if (value.agents) {
368
393
  validateCustomOnlyPromptFields(value.agents, ctx, ["agents"]);
@@ -392,7 +417,7 @@ var DEFAULT_AGENT_MCPS = {
392
417
  orchestrator: ["*", "!context7"],
393
418
  designer: [],
394
419
  oracle: [],
395
- librarian: ["websearch", "context7", "grep_app"],
420
+ librarian: ["websearch", "context7", "gh_grep"],
396
421
  explorer: [],
397
422
  fixer: [],
398
423
  observer: [],
@@ -447,6 +472,12 @@ var CUSTOM_SKILLS = [
447
472
  description: "Heavy/complex coding sessions and large modifications workflow",
448
473
  allowedAgents: ["orchestrator"],
449
474
  sourcePath: "src/skills/deepwork"
475
+ },
476
+ {
477
+ name: "oh-my-opencode-slim",
478
+ description: "Configure, customize, and safely improve oh-my-opencode-slim setups",
479
+ allowedAgents: ["orchestrator"],
480
+ sourcePath: "src/skills/oh-my-opencode-slim"
450
481
  }
451
482
  ];
452
483
 
@@ -542,10 +573,10 @@ function mergePluginConfigs(base, override) {
542
573
  tmux: deepMerge(base.tmux, override.tmux),
543
574
  multiplexer: deepMerge(base.multiplexer, override.multiplexer),
544
575
  interview: deepMerge(base.interview, override.interview),
545
- sessionManager: deepMerge(base.sessionManager, override.sessionManager),
546
- divoom: deepMerge(base.divoom, override.divoom),
576
+ backgroundJobs: deepMerge(base.backgroundJobs, override.backgroundJobs),
547
577
  fallback: deepMerge(base.fallback, override.fallback),
548
- council: deepMerge(base.council, override.council)
578
+ council: deepMerge(base.council, override.council),
579
+ companion: deepMerge(base.companion, override.companion)
549
580
  };
550
581
  }
551
582
  function deepMerge(base, override) {
@@ -595,6 +626,13 @@ function loadPluginConfig(directory, options) {
595
626
  }
596
627
  }
597
628
  }
629
+ if (config.companion) {
630
+ config.companion = {
631
+ enabled: config.companion.enabled ?? false,
632
+ position: config.companion.position ?? "bottom-right",
633
+ size: config.companion.size ?? "medium"
634
+ };
635
+ }
598
636
  return config;
599
637
  }
600
638
  function loadAgentPrompt(agentName, preset) {
@@ -632,7 +670,8 @@ function migrateTmuxToMultiplexer(config) {
632
670
  multiplexer: {
633
671
  type: "tmux",
634
672
  layout: config.tmux.layout ?? "main-vertical",
635
- main_pane_size: config.tmux.main_pane_size ?? 60
673
+ main_pane_size: config.tmux.main_pane_size ?? 60,
674
+ zellij_pane_mode: "agent-tab"
636
675
  }
637
676
  };
638
677
  }
@@ -1,4 +1,10 @@
1
1
  import { type TaskOutputState } from './task';
2
+ export interface ContextFile {
3
+ path: string;
4
+ lineCount: number;
5
+ lineNumbers?: number[];
6
+ lastReadAt: number;
7
+ }
2
8
  export type BackgroundJobState = TaskOutputState | 'reconciled';
3
9
  export interface BackgroundJobRecord {
4
10
  taskID: string;
@@ -8,13 +14,25 @@ export interface BackgroundJobRecord {
8
14
  objective?: string;
9
15
  state: BackgroundJobState;
10
16
  timedOut: boolean;
17
+ statusUncertain: boolean;
18
+ cancellationRequested: boolean;
11
19
  terminalUnreconciled: boolean;
12
20
  launchedAt: number;
13
21
  lastLaunchedAt: number;
14
22
  updatedAt: number;
23
+ lastLiveBusyAt?: number;
15
24
  completedAt?: number;
16
25
  resultSummary?: string;
26
+ lastStatusError?: string;
17
27
  alias: string;
28
+ lastUsedAt: number;
29
+ terminalState?: TaskOutputState;
30
+ contextFiles: ContextFile[];
31
+ }
32
+ export interface BackgroundJobBoardOptions {
33
+ maxReusablePerAgent?: number;
34
+ readContextMinLines?: number;
35
+ readContextMaxFiles?: number;
18
36
  }
19
37
  export interface BackgroundJobLaunchInput {
20
38
  taskID: string;
@@ -28,22 +46,44 @@ export interface BackgroundJobStatusInput {
28
46
  taskID: string;
29
47
  state: TaskOutputState;
30
48
  timedOut?: boolean;
49
+ statusUncertain?: boolean;
31
50
  resultSummary?: string;
51
+ lastStatusError?: string;
32
52
  now?: number;
33
53
  }
34
54
  export declare class BackgroundJobBoard {
35
55
  private readonly jobs;
36
56
  private readonly counters;
57
+ private readonly maxReusablePerAgent;
58
+ private readonly readContextMinLines;
59
+ private readonly readContextMaxFiles;
60
+ constructor(options?: BackgroundJobBoardOptions);
37
61
  registerLaunch(input: BackgroundJobLaunchInput): BackgroundJobRecord;
38
62
  updateStatus(input: BackgroundJobStatusInput): BackgroundJobRecord | undefined;
39
63
  updateFromStatusOutput(output: string): BackgroundJobRecord | undefined;
64
+ markRunningFromLiveSession(taskID: string, now?: number): BackgroundJobRecord | undefined;
40
65
  markReconciled(taskID: string, now?: number): BackgroundJobRecord | undefined;
66
+ markCancelled(taskID: string, reason?: string, now?: number, options?: {
67
+ force?: boolean;
68
+ }): BackgroundJobRecord | undefined;
41
69
  get(taskID: string): BackgroundJobRecord | undefined;
70
+ resolve(parentSessionID: string, taskIDOrAlias: string): BackgroundJobRecord | undefined;
71
+ resolveReusable(parentSessionID: string, taskIDOrAlias: string, agent?: string): BackgroundJobRecord | undefined;
72
+ markUsed(parentSessionID: string, key: string, now?: number): void;
73
+ taskIDs(): Set<string>;
74
+ addContext(taskID: string, files: ContextFile[]): void;
42
75
  list(parentSessionID?: string): BackgroundJobRecord[];
43
76
  hasRunning(parentSessionID: string): boolean;
44
77
  hasTerminalUnreconciled(parentSessionID: string): boolean;
45
78
  formatForPrompt(parentSessionID: string, now?: number): string | undefined;
46
79
  clearParent(parentSessionID: string): void;
47
80
  drop(taskID: string): void;
81
+ private trimReusable;
82
+ private formatReusableJob;
48
83
  private nextAlias;
49
84
  }
85
+ export declare function deriveTaskSessionLabel(input: {
86
+ description?: string;
87
+ prompt?: string;
88
+ agentType: string;
89
+ }): string;
@@ -5,6 +5,5 @@ export * from './internal-initiator';
5
5
  export { getLogDir, initLogger, log, resetLogger } from './logger';
6
6
  export * from './polling';
7
7
  export * from './session';
8
- export * from './session-manager';
9
8
  export * from './task';
10
9
  export { extractZip } from './zip-extractor';
@@ -13,8 +13,10 @@ export interface TaskStatusOutput {
13
13
  timedOut: boolean;
14
14
  result?: string;
15
15
  }
16
+ export type TaskStatusClassification = 'running' | 'terminal' | 'timeout' | 'transient_process_error' | 'unknown_error';
16
17
  export declare function parseTaskIdFromTaskOutput(output: string): string | undefined;
17
18
  export declare function parseTaskLaunchOutput(output: string): TaskLaunchOutput | undefined;
18
19
  export declare function parseTaskStatusOutput(output: string): TaskStatusOutput | undefined;
20
+ export declare function classifyTaskStatusOutput(status: TaskStatusOutput): TaskStatusClassification;
19
21
  export declare function parseTaskStateFromOutput(output: string): TaskOutputState | undefined;
20
22
  export declare function parseTaskResultFromOutput(output: string): string | undefined;
@@ -413,6 +413,14 @@
413
413
  "type": "number",
414
414
  "minimum": 20,
415
415
  "maximum": 80
416
+ },
417
+ "zellij_pane_mode": {
418
+ "default": "agent-tab",
419
+ "type": "string",
420
+ "enum": [
421
+ "agent-tab",
422
+ "current-tab"
423
+ ]
416
424
  }
417
425
  }
418
426
  },
@@ -486,7 +494,7 @@
486
494
  }
487
495
  }
488
496
  },
489
- "sessionManager": {
497
+ "backgroundJobs": {
490
498
  "type": "object",
491
499
  "properties": {
492
500
  "maxSessionsPerAgent": {
@@ -509,96 +517,6 @@
509
517
  }
510
518
  }
511
519
  },
512
- "divoom": {
513
- "type": "object",
514
- "properties": {
515
- "enabled": {
516
- "default": false,
517
- "type": "boolean"
518
- },
519
- "python": {
520
- "default": "/Applications/Divoom MiniToo.app/Contents/Resources/.venv/bin/python",
521
- "type": "string",
522
- "minLength": 1
523
- },
524
- "script": {
525
- "default": "/Applications/Divoom MiniToo.app/Contents/Resources/tools/divoom_send.py",
526
- "type": "string",
527
- "minLength": 1
528
- },
529
- "size": {
530
- "default": 128,
531
- "type": "integer",
532
- "minimum": 1,
533
- "maximum": 1024
534
- },
535
- "fps": {
536
- "default": 8,
537
- "type": "integer",
538
- "minimum": 1,
539
- "maximum": 60
540
- },
541
- "speed": {
542
- "default": 125,
543
- "type": "integer",
544
- "minimum": 1,
545
- "maximum": 10000
546
- },
547
- "maxFrames": {
548
- "default": 24,
549
- "type": "integer",
550
- "minimum": 1,
551
- "maximum": 500
552
- },
553
- "posterizeBits": {
554
- "default": 3,
555
- "type": "integer",
556
- "minimum": 1,
557
- "maximum": 8
558
- },
559
- "gifs": {
560
- "type": "object",
561
- "propertyNames": {
562
- "type": "string"
563
- },
564
- "additionalProperties": {
565
- "type": "string",
566
- "minLength": 1
567
- }
568
- }
569
- }
570
- },
571
- "todoContinuation": {
572
- "type": "object",
573
- "properties": {
574
- "maxContinuations": {
575
- "default": 5,
576
- "description": "Maximum consecutive auto-continuations before stopping to ask user",
577
- "type": "integer",
578
- "minimum": 1,
579
- "maximum": 50
580
- },
581
- "cooldownMs": {
582
- "default": 3000,
583
- "description": "Delay in ms before auto-continuing (gives user time to abort)",
584
- "type": "integer",
585
- "minimum": 0,
586
- "maximum": 30000
587
- },
588
- "autoEnable": {
589
- "default": false,
590
- "description": "Automatically enable auto-continue when the orchestrator session has enough todos",
591
- "type": "boolean"
592
- },
593
- "autoEnableThreshold": {
594
- "default": 4,
595
- "description": "Number of todos that triggers auto-enable (only used when autoEnable is true)",
596
- "type": "integer",
597
- "minimum": 1,
598
- "maximum": 50
599
- }
600
- }
601
- },
602
520
  "fallback": {
603
521
  "type": "object",
604
522
  "properties": {
@@ -738,6 +656,31 @@
738
656
  "required": [
739
657
  "presets"
740
658
  ]
659
+ },
660
+ "companion": {
661
+ "type": "object",
662
+ "properties": {
663
+ "enabled": {
664
+ "type": "boolean"
665
+ },
666
+ "position": {
667
+ "type": "string",
668
+ "enum": [
669
+ "bottom-right",
670
+ "bottom-left",
671
+ "top-right",
672
+ "top-left"
673
+ ]
674
+ },
675
+ "size": {
676
+ "type": "string",
677
+ "enum": [
678
+ "small",
679
+ "medium",
680
+ "large"
681
+ ]
682
+ }
683
+ }
741
684
  }
742
685
  },
743
686
  "title": "oh-my-opencode-slim",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-opencode-slim",
3
- "version": "2.0.0-beta.8",
3
+ "version": "2.0.0",
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",
@@ -44,14 +44,15 @@
44
44
  "oh-my-opencode-slim.schema.json",
45
45
  "README.md",
46
46
  "README.zh-CN.md",
47
+ "README.ja-JP.md",
48
+ "README.ko-KR.md",
47
49
  "LICENSE"
48
50
  ],
49
51
  "scripts": {
50
52
  "clean:dist": "bun -e \"import { rmSync } from 'node:fs'; rmSync('dist', { recursive: true, force: true })\"",
51
53
  "build:plugin": "bun build src/index.ts src/tui.ts --outdir dist --target node --format esm --external @ast-grep/napi --external @opencode-ai/plugin --external @opencode-ai/plugin/* --external @opencode-ai/sdk --external @opencode-ai/sdk/* --external @opentui/core --external @opentui/solid --external jsdom --external zod",
52
54
  "build:cli": "bun build src/cli/index.ts --outdir dist/cli --target node --format esm --external @ast-grep/napi --external @opencode-ai/plugin --external @opencode-ai/plugin/* --external @opencode-ai/sdk --external @opencode-ai/sdk/* --external jsdom --external zod",
53
- "copy:divoom-assets": "bun run scripts/copy-divoom-assets.ts",
54
- "build": "bun run clean:dist && bun run build:plugin && bun run build:cli && bun run copy:divoom-assets && tsc --emitDeclarationOnly && bun run generate-schema",
55
+ "build": "bun run clean:dist && bun run build:plugin && bun run build:cli && tsc --emitDeclarationOnly && bun run generate-schema",
55
56
  "prepare": "bun run build",
56
57
  "contributors:add": "all-contributors add",
57
58
  "contributors:check": "all-contributors check",
@@ -19,6 +19,7 @@
19
19
  - `src/skills/clonedeps/` (workflow skill for dependency source mirroring)
20
20
  - `src/skills/simplify/` (readability/refactor guidance skill)
21
21
  - `src/skills/deepwork/` (orchestrator-only workflow for heavy coding sessions)
22
+ - `src/skills/oh-my-opencode-slim/` (orchestrator-only plugin configuration and self-improvement guidance)
22
23
  - Files are considered static runtime payload. No plugin TS module in `src/` imports these files directly; they
23
24
  are loaded by OpenCode via filesystem installation.
24
25
 
@@ -40,5 +41,6 @@
40
41
  - `verify-release-artifact.ts` enforces artifact completeness by asserting key
41
42
  bundled skill payloads such as `src/skills/simplify/SKILL.md`,
42
43
  `src/skills/codemap/SKILL.md`, `src/skills/clonedeps/SKILL.md`, and
43
- `src/skills/deepwork/SKILL.md` are present in the tarball.
44
+ `src/skills/deepwork/SKILL.md`, plus `src/skills/oh-my-opencode-slim/SKILL.md`,
45
+ are present in the tarball.
44
46
  - `package.json` scripts (`verify:release`, `build`) rely on these assets to ensure install-time skill availability.
@@ -33,8 +33,30 @@ Required behavior:
33
33
  - after each phase, validate, update the deepwork file, prepare the plan file
34
34
  for oracle review and ask `@oracle` to review the phase result, fix
35
35
  actionable issues, then continue;
36
+ - when a phase includes `@designer`, preserve designer intent across later
37
+ phases. Use `@fixer` only for mechanical follow-up that does not alter the
38
+ UI/UX;
36
39
  - finish with final validation and a concise summary.
37
40
 
41
+ ## Designer Handoff Guardrail
42
+
43
+ When a deepwork phase includes `@designer`, treat the delivered UI/UX as
44
+ accepted design intent for later phases. Record any important design decisions in
45
+ the deepwork file before continuing.
46
+
47
+ After designer work:
48
+
49
+ - preserve layout, rhythm, hierarchy, motion, spacing, color, affordances,
50
+ responsiveness, and component feel;
51
+ - review and improve user-facing copy with grounded, normal wording, but do not
52
+ change visual structure or interaction intent;
53
+ - route follow-up visual, responsive, motion, hierarchy, polish, or
54
+ component-feel changes back to `@designer`;
55
+ - use `@fixer` only for bounded mechanical follow-up that preserves the design
56
+ exactly, such as wiring, tests, type fixes, or non-visual behavior changes;
57
+ - if design intent must change, record why in the deepwork file before changing
58
+ it.
59
+
38
60
  ## Deepwork File
39
61
 
40
62
  Create a task-specific file such as:
@@ -82,8 +104,8 @@ Use the scheduler model throughout:
82
104
 
83
105
  - follow Orchestrator delegations rules
84
106
  - record task/session IDs and ownership boundaries;
85
- - poll `task_status` before consuming background results;
86
- - avoid blocking Orchestrator lane too long; prefer shorter periodic task waits
87
- rather than one long wait;
107
+ - wait for hook-driven background completion before consuming background results;
108
+ - avoid blocking Orchestrator lane while background jobs run; if no independent
109
+ work remains, stop briefly and let the completion event resume the workflow;
88
110
  - do not advance to the next phase while relevant jobs are running or terminal
89
111
  results are unreconciled.