oh-my-opencode-slim 1.0.7 โ 1.1.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.
- package/README.md +9 -4
- package/dist/cli/config-io.d.ts +1 -0
- package/dist/cli/index.js +170 -52
- package/dist/index.js +586 -58
- package/dist/tools/fork/command.d.ts +28 -0
- package/dist/tools/fork/files.d.ts +33 -0
- package/dist/tools/fork/index.d.ts +10 -0
- package/dist/tools/fork/state.d.ts +7 -0
- package/dist/tools/fork/tools.d.ts +23 -0
- package/dist/tools/fork/vendor.d.ts +28 -0
- package/dist/tools/handoff/command.d.ts +29 -0
- package/dist/tools/handoff/files.d.ts +33 -0
- package/dist/tools/handoff/index.d.ts +10 -0
- package/dist/tools/handoff/state.d.ts +7 -0
- package/dist/tools/handoff/tools.d.ts +23 -0
- package/dist/tools/handoff/vendor.d.ts +28 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/subtask/command.d.ts +30 -0
- package/dist/tools/subtask/files.d.ts +34 -0
- package/dist/tools/subtask/index.d.ts +11 -0
- package/dist/tools/subtask/state.d.ts +7 -0
- package/dist/tools/subtask/tools.d.ts +23 -0
- package/dist/tools/subtask/vendor.d.ts +27 -0
- package/dist/tui.js +56 -0
- package/dist/utils/session.d.ts +2 -1
- package/package.json +1 -1
- package/src/skills/clonedeps/README.md +23 -0
- package/src/skills/clonedeps/SKILL.md +237 -0
- package/src/skills/clonedeps/codemap.md +41 -0
- package/src/skills/codemap.md +8 -5
package/README.md
CHANGED
|
@@ -39,8 +39,10 @@ bunx oh-my-opencode-slim@latest install
|
|
|
39
39
|
|
|
40
40
|
The installer also registers the companion TUI plugin in OpenCode's
|
|
41
41
|
`tui.json`, which adds a small sidebar showing specialist-agent status plus
|
|
42
|
-
active/reusable task sessions.
|
|
43
|
-
|
|
42
|
+
active/reusable task sessions. It also warms OpenCode's plugin cache so bunx
|
|
43
|
+
installs keep loading even after temporary directories are cleaned up. For
|
|
44
|
+
manual setups, add `oh-my-opencode-slim` to the `plugin` array in both
|
|
45
|
+
`opencode.json` and `tui.json`.
|
|
44
46
|
|
|
45
47
|
### Getting Started
|
|
46
48
|
|
|
@@ -488,7 +490,9 @@ Use this section as a map: start with installation, then jump to features, confi
|
|
|
488
490
|
| **[Session Management](docs/session-management.md)** | Reuse recent child-agent sessions with short aliases instead of starting over |
|
|
489
491
|
| **[Todo Continuation](docs/todo-continuation.md)** | Auto-continue orchestrator sessions with cooldowns and safety checks |
|
|
490
492
|
| **[Preset Switching](docs/preset-switching.md)** | Switch agent model presets at runtime with `/preset` |
|
|
493
|
+
| **[Subtask](docs/subtask.md)** | Run a bounded child worker with `/subtask` and return a structured summary to the main session |
|
|
491
494
|
| **[Codemap](docs/codemap.md)** | Generate hierarchical codemaps to understand large codebases faster |
|
|
495
|
+
| **[Clonedeps](docs/clonedeps.md)** | Clone selected dependency source into an ignored local workspace for inspection |
|
|
492
496
|
| **[Interview](docs/interview.md)** | Turn rough ideas into a structured markdown spec through a browser-based Q&A flow |
|
|
493
497
|
| **[Divoom Display](docs/divoom.md)** | Mirror orchestrator and specialist-agent activity to a Divoom MiniToo Bluetooth display |
|
|
494
498
|
|
|
@@ -498,7 +502,7 @@ Use this section as a map: start with installation, then jump to features, confi
|
|
|
498
502
|
|-----|----------------|
|
|
499
503
|
| **[Configuration](docs/configuration.md)** | Config file locations, JSONC support, prompt overrides, and full option reference |
|
|
500
504
|
| **[Maintainer Guide](docs/maintainers.md)** | Issue triage rules, label meanings, support routing, and repo maintenance workflow |
|
|
501
|
-
| **[Skills](docs/skills.md)** | Built-in and recommended skills such as `simplify`, `agent-browser`, and `
|
|
505
|
+
| **[Skills](docs/skills.md)** | Built-in and recommended skills such as `simplify`, `agent-browser`, `codemap`, and `clonedeps` |
|
|
502
506
|
| **[MCPs](docs/mcps.md)** | `websearch`, `context7`, `grep_app`, and how MCP permissions work per agent |
|
|
503
507
|
| **[Tools](docs/tools.md)** | Built-in tool capabilities like `webfetch`, LSP tools, code search, and formatters |
|
|
504
508
|
|
|
@@ -519,7 +523,7 @@ Use this section as a map: start with installation, then jump to features, confi
|
|
|
519
523
|
<p><sub>Every merged contribution leaves a mark on the realm.</sub></p>
|
|
520
524
|
|
|
521
525
|
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
|
522
|
-
[](#contributors-)
|
|
523
527
|
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
|
524
528
|
</div>
|
|
525
529
|
|
|
@@ -590,6 +594,7 @@ Use this section as a map: start with installation, then jump to features, confi
|
|
|
590
594
|
<td align="center" valign="top" width="16.66%"><a href="https://github.com/gustavocaiano"><img src="https://avatars.githubusercontent.com/u/104129313?v=4?s=100" width="100px;" alt="Gustavo Caiano"/><br /><sub><b>Gustavo Caiano</b></sub></a><br /><a href="https://github.com/alvinunreal/oh-my-opencode-slim/commits?author=gustavocaiano" title="Code">๐ป</a></td>
|
|
591
595
|
<td align="center" valign="top" width="16.66%"><a href="https://github.com/ThomasMldr"><img src="https://avatars.githubusercontent.com/u/6631765?v=4?s=100" width="100px;" alt="Thomas Mulder"/><br /><sub><b>Thomas Mulder</b></sub></a><br /><a href="https://github.com/alvinunreal/oh-my-opencode-slim/commits?author=ThomasMldr" title="Code">๐ป</a></td>
|
|
592
596
|
<td align="center" valign="top" width="16.66%"><a href="https://github.com/maou-shonen"><img src="https://avatars.githubusercontent.com/u/22576780?v=4?s=100" width="100px;" alt="้ญ็ๅฐๅนด(maou shonen)"/><br /><sub><b>้ญ็ๅฐๅนด(maou shonen)</b></sub></a><br /><a href="https://github.com/alvinunreal/oh-my-opencode-slim/commits?author=maou-shonen" title="Code">๐ป</a></td>
|
|
597
|
+
<td align="center" valign="top" width="16.66%"><a href="https://github.com/jelasin"><img src="https://avatars.githubusercontent.com/u/97788570?v=4?s=100" width="100px;" alt=" Jelasin"/><br /><sub><b> Jelasin</b></sub></a><br /><a href="https://github.com/alvinunreal/oh-my-opencode-slim/commits?author=jelasin" title="Code">๐ป</a></td>
|
|
593
598
|
</tr>
|
|
594
599
|
</tbody>
|
|
595
600
|
</table>
|
package/dist/cli/config-io.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ConfigMergeResult, DetectedConfig, InstallConfig, OpenCodeConfig } from './types';
|
|
2
|
+
export declare function warmOpenCodePluginCache(): Promise<ConfigMergeResult | null>;
|
|
2
3
|
/**
|
|
3
4
|
* Strip JSON comments (single-line // and multi-line) and trailing commas for JSONC support.
|
|
4
5
|
*/
|
package/dist/cli/index.js
CHANGED
|
@@ -15,13 +15,61 @@ import * as path from "node:path";
|
|
|
15
15
|
import {
|
|
16
16
|
copyFileSync as copyFileSync2,
|
|
17
17
|
existsSync as existsSync3,
|
|
18
|
+
mkdirSync as mkdirSync3,
|
|
18
19
|
readFileSync,
|
|
19
20
|
renameSync,
|
|
20
21
|
statSync as statSync2,
|
|
21
22
|
writeFileSync
|
|
22
23
|
} from "node:fs";
|
|
24
|
+
import { homedir as homedir2 } from "node:os";
|
|
23
25
|
import { dirname as dirname3, join as join3 } from "node:path";
|
|
24
26
|
|
|
27
|
+
// src/utils/compat.ts
|
|
28
|
+
import { spawn as nodeSpawn } from "node:child_process";
|
|
29
|
+
var isBun = typeof globalThis.Bun !== "undefined";
|
|
30
|
+
function collectStream(stream) {
|
|
31
|
+
if (!stream)
|
|
32
|
+
return () => Promise.resolve("");
|
|
33
|
+
const chunks = [];
|
|
34
|
+
stream.on("data", (chunk) => chunks.push(chunk));
|
|
35
|
+
return () => new Promise((resolve, reject) => {
|
|
36
|
+
if (!stream.readable) {
|
|
37
|
+
resolve(Buffer.concat(chunks).toString("utf-8"));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
|
|
41
|
+
stream.on("error", reject);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function crossSpawn(command, options) {
|
|
45
|
+
const [cmd, ...args] = command;
|
|
46
|
+
const proc = nodeSpawn(cmd, args, {
|
|
47
|
+
stdio: [
|
|
48
|
+
options?.stdin ?? "ignore",
|
|
49
|
+
options?.stdout ?? "pipe",
|
|
50
|
+
options?.stderr ?? "pipe"
|
|
51
|
+
],
|
|
52
|
+
cwd: options?.cwd,
|
|
53
|
+
env: options?.env
|
|
54
|
+
});
|
|
55
|
+
const stdoutCollector = collectStream(proc.stdout);
|
|
56
|
+
const stderrCollector = collectStream(proc.stderr);
|
|
57
|
+
const exited = new Promise((resolve, reject) => {
|
|
58
|
+
proc.on("error", reject);
|
|
59
|
+
proc.on("close", (code) => resolve(code ?? 1));
|
|
60
|
+
});
|
|
61
|
+
return {
|
|
62
|
+
proc,
|
|
63
|
+
stdout: stdoutCollector,
|
|
64
|
+
stderr: stderrCollector,
|
|
65
|
+
exited,
|
|
66
|
+
kill: (signal) => proc.kill(signal),
|
|
67
|
+
get exitCode() {
|
|
68
|
+
return proc.exitCode;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
25
73
|
// src/cli/paths.ts
|
|
26
74
|
import { existsSync, mkdirSync } from "node:fs";
|
|
27
75
|
import { homedir } from "node:os";
|
|
@@ -419,6 +467,12 @@ var CUSTOM_SKILLS = [
|
|
|
419
467
|
description: "Repository understanding and hierarchical codemap generation",
|
|
420
468
|
allowedAgents: ["orchestrator"],
|
|
421
469
|
sourcePath: "src/skills/codemap"
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
name: "clonedeps",
|
|
473
|
+
description: "Clone important dependency source for local inspection",
|
|
474
|
+
allowedAgents: ["orchestrator"],
|
|
475
|
+
sourcePath: "src/skills/clonedeps"
|
|
422
476
|
}
|
|
423
477
|
];
|
|
424
478
|
function getCustomSkillsDir() {
|
|
@@ -658,10 +712,6 @@ function findPackageRoot(startPath) {
|
|
|
658
712
|
currentPath = parentPath;
|
|
659
713
|
}
|
|
660
714
|
}
|
|
661
|
-
function isPackageManagerInstall(path) {
|
|
662
|
-
const normalizedPath = normalizePathForMatch(path);
|
|
663
|
-
return normalizedPath.includes(`/node_modules/${PACKAGE_NAME}`);
|
|
664
|
-
}
|
|
665
715
|
function isLocalPackageRootEntry(entry) {
|
|
666
716
|
if (!entry || entry.startsWith("file://")) {
|
|
667
717
|
return false;
|
|
@@ -677,6 +727,10 @@ function isLocalPackageRootEntry(entry) {
|
|
|
677
727
|
return false;
|
|
678
728
|
}
|
|
679
729
|
}
|
|
730
|
+
function isPackageManagerInstall(path) {
|
|
731
|
+
const normalizedPath = normalizePathForMatch(path);
|
|
732
|
+
return normalizedPath.includes(`/node_modules/${PACKAGE_NAME}`);
|
|
733
|
+
}
|
|
680
734
|
function isPluginEntry(entry) {
|
|
681
735
|
return entry === PACKAGE_NAME || entry.startsWith(`${PACKAGE_NAME}@`) || entry.startsWith("file://") && entry.includes(PACKAGE_NAME) || isLocalPackageRootEntry(entry);
|
|
682
736
|
}
|
|
@@ -699,6 +753,104 @@ function getPluginEntry() {
|
|
|
699
753
|
return PACKAGE_NAME;
|
|
700
754
|
}
|
|
701
755
|
}
|
|
756
|
+
function getOpenCodePluginCacheDir() {
|
|
757
|
+
const cacheDir = process.env.XDG_CACHE_HOME?.trim() || join3(homedir2(), ".cache");
|
|
758
|
+
return join3(cacheDir, "opencode", "packages", `${PACKAGE_NAME}@latest`);
|
|
759
|
+
}
|
|
760
|
+
function writeOpenCodePluginCacheManifest(cacheDir) {
|
|
761
|
+
try {
|
|
762
|
+
writeFileSync(join3(cacheDir, "package.json"), JSON.stringify({
|
|
763
|
+
name: `${PACKAGE_NAME}-cache`,
|
|
764
|
+
private: true,
|
|
765
|
+
dependencies: {
|
|
766
|
+
[PACKAGE_NAME]: "latest"
|
|
767
|
+
}
|
|
768
|
+
}, null, 2));
|
|
769
|
+
return null;
|
|
770
|
+
} catch (err) {
|
|
771
|
+
return {
|
|
772
|
+
success: false,
|
|
773
|
+
configPath: cacheDir,
|
|
774
|
+
error: `Failed to write cache package.json: ${err}`
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
function verifyOpenCodePluginCache(cacheDir) {
|
|
779
|
+
const pluginPackageJsonPath = join3(cacheDir, "node_modules", PACKAGE_NAME, "package.json");
|
|
780
|
+
if (!existsSync3(pluginPackageJsonPath)) {
|
|
781
|
+
return {
|
|
782
|
+
success: false,
|
|
783
|
+
configPath: cacheDir,
|
|
784
|
+
error: `Cached plugin package not found at ${pluginPackageJsonPath}`
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
try {
|
|
788
|
+
const packageJson = JSON.parse(readFileSync(pluginPackageJsonPath, "utf-8"));
|
|
789
|
+
if (packageJson.name !== PACKAGE_NAME) {
|
|
790
|
+
return {
|
|
791
|
+
success: false,
|
|
792
|
+
configPath: cacheDir,
|
|
793
|
+
error: `Cached plugin package has unexpected name: ${packageJson.name}`
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
} catch (err) {
|
|
797
|
+
return {
|
|
798
|
+
success: false,
|
|
799
|
+
configPath: cacheDir,
|
|
800
|
+
error: `Failed to verify cached plugin package: ${err}`
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
return null;
|
|
804
|
+
}
|
|
805
|
+
async function warmOpenCodePluginCache() {
|
|
806
|
+
const cliEntryPath = process.argv[1];
|
|
807
|
+
if (!cliEntryPath) {
|
|
808
|
+
return null;
|
|
809
|
+
}
|
|
810
|
+
const packageRoot = findPackageRoot(cliEntryPath);
|
|
811
|
+
if (!packageRoot || !isPackageManagerInstall(packageRoot)) {
|
|
812
|
+
return null;
|
|
813
|
+
}
|
|
814
|
+
const cacheDir = getOpenCodePluginCacheDir();
|
|
815
|
+
try {
|
|
816
|
+
mkdirSync3(cacheDir, { recursive: true });
|
|
817
|
+
} catch (err) {
|
|
818
|
+
return {
|
|
819
|
+
success: false,
|
|
820
|
+
configPath: cacheDir,
|
|
821
|
+
error: `Failed to create OpenCode cache directory: ${err}`
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
const manifestError = writeOpenCodePluginCacheManifest(cacheDir);
|
|
825
|
+
if (manifestError)
|
|
826
|
+
return manifestError;
|
|
827
|
+
try {
|
|
828
|
+
const proc = crossSpawn(["bun", "install", "--ignore-scripts"], {
|
|
829
|
+
cwd: cacheDir,
|
|
830
|
+
stdout: "pipe",
|
|
831
|
+
stderr: "pipe"
|
|
832
|
+
});
|
|
833
|
+
await proc.exited;
|
|
834
|
+
if (proc.exitCode !== 0) {
|
|
835
|
+
const stderr = (await proc.stderr()).trim();
|
|
836
|
+
return {
|
|
837
|
+
success: false,
|
|
838
|
+
configPath: cacheDir,
|
|
839
|
+
error: stderr || `bun install exited with code ${proc.exitCode}`
|
|
840
|
+
};
|
|
841
|
+
}
|
|
842
|
+
const verificationError = verifyOpenCodePluginCache(cacheDir);
|
|
843
|
+
if (verificationError)
|
|
844
|
+
return verificationError;
|
|
845
|
+
return { success: true, configPath: cacheDir };
|
|
846
|
+
} catch (err) {
|
|
847
|
+
return {
|
|
848
|
+
success: false,
|
|
849
|
+
configPath: cacheDir,
|
|
850
|
+
error: `Failed to warm OpenCode cache: ${err}`
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
}
|
|
702
854
|
function stripJsonComments(json) {
|
|
703
855
|
const commentPattern = /\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g;
|
|
704
856
|
const trailingCommaPattern = /\\"|"(?:\\"|[^"])*"|(,)(\s*[}\]])/g;
|
|
@@ -1205,54 +1357,6 @@ import { createInterface } from "node:readline/promises";
|
|
|
1205
1357
|
// src/cli/system.ts
|
|
1206
1358
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
1207
1359
|
import { statSync as statSync4 } from "node:fs";
|
|
1208
|
-
|
|
1209
|
-
// src/utils/compat.ts
|
|
1210
|
-
import { spawn as nodeSpawn } from "node:child_process";
|
|
1211
|
-
var isBun = typeof globalThis.Bun !== "undefined";
|
|
1212
|
-
function collectStream(stream) {
|
|
1213
|
-
if (!stream)
|
|
1214
|
-
return () => Promise.resolve("");
|
|
1215
|
-
const chunks = [];
|
|
1216
|
-
stream.on("data", (chunk) => chunks.push(chunk));
|
|
1217
|
-
return () => new Promise((resolve, reject) => {
|
|
1218
|
-
if (!stream.readable) {
|
|
1219
|
-
resolve(Buffer.concat(chunks).toString("utf-8"));
|
|
1220
|
-
return;
|
|
1221
|
-
}
|
|
1222
|
-
stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
|
|
1223
|
-
stream.on("error", reject);
|
|
1224
|
-
});
|
|
1225
|
-
}
|
|
1226
|
-
function crossSpawn(command, options) {
|
|
1227
|
-
const [cmd, ...args] = command;
|
|
1228
|
-
const proc = nodeSpawn(cmd, args, {
|
|
1229
|
-
stdio: [
|
|
1230
|
-
options?.stdin ?? "ignore",
|
|
1231
|
-
options?.stdout ?? "pipe",
|
|
1232
|
-
options?.stderr ?? "pipe"
|
|
1233
|
-
],
|
|
1234
|
-
cwd: options?.cwd,
|
|
1235
|
-
env: options?.env
|
|
1236
|
-
});
|
|
1237
|
-
const stdoutCollector = collectStream(proc.stdout);
|
|
1238
|
-
const stderrCollector = collectStream(proc.stderr);
|
|
1239
|
-
const exited = new Promise((resolve, reject) => {
|
|
1240
|
-
proc.on("error", reject);
|
|
1241
|
-
proc.on("close", (code) => resolve(code ?? 1));
|
|
1242
|
-
});
|
|
1243
|
-
return {
|
|
1244
|
-
proc,
|
|
1245
|
-
stdout: stdoutCollector,
|
|
1246
|
-
stderr: stderrCollector,
|
|
1247
|
-
exited,
|
|
1248
|
-
kill: (signal) => proc.kill(signal),
|
|
1249
|
-
get exitCode() {
|
|
1250
|
-
return proc.exitCode;
|
|
1251
|
-
}
|
|
1252
|
-
};
|
|
1253
|
-
}
|
|
1254
|
-
|
|
1255
|
-
// src/cli/system.ts
|
|
1256
1360
|
var cachedOpenCodePath = null;
|
|
1257
1361
|
function resolvePathCommand(command) {
|
|
1258
1362
|
try {
|
|
@@ -1478,6 +1582,7 @@ async function runInstall(config) {
|
|
|
1478
1582
|
totalSteps += 1;
|
|
1479
1583
|
if (config.installCustomSkills)
|
|
1480
1584
|
totalSteps += 1;
|
|
1585
|
+
totalSteps += 1;
|
|
1481
1586
|
let step = 1;
|
|
1482
1587
|
printStep(step++, totalSteps, "Checking OpenCode installation...");
|
|
1483
1588
|
if (config.dryRun) {
|
|
@@ -1506,6 +1611,19 @@ async function runInstall(config) {
|
|
|
1506
1611
|
handleStepResult(tuiResult, "TUI badge added");
|
|
1507
1612
|
}
|
|
1508
1613
|
}
|
|
1614
|
+
printStep(step++, totalSteps, "Warming OpenCode plugin cache...");
|
|
1615
|
+
if (config.dryRun) {
|
|
1616
|
+
printInfo("Dry run mode - skipping cache warm-up");
|
|
1617
|
+
} else {
|
|
1618
|
+
const cacheResult = await warmOpenCodePluginCache();
|
|
1619
|
+
if (cacheResult === null) {
|
|
1620
|
+
printInfo("Local development install - cache warm-up not required");
|
|
1621
|
+
} else if (!cacheResult.success) {
|
|
1622
|
+
printInfo(`Skipped cache warm-up: ${cacheResult.error}`);
|
|
1623
|
+
} else {
|
|
1624
|
+
handleStepResult(cacheResult, "OpenCode cache warmed");
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1509
1627
|
printStep(step++, totalSteps, "Disabling OpenCode default agents...");
|
|
1510
1628
|
if (config.dryRun) {
|
|
1511
1629
|
printInfo("Dry run mode - skipping agent disabling");
|