oh-my-opencode-slim 0.9.10 → 0.9.12
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 +2 -1
- package/dist/cli/index.js +96 -24
- package/dist/config/schema.d.ts +4 -0
- package/dist/hooks/apply-patch/execution-context.d.ts +1 -0
- package/dist/hooks/auto-update-checker/cache.d.ts +9 -4
- package/dist/hooks/auto-update-checker/checker.d.ts +4 -0
- package/dist/hooks/todo-continuation/index.d.ts +9 -0
- package/dist/hooks/todo-continuation/todo-hygiene.d.ts +37 -0
- package/dist/index.js +379 -129
- package/dist/tools/lsp/client.d.ts +1 -0
- package/oh-my-opencode-slim.schema.json +14 -0
- package/package.json +12 -12
- package/src/skills/cartography/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -388,7 +388,7 @@ Slim only intercepts `apply_patch` before native execution. It rewrites recovera
|
|
|
388
388
|
<p><sub>Every merged contribution leaves a mark on the realm.</sub></p>
|
|
389
389
|
|
|
390
390
|
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
|
391
|
-
[](#contributors-)
|
|
392
392
|
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
|
393
393
|
</div>
|
|
394
394
|
|
|
@@ -445,6 +445,7 @@ Slim only intercepts `apply_patch` before native execution. It rewrites recovera
|
|
|
445
445
|
<td align="center" valign="top" width="16.66%"><a href="https://nettee.io/"><img src="https://avatars.githubusercontent.com/u/3953668?v=4?s=100" width="100px;" alt="nettee"/><br /><sub><b>nettee</b></sub></a><br /><a href="https://github.com/alvinunreal/oh-my-opencode-slim/commits?author=nettee" title="Code">💻</a></td>
|
|
446
446
|
<td align="center" valign="top" width="16.66%"><a href="https://github.com/atomlink-ye"><img src="https://avatars.githubusercontent.com/u/48194045?v=4?s=100" width="100px;" alt="Link"/><br /><sub><b>Link</b></sub></a><br /><a href="https://github.com/alvinunreal/oh-my-opencode-slim/commits?author=atomlink-ye" title="Code">💻</a></td>
|
|
447
447
|
<td align="center" valign="top" width="16.66%"><a href="https://github.com/blaszewski"><img src="https://avatars.githubusercontent.com/u/14119531?v=4?s=100" width="100px;" alt="Bartosz Łaszewski"/><br /><sub><b>Bartosz Łaszewski</b></sub></a><br /><a href="https://github.com/alvinunreal/oh-my-opencode-slim/commits?author=blaszewski" title="Code">💻</a></td>
|
|
448
|
+
<td align="center" valign="top" width="16.66%"><a href="https://github.com/huilang021x"><img src="https://avatars.githubusercontent.com/u/77293911?v=4?s=100" width="100px;" alt="huilang021x"/><br /><sub><b>huilang021x</b></sub></a><br /><a href="https://github.com/alvinunreal/oh-my-opencode-slim/commits?author=huilang021x" title="Code">💻</a></td>
|
|
448
449
|
</tr>
|
|
449
450
|
</tbody>
|
|
450
451
|
</table>
|
package/dist/cli/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
statSync as statSync2,
|
|
14
14
|
writeFileSync
|
|
15
15
|
} from "fs";
|
|
16
|
-
import {
|
|
16
|
+
import { dirname as dirname3, join as join3 } from "path";
|
|
17
17
|
|
|
18
18
|
// src/cli/paths.ts
|
|
19
19
|
import { existsSync, mkdirSync } from "fs";
|
|
@@ -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([
|
|
@@ -480,8 +481,49 @@ function generateLiteConfig(installConfig) {
|
|
|
480
481
|
|
|
481
482
|
// src/cli/config-io.ts
|
|
482
483
|
var PACKAGE_NAME = "oh-my-opencode-slim";
|
|
484
|
+
function normalizePathForMatch(path) {
|
|
485
|
+
return path.replaceAll("\\", "/");
|
|
486
|
+
}
|
|
487
|
+
function findPackageRoot(startPath) {
|
|
488
|
+
let currentPath = dirname3(startPath);
|
|
489
|
+
while (true) {
|
|
490
|
+
const packageJsonPath = join3(currentPath, "package.json");
|
|
491
|
+
if (existsSync3(packageJsonPath)) {
|
|
492
|
+
try {
|
|
493
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
494
|
+
if (packageJson.name === PACKAGE_NAME) {
|
|
495
|
+
return currentPath;
|
|
496
|
+
}
|
|
497
|
+
} catch {}
|
|
498
|
+
}
|
|
499
|
+
const parentPath = dirname3(currentPath);
|
|
500
|
+
if (parentPath === currentPath) {
|
|
501
|
+
return null;
|
|
502
|
+
}
|
|
503
|
+
currentPath = parentPath;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
function isPackageManagerInstall(path) {
|
|
507
|
+
const normalizedPath = normalizePathForMatch(path);
|
|
508
|
+
return normalizedPath.includes(`/node_modules/${PACKAGE_NAME}`);
|
|
509
|
+
}
|
|
510
|
+
function isLocalPackageRootEntry(entry) {
|
|
511
|
+
if (!entry || entry.startsWith("file://")) {
|
|
512
|
+
return false;
|
|
513
|
+
}
|
|
514
|
+
const packageJsonPath = join3(entry, "package.json");
|
|
515
|
+
if (!existsSync3(packageJsonPath)) {
|
|
516
|
+
return false;
|
|
517
|
+
}
|
|
518
|
+
try {
|
|
519
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
520
|
+
return packageJson.name === PACKAGE_NAME;
|
|
521
|
+
} catch {
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
483
525
|
function isPluginEntry(entry) {
|
|
484
|
-
return entry === PACKAGE_NAME || entry.startsWith(`${PACKAGE_NAME}@`) || entry.startsWith("file://") && entry.includes(PACKAGE_NAME);
|
|
526
|
+
return entry === PACKAGE_NAME || entry.startsWith(`${PACKAGE_NAME}@`) || entry.startsWith("file://") && entry.includes(PACKAGE_NAME) || isLocalPackageRootEntry(entry);
|
|
485
527
|
}
|
|
486
528
|
function getPluginEntry() {
|
|
487
529
|
const cliEntryPath = process.argv[1];
|
|
@@ -489,11 +531,11 @@ function getPluginEntry() {
|
|
|
489
531
|
return PACKAGE_NAME;
|
|
490
532
|
}
|
|
491
533
|
try {
|
|
492
|
-
const
|
|
493
|
-
if (!
|
|
534
|
+
const packageRoot = findPackageRoot(cliEntryPath);
|
|
535
|
+
if (!packageRoot || isPackageManagerInstall(packageRoot)) {
|
|
494
536
|
return PACKAGE_NAME;
|
|
495
537
|
}
|
|
496
|
-
return
|
|
538
|
+
return packageRoot;
|
|
497
539
|
} catch {
|
|
498
540
|
return PACKAGE_NAME;
|
|
499
541
|
}
|
|
@@ -683,8 +725,35 @@ function detectCurrentConfig() {
|
|
|
683
725
|
return result;
|
|
684
726
|
}
|
|
685
727
|
// src/cli/system.ts
|
|
728
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
686
729
|
import { statSync as statSync3 } from "fs";
|
|
687
730
|
var cachedOpenCodePath = null;
|
|
731
|
+
function resolvePathCommand(command) {
|
|
732
|
+
try {
|
|
733
|
+
const resolver = process.platform === "win32" ? "where" : "which";
|
|
734
|
+
const result = spawnSync2(resolver, [command], {
|
|
735
|
+
encoding: "utf-8",
|
|
736
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
737
|
+
});
|
|
738
|
+
if (result.status !== 0) {
|
|
739
|
+
return null;
|
|
740
|
+
}
|
|
741
|
+
const resolved = result.stdout.split(/\r?\n/).map((line) => line.trim()).find(Boolean);
|
|
742
|
+
return resolved ?? null;
|
|
743
|
+
} catch {
|
|
744
|
+
return null;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
function canExecute(command, args) {
|
|
748
|
+
try {
|
|
749
|
+
const result = spawnSync2(command, args, {
|
|
750
|
+
stdio: "ignore"
|
|
751
|
+
});
|
|
752
|
+
return result.status === 0;
|
|
753
|
+
} catch {
|
|
754
|
+
return false;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
688
757
|
function getOpenCodePaths() {
|
|
689
758
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
690
759
|
return [
|
|
@@ -720,6 +789,11 @@ function resolveOpenCodePath() {
|
|
|
720
789
|
if (cachedOpenCodePath) {
|
|
721
790
|
return cachedOpenCodePath;
|
|
722
791
|
}
|
|
792
|
+
const pathOpenCodePath = resolvePathCommand("opencode");
|
|
793
|
+
if (pathOpenCodePath) {
|
|
794
|
+
cachedOpenCodePath = pathOpenCodePath;
|
|
795
|
+
return pathOpenCodePath;
|
|
796
|
+
}
|
|
723
797
|
const paths = getOpenCodePaths();
|
|
724
798
|
for (const opencodePath of paths) {
|
|
725
799
|
if (opencodePath === "opencode")
|
|
@@ -735,33 +809,31 @@ function resolveOpenCodePath() {
|
|
|
735
809
|
return "opencode";
|
|
736
810
|
}
|
|
737
811
|
async function isOpenCodeInstalled() {
|
|
812
|
+
const pathOpenCodePath = resolvePathCommand("opencode");
|
|
813
|
+
if (pathOpenCodePath && canExecute(pathOpenCodePath, ["--version"])) {
|
|
814
|
+
cachedOpenCodePath = pathOpenCodePath;
|
|
815
|
+
return true;
|
|
816
|
+
}
|
|
738
817
|
const paths = getOpenCodePaths();
|
|
739
818
|
for (const opencodePath of paths) {
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
if (proc.exitCode === 0) {
|
|
747
|
-
cachedOpenCodePath = opencodePath;
|
|
748
|
-
return true;
|
|
749
|
-
}
|
|
750
|
-
} catch {}
|
|
819
|
+
if (opencodePath === "opencode")
|
|
820
|
+
continue;
|
|
821
|
+
if (canExecute(opencodePath, ["--version"])) {
|
|
822
|
+
cachedOpenCodePath = opencodePath;
|
|
823
|
+
return true;
|
|
824
|
+
}
|
|
751
825
|
}
|
|
752
826
|
return false;
|
|
753
827
|
}
|
|
754
828
|
async function getOpenCodeVersion() {
|
|
755
829
|
const opencodePath = resolveOpenCodePath();
|
|
756
830
|
try {
|
|
757
|
-
const
|
|
758
|
-
|
|
759
|
-
|
|
831
|
+
const result = spawnSync2(opencodePath, ["--version"], {
|
|
832
|
+
encoding: "utf-8",
|
|
833
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
760
834
|
});
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
if (proc.exitCode === 0) {
|
|
764
|
-
return output.trim();
|
|
835
|
+
if (result.status === 0) {
|
|
836
|
+
return result.stdout.trim();
|
|
765
837
|
}
|
|
766
838
|
} catch {}
|
|
767
839
|
return null;
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -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<{
|
|
@@ -11,6 +11,7 @@ export type PreparedFileState = {
|
|
|
11
11
|
};
|
|
12
12
|
export type PatchExecutionContext = {
|
|
13
13
|
hunks: PatchHunk[];
|
|
14
|
+
pathsNormalized: boolean;
|
|
14
15
|
staged: Map<string, PreparedFileState>;
|
|
15
16
|
getPreparedFileState: (filePath: string, verb: 'update' | 'delete') => Promise<PreparedFileState>;
|
|
16
17
|
assertPreparedPathMissing: (filePath: string, verb: 'add' | 'move') => Promise<void>;
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
interface AutoUpdateInstallContext {
|
|
2
|
+
installDir: string;
|
|
3
|
+
packageJsonPath: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function resolveInstallContext(runtimePackageJsonPath?: string | null): AutoUpdateInstallContext | null;
|
|
1
6
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* @param packageName The name of the package to invalidate.
|
|
7
|
+
* Prepares the current install root for a clean re-install of the target version.
|
|
8
|
+
* Returns the install directory to run `bun install` in.
|
|
5
9
|
*/
|
|
6
|
-
export declare function
|
|
10
|
+
export declare function preparePackageUpdate(version: string, packageName?: string, runtimePackageJsonPath?: string | null): string | null;
|
|
11
|
+
export {};
|
|
@@ -9,6 +9,10 @@ export declare function extractChannel(version: string | null): string;
|
|
|
9
9
|
* Resolves the version of the plugin when running in local development mode.
|
|
10
10
|
*/
|
|
11
11
|
export declare function getLocalDevVersion(directory: string): string | null;
|
|
12
|
+
/**
|
|
13
|
+
* Resolves the package.json for the currently running plugin bundle.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getCurrentRuntimePackageJsonPath(currentModuleUrl?: string): string | null;
|
|
12
16
|
/**
|
|
13
17
|
* Searches across all config locations to find the current installation entry for this plugin.
|
|
14
18
|
*/
|
|
@@ -6,6 +6,15 @@ export declare function createTodoContinuationHook(ctx: PluginInput, config?: {
|
|
|
6
6
|
autoEnableThreshold?: number;
|
|
7
7
|
}): {
|
|
8
8
|
tool: Record<string, unknown>;
|
|
9
|
+
handleToolExecuteAfter: (input: {
|
|
10
|
+
tool: string;
|
|
11
|
+
sessionID?: string;
|
|
12
|
+
}) => Promise<void>;
|
|
13
|
+
handleChatSystemTransform: (input: {
|
|
14
|
+
sessionID?: string;
|
|
15
|
+
}, output: {
|
|
16
|
+
system: string[];
|
|
17
|
+
}) => Promise<void>;
|
|
9
18
|
handleEvent: (input: {
|
|
10
19
|
event: {
|
|
11
20
|
type: string;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export declare const TODO_HYGIENE_REMINDER = "If the active task changed or finished, update the todo list to match the current work state.";
|
|
2
|
+
export declare const TODO_FINAL_ACTIVE_REMINDER = "If you are finishing now, do not leave the active todo in_progress. Mark it completed, or move unfinished work back to pending.";
|
|
3
|
+
interface ToolInput {
|
|
4
|
+
tool: string;
|
|
5
|
+
sessionID?: string;
|
|
6
|
+
}
|
|
7
|
+
interface SystemInput {
|
|
8
|
+
sessionID?: string;
|
|
9
|
+
}
|
|
10
|
+
interface SystemOutput {
|
|
11
|
+
system: string[];
|
|
12
|
+
}
|
|
13
|
+
interface EventInput {
|
|
14
|
+
type: string;
|
|
15
|
+
properties?: {
|
|
16
|
+
info?: {
|
|
17
|
+
id?: string;
|
|
18
|
+
};
|
|
19
|
+
sessionID?: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
interface Options {
|
|
23
|
+
getTodoState: (sessionID: string) => Promise<{
|
|
24
|
+
hasOpenTodos: boolean;
|
|
25
|
+
openCount: number;
|
|
26
|
+
inProgressCount: number;
|
|
27
|
+
pendingCount: number;
|
|
28
|
+
}>;
|
|
29
|
+
shouldInject?: (sessionID: string) => boolean;
|
|
30
|
+
log?: (message: string, meta?: Record<string, unknown>) => void;
|
|
31
|
+
}
|
|
32
|
+
export declare function createTodoHygiene(options: Options): {
|
|
33
|
+
handleToolExecuteAfter(input: ToolInput): Promise<void>;
|
|
34
|
+
handleChatSystemTransform(input: SystemInput, output: SystemOutput): Promise<void>;
|
|
35
|
+
handleEvent(event: EventInput): void;
|
|
36
|
+
};
|
|
37
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -502,7 +502,8 @@ var AgentOverrideConfigSchema = z2.object({
|
|
|
502
502
|
temperature: z2.number().min(0).max(2).optional(),
|
|
503
503
|
variant: z2.string().optional().catch(undefined),
|
|
504
504
|
skills: z2.array(z2.string()).optional(),
|
|
505
|
-
mcps: z2.array(z2.string()).optional()
|
|
505
|
+
mcps: z2.array(z2.string()).optional(),
|
|
506
|
+
options: z2.record(z2.string(), z2.unknown()).optional()
|
|
506
507
|
});
|
|
507
508
|
var MultiplexerTypeSchema = z2.enum(["auto", "tmux", "zellij", "none"]);
|
|
508
509
|
var MultiplexerLayoutSchema = z2.enum([
|
|
@@ -1247,6 +1248,12 @@ function applyOverrides(agent, override) {
|
|
|
1247
1248
|
agent.config.variant = override.variant;
|
|
1248
1249
|
if (override.temperature !== undefined)
|
|
1249
1250
|
agent.config.temperature = override.temperature;
|
|
1251
|
+
if (override.options) {
|
|
1252
|
+
agent.config.options = {
|
|
1253
|
+
...agent.config.options,
|
|
1254
|
+
...override.options
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1250
1257
|
}
|
|
1251
1258
|
function applyDefaultPermissions(agent, configuredSkills) {
|
|
1252
1259
|
const existing = agent.config.permission ?? {};
|
|
@@ -3899,15 +3906,36 @@ function collectPatchTargets(root, hunks) {
|
|
|
3899
3906
|
}
|
|
3900
3907
|
return [...targets];
|
|
3901
3908
|
}
|
|
3902
|
-
function
|
|
3909
|
+
function toRelativePatchPath(root, target) {
|
|
3910
|
+
const relative = path3.relative(root, target);
|
|
3911
|
+
return (relative.length === 0 ? "." : relative).replaceAll("\\", "/");
|
|
3912
|
+
}
|
|
3913
|
+
function normalizePatchPath(root, value) {
|
|
3914
|
+
return path3.isAbsolute(value) ? toRelativePatchPath(root, path3.resolve(value)) : value;
|
|
3915
|
+
}
|
|
3916
|
+
function normalizePatchPaths(root, hunks) {
|
|
3917
|
+
const resolvedRoot = path3.resolve(root);
|
|
3918
|
+
const normalized = [];
|
|
3919
|
+
let changed = false;
|
|
3903
3920
|
for (const hunk of hunks) {
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3921
|
+
const normalizedPath = normalizePatchPath(resolvedRoot, hunk.path);
|
|
3922
|
+
if (hunk.type !== "update") {
|
|
3923
|
+
changed ||= normalizedPath !== hunk.path;
|
|
3924
|
+
normalized.push(normalizedPath === hunk.path ? hunk : {
|
|
3925
|
+
...hunk,
|
|
3926
|
+
path: normalizedPath
|
|
3927
|
+
});
|
|
3928
|
+
continue;
|
|
3909
3929
|
}
|
|
3930
|
+
const normalizedMovePath = hunk.move_path ? normalizePatchPath(resolvedRoot, hunk.move_path) : undefined;
|
|
3931
|
+
changed ||= normalizedPath !== hunk.path || normalizedMovePath !== hunk.move_path;
|
|
3932
|
+
normalized.push(normalizedPath === hunk.path && normalizedMovePath === hunk.move_path ? hunk : {
|
|
3933
|
+
...hunk,
|
|
3934
|
+
path: normalizedPath,
|
|
3935
|
+
move_path: normalizedMovePath
|
|
3936
|
+
});
|
|
3910
3937
|
}
|
|
3938
|
+
return { hunks: normalized, changed };
|
|
3911
3939
|
}
|
|
3912
3940
|
async function guardPatchTargets(root, worktree, targets) {
|
|
3913
3941
|
const guardContext = createPathGuardContext(root, worktree);
|
|
@@ -3933,7 +3961,6 @@ function parseValidatedPatch(patchText) {
|
|
|
3933
3961
|
}
|
|
3934
3962
|
throw createApplyPatchValidationError("no hunks found");
|
|
3935
3963
|
}
|
|
3936
|
-
validatePatchPaths(hunks);
|
|
3937
3964
|
return hunks;
|
|
3938
3965
|
}
|
|
3939
3966
|
async function readPreparedFileText(filePath, verb) {
|
|
@@ -3947,8 +3974,9 @@ async function readPreparedFileText(filePath, verb) {
|
|
|
3947
3974
|
}
|
|
3948
3975
|
}
|
|
3949
3976
|
async function createPatchExecutionContext(root, patchText, worktree) {
|
|
3950
|
-
const
|
|
3951
|
-
await guardPatchTargets(root, worktree, collectPatchTargets(root,
|
|
3977
|
+
const parsedHunks = parseValidatedPatch(patchText);
|
|
3978
|
+
await guardPatchTargets(root, worktree, collectPatchTargets(root, parsedHunks));
|
|
3979
|
+
const normalized = normalizePatchPaths(root, parsedHunks);
|
|
3952
3980
|
const files = createFileCacheContext();
|
|
3953
3981
|
const staged = new Map;
|
|
3954
3982
|
async function assertPreparedPathMissing(filePath, verb) {
|
|
@@ -3986,7 +4014,8 @@ async function createPatchExecutionContext(root, patchText, worktree) {
|
|
|
3986
4014
|
return state;
|
|
3987
4015
|
}
|
|
3988
4016
|
return {
|
|
3989
|
-
hunks,
|
|
4017
|
+
hunks: normalized.hunks,
|
|
4018
|
+
pathsNormalized: normalized.changed,
|
|
3990
4019
|
staged,
|
|
3991
4020
|
getPreparedFileState,
|
|
3992
4021
|
assertPreparedPathMissing
|
|
@@ -4162,13 +4191,22 @@ async function rewritePatch(root, patchText, cfg, worktree) {
|
|
|
4162
4191
|
let clearDependencyGroup = function(filePath) {
|
|
4163
4192
|
dependencyGroups.delete(filePath);
|
|
4164
4193
|
};
|
|
4165
|
-
const {
|
|
4194
|
+
const {
|
|
4195
|
+
hunks,
|
|
4196
|
+
pathsNormalized,
|
|
4197
|
+
staged,
|
|
4198
|
+
getPreparedFileState,
|
|
4199
|
+
assertPreparedPathMissing
|
|
4200
|
+
} = await createPatchExecutionContext(root, patchText, worktree);
|
|
4166
4201
|
const normalizedPatchText = normalizePatchText(patchText);
|
|
4167
4202
|
const rewritten = [];
|
|
4168
4203
|
let changed = false;
|
|
4169
4204
|
let rewrittenChunks = 0;
|
|
4170
4205
|
const rewriteModes = new Set;
|
|
4171
4206
|
const totalChunks = hunks.reduce((count, hunk) => count + (hunk.type === "update" ? hunk.chunks.length : 0), 0);
|
|
4207
|
+
if (pathsNormalized) {
|
|
4208
|
+
rewriteModes.add("normalize:patch-paths");
|
|
4209
|
+
}
|
|
4172
4210
|
const dependencyGroups = new Map;
|
|
4173
4211
|
for (const hunk of hunks) {
|
|
4174
4212
|
if (hunk.type === "add") {
|
|
@@ -4282,6 +4320,15 @@ async function rewritePatch(root, patchText, cfg, worktree) {
|
|
|
4282
4320
|
}
|
|
4283
4321
|
}
|
|
4284
4322
|
if (!changed) {
|
|
4323
|
+
if (pathsNormalized) {
|
|
4324
|
+
return {
|
|
4325
|
+
patchText: formatPatch({ hunks }),
|
|
4326
|
+
changed: true,
|
|
4327
|
+
rewrittenChunks: 0,
|
|
4328
|
+
totalChunks,
|
|
4329
|
+
rewriteModes: [...rewriteModes].sort()
|
|
4330
|
+
};
|
|
4331
|
+
}
|
|
4285
4332
|
if (normalizedPatchText !== patchText) {
|
|
4286
4333
|
return {
|
|
4287
4334
|
patchText: normalizedPatchText,
|
|
@@ -4362,8 +4409,13 @@ function createApplyPatchHook(ctx) {
|
|
|
4362
4409
|
};
|
|
4363
4410
|
}
|
|
4364
4411
|
// src/hooks/auto-update-checker/cache.ts
|
|
4412
|
+
import * as fs5 from "fs";
|
|
4413
|
+
import * as path7 from "path";
|
|
4414
|
+
// src/hooks/auto-update-checker/checker.ts
|
|
4365
4415
|
import * as fs4 from "fs";
|
|
4366
4416
|
import * as path6 from "path";
|
|
4417
|
+
import { fileURLToPath } from "url";
|
|
4418
|
+
|
|
4367
4419
|
// src/hooks/auto-update-checker/constants.ts
|
|
4368
4420
|
import * as os2 from "os";
|
|
4369
4421
|
import * as path5 from "path";
|
|
@@ -4382,80 +4434,7 @@ var configPaths = getOpenCodeConfigPaths();
|
|
|
4382
4434
|
var USER_OPENCODE_CONFIG = configPaths[0];
|
|
4383
4435
|
var USER_OPENCODE_CONFIG_JSONC = configPaths[1];
|
|
4384
4436
|
|
|
4385
|
-
// src/hooks/auto-update-checker/cache.ts
|
|
4386
|
-
function removeFromBunLock(packageName) {
|
|
4387
|
-
const lockPath = path6.join(CACHE_DIR, "bun.lock");
|
|
4388
|
-
if (!fs4.existsSync(lockPath))
|
|
4389
|
-
return false;
|
|
4390
|
-
try {
|
|
4391
|
-
const content = fs4.readFileSync(lockPath, "utf-8");
|
|
4392
|
-
let lock;
|
|
4393
|
-
try {
|
|
4394
|
-
lock = JSON.parse(stripJsonComments(content));
|
|
4395
|
-
} catch {
|
|
4396
|
-
return false;
|
|
4397
|
-
}
|
|
4398
|
-
let modified = false;
|
|
4399
|
-
if (lock.workspaces?.[""]?.dependencies?.[packageName]) {
|
|
4400
|
-
delete lock.workspaces[""].dependencies[packageName];
|
|
4401
|
-
modified = true;
|
|
4402
|
-
}
|
|
4403
|
-
if (lock.packages?.[packageName]) {
|
|
4404
|
-
delete lock.packages[packageName];
|
|
4405
|
-
modified = true;
|
|
4406
|
-
}
|
|
4407
|
-
if (modified) {
|
|
4408
|
-
fs4.writeFileSync(lockPath, JSON.stringify(lock, null, 2));
|
|
4409
|
-
log(`[auto-update-checker] Removed from bun.lock: ${packageName}`);
|
|
4410
|
-
}
|
|
4411
|
-
return modified;
|
|
4412
|
-
} catch (err) {
|
|
4413
|
-
log(`[auto-update-checker] Failed to process bun.lock:`, err);
|
|
4414
|
-
return false;
|
|
4415
|
-
}
|
|
4416
|
-
}
|
|
4417
|
-
function invalidatePackage(packageName = PACKAGE_NAME) {
|
|
4418
|
-
try {
|
|
4419
|
-
const pkgDir = path6.join(CACHE_DIR, "node_modules", packageName);
|
|
4420
|
-
const pkgJsonPath = path6.join(CACHE_DIR, "package.json");
|
|
4421
|
-
let packageRemoved = false;
|
|
4422
|
-
let dependencyRemoved = false;
|
|
4423
|
-
let lockRemoved = false;
|
|
4424
|
-
if (fs4.existsSync(pkgDir)) {
|
|
4425
|
-
fs4.rmSync(pkgDir, { recursive: true, force: true });
|
|
4426
|
-
log(`[auto-update-checker] Package removed: ${pkgDir}`);
|
|
4427
|
-
packageRemoved = true;
|
|
4428
|
-
}
|
|
4429
|
-
if (fs4.existsSync(pkgJsonPath)) {
|
|
4430
|
-
try {
|
|
4431
|
-
const content = fs4.readFileSync(pkgJsonPath, "utf-8");
|
|
4432
|
-
const pkgJson = JSON.parse(stripJsonComments(content));
|
|
4433
|
-
if (pkgJson.dependencies?.[packageName]) {
|
|
4434
|
-
delete pkgJson.dependencies[packageName];
|
|
4435
|
-
fs4.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
|
|
4436
|
-
log(`[auto-update-checker] Dependency removed from package.json: ${packageName}`);
|
|
4437
|
-
dependencyRemoved = true;
|
|
4438
|
-
}
|
|
4439
|
-
} catch (err) {
|
|
4440
|
-
log(`[auto-update-checker] Failed to update package.json for invalidation:`, err);
|
|
4441
|
-
}
|
|
4442
|
-
}
|
|
4443
|
-
lockRemoved = removeFromBunLock(packageName);
|
|
4444
|
-
if (!packageRemoved && !dependencyRemoved && !lockRemoved) {
|
|
4445
|
-
log(`[auto-update-checker] Package not found, nothing to invalidate: ${packageName}`);
|
|
4446
|
-
return false;
|
|
4447
|
-
}
|
|
4448
|
-
return true;
|
|
4449
|
-
} catch (err) {
|
|
4450
|
-
log("[auto-update-checker] Failed to invalidate package:", err);
|
|
4451
|
-
return false;
|
|
4452
|
-
}
|
|
4453
|
-
}
|
|
4454
|
-
|
|
4455
4437
|
// src/hooks/auto-update-checker/checker.ts
|
|
4456
|
-
import * as fs5 from "fs";
|
|
4457
|
-
import * as path7 from "path";
|
|
4458
|
-
import { fileURLToPath } from "url";
|
|
4459
4438
|
function isPrereleaseVersion(version) {
|
|
4460
4439
|
return version.includes("-");
|
|
4461
4440
|
}
|
|
@@ -4479,8 +4458,8 @@ function extractChannel(version) {
|
|
|
4479
4458
|
}
|
|
4480
4459
|
function getConfigPaths(directory) {
|
|
4481
4460
|
return [
|
|
4482
|
-
|
|
4483
|
-
|
|
4461
|
+
path6.join(directory, ".opencode", "opencode.json"),
|
|
4462
|
+
path6.join(directory, ".opencode", "opencode.jsonc"),
|
|
4484
4463
|
USER_OPENCODE_CONFIG,
|
|
4485
4464
|
USER_OPENCODE_CONFIG_JSONC
|
|
4486
4465
|
];
|
|
@@ -4488,9 +4467,9 @@ function getConfigPaths(directory) {
|
|
|
4488
4467
|
function getLocalDevPath(directory) {
|
|
4489
4468
|
for (const configPath of getConfigPaths(directory)) {
|
|
4490
4469
|
try {
|
|
4491
|
-
if (!
|
|
4470
|
+
if (!fs4.existsSync(configPath))
|
|
4492
4471
|
continue;
|
|
4493
|
-
const content =
|
|
4472
|
+
const content = fs4.readFileSync(configPath, "utf-8");
|
|
4494
4473
|
const config = JSON.parse(stripJsonComments(content));
|
|
4495
4474
|
const plugins = config.plugin ?? [];
|
|
4496
4475
|
for (const entry of plugins) {
|
|
@@ -4508,19 +4487,19 @@ function getLocalDevPath(directory) {
|
|
|
4508
4487
|
}
|
|
4509
4488
|
function findPackageJsonUp(startPath) {
|
|
4510
4489
|
try {
|
|
4511
|
-
const stat2 =
|
|
4512
|
-
let dir = stat2.isDirectory() ? startPath :
|
|
4490
|
+
const stat2 = fs4.statSync(startPath);
|
|
4491
|
+
let dir = stat2.isDirectory() ? startPath : path6.dirname(startPath);
|
|
4513
4492
|
for (let i = 0;i < 10; i++) {
|
|
4514
|
-
const pkgPath =
|
|
4515
|
-
if (
|
|
4493
|
+
const pkgPath = path6.join(dir, "package.json");
|
|
4494
|
+
if (fs4.existsSync(pkgPath)) {
|
|
4516
4495
|
try {
|
|
4517
|
-
const content =
|
|
4496
|
+
const content = fs4.readFileSync(pkgPath, "utf-8");
|
|
4518
4497
|
const pkg = JSON.parse(content);
|
|
4519
4498
|
if (pkg.name === PACKAGE_NAME)
|
|
4520
4499
|
return pkgPath;
|
|
4521
4500
|
} catch {}
|
|
4522
4501
|
}
|
|
4523
|
-
const parent =
|
|
4502
|
+
const parent = path6.dirname(dir);
|
|
4524
4503
|
if (parent === dir)
|
|
4525
4504
|
break;
|
|
4526
4505
|
dir = parent;
|
|
@@ -4536,19 +4515,28 @@ function getLocalDevVersion(directory) {
|
|
|
4536
4515
|
const pkgPath = findPackageJsonUp(localPath);
|
|
4537
4516
|
if (!pkgPath)
|
|
4538
4517
|
return null;
|
|
4539
|
-
const content =
|
|
4518
|
+
const content = fs4.readFileSync(pkgPath, "utf-8");
|
|
4540
4519
|
const pkg = JSON.parse(content);
|
|
4541
4520
|
return pkg.version ?? null;
|
|
4542
4521
|
} catch {
|
|
4543
4522
|
return null;
|
|
4544
4523
|
}
|
|
4545
4524
|
}
|
|
4525
|
+
function getCurrentRuntimePackageJsonPath(currentModuleUrl = import.meta.url) {
|
|
4526
|
+
try {
|
|
4527
|
+
const currentDir = path6.dirname(fileURLToPath(currentModuleUrl));
|
|
4528
|
+
return findPackageJsonUp(currentDir);
|
|
4529
|
+
} catch (err) {
|
|
4530
|
+
log("[auto-update-checker] Failed to resolve runtime package path:", err);
|
|
4531
|
+
return null;
|
|
4532
|
+
}
|
|
4533
|
+
}
|
|
4546
4534
|
function findPluginEntry(directory) {
|
|
4547
4535
|
for (const configPath of getConfigPaths(directory)) {
|
|
4548
4536
|
try {
|
|
4549
|
-
if (!
|
|
4537
|
+
if (!fs4.existsSync(configPath))
|
|
4550
4538
|
continue;
|
|
4551
|
-
const content =
|
|
4539
|
+
const content = fs4.readFileSync(configPath, "utf-8");
|
|
4552
4540
|
const config = JSON.parse(stripJsonComments(content));
|
|
4553
4541
|
const plugins = config.plugin ?? [];
|
|
4554
4542
|
for (const entry of plugins) {
|
|
@@ -4575,8 +4563,9 @@ function getCachedVersion() {
|
|
|
4575
4563
|
if (cachedPackageVersion)
|
|
4576
4564
|
return cachedPackageVersion;
|
|
4577
4565
|
try {
|
|
4578
|
-
|
|
4579
|
-
|
|
4566
|
+
const runtimePackageJsonPath = getCurrentRuntimePackageJsonPath();
|
|
4567
|
+
if (runtimePackageJsonPath && fs4.existsSync(runtimePackageJsonPath)) {
|
|
4568
|
+
const content = fs4.readFileSync(runtimePackageJsonPath, "utf-8");
|
|
4580
4569
|
const pkg = JSON.parse(content);
|
|
4581
4570
|
if (pkg.version) {
|
|
4582
4571
|
cachedPackageVersion = pkg.version;
|
|
@@ -4585,10 +4574,8 @@ function getCachedVersion() {
|
|
|
4585
4574
|
}
|
|
4586
4575
|
} catch {}
|
|
4587
4576
|
try {
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
if (pkgPath) {
|
|
4591
|
-
const content = fs5.readFileSync(pkgPath, "utf-8");
|
|
4577
|
+
if (fs4.existsSync(INSTALLED_PACKAGE_JSON)) {
|
|
4578
|
+
const content = fs4.readFileSync(INSTALLED_PACKAGE_JSON, "utf-8");
|
|
4592
4579
|
const pkg = JSON.parse(content);
|
|
4593
4580
|
if (pkg.version) {
|
|
4594
4581
|
cachedPackageVersion = pkg.version;
|
|
@@ -4619,6 +4606,108 @@ async function getLatestVersion(channel = "latest") {
|
|
|
4619
4606
|
}
|
|
4620
4607
|
}
|
|
4621
4608
|
|
|
4609
|
+
// src/hooks/auto-update-checker/cache.ts
|
|
4610
|
+
function removeFromBunLock(installDir, packageName) {
|
|
4611
|
+
const lockPath = path7.join(installDir, "bun.lock");
|
|
4612
|
+
if (!fs5.existsSync(lockPath))
|
|
4613
|
+
return false;
|
|
4614
|
+
try {
|
|
4615
|
+
const content = fs5.readFileSync(lockPath, "utf-8");
|
|
4616
|
+
let lock;
|
|
4617
|
+
try {
|
|
4618
|
+
lock = JSON.parse(stripJsonComments(content));
|
|
4619
|
+
} catch {
|
|
4620
|
+
return false;
|
|
4621
|
+
}
|
|
4622
|
+
let modified = false;
|
|
4623
|
+
if (lock.workspaces?.[""]?.dependencies?.[packageName]) {
|
|
4624
|
+
delete lock.workspaces[""].dependencies[packageName];
|
|
4625
|
+
modified = true;
|
|
4626
|
+
}
|
|
4627
|
+
if (lock.packages?.[packageName]) {
|
|
4628
|
+
delete lock.packages[packageName];
|
|
4629
|
+
modified = true;
|
|
4630
|
+
}
|
|
4631
|
+
if (modified) {
|
|
4632
|
+
fs5.writeFileSync(lockPath, JSON.stringify(lock, null, 2));
|
|
4633
|
+
log(`[auto-update-checker] Removed from bun.lock: ${packageName}`);
|
|
4634
|
+
}
|
|
4635
|
+
return modified;
|
|
4636
|
+
} catch (err) {
|
|
4637
|
+
log(`[auto-update-checker] Failed to process bun.lock:`, err);
|
|
4638
|
+
return false;
|
|
4639
|
+
}
|
|
4640
|
+
}
|
|
4641
|
+
function ensureDependencyVersion(packageJsonPath, packageName, version) {
|
|
4642
|
+
if (!fs5.existsSync(packageJsonPath))
|
|
4643
|
+
return false;
|
|
4644
|
+
try {
|
|
4645
|
+
const content = fs5.readFileSync(packageJsonPath, "utf-8");
|
|
4646
|
+
const pkgJson = JSON.parse(stripJsonComments(content));
|
|
4647
|
+
const dependencies = { ...pkgJson.dependencies ?? {} };
|
|
4648
|
+
if (dependencies[packageName] === version) {
|
|
4649
|
+
return true;
|
|
4650
|
+
}
|
|
4651
|
+
dependencies[packageName] = version;
|
|
4652
|
+
pkgJson.dependencies = dependencies;
|
|
4653
|
+
fs5.writeFileSync(packageJsonPath, JSON.stringify(pkgJson, null, 2));
|
|
4654
|
+
log(`[auto-update-checker] Updated dependency in package.json: ${packageName} \u2192 ${version}`);
|
|
4655
|
+
return true;
|
|
4656
|
+
} catch (err) {
|
|
4657
|
+
log(`[auto-update-checker] Failed to update package.json dependency for auto-update:`, err);
|
|
4658
|
+
return false;
|
|
4659
|
+
}
|
|
4660
|
+
}
|
|
4661
|
+
function removeInstalledPackage(installDir, packageName) {
|
|
4662
|
+
const pkgDir = path7.join(installDir, "node_modules", packageName);
|
|
4663
|
+
if (!fs5.existsSync(pkgDir))
|
|
4664
|
+
return false;
|
|
4665
|
+
fs5.rmSync(pkgDir, { recursive: true, force: true });
|
|
4666
|
+
log(`[auto-update-checker] Package removed: ${pkgDir}`);
|
|
4667
|
+
return true;
|
|
4668
|
+
}
|
|
4669
|
+
function resolveInstallContext(runtimePackageJsonPath = getCurrentRuntimePackageJsonPath()) {
|
|
4670
|
+
if (runtimePackageJsonPath) {
|
|
4671
|
+
const packageDir = path7.dirname(runtimePackageJsonPath);
|
|
4672
|
+
const nodeModulesDir = path7.dirname(packageDir);
|
|
4673
|
+
if (path7.basename(packageDir) === PACKAGE_NAME && path7.basename(nodeModulesDir) === "node_modules") {
|
|
4674
|
+
const installDir = path7.dirname(nodeModulesDir);
|
|
4675
|
+
const packageJsonPath = path7.join(installDir, "package.json");
|
|
4676
|
+
if (fs5.existsSync(packageJsonPath)) {
|
|
4677
|
+
return { installDir, packageJsonPath };
|
|
4678
|
+
}
|
|
4679
|
+
}
|
|
4680
|
+
return null;
|
|
4681
|
+
}
|
|
4682
|
+
const legacyPackageJsonPath = path7.join(CACHE_DIR, "package.json");
|
|
4683
|
+
if (fs5.existsSync(legacyPackageJsonPath)) {
|
|
4684
|
+
return { installDir: CACHE_DIR, packageJsonPath: legacyPackageJsonPath };
|
|
4685
|
+
}
|
|
4686
|
+
return null;
|
|
4687
|
+
}
|
|
4688
|
+
function preparePackageUpdate(version, packageName = PACKAGE_NAME, runtimePackageJsonPath = getCurrentRuntimePackageJsonPath()) {
|
|
4689
|
+
try {
|
|
4690
|
+
const installContext = resolveInstallContext(runtimePackageJsonPath);
|
|
4691
|
+
if (!installContext) {
|
|
4692
|
+
log("[auto-update-checker] No install context found for auto-update");
|
|
4693
|
+
return null;
|
|
4694
|
+
}
|
|
4695
|
+
const dependencyReady = ensureDependencyVersion(installContext.packageJsonPath, packageName, version);
|
|
4696
|
+
if (!dependencyReady) {
|
|
4697
|
+
return null;
|
|
4698
|
+
}
|
|
4699
|
+
const packageRemoved = removeInstalledPackage(installContext.installDir, packageName);
|
|
4700
|
+
const lockRemoved = removeFromBunLock(installContext.installDir, packageName);
|
|
4701
|
+
if (!packageRemoved && !lockRemoved) {
|
|
4702
|
+
log(`[auto-update-checker] No cached package artifacts removed for ${packageName}; continuing with updated dependency spec`);
|
|
4703
|
+
}
|
|
4704
|
+
return installContext.installDir;
|
|
4705
|
+
} catch (err) {
|
|
4706
|
+
log("[auto-update-checker] Failed to prepare package update:", err);
|
|
4707
|
+
return null;
|
|
4708
|
+
}
|
|
4709
|
+
}
|
|
4710
|
+
|
|
4622
4711
|
// src/hooks/auto-update-checker/index.ts
|
|
4623
4712
|
function createAutoUpdateCheckerHook(ctx, options = {}) {
|
|
4624
4713
|
const { showStartupToast = true, autoUpdate = true } = options;
|
|
@@ -4688,23 +4777,24 @@ Version is pinned. Update your plugin config to apply.`, "info", 8000);
|
|
|
4688
4777
|
log("[auto-update-checker] Auto-update disabled, notification only");
|
|
4689
4778
|
return;
|
|
4690
4779
|
}
|
|
4691
|
-
|
|
4692
|
-
|
|
4780
|
+
const installDir = preparePackageUpdate(latestVersion, PACKAGE_NAME);
|
|
4781
|
+
if (!installDir) {
|
|
4782
|
+
showToast(ctx, `OMO-Slim ${latestVersion}`, `v${latestVersion} available. Auto-update could not prepare the active install.`, "info", 8000);
|
|
4783
|
+
log("[auto-update-checker] Failed to prepare install root for auto-update");
|
|
4784
|
+
return;
|
|
4785
|
+
}
|
|
4786
|
+
const installSuccess = await runBunInstallSafe(installDir);
|
|
4693
4787
|
if (installSuccess) {
|
|
4694
4788
|
showToast(ctx, "OMO-Slim Updated!", `v${currentVersion} \u2192 v${latestVersion}
|
|
4695
4789
|
Restart OpenCode to apply.`, "success", 8000);
|
|
4696
4790
|
log(`[auto-update-checker] Update installed: ${currentVersion} \u2192 ${latestVersion}`);
|
|
4697
4791
|
} else {
|
|
4698
|
-
showToast(ctx, `OMO-Slim ${latestVersion}`, `v${latestVersion} available
|
|
4792
|
+
showToast(ctx, `OMO-Slim ${latestVersion}`, `v${latestVersion} available, but auto-update failed to install it. Check logs or retry manually.`, "error", 8000);
|
|
4699
4793
|
log("[auto-update-checker] bun install failed; update not installed");
|
|
4700
4794
|
}
|
|
4701
4795
|
}
|
|
4702
|
-
function
|
|
4703
|
-
return CACHE_DIR;
|
|
4704
|
-
}
|
|
4705
|
-
async function runBunInstallSafe() {
|
|
4796
|
+
async function runBunInstallSafe(installDir) {
|
|
4706
4797
|
try {
|
|
4707
|
-
const installDir = getAutoUpdateInstallDir();
|
|
4708
4798
|
const proc = Bun.spawn(["bun", "install"], {
|
|
4709
4799
|
cwd: installDir,
|
|
4710
4800
|
stdout: "pipe",
|
|
@@ -5297,6 +5387,126 @@ function createPostFileToolNudgeHook(options = {}) {
|
|
|
5297
5387
|
}
|
|
5298
5388
|
// src/hooks/todo-continuation/index.ts
|
|
5299
5389
|
import { tool } from "@opencode-ai/plugin/tool";
|
|
5390
|
+
|
|
5391
|
+
// src/hooks/todo-continuation/todo-hygiene.ts
|
|
5392
|
+
var TODO_HYGIENE_REMINDER = "If the active task changed or finished, update the todo list to match the current work state.";
|
|
5393
|
+
var TODO_FINAL_ACTIVE_REMINDER = "If you are finishing now, do not leave the active todo in_progress. Mark it completed, or move unfinished work back to pending.";
|
|
5394
|
+
var RESET = new Set(["todowrite"]);
|
|
5395
|
+
var IGNORE = new Set(["auto_continue"]);
|
|
5396
|
+
function createTodoHygiene(options) {
|
|
5397
|
+
const pending = new Set;
|
|
5398
|
+
const done = new Set;
|
|
5399
|
+
function clear(sessionID) {
|
|
5400
|
+
pending.delete(sessionID);
|
|
5401
|
+
done.delete(sessionID);
|
|
5402
|
+
}
|
|
5403
|
+
function isFinalActive(state) {
|
|
5404
|
+
return state.inProgressCount === 1 && state.pendingCount === 0 && state.openCount === 1;
|
|
5405
|
+
}
|
|
5406
|
+
return {
|
|
5407
|
+
async handleToolExecuteAfter(input) {
|
|
5408
|
+
if (!input.sessionID) {
|
|
5409
|
+
return;
|
|
5410
|
+
}
|
|
5411
|
+
const tool = input.tool.toLowerCase();
|
|
5412
|
+
if (IGNORE.has(tool)) {
|
|
5413
|
+
return;
|
|
5414
|
+
}
|
|
5415
|
+
try {
|
|
5416
|
+
if (RESET.has(tool)) {
|
|
5417
|
+
const state = await options.getTodoState(input.sessionID);
|
|
5418
|
+
if (!state.hasOpenTodos) {
|
|
5419
|
+
clear(input.sessionID);
|
|
5420
|
+
options.log?.("Cleared todo hygiene cycle", {
|
|
5421
|
+
sessionID: input.sessionID,
|
|
5422
|
+
tool
|
|
5423
|
+
});
|
|
5424
|
+
return;
|
|
5425
|
+
}
|
|
5426
|
+
pending.delete(input.sessionID);
|
|
5427
|
+
done.delete(input.sessionID);
|
|
5428
|
+
if (isFinalActive(state)) {
|
|
5429
|
+
pending.add(input.sessionID);
|
|
5430
|
+
options.log?.("Armed final-active todo hygiene reminder", {
|
|
5431
|
+
sessionID: input.sessionID,
|
|
5432
|
+
tool
|
|
5433
|
+
});
|
|
5434
|
+
return;
|
|
5435
|
+
}
|
|
5436
|
+
options.log?.("Reset todo hygiene cycle", {
|
|
5437
|
+
sessionID: input.sessionID,
|
|
5438
|
+
tool
|
|
5439
|
+
});
|
|
5440
|
+
return;
|
|
5441
|
+
}
|
|
5442
|
+
if (pending.has(input.sessionID) || done.has(input.sessionID)) {
|
|
5443
|
+
return;
|
|
5444
|
+
}
|
|
5445
|
+
if (!(await options.getTodoState(input.sessionID)).hasOpenTodos) {
|
|
5446
|
+
return;
|
|
5447
|
+
}
|
|
5448
|
+
pending.add(input.sessionID);
|
|
5449
|
+
options.log?.("Armed todo hygiene reminder", {
|
|
5450
|
+
sessionID: input.sessionID,
|
|
5451
|
+
tool
|
|
5452
|
+
});
|
|
5453
|
+
} catch (error) {
|
|
5454
|
+
if (RESET.has(tool)) {
|
|
5455
|
+
clear(input.sessionID);
|
|
5456
|
+
}
|
|
5457
|
+
options.log?.("Skipped todo hygiene reminder: failed to inspect todos", {
|
|
5458
|
+
sessionID: input.sessionID,
|
|
5459
|
+
tool,
|
|
5460
|
+
error: error instanceof Error ? error.message : String(error)
|
|
5461
|
+
});
|
|
5462
|
+
}
|
|
5463
|
+
},
|
|
5464
|
+
async handleChatSystemTransform(input, output) {
|
|
5465
|
+
if (!input.sessionID || !pending.has(input.sessionID)) {
|
|
5466
|
+
return;
|
|
5467
|
+
}
|
|
5468
|
+
if (options.shouldInject && !options.shouldInject(input.sessionID)) {
|
|
5469
|
+
pending.delete(input.sessionID);
|
|
5470
|
+
done.add(input.sessionID);
|
|
5471
|
+
return;
|
|
5472
|
+
}
|
|
5473
|
+
try {
|
|
5474
|
+
const state = await options.getTodoState(input.sessionID);
|
|
5475
|
+
if (!state.hasOpenTodos) {
|
|
5476
|
+
clear(input.sessionID);
|
|
5477
|
+
return;
|
|
5478
|
+
}
|
|
5479
|
+
const finalActive = isFinalActive(state);
|
|
5480
|
+
const reminder = finalActive ? TODO_FINAL_ACTIVE_REMINDER : TODO_HYGIENE_REMINDER;
|
|
5481
|
+
pending.delete(input.sessionID);
|
|
5482
|
+
done.add(input.sessionID);
|
|
5483
|
+
output.system.push(reminder);
|
|
5484
|
+
options.log?.("Injected todo hygiene reminder", {
|
|
5485
|
+
sessionID: input.sessionID,
|
|
5486
|
+
reminder: finalActive ? "final-active" : "general"
|
|
5487
|
+
});
|
|
5488
|
+
} catch (error) {
|
|
5489
|
+
clear(input.sessionID);
|
|
5490
|
+
options.log?.("Skipped todo hygiene reminder: failed to inspect todos", {
|
|
5491
|
+
sessionID: input.sessionID,
|
|
5492
|
+
error: error instanceof Error ? error.message : String(error)
|
|
5493
|
+
});
|
|
5494
|
+
}
|
|
5495
|
+
},
|
|
5496
|
+
handleEvent(event) {
|
|
5497
|
+
if (event.type !== "session.deleted") {
|
|
5498
|
+
return;
|
|
5499
|
+
}
|
|
5500
|
+
const sessionID = event.properties?.sessionID ?? event.properties?.info?.id;
|
|
5501
|
+
if (!sessionID) {
|
|
5502
|
+
return;
|
|
5503
|
+
}
|
|
5504
|
+
clear(sessionID);
|
|
5505
|
+
}
|
|
5506
|
+
};
|
|
5507
|
+
}
|
|
5508
|
+
|
|
5509
|
+
// src/hooks/todo-continuation/index.ts
|
|
5300
5510
|
var HOOK_NAME = "todo-continuation";
|
|
5301
5511
|
var COMMAND_NAME = "auto-continue";
|
|
5302
5512
|
var CONTINUATION_PROMPT = "[Auto-continue: enabled - there are incomplete todos remaining. Continue with the next uncompleted item. Press Esc to cancel. If you need user input or review for the next item, ask instead of proceeding.]";
|
|
@@ -5354,6 +5564,23 @@ function createTodoContinuationHook(ctx, config) {
|
|
|
5354
5564
|
notifyingSessionIds: new Set,
|
|
5355
5565
|
notificationBusyUntilBySession: new Map
|
|
5356
5566
|
};
|
|
5567
|
+
const hygiene = createTodoHygiene({
|
|
5568
|
+
getTodoState: async (sessionID) => {
|
|
5569
|
+
const result = await ctx.client.session.todo({
|
|
5570
|
+
path: { id: sessionID }
|
|
5571
|
+
});
|
|
5572
|
+
const todos = result.data;
|
|
5573
|
+
const openTodos = todos.filter((todo) => !TERMINAL_TODO_STATUSES.includes(todo.status));
|
|
5574
|
+
return {
|
|
5575
|
+
hasOpenTodos: openTodos.length > 0,
|
|
5576
|
+
openCount: openTodos.length,
|
|
5577
|
+
inProgressCount: openTodos.filter((todo) => todo.status === "in_progress").length,
|
|
5578
|
+
pendingCount: openTodos.filter((todo) => todo.status === "pending").length
|
|
5579
|
+
};
|
|
5580
|
+
},
|
|
5581
|
+
shouldInject: (sessionID) => isOrchestratorSession(sessionID),
|
|
5582
|
+
log: (message, meta) => log(`[${HOOK_NAME}] ${message}`, meta)
|
|
5583
|
+
});
|
|
5357
5584
|
function markNotificationStarted(sessionID) {
|
|
5358
5585
|
state.notifyingSessionIds.add(sessionID);
|
|
5359
5586
|
}
|
|
@@ -5411,6 +5638,13 @@ function createTodoContinuationHook(ctx, config) {
|
|
|
5411
5638
|
async function handleEvent(input) {
|
|
5412
5639
|
const { event } = input;
|
|
5413
5640
|
const properties = event.properties ?? {};
|
|
5641
|
+
hygiene.handleEvent({
|
|
5642
|
+
type: event.type,
|
|
5643
|
+
properties: {
|
|
5644
|
+
info: properties.info,
|
|
5645
|
+
sessionID: properties.sessionID
|
|
5646
|
+
}
|
|
5647
|
+
});
|
|
5414
5648
|
if (event.type === "session.idle" || event.type === "session.status" && properties.status?.type === "idle") {
|
|
5415
5649
|
const sessionID = properties.sessionID;
|
|
5416
5650
|
if (!sessionID) {
|
|
@@ -5692,6 +5926,8 @@ function createTodoContinuationHook(ctx, config) {
|
|
|
5692
5926
|
}
|
|
5693
5927
|
return {
|
|
5694
5928
|
tool: { auto_continue: autoContinue },
|
|
5929
|
+
handleToolExecuteAfter: hygiene.handleToolExecuteAfter,
|
|
5930
|
+
handleChatSystemTransform: hygiene.handleChatSystemTransform,
|
|
5695
5931
|
handleEvent,
|
|
5696
5932
|
handleChatMessage,
|
|
5697
5933
|
handleCommandExecuteBefore
|
|
@@ -7271,7 +7507,7 @@ var {spawn: spawn5 } = globalThis.Bun;
|
|
|
7271
7507
|
// src/tools/ast-grep/constants.ts
|
|
7272
7508
|
import { existsSync as existsSync6, statSync as statSync2 } from "fs";
|
|
7273
7509
|
import { createRequire as createRequire2 } from "module";
|
|
7274
|
-
import { dirname as
|
|
7510
|
+
import { dirname as dirname6, join as join9 } from "path";
|
|
7275
7511
|
|
|
7276
7512
|
// src/tools/ast-grep/downloader.ts
|
|
7277
7513
|
import { chmodSync, existsSync as existsSync5, mkdirSync as mkdirSync2, unlinkSync } from "fs";
|
|
@@ -7428,7 +7664,7 @@ function findSgCliPathSync() {
|
|
|
7428
7664
|
try {
|
|
7429
7665
|
const require2 = createRequire2(import.meta.url);
|
|
7430
7666
|
const cliPkgPath = require2.resolve("@ast-grep/cli/package.json");
|
|
7431
|
-
const cliDir =
|
|
7667
|
+
const cliDir = dirname6(cliPkgPath);
|
|
7432
7668
|
const sgPath = join9(cliDir, binaryName);
|
|
7433
7669
|
if (existsSync6(sgPath) && isValidBinary(sgPath)) {
|
|
7434
7670
|
return sgPath;
|
|
@@ -7439,7 +7675,7 @@ function findSgCliPathSync() {
|
|
|
7439
7675
|
try {
|
|
7440
7676
|
const require2 = createRequire2(import.meta.url);
|
|
7441
7677
|
const pkgPath = require2.resolve(`${platformPkg}/package.json`);
|
|
7442
|
-
const pkgDir =
|
|
7678
|
+
const pkgDir = dirname6(pkgPath);
|
|
7443
7679
|
const astGrepName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
|
|
7444
7680
|
const binaryPath = join9(pkgDir, astGrepName);
|
|
7445
7681
|
if (existsSync6(binaryPath) && isValidBinary(binaryPath)) {
|
|
@@ -8001,7 +8237,7 @@ import {
|
|
|
8001
8237
|
// src/tools/lsp/config.ts
|
|
8002
8238
|
import { existsSync as existsSync9 } from "fs";
|
|
8003
8239
|
import { homedir as homedir4 } from "os";
|
|
8004
|
-
import { dirname as
|
|
8240
|
+
import { dirname as dirname8, join as join10, resolve as resolve3 } from "path";
|
|
8005
8241
|
import whichSync from "which";
|
|
8006
8242
|
|
|
8007
8243
|
// src/tools/lsp/config-store.ts
|
|
@@ -8033,7 +8269,7 @@ function hasUserLspConfig() {
|
|
|
8033
8269
|
|
|
8034
8270
|
// src/tools/lsp/constants.ts
|
|
8035
8271
|
import { existsSync as existsSync8, readdirSync, statSync as statSync3 } from "fs";
|
|
8036
|
-
import { dirname as
|
|
8272
|
+
import { dirname as dirname7, resolve as resolve2 } from "path";
|
|
8037
8273
|
var SEVERITY_MAP = {
|
|
8038
8274
|
1: "error",
|
|
8039
8275
|
2: "warning",
|
|
@@ -8053,10 +8289,10 @@ function* walkUpDirectories(start, stop) {
|
|
|
8053
8289
|
let dir = resolve2(start);
|
|
8054
8290
|
try {
|
|
8055
8291
|
if (!statSync3(dir).isDirectory()) {
|
|
8056
|
-
dir =
|
|
8292
|
+
dir = dirname7(dir);
|
|
8057
8293
|
}
|
|
8058
8294
|
} catch {
|
|
8059
|
-
dir =
|
|
8295
|
+
dir = dirname7(dir);
|
|
8060
8296
|
}
|
|
8061
8297
|
let prevDir = "";
|
|
8062
8298
|
while (dir !== prevDir && dir !== "/") {
|
|
@@ -8064,7 +8300,7 @@ function* walkUpDirectories(start, stop) {
|
|
|
8064
8300
|
prevDir = dir;
|
|
8065
8301
|
if (dir === stop)
|
|
8066
8302
|
break;
|
|
8067
|
-
dir =
|
|
8303
|
+
dir = dirname7(dir);
|
|
8068
8304
|
}
|
|
8069
8305
|
}
|
|
8070
8306
|
function NearestRoot(includePatterns, excludePatterns) {
|
|
@@ -8610,7 +8846,7 @@ function getServerWorkspace(config, filePath) {
|
|
|
8610
8846
|
return;
|
|
8611
8847
|
}
|
|
8612
8848
|
if (!config.root) {
|
|
8613
|
-
return
|
|
8849
|
+
return dirname8(resolve3(filePath));
|
|
8614
8850
|
}
|
|
8615
8851
|
return config.root(filePath);
|
|
8616
8852
|
}
|
|
@@ -8634,7 +8870,7 @@ function findInstalledServer(configs, filePath) {
|
|
|
8634
8870
|
let firstNotInstalled = null;
|
|
8635
8871
|
for (const config of configs) {
|
|
8636
8872
|
const workspace = getServerWorkspace(config, filePath);
|
|
8637
|
-
const resolvedCommand = resolveServerCommand(config.command, workspace ?? (filePath ?
|
|
8873
|
+
const resolvedCommand = resolveServerCommand(config.command, workspace ?? (filePath ? dirname8(resolve3(filePath)) : undefined));
|
|
8638
8874
|
const server = toResolvedServer(config, resolvedCommand ?? undefined);
|
|
8639
8875
|
log(`[LSP] Considering server for ${config.extensions.join(", ")}: ${config.id} with command ${config.command.join(" ")}`);
|
|
8640
8876
|
if (resolvedCommand) {
|
|
@@ -8705,12 +8941,14 @@ function resolveServerCommand(command, cwd) {
|
|
|
8705
8941
|
// src/tools/lsp/client.ts
|
|
8706
8942
|
var START_TIMEOUT_MS = 5000;
|
|
8707
8943
|
var REQUEST_TIMEOUT_MS = 5000;
|
|
8944
|
+
var DIAGNOSTICS_TIMEOUT_MS = 15000;
|
|
8708
8945
|
var OPEN_FILE_DELAY_MS = 250;
|
|
8709
8946
|
var INITIALIZE_DELAY_MS = 100;
|
|
8710
8947
|
var DIAGNOSTIC_SETTLE_DELAY_MS = 250;
|
|
8711
8948
|
var LSP_TIMEOUTS = {
|
|
8712
8949
|
start: START_TIMEOUT_MS,
|
|
8713
8950
|
request: REQUEST_TIMEOUT_MS,
|
|
8951
|
+
diagnostics: DIAGNOSTICS_TIMEOUT_MS,
|
|
8714
8952
|
openFileDelay: OPEN_FILE_DELAY_MS,
|
|
8715
8953
|
initializeDelay: INITIALIZE_DELAY_MS,
|
|
8716
8954
|
diagnosticSettleDelay: DIAGNOSTIC_SETTLE_DELAY_MS
|
|
@@ -9135,7 +9373,7 @@ stderr: ${stderr}` : ""));
|
|
|
9135
9373
|
await new Promise((r) => setTimeout(r, LSP_TIMEOUTS.initializeDelay));
|
|
9136
9374
|
log("[lsp] LSPClient.initialize: complete", { server: this.server.id });
|
|
9137
9375
|
}
|
|
9138
|
-
async waitForPublishedDiagnostics(uri, timeoutMs = LSP_TIMEOUTS.
|
|
9376
|
+
async waitForPublishedDiagnostics(uri, timeoutMs = LSP_TIMEOUTS.diagnostics) {
|
|
9139
9377
|
const cachedDiagnostics = this.diagnosticsStore.get(uri);
|
|
9140
9378
|
if (cachedDiagnostics) {
|
|
9141
9379
|
return cachedDiagnostics;
|
|
@@ -9215,6 +9453,7 @@ stderr: ${stderr}` : ""));
|
|
|
9215
9453
|
async diagnostics(filePath) {
|
|
9216
9454
|
const absPath = resolve4(filePath);
|
|
9217
9455
|
const uri = pathToFileURL(absPath).href;
|
|
9456
|
+
const startedAt = Date.now();
|
|
9218
9457
|
await this.openFile(absPath);
|
|
9219
9458
|
await new Promise((r) => setTimeout(r, LSP_TIMEOUTS.diagnosticSettleDelay));
|
|
9220
9459
|
log("[lsp] diagnostics mode selected", {
|
|
@@ -9232,7 +9471,7 @@ stderr: ${stderr}` : ""));
|
|
|
9232
9471
|
const result = this.connection ? await withTimeout(this.connection.sendRequest("textDocument/diagnostic", {
|
|
9233
9472
|
textDocument: { uri },
|
|
9234
9473
|
previousResultId: this.diagnosticResultIds.get(uri)
|
|
9235
|
-
}), LSP_TIMEOUTS.
|
|
9474
|
+
}), LSP_TIMEOUTS.diagnostics, `LSP diagnostics (${this.server.id})`) : undefined;
|
|
9236
9475
|
const report = result;
|
|
9237
9476
|
if (report?.kind === "full") {
|
|
9238
9477
|
if (report.resultId) {
|
|
@@ -9261,7 +9500,9 @@ stderr: ${stderr}` : ""));
|
|
|
9261
9500
|
});
|
|
9262
9501
|
}
|
|
9263
9502
|
}
|
|
9264
|
-
const
|
|
9503
|
+
const elapsed = Date.now() - startedAt;
|
|
9504
|
+
const remainingTimeout = Math.max(LSP_TIMEOUTS.diagnostics - elapsed, 0);
|
|
9505
|
+
const cachedDiagnostics = await this.waitForPublishedDiagnostics(uri, remainingTimeout);
|
|
9265
9506
|
if (cachedDiagnostics) {
|
|
9266
9507
|
return { items: cachedDiagnostics };
|
|
9267
9508
|
}
|
|
@@ -9313,13 +9554,13 @@ import {
|
|
|
9313
9554
|
unlinkSync as unlinkSync2,
|
|
9314
9555
|
writeFileSync as writeFileSync3
|
|
9315
9556
|
} from "fs";
|
|
9316
|
-
import { dirname as
|
|
9557
|
+
import { dirname as dirname9, extname as extname3, join as join11, resolve as resolve5 } from "path";
|
|
9317
9558
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
9318
9559
|
function findServerProjectRoot(filePath, server) {
|
|
9319
9560
|
if (server.root) {
|
|
9320
|
-
return server.root(filePath) ??
|
|
9561
|
+
return server.root(filePath) ?? dirname9(resolve5(filePath));
|
|
9321
9562
|
}
|
|
9322
|
-
return
|
|
9563
|
+
return dirname9(resolve5(filePath));
|
|
9323
9564
|
}
|
|
9324
9565
|
function uriToPath(uri) {
|
|
9325
9566
|
return fileURLToPath2(uri);
|
|
@@ -9349,7 +9590,7 @@ async function withLspClient(filePath, fn) {
|
|
|
9349
9590
|
throw new Error(formatServerLookupError(result));
|
|
9350
9591
|
}
|
|
9351
9592
|
const server = result.server;
|
|
9352
|
-
const root = findServerProjectRoot(absPath, server) ??
|
|
9593
|
+
const root = findServerProjectRoot(absPath, server) ?? dirname9(absPath);
|
|
9353
9594
|
log("[lsp] withLspClient: selected server", {
|
|
9354
9595
|
filePath: absPath,
|
|
9355
9596
|
extension: ext,
|
|
@@ -11545,6 +11786,13 @@ var OhMyOpenCodeLite = async (ctx) => {
|
|
|
11545
11786
|
await multiplexerSessionManager.onSessionDeleted(input.event);
|
|
11546
11787
|
await interviewManager.handleEvent(input);
|
|
11547
11788
|
await postFileToolNudgeHook.event(input);
|
|
11789
|
+
if (input.event.type === "session.deleted") {
|
|
11790
|
+
const props = input.event.properties;
|
|
11791
|
+
const sessionID = props?.info?.id ?? props?.sessionID;
|
|
11792
|
+
if (sessionID) {
|
|
11793
|
+
sessionAgentMap.delete(sessionID);
|
|
11794
|
+
}
|
|
11795
|
+
}
|
|
11548
11796
|
},
|
|
11549
11797
|
"tool.execute.before": async (input, output) => {
|
|
11550
11798
|
await applyPatchHook["tool.execute.before"](input, output);
|
|
@@ -11575,6 +11823,7 @@ var OhMyOpenCodeLite = async (ctx) => {
|
|
|
11575
11823
|
${output.system[0]}` : "");
|
|
11576
11824
|
}
|
|
11577
11825
|
}
|
|
11826
|
+
await todoContinuationHook.handleChatSystemTransform(input, output);
|
|
11578
11827
|
await postFileToolNudgeHook["experimental.chat.system.transform"](input, output);
|
|
11579
11828
|
},
|
|
11580
11829
|
"experimental.chat.messages.transform": async (input, output) => {
|
|
@@ -11585,6 +11834,7 @@ ${output.system[0]}` : "");
|
|
|
11585
11834
|
"tool.execute.after": async (input, output) => {
|
|
11586
11835
|
await delegateTaskRetryHook["tool.execute.after"](input, output);
|
|
11587
11836
|
await jsonErrorRecoveryHook["tool.execute.after"](input, output);
|
|
11837
|
+
await todoContinuationHook.handleToolExecuteAfter(input);
|
|
11588
11838
|
await postFileToolNudgeHook["tool.execute.after"](input, output);
|
|
11589
11839
|
}
|
|
11590
11840
|
};
|
|
@@ -258,6 +258,13 @@
|
|
|
258
258
|
"items": {
|
|
259
259
|
"type": "string"
|
|
260
260
|
}
|
|
261
|
+
},
|
|
262
|
+
"options": {
|
|
263
|
+
"type": "object",
|
|
264
|
+
"propertyNames": {
|
|
265
|
+
"type": "string"
|
|
266
|
+
},
|
|
267
|
+
"additionalProperties": {}
|
|
261
268
|
}
|
|
262
269
|
}
|
|
263
270
|
}
|
|
@@ -321,6 +328,13 @@
|
|
|
321
328
|
"items": {
|
|
322
329
|
"type": "string"
|
|
323
330
|
}
|
|
331
|
+
},
|
|
332
|
+
"options": {
|
|
333
|
+
"type": "object",
|
|
334
|
+
"propertyNames": {
|
|
335
|
+
"type": "string"
|
|
336
|
+
},
|
|
337
|
+
"additionalProperties": {}
|
|
324
338
|
}
|
|
325
339
|
}
|
|
326
340
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oh-my-opencode-slim",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.12",
|
|
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",
|
|
@@ -55,27 +55,27 @@
|
|
|
55
55
|
"release:major": "npm version major && git push --follow-tags && npm publish"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
+
"@ast-grep/cli": "^0.42.1",
|
|
59
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
58
60
|
"@mozilla/readability": "^0.6.0",
|
|
59
|
-
"@
|
|
60
|
-
"@
|
|
61
|
-
"@opencode-ai/plugin": "^1.2.6",
|
|
62
|
-
"@opencode-ai/sdk": "^1.2.6",
|
|
61
|
+
"@opencode-ai/plugin": "^1.3.17",
|
|
62
|
+
"@opencode-ai/sdk": "^1.3.17",
|
|
63
63
|
"jsdom": "^26.1.0",
|
|
64
|
-
"lru-cache": "^11.
|
|
65
|
-
"turndown": "^7.2.
|
|
66
|
-
"vscode-jsonrpc": "^8.2.
|
|
64
|
+
"lru-cache": "^11.3.3",
|
|
65
|
+
"turndown": "^7.2.4",
|
|
66
|
+
"vscode-jsonrpc": "^8.2.1",
|
|
67
67
|
"vscode-languageserver-protocol": "^3.17.5",
|
|
68
|
-
"which": "^6.0.
|
|
68
|
+
"which": "^6.0.1",
|
|
69
69
|
"zod": "^4.3.6"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
|
-
"@biomejs/biome": "2.4.
|
|
72
|
+
"@biomejs/biome": "2.4.11",
|
|
73
73
|
"@types/jsdom": "^21.1.7",
|
|
74
74
|
"@types/node": "^24.6.1",
|
|
75
|
-
"@types/turndown": "^5.0.
|
|
75
|
+
"@types/turndown": "^5.0.6",
|
|
76
76
|
"@types/which": "^3.0.4",
|
|
77
77
|
"all-contributors-cli": "^6.26.1",
|
|
78
|
-
"bun-types": "1.3.
|
|
78
|
+
"bun-types": "1.3.12",
|
|
79
79
|
"typescript": "^5.9.3"
|
|
80
80
|
},
|
|
81
81
|
"trustedDependencies": [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cartography
|
|
3
|
-
description:
|
|
3
|
+
description: Generate comprehensive hierarchical codemaps for UNFAMILIAR repositories. Expensive operation - only use when explicitly asked for codebase documentation or initial repository mapping
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Cartography Skill
|