oh-my-opencode 2.5.3 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.ja.md +27 -20
  2. package/README.ko.md +27 -20
  3. package/README.md +57 -20
  4. package/README.zh-cn.md +27 -20
  5. package/dist/cli/get-local-version/formatter.d.ts +3 -0
  6. package/dist/cli/get-local-version/index.d.ts +3 -0
  7. package/dist/cli/get-local-version/types.d.ts +13 -0
  8. package/dist/cli/index.js +1422 -129
  9. package/dist/cli/run/events.d.ts +4 -0
  10. package/dist/cli/run/types.d.ts +26 -0
  11. package/dist/config/index.d.ts +1 -1
  12. package/dist/config/schema.d.ts +92 -7
  13. package/dist/features/background-agent/manager.d.ts +1 -0
  14. package/dist/features/background-agent/types.d.ts +8 -0
  15. package/dist/features/claude-code-plugin-loader/index.d.ts +3 -0
  16. package/dist/features/claude-code-plugin-loader/loader.d.ts +20 -0
  17. package/dist/features/claude-code-plugin-loader/types.d.ts +173 -0
  18. package/dist/hooks/anthropic-auto-compact/executor.test.d.ts +1 -0
  19. package/dist/hooks/anthropic-auto-compact/index.d.ts +1 -1
  20. package/dist/hooks/anthropic-auto-compact/pruning-deduplication.d.ts +7 -0
  21. package/dist/hooks/anthropic-auto-compact/pruning-deduplication.test.d.ts +1 -0
  22. package/dist/hooks/anthropic-auto-compact/pruning-executor.d.ts +3 -0
  23. package/dist/hooks/anthropic-auto-compact/pruning-purge-errors.d.ts +7 -0
  24. package/dist/hooks/anthropic-auto-compact/pruning-storage.d.ts +2 -0
  25. package/dist/hooks/anthropic-auto-compact/pruning-supersede.d.ts +6 -0
  26. package/dist/hooks/anthropic-auto-compact/pruning-types.d.ts +36 -0
  27. package/dist/hooks/anthropic-auto-compact/types.d.ts +5 -0
  28. package/dist/hooks/index.d.ts +1 -0
  29. package/dist/hooks/session-notification-utils.d.ts +9 -0
  30. package/dist/hooks/thinking-block-validator/index.d.ts +30 -0
  31. package/dist/index.js +2946 -814
  32. package/dist/shared/claude-config-dir.d.ts +1 -0
  33. package/dist/shared/claude-config-dir.test.d.ts +1 -0
  34. package/dist/shared/index.d.ts +2 -0
  35. package/dist/shared/jsonc-parser.d.ts +15 -0
  36. package/dist/shared/jsonc-parser.test.d.ts +1 -0
  37. package/dist/tools/ast-grep/index.d.ts +2 -90
  38. package/dist/tools/ast-grep/tools.d.ts +3 -88
  39. package/dist/tools/background-task/tools.d.ts +4 -38
  40. package/dist/tools/call-omo-agent/tools.d.ts +2 -21
  41. package/dist/tools/glob/tools.d.ts +2 -11
  42. package/dist/tools/grep/tools.d.ts +2 -13
  43. package/dist/tools/index.d.ts +3 -367
  44. package/dist/tools/interactive-bash/tools.d.ts +2 -9
  45. package/dist/tools/look-at/tools.d.ts +2 -12
  46. package/dist/tools/lsp/tools.d.ts +12 -152
  47. package/dist/tools/session-manager/tools.d.ts +5 -52
  48. package/dist/tools/slashcommand/tools.d.ts +2 -9
  49. package/package.json +2 -1
package/dist/cli/index.js CHANGED
@@ -2244,7 +2244,7 @@ var require_picocolors = __commonJS((exports, module) => {
2244
2244
  var require_package = __commonJS((exports, module) => {
2245
2245
  module.exports = {
2246
2246
  name: "oh-my-opencode",
2247
- version: "2.5.2",
2247
+ version: "2.5.4",
2248
2248
  description: "OpenCode plugin - custom agents (oracle, librarian) and enhanced features",
2249
2249
  main: "dist/index.js",
2250
2250
  types: "dist/index.d.ts",
@@ -2303,6 +2303,7 @@ var require_package = __commonJS((exports, module) => {
2303
2303
  "@opencode-ai/sdk": "^1.0.162",
2304
2304
  commander: "^14.0.2",
2305
2305
  hono: "^4.10.4",
2306
+ "jsonc-parser": "^3.3.1",
2306
2307
  picocolors: "^1.1.1",
2307
2308
  picomatch: "^4.0.2",
2308
2309
  "xdg-basedir": "^5.1.0",
@@ -2923,12 +2924,886 @@ var import_picocolors2 = __toESM(require_picocolors(), 1);
2923
2924
  // src/cli/config-manager.ts
2924
2925
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
2925
2926
  import { homedir } from "os";
2926
- import { join } from "path";
2927
- var OPENCODE_CONFIG_DIR = join(homedir(), ".config", "opencode");
2928
- var OPENCODE_JSON = join(OPENCODE_CONFIG_DIR, "opencode.json");
2929
- var OPENCODE_JSONC = join(OPENCODE_CONFIG_DIR, "opencode.jsonc");
2930
- var OPENCODE_PACKAGE_JSON = join(OPENCODE_CONFIG_DIR, "package.json");
2931
- var OMO_CONFIG = join(OPENCODE_CONFIG_DIR, "oh-my-opencode.json");
2927
+ import { join as join2 } from "path";
2928
+ // src/shared/command-executor.ts
2929
+ import { exec } from "child_process";
2930
+ import { promisify } from "util";
2931
+ var execAsync = promisify(exec);
2932
+ // src/shared/logger.ts
2933
+ import * as fs from "fs";
2934
+ import * as os from "os";
2935
+ import * as path from "path";
2936
+ var logFile = path.join(os.tmpdir(), "oh-my-opencode.log");
2937
+ function log(message, data) {
2938
+ try {
2939
+ const timestamp = new Date().toISOString();
2940
+ const logEntry = `[${timestamp}] ${message} ${data ? JSON.stringify(data) : ""}
2941
+ `;
2942
+ fs.appendFileSync(logFile, logEntry);
2943
+ } catch {}
2944
+ }
2945
+ // src/shared/deep-merge.ts
2946
+ var DANGEROUS_KEYS = new Set(["__proto__", "constructor", "prototype"]);
2947
+ // node_modules/jsonc-parser/lib/esm/impl/scanner.js
2948
+ function createScanner(text, ignoreTrivia = false) {
2949
+ const len = text.length;
2950
+ let pos = 0, value = "", tokenOffset = 0, token = 16, lineNumber = 0, lineStartOffset = 0, tokenLineStartOffset = 0, prevTokenLineStartOffset = 0, scanError = 0;
2951
+ function scanHexDigits(count, exact) {
2952
+ let digits = 0;
2953
+ let value2 = 0;
2954
+ while (digits < count || !exact) {
2955
+ let ch = text.charCodeAt(pos);
2956
+ if (ch >= 48 && ch <= 57) {
2957
+ value2 = value2 * 16 + ch - 48;
2958
+ } else if (ch >= 65 && ch <= 70) {
2959
+ value2 = value2 * 16 + ch - 65 + 10;
2960
+ } else if (ch >= 97 && ch <= 102) {
2961
+ value2 = value2 * 16 + ch - 97 + 10;
2962
+ } else {
2963
+ break;
2964
+ }
2965
+ pos++;
2966
+ digits++;
2967
+ }
2968
+ if (digits < count) {
2969
+ value2 = -1;
2970
+ }
2971
+ return value2;
2972
+ }
2973
+ function setPosition(newPosition) {
2974
+ pos = newPosition;
2975
+ value = "";
2976
+ tokenOffset = 0;
2977
+ token = 16;
2978
+ scanError = 0;
2979
+ }
2980
+ function scanNumber() {
2981
+ let start = pos;
2982
+ if (text.charCodeAt(pos) === 48) {
2983
+ pos++;
2984
+ } else {
2985
+ pos++;
2986
+ while (pos < text.length && isDigit(text.charCodeAt(pos))) {
2987
+ pos++;
2988
+ }
2989
+ }
2990
+ if (pos < text.length && text.charCodeAt(pos) === 46) {
2991
+ pos++;
2992
+ if (pos < text.length && isDigit(text.charCodeAt(pos))) {
2993
+ pos++;
2994
+ while (pos < text.length && isDigit(text.charCodeAt(pos))) {
2995
+ pos++;
2996
+ }
2997
+ } else {
2998
+ scanError = 3;
2999
+ return text.substring(start, pos);
3000
+ }
3001
+ }
3002
+ let end = pos;
3003
+ if (pos < text.length && (text.charCodeAt(pos) === 69 || text.charCodeAt(pos) === 101)) {
3004
+ pos++;
3005
+ if (pos < text.length && text.charCodeAt(pos) === 43 || text.charCodeAt(pos) === 45) {
3006
+ pos++;
3007
+ }
3008
+ if (pos < text.length && isDigit(text.charCodeAt(pos))) {
3009
+ pos++;
3010
+ while (pos < text.length && isDigit(text.charCodeAt(pos))) {
3011
+ pos++;
3012
+ }
3013
+ end = pos;
3014
+ } else {
3015
+ scanError = 3;
3016
+ }
3017
+ }
3018
+ return text.substring(start, end);
3019
+ }
3020
+ function scanString() {
3021
+ let result = "", start = pos;
3022
+ while (true) {
3023
+ if (pos >= len) {
3024
+ result += text.substring(start, pos);
3025
+ scanError = 2;
3026
+ break;
3027
+ }
3028
+ const ch = text.charCodeAt(pos);
3029
+ if (ch === 34) {
3030
+ result += text.substring(start, pos);
3031
+ pos++;
3032
+ break;
3033
+ }
3034
+ if (ch === 92) {
3035
+ result += text.substring(start, pos);
3036
+ pos++;
3037
+ if (pos >= len) {
3038
+ scanError = 2;
3039
+ break;
3040
+ }
3041
+ const ch2 = text.charCodeAt(pos++);
3042
+ switch (ch2) {
3043
+ case 34:
3044
+ result += '"';
3045
+ break;
3046
+ case 92:
3047
+ result += "\\";
3048
+ break;
3049
+ case 47:
3050
+ result += "/";
3051
+ break;
3052
+ case 98:
3053
+ result += "\b";
3054
+ break;
3055
+ case 102:
3056
+ result += "\f";
3057
+ break;
3058
+ case 110:
3059
+ result += `
3060
+ `;
3061
+ break;
3062
+ case 114:
3063
+ result += "\r";
3064
+ break;
3065
+ case 116:
3066
+ result += "\t";
3067
+ break;
3068
+ case 117:
3069
+ const ch3 = scanHexDigits(4, true);
3070
+ if (ch3 >= 0) {
3071
+ result += String.fromCharCode(ch3);
3072
+ } else {
3073
+ scanError = 4;
3074
+ }
3075
+ break;
3076
+ default:
3077
+ scanError = 5;
3078
+ }
3079
+ start = pos;
3080
+ continue;
3081
+ }
3082
+ if (ch >= 0 && ch <= 31) {
3083
+ if (isLineBreak(ch)) {
3084
+ result += text.substring(start, pos);
3085
+ scanError = 2;
3086
+ break;
3087
+ } else {
3088
+ scanError = 6;
3089
+ }
3090
+ }
3091
+ pos++;
3092
+ }
3093
+ return result;
3094
+ }
3095
+ function scanNext() {
3096
+ value = "";
3097
+ scanError = 0;
3098
+ tokenOffset = pos;
3099
+ lineStartOffset = lineNumber;
3100
+ prevTokenLineStartOffset = tokenLineStartOffset;
3101
+ if (pos >= len) {
3102
+ tokenOffset = len;
3103
+ return token = 17;
3104
+ }
3105
+ let code = text.charCodeAt(pos);
3106
+ if (isWhiteSpace(code)) {
3107
+ do {
3108
+ pos++;
3109
+ value += String.fromCharCode(code);
3110
+ code = text.charCodeAt(pos);
3111
+ } while (isWhiteSpace(code));
3112
+ return token = 15;
3113
+ }
3114
+ if (isLineBreak(code)) {
3115
+ pos++;
3116
+ value += String.fromCharCode(code);
3117
+ if (code === 13 && text.charCodeAt(pos) === 10) {
3118
+ pos++;
3119
+ value += `
3120
+ `;
3121
+ }
3122
+ lineNumber++;
3123
+ tokenLineStartOffset = pos;
3124
+ return token = 14;
3125
+ }
3126
+ switch (code) {
3127
+ case 123:
3128
+ pos++;
3129
+ return token = 1;
3130
+ case 125:
3131
+ pos++;
3132
+ return token = 2;
3133
+ case 91:
3134
+ pos++;
3135
+ return token = 3;
3136
+ case 93:
3137
+ pos++;
3138
+ return token = 4;
3139
+ case 58:
3140
+ pos++;
3141
+ return token = 6;
3142
+ case 44:
3143
+ pos++;
3144
+ return token = 5;
3145
+ case 34:
3146
+ pos++;
3147
+ value = scanString();
3148
+ return token = 10;
3149
+ case 47:
3150
+ const start = pos - 1;
3151
+ if (text.charCodeAt(pos + 1) === 47) {
3152
+ pos += 2;
3153
+ while (pos < len) {
3154
+ if (isLineBreak(text.charCodeAt(pos))) {
3155
+ break;
3156
+ }
3157
+ pos++;
3158
+ }
3159
+ value = text.substring(start, pos);
3160
+ return token = 12;
3161
+ }
3162
+ if (text.charCodeAt(pos + 1) === 42) {
3163
+ pos += 2;
3164
+ const safeLength = len - 1;
3165
+ let commentClosed = false;
3166
+ while (pos < safeLength) {
3167
+ const ch = text.charCodeAt(pos);
3168
+ if (ch === 42 && text.charCodeAt(pos + 1) === 47) {
3169
+ pos += 2;
3170
+ commentClosed = true;
3171
+ break;
3172
+ }
3173
+ pos++;
3174
+ if (isLineBreak(ch)) {
3175
+ if (ch === 13 && text.charCodeAt(pos) === 10) {
3176
+ pos++;
3177
+ }
3178
+ lineNumber++;
3179
+ tokenLineStartOffset = pos;
3180
+ }
3181
+ }
3182
+ if (!commentClosed) {
3183
+ pos++;
3184
+ scanError = 1;
3185
+ }
3186
+ value = text.substring(start, pos);
3187
+ return token = 13;
3188
+ }
3189
+ value += String.fromCharCode(code);
3190
+ pos++;
3191
+ return token = 16;
3192
+ case 45:
3193
+ value += String.fromCharCode(code);
3194
+ pos++;
3195
+ if (pos === len || !isDigit(text.charCodeAt(pos))) {
3196
+ return token = 16;
3197
+ }
3198
+ case 48:
3199
+ case 49:
3200
+ case 50:
3201
+ case 51:
3202
+ case 52:
3203
+ case 53:
3204
+ case 54:
3205
+ case 55:
3206
+ case 56:
3207
+ case 57:
3208
+ value += scanNumber();
3209
+ return token = 11;
3210
+ default:
3211
+ while (pos < len && isUnknownContentCharacter(code)) {
3212
+ pos++;
3213
+ code = text.charCodeAt(pos);
3214
+ }
3215
+ if (tokenOffset !== pos) {
3216
+ value = text.substring(tokenOffset, pos);
3217
+ switch (value) {
3218
+ case "true":
3219
+ return token = 8;
3220
+ case "false":
3221
+ return token = 9;
3222
+ case "null":
3223
+ return token = 7;
3224
+ }
3225
+ return token = 16;
3226
+ }
3227
+ value += String.fromCharCode(code);
3228
+ pos++;
3229
+ return token = 16;
3230
+ }
3231
+ }
3232
+ function isUnknownContentCharacter(code) {
3233
+ if (isWhiteSpace(code) || isLineBreak(code)) {
3234
+ return false;
3235
+ }
3236
+ switch (code) {
3237
+ case 125:
3238
+ case 93:
3239
+ case 123:
3240
+ case 91:
3241
+ case 34:
3242
+ case 58:
3243
+ case 44:
3244
+ case 47:
3245
+ return false;
3246
+ }
3247
+ return true;
3248
+ }
3249
+ function scanNextNonTrivia() {
3250
+ let result;
3251
+ do {
3252
+ result = scanNext();
3253
+ } while (result >= 12 && result <= 15);
3254
+ return result;
3255
+ }
3256
+ return {
3257
+ setPosition,
3258
+ getPosition: () => pos,
3259
+ scan: ignoreTrivia ? scanNextNonTrivia : scanNext,
3260
+ getToken: () => token,
3261
+ getTokenValue: () => value,
3262
+ getTokenOffset: () => tokenOffset,
3263
+ getTokenLength: () => pos - tokenOffset,
3264
+ getTokenStartLine: () => lineStartOffset,
3265
+ getTokenStartCharacter: () => tokenOffset - prevTokenLineStartOffset,
3266
+ getTokenError: () => scanError
3267
+ };
3268
+ }
3269
+ function isWhiteSpace(ch) {
3270
+ return ch === 32 || ch === 9;
3271
+ }
3272
+ function isLineBreak(ch) {
3273
+ return ch === 10 || ch === 13;
3274
+ }
3275
+ function isDigit(ch) {
3276
+ return ch >= 48 && ch <= 57;
3277
+ }
3278
+ var CharacterCodes;
3279
+ (function(CharacterCodes2) {
3280
+ CharacterCodes2[CharacterCodes2["lineFeed"] = 10] = "lineFeed";
3281
+ CharacterCodes2[CharacterCodes2["carriageReturn"] = 13] = "carriageReturn";
3282
+ CharacterCodes2[CharacterCodes2["space"] = 32] = "space";
3283
+ CharacterCodes2[CharacterCodes2["_0"] = 48] = "_0";
3284
+ CharacterCodes2[CharacterCodes2["_1"] = 49] = "_1";
3285
+ CharacterCodes2[CharacterCodes2["_2"] = 50] = "_2";
3286
+ CharacterCodes2[CharacterCodes2["_3"] = 51] = "_3";
3287
+ CharacterCodes2[CharacterCodes2["_4"] = 52] = "_4";
3288
+ CharacterCodes2[CharacterCodes2["_5"] = 53] = "_5";
3289
+ CharacterCodes2[CharacterCodes2["_6"] = 54] = "_6";
3290
+ CharacterCodes2[CharacterCodes2["_7"] = 55] = "_7";
3291
+ CharacterCodes2[CharacterCodes2["_8"] = 56] = "_8";
3292
+ CharacterCodes2[CharacterCodes2["_9"] = 57] = "_9";
3293
+ CharacterCodes2[CharacterCodes2["a"] = 97] = "a";
3294
+ CharacterCodes2[CharacterCodes2["b"] = 98] = "b";
3295
+ CharacterCodes2[CharacterCodes2["c"] = 99] = "c";
3296
+ CharacterCodes2[CharacterCodes2["d"] = 100] = "d";
3297
+ CharacterCodes2[CharacterCodes2["e"] = 101] = "e";
3298
+ CharacterCodes2[CharacterCodes2["f"] = 102] = "f";
3299
+ CharacterCodes2[CharacterCodes2["g"] = 103] = "g";
3300
+ CharacterCodes2[CharacterCodes2["h"] = 104] = "h";
3301
+ CharacterCodes2[CharacterCodes2["i"] = 105] = "i";
3302
+ CharacterCodes2[CharacterCodes2["j"] = 106] = "j";
3303
+ CharacterCodes2[CharacterCodes2["k"] = 107] = "k";
3304
+ CharacterCodes2[CharacterCodes2["l"] = 108] = "l";
3305
+ CharacterCodes2[CharacterCodes2["m"] = 109] = "m";
3306
+ CharacterCodes2[CharacterCodes2["n"] = 110] = "n";
3307
+ CharacterCodes2[CharacterCodes2["o"] = 111] = "o";
3308
+ CharacterCodes2[CharacterCodes2["p"] = 112] = "p";
3309
+ CharacterCodes2[CharacterCodes2["q"] = 113] = "q";
3310
+ CharacterCodes2[CharacterCodes2["r"] = 114] = "r";
3311
+ CharacterCodes2[CharacterCodes2["s"] = 115] = "s";
3312
+ CharacterCodes2[CharacterCodes2["t"] = 116] = "t";
3313
+ CharacterCodes2[CharacterCodes2["u"] = 117] = "u";
3314
+ CharacterCodes2[CharacterCodes2["v"] = 118] = "v";
3315
+ CharacterCodes2[CharacterCodes2["w"] = 119] = "w";
3316
+ CharacterCodes2[CharacterCodes2["x"] = 120] = "x";
3317
+ CharacterCodes2[CharacterCodes2["y"] = 121] = "y";
3318
+ CharacterCodes2[CharacterCodes2["z"] = 122] = "z";
3319
+ CharacterCodes2[CharacterCodes2["A"] = 65] = "A";
3320
+ CharacterCodes2[CharacterCodes2["B"] = 66] = "B";
3321
+ CharacterCodes2[CharacterCodes2["C"] = 67] = "C";
3322
+ CharacterCodes2[CharacterCodes2["D"] = 68] = "D";
3323
+ CharacterCodes2[CharacterCodes2["E"] = 69] = "E";
3324
+ CharacterCodes2[CharacterCodes2["F"] = 70] = "F";
3325
+ CharacterCodes2[CharacterCodes2["G"] = 71] = "G";
3326
+ CharacterCodes2[CharacterCodes2["H"] = 72] = "H";
3327
+ CharacterCodes2[CharacterCodes2["I"] = 73] = "I";
3328
+ CharacterCodes2[CharacterCodes2["J"] = 74] = "J";
3329
+ CharacterCodes2[CharacterCodes2["K"] = 75] = "K";
3330
+ CharacterCodes2[CharacterCodes2["L"] = 76] = "L";
3331
+ CharacterCodes2[CharacterCodes2["M"] = 77] = "M";
3332
+ CharacterCodes2[CharacterCodes2["N"] = 78] = "N";
3333
+ CharacterCodes2[CharacterCodes2["O"] = 79] = "O";
3334
+ CharacterCodes2[CharacterCodes2["P"] = 80] = "P";
3335
+ CharacterCodes2[CharacterCodes2["Q"] = 81] = "Q";
3336
+ CharacterCodes2[CharacterCodes2["R"] = 82] = "R";
3337
+ CharacterCodes2[CharacterCodes2["S"] = 83] = "S";
3338
+ CharacterCodes2[CharacterCodes2["T"] = 84] = "T";
3339
+ CharacterCodes2[CharacterCodes2["U"] = 85] = "U";
3340
+ CharacterCodes2[CharacterCodes2["V"] = 86] = "V";
3341
+ CharacterCodes2[CharacterCodes2["W"] = 87] = "W";
3342
+ CharacterCodes2[CharacterCodes2["X"] = 88] = "X";
3343
+ CharacterCodes2[CharacterCodes2["Y"] = 89] = "Y";
3344
+ CharacterCodes2[CharacterCodes2["Z"] = 90] = "Z";
3345
+ CharacterCodes2[CharacterCodes2["asterisk"] = 42] = "asterisk";
3346
+ CharacterCodes2[CharacterCodes2["backslash"] = 92] = "backslash";
3347
+ CharacterCodes2[CharacterCodes2["closeBrace"] = 125] = "closeBrace";
3348
+ CharacterCodes2[CharacterCodes2["closeBracket"] = 93] = "closeBracket";
3349
+ CharacterCodes2[CharacterCodes2["colon"] = 58] = "colon";
3350
+ CharacterCodes2[CharacterCodes2["comma"] = 44] = "comma";
3351
+ CharacterCodes2[CharacterCodes2["dot"] = 46] = "dot";
3352
+ CharacterCodes2[CharacterCodes2["doubleQuote"] = 34] = "doubleQuote";
3353
+ CharacterCodes2[CharacterCodes2["minus"] = 45] = "minus";
3354
+ CharacterCodes2[CharacterCodes2["openBrace"] = 123] = "openBrace";
3355
+ CharacterCodes2[CharacterCodes2["openBracket"] = 91] = "openBracket";
3356
+ CharacterCodes2[CharacterCodes2["plus"] = 43] = "plus";
3357
+ CharacterCodes2[CharacterCodes2["slash"] = 47] = "slash";
3358
+ CharacterCodes2[CharacterCodes2["formFeed"] = 12] = "formFeed";
3359
+ CharacterCodes2[CharacterCodes2["tab"] = 9] = "tab";
3360
+ })(CharacterCodes || (CharacterCodes = {}));
3361
+
3362
+ // node_modules/jsonc-parser/lib/esm/impl/string-intern.js
3363
+ var cachedSpaces = new Array(20).fill(0).map((_3, index) => {
3364
+ return " ".repeat(index);
3365
+ });
3366
+ var maxCachedValues = 200;
3367
+ var cachedBreakLinesWithSpaces = {
3368
+ " ": {
3369
+ "\n": new Array(maxCachedValues).fill(0).map((_3, index) => {
3370
+ return `
3371
+ ` + " ".repeat(index);
3372
+ }),
3373
+ "\r": new Array(maxCachedValues).fill(0).map((_3, index) => {
3374
+ return "\r" + " ".repeat(index);
3375
+ }),
3376
+ "\r\n": new Array(maxCachedValues).fill(0).map((_3, index) => {
3377
+ return `\r
3378
+ ` + " ".repeat(index);
3379
+ })
3380
+ },
3381
+ "\t": {
3382
+ "\n": new Array(maxCachedValues).fill(0).map((_3, index) => {
3383
+ return `
3384
+ ` + "\t".repeat(index);
3385
+ }),
3386
+ "\r": new Array(maxCachedValues).fill(0).map((_3, index) => {
3387
+ return "\r" + "\t".repeat(index);
3388
+ }),
3389
+ "\r\n": new Array(maxCachedValues).fill(0).map((_3, index) => {
3390
+ return `\r
3391
+ ` + "\t".repeat(index);
3392
+ })
3393
+ }
3394
+ };
3395
+
3396
+ // node_modules/jsonc-parser/lib/esm/impl/parser.js
3397
+ var ParseOptions;
3398
+ (function(ParseOptions2) {
3399
+ ParseOptions2.DEFAULT = {
3400
+ allowTrailingComma: false
3401
+ };
3402
+ })(ParseOptions || (ParseOptions = {}));
3403
+ function parse(text, errors = [], options = ParseOptions.DEFAULT) {
3404
+ let currentProperty = null;
3405
+ let currentParent = [];
3406
+ const previousParents = [];
3407
+ function onValue(value) {
3408
+ if (Array.isArray(currentParent)) {
3409
+ currentParent.push(value);
3410
+ } else if (currentProperty !== null) {
3411
+ currentParent[currentProperty] = value;
3412
+ }
3413
+ }
3414
+ const visitor = {
3415
+ onObjectBegin: () => {
3416
+ const object = {};
3417
+ onValue(object);
3418
+ previousParents.push(currentParent);
3419
+ currentParent = object;
3420
+ currentProperty = null;
3421
+ },
3422
+ onObjectProperty: (name) => {
3423
+ currentProperty = name;
3424
+ },
3425
+ onObjectEnd: () => {
3426
+ currentParent = previousParents.pop();
3427
+ },
3428
+ onArrayBegin: () => {
3429
+ const array = [];
3430
+ onValue(array);
3431
+ previousParents.push(currentParent);
3432
+ currentParent = array;
3433
+ currentProperty = null;
3434
+ },
3435
+ onArrayEnd: () => {
3436
+ currentParent = previousParents.pop();
3437
+ },
3438
+ onLiteralValue: onValue,
3439
+ onError: (error, offset, length) => {
3440
+ errors.push({ error, offset, length });
3441
+ }
3442
+ };
3443
+ visit(text, visitor, options);
3444
+ return currentParent[0];
3445
+ }
3446
+ function visit(text, visitor, options = ParseOptions.DEFAULT) {
3447
+ const _scanner = createScanner(text, false);
3448
+ const _jsonPath = [];
3449
+ let suppressedCallbacks = 0;
3450
+ function toNoArgVisit(visitFunction) {
3451
+ return visitFunction ? () => suppressedCallbacks === 0 && visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;
3452
+ }
3453
+ function toOneArgVisit(visitFunction) {
3454
+ return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;
3455
+ }
3456
+ function toOneArgVisitWithPath(visitFunction) {
3457
+ return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice()) : () => true;
3458
+ }
3459
+ function toBeginVisit(visitFunction) {
3460
+ return visitFunction ? () => {
3461
+ if (suppressedCallbacks > 0) {
3462
+ suppressedCallbacks++;
3463
+ } else {
3464
+ let cbReturn = visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice());
3465
+ if (cbReturn === false) {
3466
+ suppressedCallbacks = 1;
3467
+ }
3468
+ }
3469
+ } : () => true;
3470
+ }
3471
+ function toEndVisit(visitFunction) {
3472
+ return visitFunction ? () => {
3473
+ if (suppressedCallbacks > 0) {
3474
+ suppressedCallbacks--;
3475
+ }
3476
+ if (suppressedCallbacks === 0) {
3477
+ visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter());
3478
+ }
3479
+ } : () => true;
3480
+ }
3481
+ const onObjectBegin = toBeginVisit(visitor.onObjectBegin), onObjectProperty = toOneArgVisitWithPath(visitor.onObjectProperty), onObjectEnd = toEndVisit(visitor.onObjectEnd), onArrayBegin = toBeginVisit(visitor.onArrayBegin), onArrayEnd = toEndVisit(visitor.onArrayEnd), onLiteralValue = toOneArgVisitWithPath(visitor.onLiteralValue), onSeparator = toOneArgVisit(visitor.onSeparator), onComment = toNoArgVisit(visitor.onComment), onError = toOneArgVisit(visitor.onError);
3482
+ const disallowComments = options && options.disallowComments;
3483
+ const allowTrailingComma = options && options.allowTrailingComma;
3484
+ function scanNext() {
3485
+ while (true) {
3486
+ const token = _scanner.scan();
3487
+ switch (_scanner.getTokenError()) {
3488
+ case 4:
3489
+ handleError(14);
3490
+ break;
3491
+ case 5:
3492
+ handleError(15);
3493
+ break;
3494
+ case 3:
3495
+ handleError(13);
3496
+ break;
3497
+ case 1:
3498
+ if (!disallowComments) {
3499
+ handleError(11);
3500
+ }
3501
+ break;
3502
+ case 2:
3503
+ handleError(12);
3504
+ break;
3505
+ case 6:
3506
+ handleError(16);
3507
+ break;
3508
+ }
3509
+ switch (token) {
3510
+ case 12:
3511
+ case 13:
3512
+ if (disallowComments) {
3513
+ handleError(10);
3514
+ } else {
3515
+ onComment();
3516
+ }
3517
+ break;
3518
+ case 16:
3519
+ handleError(1);
3520
+ break;
3521
+ case 15:
3522
+ case 14:
3523
+ break;
3524
+ default:
3525
+ return token;
3526
+ }
3527
+ }
3528
+ }
3529
+ function handleError(error, skipUntilAfter = [], skipUntil = []) {
3530
+ onError(error);
3531
+ if (skipUntilAfter.length + skipUntil.length > 0) {
3532
+ let token = _scanner.getToken();
3533
+ while (token !== 17) {
3534
+ if (skipUntilAfter.indexOf(token) !== -1) {
3535
+ scanNext();
3536
+ break;
3537
+ } else if (skipUntil.indexOf(token) !== -1) {
3538
+ break;
3539
+ }
3540
+ token = scanNext();
3541
+ }
3542
+ }
3543
+ }
3544
+ function parseString(isValue) {
3545
+ const value = _scanner.getTokenValue();
3546
+ if (isValue) {
3547
+ onLiteralValue(value);
3548
+ } else {
3549
+ onObjectProperty(value);
3550
+ _jsonPath.push(value);
3551
+ }
3552
+ scanNext();
3553
+ return true;
3554
+ }
3555
+ function parseLiteral() {
3556
+ switch (_scanner.getToken()) {
3557
+ case 11:
3558
+ const tokenValue = _scanner.getTokenValue();
3559
+ let value = Number(tokenValue);
3560
+ if (isNaN(value)) {
3561
+ handleError(2);
3562
+ value = 0;
3563
+ }
3564
+ onLiteralValue(value);
3565
+ break;
3566
+ case 7:
3567
+ onLiteralValue(null);
3568
+ break;
3569
+ case 8:
3570
+ onLiteralValue(true);
3571
+ break;
3572
+ case 9:
3573
+ onLiteralValue(false);
3574
+ break;
3575
+ default:
3576
+ return false;
3577
+ }
3578
+ scanNext();
3579
+ return true;
3580
+ }
3581
+ function parseProperty() {
3582
+ if (_scanner.getToken() !== 10) {
3583
+ handleError(3, [], [2, 5]);
3584
+ return false;
3585
+ }
3586
+ parseString(false);
3587
+ if (_scanner.getToken() === 6) {
3588
+ onSeparator(":");
3589
+ scanNext();
3590
+ if (!parseValue()) {
3591
+ handleError(4, [], [2, 5]);
3592
+ }
3593
+ } else {
3594
+ handleError(5, [], [2, 5]);
3595
+ }
3596
+ _jsonPath.pop();
3597
+ return true;
3598
+ }
3599
+ function parseObject() {
3600
+ onObjectBegin();
3601
+ scanNext();
3602
+ let needsComma = false;
3603
+ while (_scanner.getToken() !== 2 && _scanner.getToken() !== 17) {
3604
+ if (_scanner.getToken() === 5) {
3605
+ if (!needsComma) {
3606
+ handleError(4, [], []);
3607
+ }
3608
+ onSeparator(",");
3609
+ scanNext();
3610
+ if (_scanner.getToken() === 2 && allowTrailingComma) {
3611
+ break;
3612
+ }
3613
+ } else if (needsComma) {
3614
+ handleError(6, [], []);
3615
+ }
3616
+ if (!parseProperty()) {
3617
+ handleError(4, [], [2, 5]);
3618
+ }
3619
+ needsComma = true;
3620
+ }
3621
+ onObjectEnd();
3622
+ if (_scanner.getToken() !== 2) {
3623
+ handleError(7, [2], []);
3624
+ } else {
3625
+ scanNext();
3626
+ }
3627
+ return true;
3628
+ }
3629
+ function parseArray() {
3630
+ onArrayBegin();
3631
+ scanNext();
3632
+ let isFirstElement = true;
3633
+ let needsComma = false;
3634
+ while (_scanner.getToken() !== 4 && _scanner.getToken() !== 17) {
3635
+ if (_scanner.getToken() === 5) {
3636
+ if (!needsComma) {
3637
+ handleError(4, [], []);
3638
+ }
3639
+ onSeparator(",");
3640
+ scanNext();
3641
+ if (_scanner.getToken() === 4 && allowTrailingComma) {
3642
+ break;
3643
+ }
3644
+ } else if (needsComma) {
3645
+ handleError(6, [], []);
3646
+ }
3647
+ if (isFirstElement) {
3648
+ _jsonPath.push(0);
3649
+ isFirstElement = false;
3650
+ } else {
3651
+ _jsonPath[_jsonPath.length - 1]++;
3652
+ }
3653
+ if (!parseValue()) {
3654
+ handleError(4, [], [4, 5]);
3655
+ }
3656
+ needsComma = true;
3657
+ }
3658
+ onArrayEnd();
3659
+ if (!isFirstElement) {
3660
+ _jsonPath.pop();
3661
+ }
3662
+ if (_scanner.getToken() !== 4) {
3663
+ handleError(8, [4], []);
3664
+ } else {
3665
+ scanNext();
3666
+ }
3667
+ return true;
3668
+ }
3669
+ function parseValue() {
3670
+ switch (_scanner.getToken()) {
3671
+ case 3:
3672
+ return parseArray();
3673
+ case 1:
3674
+ return parseObject();
3675
+ case 10:
3676
+ return parseString(true);
3677
+ default:
3678
+ return parseLiteral();
3679
+ }
3680
+ }
3681
+ scanNext();
3682
+ if (_scanner.getToken() === 17) {
3683
+ if (options.allowEmptyContent) {
3684
+ return true;
3685
+ }
3686
+ handleError(4, [], []);
3687
+ return false;
3688
+ }
3689
+ if (!parseValue()) {
3690
+ handleError(4, [], []);
3691
+ return false;
3692
+ }
3693
+ if (_scanner.getToken() !== 17) {
3694
+ handleError(9, [], []);
3695
+ }
3696
+ return true;
3697
+ }
3698
+
3699
+ // node_modules/jsonc-parser/lib/esm/main.js
3700
+ var ScanError;
3701
+ (function(ScanError2) {
3702
+ ScanError2[ScanError2["None"] = 0] = "None";
3703
+ ScanError2[ScanError2["UnexpectedEndOfComment"] = 1] = "UnexpectedEndOfComment";
3704
+ ScanError2[ScanError2["UnexpectedEndOfString"] = 2] = "UnexpectedEndOfString";
3705
+ ScanError2[ScanError2["UnexpectedEndOfNumber"] = 3] = "UnexpectedEndOfNumber";
3706
+ ScanError2[ScanError2["InvalidUnicode"] = 4] = "InvalidUnicode";
3707
+ ScanError2[ScanError2["InvalidEscapeCharacter"] = 5] = "InvalidEscapeCharacter";
3708
+ ScanError2[ScanError2["InvalidCharacter"] = 6] = "InvalidCharacter";
3709
+ })(ScanError || (ScanError = {}));
3710
+ var SyntaxKind;
3711
+ (function(SyntaxKind2) {
3712
+ SyntaxKind2[SyntaxKind2["OpenBraceToken"] = 1] = "OpenBraceToken";
3713
+ SyntaxKind2[SyntaxKind2["CloseBraceToken"] = 2] = "CloseBraceToken";
3714
+ SyntaxKind2[SyntaxKind2["OpenBracketToken"] = 3] = "OpenBracketToken";
3715
+ SyntaxKind2[SyntaxKind2["CloseBracketToken"] = 4] = "CloseBracketToken";
3716
+ SyntaxKind2[SyntaxKind2["CommaToken"] = 5] = "CommaToken";
3717
+ SyntaxKind2[SyntaxKind2["ColonToken"] = 6] = "ColonToken";
3718
+ SyntaxKind2[SyntaxKind2["NullKeyword"] = 7] = "NullKeyword";
3719
+ SyntaxKind2[SyntaxKind2["TrueKeyword"] = 8] = "TrueKeyword";
3720
+ SyntaxKind2[SyntaxKind2["FalseKeyword"] = 9] = "FalseKeyword";
3721
+ SyntaxKind2[SyntaxKind2["StringLiteral"] = 10] = "StringLiteral";
3722
+ SyntaxKind2[SyntaxKind2["NumericLiteral"] = 11] = "NumericLiteral";
3723
+ SyntaxKind2[SyntaxKind2["LineCommentTrivia"] = 12] = "LineCommentTrivia";
3724
+ SyntaxKind2[SyntaxKind2["BlockCommentTrivia"] = 13] = "BlockCommentTrivia";
3725
+ SyntaxKind2[SyntaxKind2["LineBreakTrivia"] = 14] = "LineBreakTrivia";
3726
+ SyntaxKind2[SyntaxKind2["Trivia"] = 15] = "Trivia";
3727
+ SyntaxKind2[SyntaxKind2["Unknown"] = 16] = "Unknown";
3728
+ SyntaxKind2[SyntaxKind2["EOF"] = 17] = "EOF";
3729
+ })(SyntaxKind || (SyntaxKind = {}));
3730
+ var parse2 = parse;
3731
+ var ParseErrorCode;
3732
+ (function(ParseErrorCode2) {
3733
+ ParseErrorCode2[ParseErrorCode2["InvalidSymbol"] = 1] = "InvalidSymbol";
3734
+ ParseErrorCode2[ParseErrorCode2["InvalidNumberFormat"] = 2] = "InvalidNumberFormat";
3735
+ ParseErrorCode2[ParseErrorCode2["PropertyNameExpected"] = 3] = "PropertyNameExpected";
3736
+ ParseErrorCode2[ParseErrorCode2["ValueExpected"] = 4] = "ValueExpected";
3737
+ ParseErrorCode2[ParseErrorCode2["ColonExpected"] = 5] = "ColonExpected";
3738
+ ParseErrorCode2[ParseErrorCode2["CommaExpected"] = 6] = "CommaExpected";
3739
+ ParseErrorCode2[ParseErrorCode2["CloseBraceExpected"] = 7] = "CloseBraceExpected";
3740
+ ParseErrorCode2[ParseErrorCode2["CloseBracketExpected"] = 8] = "CloseBracketExpected";
3741
+ ParseErrorCode2[ParseErrorCode2["EndOfFileExpected"] = 9] = "EndOfFileExpected";
3742
+ ParseErrorCode2[ParseErrorCode2["InvalidCommentToken"] = 10] = "InvalidCommentToken";
3743
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfComment"] = 11] = "UnexpectedEndOfComment";
3744
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfString"] = 12] = "UnexpectedEndOfString";
3745
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfNumber"] = 13] = "UnexpectedEndOfNumber";
3746
+ ParseErrorCode2[ParseErrorCode2["InvalidUnicode"] = 14] = "InvalidUnicode";
3747
+ ParseErrorCode2[ParseErrorCode2["InvalidEscapeCharacter"] = 15] = "InvalidEscapeCharacter";
3748
+ ParseErrorCode2[ParseErrorCode2["InvalidCharacter"] = 16] = "InvalidCharacter";
3749
+ })(ParseErrorCode || (ParseErrorCode = {}));
3750
+ function printParseErrorCode(code) {
3751
+ switch (code) {
3752
+ case 1:
3753
+ return "InvalidSymbol";
3754
+ case 2:
3755
+ return "InvalidNumberFormat";
3756
+ case 3:
3757
+ return "PropertyNameExpected";
3758
+ case 4:
3759
+ return "ValueExpected";
3760
+ case 5:
3761
+ return "ColonExpected";
3762
+ case 6:
3763
+ return "CommaExpected";
3764
+ case 7:
3765
+ return "CloseBraceExpected";
3766
+ case 8:
3767
+ return "CloseBracketExpected";
3768
+ case 9:
3769
+ return "EndOfFileExpected";
3770
+ case 10:
3771
+ return "InvalidCommentToken";
3772
+ case 11:
3773
+ return "UnexpectedEndOfComment";
3774
+ case 12:
3775
+ return "UnexpectedEndOfString";
3776
+ case 13:
3777
+ return "UnexpectedEndOfNumber";
3778
+ case 14:
3779
+ return "InvalidUnicode";
3780
+ case 15:
3781
+ return "InvalidEscapeCharacter";
3782
+ case 16:
3783
+ return "InvalidCharacter";
3784
+ }
3785
+ return "<unknown ParseErrorCode>";
3786
+ }
3787
+
3788
+ // src/shared/jsonc-parser.ts
3789
+ function parseJsonc(content) {
3790
+ const errors = [];
3791
+ const result = parse2(content, errors, {
3792
+ allowTrailingComma: true,
3793
+ disallowComments: false
3794
+ });
3795
+ if (errors.length > 0) {
3796
+ const errorMessages = errors.map((e2) => `${printParseErrorCode(e2.error)} at offset ${e2.offset}`).join(", ");
3797
+ throw new SyntaxError(`JSONC parse error: ${errorMessages}`);
3798
+ }
3799
+ return result;
3800
+ }
3801
+ // src/cli/config-manager.ts
3802
+ var OPENCODE_CONFIG_DIR = join2(homedir(), ".config", "opencode");
3803
+ var OPENCODE_JSON = join2(OPENCODE_CONFIG_DIR, "opencode.json");
3804
+ var OPENCODE_JSONC = join2(OPENCODE_CONFIG_DIR, "opencode.jsonc");
3805
+ var OPENCODE_PACKAGE_JSON = join2(OPENCODE_CONFIG_DIR, "package.json");
3806
+ var OMO_CONFIG = join2(OPENCODE_CONFIG_DIR, "oh-my-opencode.json");
2932
3807
  var CHATGPT_HOTFIX_REPO = "code-yeongyu/opencode-openai-codex-auth#fix/orphaned-function-call-output-with-tools";
2933
3808
  async function fetchLatestVersion(packageName) {
2934
3809
  try {
@@ -2950,67 +3825,10 @@ function detectConfigFormat() {
2950
3825
  }
2951
3826
  return { format: "none", path: OPENCODE_JSON };
2952
3827
  }
2953
- function stripJsoncComments(content) {
2954
- let result = "";
2955
- let i = 0;
2956
- let inString = false;
2957
- let escape = false;
2958
- while (i < content.length) {
2959
- const char = content[i];
2960
- if (escape) {
2961
- result += char;
2962
- escape = false;
2963
- i++;
2964
- continue;
2965
- }
2966
- if (char === "\\") {
2967
- result += char;
2968
- escape = true;
2969
- i++;
2970
- continue;
2971
- }
2972
- if (char === '"' && !inString) {
2973
- inString = true;
2974
- result += char;
2975
- i++;
2976
- continue;
2977
- }
2978
- if (char === '"' && inString) {
2979
- inString = false;
2980
- result += char;
2981
- i++;
2982
- continue;
2983
- }
2984
- if (inString) {
2985
- result += char;
2986
- i++;
2987
- continue;
2988
- }
2989
- if (char === "/" && content[i + 1] === "/") {
2990
- while (i < content.length && content[i] !== `
2991
- `) {
2992
- i++;
2993
- }
2994
- continue;
2995
- }
2996
- if (char === "/" && content[i + 1] === "*") {
2997
- i += 2;
2998
- while (i < content.length - 1 && !(content[i] === "*" && content[i + 1] === "/")) {
2999
- i++;
3000
- }
3001
- i += 2;
3002
- continue;
3003
- }
3004
- result += char;
3005
- i++;
3006
- }
3007
- return result.replace(/,(\s*[}\]])/g, "$1");
3008
- }
3009
- function parseConfig(path, isJsonc) {
3828
+ function parseConfig(path2, isJsonc) {
3010
3829
  try {
3011
- const content = readFileSync(path, "utf-8");
3012
- const cleaned = isJsonc ? stripJsoncComments(content) : content;
3013
- return JSON.parse(cleaned);
3830
+ const content = readFileSync(path2, "utf-8");
3831
+ return parseJsonc(content);
3014
3832
  } catch {
3015
3833
  return null;
3016
3834
  }
@@ -3022,26 +3840,26 @@ function ensureConfigDir() {
3022
3840
  }
3023
3841
  function addPluginToOpenCodeConfig() {
3024
3842
  ensureConfigDir();
3025
- const { format, path } = detectConfigFormat();
3843
+ const { format: format2, path: path2 } = detectConfigFormat();
3026
3844
  const pluginName = "oh-my-opencode";
3027
3845
  try {
3028
- if (format === "none") {
3846
+ if (format2 === "none") {
3029
3847
  const config2 = { plugin: [pluginName] };
3030
- writeFileSync(path, JSON.stringify(config2, null, 2) + `
3848
+ writeFileSync(path2, JSON.stringify(config2, null, 2) + `
3031
3849
  `);
3032
- return { success: true, configPath: path };
3850
+ return { success: true, configPath: path2 };
3033
3851
  }
3034
- const config = parseConfig(path, format === "jsonc");
3852
+ const config = parseConfig(path2, format2 === "jsonc");
3035
3853
  if (!config) {
3036
- return { success: false, configPath: path, error: "Failed to parse config" };
3854
+ return { success: false, configPath: path2, error: "Failed to parse config" };
3037
3855
  }
3038
3856
  const plugins = config.plugin ?? [];
3039
3857
  if (plugins.some((p2) => p2.startsWith(pluginName))) {
3040
- return { success: true, configPath: path };
3858
+ return { success: true, configPath: path2 };
3041
3859
  }
3042
3860
  config.plugin = [...plugins, pluginName];
3043
- if (format === "jsonc") {
3044
- const content = readFileSync(path, "utf-8");
3861
+ if (format2 === "jsonc") {
3862
+ const content = readFileSync(path2, "utf-8");
3045
3863
  const pluginArrayRegex = /"plugin"\s*:\s*\[([\s\S]*?)\]/;
3046
3864
  const match = content.match(pluginArrayRegex);
3047
3865
  if (match) {
@@ -3051,19 +3869,19 @@ function addPluginToOpenCodeConfig() {
3051
3869
  const newContent = content.replace(pluginArrayRegex, `"plugin": [
3052
3870
  ${newArrayContent}
3053
3871
  ]`);
3054
- writeFileSync(path, newContent);
3872
+ writeFileSync(path2, newContent);
3055
3873
  } else {
3056
3874
  const newContent = content.replace(/^(\s*\{)/, `$1
3057
3875
  "plugin": ["${pluginName}"],`);
3058
- writeFileSync(path, newContent);
3876
+ writeFileSync(path2, newContent);
3059
3877
  }
3060
3878
  } else {
3061
- writeFileSync(path, JSON.stringify(config, null, 2) + `
3879
+ writeFileSync(path2, JSON.stringify(config, null, 2) + `
3062
3880
  `);
3063
3881
  }
3064
- return { success: true, configPath: path };
3882
+ return { success: true, configPath: path2 };
3065
3883
  } catch (err) {
3066
- return { success: false, configPath: path, error: String(err) };
3884
+ return { success: false, configPath: path2, error: String(err) };
3067
3885
  }
3068
3886
  }
3069
3887
  function deepMerge(target, source) {
@@ -3119,8 +3937,7 @@ function writeOmoConfig(installConfig) {
3119
3937
  const newConfig = generateOmoConfig(installConfig);
3120
3938
  if (existsSync(OMO_CONFIG)) {
3121
3939
  const content = readFileSync(OMO_CONFIG, "utf-8");
3122
- const cleaned = stripJsoncComments(content);
3123
- const existing = JSON.parse(cleaned);
3940
+ const existing = parseJsonc(content);
3124
3941
  delete existing.agents;
3125
3942
  const merged = deepMerge(existing, newConfig);
3126
3943
  writeFileSync(OMO_CONFIG, JSON.stringify(merged, null, 2) + `
@@ -3161,9 +3978,9 @@ async function getOpenCodeVersion() {
3161
3978
  }
3162
3979
  async function addAuthPlugins(config) {
3163
3980
  ensureConfigDir();
3164
- const { format, path } = detectConfigFormat();
3981
+ const { format: format2, path: path2 } = detectConfigFormat();
3165
3982
  try {
3166
- const existingConfig = format !== "none" ? parseConfig(path, format === "jsonc") : null;
3983
+ const existingConfig = format2 !== "none" ? parseConfig(path2, format2 === "jsonc") : null;
3167
3984
  const plugins = existingConfig?.plugin ?? [];
3168
3985
  if (config.hasGemini) {
3169
3986
  const version = await fetchLatestVersion("opencode-antigravity-auth");
@@ -3178,11 +3995,11 @@ async function addAuthPlugins(config) {
3178
3995
  }
3179
3996
  }
3180
3997
  const newConfig = { ...existingConfig ?? {}, plugin: plugins };
3181
- writeFileSync(path, JSON.stringify(newConfig, null, 2) + `
3998
+ writeFileSync(path2, JSON.stringify(newConfig, null, 2) + `
3182
3999
  `);
3183
- return { success: true, configPath: path };
4000
+ return { success: true, configPath: path2 };
3184
4001
  } catch (err) {
3185
- return { success: false, configPath: path, error: String(err) };
4002
+ return { success: false, configPath: path2, error: String(err) };
3186
4003
  }
3187
4004
  }
3188
4005
  function setupChatGPTHotfix() {
@@ -3270,9 +4087,9 @@ var CODEX_PROVIDER_CONFIG = {
3270
4087
  };
3271
4088
  function addProviderConfig(config) {
3272
4089
  ensureConfigDir();
3273
- const { format, path } = detectConfigFormat();
4090
+ const { format: format2, path: path2 } = detectConfigFormat();
3274
4091
  try {
3275
- const existingConfig = format !== "none" ? parseConfig(path, format === "jsonc") : null;
4092
+ const existingConfig = format2 !== "none" ? parseConfig(path2, format2 === "jsonc") : null;
3276
4093
  const newConfig = { ...existingConfig ?? {} };
3277
4094
  const providers = newConfig.provider ?? {};
3278
4095
  if (config.hasGemini) {
@@ -3284,11 +4101,11 @@ function addProviderConfig(config) {
3284
4101
  if (Object.keys(providers).length > 0) {
3285
4102
  newConfig.provider = providers;
3286
4103
  }
3287
- writeFileSync(path, JSON.stringify(newConfig, null, 2) + `
4104
+ writeFileSync(path2, JSON.stringify(newConfig, null, 2) + `
3288
4105
  `);
3289
- return { success: true, configPath: path };
4106
+ return { success: true, configPath: path2 };
3290
4107
  } catch (err) {
3291
- return { success: false, configPath: path, error: String(err) };
4108
+ return { success: false, configPath: path2, error: String(err) };
3292
4109
  }
3293
4110
  }
3294
4111
  function detectCurrentConfig() {
@@ -3299,11 +4116,11 @@ function detectCurrentConfig() {
3299
4116
  hasChatGPT: true,
3300
4117
  hasGemini: false
3301
4118
  };
3302
- const { format, path } = detectConfigFormat();
3303
- if (format === "none") {
4119
+ const { format: format2, path: path2 } = detectConfigFormat();
4120
+ if (format2 === "none") {
3304
4121
  return result;
3305
4122
  }
3306
- const openCodeConfig = parseConfig(path, format === "jsonc");
4123
+ const openCodeConfig = parseConfig(path2, format2 === "jsonc");
3307
4124
  if (!openCodeConfig) {
3308
4125
  return result;
3309
4126
  }
@@ -3319,7 +4136,7 @@ function detectCurrentConfig() {
3319
4136
  }
3320
4137
  try {
3321
4138
  const content = readFileSync(OMO_CONFIG, "utf-8");
3322
- const omoConfig = JSON.parse(stripJsoncComments(content));
4139
+ const omoConfig = parseJsonc(content);
3323
4140
  const agents = omoConfig.agents ?? {};
3324
4141
  if (agents["Sisyphus"]?.model === "opencode/big-pickle") {
3325
4142
  result.hasClaude = false;
@@ -3946,7 +4763,7 @@ var serializeObjectParam = ({ allowReserved, explode, name, style, value, valueO
3946
4763
 
3947
4764
  // node_modules/@opencode-ai/sdk/dist/gen/core/utils.gen.js
3948
4765
  var PATH_PARAM_RE = /\{[^{}]+\}/g;
3949
- var defaultPathSerializer = ({ path, url: _url }) => {
4766
+ var defaultPathSerializer = ({ path: path2, url: _url }) => {
3950
4767
  let url = _url;
3951
4768
  const matches = _url.match(PATH_PARAM_RE);
3952
4769
  if (matches) {
@@ -3965,7 +4782,7 @@ var defaultPathSerializer = ({ path, url: _url }) => {
3965
4782
  name = name.substring(1);
3966
4783
  style = "matrix";
3967
4784
  }
3968
- const value = path[name];
4785
+ const value = path2[name];
3969
4786
  if (value === undefined || value === null) {
3970
4787
  continue;
3971
4788
  }
@@ -3996,11 +4813,11 @@ var defaultPathSerializer = ({ path, url: _url }) => {
3996
4813
  }
3997
4814
  return url;
3998
4815
  };
3999
- var getUrl = ({ baseUrl, path, query, querySerializer, url: _url }) => {
4816
+ var getUrl = ({ baseUrl, path: path2, query, querySerializer, url: _url }) => {
4000
4817
  const pathUrl = _url.startsWith("/") ? _url : `/${_url}`;
4001
4818
  let url = (baseUrl ?? "") + pathUrl;
4002
- if (path) {
4003
- url = defaultPathSerializer({ path, url });
4819
+ if (path2) {
4820
+ url = defaultPathSerializer({ path: path2, url });
4004
4821
  }
4005
4822
  let search = query ? querySerializer(query) : "";
4006
4823
  if (search.startsWith("?")) {
@@ -5152,7 +5969,7 @@ async function createOpencode(options) {
5152
5969
  }
5153
5970
 
5154
5971
  // src/cli/run/runner.ts
5155
- var import_picocolors4 = __toESM(require_picocolors(), 1);
5972
+ var import_picocolors5 = __toESM(require_picocolors(), 1);
5156
5973
 
5157
5974
  // src/cli/run/completion.ts
5158
5975
  var import_picocolors3 = __toESM(require_picocolors(), 1);
@@ -5165,7 +5982,8 @@ async function checkCompletionConditions(ctx) {
5165
5982
  return false;
5166
5983
  }
5167
5984
  return true;
5168
- } catch {
5985
+ } catch (err) {
5986
+ console.error(import_picocolors3.default.red(`[completion] API error: ${err}`));
5169
5987
  return false;
5170
5988
  }
5171
5989
  }
@@ -5207,10 +6025,15 @@ async function areAllDescendantsIdle(ctx, sessionID, allStatuses) {
5207
6025
  }
5208
6026
 
5209
6027
  // src/cli/run/events.ts
6028
+ var import_picocolors4 = __toESM(require_picocolors(), 1);
5210
6029
  function createEventState() {
5211
6030
  return {
5212
6031
  mainSessionIdle: false,
5213
- lastOutput: ""
6032
+ mainSessionError: false,
6033
+ lastError: null,
6034
+ lastOutput: "",
6035
+ lastPartText: "",
6036
+ currentTool: null
5214
6037
  };
5215
6038
  }
5216
6039
  async function processEvents(ctx, stream, state) {
@@ -5218,13 +6041,76 @@ async function processEvents(ctx, stream, state) {
5218
6041
  if (ctx.abortController.signal.aborted)
5219
6042
  break;
5220
6043
  try {
5221
- const payload = event.payload;
5222
- if (!payload)
6044
+ const payload = event;
6045
+ if (!payload?.type) {
6046
+ console.error(import_picocolors4.default.dim(`[event] no type: ${JSON.stringify(event)}`));
5223
6047
  continue;
6048
+ }
6049
+ logEventVerbose(ctx, payload);
6050
+ handleSessionError(ctx, payload, state);
5224
6051
  handleSessionIdle(ctx, payload, state);
5225
6052
  handleSessionStatus(ctx, payload, state);
6053
+ handleMessagePartUpdated(ctx, payload, state);
5226
6054
  handleMessageUpdated(ctx, payload, state);
5227
- } catch {}
6055
+ handleToolExecute(ctx, payload, state);
6056
+ handleToolResult(ctx, payload, state);
6057
+ } catch (err) {
6058
+ console.error(import_picocolors4.default.red(`[event error] ${err}`));
6059
+ }
6060
+ }
6061
+ }
6062
+ function logEventVerbose(ctx, payload) {
6063
+ const props = payload.properties;
6064
+ const info = props?.info;
6065
+ const sessionID = props?.sessionID ?? info?.sessionID;
6066
+ const isMainSession = sessionID === ctx.sessionID;
6067
+ const sessionTag = isMainSession ? import_picocolors4.default.green("[MAIN]") : import_picocolors4.default.yellow(`[${String(sessionID).slice(0, 8)}]`);
6068
+ switch (payload.type) {
6069
+ case "session.idle":
6070
+ case "session.status": {
6071
+ const status = props?.status?.type ?? "idle";
6072
+ console.error(import_picocolors4.default.dim(`${sessionTag} ${payload.type}: ${status}`));
6073
+ break;
6074
+ }
6075
+ case "message.part.updated": {
6076
+ const partProps = props;
6077
+ const role = partProps?.info?.role ?? "unknown";
6078
+ const part = partProps?.part;
6079
+ if (part?.type === "text" && part.text) {
6080
+ const preview = part.text.slice(0, 100).replace(/\n/g, "\\n");
6081
+ console.error(import_picocolors4.default.dim(`${sessionTag} message.part (${role}): "${preview}${part.text.length > 100 ? "..." : ""}"`));
6082
+ } else if (part?.type === "tool-invocation") {
6083
+ const toolPart = part;
6084
+ console.error(import_picocolors4.default.dim(`${sessionTag} message.part (tool): ${toolPart.toolName} [${toolPart.state}]`));
6085
+ }
6086
+ break;
6087
+ }
6088
+ case "message.updated": {
6089
+ const msgProps = props;
6090
+ const role = msgProps?.info?.role ?? "unknown";
6091
+ const content = msgProps?.content ?? "";
6092
+ const preview = content.slice(0, 100).replace(/\n/g, "\\n");
6093
+ console.error(import_picocolors4.default.dim(`${sessionTag} message.updated (${role}): "${preview}${content.length > 100 ? "..." : ""}"`));
6094
+ break;
6095
+ }
6096
+ case "tool.execute": {
6097
+ const toolProps = props;
6098
+ const toolName = toolProps?.name ?? "unknown";
6099
+ const input = toolProps?.input ?? {};
6100
+ const inputStr = JSON.stringify(input).slice(0, 150);
6101
+ console.error(import_picocolors4.default.cyan(`${sessionTag} \u26A1 TOOL.EXECUTE: ${import_picocolors4.default.bold(toolName)}`));
6102
+ console.error(import_picocolors4.default.dim(` input: ${inputStr}${inputStr.length >= 150 ? "..." : ""}`));
6103
+ break;
6104
+ }
6105
+ case "tool.result": {
6106
+ const resultProps = props;
6107
+ const output = resultProps?.output ?? "";
6108
+ const preview = output.slice(0, 200).replace(/\n/g, "\\n");
6109
+ console.error(import_picocolors4.default.green(`${sessionTag} \u2713 TOOL.RESULT: "${preview}${output.length > 200 ? "..." : ""}"`));
6110
+ break;
6111
+ }
6112
+ default:
6113
+ console.error(import_picocolors4.default.dim(`${sessionTag} ${payload.type}`));
5228
6114
  }
5229
6115
  }
5230
6116
  function handleSessionIdle(ctx, payload, state) {
@@ -5243,6 +6129,36 @@ function handleSessionStatus(ctx, payload, state) {
5243
6129
  state.mainSessionIdle = false;
5244
6130
  }
5245
6131
  }
6132
+ function handleSessionError(ctx, payload, state) {
6133
+ if (payload.type !== "session.error")
6134
+ return;
6135
+ const props = payload.properties;
6136
+ if (props?.sessionID === ctx.sessionID) {
6137
+ state.mainSessionError = true;
6138
+ state.lastError = props?.error ? String(props.error instanceof Error ? props.error.message : props.error) : "Unknown error";
6139
+ console.error(import_picocolors4.default.red(`
6140
+ [session.error] ${state.lastError}`));
6141
+ }
6142
+ }
6143
+ function handleMessagePartUpdated(ctx, payload, state) {
6144
+ if (payload.type !== "message.part.updated")
6145
+ return;
6146
+ const props = payload.properties;
6147
+ if (props?.info?.sessionID !== ctx.sessionID)
6148
+ return;
6149
+ if (props?.info?.role !== "assistant")
6150
+ return;
6151
+ const part = props.part;
6152
+ if (!part)
6153
+ return;
6154
+ if (part.type === "text" && part.text) {
6155
+ const newText = part.text.slice(state.lastPartText.length);
6156
+ if (newText) {
6157
+ process.stdout.write(newText);
6158
+ }
6159
+ state.lastPartText = part.text;
6160
+ }
6161
+ }
5246
6162
  function handleMessageUpdated(ctx, payload, state) {
5247
6163
  if (payload.type !== "message.updated")
5248
6164
  return;
@@ -5254,16 +6170,62 @@ function handleMessageUpdated(ctx, payload, state) {
5254
6170
  const content = props.content;
5255
6171
  if (!content || content === state.lastOutput)
5256
6172
  return;
5257
- const newContent = content.slice(state.lastOutput.length);
5258
- if (newContent) {
5259
- process.stdout.write(newContent);
6173
+ if (state.lastPartText.length === 0) {
6174
+ const newContent = content.slice(state.lastOutput.length);
6175
+ if (newContent) {
6176
+ process.stdout.write(newContent);
6177
+ }
5260
6178
  }
5261
6179
  state.lastOutput = content;
5262
6180
  }
6181
+ function handleToolExecute(ctx, payload, state) {
6182
+ if (payload.type !== "tool.execute")
6183
+ return;
6184
+ const props = payload.properties;
6185
+ if (props?.sessionID !== ctx.sessionID)
6186
+ return;
6187
+ const toolName = props?.name || "unknown";
6188
+ state.currentTool = toolName;
6189
+ let inputPreview = "";
6190
+ if (props?.input) {
6191
+ const input = props.input;
6192
+ if (input.command) {
6193
+ inputPreview = ` ${import_picocolors4.default.dim(String(input.command).slice(0, 60))}`;
6194
+ } else if (input.pattern) {
6195
+ inputPreview = ` ${import_picocolors4.default.dim(String(input.pattern).slice(0, 40))}`;
6196
+ } else if (input.filePath) {
6197
+ inputPreview = ` ${import_picocolors4.default.dim(String(input.filePath))}`;
6198
+ } else if (input.query) {
6199
+ inputPreview = ` ${import_picocolors4.default.dim(String(input.query).slice(0, 40))}`;
6200
+ }
6201
+ }
6202
+ process.stdout.write(`
6203
+ ${import_picocolors4.default.cyan("\u26A1")} ${import_picocolors4.default.bold(toolName)}${inputPreview}
6204
+ `);
6205
+ }
6206
+ function handleToolResult(ctx, payload, state) {
6207
+ if (payload.type !== "tool.result")
6208
+ return;
6209
+ const props = payload.properties;
6210
+ if (props?.sessionID !== ctx.sessionID)
6211
+ return;
6212
+ const output = props?.output || "";
6213
+ const maxLen = 200;
6214
+ const preview = output.length > maxLen ? output.slice(0, maxLen) + "..." : output;
6215
+ if (preview.trim()) {
6216
+ const lines = preview.split(`
6217
+ `).slice(0, 3);
6218
+ process.stdout.write(import_picocolors4.default.dim(` \u2514\u2500 ${lines.join(`
6219
+ `)}
6220
+ `));
6221
+ }
6222
+ state.currentTool = null;
6223
+ state.lastPartText = "";
6224
+ }
5263
6225
 
5264
6226
  // src/cli/run/runner.ts
5265
6227
  var POLL_INTERVAL_MS = 500;
5266
- var DEFAULT_TIMEOUT_MS = 30 * 60 * 1000;
6228
+ var DEFAULT_TIMEOUT_MS = 0;
5267
6229
  async function run(options) {
5268
6230
  const {
5269
6231
  message,
@@ -5271,23 +6233,27 @@ async function run(options) {
5271
6233
  directory = process.cwd(),
5272
6234
  timeout = DEFAULT_TIMEOUT_MS
5273
6235
  } = options;
5274
- console.log(import_picocolors4.default.cyan("Starting opencode server..."));
6236
+ console.log(import_picocolors5.default.cyan("Starting opencode server..."));
5275
6237
  const abortController = new AbortController;
5276
- const timeoutId = setTimeout(() => {
5277
- console.log(import_picocolors4.default.yellow(`
6238
+ let timeoutId = null;
6239
+ if (timeout > 0) {
6240
+ timeoutId = setTimeout(() => {
6241
+ console.log(import_picocolors5.default.yellow(`
5278
6242
  Timeout reached. Aborting...`));
5279
- abortController.abort();
5280
- }, timeout);
6243
+ abortController.abort();
6244
+ }, timeout);
6245
+ }
5281
6246
  try {
5282
6247
  const { client: client3, server: server2 } = await createOpencode({
5283
6248
  signal: abortController.signal
5284
6249
  });
5285
6250
  const cleanup = () => {
5286
- clearTimeout(timeoutId);
6251
+ if (timeoutId)
6252
+ clearTimeout(timeoutId);
5287
6253
  server2.close();
5288
6254
  };
5289
6255
  process.on("SIGINT", () => {
5290
- console.log(import_picocolors4.default.yellow(`
6256
+ console.log(import_picocolors5.default.yellow(`
5291
6257
  Interrupted. Shutting down...`));
5292
6258
  cleanup();
5293
6259
  process.exit(130);
@@ -5298,10 +6264,10 @@ Interrupted. Shutting down...`));
5298
6264
  });
5299
6265
  const sessionID = sessionRes.data?.id;
5300
6266
  if (!sessionID) {
5301
- console.error(import_picocolors4.default.red("Failed to create session"));
6267
+ console.error(import_picocolors5.default.red("Failed to create session"));
5302
6268
  return 1;
5303
6269
  }
5304
- console.log(import_picocolors4.default.dim(`Session: ${sessionID}`));
6270
+ console.log(import_picocolors5.default.dim(`Session: ${sessionID}`));
5305
6271
  const ctx = {
5306
6272
  client: client3,
5307
6273
  sessionID,
@@ -5311,7 +6277,7 @@ Interrupted. Shutting down...`));
5311
6277
  const events = await client3.event.subscribe();
5312
6278
  const eventState = createEventState();
5313
6279
  const eventProcessor = processEvents(ctx, events.stream, eventState);
5314
- console.log(import_picocolors4.default.dim(`
6280
+ console.log(import_picocolors5.default.dim(`
5315
6281
  Sending prompt...`));
5316
6282
  await client3.session.promptAsync({
5317
6283
  path: { id: sessionID },
@@ -5321,22 +6287,28 @@ Sending prompt...`));
5321
6287
  },
5322
6288
  query: { directory }
5323
6289
  });
5324
- console.log(import_picocolors4.default.dim(`Waiting for completion...
6290
+ console.log(import_picocolors5.default.dim(`Waiting for completion...
5325
6291
  `));
5326
6292
  while (!abortController.signal.aborted) {
5327
6293
  await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
5328
6294
  if (!eventState.mainSessionIdle) {
5329
6295
  continue;
5330
6296
  }
6297
+ if (eventState.mainSessionError) {
6298
+ console.error(import_picocolors5.default.red(`
6299
+
6300
+ Session ended with error: ${eventState.lastError}`));
6301
+ console.error(import_picocolors5.default.yellow("Check if todos were completed before the error."));
6302
+ cleanup();
6303
+ process.exit(1);
6304
+ }
5331
6305
  const shouldExit = await checkCompletionConditions(ctx);
5332
6306
  if (shouldExit) {
5333
- console.log(import_picocolors4.default.green(`
6307
+ console.log(import_picocolors5.default.green(`
5334
6308
 
5335
6309
  All tasks completed.`));
5336
- abortController.abort();
5337
- await eventProcessor.catch(() => {});
5338
6310
  cleanup();
5339
- return 0;
6311
+ process.exit(0);
5340
6312
  }
5341
6313
  }
5342
6314
  await eventProcessor.catch(() => {});
@@ -5347,14 +6319,316 @@ All tasks completed.`));
5347
6319
  throw err;
5348
6320
  }
5349
6321
  } catch (err) {
5350
- clearTimeout(timeoutId);
6322
+ if (timeoutId)
6323
+ clearTimeout(timeoutId);
5351
6324
  if (err instanceof Error && err.name === "AbortError") {
5352
6325
  return 130;
5353
6326
  }
5354
- console.error(import_picocolors4.default.red(`Error: ${err}`));
6327
+ console.error(import_picocolors5.default.red(`Error: ${err}`));
5355
6328
  return 1;
5356
6329
  }
5357
6330
  }
6331
+ // src/hooks/auto-update-checker/checker.ts
6332
+ import * as fs2 from "fs";
6333
+ import * as path3 from "path";
6334
+ import { fileURLToPath } from "url";
6335
+
6336
+ // src/hooks/auto-update-checker/constants.ts
6337
+ import * as path2 from "path";
6338
+ import * as os2 from "os";
6339
+ var PACKAGE_NAME = "oh-my-opencode";
6340
+ var NPM_REGISTRY_URL = `https://registry.npmjs.org/-/package/${PACKAGE_NAME}/dist-tags`;
6341
+ var NPM_FETCH_TIMEOUT = 5000;
6342
+ function getCacheDir() {
6343
+ if (process.platform === "win32") {
6344
+ return path2.join(process.env.LOCALAPPDATA ?? os2.homedir(), "opencode");
6345
+ }
6346
+ return path2.join(os2.homedir(), ".cache", "opencode");
6347
+ }
6348
+ var CACHE_DIR = getCacheDir();
6349
+ var VERSION_FILE = path2.join(CACHE_DIR, "version");
6350
+ var INSTALLED_PACKAGE_JSON = path2.join(CACHE_DIR, "node_modules", PACKAGE_NAME, "package.json");
6351
+ function getUserConfigDir() {
6352
+ if (process.platform === "win32") {
6353
+ return process.env.APPDATA ?? path2.join(os2.homedir(), "AppData", "Roaming");
6354
+ }
6355
+ return process.env.XDG_CONFIG_HOME ?? path2.join(os2.homedir(), ".config");
6356
+ }
6357
+ var USER_CONFIG_DIR = getUserConfigDir();
6358
+ var USER_OPENCODE_CONFIG = path2.join(USER_CONFIG_DIR, "opencode", "opencode.json");
6359
+ var USER_OPENCODE_CONFIG_JSONC = path2.join(USER_CONFIG_DIR, "opencode", "opencode.jsonc");
6360
+
6361
+ // src/hooks/auto-update-checker/checker.ts
6362
+ function isLocalDevMode(directory) {
6363
+ return getLocalDevPath(directory) !== null;
6364
+ }
6365
+ function stripJsonComments(json) {
6366
+ return json.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (m2, g2) => g2 ? "" : m2).replace(/,(\s*[}\]])/g, "$1");
6367
+ }
6368
+ function getConfigPaths(directory) {
6369
+ return [
6370
+ path3.join(directory, ".opencode", "opencode.json"),
6371
+ path3.join(directory, ".opencode", "opencode.jsonc"),
6372
+ USER_OPENCODE_CONFIG,
6373
+ USER_OPENCODE_CONFIG_JSONC
6374
+ ];
6375
+ }
6376
+ function getLocalDevPath(directory) {
6377
+ for (const configPath of getConfigPaths(directory)) {
6378
+ try {
6379
+ if (!fs2.existsSync(configPath))
6380
+ continue;
6381
+ const content = fs2.readFileSync(configPath, "utf-8");
6382
+ const config = JSON.parse(stripJsonComments(content));
6383
+ const plugins = config.plugin ?? [];
6384
+ for (const entry of plugins) {
6385
+ if (entry.startsWith("file://") && entry.includes(PACKAGE_NAME)) {
6386
+ try {
6387
+ return fileURLToPath(entry);
6388
+ } catch {
6389
+ return entry.replace("file://", "");
6390
+ }
6391
+ }
6392
+ }
6393
+ } catch {
6394
+ continue;
6395
+ }
6396
+ }
6397
+ return null;
6398
+ }
6399
+ function findPackageJsonUp(startPath) {
6400
+ try {
6401
+ const stat = fs2.statSync(startPath);
6402
+ let dir = stat.isDirectory() ? startPath : path3.dirname(startPath);
6403
+ for (let i = 0;i < 10; i++) {
6404
+ const pkgPath = path3.join(dir, "package.json");
6405
+ if (fs2.existsSync(pkgPath)) {
6406
+ try {
6407
+ const content = fs2.readFileSync(pkgPath, "utf-8");
6408
+ const pkg = JSON.parse(content);
6409
+ if (pkg.name === PACKAGE_NAME)
6410
+ return pkgPath;
6411
+ } catch {}
6412
+ }
6413
+ const parent = path3.dirname(dir);
6414
+ if (parent === dir)
6415
+ break;
6416
+ dir = parent;
6417
+ }
6418
+ } catch {}
6419
+ return null;
6420
+ }
6421
+ function findPluginEntry(directory) {
6422
+ for (const configPath of getConfigPaths(directory)) {
6423
+ try {
6424
+ if (!fs2.existsSync(configPath))
6425
+ continue;
6426
+ const content = fs2.readFileSync(configPath, "utf-8");
6427
+ const config = JSON.parse(stripJsonComments(content));
6428
+ const plugins = config.plugin ?? [];
6429
+ for (const entry of plugins) {
6430
+ if (entry === PACKAGE_NAME) {
6431
+ return { entry, isPinned: false, pinnedVersion: null, configPath };
6432
+ }
6433
+ if (entry.startsWith(`${PACKAGE_NAME}@`)) {
6434
+ const pinnedVersion = entry.slice(PACKAGE_NAME.length + 1);
6435
+ const isPinned = pinnedVersion !== "latest";
6436
+ return { entry, isPinned, pinnedVersion: isPinned ? pinnedVersion : null, configPath };
6437
+ }
6438
+ }
6439
+ } catch {
6440
+ continue;
6441
+ }
6442
+ }
6443
+ return null;
6444
+ }
6445
+ function getCachedVersion() {
6446
+ try {
6447
+ if (fs2.existsSync(INSTALLED_PACKAGE_JSON)) {
6448
+ const content = fs2.readFileSync(INSTALLED_PACKAGE_JSON, "utf-8");
6449
+ const pkg = JSON.parse(content);
6450
+ if (pkg.version)
6451
+ return pkg.version;
6452
+ }
6453
+ } catch {}
6454
+ try {
6455
+ const currentDir = path3.dirname(fileURLToPath(import.meta.url));
6456
+ const pkgPath = findPackageJsonUp(currentDir);
6457
+ if (pkgPath) {
6458
+ const content = fs2.readFileSync(pkgPath, "utf-8");
6459
+ const pkg = JSON.parse(content);
6460
+ if (pkg.version)
6461
+ return pkg.version;
6462
+ }
6463
+ } catch (err) {
6464
+ log("[auto-update-checker] Failed to resolve version from current directory:", err);
6465
+ }
6466
+ return null;
6467
+ }
6468
+ async function getLatestVersion() {
6469
+ const controller = new AbortController;
6470
+ const timeoutId = setTimeout(() => controller.abort(), NPM_FETCH_TIMEOUT);
6471
+ try {
6472
+ const response = await fetch(NPM_REGISTRY_URL, {
6473
+ signal: controller.signal,
6474
+ headers: { Accept: "application/json" }
6475
+ });
6476
+ if (!response.ok)
6477
+ return null;
6478
+ const data = await response.json();
6479
+ return data.latest ?? null;
6480
+ } catch {
6481
+ return null;
6482
+ } finally {
6483
+ clearTimeout(timeoutId);
6484
+ }
6485
+ }
6486
+
6487
+ // src/cli/get-local-version/formatter.ts
6488
+ var import_picocolors6 = __toESM(require_picocolors(), 1);
6489
+ var SYMBOLS2 = {
6490
+ check: import_picocolors6.default.green("\u2713"),
6491
+ cross: import_picocolors6.default.red("\u2717"),
6492
+ arrow: import_picocolors6.default.cyan("\u2192"),
6493
+ info: import_picocolors6.default.blue("\u2139"),
6494
+ warn: import_picocolors6.default.yellow("\u26A0"),
6495
+ pin: import_picocolors6.default.magenta("\uD83D\uDCCC"),
6496
+ dev: import_picocolors6.default.cyan("\uD83D\uDD27")
6497
+ };
6498
+ function formatVersionOutput(info) {
6499
+ const lines = [];
6500
+ lines.push("");
6501
+ lines.push(import_picocolors6.default.bold(import_picocolors6.default.white("oh-my-opencode Version Information")));
6502
+ lines.push(import_picocolors6.default.dim("\u2500".repeat(50)));
6503
+ lines.push("");
6504
+ if (info.currentVersion) {
6505
+ lines.push(` Current Version: ${import_picocolors6.default.cyan(info.currentVersion)}`);
6506
+ } else {
6507
+ lines.push(` Current Version: ${import_picocolors6.default.dim("unknown")}`);
6508
+ }
6509
+ if (!info.isLocalDev && info.latestVersion) {
6510
+ lines.push(` Latest Version: ${import_picocolors6.default.cyan(info.latestVersion)}`);
6511
+ }
6512
+ lines.push("");
6513
+ switch (info.status) {
6514
+ case "up-to-date":
6515
+ lines.push(` ${SYMBOLS2.check} ${import_picocolors6.default.green("You're up to date!")}`);
6516
+ break;
6517
+ case "outdated":
6518
+ lines.push(` ${SYMBOLS2.warn} ${import_picocolors6.default.yellow("Update available")}`);
6519
+ lines.push(` ${import_picocolors6.default.dim("Run:")} ${import_picocolors6.default.cyan("cd ~/.config/opencode && bun update oh-my-opencode")}`);
6520
+ break;
6521
+ case "local-dev":
6522
+ lines.push(` ${SYMBOLS2.dev} ${import_picocolors6.default.cyan("Running in local development mode")}`);
6523
+ lines.push(` ${import_picocolors6.default.dim("Using file:// protocol from config")}`);
6524
+ break;
6525
+ case "pinned":
6526
+ lines.push(` ${SYMBOLS2.pin} ${import_picocolors6.default.magenta(`Version pinned to ${info.pinnedVersion}`)}`);
6527
+ lines.push(` ${import_picocolors6.default.dim("Update check skipped for pinned versions")}`);
6528
+ break;
6529
+ case "error":
6530
+ lines.push(` ${SYMBOLS2.cross} ${import_picocolors6.default.red("Unable to check for updates")}`);
6531
+ lines.push(` ${import_picocolors6.default.dim("Network error or npm registry unavailable")}`);
6532
+ break;
6533
+ case "unknown":
6534
+ lines.push(` ${SYMBOLS2.info} ${import_picocolors6.default.yellow("Version information unavailable")}`);
6535
+ break;
6536
+ }
6537
+ lines.push("");
6538
+ return lines.join(`
6539
+ `);
6540
+ }
6541
+ function formatJsonOutput(info) {
6542
+ return JSON.stringify(info, null, 2);
6543
+ }
6544
+
6545
+ // src/cli/get-local-version/index.ts
6546
+ async function getLocalVersion(options = {}) {
6547
+ const directory = options.directory ?? process.cwd();
6548
+ try {
6549
+ if (isLocalDevMode(directory)) {
6550
+ const currentVersion2 = getCachedVersion();
6551
+ const info2 = {
6552
+ currentVersion: currentVersion2,
6553
+ latestVersion: null,
6554
+ isUpToDate: false,
6555
+ isLocalDev: true,
6556
+ isPinned: false,
6557
+ pinnedVersion: null,
6558
+ status: "local-dev"
6559
+ };
6560
+ console.log(options.json ? formatJsonOutput(info2) : formatVersionOutput(info2));
6561
+ return 0;
6562
+ }
6563
+ const pluginInfo = findPluginEntry(directory);
6564
+ if (pluginInfo?.isPinned) {
6565
+ const info2 = {
6566
+ currentVersion: pluginInfo.pinnedVersion,
6567
+ latestVersion: null,
6568
+ isUpToDate: false,
6569
+ isLocalDev: false,
6570
+ isPinned: true,
6571
+ pinnedVersion: pluginInfo.pinnedVersion,
6572
+ status: "pinned"
6573
+ };
6574
+ console.log(options.json ? formatJsonOutput(info2) : formatVersionOutput(info2));
6575
+ return 0;
6576
+ }
6577
+ const currentVersion = getCachedVersion();
6578
+ if (!currentVersion) {
6579
+ const info2 = {
6580
+ currentVersion: null,
6581
+ latestVersion: null,
6582
+ isUpToDate: false,
6583
+ isLocalDev: false,
6584
+ isPinned: false,
6585
+ pinnedVersion: null,
6586
+ status: "unknown"
6587
+ };
6588
+ console.log(options.json ? formatJsonOutput(info2) : formatVersionOutput(info2));
6589
+ return 1;
6590
+ }
6591
+ const latestVersion = await getLatestVersion();
6592
+ if (!latestVersion) {
6593
+ const info2 = {
6594
+ currentVersion,
6595
+ latestVersion: null,
6596
+ isUpToDate: false,
6597
+ isLocalDev: false,
6598
+ isPinned: false,
6599
+ pinnedVersion: null,
6600
+ status: "error"
6601
+ };
6602
+ console.log(options.json ? formatJsonOutput(info2) : formatVersionOutput(info2));
6603
+ return 0;
6604
+ }
6605
+ const isUpToDate = currentVersion === latestVersion;
6606
+ const info = {
6607
+ currentVersion,
6608
+ latestVersion,
6609
+ isUpToDate,
6610
+ isLocalDev: false,
6611
+ isPinned: false,
6612
+ pinnedVersion: null,
6613
+ status: isUpToDate ? "up-to-date" : "outdated"
6614
+ };
6615
+ console.log(options.json ? formatJsonOutput(info) : formatVersionOutput(info));
6616
+ return 0;
6617
+ } catch (error) {
6618
+ const info = {
6619
+ currentVersion: null,
6620
+ latestVersion: null,
6621
+ isUpToDate: false,
6622
+ isLocalDev: false,
6623
+ isPinned: false,
6624
+ pinnedVersion: null,
6625
+ status: "error"
6626
+ };
6627
+ console.log(options.json ? formatJsonOutput(info) : formatVersionOutput(info));
6628
+ return 1;
6629
+ }
6630
+ }
6631
+
5358
6632
  // src/cli/index.ts
5359
6633
  var packageJson = await Promise.resolve().then(() => __toESM(require_package(), 1));
5360
6634
  var VERSION = packageJson.version;
@@ -5400,6 +6674,25 @@ Unlike 'opencode run', this command waits until:
5400
6674
  const exitCode = await run(runOptions);
5401
6675
  process.exit(exitCode);
5402
6676
  });
6677
+ program2.command("get-local-version").description("Show current installed version and check for updates").option("-d, --directory <path>", "Working directory to check config from").option("--json", "Output in JSON format for scripting").addHelpText("after", `
6678
+ Examples:
6679
+ $ bunx oh-my-opencode get-local-version
6680
+ $ bunx oh-my-opencode get-local-version --json
6681
+ $ bunx oh-my-opencode get-local-version --directory /path/to/project
6682
+
6683
+ This command shows:
6684
+ - Current installed version
6685
+ - Latest available version on npm
6686
+ - Whether you're up to date
6687
+ - Special modes (local dev, pinned version)
6688
+ `).action(async (options) => {
6689
+ const versionOptions = {
6690
+ directory: options.directory,
6691
+ json: options.json ?? false
6692
+ };
6693
+ const exitCode = await getLocalVersion(versionOptions);
6694
+ process.exit(exitCode);
6695
+ });
5403
6696
  program2.command("version").description("Show version information").action(() => {
5404
6697
  console.log(`oh-my-opencode v${VERSION}`);
5405
6698
  });