opencode-orchestrator 1.2.62 → 1.2.67

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.
@@ -1,9 +1,197 @@
1
1
  #!/usr/bin/env node
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
9
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
10
+ }) : x)(function(x) {
11
+ if (typeof require !== "undefined") return require.apply(this, arguments);
12
+ throw Error('Dynamic require of "' + x + '" is not supported');
13
+ });
14
+ var __commonJS = (cb, mod) => function __require2() {
15
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
16
+ };
17
+ var __copyProps = (to, from, except, desc) => {
18
+ if (from && typeof from === "object" || typeof from === "function") {
19
+ for (let key of __getOwnPropNames(from))
20
+ if (!__hasOwnProp.call(to, key) && key !== except)
21
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
22
+ }
23
+ return to;
24
+ };
25
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
26
+ // If the importer is in node compatibility mode or this is not an ESM
27
+ // file that has been converted to a CommonJS file using a Babel-
28
+ // compatible transform (i.e. "__esModule" has not been set), then set
29
+ // "default" to the CommonJS "module.exports" for node compatibility.
30
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
31
+ mod
32
+ ));
33
+
34
+ // node_modules/jsonc-parser/lib/umd/main.js
35
+ var require_main = __commonJS({
36
+ "node_modules/jsonc-parser/lib/umd/main.js"(exports, module) {
37
+ (function(factory) {
38
+ if (typeof module === "object" && typeof module.exports === "object") {
39
+ var v = factory(__require, exports);
40
+ if (v !== void 0) module.exports = v;
41
+ } else if (typeof define === "function" && define.amd) {
42
+ define(["require", "exports", "./impl/format", "./impl/edit", "./impl/scanner", "./impl/parser"], factory);
43
+ }
44
+ })(function(require2, exports2) {
45
+ "use strict";
46
+ Object.defineProperty(exports2, "__esModule", { value: true });
47
+ exports2.applyEdits = exports2.modify = exports2.format = exports2.printParseErrorCode = exports2.ParseErrorCode = exports2.stripComments = exports2.visit = exports2.getNodeValue = exports2.getNodePath = exports2.findNodeAtOffset = exports2.findNodeAtLocation = exports2.parseTree = exports2.parse = exports2.getLocation = exports2.SyntaxKind = exports2.ScanError = exports2.createScanner = void 0;
48
+ const formatter = require2("./impl/format");
49
+ const edit = require2("./impl/edit");
50
+ const scanner = require2("./impl/scanner");
51
+ const parser = require2("./impl/parser");
52
+ exports2.createScanner = scanner.createScanner;
53
+ var ScanError;
54
+ (function(ScanError2) {
55
+ ScanError2[ScanError2["None"] = 0] = "None";
56
+ ScanError2[ScanError2["UnexpectedEndOfComment"] = 1] = "UnexpectedEndOfComment";
57
+ ScanError2[ScanError2["UnexpectedEndOfString"] = 2] = "UnexpectedEndOfString";
58
+ ScanError2[ScanError2["UnexpectedEndOfNumber"] = 3] = "UnexpectedEndOfNumber";
59
+ ScanError2[ScanError2["InvalidUnicode"] = 4] = "InvalidUnicode";
60
+ ScanError2[ScanError2["InvalidEscapeCharacter"] = 5] = "InvalidEscapeCharacter";
61
+ ScanError2[ScanError2["InvalidCharacter"] = 6] = "InvalidCharacter";
62
+ })(ScanError || (exports2.ScanError = ScanError = {}));
63
+ var SyntaxKind;
64
+ (function(SyntaxKind2) {
65
+ SyntaxKind2[SyntaxKind2["OpenBraceToken"] = 1] = "OpenBraceToken";
66
+ SyntaxKind2[SyntaxKind2["CloseBraceToken"] = 2] = "CloseBraceToken";
67
+ SyntaxKind2[SyntaxKind2["OpenBracketToken"] = 3] = "OpenBracketToken";
68
+ SyntaxKind2[SyntaxKind2["CloseBracketToken"] = 4] = "CloseBracketToken";
69
+ SyntaxKind2[SyntaxKind2["CommaToken"] = 5] = "CommaToken";
70
+ SyntaxKind2[SyntaxKind2["ColonToken"] = 6] = "ColonToken";
71
+ SyntaxKind2[SyntaxKind2["NullKeyword"] = 7] = "NullKeyword";
72
+ SyntaxKind2[SyntaxKind2["TrueKeyword"] = 8] = "TrueKeyword";
73
+ SyntaxKind2[SyntaxKind2["FalseKeyword"] = 9] = "FalseKeyword";
74
+ SyntaxKind2[SyntaxKind2["StringLiteral"] = 10] = "StringLiteral";
75
+ SyntaxKind2[SyntaxKind2["NumericLiteral"] = 11] = "NumericLiteral";
76
+ SyntaxKind2[SyntaxKind2["LineCommentTrivia"] = 12] = "LineCommentTrivia";
77
+ SyntaxKind2[SyntaxKind2["BlockCommentTrivia"] = 13] = "BlockCommentTrivia";
78
+ SyntaxKind2[SyntaxKind2["LineBreakTrivia"] = 14] = "LineBreakTrivia";
79
+ SyntaxKind2[SyntaxKind2["Trivia"] = 15] = "Trivia";
80
+ SyntaxKind2[SyntaxKind2["Unknown"] = 16] = "Unknown";
81
+ SyntaxKind2[SyntaxKind2["EOF"] = 17] = "EOF";
82
+ })(SyntaxKind || (exports2.SyntaxKind = SyntaxKind = {}));
83
+ exports2.getLocation = parser.getLocation;
84
+ exports2.parse = parser.parse;
85
+ exports2.parseTree = parser.parseTree;
86
+ exports2.findNodeAtLocation = parser.findNodeAtLocation;
87
+ exports2.findNodeAtOffset = parser.findNodeAtOffset;
88
+ exports2.getNodePath = parser.getNodePath;
89
+ exports2.getNodeValue = parser.getNodeValue;
90
+ exports2.visit = parser.visit;
91
+ exports2.stripComments = parser.stripComments;
92
+ var ParseErrorCode;
93
+ (function(ParseErrorCode2) {
94
+ ParseErrorCode2[ParseErrorCode2["InvalidSymbol"] = 1] = "InvalidSymbol";
95
+ ParseErrorCode2[ParseErrorCode2["InvalidNumberFormat"] = 2] = "InvalidNumberFormat";
96
+ ParseErrorCode2[ParseErrorCode2["PropertyNameExpected"] = 3] = "PropertyNameExpected";
97
+ ParseErrorCode2[ParseErrorCode2["ValueExpected"] = 4] = "ValueExpected";
98
+ ParseErrorCode2[ParseErrorCode2["ColonExpected"] = 5] = "ColonExpected";
99
+ ParseErrorCode2[ParseErrorCode2["CommaExpected"] = 6] = "CommaExpected";
100
+ ParseErrorCode2[ParseErrorCode2["CloseBraceExpected"] = 7] = "CloseBraceExpected";
101
+ ParseErrorCode2[ParseErrorCode2["CloseBracketExpected"] = 8] = "CloseBracketExpected";
102
+ ParseErrorCode2[ParseErrorCode2["EndOfFileExpected"] = 9] = "EndOfFileExpected";
103
+ ParseErrorCode2[ParseErrorCode2["InvalidCommentToken"] = 10] = "InvalidCommentToken";
104
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfComment"] = 11] = "UnexpectedEndOfComment";
105
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfString"] = 12] = "UnexpectedEndOfString";
106
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfNumber"] = 13] = "UnexpectedEndOfNumber";
107
+ ParseErrorCode2[ParseErrorCode2["InvalidUnicode"] = 14] = "InvalidUnicode";
108
+ ParseErrorCode2[ParseErrorCode2["InvalidEscapeCharacter"] = 15] = "InvalidEscapeCharacter";
109
+ ParseErrorCode2[ParseErrorCode2["InvalidCharacter"] = 16] = "InvalidCharacter";
110
+ })(ParseErrorCode || (exports2.ParseErrorCode = ParseErrorCode = {}));
111
+ function printParseErrorCode2(code) {
112
+ switch (code) {
113
+ case 1:
114
+ return "InvalidSymbol";
115
+ case 2:
116
+ return "InvalidNumberFormat";
117
+ case 3:
118
+ return "PropertyNameExpected";
119
+ case 4:
120
+ return "ValueExpected";
121
+ case 5:
122
+ return "ColonExpected";
123
+ case 6:
124
+ return "CommaExpected";
125
+ case 7:
126
+ return "CloseBraceExpected";
127
+ case 8:
128
+ return "CloseBracketExpected";
129
+ case 9:
130
+ return "EndOfFileExpected";
131
+ case 10:
132
+ return "InvalidCommentToken";
133
+ case 11:
134
+ return "UnexpectedEndOfComment";
135
+ case 12:
136
+ return "UnexpectedEndOfString";
137
+ case 13:
138
+ return "UnexpectedEndOfNumber";
139
+ case 14:
140
+ return "InvalidUnicode";
141
+ case 15:
142
+ return "InvalidEscapeCharacter";
143
+ case 16:
144
+ return "InvalidCharacter";
145
+ }
146
+ return "<unknown ParseErrorCode>";
147
+ }
148
+ exports2.printParseErrorCode = printParseErrorCode2;
149
+ function format(documentText, range, options) {
150
+ return formatter.format(documentText, range, options);
151
+ }
152
+ exports2.format = format;
153
+ function modify2(text, path, value, options) {
154
+ return edit.setProperty(text, path, value, options);
155
+ }
156
+ exports2.modify = modify2;
157
+ function applyEdits2(text, edits) {
158
+ let sortedEdits = edits.slice(0).sort((a, b) => {
159
+ const diff = a.offset - b.offset;
160
+ if (diff === 0) {
161
+ return a.length - b.length;
162
+ }
163
+ return diff;
164
+ });
165
+ let lastModifiedOffset = text.length;
166
+ for (let i = sortedEdits.length - 1; i >= 0; i--) {
167
+ let e = sortedEdits[i];
168
+ if (e.offset + e.length <= lastModifiedOffset) {
169
+ text = edit.applyEdit(text, e);
170
+ } else {
171
+ throw new Error("Overlapping edit");
172
+ }
173
+ lastModifiedOffset = e.offset;
174
+ }
175
+ return text;
176
+ }
177
+ exports2.applyEdits = applyEdits2;
178
+ });
179
+ }
180
+ });
2
181
 
3
182
  // scripts/postinstall.ts
183
+ var import_jsonc_parser = __toESM(require_main(), 1);
4
184
  import { existsSync, mkdirSync, readFileSync, writeFileSync, appendFileSync, copyFileSync, renameSync, unlinkSync, readdirSync } from "fs";
5
185
  import { homedir, tmpdir } from "os";
6
- import { join } from "path";
186
+ import { dirname, join, basename } from "path";
187
+ var isCI = process.env.CI === "true" || process.env.CONTINUOUS_INTEGRATION === "true";
188
+ var TIMEOUT_MS = 3e4;
189
+ var timeoutId = setTimeout(() => {
190
+ console.log("\u26A0\uFE0F postinstall timeout - exiting gracefully");
191
+ process.exit(0);
192
+ }, TIMEOUT_MS);
193
+ process.on("SIGINT", () => process.exit(0));
194
+ process.on("SIGTERM", () => process.exit(0));
7
195
  var LOG_FILE = join(tmpdir(), "opencode-orchestrator.log");
8
196
  function log(message, data) {
9
197
  try {
@@ -40,6 +228,41 @@ function formatError(err, context) {
40
228
  return `Failed to ${context}: ${String(err)}`;
41
229
  }
42
230
  var PLUGIN_NAME = "opencode-orchestrator";
231
+ function isOurPluginEntry(p) {
232
+ return p === PLUGIN_NAME || p.startsWith(`${PLUGIN_NAME}@`);
233
+ }
234
+ function getConfigFileCandidates(configDir) {
235
+ return [join(configDir, "opencode.jsonc"), join(configDir, "opencode.json")];
236
+ }
237
+ function resolveConfigFile(configDir) {
238
+ for (const candidate of getConfigFileCandidates(configDir)) {
239
+ if (existsSync(candidate)) {
240
+ return candidate;
241
+ }
242
+ }
243
+ return getConfigFileCandidates(configDir)[0];
244
+ }
245
+ function parseConfigContent(rawContent) {
246
+ const errors = [];
247
+ const config = (0, import_jsonc_parser.parse)(rawContent, errors, {
248
+ allowTrailingComma: true,
249
+ disallowComments: false
250
+ });
251
+ if (errors.length > 0) {
252
+ const [firstError] = errors;
253
+ const line = rawContent.slice(0, firstError.offset).split("\n").length;
254
+ const column = firstError.offset - rawContent.lastIndexOf("\n", firstError.offset - 1);
255
+ return {
256
+ parseError: `${(0, import_jsonc_parser.printParseErrorCode)(firstError.error)} at line ${line}, column ${column}`
257
+ };
258
+ }
259
+ if (typeof config !== "object" || config === null || Array.isArray(config)) {
260
+ return {
261
+ parseError: "Root config must be a JSON object"
262
+ };
263
+ }
264
+ return { config };
265
+ }
43
266
  function detectWSLWindowsConfigDir() {
44
267
  try {
45
268
  const isWSL = process.env.WSL_DISTRO_NAME || process.env.WSLENV;
@@ -99,7 +322,21 @@ function getConfigPaths() {
99
322
  paths.push(wslWindowsConfig);
100
323
  }
101
324
  }
102
- return paths;
325
+ return [...new Set(paths)];
326
+ }
327
+ function readExistingConfig(configDir) {
328
+ for (const configFile of getConfigFileCandidates(configDir)) {
329
+ if (!existsSync(configFile)) continue;
330
+ const rawContent = readFileSync(configFile, "utf-8").trim();
331
+ if (!rawContent) {
332
+ return { file: configFile, config: {} };
333
+ }
334
+ const parsed = parseConfigContent(rawContent);
335
+ if (parsed.config) {
336
+ return { file: configFile, config: parsed.config };
337
+ }
338
+ }
339
+ return null;
103
340
  }
104
341
  function validateConfig(config) {
105
342
  try {
@@ -136,10 +373,19 @@ function createBackup(configFile) {
136
373
  return null;
137
374
  }
138
375
  }
139
- function atomicWriteJSON(filePath, data) {
376
+ function atomicWriteJSON(filePath, data, originalContent) {
140
377
  const tempFile = `${filePath}.tmp.${Date.now()}`;
141
378
  try {
142
- writeFileSync(tempFile, JSON.stringify(data, null, 2) + "\n", { mode: 420 });
379
+ let output = JSON.stringify(data, null, 2) + "\n";
380
+ if (filePath.endsWith(".jsonc") && originalContent !== void 0) {
381
+ const source = originalContent.trim() ? originalContent : "{}";
382
+ const edits = (0, import_jsonc_parser.modify)(source, ["plugin"], data.plugin, {
383
+ formattingOptions: { tabSize: 2, insertSpaces: true }
384
+ });
385
+ output = (0, import_jsonc_parser.applyEdits)(source, edits);
386
+ if (!output.endsWith("\n")) output += "\n";
387
+ }
388
+ writeFileSync(tempFile, output, { mode: 420 });
143
389
  renameSync(tempFile, filePath);
144
390
  log("Atomic write successful", { filePath });
145
391
  } catch (error) {
@@ -153,8 +399,9 @@ function atomicWriteJSON(filePath, data) {
153
399
  }
154
400
  }
155
401
  function registerInConfig(configDir) {
156
- const configFile = join(configDir, "opencode.json");
402
+ const configFile = resolveConfigFile(configDir);
157
403
  let backupFile = null;
404
+ let originalContent;
158
405
  try {
159
406
  if (!existsSync(configDir)) {
160
407
  mkdirSync(configDir, { recursive: true, mode: 493 });
@@ -164,24 +411,22 @@ function registerInConfig(configDir) {
164
411
  let fileExisted = false;
165
412
  if (existsSync(configFile)) {
166
413
  fileExisted = true;
167
- const rawContent = readFileSync(configFile, "utf-8").trim();
168
- if (rawContent) {
169
- let parseError;
170
- try {
171
- config = JSON.parse(rawContent);
172
- } catch (err) {
173
- parseError = err;
174
- }
175
- if (parseError) {
414
+ const rawContent = readFileSync(configFile, "utf-8");
415
+ originalContent = rawContent;
416
+ const trimmedContent = rawContent.trim();
417
+ if (trimmedContent) {
418
+ const parsed = parseConfigContent(trimmedContent);
419
+ if (parsed.parseError) {
176
420
  backupFile = createBackup(configFile);
177
- log("Corrupted config JSON, skipping this path to avoid data loss", { configFile });
178
- console.log(`\u26A0\uFE0F opencode.json at ${configFile} has invalid JSON and was skipped.`);
421
+ log("Corrupted config JSON, skipping this path to avoid data loss", { configFile, parseError: parsed.parseError });
422
+ console.log(`\u26A0\uFE0F opencode config at ${configFile} has invalid JSON/JSONC and was skipped.`);
179
423
  if (backupFile) {
180
424
  console.log(` Backup saved: ${backupFile}`);
181
425
  }
182
426
  console.log(` Please fix the file manually, then add "${PLUGIN_NAME}" to the "plugin" array.`);
183
427
  return { success: false, backupFile, skipped: true };
184
428
  }
429
+ config = parsed.config ?? {};
185
430
  if (!validateConfig(config)) {
186
431
  log("Unexpected config structure, skipping to avoid corruption", { config, configFile });
187
432
  console.log(`\u26A0\uFE0F Unexpected config structure in ${configFile}. Skipping to avoid corruption.`);
@@ -198,7 +443,7 @@ function registerInConfig(configDir) {
198
443
  }
199
444
  const hasPlugin = config.plugin.some((p) => {
200
445
  if (typeof p !== "string") return false;
201
- return p === PLUGIN_NAME || p.includes(PLUGIN_NAME);
446
+ return isOurPluginEntry(p);
202
447
  });
203
448
  if (hasPlugin) {
204
449
  log("Plugin already registered", { configFile });
@@ -209,11 +454,15 @@ function registerInConfig(configDir) {
209
454
  }
210
455
  config.plugin.push(PLUGIN_NAME);
211
456
  log("Adding plugin to config", { plugin: PLUGIN_NAME, configFile });
212
- atomicWriteJSON(configFile, config);
457
+ atomicWriteJSON(configFile, config, originalContent);
213
458
  try {
214
459
  const verifyContent = readFileSync(configFile, "utf-8");
215
- const verifyConfig = JSON.parse(verifyContent);
216
- if (!verifyConfig.plugin?.includes(PLUGIN_NAME)) {
460
+ const verifyParsed = parseConfigContent(verifyContent);
461
+ if (verifyParsed.parseError || !verifyParsed.config) {
462
+ throw new Error(`Verification parse failed: ${verifyParsed.parseError ?? "unknown parse error"}`);
463
+ }
464
+ const verifyConfig = verifyParsed.config;
465
+ if (!verifyConfig.plugin?.some((p) => isOurPluginEntry(p))) {
217
466
  throw new Error("Verification failed: plugin not found after write");
218
467
  }
219
468
  } catch (verifyError) {
@@ -242,9 +491,10 @@ function registerInConfig(configDir) {
242
491
  }
243
492
  function cleanupOldBackups(configFile) {
244
493
  try {
245
- const configDir = join(configFile, "..");
494
+ const configDir = dirname(configFile);
495
+ const configBase = basename(configFile);
246
496
  const files = readdirSync(configDir);
247
- const backupFiles = files.filter((f) => f.startsWith("opencode.json.backup.")).sort().reverse();
497
+ const backupFiles = files.filter((f) => f.startsWith(`${configBase}.backup.`)).sort().reverse();
248
498
  for (let i = 5; i < backupFiles.length; i++) {
249
499
  const backupPath = join(configDir, backupFiles[i]);
250
500
  try {
@@ -257,32 +507,37 @@ function cleanupOldBackups(configFile) {
257
507
  }
258
508
  }
259
509
  try {
510
+ if (isCI) log("Running in CI mode");
260
511
  console.log("\u{1F3AF} OpenCode Orchestrator - Installing...");
261
512
  log("Installation started", { platform: process.platform, node: process.version });
513
+ if (isCI) {
514
+ console.log("\u2139\uFE0F CI environment detected. Skipping automatic plugin registration.");
515
+ log("Skipping automatic plugin registration in CI");
516
+ clearTimeout(timeoutId);
517
+ process.exit(0);
518
+ }
262
519
  const configPaths = getConfigPaths();
263
520
  log("Config paths to check", configPaths);
264
521
  let registered = false;
265
522
  let alreadyRegistered = false;
266
523
  let skippedCorrupt = false;
267
524
  let backupCreated = null;
525
+ let targetConfigDir = configPaths[0];
268
526
  for (const configDir of configPaths) {
269
- const configFile = join(configDir, "opencode.json");
270
- if (existsSync(configFile)) {
271
- try {
272
- const content = readFileSync(configFile, "utf-8").trim();
273
- if (content) {
274
- const config = JSON.parse(content);
275
- if (config.plugin?.some((p) => typeof p === "string" && (p === PLUGIN_NAME || p.includes(PLUGIN_NAME)))) {
276
- alreadyRegistered = true;
277
- log("Plugin already registered in this location", { configFile });
278
- continue;
279
- }
280
- }
281
- } catch (error) {
282
- log("Error checking existing config", { error: String(error), configFile });
283
- }
527
+ const existing = readExistingConfig(configDir);
528
+ if (!existing) {
529
+ continue;
284
530
  }
285
- const result = registerInConfig(configDir);
531
+ targetConfigDir = configDir;
532
+ if (existing.config.plugin?.some((p) => typeof p === "string" && isOurPluginEntry(p))) {
533
+ alreadyRegistered = true;
534
+ log("Plugin already registered in this location", { configFile: existing.file });
535
+ break;
536
+ }
537
+ }
538
+ if (!alreadyRegistered && targetConfigDir) {
539
+ const configFile = resolveConfigFile(targetConfigDir);
540
+ const result = registerInConfig(targetConfigDir);
286
541
  if (result.skipped) {
287
542
  skippedCorrupt = true;
288
543
  if (result.backupFile) backupCreated = result.backupFile;
@@ -310,6 +565,7 @@ try {
310
565
  console.log(` Check logs: ${LOG_FILE}`);
311
566
  log("Failed to register plugin in any location");
312
567
  }
568
+ clearTimeout(timeoutId);
313
569
  console.log("");
314
570
  console.log("\u{1F680} Ready! Restart OpenCode to use.");
315
571
  console.log("");
@@ -319,4 +575,6 @@ try {
319
575
  console.error("\u274C " + formatError(error, "register plugin"));
320
576
  console.log(` Check logs: ${LOG_FILE}`);
321
577
  process.exit(0);
578
+ } finally {
579
+ clearTimeout(timeoutId);
322
580
  }