opendevbrowser 0.0.21 → 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +12 -2
  2. package/dist/chunk-3ILXPKSJ.js +86 -0
  3. package/dist/chunk-3ILXPKSJ.js.map +1 -0
  4. package/dist/{chunk-4KVXCXV3.js → chunk-OGE5KJ4X.js} +10 -6
  5. package/dist/{chunk-4KVXCXV3.js.map → chunk-OGE5KJ4X.js.map} +1 -1
  6. package/dist/chunk-QVWOPIZJ.js +612 -0
  7. package/dist/chunk-QVWOPIZJ.js.map +1 -0
  8. package/dist/{chunk-3VA6XR25.js → chunk-STGGGVYT.js} +23 -100
  9. package/dist/chunk-STGGGVYT.js.map +1 -0
  10. package/dist/cli/commands/uninstall.d.ts +1 -0
  11. package/dist/cli/commands/uninstall.d.ts.map +1 -1
  12. package/dist/cli/index.js +249 -614
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/cli/installers/postinstall-skill-sync.d.ts +15 -0
  15. package/dist/cli/installers/postinstall-skill-sync.d.ts.map +1 -0
  16. package/dist/cli/installers/postinstall-skill-sync.js +48 -0
  17. package/dist/cli/installers/postinstall-skill-sync.js.map +1 -0
  18. package/dist/cli/installers/skills.d.ts +9 -14
  19. package/dist/cli/installers/skills.d.ts.map +1 -1
  20. package/dist/cli/skill-lifecycle.d.ts +26 -0
  21. package/dist/cli/skill-lifecycle.d.ts.map +1 -0
  22. package/dist/cli/update-skill-modes.d.ts +3 -0
  23. package/dist/cli/update-skill-modes.d.ts.map +1 -0
  24. package/dist/index.js +3 -2
  25. package/dist/index.js.map +1 -1
  26. package/dist/opendevbrowser.js +3 -2
  27. package/dist/opendevbrowser.js.map +1 -1
  28. package/dist/public-surface/generated-manifest.d.ts +3 -3
  29. package/dist/public-surface/generated-manifest.d.ts.map +1 -1
  30. package/dist/public-surface/source.d.ts +4 -4
  31. package/dist/skills/skill-loader.js +2 -1
  32. package/extension/manifest.json +1 -1
  33. package/package.json +6 -4
  34. package/scripts/postinstall-sync-skills.mjs +33 -0
  35. package/dist/chunk-3VA6XR25.js.map +0 -1
package/dist/cli/index.js CHANGED
@@ -31,11 +31,26 @@ import {
31
31
  resolveExitCode,
32
32
  startDaemon,
33
33
  toCliError
34
- } from "../chunk-4KVXCXV3.js";
34
+ } from "../chunk-OGE5KJ4X.js";
35
+ import "../chunk-STGGGVYT.js";
35
36
  import {
36
- getBundledSkillsDir,
37
- listBundledSkillDirectories
38
- } from "../chunk-3VA6XR25.js";
37
+ createNoOpSkillRemovalResult,
38
+ ensureDir,
39
+ getBundledSkillLifecycleTargets,
40
+ getBundledSkillTargets,
41
+ getGlobalConfigPath,
42
+ getLocalConfigPath,
43
+ hasBundledSkillArtifacts,
44
+ hasManagedBundledSkillInstall,
45
+ hasPlugin,
46
+ readConfig,
47
+ removeBundledSkillsForTargets,
48
+ removePluginFromContent,
49
+ syncBundledSkills,
50
+ syncBundledSkillsForTargets,
51
+ updateConfigContent
52
+ } from "../chunk-QVWOPIZJ.js";
53
+ import "../chunk-3ILXPKSJ.js";
39
54
  import {
40
55
  writeFileAtomic
41
56
  } from "../chunk-TBUCZX4A.js";
@@ -706,86 +721,12 @@ function getCommand(name) {
706
721
  }
707
722
 
708
723
  // src/cli/installers/global.ts
709
- import * as fs3 from "fs";
724
+ import * as fs2 from "fs";
710
725
 
711
- // src/cli/utils/config.ts
726
+ // src/cli/templates/config.ts
712
727
  import * as fs from "fs";
713
728
  import * as path from "path";
714
729
  import * as os from "os";
715
- import { parse as parseJsonc, modify, applyEdits } from "jsonc-parser";
716
- var PLUGIN_NAME = "opendevbrowser";
717
- var SCHEMA_URL = "https://opencode.ai/config.json";
718
- function getGlobalConfigPath() {
719
- const configDir = process.env.OPENCODE_CONFIG_DIR || path.join(os.homedir(), ".config", "opencode");
720
- return path.join(configDir, "opencode.json");
721
- }
722
- function getLocalConfigPath() {
723
- return path.join(process.cwd(), "opencode.json");
724
- }
725
- function ensureDir(dirPath) {
726
- if (!fs.existsSync(dirPath)) {
727
- fs.mkdirSync(dirPath, { recursive: true });
728
- }
729
- }
730
- function readConfig(configPath) {
731
- if (!fs.existsSync(configPath)) {
732
- return { content: "", config: {} };
733
- }
734
- const content = fs.readFileSync(configPath, "utf-8");
735
- const errors = [];
736
- const parsed = parseJsonc(content, errors, { allowTrailingComma: true });
737
- if (errors.length > 0) {
738
- const firstError = errors[0];
739
- throw new Error(`Invalid JSONC at ${configPath}: parse error at offset ${firstError?.offset ?? 0}`);
740
- }
741
- return { content, config: parsed ?? {} };
742
- }
743
- function hasPlugin(config, pluginName = PLUGIN_NAME) {
744
- return config.plugin?.includes(pluginName) ?? false;
745
- }
746
- function createConfigWithPlugin(pluginName = PLUGIN_NAME) {
747
- return {
748
- $schema: SCHEMA_URL,
749
- plugin: [pluginName]
750
- };
751
- }
752
- function updateConfigContent(content, pluginName = PLUGIN_NAME) {
753
- if (!content.trim()) {
754
- return JSON.stringify(createConfigWithPlugin(pluginName), null, 2) + "\n";
755
- }
756
- const parsed = parseJsonc(content, [], { allowTrailingComma: true }) ?? {};
757
- if (parsed.plugin?.includes(pluginName)) {
758
- return content;
759
- }
760
- let result = content;
761
- if (!parsed.$schema) {
762
- const edits2 = modify(result, ["$schema"], SCHEMA_URL, { formattingOptions: { tabSize: 2, insertSpaces: true } });
763
- result = applyEdits(result, edits2);
764
- }
765
- const newPlugins = parsed.plugin ? [...parsed.plugin, pluginName] : [pluginName];
766
- const edits = modify(result, ["plugin"], newPlugins, { formattingOptions: { tabSize: 2, insertSpaces: true } });
767
- result = applyEdits(result, edits);
768
- return result;
769
- }
770
- function removePluginFromContent(content, pluginName = PLUGIN_NAME) {
771
- if (!content.trim()) {
772
- return content;
773
- }
774
- const parsed = parseJsonc(content, [], { allowTrailingComma: true }) ?? {};
775
- if (!parsed.plugin?.includes(pluginName)) {
776
- return content;
777
- }
778
- const newPlugins = parsed.plugin.filter((p) => p !== pluginName);
779
- const edits = modify(content, ["plugin"], newPlugins.length > 0 ? newPlugins : void 0, {
780
- formattingOptions: { tabSize: 2, insertSpaces: true }
781
- });
782
- return applyEdits(content, edits);
783
- }
784
-
785
- // src/cli/templates/config.ts
786
- import * as fs2 from "fs";
787
- import * as path2 from "path";
788
- import * as os2 from "os";
789
730
  function buildConfigTemplate(relayToken, daemonToken) {
790
731
  return `{
791
732
  // OpenDevBrowser Plugin Configuration
@@ -862,19 +803,19 @@ function buildConfigTemplate(relayToken, daemonToken) {
862
803
  }
863
804
  function getPluginConfigPath(mode) {
864
805
  if (mode === "global") {
865
- const configDir = process.env.OPENCODE_CONFIG_DIR || path2.join(os2.homedir(), ".config", "opencode");
866
- return path2.join(configDir, "opendevbrowser.jsonc");
806
+ const configDir = process.env.OPENCODE_CONFIG_DIR || path.join(os.homedir(), ".config", "opencode");
807
+ return path.join(configDir, "opendevbrowser.jsonc");
867
808
  }
868
- return path2.join(process.cwd(), "opendevbrowser.jsonc");
809
+ return path.join(process.cwd(), "opendevbrowser.jsonc");
869
810
  }
870
811
  function createPluginConfig(mode) {
871
812
  const configPath = getPluginConfigPath(mode);
872
- if (fs2.existsSync(configPath)) {
813
+ if (fs.existsSync(configPath)) {
873
814
  return { created: false, path: configPath };
874
815
  }
875
- const dir = path2.dirname(configPath);
876
- if (!fs2.existsSync(dir)) {
877
- fs2.mkdirSync(dir, { recursive: true });
816
+ const dir = path.dirname(configPath);
817
+ if (!fs.existsSync(dir)) {
818
+ fs.mkdirSync(dir, { recursive: true });
878
819
  }
879
820
  const relayToken = generateSecureToken();
880
821
  const daemonToken = generateSecureToken();
@@ -898,7 +839,7 @@ function installGlobal(withConfig = false) {
898
839
  }
899
840
  const newContent = updateConfigContent(content, "opendevbrowser");
900
841
  ensureDir(configPath.replace(/[/\\][^/\\]+$/, ""));
901
- fs3.writeFileSync(configPath, newContent, "utf-8");
842
+ fs2.writeFileSync(configPath, newContent, "utf-8");
902
843
  if (withConfig) {
903
844
  createPluginConfig("global");
904
845
  }
@@ -922,7 +863,7 @@ function installGlobal(withConfig = false) {
922
863
  }
923
864
 
924
865
  // src/cli/installers/local.ts
925
- import * as fs4 from "fs";
866
+ import * as fs3 from "fs";
926
867
  function installLocal(withConfig = false) {
927
868
  const configPath = getLocalConfigPath();
928
869
  try {
@@ -937,7 +878,7 @@ function installLocal(withConfig = false) {
937
878
  };
938
879
  }
939
880
  const newContent = updateConfigContent(content, "opendevbrowser");
940
- fs4.writeFileSync(configPath, newContent, "utf-8");
881
+ fs3.writeFileSync(configPath, newContent, "utf-8");
941
882
  if (withConfig) {
942
883
  createPluginConfig("local");
943
884
  }
@@ -960,407 +901,32 @@ function installLocal(withConfig = false) {
960
901
  }
961
902
  }
962
903
 
963
- // src/cli/installers/skills.ts
964
- import * as crypto from "crypto";
965
- import * as fs5 from "fs";
966
- import * as path4 from "path";
967
-
968
- // src/cli/utils/skills.ts
969
- import * as path3 from "path";
970
- import * as os3 from "os";
971
- var SKILL_DIR_NAME = "skill";
972
- var SKILLS_DIR_NAME = "skills";
973
- function getGlobalSkillDir() {
974
- const configDir = process.env.OPENCODE_CONFIG_DIR || path3.join(os3.homedir(), ".config", "opencode");
975
- return path3.join(configDir, SKILL_DIR_NAME);
976
- }
977
- function getLocalSkillDir() {
978
- return path3.join(process.cwd(), ".opencode", SKILL_DIR_NAME);
979
- }
980
- function getCodexHomeDir() {
981
- return process.env.CODEX_HOME || path3.join(os3.homedir(), ".codex");
982
- }
983
- function getClaudeCodeHomeDir() {
984
- return process.env.CLAUDECODE_HOME || path3.join(os3.homedir(), ".claude");
985
- }
986
- function getAmpHomeDir() {
987
- return process.env.AMP_CLI_HOME || path3.join(os3.homedir(), ".amp");
988
- }
989
- function dedupeTargets(targets) {
990
- const deduped = /* @__PURE__ */ new Map();
991
- for (const target of targets) {
992
- const key = path3.resolve(target.dir);
993
- const existing = deduped.get(key);
994
- if (existing) {
995
- if (!existing.agents.includes(target.agent)) {
996
- existing.agents.push(target.agent);
997
- }
998
- continue;
999
- }
1000
- deduped.set(key, { agents: [target.agent], dir: target.dir });
1001
- }
1002
- return Array.from(deduped.values());
1003
- }
1004
- function getGlobalSkillTargets() {
1005
- const claudeSkillsDir = path3.join(getClaudeCodeHomeDir(), SKILLS_DIR_NAME);
1006
- const ampSkillsDir = path3.join(getAmpHomeDir(), SKILLS_DIR_NAME);
1007
- return dedupeTargets([
1008
- { agent: "opencode", dir: getGlobalSkillDir() },
1009
- { agent: "codex", dir: path3.join(getCodexHomeDir(), SKILLS_DIR_NAME) },
1010
- { agent: "claudecode", dir: claudeSkillsDir },
1011
- { agent: "ampcli", dir: ampSkillsDir }
1012
- ]);
1013
- }
1014
- function getLocalSkillTargets() {
1015
- const localClaudeSkillsDir = path3.join(process.cwd(), ".claude", SKILLS_DIR_NAME);
1016
- const localAmpSkillsDir = path3.join(process.cwd(), ".amp", SKILLS_DIR_NAME);
1017
- return dedupeTargets([
1018
- { agent: "opencode", dir: getLocalSkillDir() },
1019
- { agent: "codex", dir: path3.join(process.cwd(), ".codex", SKILLS_DIR_NAME) },
1020
- { agent: "claudecode", dir: localClaudeSkillsDir },
1021
- { agent: "ampcli", dir: localAmpSkillsDir }
1022
- ]);
1023
- }
1024
-
1025
- // src/cli/installers/skills.ts
1026
- var LEGACY_ALIAS_DIRS = [
1027
- { name: "research", canonical: "opendevbrowser-research" },
1028
- { name: "shopping", canonical: "opendevbrowser-shopping" }
1029
- ];
1030
- function getTargets(mode) {
1031
- return mode === "global" ? getGlobalSkillTargets() : getLocalSkillTargets();
1032
- }
1033
- function getCanonicalBundledSkillNames() {
1034
- return listBundledSkillDirectories().map((entry) => entry.name);
1035
- }
1036
- function hasCanonicalBundledSkillInTarget(targetDir, packNames) {
1037
- return packNames.some((packName) => fs5.existsSync(path4.join(targetDir, packName)));
1038
- }
1039
- function formatSummary(parts, totalTargets, failures) {
1040
- const summary = parts.length > 0 ? parts.join(", ") : "no lifecycle changes";
1041
- const failureSummary = failures > 0 ? `, ${failures} failed` : "";
1042
- return `${summary} across ${totalTargets} targets${failureSummary}`;
1043
- }
1044
- function hashDirectoryTree(dirPath) {
1045
- const hash = crypto.createHash("sha256");
1046
- const visit = (currentPath, relativePath) => {
1047
- const entries = fs5.readdirSync(currentPath, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));
1048
- for (const entry of entries) {
1049
- const absolutePath = path4.join(currentPath, entry.name);
1050
- const entryRelativePath = relativePath ? path4.posix.join(relativePath, entry.name) : entry.name;
1051
- if (entry.isDirectory()) {
1052
- hash.update(`D:${entryRelativePath}\0`);
1053
- visit(absolutePath, entryRelativePath);
1054
- continue;
1055
- }
1056
- if (entry.isFile()) {
1057
- hash.update(`F:${entryRelativePath}\0`);
1058
- hash.update(fs5.readFileSync(absolutePath));
1059
- hash.update("\0");
1060
- continue;
1061
- }
1062
- if (entry.isSymbolicLink()) {
1063
- hash.update(`L:${entryRelativePath}\0${fs5.readlinkSync(absolutePath)}\0`);
1064
- }
1065
- }
1066
- };
1067
- visit(dirPath, "");
1068
- return hash.digest("hex");
1069
- }
1070
- function syncSkillDirectory(sourcePath, targetPath, sourceFingerprint) {
1071
- if (!fs5.existsSync(targetPath)) {
1072
- fs5.cpSync(sourcePath, targetPath, { recursive: true });
1073
- return "installed";
1074
- }
1075
- const targetFingerprint = hashDirectoryTree(targetPath);
1076
- if (targetFingerprint === sourceFingerprint) {
1077
- return "unchanged";
1078
- }
1079
- const parentDir = path4.dirname(targetPath);
1080
- const targetName = path4.basename(targetPath);
1081
- const stagingRoot = fs5.mkdtempSync(path4.join(parentDir, `.${targetName}-sync-`));
1082
- const stagedPath = path4.join(stagingRoot, targetName);
1083
- const backupPath = path4.join(stagingRoot, `${targetName}-backup`);
1084
- try {
1085
- fs5.cpSync(sourcePath, stagedPath, { recursive: true });
1086
- fs5.renameSync(targetPath, backupPath);
1087
- try {
1088
- fs5.renameSync(stagedPath, targetPath);
1089
- } catch (error) {
1090
- if (fs5.existsSync(backupPath) && !fs5.existsSync(targetPath)) {
1091
- fs5.renameSync(backupPath, targetPath);
1092
- }
1093
- throw error;
1094
- }
1095
- fs5.rmSync(backupPath, { recursive: true, force: true });
1096
- return "refreshed";
1097
- } finally {
1098
- if (fs5.existsSync(stagedPath)) {
1099
- fs5.rmSync(stagedPath, { recursive: true, force: true });
1100
- }
1101
- if (fs5.existsSync(backupPath)) {
1102
- fs5.rmSync(backupPath, { recursive: true, force: true });
1103
- }
1104
- fs5.rmSync(stagingRoot, { recursive: true, force: true });
1105
- }
1106
- }
1107
- function cleanupLegacyAlias(targetDir, aliasName) {
1108
- const aliasPath = path4.join(targetDir, aliasName);
1109
- if (!fs5.existsSync(aliasPath)) {
1110
- return { removed: [], preserved: [] };
1111
- }
1112
- let stats;
1113
- try {
1114
- stats = fs5.statSync(aliasPath);
1115
- } catch {
1116
- return {
1117
- removed: [],
1118
- preserved: [{ targetDir, name: aliasName, reason: "unknown_layout" }]
1119
- };
1120
- }
1121
- if (!stats.isDirectory()) {
1122
- return {
1123
- removed: [],
1124
- preserved: [{ targetDir, name: aliasName, reason: "unknown_layout" }]
1125
- };
1126
- }
1127
- if (fs5.existsSync(path4.join(aliasPath, "SKILL.md"))) {
1128
- return {
1129
- removed: [],
1130
- preserved: [{ targetDir, name: aliasName, reason: "contains_skill_md" }]
1131
- };
1132
- }
1133
- const entries = fs5.readdirSync(aliasPath);
1134
- if (entries.length === 0) {
1135
- fs5.rmSync(aliasPath, { recursive: true, force: true });
1136
- return { removed: [aliasName], preserved: [] };
1137
- }
1138
- return {
1139
- removed: [],
1140
- preserved: [{ targetDir, name: aliasName, reason: "non_empty" }]
1141
- };
1142
- }
1143
- function cleanupLegacyAliases(targetDir) {
1144
- const removed = [];
1145
- const preserved = [];
1146
- for (const alias of LEGACY_ALIAS_DIRS) {
1147
- const result = cleanupLegacyAlias(targetDir, alias.name);
1148
- removed.push(...result.removed);
1149
- preserved.push(...result.preserved);
1150
- }
1151
- return { removed, preserved };
1152
- }
1153
- function buildSyncMessage(mode, result) {
1154
- return `Skills ${mode} sync: ${formatSummary(
1155
- [
1156
- result.installed.length > 0 ? `${result.installed.length} installed` : "",
1157
- result.refreshed.length > 0 ? `${result.refreshed.length} refreshed` : "",
1158
- result.unchanged.length > 0 ? `${result.unchanged.length} unchanged` : "",
1159
- result.removedLegacyAliases.length > 0 ? `${result.removedLegacyAliases.length} legacy aliases removed` : "",
1160
- result.preservedLegacyAliases.length > 0 ? `${result.preservedLegacyAliases.length} legacy aliases preserved` : ""
1161
- ].filter(Boolean),
1162
- result.targets.length,
1163
- result.targets.filter((entry) => !entry.success).length
1164
- )}`;
1165
- }
1166
- function buildRemovalMessage(mode, result) {
1167
- return `Skills ${mode} removal: ${formatSummary(
1168
- [
1169
- result.removed.length > 0 ? `${result.removed.length} removed` : "",
1170
- result.missing.length > 0 ? `${result.missing.length} already absent` : "",
1171
- result.removedLegacyAliases.length > 0 ? `${result.removedLegacyAliases.length} legacy aliases removed` : "",
1172
- result.preservedLegacyAliases.length > 0 ? `${result.preservedLegacyAliases.length} legacy aliases preserved` : ""
1173
- ].filter(Boolean),
1174
- result.targets.length,
1175
- result.targets.filter((entry) => !entry.success).length
1176
- )}`;
1177
- }
1178
- function syncBundledSkills(mode) {
1179
- const targets = getTargets(mode);
1180
- const targetResults = [];
1181
- try {
1182
- const sourceDir = getBundledSkillsDir();
1183
- const packNames = getCanonicalBundledSkillNames();
1184
- const bundledFingerprints = /* @__PURE__ */ new Map();
1185
- for (const packName of packNames) {
1186
- const sourcePath = path4.join(sourceDir, packName);
1187
- if (!fs5.existsSync(sourcePath)) {
1188
- throw new Error(`Bundled skill directory missing: ${packName}`);
1189
- }
1190
- bundledFingerprints.set(packName, hashDirectoryTree(sourcePath));
1191
- }
1192
- for (const target of targets) {
1193
- const installed = [];
1194
- const refreshed = [];
1195
- const unchanged = [];
1196
- const removedLegacyAliases = [];
1197
- const preservedLegacyAliases = [];
1198
- try {
1199
- ensureDir(target.dir);
1200
- for (const packName of packNames) {
1201
- const sourcePath = path4.join(sourceDir, packName);
1202
- const targetPath = path4.join(target.dir, packName);
1203
- const sourceFingerprint = bundledFingerprints.get(packName);
1204
- if (!sourceFingerprint) {
1205
- throw new Error(`Bundled fingerprint missing: ${packName}`);
1206
- }
1207
- const outcome = syncSkillDirectory(sourcePath, targetPath, sourceFingerprint);
1208
- if (outcome === "installed") {
1209
- installed.push(packName);
1210
- } else if (outcome === "refreshed") {
1211
- refreshed.push(packName);
1212
- } else {
1213
- unchanged.push(packName);
1214
- }
1215
- }
1216
- const legacyCleanup = cleanupLegacyAliases(target.dir);
1217
- removedLegacyAliases.push(...legacyCleanup.removed);
1218
- preservedLegacyAliases.push(...legacyCleanup.preserved);
1219
- targetResults.push({
1220
- agents: target.agents,
1221
- targetDir: target.dir,
1222
- installed,
1223
- refreshed,
1224
- unchanged,
1225
- removedLegacyAliases,
1226
- preservedLegacyAliases,
1227
- success: true
1228
- });
1229
- } catch (error) {
1230
- const message = error instanceof Error ? error.message : String(error);
1231
- targetResults.push({
1232
- agents: target.agents,
1233
- targetDir: target.dir,
1234
- installed,
1235
- refreshed,
1236
- unchanged,
1237
- removedLegacyAliases,
1238
- preservedLegacyAliases,
1239
- success: false,
1240
- error: message
1241
- });
1242
- }
1243
- }
1244
- const result = {
1245
- success: targetResults.every((entry) => entry.success),
1246
- message: "",
1247
- mode,
1248
- targets: targetResults,
1249
- installed: targetResults.flatMap((entry) => entry.installed),
1250
- refreshed: targetResults.flatMap((entry) => entry.refreshed),
1251
- unchanged: targetResults.flatMap((entry) => entry.unchanged),
1252
- removedLegacyAliases: targetResults.flatMap((entry) => entry.removedLegacyAliases),
1253
- preservedLegacyAliases: targetResults.flatMap((entry) => entry.preservedLegacyAliases)
1254
- };
1255
- result.message = buildSyncMessage(mode, result);
1256
- return result;
1257
- } catch (error) {
1258
- const message = error instanceof Error ? error.message : String(error);
1259
- const result = {
1260
- success: false,
1261
- message: "",
1262
- mode,
1263
- targets: targetResults,
1264
- installed: targetResults.flatMap((entry) => entry.installed),
1265
- refreshed: targetResults.flatMap((entry) => entry.refreshed),
1266
- unchanged: targetResults.flatMap((entry) => entry.unchanged),
1267
- removedLegacyAliases: targetResults.flatMap((entry) => entry.removedLegacyAliases),
1268
- preservedLegacyAliases: targetResults.flatMap((entry) => entry.preservedLegacyAliases)
1269
- };
1270
- result.message = `Failed to sync skills (${mode}): ${message}`;
1271
- return result;
1272
- }
1273
- }
1274
- function removeBundledSkills(mode) {
1275
- const targets = getTargets(mode);
1276
- const packNames = getCanonicalBundledSkillNames();
1277
- const targetResults = [];
1278
- for (const target of targets) {
1279
- const removed = [];
1280
- const missing = [];
1281
- const removedLegacyAliases = [];
1282
- const preservedLegacyAliases = [];
1283
- try {
1284
- for (const packName of packNames) {
1285
- const targetPath = path4.join(target.dir, packName);
1286
- if (fs5.existsSync(targetPath)) {
1287
- fs5.rmSync(targetPath, { recursive: true, force: true });
1288
- removed.push(packName);
1289
- } else {
1290
- missing.push(packName);
1291
- }
1292
- }
1293
- const legacyCleanup = cleanupLegacyAliases(target.dir);
1294
- removedLegacyAliases.push(...legacyCleanup.removed);
1295
- preservedLegacyAliases.push(...legacyCleanup.preserved);
1296
- targetResults.push({
1297
- agents: target.agents,
1298
- targetDir: target.dir,
1299
- removed,
1300
- missing,
1301
- removedLegacyAliases,
1302
- preservedLegacyAliases,
1303
- success: true
1304
- });
1305
- } catch (error) {
1306
- const message = error instanceof Error ? error.message : String(error);
1307
- targetResults.push({
1308
- agents: target.agents,
1309
- targetDir: target.dir,
1310
- removed,
1311
- missing,
1312
- removedLegacyAliases,
1313
- preservedLegacyAliases,
1314
- success: false,
1315
- error: message
1316
- });
1317
- }
1318
- }
1319
- const result = {
1320
- success: targetResults.every((entry) => entry.success),
1321
- message: "",
1322
- mode,
1323
- targets: targetResults,
1324
- removed: targetResults.flatMap((entry) => entry.removed),
1325
- missing: targetResults.flatMap((entry) => entry.missing),
1326
- removedLegacyAliases: targetResults.flatMap((entry) => entry.removedLegacyAliases),
1327
- preservedLegacyAliases: targetResults.flatMap((entry) => entry.preservedLegacyAliases)
1328
- };
1329
- result.message = buildRemovalMessage(mode, result);
1330
- return result;
1331
- }
1332
- function hasBundledSkillArtifacts(mode) {
1333
- const packNames = getCanonicalBundledSkillNames();
1334
- const targets = getTargets(mode);
1335
- return targets.some((target) => hasCanonicalBundledSkillInTarget(target.dir, packNames));
1336
- }
1337
-
1338
904
  // src/cli/commands/update.ts
1339
- import * as fs6 from "fs";
1340
- import * as path5 from "path";
1341
- import * as os4 from "os";
1342
- var PLUGIN_NAME2 = "opendevbrowser";
905
+ import * as fs4 from "fs";
906
+ import * as path2 from "path";
907
+ import * as os2 from "os";
908
+ var PLUGIN_NAME = "opendevbrowser";
1343
909
  function getCacheDir() {
1344
- return process.env.OPENCODE_CACHE_DIR || path5.join(os4.homedir(), ".cache", "opencode");
910
+ return process.env.OPENCODE_CACHE_DIR || path2.join(os2.homedir(), ".cache", "opencode");
1345
911
  }
1346
912
  function rmdir(dirPath) {
1347
913
  const cacheDir = getCacheDir();
1348
- const resolvedCache = path5.resolve(cacheDir);
1349
- const resolvedPath = path5.resolve(dirPath);
1350
- if (!resolvedPath.startsWith(resolvedCache + path5.sep) || resolvedPath === resolvedCache) {
914
+ const resolvedCache = path2.resolve(cacheDir);
915
+ const resolvedPath = path2.resolve(dirPath);
916
+ if (!resolvedPath.startsWith(resolvedCache + path2.sep) || resolvedPath === resolvedCache) {
1351
917
  throw new Error(`Security: refusing to delete path outside cache directory: ${dirPath}`);
1352
918
  }
1353
- if (fs6.existsSync(dirPath)) {
1354
- fs6.rmSync(dirPath, { recursive: true, force: true });
919
+ if (fs4.existsSync(dirPath)) {
920
+ fs4.rmSync(dirPath, { recursive: true, force: true });
1355
921
  }
1356
922
  }
1357
923
  function runUpdate() {
1358
924
  const cacheDir = getCacheDir();
1359
- const nodeModulesDir = path5.join(cacheDir, "node_modules");
1360
- const pluginCacheDir = path5.join(nodeModulesDir, PLUGIN_NAME2);
925
+ const nodeModulesDir = path2.join(cacheDir, "node_modules");
926
+ const pluginCacheDir = path2.join(nodeModulesDir, PLUGIN_NAME);
1361
927
  try {
1362
- if (!fs6.existsSync(pluginCacheDir)) {
1363
- if (fs6.existsSync(nodeModulesDir)) {
928
+ if (!fs4.existsSync(pluginCacheDir)) {
929
+ if (fs4.existsSync(nodeModulesDir)) {
1364
930
  rmdir(nodeModulesDir);
1365
931
  return {
1366
932
  success: true,
@@ -1391,20 +957,29 @@ function runUpdate() {
1391
957
  }
1392
958
 
1393
959
  // src/cli/commands/uninstall.ts
1394
- import * as fs7 from "fs";
1395
- import * as path6 from "path";
1396
- import * as os5 from "os";
960
+ import * as fs5 from "fs";
961
+ import * as path3 from "path";
962
+ import * as os3 from "os";
963
+ function hasInstalledConfig(mode) {
964
+ const configPath = mode === "global" ? getGlobalConfigPath() : getLocalConfigPath();
965
+ try {
966
+ const { config } = readConfig(configPath);
967
+ return hasPlugin(config);
968
+ } catch {
969
+ return false;
970
+ }
971
+ }
1397
972
  function getPluginConfigPath2(mode) {
1398
973
  if (mode === "global") {
1399
- const configDir = process.env.OPENCODE_CONFIG_DIR || path6.join(os5.homedir(), ".config", "opencode");
1400
- return path6.join(configDir, "opendevbrowser.jsonc");
974
+ const configDir = process.env.OPENCODE_CONFIG_DIR || path3.join(os3.homedir(), ".config", "opencode");
975
+ return path3.join(configDir, "opendevbrowser.jsonc");
1401
976
  }
1402
- return path6.join(process.cwd(), "opendevbrowser.jsonc");
977
+ return path3.join(process.cwd(), "opendevbrowser.jsonc");
1403
978
  }
1404
979
  function removePluginConfigFile(mode) {
1405
980
  const configPath = getPluginConfigPath2(mode);
1406
- if (fs7.existsSync(configPath)) {
1407
- fs7.unlinkSync(configPath);
981
+ if (fs5.existsSync(configPath)) {
982
+ fs5.unlinkSync(configPath);
1408
983
  return true;
1409
984
  }
1410
985
  return false;
@@ -1416,14 +991,14 @@ function runUninstall(mode, deleteConfigFile = false) {
1416
991
  if (!hasPlugin(config)) {
1417
992
  return {
1418
993
  success: true,
1419
- message: `opendevbrowser is not installed in ${configPath}`,
994
+ message: `No plugin config found in ${configPath}`,
1420
995
  configPath,
1421
996
  removed: false,
1422
997
  configFileDeleted: false
1423
998
  };
1424
999
  }
1425
1000
  const newContent = removePluginFromContent(content, "opendevbrowser");
1426
- fs7.writeFileSync(configPath, newContent, "utf-8");
1001
+ fs5.writeFileSync(configPath, newContent, "utf-8");
1427
1002
  let configFileDeleted = false;
1428
1003
  if (deleteConfigFile) {
1429
1004
  configFileDeleted = removePluginConfigFile(mode);
@@ -1447,19 +1022,10 @@ function runUninstall(mode, deleteConfigFile = false) {
1447
1022
  }
1448
1023
  }
1449
1024
  function findInstalledConfigs() {
1450
- let global = false;
1451
- let local = false;
1452
- try {
1453
- const { config: globalConfig } = readConfig(getGlobalConfigPath());
1454
- global = hasPlugin(globalConfig);
1455
- } catch {
1456
- }
1457
- try {
1458
- const { config: localConfig } = readConfig(getLocalConfigPath());
1459
- local = hasPlugin(localConfig);
1460
- } catch {
1461
- }
1462
- return { global, local };
1025
+ return {
1026
+ global: hasInstalledConfig("global") || hasManagedBundledSkillInstall("global") || hasBundledSkillArtifacts("global"),
1027
+ local: hasInstalledConfig("local") || hasManagedBundledSkillInstall("local") || hasBundledSkillArtifacts("local")
1028
+ };
1463
1029
  }
1464
1030
 
1465
1031
  // src/cli/commands/serve.ts
@@ -1549,8 +1115,8 @@ function parseRepeatedStringFlag(rawArgs, flag) {
1549
1115
  }
1550
1116
 
1551
1117
  // src/cli/commands/native.ts
1552
- import * as fs8 from "fs";
1553
- import * as path7 from "path";
1118
+ import * as fs6 from "fs";
1119
+ import * as path4 from "path";
1554
1120
  import { execFileSync } from "child_process";
1555
1121
  import { fileURLToPath } from "url";
1556
1122
  var EXTENSION_ID_RE = /^[a-p]{32}$/;
@@ -1585,33 +1151,33 @@ var parseNativeArgs = (rawArgs) => {
1585
1151
  };
1586
1152
  var getManifestDir = () => {
1587
1153
  if (process.platform === "darwin") {
1588
- return path7.join(process.env.HOME || "", "Library", "Application Support", "Google", "Chrome", "NativeMessagingHosts");
1154
+ return path4.join(process.env.HOME || "", "Library", "Application Support", "Google", "Chrome", "NativeMessagingHosts");
1589
1155
  }
1590
1156
  if (process.platform === "linux") {
1591
- return path7.join(process.env.HOME || "", ".config", "google-chrome", "NativeMessagingHosts");
1157
+ return path4.join(process.env.HOME || "", ".config", "google-chrome", "NativeMessagingHosts");
1592
1158
  }
1593
1159
  if (process.platform === "win32") {
1594
- const base = process.env.LOCALAPPDATA || (process.env.USERPROFILE ? path7.join(process.env.USERPROFILE, "AppData", "Local") : "");
1160
+ const base = process.env.LOCALAPPDATA || (process.env.USERPROFILE ? path4.join(process.env.USERPROFILE, "AppData", "Local") : "");
1595
1161
  if (!base) {
1596
1162
  throw createUsageError("LOCALAPPDATA is not set. Unable to locate NativeMessagingHosts directory.");
1597
1163
  }
1598
- return path7.join(base, "Google", "Chrome", "User Data", "NativeMessagingHosts");
1164
+ return path4.join(base, "Google", "Chrome", "User Data", "NativeMessagingHosts");
1599
1165
  }
1600
1166
  throw createUsageError(`Native messaging is not supported on ${process.platform}.`);
1601
1167
  };
1602
1168
  var getScriptsDir = () => {
1603
1169
  const __filename = fileURLToPath(import.meta.url);
1604
- const startDir = path7.dirname(__filename);
1170
+ const startDir = path4.dirname(__filename);
1605
1171
  const rootsToScan = [startDir, process.cwd()];
1606
1172
  for (const root of rootsToScan) {
1607
- let current = path7.resolve(root);
1173
+ let current = path4.resolve(root);
1608
1174
  while (true) {
1609
- const scriptsDir = path7.join(current, "scripts", "native");
1610
- const packageJsonPath = path7.join(current, "package.json");
1611
- if (fs8.existsSync(scriptsDir) && fs8.existsSync(packageJsonPath)) {
1175
+ const scriptsDir = path4.join(current, "scripts", "native");
1176
+ const packageJsonPath = path4.join(current, "package.json");
1177
+ if (fs6.existsSync(scriptsDir) && fs6.existsSync(packageJsonPath)) {
1612
1178
  return scriptsDir;
1613
1179
  }
1614
- const parent = path7.dirname(current);
1180
+ const parent = path4.dirname(current);
1615
1181
  if (parent === current) {
1616
1182
  break;
1617
1183
  }
@@ -1621,18 +1187,18 @@ var getScriptsDir = () => {
1621
1187
  throw createUsageError("Unable to locate scripts/native directory.");
1622
1188
  };
1623
1189
  var getHostScriptPath = () => {
1624
- return path7.join(getScriptsDir(), "host.cjs");
1190
+ return path4.join(getScriptsDir(), "host.cjs");
1625
1191
  };
1626
1192
  var getManifestPath = () => {
1627
- return path7.join(getManifestDir(), "com.opendevbrowser.native.json");
1193
+ return path4.join(getManifestDir(), "com.opendevbrowser.native.json");
1628
1194
  };
1629
1195
  var getWrapperPath = () => {
1630
1196
  const wrapperName = process.platform === "win32" ? "com.opendevbrowser.native.cmd" : "com.opendevbrowser.native.sh";
1631
- return path7.join(getManifestDir(), wrapperName);
1197
+ return path4.join(getManifestDir(), wrapperName);
1632
1198
  };
1633
1199
  var readManifest = (manifestPath) => {
1634
1200
  try {
1635
- const raw = fs8.readFileSync(manifestPath, "utf8");
1201
+ const raw = fs6.readFileSync(manifestPath, "utf8");
1636
1202
  const data = JSON.parse(raw);
1637
1203
  const origins = Array.isArray(data.allowed_origins) ? data.allowed_origins : [];
1638
1204
  const match = origins.find((origin) => origin.startsWith("chrome-extension://"));
@@ -1669,9 +1235,9 @@ var readRegistryPath = () => {
1669
1235
  };
1670
1236
  var normalizePath = (value) => {
1671
1237
  try {
1672
- return fs8.realpathSync(value);
1238
+ return fs6.realpathSync(value);
1673
1239
  } catch {
1674
- return path7.resolve(value);
1240
+ return path4.resolve(value);
1675
1241
  }
1676
1242
  };
1677
1243
  var findExtensionIdInCommands = (preferences) => {
@@ -1732,8 +1298,8 @@ var getExtensionPathCandidates = () => {
1732
1298
  if (primary) {
1733
1299
  candidates.add(normalizePath(primary));
1734
1300
  }
1735
- const cwdExtension = path7.join(process.cwd(), "extension");
1736
- if (fs8.existsSync(path7.join(cwdExtension, "manifest.json"))) {
1301
+ const cwdExtension = path4.join(process.cwd(), "extension");
1302
+ if (fs6.existsSync(path4.join(cwdExtension, "manifest.json"))) {
1737
1303
  candidates.add(normalizePath(cwdExtension));
1738
1304
  }
1739
1305
  if (candidates.size === 0) {
@@ -1818,13 +1384,13 @@ var getNativeStatusSnapshot = () => {
1818
1384
  let manifestExists = false;
1819
1385
  let wrapperExists = false;
1820
1386
  let extensionIdValue = null;
1821
- if (fs8.existsSync(manifestPath)) {
1387
+ if (fs6.existsSync(manifestPath)) {
1822
1388
  manifestExists = true;
1823
1389
  installed = true;
1824
1390
  const manifest = readManifest(manifestPath);
1825
1391
  extensionIdValue = manifest.extensionId;
1826
1392
  }
1827
- if (fs8.existsSync(wrapperPath)) {
1393
+ if (fs6.existsSync(wrapperPath)) {
1828
1394
  wrapperExists = true;
1829
1395
  }
1830
1396
  if (!manifestExists || !wrapperExists) {
@@ -1884,7 +1450,7 @@ function installNativeHost(extensionId) {
1884
1450
  };
1885
1451
  }
1886
1452
  const hostScript = getHostScriptPath();
1887
- if (!fs8.existsSync(hostScript)) {
1453
+ if (!fs6.existsSync(hostScript)) {
1888
1454
  return {
1889
1455
  success: false,
1890
1456
  message: `Native host not found at ${hostScript}.`,
@@ -1893,7 +1459,7 @@ function installNativeHost(extensionId) {
1893
1459
  }
1894
1460
  const scriptsDir = getScriptsDir();
1895
1461
  const manifestPath = getManifestPath();
1896
- const installScript = process.platform === "win32" ? path7.join(scriptsDir, "install.ps1") : path7.join(scriptsDir, "install.sh");
1462
+ const installScript = process.platform === "win32" ? path4.join(scriptsDir, "install.ps1") : path4.join(scriptsDir, "install.sh");
1897
1463
  try {
1898
1464
  runScript(installScript, [normalized]);
1899
1465
  return {
@@ -1913,7 +1479,7 @@ function installNativeHost(extensionId) {
1913
1479
  async function runNativeCommand(args) {
1914
1480
  const { subcommand, extensionId } = parseNativeArgs(args.rawArgs);
1915
1481
  const scriptsDir = getScriptsDir();
1916
- const uninstallScript = process.platform === "win32" ? path7.join(scriptsDir, "uninstall.ps1") : path7.join(scriptsDir, "uninstall.sh");
1482
+ const uninstallScript = process.platform === "win32" ? path4.join(scriptsDir, "uninstall.ps1") : path4.join(scriptsDir, "uninstall.sh");
1917
1483
  if (subcommand === "install") {
1918
1484
  return installNativeHost(extensionId);
1919
1485
  }
@@ -2289,9 +1855,9 @@ ${nativeMessage}${fingerprintNote}${staleNote}` : `${baseMessage}${fingerprintNo
2289
1855
 
2290
1856
  // src/cli/daemon-autostart.ts
2291
1857
  import { execFileSync as execFileSync2 } from "child_process";
2292
- import { existsSync as existsSync7, mkdirSync as mkdirSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "fs";
2293
- import { homedir as homedir6, tmpdir } from "os";
2294
- import { dirname as dirname5, isAbsolute, join as join8, relative, resolve as resolve4 } from "path";
1858
+ import { existsSync as existsSync5, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "fs";
1859
+ import { homedir as homedir4, tmpdir } from "os";
1860
+ import { dirname as dirname3, isAbsolute, join as join5, relative, resolve as resolve3 } from "path";
2295
1861
  import { fileURLToPath as fileURLToPath2 } from "url";
2296
1862
  var MAC_LABEL = "com.opendevbrowser.daemon";
2297
1863
  var WIN_TASK_NAME = "OpenDevBrowser Daemon";
@@ -2301,9 +1867,9 @@ var defaultDeps = () => ({
2301
1867
  argv1: process.argv[1] ?? "",
2302
1868
  moduleUrl: import.meta.url,
2303
1869
  uid: typeof process.getuid === "function" ? process.getuid() : 0,
2304
- homedir: homedir6,
2305
- existsSync: existsSync7,
2306
- mkdirSync: mkdirSync3,
1870
+ homedir: homedir4,
1871
+ existsSync: existsSync5,
1872
+ mkdirSync: mkdirSync2,
2307
1873
  writeFileSync: writeFileSync4,
2308
1874
  unlinkSync: unlinkSync2,
2309
1875
  execFileSync: execFileSync2,
@@ -2315,14 +1881,14 @@ var formatCommand = (programArguments) => {
2315
1881
  };
2316
1882
  var resolveCliPathFromModule = (moduleUrl, exists) => {
2317
1883
  const modulePath = fileURLToPath2(moduleUrl);
2318
- const candidate = resolve4(dirname5(modulePath), "..", "index.js");
1884
+ const candidate = resolve3(dirname3(modulePath), "..", "index.js");
2319
1885
  if (!exists(candidate)) {
2320
1886
  throw new Error(`CLI entrypoint not found at ${candidate}`);
2321
1887
  }
2322
1888
  return candidate;
2323
1889
  };
2324
1890
  var normalizeComparisonPath = (value, platform) => {
2325
- const resolvedPath = resolve4(value);
1891
+ const resolvedPath = resolve3(value);
2326
1892
  return platform === "win32" ? resolvedPath.toLowerCase() : resolvedPath;
2327
1893
  };
2328
1894
  var isPathInsideRoot = (candidate, root, platform) => {
@@ -2357,7 +1923,7 @@ var resolveCliEntrypoint = (deps = {}) => {
2357
1923
  let cliPath = null;
2358
1924
  let source = "module";
2359
1925
  if (resolved.argv1) {
2360
- const candidate = resolve4(resolved.argv1);
1926
+ const candidate = resolve3(resolved.argv1);
2361
1927
  if (exists(candidate)) {
2362
1928
  cliPath = candidate;
2363
1929
  source = "argv1";
@@ -2372,13 +1938,13 @@ var resolveCliEntrypoint = (deps = {}) => {
2372
1938
  const isTransient = isTransientCliPath(cliPath, resolved);
2373
1939
  return { nodePath, cliPath, args, command, source, isTransient };
2374
1940
  };
2375
- var getLaunchAgentPath = (home = homedir6()) => {
2376
- return join8(home, "Library", "LaunchAgents", `${MAC_LABEL}.plist`);
1941
+ var getLaunchAgentPath = (home = homedir4()) => {
1942
+ return join5(home, "Library", "LaunchAgents", `${MAC_LABEL}.plist`);
2377
1943
  };
2378
1944
  var buildLaunchAgentPlist = (entrypoint, options = {}) => {
2379
1945
  const label = options.label ?? MAC_LABEL;
2380
- const stdoutPath = options.stdoutPath ?? join8(homedir6(), "Library", "Logs", "opendevbrowser-daemon.log");
2381
- const stderrPath = options.stderrPath ?? join8(homedir6(), "Library", "Logs", "opendevbrowser-daemon.err.log");
1946
+ const stdoutPath = options.stdoutPath ?? join5(homedir4(), "Library", "Logs", "opendevbrowser-daemon.log");
1947
+ const stderrPath = options.stderrPath ?? join5(homedir4(), "Library", "Logs", "opendevbrowser-daemon.err.log");
2382
1948
  const programArgs = [entrypoint.nodePath, ...entrypoint.args].map((value) => ` <string>${value}</string>`).join("\n");
2383
1949
  return [
2384
1950
  '<?xml version="1.0" encoding="UTF-8"?>',
@@ -2583,10 +2149,10 @@ var installMacAutostart = (deps = {}) => {
2583
2149
  assertPersistentEntrypoint(entrypoint);
2584
2150
  const home = resolved.homedir();
2585
2151
  const plistPath = getLaunchAgentPath(home);
2586
- const stdoutPath = join8(home, "Library", "Logs", "opendevbrowser-daemon.log");
2587
- const stderrPath = join8(home, "Library", "Logs", "opendevbrowser-daemon.err.log");
2588
- const logsDir = dirname5(stdoutPath);
2589
- resolved.mkdirSync(dirname5(plistPath), { recursive: true });
2152
+ const stdoutPath = join5(home, "Library", "Logs", "opendevbrowser-daemon.log");
2153
+ const stderrPath = join5(home, "Library", "Logs", "opendevbrowser-daemon.err.log");
2154
+ const logsDir = dirname3(stdoutPath);
2155
+ resolved.mkdirSync(dirname3(plistPath), { recursive: true });
2590
2156
  resolved.mkdirSync(logsDir, { recursive: true });
2591
2157
  resolved.writeFileSync(
2592
2158
  plistPath,
@@ -2963,7 +2529,7 @@ async function runDaemonCommand(args) {
2963
2529
  }
2964
2530
 
2965
2531
  // src/cli/commands/artifacts.ts
2966
- import { join as join9, resolve as resolve5 } from "path";
2532
+ import { join as join6, resolve as resolve4 } from "path";
2967
2533
  import { tmpdir as tmpdir2 } from "os";
2968
2534
  var PASSTHROUGH_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
2969
2535
  "--with-config",
@@ -3052,7 +2618,7 @@ var parseArtifactsArgs = (rawArgs) => {
3052
2618
  };
3053
2619
  async function runArtifactsCommand(args) {
3054
2620
  const parsed = parseArtifactsArgs(args.rawArgs);
3055
- const rootDir = parsed.outputDir ? resolve5(parsed.outputDir) : join9(tmpdir2(), "opendevbrowser");
2621
+ const rootDir = parsed.outputDir ? resolve4(parsed.outputDir) : join6(tmpdir2(), "opendevbrowser");
3056
2622
  const cleaned = await cleanupExpiredArtifacts(rootDir);
3057
2623
  return {
3058
2624
  success: true,
@@ -3163,34 +2729,34 @@ function formatAutostartReconciliationMessage(result) {
3163
2729
  }
3164
2730
 
3165
2731
  // src/cli/commands/run.ts
3166
- import { readFileSync as readFileSync4 } from "fs";
2732
+ import { readFileSync as readFileSync2 } from "fs";
3167
2733
 
3168
2734
  // src/cli/output.ts
3169
2735
  var normalizeExitCode = (code) => {
3170
2736
  return Number.isInteger(code) ? Number(code) : 0;
3171
2737
  };
3172
2738
  var flushStream = (stream) => {
3173
- return new Promise((resolve6) => {
2739
+ return new Promise((resolve5) => {
3174
2740
  if (!stream || typeof stream.write !== "function") {
3175
- resolve6();
2741
+ resolve5();
3176
2742
  return;
3177
2743
  }
3178
2744
  try {
3179
- stream.write("", () => resolve6());
2745
+ stream.write("", () => resolve5());
3180
2746
  } catch {
3181
- resolve6();
2747
+ resolve5();
3182
2748
  }
3183
2749
  });
3184
2750
  };
3185
2751
  async function flushOutputAndExit(code, proc = process, timeoutMs = 250) {
3186
2752
  const finalCode = normalizeExitCode(code);
3187
2753
  proc.exitCode = finalCode;
3188
- await new Promise((resolve6) => {
2754
+ await new Promise((resolve5) => {
3189
2755
  let settled = false;
3190
2756
  const finish = () => {
3191
2757
  if (settled) return;
3192
2758
  settled = true;
3193
- resolve6();
2759
+ resolve5();
3194
2760
  };
3195
2761
  const timer = setTimeout(finish, Math.max(0, timeoutMs));
3196
2762
  timer.unref?.();
@@ -3312,13 +2878,13 @@ function parseRunArgs(rawArgs) {
3312
2878
  return parsed;
3313
2879
  }
3314
2880
  function readScriptFromStdin() {
3315
- return new Promise((resolve6, reject) => {
2881
+ return new Promise((resolve5, reject) => {
3316
2882
  let data = "";
3317
2883
  process.stdin.setEncoding("utf8");
3318
2884
  process.stdin.on("data", (chunk) => {
3319
2885
  data += chunk;
3320
2886
  });
3321
- process.stdin.on("end", () => resolve6(data));
2887
+ process.stdin.on("end", () => resolve5(data));
3322
2888
  process.stdin.on("error", reject);
3323
2889
  });
3324
2890
  }
@@ -3327,7 +2893,7 @@ async function runScriptCommand(args) {
3327
2893
  const outputOptions = { format: args.outputFormat, quiet: args.quiet };
3328
2894
  let scriptRaw = "";
3329
2895
  if (runArgs.scriptPath) {
3330
- scriptRaw = readFileSync4(runArgs.scriptPath, "utf-8");
2896
+ scriptRaw = readFileSync2(runArgs.scriptPath, "utf-8");
3331
2897
  } else if (!process.stdin.isTTY) {
3332
2898
  scriptRaw = await readScriptFromStdin();
3333
2899
  } else {
@@ -3552,16 +3118,16 @@ function promptYesNo(question, defaultYes) {
3552
3118
  return Promise.resolve(false);
3553
3119
  }
3554
3120
  const suffix = defaultYes ? " [Y/n] " : " [y/N] ";
3555
- return new Promise((resolve6) => {
3121
+ return new Promise((resolve5) => {
3556
3122
  process.stdout.write(`${question}${suffix}`);
3557
3123
  process.stdin.setEncoding("utf8");
3558
3124
  process.stdin.once("data", (data) => {
3559
3125
  const input = data.toString().trim().toLowerCase();
3560
3126
  if (!input) {
3561
- resolve6(defaultYes);
3127
+ resolve5(defaultYes);
3562
3128
  return;
3563
3129
  }
3564
- resolve6(input === "y" || input === "yes");
3130
+ resolve5(input === "y" || input === "yes");
3565
3131
  });
3566
3132
  });
3567
3133
  }
@@ -4519,7 +4085,7 @@ async function runAnnotate(args) {
4519
4085
  }
4520
4086
 
4521
4087
  // src/cli/commands/canvas.ts
4522
- import { readFileSync as readFileSync5 } from "fs";
4088
+ import { readFileSync as readFileSync3 } from "fs";
4523
4089
  var DEFAULT_FEEDBACK_STREAM_TIMEOUT_MS = 3e4;
4524
4090
  var isRecord = (value) => {
4525
4091
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -4720,7 +4286,7 @@ var resolveCanvasParams = (canvasArgs) => {
4720
4286
  if (hasParamsFile) {
4721
4287
  let raw = "";
4722
4288
  try {
4723
- raw = readFileSync5(canvasArgs.paramsFile ?? "", "utf8");
4289
+ raw = readFileSync3(canvasArgs.paramsFile ?? "", "utf8");
4724
4290
  } catch (error) {
4725
4291
  const message = error instanceof Error ? error.message : "Unable to read file";
4726
4292
  throw createUsageError(`Invalid --params-file: ${message}`);
@@ -4789,7 +4355,7 @@ async function runCanvas(args) {
4789
4355
  }
4790
4356
 
4791
4357
  // src/cli/commands/rpc.ts
4792
- import { readFileSync as readFileSync6 } from "fs";
4358
+ import { readFileSync as readFileSync4 } from "fs";
4793
4359
  var requireValue4 = (value, flag) => {
4794
4360
  if (!value) throw createUsageError(`Missing value for ${flag}`);
4795
4361
  return value;
@@ -4869,7 +4435,7 @@ var resolveRpcParams = (rpcArgs) => {
4869
4435
  if (hasParamsFile) {
4870
4436
  let raw = "";
4871
4437
  try {
4872
- raw = readFileSync6(rpcArgs.paramsFile ?? "", "utf8");
4438
+ raw = readFileSync4(rpcArgs.paramsFile ?? "", "utf8");
4873
4439
  } catch (error) {
4874
4440
  const message = error instanceof Error ? error.message : "Unable to read file";
4875
4441
  throw createUsageError(`Invalid --params-file: ${message}`);
@@ -6249,11 +5815,11 @@ function parseScreenshotArgs(rawArgs) {
6249
5815
  return parsed;
6250
5816
  }
6251
5817
  async function runScreenshot(args) {
6252
- const { sessionId, targetId, path: path8, ref, fullPage, timeoutMs } = parseScreenshotArgs(args.rawArgs);
5818
+ const { sessionId, targetId, path: path5, ref, fullPage, timeoutMs } = parseScreenshotArgs(args.rawArgs);
6253
5819
  if (!sessionId) throw createUsageError("Missing --session-id");
6254
5820
  const params = {
6255
5821
  sessionId,
6256
- ...typeof path8 === "string" ? { path: path8 } : {},
5822
+ ...typeof path5 === "string" ? { path: path5 } : {},
6257
5823
  ...typeof targetId === "string" ? { targetId } : {},
6258
5824
  ...typeof ref === "string" ? { ref } : {},
6259
5825
  ...fullPage === true ? { fullPage: true } : {}
@@ -6652,7 +6218,7 @@ async function runDesktopAccessibilitySnapshot(args) {
6652
6218
  }
6653
6219
 
6654
6220
  // src/cli/commands/session/cookie-import.ts
6655
- import { readFileSync as readFileSync7 } from "fs";
6221
+ import { readFileSync as readFileSync5 } from "fs";
6656
6222
  var requireValue5 = (value, flag) => {
6657
6223
  if (!value) {
6658
6224
  throw createUsageError(`Missing value for ${flag}`);
@@ -6767,7 +6333,7 @@ var resolveCookies = (parsed) => {
6767
6333
  }
6768
6334
  let raw = "";
6769
6335
  try {
6770
- raw = readFileSync7(parsed.cookiesFile ?? "", "utf8");
6336
+ raw = readFileSync5(parsed.cookiesFile ?? "", "utf8");
6771
6337
  } catch (error) {
6772
6338
  const message = error instanceof Error ? error.message : "Unable to read file";
6773
6339
  throw createUsageError(`Invalid --cookies-file: ${message}`);
@@ -7803,7 +7369,7 @@ async function runInspiredesignCommand(args) {
7803
7369
  // package.json
7804
7370
  var package_default = {
7805
7371
  name: "opendevbrowser",
7806
- version: "0.0.21",
7372
+ version: "0.0.22",
7807
7373
  description: "Browser automation runtime with snapshot-refs-actions, browser replay screencasts, public read-only desktop observation, and browser-scoped computer-use orchestration",
7808
7374
  type: "module",
7809
7375
  main: "dist/index.js",
@@ -7814,6 +7380,7 @@ var package_default = {
7814
7380
  files: [
7815
7381
  "dist",
7816
7382
  "skills",
7383
+ "scripts/postinstall-sync-skills.mjs",
7817
7384
  "scripts/native",
7818
7385
  "extension/canvas.html",
7819
7386
  "extension/manifest.json",
@@ -7848,8 +7415,8 @@ var package_default = {
7848
7415
  node: ">=18"
7849
7416
  },
7850
7417
  scripts: {
7851
- build: "node scripts/run-package-tool.mjs tsup src/index.ts src/cli/index.ts src/skills/skill-loader.ts --format esm --clean --sourcemap && node scripts/run-package-tool.mjs tsc --emitDeclarationOnly --declaration --declarationMap -p tsconfig.json && node scripts/postbuild-dist.mjs",
7852
- dev: "tsup src/index.ts src/cli/index.ts src/skills/skill-loader.ts --format esm --dts --watch",
7418
+ build: "node scripts/run-package-tool.mjs tsup src/index.ts src/cli/index.ts src/cli/installers/postinstall-skill-sync.ts src/skills/skill-loader.ts --format esm --clean --sourcemap && node scripts/run-package-tool.mjs tsc --emitDeclarationOnly --declaration --declarationMap -p tsconfig.json && node scripts/postbuild-dist.mjs",
7419
+ dev: "tsup src/index.ts src/cli/index.ts src/cli/installers/postinstall-skill-sync.ts src/skills/skill-loader.ts --format esm --dts --watch",
7853
7420
  lint: 'node scripts/run-package-tool.mjs eslint "src/**/*.ts" "tests/**/*.ts"',
7854
7421
  typecheck: "node scripts/run-package-tool.mjs tsc --noEmit -p tsconfig.json",
7855
7422
  test: "node scripts/run-vitest-coverage.mjs",
@@ -7864,7 +7431,8 @@ var package_default = {
7864
7431
  "extension:pack": "cd extension && zip -r ../opendevbrowser-extension.zip manifest.json popup.html canvas.html dist/ icons/",
7865
7432
  "extension:store": "node scripts/chrome-store-publish.mjs",
7866
7433
  "version:check": "node scripts/verify-versions.mjs",
7867
- prepack: "npm run version:check && npm run build && npm run extension:build"
7434
+ prepack: "npm run version:check && npm run build && npm run extension:build",
7435
+ postinstall: "node scripts/postinstall-sync-skills.mjs"
7868
7436
  },
7869
7437
  dependencies: {
7870
7438
  "@opencode-ai/plugin": "^1.2.25",
@@ -7892,8 +7460,10 @@ var package_default = {
7892
7460
  }
7893
7461
  };
7894
7462
 
7895
- // src/cli/index.ts
7896
- var VERSION = typeof package_default.version === "string" ? package_default.version : "0.0.0";
7463
+ // src/cli/update-skill-modes.ts
7464
+ function shouldRefreshManagedSkills(mode) {
7465
+ return hasManagedBundledSkillInstall(mode) || hasBundledSkillArtifacts(mode);
7466
+ }
7897
7467
  function resolveUpdateSkillModes(args) {
7898
7468
  if (args.rawArgs.includes("--no-skills")) {
7899
7469
  return [];
@@ -7907,22 +7477,102 @@ function resolveUpdateSkillModes(args) {
7907
7477
  if (args.mode) {
7908
7478
  return [args.mode];
7909
7479
  }
7910
- const installed = findInstalledConfigs();
7911
7480
  const modes = [];
7912
- if (installed.global || hasBundledSkillArtifacts("global")) {
7481
+ if (shouldRefreshManagedSkills("global")) {
7913
7482
  modes.push("global");
7914
7483
  }
7915
- if (installed.local || hasBundledSkillArtifacts("local")) {
7484
+ if (shouldRefreshManagedSkills("local")) {
7916
7485
  modes.push("local");
7917
7486
  }
7918
7487
  return modes;
7919
7488
  }
7489
+
7490
+ // src/cli/skill-lifecycle.ts
7491
+ function shouldSkipSkills(args) {
7492
+ return args.rawArgs.includes("--no-skills");
7493
+ }
7494
+ function getUpdateTargets(args, mode, deps) {
7495
+ if (deps.hasInstalledConfig(mode)) {
7496
+ return deps.getBundledSkillTargets(mode);
7497
+ }
7498
+ return deps.getBundledSkillLifecycleTargets(mode, {
7499
+ includeLegacyArtifacts: deps.hasBundledSkillArtifacts(mode)
7500
+ });
7501
+ }
7502
+ function collectUpdateSkillResults(args, deps, modes) {
7503
+ return modes.flatMap((mode) => {
7504
+ const targets = getUpdateTargets(args, mode, deps);
7505
+ return targets.length > 0 ? [deps.syncBundledSkillsForTargets(mode, targets)] : [];
7506
+ });
7507
+ }
7508
+ function getResolvedUpdateSkillModes(args, result, deps) {
7509
+ return result.success ? deps.resolveUpdateSkillModes(args) : [];
7510
+ }
7511
+ function buildUpdateSkillMessage(args, result, skillResults) {
7512
+ if (!result.success) {
7513
+ return "";
7514
+ }
7515
+ if (shouldSkipSkills(args)) {
7516
+ return "Managed skill refresh skipped (--no-skills).";
7517
+ }
7518
+ if (skillResults.length === 0) {
7519
+ return "No managed skill packs required refresh.";
7520
+ }
7521
+ return skillResults.map((entry) => entry.message).join("\n");
7522
+ }
7523
+ function buildUpdateCommandResult(args, result, deps) {
7524
+ const skillModes = getResolvedUpdateSkillModes(args, result, deps);
7525
+ const skillResults = result.success && !shouldSkipSkills(args) ? collectUpdateSkillResults(args, deps, skillModes) : [];
7526
+ const message = [result.message, buildUpdateSkillMessage(args, result, skillResults)].filter(Boolean).join("\n");
7527
+ return {
7528
+ success: result.success && skillResults.every((entry) => entry.success),
7529
+ message,
7530
+ data: {
7531
+ cacheCleared: result.cleared,
7532
+ skillModes,
7533
+ skills: skillResults
7534
+ }
7535
+ };
7536
+ }
7537
+ function buildUninstallSkillMessage(args, result, skillsResult) {
7538
+ if (!result.success) {
7539
+ return "";
7540
+ }
7541
+ if (shouldSkipSkills(args)) {
7542
+ return "Managed skill cleanup skipped (--no-skills).";
7543
+ }
7544
+ return skillsResult?.message ?? "No managed skill packs required cleanup.";
7545
+ }
7546
+ function getUninstallTargets(args, mode, result, deps) {
7547
+ if (!result.success || shouldSkipSkills(args)) {
7548
+ return [];
7549
+ }
7550
+ return deps.getBundledSkillLifecycleTargets(mode, {
7551
+ includeLegacyArtifacts: result.removed || deps.hasBundledSkillArtifacts(mode)
7552
+ });
7553
+ }
7554
+ function buildUninstallCommandResult(args, mode, result, deps) {
7555
+ const targets = getUninstallTargets(args, mode, result, deps);
7556
+ const skillsResult = result.success && !shouldSkipSkills(args) ? targets.length > 0 ? deps.removeBundledSkillsForTargets(mode, targets) : createNoOpSkillRemovalResult(mode) : void 0;
7557
+ const skillMessage = buildUninstallSkillMessage(args, result, skillsResult);
7558
+ return {
7559
+ success: result.success && (skillsResult?.success ?? true),
7560
+ message: [result.message, skillMessage].filter(Boolean).join("\n"),
7561
+ data: {
7562
+ config: result,
7563
+ skills: skillsResult
7564
+ }
7565
+ };
7566
+ }
7567
+
7568
+ // src/cli/index.ts
7569
+ var VERSION = typeof package_default.version === "string" ? package_default.version : "0.0.0";
7920
7570
  async function promptInstallMode() {
7921
7571
  if (!process.stdin.isTTY) {
7922
7572
  console.log("Non-interactive mode detected. Using global install.");
7923
7573
  return "global";
7924
7574
  }
7925
- return new Promise((resolve6) => {
7575
+ return new Promise((resolve5) => {
7926
7576
  console.log("\nWhere would you like to install opendevbrowser?\n");
7927
7577
  console.log(" 1. Global (~/.config/opencode/opencode.json)");
7928
7578
  console.log(" 2. Local (./opencode.json in this project)\n");
@@ -7942,23 +7592,23 @@ async function promptInstallMode() {
7942
7592
  resolved = true;
7943
7593
  const input = data.toString().trim();
7944
7594
  if (input === "2") {
7945
- resolve6("local");
7595
+ resolve5("local");
7946
7596
  } else {
7947
- resolve6("global");
7597
+ resolve5("global");
7948
7598
  }
7949
7599
  });
7950
7600
  process.stdin.once("close", () => {
7951
7601
  cleanup();
7952
7602
  if (resolved) return;
7953
7603
  resolved = true;
7954
- resolve6("global");
7604
+ resolve5("global");
7955
7605
  });
7956
7606
  timeoutId = setTimeout(() => {
7957
7607
  timeoutId = null;
7958
7608
  if (resolved) return;
7959
7609
  resolved = true;
7960
7610
  console.log("\nTimeout - using global install.");
7961
- resolve6("global");
7611
+ resolve5("global");
7962
7612
  }, 3e4);
7963
7613
  });
7964
7614
  }
@@ -7978,7 +7628,7 @@ async function promptUninstallMode() {
7978
7628
  console.log("Plugin found in both global and local configs. Use --global or --local flag.");
7979
7629
  return null;
7980
7630
  }
7981
- return new Promise((resolve6) => {
7631
+ return new Promise((resolve5) => {
7982
7632
  console.log("\nopendevbrowser is installed in multiple locations:\n");
7983
7633
  console.log(" 1. Global (~/.config/opencode/opencode.json)");
7984
7634
  console.log(" 2. Local (./opencode.json)");
@@ -7988,15 +7638,15 @@ async function promptUninstallMode() {
7988
7638
  process.stdin.once("data", (data) => {
7989
7639
  const input = data.toString().trim();
7990
7640
  if (input === "1") {
7991
- resolve6("global");
7641
+ resolve5("global");
7992
7642
  } else if (input === "2") {
7993
- resolve6("local");
7643
+ resolve5("local");
7994
7644
  } else {
7995
- resolve6(null);
7645
+ resolve5(null);
7996
7646
  }
7997
7647
  });
7998
7648
  process.stdin.once("close", () => {
7999
- resolve6(null);
7649
+ resolve5(null);
8000
7650
  });
8001
7651
  });
8002
7652
  }
@@ -8054,22 +7704,14 @@ async function main() {
8054
7704
  registerCommand({
8055
7705
  name: "update",
8056
7706
  description: "Clear cached plugin and refresh managed skill packs",
8057
- run: () => {
8058
- const result2 = runUpdate();
8059
- const skillModes = result2.success ? resolveUpdateSkillModes(args) : [];
8060
- const skillResults = result2.success ? skillModes.map((mode) => syncBundledSkills(mode)) : [];
8061
- const skillMessage = args.rawArgs.includes("--no-skills") ? "Managed skill refresh skipped (--no-skills)." : skillResults.length > 0 ? skillResults.map((entry) => entry.message).join("\n") : result2.success ? "No managed skill packs required refresh." : "";
8062
- const message = [result2.message, skillMessage].filter(Boolean).join("\n");
8063
- return {
8064
- success: result2.success && skillResults.every((entry) => entry.success),
8065
- message,
8066
- data: {
8067
- cacheCleared: result2.cleared,
8068
- skillModes,
8069
- skills: skillResults
8070
- }
8071
- };
8072
- }
7707
+ run: () => buildUpdateCommandResult(args, runUpdate(), {
7708
+ resolveUpdateSkillModes,
7709
+ hasInstalledConfig,
7710
+ hasBundledSkillArtifacts,
7711
+ getBundledSkillTargets,
7712
+ getBundledSkillLifecycleTargets,
7713
+ syncBundledSkillsForTargets
7714
+ })
8073
7715
  });
8074
7716
  registerCommand({
8075
7717
  name: "uninstall",
@@ -8085,18 +7727,11 @@ async function main() {
8085
7727
  if (!mode) {
8086
7728
  return { success: false, message: "Error: Please specify --global or --local for uninstall.", exitCode: EXIT_USAGE };
8087
7729
  }
8088
- const result2 = runUninstall(mode);
8089
- const skipSkills = args.rawArgs.includes("--no-skills");
8090
- const skillsResult = result2.success && !skipSkills ? removeBundledSkills(mode) : void 0;
8091
- const skillMessage = skipSkills ? "Managed skill cleanup skipped (--no-skills)." : skillsResult?.message ?? "";
8092
- return {
8093
- success: result2.success && (skillsResult?.success ?? true),
8094
- message: [result2.message, skillMessage].filter(Boolean).join("\n"),
8095
- data: {
8096
- config: result2,
8097
- skills: skillsResult
8098
- }
8099
- };
7730
+ return buildUninstallCommandResult(args, mode, runUninstall(mode), {
7731
+ hasBundledSkillArtifacts,
7732
+ getBundledSkillLifecycleTargets,
7733
+ removeBundledSkillsForTargets
7734
+ });
8100
7735
  }
8101
7736
  });
8102
7737
  registerCommand({