clikit-plugin 0.3.4 → 0.3.6
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/dist/.tsbuildinfo +1 -1
- package/dist/cli.js +0 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +521 -111
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3386,7 +3386,7 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
3386
3386
|
|
|
3387
3387
|
// node_modules/gray-matter/index.js
|
|
3388
3388
|
var require_gray_matter = __commonJS((exports, module) => {
|
|
3389
|
-
var
|
|
3389
|
+
var fs2 = __require("fs");
|
|
3390
3390
|
var sections = require_section_matter();
|
|
3391
3391
|
var defaults = require_defaults();
|
|
3392
3392
|
var stringify = require_stringify();
|
|
@@ -3473,7 +3473,7 @@ var require_gray_matter = __commonJS((exports, module) => {
|
|
|
3473
3473
|
return stringify(file2, data, options2);
|
|
3474
3474
|
};
|
|
3475
3475
|
matter.read = function(filepath, options2) {
|
|
3476
|
-
const str2 =
|
|
3476
|
+
const str2 = fs2.readFileSync(filepath, "utf8");
|
|
3477
3477
|
const file2 = matter(str2, options2);
|
|
3478
3478
|
file2.path = filepath;
|
|
3479
3479
|
return file2;
|
|
@@ -3500,6 +3500,369 @@ var require_gray_matter = __commonJS((exports, module) => {
|
|
|
3500
3500
|
module.exports = matter;
|
|
3501
3501
|
});
|
|
3502
3502
|
|
|
3503
|
+
// src/cli.ts
|
|
3504
|
+
import * as fs from "fs";
|
|
3505
|
+
import * as path from "path";
|
|
3506
|
+
import * as os from "os";
|
|
3507
|
+
import { fileURLToPath } from "url";
|
|
3508
|
+
var PLUGIN_NAME = "clikit-plugin";
|
|
3509
|
+
var DCP_PLUGIN_ENTRY = "@tarquinen/opencode-dcp@beta";
|
|
3510
|
+
var VERSION = "0.0.0";
|
|
3511
|
+
function getPackageRoot() {
|
|
3512
|
+
const currentFile = fileURLToPath(import.meta.url);
|
|
3513
|
+
const currentDir = path.dirname(currentFile);
|
|
3514
|
+
if (path.basename(currentDir) === "dist") {
|
|
3515
|
+
return path.dirname(currentDir);
|
|
3516
|
+
}
|
|
3517
|
+
return path.dirname(currentDir);
|
|
3518
|
+
}
|
|
3519
|
+
function getPackageVersion() {
|
|
3520
|
+
const packageJsonPath = path.join(getPackageRoot(), "package.json");
|
|
3521
|
+
try {
|
|
3522
|
+
const raw = fs.readFileSync(packageJsonPath, "utf-8");
|
|
3523
|
+
const parsed = JSON.parse(raw);
|
|
3524
|
+
return parsed.version || VERSION;
|
|
3525
|
+
} catch {
|
|
3526
|
+
return VERSION;
|
|
3527
|
+
}
|
|
3528
|
+
}
|
|
3529
|
+
function getPluginEntry() {
|
|
3530
|
+
return `${PLUGIN_NAME}@latest`;
|
|
3531
|
+
}
|
|
3532
|
+
function resolveProjectDir(env = process.env, cwd = process.cwd()) {
|
|
3533
|
+
const candidates = [env.INIT_CWD, env.PWD, cwd].filter((value) => typeof value === "string" && value.trim().length > 0);
|
|
3534
|
+
for (const candidate of candidates) {
|
|
3535
|
+
const resolved = path.resolve(candidate);
|
|
3536
|
+
try {
|
|
3537
|
+
if (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {
|
|
3538
|
+
return resolved;
|
|
3539
|
+
}
|
|
3540
|
+
} catch {}
|
|
3541
|
+
}
|
|
3542
|
+
return cwd;
|
|
3543
|
+
}
|
|
3544
|
+
function upsertPluginEntry(existingPlugins, pluginEntry) {
|
|
3545
|
+
let pluginName;
|
|
3546
|
+
if (pluginEntry.startsWith("@")) {
|
|
3547
|
+
const versionAt = pluginEntry.indexOf("@", 1);
|
|
3548
|
+
pluginName = versionAt === -1 ? pluginEntry : pluginEntry.slice(0, versionAt);
|
|
3549
|
+
} else {
|
|
3550
|
+
pluginName = pluginEntry.split("@")[0] || pluginEntry;
|
|
3551
|
+
}
|
|
3552
|
+
const filteredPlugins = existingPlugins.filter((p) => p !== pluginName && !p.startsWith(`${pluginName}@`));
|
|
3553
|
+
filteredPlugins.push(pluginEntry);
|
|
3554
|
+
return filteredPlugins;
|
|
3555
|
+
}
|
|
3556
|
+
function copyFileIfMissing(sourcePath, targetPath, stats) {
|
|
3557
|
+
if (!fs.existsSync(sourcePath)) {
|
|
3558
|
+
stats.missingSources.push(sourcePath);
|
|
3559
|
+
return;
|
|
3560
|
+
}
|
|
3561
|
+
if (fs.existsSync(targetPath)) {
|
|
3562
|
+
stats.skipped += 1;
|
|
3563
|
+
return;
|
|
3564
|
+
}
|
|
3565
|
+
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
3566
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
3567
|
+
stats.copied += 1;
|
|
3568
|
+
}
|
|
3569
|
+
function copyDirectoryFilesIfMissing(sourceDir, targetDir, stats) {
|
|
3570
|
+
if (!fs.existsSync(sourceDir)) {
|
|
3571
|
+
stats.missingSources.push(sourceDir);
|
|
3572
|
+
return;
|
|
3573
|
+
}
|
|
3574
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
3575
|
+
const entries = fs.readdirSync(sourceDir, { withFileTypes: true });
|
|
3576
|
+
for (const entry of entries) {
|
|
3577
|
+
const sourcePath = path.join(sourceDir, entry.name);
|
|
3578
|
+
const targetPath = path.join(targetDir, entry.name);
|
|
3579
|
+
if (entry.isDirectory()) {
|
|
3580
|
+
copyDirectoryFilesIfMissing(sourcePath, targetPath, stats);
|
|
3581
|
+
continue;
|
|
3582
|
+
}
|
|
3583
|
+
if (entry.isFile()) {
|
|
3584
|
+
copyFileIfMissing(sourcePath, targetPath, stats);
|
|
3585
|
+
}
|
|
3586
|
+
}
|
|
3587
|
+
}
|
|
3588
|
+
function scaffoldProjectOpencode(projectDir, packageRoot = getPackageRoot()) {
|
|
3589
|
+
const projectOpencodeDir = path.join(projectDir, ".opencode");
|
|
3590
|
+
const stats = {
|
|
3591
|
+
copied: 0,
|
|
3592
|
+
skipped: 0,
|
|
3593
|
+
missingSources: []
|
|
3594
|
+
};
|
|
3595
|
+
fs.mkdirSync(projectOpencodeDir, { recursive: true });
|
|
3596
|
+
copyFileIfMissing(path.join(packageRoot, "AGENTS.md"), path.join(projectOpencodeDir, "AGENTS.md"), stats);
|
|
3597
|
+
copyDirectoryFilesIfMissing(path.join(packageRoot, "command"), path.join(projectOpencodeDir, "command"), stats);
|
|
3598
|
+
copyDirectoryFilesIfMissing(path.join(packageRoot, "skill"), path.join(projectOpencodeDir, "skill"), stats);
|
|
3599
|
+
copyDirectoryFilesIfMissing(path.join(packageRoot, "memory", "_templates"), path.join(projectOpencodeDir, "memory", "_templates"), stats);
|
|
3600
|
+
copyDirectoryFilesIfMissing(path.join(packageRoot, "src", "agents"), path.join(projectOpencodeDir, "src", "agents"), stats);
|
|
3601
|
+
copyFileIfMissing(path.join(packageRoot, "README.md"), path.join(projectOpencodeDir, "README-clikit.md"), stats);
|
|
3602
|
+
const indexPath = path.join(projectOpencodeDir, "index.ts");
|
|
3603
|
+
if (!fs.existsSync(indexPath)) {
|
|
3604
|
+
fs.writeFileSync(indexPath, `import CliKitPlugin from "${PLUGIN_NAME}";
|
|
3605
|
+
|
|
3606
|
+
export default CliKitPlugin;
|
|
3607
|
+
`);
|
|
3608
|
+
stats.copied += 1;
|
|
3609
|
+
} else {
|
|
3610
|
+
stats.skipped += 1;
|
|
3611
|
+
}
|
|
3612
|
+
return stats;
|
|
3613
|
+
}
|
|
3614
|
+
function getShellRcFiles() {
|
|
3615
|
+
const home = getRealHome();
|
|
3616
|
+
const rcFiles = [];
|
|
3617
|
+
const shell = process.env.SHELL || "";
|
|
3618
|
+
if (shell.includes("zsh")) {
|
|
3619
|
+
rcFiles.push(path.join(home, ".zshrc"));
|
|
3620
|
+
} else if (shell.includes("fish")) {
|
|
3621
|
+
rcFiles.push(path.join(home, ".config", "fish", "config.fish"));
|
|
3622
|
+
} else {
|
|
3623
|
+
rcFiles.push(path.join(home, ".bashrc"));
|
|
3624
|
+
const bashProfile = path.join(home, ".bash_profile");
|
|
3625
|
+
if (fs.existsSync(bashProfile)) {
|
|
3626
|
+
rcFiles.push(bashProfile);
|
|
3627
|
+
}
|
|
3628
|
+
}
|
|
3629
|
+
return rcFiles;
|
|
3630
|
+
}
|
|
3631
|
+
function ensureEnvInShellRc(key, value) {
|
|
3632
|
+
const exportLine = `export ${key}=${value}`;
|
|
3633
|
+
const marker = `# Added by clikit-plugin`;
|
|
3634
|
+
const block = `
|
|
3635
|
+
${marker}
|
|
3636
|
+
${exportLine}
|
|
3637
|
+
`;
|
|
3638
|
+
const rcFiles = getShellRcFiles();
|
|
3639
|
+
for (const rcFile of rcFiles) {
|
|
3640
|
+
try {
|
|
3641
|
+
const existing = fs.existsSync(rcFile) ? fs.readFileSync(rcFile, "utf-8") : "";
|
|
3642
|
+
if (existing.includes(`export ${key}=`) || existing.includes(`${key}=`)) {
|
|
3643
|
+
console.log(`\u2713 ${key} already set in ${rcFile}`);
|
|
3644
|
+
continue;
|
|
3645
|
+
}
|
|
3646
|
+
fs.appendFileSync(rcFile, block, "utf-8");
|
|
3647
|
+
console.log(`\u2713 Added ${exportLine} to ${rcFile}`);
|
|
3648
|
+
} catch (err) {
|
|
3649
|
+
console.warn(`\u26A0 Could not write to ${rcFile}: ${err}`);
|
|
3650
|
+
}
|
|
3651
|
+
}
|
|
3652
|
+
}
|
|
3653
|
+
function removeLegacyGlobalPluginAssets(configDir) {
|
|
3654
|
+
const legacyPluginPath = path.join(configDir, "plugins", "clikit.js");
|
|
3655
|
+
const legacyAgentsDir = path.join(configDir, "plugins", "agents");
|
|
3656
|
+
const legacyCommandDir = path.join(configDir, "command");
|
|
3657
|
+
const legacyStatusPath = path.join(legacyCommandDir, "status.md");
|
|
3658
|
+
const legacyStatusBeadsPath = path.join(legacyCommandDir, "status-beads.md");
|
|
3659
|
+
if (fs.existsSync(legacyPluginPath)) {
|
|
3660
|
+
fs.rmSync(legacyPluginPath, { force: true });
|
|
3661
|
+
console.log(`\u2713 Removed legacy local plugin file: ${legacyPluginPath}`);
|
|
3662
|
+
}
|
|
3663
|
+
if (fs.existsSync(legacyAgentsDir)) {
|
|
3664
|
+
fs.rmSync(legacyAgentsDir, { recursive: true, force: true });
|
|
3665
|
+
console.log(`\u2713 Removed legacy local agents directory: ${legacyAgentsDir}`);
|
|
3666
|
+
}
|
|
3667
|
+
if (fs.existsSync(legacyStatusPath)) {
|
|
3668
|
+
fs.rmSync(legacyStatusPath, { force: true });
|
|
3669
|
+
console.log(`\u2713 Removed legacy command file: ${legacyStatusPath}`);
|
|
3670
|
+
}
|
|
3671
|
+
if (fs.existsSync(legacyStatusBeadsPath)) {
|
|
3672
|
+
fs.rmSync(legacyStatusBeadsPath, { force: true });
|
|
3673
|
+
console.log(`\u2713 Removed legacy command file: ${legacyStatusBeadsPath}`);
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
function getRealHome() {
|
|
3677
|
+
if (process.env.SNAP_REAL_HOME) {
|
|
3678
|
+
return process.env.SNAP_REAL_HOME;
|
|
3679
|
+
}
|
|
3680
|
+
const home = os.homedir();
|
|
3681
|
+
const snapMatch = home.match(/^(\/home\/[^/]+)\/snap\//);
|
|
3682
|
+
if (snapMatch) {
|
|
3683
|
+
return snapMatch[1];
|
|
3684
|
+
}
|
|
3685
|
+
return home;
|
|
3686
|
+
}
|
|
3687
|
+
function getConfigDir() {
|
|
3688
|
+
if (process.env.OPENCODE_CONFIG_DIR) {
|
|
3689
|
+
return process.env.OPENCODE_CONFIG_DIR;
|
|
3690
|
+
}
|
|
3691
|
+
const home = getRealHome();
|
|
3692
|
+
return path.join(process.env.XDG_CONFIG_HOME || path.join(home, ".config"), "opencode");
|
|
3693
|
+
}
|
|
3694
|
+
function getConfigPath() {
|
|
3695
|
+
const configDir = getConfigDir();
|
|
3696
|
+
const jsonPath = path.join(configDir, "opencode.json");
|
|
3697
|
+
const jsoncPath = path.join(configDir, "opencode.jsonc");
|
|
3698
|
+
if (fs.existsSync(jsoncPath))
|
|
3699
|
+
return jsoncPath;
|
|
3700
|
+
if (fs.existsSync(jsonPath))
|
|
3701
|
+
return jsonPath;
|
|
3702
|
+
return jsonPath;
|
|
3703
|
+
}
|
|
3704
|
+
function getCliKitConfigPath(configDir = getConfigDir()) {
|
|
3705
|
+
const candidates = ["clikit.jsonc", "clikit.json", "clikit.config.json"];
|
|
3706
|
+
for (const name of candidates) {
|
|
3707
|
+
const fullPath = path.join(configDir, name);
|
|
3708
|
+
if (fs.existsSync(fullPath)) {
|
|
3709
|
+
return fullPath;
|
|
3710
|
+
}
|
|
3711
|
+
}
|
|
3712
|
+
return path.join(configDir, "clikit.json");
|
|
3713
|
+
}
|
|
3714
|
+
function ensureConfigDir() {
|
|
3715
|
+
const configDir = getConfigDir();
|
|
3716
|
+
if (!fs.existsSync(configDir)) {
|
|
3717
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
3718
|
+
}
|
|
3719
|
+
}
|
|
3720
|
+
function parseConfig(configPath) {
|
|
3721
|
+
try {
|
|
3722
|
+
if (!fs.existsSync(configPath)) {
|
|
3723
|
+
return { config: {}, raw: "", parseError: null };
|
|
3724
|
+
}
|
|
3725
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
3726
|
+
try {
|
|
3727
|
+
const parsed = JSON.parse(content);
|
|
3728
|
+
return { config: parsed, raw: content, parseError: null };
|
|
3729
|
+
} catch {
|
|
3730
|
+
const cleaned = content.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
3731
|
+
const cleanedTrailing = cleaned.replace(/,\s*([}\]])/g, "$1");
|
|
3732
|
+
const parsed = JSON.parse(cleanedTrailing);
|
|
3733
|
+
return { config: parsed, raw: content, parseError: null };
|
|
3734
|
+
}
|
|
3735
|
+
} catch (err) {
|
|
3736
|
+
const raw = fs.existsSync(configPath) ? fs.readFileSync(configPath, "utf-8") : "";
|
|
3737
|
+
return { config: {}, raw, parseError: String(err) };
|
|
3738
|
+
}
|
|
3739
|
+
}
|
|
3740
|
+
function writeConfig(configPath, config) {
|
|
3741
|
+
ensureConfigDir();
|
|
3742
|
+
const tmpPath = `${configPath}.tmp`;
|
|
3743
|
+
const content = JSON.stringify(config, null, 2) + `
|
|
3744
|
+
`;
|
|
3745
|
+
fs.writeFileSync(tmpPath, content);
|
|
3746
|
+
fs.renameSync(tmpPath, configPath);
|
|
3747
|
+
}
|
|
3748
|
+
async function install(options2) {
|
|
3749
|
+
const pluginEntry = getPluginEntry();
|
|
3750
|
+
try {
|
|
3751
|
+
ensureConfigDir();
|
|
3752
|
+
const configPath = getConfigPath();
|
|
3753
|
+
const result = parseConfig(configPath);
|
|
3754
|
+
if (result.parseError && result.raw.trim()) {
|
|
3755
|
+
console.error(`\u2717 Config file has syntax errors and cannot be safely modified.`);
|
|
3756
|
+
console.error(` Error: ${result.parseError}`);
|
|
3757
|
+
console.error(` Please fix the config file manually.`);
|
|
3758
|
+
return 1;
|
|
3759
|
+
}
|
|
3760
|
+
const config = result.config;
|
|
3761
|
+
const existingPlugins = Array.isArray(config.plugin) ? config.plugin.filter((p) => typeof p === "string") : [];
|
|
3762
|
+
const filteredPlugins = upsertPluginEntry(existingPlugins, pluginEntry);
|
|
3763
|
+
const finalPlugins = upsertPluginEntry(filteredPlugins, DCP_PLUGIN_ENTRY);
|
|
3764
|
+
const pluginMergedConfig = { ...config, plugin: finalPlugins };
|
|
3765
|
+
writeConfig(configPath, pluginMergedConfig);
|
|
3766
|
+
if (options2.includeProjectScaffold) {
|
|
3767
|
+
const projectDir = resolveProjectDir();
|
|
3768
|
+
scaffoldProjectOpencode(projectDir);
|
|
3769
|
+
}
|
|
3770
|
+
removeLegacyGlobalPluginAssets(getConfigDir());
|
|
3771
|
+
ensureEnvInShellRc("OPENCODE_ENABLE_EXA", "1");
|
|
3772
|
+
const memoryDir = path.join(getConfigDir(), "memory");
|
|
3773
|
+
const memorySubdirs = ["specs", "plans", "research", "reviews", "handoffs", "beads", "prds"];
|
|
3774
|
+
for (const subdir of memorySubdirs) {
|
|
3775
|
+
const dir = path.join(memoryDir, subdir);
|
|
3776
|
+
if (!fs.existsSync(dir)) {
|
|
3777
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
3778
|
+
}
|
|
3779
|
+
}
|
|
3780
|
+
const clikitConfigPath = getCliKitConfigPath();
|
|
3781
|
+
if (!fs.existsSync(clikitConfigPath)) {
|
|
3782
|
+
const defaultConfig = {
|
|
3783
|
+
$schema: `https://unpkg.com/${PLUGIN_NAME}@latest/schema.json`,
|
|
3784
|
+
disabled_agents: [],
|
|
3785
|
+
disabled_commands: [],
|
|
3786
|
+
disabled_skills: [],
|
|
3787
|
+
agents: {},
|
|
3788
|
+
commands: {},
|
|
3789
|
+
skills: {
|
|
3790
|
+
enable: [],
|
|
3791
|
+
disable: []
|
|
3792
|
+
},
|
|
3793
|
+
hooks: {}
|
|
3794
|
+
};
|
|
3795
|
+
writeConfig(clikitConfigPath, defaultConfig);
|
|
3796
|
+
}
|
|
3797
|
+
console.log(`\u2713 CliKit installed (${pluginEntry})`);
|
|
3798
|
+
console.log(`\u2713 DCP installed (${DCP_PLUGIN_ENTRY})`);
|
|
3799
|
+
console.log(`\u2713 Config: ${configPath}`);
|
|
3800
|
+
console.log("\u2713 Restart OpenCode");
|
|
3801
|
+
return 0;
|
|
3802
|
+
} catch (err) {
|
|
3803
|
+
console.error(`\u2717 Install failed: ${err}`);
|
|
3804
|
+
return 1;
|
|
3805
|
+
}
|
|
3806
|
+
}
|
|
3807
|
+
function help() {
|
|
3808
|
+
console.log(`
|
|
3809
|
+
CliKit - OpenCode Plugin
|
|
3810
|
+
|
|
3811
|
+
Usage:
|
|
3812
|
+
bun x clikit-plugin <command>
|
|
3813
|
+
|
|
3814
|
+
Commands:
|
|
3815
|
+
install Install CliKit globally for OpenCode
|
|
3816
|
+
help Show this help message
|
|
3817
|
+
version Show version
|
|
3818
|
+
|
|
3819
|
+
Install options:
|
|
3820
|
+
--project Also scaffold project .opencode files (default: disabled)
|
|
3821
|
+
|
|
3822
|
+
Examples:
|
|
3823
|
+
bun x clikit-plugin install
|
|
3824
|
+
bun x clikit-plugin install --project
|
|
3825
|
+
`);
|
|
3826
|
+
}
|
|
3827
|
+
function version() {
|
|
3828
|
+
console.log(`clikit-plugin v${getPackageVersion()}`);
|
|
3829
|
+
}
|
|
3830
|
+
async function main() {
|
|
3831
|
+
const args = process.argv.slice(2);
|
|
3832
|
+
const command = args[0] || "help";
|
|
3833
|
+
const flags = args.slice(1);
|
|
3834
|
+
let exitCode = 0;
|
|
3835
|
+
switch (command) {
|
|
3836
|
+
case "install":
|
|
3837
|
+
case "i":
|
|
3838
|
+
exitCode = await install({
|
|
3839
|
+
includeProjectScaffold: flags.includes("--project")
|
|
3840
|
+
});
|
|
3841
|
+
break;
|
|
3842
|
+
case "help":
|
|
3843
|
+
case "-h":
|
|
3844
|
+
case "--help":
|
|
3845
|
+
help();
|
|
3846
|
+
break;
|
|
3847
|
+
case "version":
|
|
3848
|
+
case "-v":
|
|
3849
|
+
case "--version":
|
|
3850
|
+
version();
|
|
3851
|
+
break;
|
|
3852
|
+
default:
|
|
3853
|
+
console.error(`Unknown command: ${command}`);
|
|
3854
|
+
help();
|
|
3855
|
+
exitCode = 1;
|
|
3856
|
+
}
|
|
3857
|
+
process.exit(exitCode);
|
|
3858
|
+
}
|
|
3859
|
+
if (import.meta.main) {
|
|
3860
|
+
main().catch((err) => {
|
|
3861
|
+
console.error(err);
|
|
3862
|
+
process.exit(1);
|
|
3863
|
+
});
|
|
3864
|
+
}
|
|
3865
|
+
|
|
3503
3866
|
// node_modules/zod/v4/classic/external.js
|
|
3504
3867
|
var exports_external = {};
|
|
3505
3868
|
__export(exports_external, {
|
|
@@ -3733,7 +4096,7 @@ __export(exports_external, {
|
|
|
3733
4096
|
// node_modules/zod/v4/core/index.js
|
|
3734
4097
|
var exports_core2 = {};
|
|
3735
4098
|
__export(exports_core2, {
|
|
3736
|
-
version: () =>
|
|
4099
|
+
version: () => version2,
|
|
3737
4100
|
util: () => exports_util,
|
|
3738
4101
|
treeifyError: () => treeifyError,
|
|
3739
4102
|
toJSONSchema: () => toJSONSchema,
|
|
@@ -4229,10 +4592,10 @@ function mergeDefs(...defs) {
|
|
|
4229
4592
|
function cloneDef(schema) {
|
|
4230
4593
|
return mergeDefs(schema._zod.def);
|
|
4231
4594
|
}
|
|
4232
|
-
function getElementAtPath(obj,
|
|
4233
|
-
if (!
|
|
4595
|
+
function getElementAtPath(obj, path2) {
|
|
4596
|
+
if (!path2)
|
|
4234
4597
|
return obj;
|
|
4235
|
-
return
|
|
4598
|
+
return path2.reduce((acc, key) => acc?.[key], obj);
|
|
4236
4599
|
}
|
|
4237
4600
|
function promiseAllObject(promisesObj) {
|
|
4238
4601
|
const keys = Object.keys(promisesObj);
|
|
@@ -4591,11 +4954,11 @@ function aborted(x, startIndex = 0) {
|
|
|
4591
4954
|
}
|
|
4592
4955
|
return false;
|
|
4593
4956
|
}
|
|
4594
|
-
function prefixIssues(
|
|
4957
|
+
function prefixIssues(path2, issues) {
|
|
4595
4958
|
return issues.map((iss) => {
|
|
4596
4959
|
var _a;
|
|
4597
4960
|
(_a = iss).path ?? (_a.path = []);
|
|
4598
|
-
iss.path.unshift(
|
|
4961
|
+
iss.path.unshift(path2);
|
|
4599
4962
|
return iss;
|
|
4600
4963
|
});
|
|
4601
4964
|
}
|
|
@@ -4763,7 +5126,7 @@ function treeifyError(error, _mapper) {
|
|
|
4763
5126
|
return issue2.message;
|
|
4764
5127
|
};
|
|
4765
5128
|
const result = { errors: [] };
|
|
4766
|
-
const processError = (error2,
|
|
5129
|
+
const processError = (error2, path2 = []) => {
|
|
4767
5130
|
var _a, _b;
|
|
4768
5131
|
for (const issue2 of error2.issues) {
|
|
4769
5132
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -4773,7 +5136,7 @@ function treeifyError(error, _mapper) {
|
|
|
4773
5136
|
} else if (issue2.code === "invalid_element") {
|
|
4774
5137
|
processError({ issues: issue2.issues }, issue2.path);
|
|
4775
5138
|
} else {
|
|
4776
|
-
const fullpath = [...
|
|
5139
|
+
const fullpath = [...path2, ...issue2.path];
|
|
4777
5140
|
if (fullpath.length === 0) {
|
|
4778
5141
|
result.errors.push(mapper(issue2));
|
|
4779
5142
|
continue;
|
|
@@ -4805,8 +5168,8 @@ function treeifyError(error, _mapper) {
|
|
|
4805
5168
|
}
|
|
4806
5169
|
function toDotPath(_path) {
|
|
4807
5170
|
const segs = [];
|
|
4808
|
-
const
|
|
4809
|
-
for (const seg of
|
|
5171
|
+
const path2 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
5172
|
+
for (const seg of path2) {
|
|
4810
5173
|
if (typeof seg === "number")
|
|
4811
5174
|
segs.push(`[${seg}]`);
|
|
4812
5175
|
else if (typeof seg === "symbol")
|
|
@@ -4990,10 +5353,10 @@ var nanoid = /^[a-zA-Z0-9_-]{21}$/;
|
|
|
4990
5353
|
var duration = /^P(?:(\d+W)|(?!.*W)(?=\d|T\d)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+([.,]\d+)?S)?)?)$/;
|
|
4991
5354
|
var extendedDuration = /^[-+]?P(?!$)(?:(?:[-+]?\d+Y)|(?:[-+]?\d+[.,]\d+Y$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:(?:[-+]?\d+W)|(?:[-+]?\d+[.,]\d+W$))?(?:(?:[-+]?\d+D)|(?:[-+]?\d+[.,]\d+D$))?(?:T(?=[\d+-])(?:(?:[-+]?\d+H)|(?:[-+]?\d+[.,]\d+H$))?(?:(?:[-+]?\d+M)|(?:[-+]?\d+[.,]\d+M$))?(?:[-+]?\d+(?:[.,]\d+)?S)?)??$/;
|
|
4992
5355
|
var guid = /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/;
|
|
4993
|
-
var uuid = (
|
|
4994
|
-
if (!
|
|
5356
|
+
var uuid = (version2) => {
|
|
5357
|
+
if (!version2)
|
|
4995
5358
|
return /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/;
|
|
4996
|
-
return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${
|
|
5359
|
+
return new RegExp(`^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-${version2}[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$`);
|
|
4997
5360
|
};
|
|
4998
5361
|
var uuid4 = /* @__PURE__ */ uuid(4);
|
|
4999
5362
|
var uuid6 = /* @__PURE__ */ uuid(6);
|
|
@@ -5652,7 +6015,7 @@ class Doc {
|
|
|
5652
6015
|
}
|
|
5653
6016
|
|
|
5654
6017
|
// node_modules/zod/v4/core/versions.js
|
|
5655
|
-
var
|
|
6018
|
+
var version2 = {
|
|
5656
6019
|
major: 4,
|
|
5657
6020
|
minor: 1,
|
|
5658
6021
|
patch: 8
|
|
@@ -5664,7 +6027,7 @@ var $ZodType = /* @__PURE__ */ $constructor("$ZodType", (inst, def) => {
|
|
|
5664
6027
|
inst ?? (inst = {});
|
|
5665
6028
|
inst._zod.def = def;
|
|
5666
6029
|
inst._zod.bag = inst._zod.bag || {};
|
|
5667
|
-
inst._zod.version =
|
|
6030
|
+
inst._zod.version = version2;
|
|
5668
6031
|
const checks = [...inst._zod.def.checks ?? []];
|
|
5669
6032
|
if (inst._zod.traits.has("$ZodCheck")) {
|
|
5670
6033
|
checks.unshift(inst);
|
|
@@ -15823,15 +16186,18 @@ tool.schema = exports_external;
|
|
|
15823
16186
|
// src/index.ts
|
|
15824
16187
|
import { execFile as execFile3 } from "child_process";
|
|
15825
16188
|
import { promisify as promisify3 } from "util";
|
|
16189
|
+
import * as fs11 from "fs";
|
|
16190
|
+
import * as path11 from "path";
|
|
16191
|
+
import * as os3 from "os";
|
|
15826
16192
|
|
|
15827
16193
|
// src/agents/index.ts
|
|
15828
16194
|
var import_gray_matter = __toESM(require_gray_matter(), 1);
|
|
15829
|
-
import * as
|
|
15830
|
-
import * as
|
|
16195
|
+
import * as fs3 from "fs";
|
|
16196
|
+
import * as path3 from "path";
|
|
15831
16197
|
|
|
15832
16198
|
// src/hooks/error-logger.ts
|
|
15833
|
-
import * as
|
|
15834
|
-
import * as
|
|
16199
|
+
import * as fs2 from "fs";
|
|
16200
|
+
import * as path2 from "path";
|
|
15835
16201
|
var BLOCKED_TOOL_ERROR_PREFIX = "[CliKit] Blocked tool execution:";
|
|
15836
16202
|
var _initErrorBuffer = [];
|
|
15837
16203
|
function bufferInitError(source, level, message, context) {
|
|
@@ -15874,10 +16240,10 @@ function formatHookErrorLog(hookName, error45, context) {
|
|
|
15874
16240
|
}
|
|
15875
16241
|
function writeErrorLog(hookName, error45, projectDir, context) {
|
|
15876
16242
|
try {
|
|
15877
|
-
const logDir =
|
|
15878
|
-
const logPath =
|
|
15879
|
-
if (!
|
|
15880
|
-
|
|
16243
|
+
const logDir = path2.join(projectDir, ".opencode");
|
|
16244
|
+
const logPath = path2.join(logDir, "error-log.txt");
|
|
16245
|
+
if (!fs2.existsSync(logDir)) {
|
|
16246
|
+
fs2.mkdirSync(logDir, { recursive: true });
|
|
15881
16247
|
}
|
|
15882
16248
|
const timestamp = new Date().toISOString();
|
|
15883
16249
|
const message = getErrorMessage(error45);
|
|
@@ -15894,15 +16260,15 @@ ${stack}`] : [],
|
|
|
15894
16260
|
""
|
|
15895
16261
|
].join(`
|
|
15896
16262
|
`);
|
|
15897
|
-
|
|
16263
|
+
fs2.appendFileSync(logPath, entry, "utf-8");
|
|
15898
16264
|
} catch {}
|
|
15899
16265
|
}
|
|
15900
16266
|
function writeBufferedErrorLog(entry, projectDir) {
|
|
15901
16267
|
try {
|
|
15902
|
-
const logDir =
|
|
15903
|
-
const logPath =
|
|
15904
|
-
if (!
|
|
15905
|
-
|
|
16268
|
+
const logDir = path2.join(projectDir, ".opencode");
|
|
16269
|
+
const logPath = path2.join(logDir, "error-log.txt");
|
|
16270
|
+
if (!fs2.existsSync(logDir)) {
|
|
16271
|
+
fs2.mkdirSync(logDir, { recursive: true });
|
|
15906
16272
|
}
|
|
15907
16273
|
const timestamp = new Date().toISOString();
|
|
15908
16274
|
const contextStr = entry.context && Object.keys(entry.context).length > 0 ? `context: ${JSON.stringify(entry.context, null, 2)}` : "";
|
|
@@ -15915,29 +16281,29 @@ function writeBufferedErrorLog(entry, projectDir) {
|
|
|
15915
16281
|
""
|
|
15916
16282
|
].join(`
|
|
15917
16283
|
`);
|
|
15918
|
-
|
|
16284
|
+
fs2.appendFileSync(logPath, line, "utf-8");
|
|
15919
16285
|
} catch {}
|
|
15920
16286
|
}
|
|
15921
16287
|
|
|
15922
16288
|
// src/agents/index.ts
|
|
15923
16289
|
var AGENTS_DIR_CANDIDATES = [
|
|
15924
16290
|
import.meta.dir,
|
|
15925
|
-
|
|
15926
|
-
|
|
15927
|
-
|
|
16291
|
+
path3.join(import.meta.dir, "../src/agents"),
|
|
16292
|
+
path3.join(import.meta.dir, "../../src/agents"),
|
|
16293
|
+
path3.join(import.meta.dir, "../agents")
|
|
15928
16294
|
];
|
|
15929
16295
|
function resolveAgentsDir() {
|
|
15930
16296
|
for (const dir of AGENTS_DIR_CANDIDATES) {
|
|
15931
|
-
if (!
|
|
16297
|
+
if (!fs3.existsSync(dir))
|
|
15932
16298
|
continue;
|
|
15933
16299
|
try {
|
|
15934
|
-
const hasAgentFiles =
|
|
16300
|
+
const hasAgentFiles = fs3.readdirSync(dir).some((f) => f.endsWith(".md") && f !== "AGENTS.md");
|
|
15935
16301
|
if (hasAgentFiles)
|
|
15936
16302
|
return dir;
|
|
15937
16303
|
} catch {}
|
|
15938
16304
|
}
|
|
15939
16305
|
for (const dir of AGENTS_DIR_CANDIDATES) {
|
|
15940
|
-
if (
|
|
16306
|
+
if (fs3.existsSync(dir)) {
|
|
15941
16307
|
return dir;
|
|
15942
16308
|
}
|
|
15943
16309
|
}
|
|
@@ -15946,7 +16312,7 @@ function resolveAgentsDir() {
|
|
|
15946
16312
|
var VALID_MODES = new Set(["subagent", "primary", "all"]);
|
|
15947
16313
|
function validateFrontmatter(frontmatter, filePath) {
|
|
15948
16314
|
const warnings = [];
|
|
15949
|
-
const name =
|
|
16315
|
+
const name = path3.basename(filePath, ".md");
|
|
15950
16316
|
if (!frontmatter.description) {
|
|
15951
16317
|
warnings.push(`[${name}] Missing 'description' \u2014 agent will have empty description`);
|
|
15952
16318
|
}
|
|
@@ -15969,7 +16335,7 @@ function validateFrontmatter(frontmatter, filePath) {
|
|
|
15969
16335
|
}
|
|
15970
16336
|
function parseAgentMarkdown(filePath) {
|
|
15971
16337
|
try {
|
|
15972
|
-
const content =
|
|
16338
|
+
const content = fs3.readFileSync(filePath, "utf-8");
|
|
15973
16339
|
const { data: frontmatter, content: body } = import_gray_matter.default(content);
|
|
15974
16340
|
const warnings = validateFrontmatter(frontmatter, filePath);
|
|
15975
16341
|
for (const warning of warnings) {
|
|
@@ -16005,13 +16371,13 @@ function parseAgentMarkdown(filePath) {
|
|
|
16005
16371
|
function loadAgents() {
|
|
16006
16372
|
const agents = {};
|
|
16007
16373
|
const agentsDir = resolveAgentsDir();
|
|
16008
|
-
if (!
|
|
16374
|
+
if (!fs3.existsSync(agentsDir)) {
|
|
16009
16375
|
return agents;
|
|
16010
16376
|
}
|
|
16011
|
-
const files =
|
|
16377
|
+
const files = fs3.readdirSync(agentsDir).filter((f) => f.endsWith(".md") && f !== "AGENTS.md").sort();
|
|
16012
16378
|
for (const file2 of files) {
|
|
16013
|
-
const agentName =
|
|
16014
|
-
const agentPath =
|
|
16379
|
+
const agentName = path3.basename(file2, ".md");
|
|
16380
|
+
const agentPath = path3.join(agentsDir, file2);
|
|
16015
16381
|
const agent = parseAgentMarkdown(agentPath);
|
|
16016
16382
|
if (agent) {
|
|
16017
16383
|
agents[agentName] = agent;
|
|
@@ -16022,10 +16388,10 @@ function loadAgents() {
|
|
|
16022
16388
|
var _cachedAgents = null;
|
|
16023
16389
|
var _cachedAgentsFingerprint = "";
|
|
16024
16390
|
function getAgentsFingerprint(agentsDir) {
|
|
16025
|
-
const files =
|
|
16391
|
+
const files = fs3.readdirSync(agentsDir).filter((f) => f.endsWith(".md") && f !== "AGENTS.md").sort();
|
|
16026
16392
|
const parts = files.map((file2) => {
|
|
16027
|
-
const fullPath =
|
|
16028
|
-
const stat =
|
|
16393
|
+
const fullPath = path3.join(agentsDir, file2);
|
|
16394
|
+
const stat = fs3.statSync(fullPath);
|
|
16029
16395
|
const size = stat.size;
|
|
16030
16396
|
return `${file2}:${stat.mtimeMs}:${size}`;
|
|
16031
16397
|
});
|
|
@@ -16047,16 +16413,16 @@ function getBuiltinAgents() {
|
|
|
16047
16413
|
|
|
16048
16414
|
// src/commands/index.ts
|
|
16049
16415
|
var import_gray_matter2 = __toESM(require_gray_matter(), 1);
|
|
16050
|
-
import * as
|
|
16051
|
-
import * as
|
|
16416
|
+
import * as fs4 from "fs";
|
|
16417
|
+
import * as path4 from "path";
|
|
16052
16418
|
var COMMANDS_DIR_CANDIDATES = [
|
|
16053
|
-
|
|
16054
|
-
|
|
16055
|
-
|
|
16419
|
+
path4.join(import.meta.dir, "../command"),
|
|
16420
|
+
path4.join(import.meta.dir, "../../command"),
|
|
16421
|
+
path4.join(import.meta.dir, "../../../command")
|
|
16056
16422
|
];
|
|
16057
16423
|
function resolveCommandsDir() {
|
|
16058
16424
|
for (const dir of COMMANDS_DIR_CANDIDATES) {
|
|
16059
|
-
if (
|
|
16425
|
+
if (fs4.existsSync(dir)) {
|
|
16060
16426
|
return dir;
|
|
16061
16427
|
}
|
|
16062
16428
|
}
|
|
@@ -16064,7 +16430,7 @@ function resolveCommandsDir() {
|
|
|
16064
16430
|
}
|
|
16065
16431
|
function parseCommandMarkdown(filePath) {
|
|
16066
16432
|
try {
|
|
16067
|
-
const content =
|
|
16433
|
+
const content = fs4.readFileSync(filePath, "utf-8");
|
|
16068
16434
|
const { data: frontmatter, content: body } = import_gray_matter2.default(content);
|
|
16069
16435
|
const config2 = {
|
|
16070
16436
|
description: frontmatter.description || "",
|
|
@@ -16091,13 +16457,13 @@ function parseCommandMarkdown(filePath) {
|
|
|
16091
16457
|
function loadCommands() {
|
|
16092
16458
|
const commands = {};
|
|
16093
16459
|
const commandsDir = resolveCommandsDir();
|
|
16094
|
-
if (!
|
|
16460
|
+
if (!fs4.existsSync(commandsDir)) {
|
|
16095
16461
|
return commands;
|
|
16096
16462
|
}
|
|
16097
|
-
const files =
|
|
16463
|
+
const files = fs4.readdirSync(commandsDir).filter((f) => f.endsWith(".md")).sort();
|
|
16098
16464
|
for (const file2 of files) {
|
|
16099
|
-
const commandName =
|
|
16100
|
-
const commandPath =
|
|
16465
|
+
const commandName = path4.basename(file2, ".md");
|
|
16466
|
+
const commandPath = path4.join(commandsDir, file2);
|
|
16101
16467
|
const command = parseCommandMarkdown(commandPath);
|
|
16102
16468
|
if (command) {
|
|
16103
16469
|
commands[commandName] = command;
|
|
@@ -16108,10 +16474,10 @@ function loadCommands() {
|
|
|
16108
16474
|
var _cachedCommands = null;
|
|
16109
16475
|
var _cachedCommandsFingerprint = "";
|
|
16110
16476
|
function getCommandsFingerprint(commandsDir) {
|
|
16111
|
-
const files =
|
|
16477
|
+
const files = fs4.readdirSync(commandsDir).filter((f) => f.endsWith(".md")).sort();
|
|
16112
16478
|
const parts = files.map((file2) => {
|
|
16113
|
-
const fullPath =
|
|
16114
|
-
const stat =
|
|
16479
|
+
const fullPath = path4.join(commandsDir, file2);
|
|
16480
|
+
const stat = fs4.statSync(fullPath);
|
|
16115
16481
|
return `${file2}:${stat.mtimeMs}`;
|
|
16116
16482
|
});
|
|
16117
16483
|
return parts.join("|");
|
|
@@ -16132,16 +16498,16 @@ function getBuiltinCommands() {
|
|
|
16132
16498
|
|
|
16133
16499
|
// src/skills/index.ts
|
|
16134
16500
|
var import_gray_matter3 = __toESM(require_gray_matter(), 1);
|
|
16135
|
-
import * as
|
|
16136
|
-
import * as
|
|
16501
|
+
import * as fs5 from "fs";
|
|
16502
|
+
import * as path5 from "path";
|
|
16137
16503
|
var SKILLS_DIR_CANDIDATES = [
|
|
16138
|
-
|
|
16139
|
-
|
|
16140
|
-
|
|
16504
|
+
path5.join(import.meta.dir, "../skill"),
|
|
16505
|
+
path5.join(import.meta.dir, "../../skill"),
|
|
16506
|
+
path5.join(import.meta.dir, "../../../skill")
|
|
16141
16507
|
];
|
|
16142
16508
|
function resolveSkillsDir() {
|
|
16143
16509
|
for (const dir of SKILLS_DIR_CANDIDATES) {
|
|
16144
|
-
if (
|
|
16510
|
+
if (fs5.existsSync(dir)) {
|
|
16145
16511
|
return dir;
|
|
16146
16512
|
}
|
|
16147
16513
|
}
|
|
@@ -16150,23 +16516,23 @@ function resolveSkillsDir() {
|
|
|
16150
16516
|
function getBuiltinSkills() {
|
|
16151
16517
|
const skills = {};
|
|
16152
16518
|
const skillsDir = resolveSkillsDir();
|
|
16153
|
-
if (!
|
|
16519
|
+
if (!fs5.existsSync(skillsDir)) {
|
|
16154
16520
|
bufferInitError("skills", "warn", `Skills directory not found: ${skillsDir}`);
|
|
16155
16521
|
return skills;
|
|
16156
16522
|
}
|
|
16157
|
-
const skillDirs =
|
|
16523
|
+
const skillDirs = fs5.readdirSync(skillsDir, { withFileTypes: true });
|
|
16158
16524
|
for (const dirent of skillDirs) {
|
|
16159
16525
|
if (!dirent.isDirectory())
|
|
16160
16526
|
continue;
|
|
16161
16527
|
const skillName = dirent.name;
|
|
16162
|
-
const skillPath =
|
|
16163
|
-
const skillMdPath =
|
|
16164
|
-
if (!
|
|
16528
|
+
const skillPath = path5.join(skillsDir, skillName);
|
|
16529
|
+
const skillMdPath = path5.join(skillPath, "SKILL.md");
|
|
16530
|
+
if (!fs5.existsSync(skillMdPath)) {
|
|
16165
16531
|
bufferInitError("skills", "warn", `Missing SKILL.md for skill: ${skillName}`, { skillPath });
|
|
16166
16532
|
continue;
|
|
16167
16533
|
}
|
|
16168
16534
|
try {
|
|
16169
|
-
const fileContent =
|
|
16535
|
+
const fileContent = fs5.readFileSync(skillMdPath, "utf-8");
|
|
16170
16536
|
const { data, content } = import_gray_matter3.default(fileContent);
|
|
16171
16537
|
skills[skillName] = {
|
|
16172
16538
|
name: data.name || skillName,
|
|
@@ -16185,9 +16551,9 @@ function getBuiltinSkills() {
|
|
|
16185
16551
|
}
|
|
16186
16552
|
|
|
16187
16553
|
// src/config.ts
|
|
16188
|
-
import * as
|
|
16189
|
-
import * as
|
|
16190
|
-
import * as
|
|
16554
|
+
import * as fs6 from "fs";
|
|
16555
|
+
import * as path6 from "path";
|
|
16556
|
+
import * as os2 from "os";
|
|
16191
16557
|
var DEFAULT_CONFIG = {
|
|
16192
16558
|
disabled_agents: [],
|
|
16193
16559
|
disabled_commands: [],
|
|
@@ -16277,15 +16643,15 @@ var DEFAULT_CONFIG = {
|
|
|
16277
16643
|
};
|
|
16278
16644
|
function getUserConfigDir() {
|
|
16279
16645
|
if (process.platform === "win32") {
|
|
16280
|
-
return process.env.APPDATA ||
|
|
16646
|
+
return process.env.APPDATA || path6.join(os2.homedir(), "AppData", "Roaming");
|
|
16281
16647
|
}
|
|
16282
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
16648
|
+
return process.env.XDG_CONFIG_HOME || path6.join(os2.homedir(), ".config");
|
|
16283
16649
|
}
|
|
16284
16650
|
function getOpenCodeConfigDir() {
|
|
16285
16651
|
if (process.env.OPENCODE_CONFIG_DIR) {
|
|
16286
16652
|
return process.env.OPENCODE_CONFIG_DIR;
|
|
16287
16653
|
}
|
|
16288
|
-
return
|
|
16654
|
+
return path6.join(getUserConfigDir(), "opencode");
|
|
16289
16655
|
}
|
|
16290
16656
|
function stripJsonComments(content) {
|
|
16291
16657
|
let result = "";
|
|
@@ -16343,10 +16709,10 @@ function stripJsonComments(content) {
|
|
|
16343
16709
|
}
|
|
16344
16710
|
function loadJsonFile(filePath) {
|
|
16345
16711
|
try {
|
|
16346
|
-
if (!
|
|
16712
|
+
if (!fs6.existsSync(filePath)) {
|
|
16347
16713
|
return null;
|
|
16348
16714
|
}
|
|
16349
|
-
const content =
|
|
16715
|
+
const content = fs6.readFileSync(filePath, "utf-8");
|
|
16350
16716
|
try {
|
|
16351
16717
|
return JSON.parse(content);
|
|
16352
16718
|
} catch {
|
|
@@ -16380,12 +16746,12 @@ function loadCliKitConfig(projectDirectory) {
|
|
|
16380
16746
|
const userBaseDir = getOpenCodeConfigDir();
|
|
16381
16747
|
const projectBaseDirs = [
|
|
16382
16748
|
safeDir,
|
|
16383
|
-
|
|
16749
|
+
path6.join(safeDir, ".opencode")
|
|
16384
16750
|
];
|
|
16385
16751
|
const configCandidates = ["clikit.jsonc", "clikit.json", "clikit.config.json"];
|
|
16386
16752
|
let config2 = { ...DEFAULT_CONFIG };
|
|
16387
16753
|
for (const candidate of configCandidates) {
|
|
16388
|
-
const userConfigPath =
|
|
16754
|
+
const userConfigPath = path6.join(userBaseDir, candidate);
|
|
16389
16755
|
const userConfig = loadJsonFile(userConfigPath);
|
|
16390
16756
|
if (userConfig) {
|
|
16391
16757
|
config2 = deepMerge(config2, userConfig);
|
|
@@ -16394,7 +16760,7 @@ function loadCliKitConfig(projectDirectory) {
|
|
|
16394
16760
|
}
|
|
16395
16761
|
for (const baseDir of projectBaseDirs) {
|
|
16396
16762
|
for (const candidate of configCandidates) {
|
|
16397
|
-
const projectConfigPath =
|
|
16763
|
+
const projectConfigPath = path6.join(baseDir, candidate);
|
|
16398
16764
|
const projectConfig = loadJsonFile(projectConfigPath);
|
|
16399
16765
|
if (projectConfig) {
|
|
16400
16766
|
config2 = deepMerge(config2, projectConfig);
|
|
@@ -16904,8 +17270,8 @@ function formatTruncationLog(result) {
|
|
|
16904
17270
|
return `[CliKit:truncator] Truncated output: ${result.originalLines} \u2192 ${result.truncatedLines} lines, saved ${(saved / 1024).toFixed(1)}KB`;
|
|
16905
17271
|
}
|
|
16906
17272
|
// src/hooks/memory-digest.ts
|
|
16907
|
-
import * as
|
|
16908
|
-
import * as
|
|
17273
|
+
import * as fs7 from "fs";
|
|
17274
|
+
import * as path7 from "path";
|
|
16909
17275
|
import { Database } from "bun:sqlite";
|
|
16910
17276
|
function parseJsonArray(value) {
|
|
16911
17277
|
if (typeof value !== "string" || !value.trim())
|
|
@@ -16925,7 +17291,7 @@ function formatDate(iso) {
|
|
|
16925
17291
|
}
|
|
16926
17292
|
}
|
|
16927
17293
|
function writeTopicFile(memoryDir, type, heading, rows) {
|
|
16928
|
-
const topicPath =
|
|
17294
|
+
const topicPath = path7.join(memoryDir, `${type}.md`);
|
|
16929
17295
|
const lines = [];
|
|
16930
17296
|
lines.push(`# ${heading}`);
|
|
16931
17297
|
lines.push("");
|
|
@@ -16966,16 +17332,16 @@ function writeTopicFile(memoryDir, type, heading, rows) {
|
|
|
16966
17332
|
lines.push("---");
|
|
16967
17333
|
lines.push("");
|
|
16968
17334
|
}
|
|
16969
|
-
|
|
17335
|
+
fs7.writeFileSync(topicPath, lines.join(`
|
|
16970
17336
|
`), "utf-8");
|
|
16971
17337
|
}
|
|
16972
17338
|
function generateMemoryDigest(projectDir, config2) {
|
|
16973
17339
|
const result = { written: false, path: "", counts: {} };
|
|
16974
17340
|
if (typeof projectDir !== "string" || !projectDir)
|
|
16975
17341
|
return result;
|
|
16976
|
-
const memoryDir =
|
|
16977
|
-
const dbPath =
|
|
16978
|
-
if (!
|
|
17342
|
+
const memoryDir = path7.join(projectDir, ".opencode", "memory");
|
|
17343
|
+
const dbPath = path7.join(memoryDir, "memory.db");
|
|
17344
|
+
if (!fs7.existsSync(dbPath)) {
|
|
16979
17345
|
return result;
|
|
16980
17346
|
}
|
|
16981
17347
|
const compactMode = config2?.compact_mode !== false;
|
|
@@ -17040,14 +17406,14 @@ function generateMemoryDigest(projectDir, config2) {
|
|
|
17040
17406
|
sections.push("*No observations found in memory database.*");
|
|
17041
17407
|
sections.push("");
|
|
17042
17408
|
}
|
|
17043
|
-
const digestPath =
|
|
17409
|
+
const digestPath = path7.join(memoryDir, "_digest.md");
|
|
17044
17410
|
const content = sections.join(`
|
|
17045
17411
|
`);
|
|
17046
17412
|
try {
|
|
17047
|
-
if (!
|
|
17048
|
-
|
|
17413
|
+
if (!fs7.existsSync(memoryDir)) {
|
|
17414
|
+
fs7.mkdirSync(memoryDir, { recursive: true });
|
|
17049
17415
|
}
|
|
17050
|
-
|
|
17416
|
+
fs7.writeFileSync(digestPath, content, "utf-8");
|
|
17051
17417
|
result.written = true;
|
|
17052
17418
|
result.path = digestPath;
|
|
17053
17419
|
} catch {}
|
|
@@ -17061,8 +17427,8 @@ function formatDigestLog(result) {
|
|
|
17061
17427
|
return `[CliKit:memory-digest] Generated digest: ${parts || "empty"}`;
|
|
17062
17428
|
}
|
|
17063
17429
|
// src/hooks/todo-beads-sync.ts
|
|
17064
|
-
import * as
|
|
17065
|
-
import * as
|
|
17430
|
+
import * as fs8 from "fs";
|
|
17431
|
+
import * as path8 from "path";
|
|
17066
17432
|
import { Database as Database2 } from "bun:sqlite";
|
|
17067
17433
|
import { execFile } from "child_process";
|
|
17068
17434
|
import { promisify } from "util";
|
|
@@ -17217,8 +17583,8 @@ function syncTodosToBeads(projectDirectory, sessionID, todos, config2) {
|
|
|
17217
17583
|
skippedReason: "Todo sync disabled; Beads is authoritative"
|
|
17218
17584
|
};
|
|
17219
17585
|
}
|
|
17220
|
-
const beadsDbPath =
|
|
17221
|
-
if (!
|
|
17586
|
+
const beadsDbPath = path8.join(projectDirectory, ".beads", "beads.db");
|
|
17587
|
+
if (!fs8.existsSync(beadsDbPath)) {
|
|
17222
17588
|
return {
|
|
17223
17589
|
synced: false,
|
|
17224
17590
|
sessionID,
|
|
@@ -17248,7 +17614,7 @@ function syncTodosToBeads(projectDirectory, sessionID, todos, config2) {
|
|
|
17248
17614
|
throw lastError instanceof Error ? lastError : new Error("Todo-Beads sync failed after retries");
|
|
17249
17615
|
}
|
|
17250
17616
|
function flushBeadsJsonl(projectDirectory, result) {
|
|
17251
|
-
const jsonlPath =
|
|
17617
|
+
const jsonlPath = path8.join(projectDirectory, ".beads", "issues.jsonl");
|
|
17252
17618
|
execFileAsync("bd", ["export", "--force", "-o", jsonlPath], {
|
|
17253
17619
|
cwd: projectDirectory,
|
|
17254
17620
|
timeout: 5000
|
|
@@ -17265,8 +17631,8 @@ function formatTodoBeadsSyncLog(result) {
|
|
|
17265
17631
|
return `[CliKit:todo-beads-sync] session=${result.sessionID} todos=${result.totalTodos} created=${result.created} updated=${result.updated} closed=${result.closed}`;
|
|
17266
17632
|
}
|
|
17267
17633
|
// src/hooks/beads-context.ts
|
|
17268
|
-
import * as
|
|
17269
|
-
import * as
|
|
17634
|
+
import * as fs9 from "fs";
|
|
17635
|
+
import * as path9 from "path";
|
|
17270
17636
|
import { Database as Database3 } from "bun:sqlite";
|
|
17271
17637
|
var BEADS_CONTEXT_BUSY_TIMEOUT_MS = 2000;
|
|
17272
17638
|
var PRIORITY_LABELS = {
|
|
@@ -17282,8 +17648,8 @@ var STATUS_ICONS = {
|
|
|
17282
17648
|
closed: "\u2713"
|
|
17283
17649
|
};
|
|
17284
17650
|
function openBeadsDbReadonly(projectDirectory) {
|
|
17285
|
-
const beadsDbPath =
|
|
17286
|
-
if (!
|
|
17651
|
+
const beadsDbPath = path9.join(projectDirectory, ".beads", "beads.db");
|
|
17652
|
+
if (!fs9.existsSync(beadsDbPath)) {
|
|
17287
17653
|
return null;
|
|
17288
17654
|
}
|
|
17289
17655
|
try {
|
|
@@ -17440,8 +17806,8 @@ function shouldAttemptTilthForTool(toolName, toolInput) {
|
|
|
17440
17806
|
const normalized = toolName.toLowerCase();
|
|
17441
17807
|
if (!normalized.includes("read"))
|
|
17442
17808
|
return false;
|
|
17443
|
-
const
|
|
17444
|
-
return typeof
|
|
17809
|
+
const path10 = extractFilePath(toolInput);
|
|
17810
|
+
return typeof path10 === "string" && path10.length > 0;
|
|
17445
17811
|
}
|
|
17446
17812
|
function extractFilePath(toolInput) {
|
|
17447
17813
|
for (const key of ["filePath", "file_path", "path", "file"]) {
|
|
@@ -17527,12 +17893,12 @@ import { execFile as execFile2 } from "child_process";
|
|
|
17527
17893
|
import { promisify as promisify2 } from "util";
|
|
17528
17894
|
|
|
17529
17895
|
// src/tools/memory-db.ts
|
|
17530
|
-
import * as
|
|
17531
|
-
import * as
|
|
17896
|
+
import * as fs10 from "fs";
|
|
17897
|
+
import * as path10 from "path";
|
|
17532
17898
|
import { Database as Database4 } from "bun:sqlite";
|
|
17533
17899
|
function getMemoryPaths(projectDir = process.cwd()) {
|
|
17534
|
-
const memoryDir =
|
|
17535
|
-
const memoryDbPath =
|
|
17900
|
+
const memoryDir = path10.join(projectDir, ".opencode", "memory");
|
|
17901
|
+
const memoryDbPath = path10.join(memoryDir, "memory.db");
|
|
17536
17902
|
return { memoryDir, memoryDbPath };
|
|
17537
17903
|
}
|
|
17538
17904
|
function ensureObservationSchema(db) {
|
|
@@ -17594,8 +17960,8 @@ function ensureObservationSchema(db) {
|
|
|
17594
17960
|
function openMemoryDb(options2 = {}) {
|
|
17595
17961
|
const { projectDir, readonly: readonly2 = false } = options2;
|
|
17596
17962
|
const { memoryDir, memoryDbPath } = getMemoryPaths(projectDir);
|
|
17597
|
-
if (!readonly2 && !
|
|
17598
|
-
|
|
17963
|
+
if (!readonly2 && !fs10.existsSync(memoryDir)) {
|
|
17964
|
+
fs10.mkdirSync(memoryDir, { recursive: true });
|
|
17599
17965
|
}
|
|
17600
17966
|
const db = new Database4(memoryDbPath, readonly2 ? { readonly: true } : undefined);
|
|
17601
17967
|
if (!readonly2) {
|
|
@@ -17953,6 +18319,49 @@ function buildSummary(sections, maxTokens) {
|
|
|
17953
18319
|
|
|
17954
18320
|
// src/index.ts
|
|
17955
18321
|
var execFileAsync3 = promisify3(execFile3);
|
|
18322
|
+
var DCP_PLUGIN_ENTRY2 = "@tarquinen/opencode-dcp@beta";
|
|
18323
|
+
var DCP_PLUGIN_BASE = "@tarquinen/opencode-dcp";
|
|
18324
|
+
function ensureDcpInConfig() {
|
|
18325
|
+
try {
|
|
18326
|
+
const configDir = (() => {
|
|
18327
|
+
if (process.env.OPENCODE_CONFIG_DIR)
|
|
18328
|
+
return process.env.OPENCODE_CONFIG_DIR;
|
|
18329
|
+
const home = (() => {
|
|
18330
|
+
if (process.env.SNAP_REAL_HOME)
|
|
18331
|
+
return process.env.SNAP_REAL_HOME;
|
|
18332
|
+
const h = os3.homedir();
|
|
18333
|
+
const m = h.match(/^(\/home\/[^/]+)\/snap\//);
|
|
18334
|
+
return m ? m[1] : h;
|
|
18335
|
+
})();
|
|
18336
|
+
if (process.platform === "win32") {
|
|
18337
|
+
return path11.join(process.env.APPDATA || path11.join(home, "AppData", "Roaming"), "opencode");
|
|
18338
|
+
}
|
|
18339
|
+
return path11.join(process.env.XDG_CONFIG_HOME || path11.join(home, ".config"), "opencode");
|
|
18340
|
+
})();
|
|
18341
|
+
const jsoncPath = path11.join(configDir, "opencode.jsonc");
|
|
18342
|
+
const jsonPath = path11.join(configDir, "opencode.json");
|
|
18343
|
+
const configPath = fs11.existsSync(jsoncPath) ? jsoncPath : jsonPath;
|
|
18344
|
+
if (!fs11.existsSync(configPath))
|
|
18345
|
+
return;
|
|
18346
|
+
const raw = fs11.readFileSync(configPath, "utf-8");
|
|
18347
|
+
let config2;
|
|
18348
|
+
try {
|
|
18349
|
+
config2 = JSON.parse(raw);
|
|
18350
|
+
} catch {
|
|
18351
|
+
const cleaned = raw.replace(/\/\*[\s\S]*?\*\//g, "").replace(/,\s*([}\]])/g, "$1");
|
|
18352
|
+
config2 = JSON.parse(cleaned);
|
|
18353
|
+
}
|
|
18354
|
+
const plugins = Array.isArray(config2.plugin) ? config2.plugin.filter((p) => typeof p === "string") : [];
|
|
18355
|
+
const hasDcp = plugins.some((p) => p === DCP_PLUGIN_BASE || p.startsWith(`${DCP_PLUGIN_BASE}@`));
|
|
18356
|
+
if (hasDcp)
|
|
18357
|
+
return;
|
|
18358
|
+
const updated = upsertPluginEntry(plugins, DCP_PLUGIN_ENTRY2);
|
|
18359
|
+
const tmpPath = `${configPath}.tmp`;
|
|
18360
|
+
fs11.writeFileSync(tmpPath, JSON.stringify({ ...config2, plugin: updated }, null, 2) + `
|
|
18361
|
+
`);
|
|
18362
|
+
fs11.renameSync(tmpPath, configPath);
|
|
18363
|
+
} catch {}
|
|
18364
|
+
}
|
|
17956
18365
|
var CliKitPlugin = async (ctx) => {
|
|
17957
18366
|
const todosBySession = new Map;
|
|
17958
18367
|
const defaultMcpEntries = {
|
|
@@ -18209,6 +18618,7 @@ ${(content || "").trim()}`.trim();
|
|
|
18209
18618
|
].join(`
|
|
18210
18619
|
`);
|
|
18211
18620
|
}
|
|
18621
|
+
ensureDcpInConfig();
|
|
18212
18622
|
const pluginConfig = loadCliKitConfig(ctx.directory) ?? {};
|
|
18213
18623
|
const debugLogsEnabled = pluginConfig.hooks?.session_logging === true && process.env.CLIKIT_DEBUG === "1";
|
|
18214
18624
|
const toolLogsEnabled = pluginConfig.hooks?.tool_logging === true && process.env.CLIKIT_DEBUG === "1";
|