oh-my-opencode-slim 0.9.9 → 0.9.11

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.
package/README.md CHANGED
@@ -371,6 +371,8 @@ If any agent fails to respond, check your provider authentication and config fil
371
371
  | **[Tools](docs/tools.md)** | Background tasks, LSP, code search, formatters |
372
372
  | **[Configuration](docs/configuration.md)** | Config files, prompt overriding, JSONC, full option reference |
373
373
 
374
+ Slim only intercepts `apply_patch` before native execution. It rewrites recoverable stale patches, canonizes safe tolerant matches against the real file when unicode/trim drift is the only mismatch, keeps the authored `new_lines` bytes intact, preserves existing file EOL/final-newline state for updates, validates malformed patches strictly before helper execution, uses a conservative bounded LCS fallback, supports sequential `Update File` hunks on the same path through accumulated helper state, and blocks `apply_patch` before the native tool runs if any patch path falls outside the allowed root/worktree. This rescue does not extend to `edit` or `write`.
375
+
374
376
  ### 💡 Author's Setup
375
377
 
376
378
  | Doc | Contents |
package/dist/cli/index.js CHANGED
@@ -208,7 +208,8 @@ var AgentOverrideConfigSchema = z2.object({
208
208
  temperature: z2.number().min(0).max(2).optional(),
209
209
  variant: z2.string().optional().catch(undefined),
210
210
  skills: z2.array(z2.string()).optional(),
211
- mcps: z2.array(z2.string()).optional()
211
+ mcps: z2.array(z2.string()).optional(),
212
+ options: z2.record(z2.string(), z2.unknown()).optional()
212
213
  });
213
214
  var MultiplexerTypeSchema = z2.enum(["auto", "tmux", "zellij", "none"]);
214
215
  var MultiplexerLayoutSchema = z2.enum([
@@ -59,6 +59,7 @@ export declare const AgentOverrideConfigSchema: z.ZodObject<{
59
59
  variant: z.ZodCatch<z.ZodOptional<z.ZodString>>;
60
60
  skills: z.ZodOptional<z.ZodArray<z.ZodString>>;
61
61
  mcps: z.ZodOptional<z.ZodArray<z.ZodString>>;
62
+ options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
62
63
  }, z.core.$strip>;
63
64
  export declare const MultiplexerTypeSchema: z.ZodEnum<{
64
65
  auto: "auto";
@@ -127,6 +128,7 @@ export declare const PresetSchema: z.ZodRecord<z.ZodString, z.ZodObject<{
127
128
  variant: z.ZodCatch<z.ZodOptional<z.ZodString>>;
128
129
  skills: z.ZodOptional<z.ZodArray<z.ZodString>>;
129
130
  mcps: z.ZodOptional<z.ZodArray<z.ZodString>>;
131
+ options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
130
132
  }, z.core.$strip>>;
131
133
  export type Preset = z.infer<typeof PresetSchema>;
132
134
  export declare const WebsearchConfigSchema: z.ZodObject<{
@@ -231,6 +233,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
231
233
  variant: z.ZodCatch<z.ZodOptional<z.ZodString>>;
232
234
  skills: z.ZodOptional<z.ZodArray<z.ZodString>>;
233
235
  mcps: z.ZodOptional<z.ZodArray<z.ZodString>>;
236
+ options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
234
237
  }, z.core.$strip>>>>;
235
238
  agents: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
236
239
  model: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
@@ -241,6 +244,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
241
244
  variant: z.ZodCatch<z.ZodOptional<z.ZodString>>;
242
245
  skills: z.ZodOptional<z.ZodArray<z.ZodString>>;
243
246
  mcps: z.ZodOptional<z.ZodArray<z.ZodString>>;
247
+ options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
244
248
  }, z.core.$strip>>>;
245
249
  disabled_mcps: z.ZodOptional<z.ZodArray<z.ZodString>>;
246
250
  multiplexer: z.ZodOptional<z.ZodObject<{
@@ -0,0 +1,7 @@
1
+ import type { ParsedPatch } from './types';
2
+ export declare function normalizeUnicode(text: string): string;
3
+ export declare function stripHeredoc(input: string): string;
4
+ export declare function normalizePatchText(patchText: string): string;
5
+ export declare function parsePatch(patchText: string): ParsedPatch;
6
+ export declare function parsePatchStrict(patchText: string): ParsedPatch;
7
+ export declare function formatPatch(patch: ParsedPatch): string;
@@ -0,0 +1,25 @@
1
+ import type { ApplyPatchErrorCode, ApplyPatchErrorKind } from './types';
2
+ export declare class ApplyPatchError extends Error {
3
+ readonly kind: ApplyPatchErrorKind;
4
+ readonly code: ApplyPatchErrorCode;
5
+ readonly cause?: unknown;
6
+ constructor(kind: ApplyPatchErrorKind, code: ApplyPatchErrorCode, message: string, options?: {
7
+ cause?: unknown;
8
+ });
9
+ }
10
+ export declare function getErrorMessage(error: unknown): string;
11
+ export declare function createApplyPatchBlockedError(message: string, cause?: unknown): ApplyPatchError;
12
+ export declare function createApplyPatchValidationError(message: string, cause?: unknown): ApplyPatchError;
13
+ export declare function createApplyPatchVerificationError(message: string, cause?: unknown): ApplyPatchError;
14
+ export declare function createApplyPatchInternalError(message: string, cause?: unknown): ApplyPatchError;
15
+ export declare function isApplyPatchError(error: unknown): error is ApplyPatchError;
16
+ export declare function isApplyPatchBlockedError(error: unknown): boolean;
17
+ export declare function isApplyPatchValidationError(error: unknown): boolean;
18
+ export declare function isApplyPatchVerificationError(error: unknown): boolean;
19
+ export declare function isApplyPatchInternalError(error: unknown): boolean;
20
+ export declare function getApplyPatchErrorDetails(error: unknown): {
21
+ kind: ApplyPatchErrorKind;
22
+ code: ApplyPatchErrorCode;
23
+ message: string;
24
+ } | undefined;
25
+ export declare function ensureApplyPatchError(error: unknown, context: string): ApplyPatchError;
@@ -0,0 +1,30 @@
1
+ import { resolveUpdateChunksFromText } from './resolution';
2
+ import type { ApplyPatchRuntimeOptions, PatchHunk, UpdatePatchHunk } from './types';
3
+ export type PreparedFileState = {
4
+ exists: false;
5
+ derived: boolean;
6
+ } | {
7
+ exists: true;
8
+ text: string;
9
+ mode?: number;
10
+ derived: boolean;
11
+ };
12
+ export type PatchExecutionContext = {
13
+ hunks: PatchHunk[];
14
+ pathsNormalized: boolean;
15
+ staged: Map<string, PreparedFileState>;
16
+ getPreparedFileState: (filePath: string, verb: 'update' | 'delete') => Promise<PreparedFileState>;
17
+ assertPreparedPathMissing: (filePath: string, verb: 'add' | 'move') => Promise<void>;
18
+ };
19
+ export type ResolvedPreparedUpdate = {
20
+ resolved: Awaited<ReturnType<typeof resolveUpdateChunksFromText>>['resolved'];
21
+ nextText: string;
22
+ };
23
+ export declare function isMissingPathError(error: unknown): boolean;
24
+ export declare function parseValidatedPatch(root: string, patchText: string, worktree?: string): Promise<{
25
+ hunks: PatchHunk[];
26
+ pathsNormalized: boolean;
27
+ }>;
28
+ export declare function createPatchExecutionContext(root: string, patchText: string, worktree?: string): Promise<PatchExecutionContext>;
29
+ export declare function resolvePreparedUpdate(filePath: string, currentText: string, hunk: UpdatePatchHunk, cfg: ApplyPatchRuntimeOptions): ResolvedPreparedUpdate;
30
+ export declare function stageAddedText(contents: string): string;
@@ -0,0 +1,15 @@
1
+ import type { PluginInput } from '@opencode-ai/plugin';
2
+ interface ToolExecuteBeforeInput {
3
+ tool: string;
4
+ directory?: string;
5
+ }
6
+ interface ToolExecuteBeforeOutput {
7
+ args?: {
8
+ patchText?: unknown;
9
+ [key: string]: unknown;
10
+ };
11
+ }
12
+ export declare function createApplyPatchHook(ctx: PluginInput): {
13
+ 'tool.execute.before': (input: ToolExecuteBeforeInput, output: ToolExecuteBeforeOutput) => Promise<void>;
14
+ };
15
+ export {};
@@ -0,0 +1,18 @@
1
+ import type { LineComparator, RescueResult, SeekHit } from './types';
2
+ export declare function equalExact(a: string, b: string): boolean;
3
+ export declare function equalUnicodeExact(a: string, b: string): boolean;
4
+ export declare function equalTrimEnd(a: string, b: string): boolean;
5
+ export declare function equalUnicodeTrimEnd(a: string, b: string): boolean;
6
+ export declare function equalTrim(a: string, b: string): boolean;
7
+ export declare function equalUnicodeTrim(a: string, b: string): boolean;
8
+ export declare const autoRescueComparators: LineComparator[];
9
+ export declare const permissiveComparators: LineComparator[];
10
+ export declare function seekMatch(lines: string[], pattern: string[], start: number, eof?: boolean): SeekHit | undefined;
11
+ export declare function seek(lines: string[], pattern: string[], start: number, eof?: boolean): number;
12
+ export declare function list(lines: string[], pattern: string[], start: number, same: LineComparator): number[];
13
+ export declare function sameRescueLine(a: string, b: string): boolean;
14
+ export declare function prefix(old_lines: string[], new_lines: string[]): number;
15
+ export declare function suffix(old_lines: string[], new_lines: string[], prefixLength: number): number;
16
+ export declare function rescueByPrefixSuffix(lines: string[], old_lines: string[], new_lines: string[], start: number): RescueResult;
17
+ export declare function score(a: string[], b: string[]): number;
18
+ export declare function rescueByLcs(lines: string[], old_lines: string[], new_lines: string[], start: number): RescueResult;
@@ -0,0 +1,3 @@
1
+ export { parseValidatedPatch } from './execution-context';
2
+ export { applyPreparedChanges, preparePatchChanges } from './prepared-changes';
3
+ export { rewritePatch, rewritePatchText } from './rewrite';
@@ -0,0 +1,2 @@
1
+ export { parsePatch } from './codec';
2
+ export { preparePatchChanges, rewritePatch, rewritePatchText, } from './operations';
@@ -0,0 +1,17 @@
1
+ import type { ApplyPatchRuntimeOptions, PreparedChange } from './types';
2
+ export declare function preparePatchChanges(root: string, patchText: string, cfg: ApplyPatchRuntimeOptions, worktree?: string): Promise<PreparedChange[]>;
3
+ /**
4
+ * Internal best-effort helper that applies the output of
5
+ * `preparePatchChanges()`: it snapshots all touched paths first and uses
6
+ * temp + rename for writes to regular files. It is not a universal multi-file
7
+ * transaction and is not perfect against concurrent external interference,
8
+ * but it avoids leaving silent partial states on normal apply failures.
9
+ *
10
+ * Contract: although it is exported for local tests/helpers, its expected
11
+ * input is the already prepared output of `preparePatchChanges()`. If it
12
+ * receives manual arrays, it revalidates the basic shape
13
+ * (types/text/normalized absolute paths) and filesystem invariants: it
14
+ * rejects updates/deletes/moves whose source does not exist, and add/move
15
+ * operations whose destination is already occupied.
16
+ */
17
+ export declare function applyPreparedChanges(changes: PreparedChange[]): Promise<void>;
@@ -0,0 +1,19 @@
1
+ import type { ApplyPatchRuntimeOptions, MatchHit, PatchChunk, ResolvedChunk } from './types';
2
+ export declare function readFileLines(file: string): Promise<string[]>;
3
+ export declare function resolveChunkStart(lines: string[], chunk: PatchChunk, start: number): number;
4
+ export declare function locateChunk(lines: string[], file: string, chunk: PatchChunk, start: number, cfg: ApplyPatchRuntimeOptions): ResolvedChunk;
5
+ export declare function applyHits(lines: string[], hits: MatchHit[], eol?: '\n' | '\r\n', hasFinalNewline?: boolean): string;
6
+ export declare function resolveUpdateChunks(file: string, chunks: PatchChunk[], cfg: ApplyPatchRuntimeOptions): Promise<{
7
+ lines: string[];
8
+ resolved: ResolvedChunk[];
9
+ eol: '\n' | '\r\n';
10
+ hasFinalNewline: boolean;
11
+ }>;
12
+ export declare function deriveNewContentFromText(file: string, text: string, chunks: PatchChunk[], cfg: ApplyPatchRuntimeOptions): string;
13
+ export declare function resolveUpdateChunksFromText(file: string, text: string, chunks: PatchChunk[], cfg: ApplyPatchRuntimeOptions): {
14
+ lines: string[];
15
+ resolved: ResolvedChunk[];
16
+ eol: '\n' | '\r\n';
17
+ hasFinalNewline: boolean;
18
+ };
19
+ export declare function deriveNewContent(file: string, chunks: PatchChunk[], cfg: ApplyPatchRuntimeOptions): Promise<string>;
@@ -0,0 +1,10 @@
1
+ import type { ApplyPatchRuntimeOptions } from './types';
2
+ export type RewritePatchResult = {
3
+ patchText: string;
4
+ changed: boolean;
5
+ rewrittenChunks: number;
6
+ totalChunks: number;
7
+ rewriteModes: string[];
8
+ };
9
+ export declare function rewritePatch(root: string, patchText: string, cfg: ApplyPatchRuntimeOptions, worktree?: string): Promise<RewritePatchResult>;
10
+ export declare function rewritePatchText(root: string, patchText: string, cfg: ApplyPatchRuntimeOptions, worktree?: string): Promise<string>;
@@ -0,0 +1,6 @@
1
+ import type { ApplyPatchRuntimeOptions } from './types';
2
+ export declare const DEFAULT_OPTIONS: ApplyPatchRuntimeOptions;
3
+ export declare function createTempDir(prefix?: string): Promise<string>;
4
+ export declare function writeFixture(root: string, relativePath: string, contents: string): Promise<void>;
5
+ export declare function readText(root: string, relativePath: string): Promise<string>;
6
+ export declare function applyPatch(root: string, patchText: string, cfg?: ApplyPatchRuntimeOptions): Promise<void>;
@@ -0,0 +1,80 @@
1
+ export type ApplyPatchRuntimeOptions = {
2
+ prefixSuffix: boolean;
3
+ lcsRescue: boolean;
4
+ };
5
+ export type ApplyPatchErrorKind = 'blocked' | 'validation' | 'verification' | 'internal';
6
+ export type ApplyPatchErrorCode = 'malformed_patch' | 'outside_workspace' | 'verification_failed' | 'internal_unexpected';
7
+ export type ApplyPatchRescueStrategy = 'prefix/suffix' | 'lcs' | 'anchor';
8
+ export type MatchComparatorName = 'exact' | 'unicode' | 'trim-end' | 'unicode-trim-end' | 'trim' | 'unicode-trim';
9
+ export type PatchChunk = {
10
+ old_lines: string[];
11
+ new_lines: string[];
12
+ change_context?: string;
13
+ is_end_of_file?: boolean;
14
+ };
15
+ export type AddPatchHunk = {
16
+ type: 'add';
17
+ path: string;
18
+ contents: string;
19
+ };
20
+ export type DeletePatchHunk = {
21
+ type: 'delete';
22
+ path: string;
23
+ };
24
+ export type UpdatePatchHunk = {
25
+ type: 'update';
26
+ path: string;
27
+ move_path?: string;
28
+ chunks: PatchChunk[];
29
+ };
30
+ export type PatchHunk = AddPatchHunk | DeletePatchHunk | UpdatePatchHunk;
31
+ export type ParsedPatch = {
32
+ hunks: PatchHunk[];
33
+ };
34
+ export type AddPreparedChange = {
35
+ type: 'add';
36
+ file: string;
37
+ text: string;
38
+ };
39
+ export type DeletePreparedChange = {
40
+ type: 'delete';
41
+ file: string;
42
+ };
43
+ export type UpdatePreparedChange = {
44
+ type: 'update';
45
+ file: string;
46
+ move?: string;
47
+ text: string;
48
+ };
49
+ export type PreparedChange = AddPreparedChange | DeletePreparedChange | UpdatePreparedChange;
50
+ export type MatchHit = {
51
+ start: number;
52
+ del: number;
53
+ add: string[];
54
+ };
55
+ export type SeekHit = {
56
+ index: number;
57
+ comparator: MatchComparatorName;
58
+ exact: boolean;
59
+ };
60
+ export type ResolvedChunk = {
61
+ hit: MatchHit;
62
+ old_lines: string[];
63
+ canonical_old_lines: string[];
64
+ canonical_new_lines: string[];
65
+ canonical_change_context?: string;
66
+ resolved_is_end_of_file: boolean;
67
+ rewritten: boolean;
68
+ strategy?: ApplyPatchRescueStrategy;
69
+ matchComparator?: MatchComparatorName;
70
+ };
71
+ export type RescueResult = {
72
+ kind: 'miss';
73
+ } | {
74
+ kind: 'ambiguous';
75
+ phase: 'prefix_suffix' | 'lcs';
76
+ } | {
77
+ kind: 'match';
78
+ hit: MatchHit;
79
+ };
80
+ export type LineComparator = (a: string, b: string) => boolean;
@@ -1,3 +1,4 @@
1
+ export { createApplyPatchHook } from './apply-patch';
1
2
  export type { AutoUpdateCheckerOptions } from './auto-update-checker';
2
3
  export { createAutoUpdateCheckerHook } from './auto-update-checker';
3
4
  export { createChatHeadersHook } from './chat-headers';
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Post-tool nudge - appends a delegation reminder after file reads/writes.
2
+ * Post-tool nudge - queues a delegation reminder after file reads/writes.
3
3
  * Catches the "inspect/edit files → implement myself" anti-pattern.
4
4
  */
5
5
  interface ToolExecuteAfterInput {
@@ -7,12 +7,29 @@ interface ToolExecuteAfterInput {
7
7
  sessionID?: string;
8
8
  callID?: string;
9
9
  }
10
- interface ToolExecuteAfterOutput {
11
- title: string;
12
- output: string;
13
- metadata: Record<string, unknown>;
10
+ interface ChatSystemTransformInput {
11
+ sessionID?: string;
12
+ }
13
+ interface ChatSystemTransformOutput {
14
+ system: string[];
15
+ }
16
+ interface EventInput {
17
+ event: {
18
+ type: string;
19
+ properties?: {
20
+ info?: {
21
+ id?: string;
22
+ };
23
+ sessionID?: string;
24
+ };
25
+ };
26
+ }
27
+ interface PostFileToolNudgeOptions {
28
+ shouldInject?: (sessionID: string) => boolean;
14
29
  }
15
- export declare function createPostFileToolNudgeHook(): {
16
- 'tool.execute.after': (input: ToolExecuteAfterInput, output: ToolExecuteAfterOutput) => Promise<void>;
30
+ export declare function createPostFileToolNudgeHook(options?: PostFileToolNudgeOptions): {
31
+ 'tool.execute.after': (input: ToolExecuteAfterInput, _output: unknown) => Promise<void>;
32
+ 'experimental.chat.system.transform': (input: ChatSystemTransformInput, output: ChatSystemTransformOutput) => Promise<void>;
33
+ event: (input: EventInput) => Promise<void>;
17
34
  };
18
35
  export {};
@@ -12,6 +12,10 @@ export declare function createTodoContinuationHook(ctx: PluginInput, config?: {
12
12
  properties?: Record<string, unknown>;
13
13
  };
14
14
  }) => Promise<void>;
15
+ handleChatMessage: (input: {
16
+ sessionID: string;
17
+ agent?: string;
18
+ }) => void;
15
19
  handleCommandExecuteBefore: (input: {
16
20
  command: string;
17
21
  sessionID: string;