opencode-orchestrator 1.2.62 → 1.2.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +196 -41
- package/dist/core/agents/consts/task-status.const.d.ts +2 -21
- package/dist/core/loop/circuit-breaker.d.ts +19 -0
- package/dist/core/loop/compaction-guard.d.ts +15 -0
- package/dist/core/loop/mission-loop-handler.d.ts +3 -12
- package/dist/core/loop/mission-loop.d.ts +0 -4
- package/dist/core/loop/progress-tracker.d.ts +39 -0
- package/dist/core/loop/session-state-store.d.ts +26 -0
- package/dist/core/notification/toast-core.d.ts +1 -1
- package/dist/core/plugins/plugin-manager.d.ts +2 -1
- package/dist/index.js +578 -113
- package/dist/scripts/postinstall.js +296 -38
- package/dist/scripts/preuninstall.js +267 -19
- package/dist/shared/index.d.ts +0 -1
- package/dist/shared/loop/constants/index.d.ts +1 -0
- package/dist/shared/loop/constants/task-status.d.ts +9 -0
- package/package.json +11 -6
- package/scripts/run-install-hook.mjs +66 -0
|
@@ -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/preuninstall.ts
|
|
183
|
+
var import_jsonc_parser = __toESM(require_main(), 1);
|
|
4
184
|
import { existsSync, 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 preuninstall 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;
|
|
@@ -97,7 +320,7 @@ function getConfigPaths() {
|
|
|
97
320
|
paths.push(wslWindowsConfig);
|
|
98
321
|
}
|
|
99
322
|
}
|
|
100
|
-
return paths;
|
|
323
|
+
return [...new Set(paths)];
|
|
101
324
|
}
|
|
102
325
|
function validateConfig(config) {
|
|
103
326
|
try {
|
|
@@ -134,10 +357,19 @@ function createBackup(configFile) {
|
|
|
134
357
|
return null;
|
|
135
358
|
}
|
|
136
359
|
}
|
|
137
|
-
function atomicWriteJSON(filePath, data) {
|
|
360
|
+
function atomicWriteJSON(filePath, data, originalContent) {
|
|
138
361
|
const tempFile = `${filePath}.tmp.${Date.now()}`;
|
|
139
362
|
try {
|
|
140
|
-
|
|
363
|
+
let output = JSON.stringify(data, null, 2) + "\n";
|
|
364
|
+
if (filePath.endsWith(".jsonc") && originalContent !== void 0) {
|
|
365
|
+
const source = originalContent.trim() ? originalContent : "{}";
|
|
366
|
+
const edits = (0, import_jsonc_parser.modify)(source, ["plugin"], data.plugin, {
|
|
367
|
+
formattingOptions: { tabSize: 2, insertSpaces: true }
|
|
368
|
+
});
|
|
369
|
+
output = (0, import_jsonc_parser.applyEdits)(source, edits);
|
|
370
|
+
if (!output.endsWith("\n")) output += "\n";
|
|
371
|
+
}
|
|
372
|
+
writeFileSync(tempFile, output, { mode: 420 });
|
|
141
373
|
renameSync(tempFile, filePath);
|
|
142
374
|
log("Atomic write successful", { filePath });
|
|
143
375
|
} catch (error) {
|
|
@@ -151,27 +383,29 @@ function atomicWriteJSON(filePath, data) {
|
|
|
151
383
|
}
|
|
152
384
|
}
|
|
153
385
|
function removeFromConfig(configDir) {
|
|
154
|
-
const configFile =
|
|
386
|
+
const configFile = resolveConfigFile(configDir);
|
|
155
387
|
let backupFile = null;
|
|
388
|
+
let originalContent;
|
|
156
389
|
try {
|
|
157
390
|
if (!existsSync(configFile)) {
|
|
158
391
|
log("Config file does not exist", { configFile });
|
|
159
392
|
return { success: false, backupFile: null };
|
|
160
393
|
}
|
|
161
394
|
backupFile = createBackup(configFile);
|
|
162
|
-
const content = readFileSync(configFile, "utf-8")
|
|
163
|
-
|
|
395
|
+
const content = readFileSync(configFile, "utf-8");
|
|
396
|
+
originalContent = content;
|
|
397
|
+
const trimmedContent = content.trim();
|
|
398
|
+
if (!trimmedContent) {
|
|
164
399
|
log("Empty config file", { configFile });
|
|
165
400
|
return { success: false, backupFile };
|
|
166
401
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
config
|
|
170
|
-
} catch (error) {
|
|
171
|
-
log("Failed to parse config, skipping", { error: String(error), configFile });
|
|
402
|
+
const parsed = parseConfigContent(trimmedContent);
|
|
403
|
+
if (parsed.parseError) {
|
|
404
|
+
log("Failed to parse config, skipping", { error: parsed.parseError, configFile });
|
|
172
405
|
console.log(`\u26A0\uFE0F Corrupted config detected. Backup saved: ${backupFile}`);
|
|
173
406
|
return { success: false, backupFile };
|
|
174
407
|
}
|
|
408
|
+
const config = parsed.config ?? {};
|
|
175
409
|
if (!validateConfig(config)) {
|
|
176
410
|
log("Invalid config structure, skipping", { config, configFile });
|
|
177
411
|
return { success: false, backupFile };
|
|
@@ -184,7 +418,7 @@ function removeFromConfig(configDir) {
|
|
|
184
418
|
const originalPlugins = [...config.plugin];
|
|
185
419
|
config.plugin = config.plugin.filter((p) => {
|
|
186
420
|
if (typeof p !== "string") return true;
|
|
187
|
-
return
|
|
421
|
+
return !isOurPluginEntry(p);
|
|
188
422
|
});
|
|
189
423
|
if (config.plugin.length === originalLength) {
|
|
190
424
|
log("Plugin not found in config", { configFile });
|
|
@@ -198,12 +432,16 @@ function removeFromConfig(configDir) {
|
|
|
198
432
|
newPlugins: config.plugin,
|
|
199
433
|
configFile
|
|
200
434
|
});
|
|
201
|
-
atomicWriteJSON(configFile, config);
|
|
435
|
+
atomicWriteJSON(configFile, config, originalContent);
|
|
202
436
|
try {
|
|
203
437
|
const verifyContent = readFileSync(configFile, "utf-8");
|
|
204
|
-
const
|
|
438
|
+
const verifyParsed = parseConfigContent(verifyContent);
|
|
439
|
+
if (verifyParsed.parseError || !verifyParsed.config) {
|
|
440
|
+
throw new Error(`Verification parse failed: ${verifyParsed.parseError ?? "unknown parse error"}`);
|
|
441
|
+
}
|
|
442
|
+
const verifyConfig = verifyParsed.config;
|
|
205
443
|
const stillHasPlugin = verifyConfig.plugin?.some(
|
|
206
|
-
(p) => typeof p === "string" && (p
|
|
444
|
+
(p) => typeof p === "string" && isOurPluginEntry(p)
|
|
207
445
|
);
|
|
208
446
|
if (stillHasPlugin) {
|
|
209
447
|
throw new Error("Verification failed: plugin still present after removal");
|
|
@@ -234,9 +472,10 @@ function removeFromConfig(configDir) {
|
|
|
234
472
|
}
|
|
235
473
|
function cleanupOldBackups(configFile) {
|
|
236
474
|
try {
|
|
237
|
-
const configDir =
|
|
475
|
+
const configDir = dirname(configFile);
|
|
476
|
+
const configBase = basename(configFile);
|
|
238
477
|
const files = readdirSync(configDir);
|
|
239
|
-
const backupFiles = files.filter((f) => f.startsWith(
|
|
478
|
+
const backupFiles = files.filter((f) => f.startsWith(`${configBase}.backup.`)).sort().reverse();
|
|
240
479
|
for (let i = 5; i < backupFiles.length; i++) {
|
|
241
480
|
const backupPath = join(configDir, backupFiles[i]);
|
|
242
481
|
try {
|
|
@@ -250,13 +489,20 @@ function cleanupOldBackups(configFile) {
|
|
|
250
489
|
}
|
|
251
490
|
try {
|
|
252
491
|
console.log("\u{1F9F9} OpenCode Orchestrator - Uninstalling...");
|
|
492
|
+
if (isCI) log("Running in CI mode");
|
|
253
493
|
log("Uninstallation started", { platform: process.platform, node: process.version });
|
|
494
|
+
if (isCI) {
|
|
495
|
+
console.log("\u2139\uFE0F CI environment detected. Skipping automatic plugin cleanup.");
|
|
496
|
+
log("Skipping automatic plugin cleanup in CI");
|
|
497
|
+
clearTimeout(timeoutId);
|
|
498
|
+
process.exit(0);
|
|
499
|
+
}
|
|
254
500
|
const configPaths = getConfigPaths();
|
|
255
501
|
log("Config paths to check", configPaths);
|
|
256
502
|
let removed = false;
|
|
257
503
|
let backupCreated = null;
|
|
258
504
|
for (const configDir of configPaths) {
|
|
259
|
-
const configFile =
|
|
505
|
+
const configFile = resolveConfigFile(configDir);
|
|
260
506
|
const result = removeFromConfig(configDir);
|
|
261
507
|
if (result.success) {
|
|
262
508
|
console.log(`\u2705 Plugin removed: ${configFile}`);
|
|
@@ -281,4 +527,6 @@ try {
|
|
|
281
527
|
console.error("\u274C " + formatError(error, "clean up config"));
|
|
282
528
|
console.log(` Check logs: ${LOG_FILE}`);
|
|
283
529
|
process.exit(0);
|
|
530
|
+
} finally {
|
|
531
|
+
clearTimeout(timeoutId);
|
|
284
532
|
}
|
package/dist/shared/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "opencode-orchestrator",
|
|
3
3
|
"displayName": "OpenCode Orchestrator",
|
|
4
4
|
"description": "Distributed Cognitive Architecture for OpenCode. Turns simple prompts into specialized multi-agent workflows (Planner, Coder, Reviewer).",
|
|
5
|
-
"version": "1.2.
|
|
5
|
+
"version": "1.2.66",
|
|
6
6
|
"author": "agnusdei1207",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
},
|
|
35
35
|
"files": [
|
|
36
36
|
"dist",
|
|
37
|
+
"scripts/run-install-hook.mjs",
|
|
37
38
|
"bin",
|
|
38
39
|
"README.md",
|
|
39
40
|
"LICENSE"
|
|
@@ -51,13 +52,16 @@
|
|
|
51
52
|
"test:unit": "vitest run tests/unit --reporter=verbose",
|
|
52
53
|
"test:e2e": "vitest run tests/e2e --reporter=verbose",
|
|
53
54
|
"test:all": "npm run build && vitest run --reporter=verbose && echo '=== ALL TESTS PASSED ==='",
|
|
54
|
-
"postinstall": "node
|
|
55
|
-
"preuninstall": "node
|
|
55
|
+
"postinstall": "node scripts/run-install-hook.mjs postinstall",
|
|
56
|
+
"preuninstall": "node scripts/run-install-hook.mjs preuninstall",
|
|
56
57
|
"prepublishOnly": "npm run build",
|
|
57
58
|
"publish:token": "npm publish --access public",
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
59
|
+
"releae:patch": "npm run release:patch",
|
|
60
|
+
"sync:readme-version": "node scripts/sync-readme-version.mjs",
|
|
61
|
+
"version": "npm run sync:readme-version",
|
|
62
|
+
"release:patch": "npm version patch && npm run build && npm run docker:rust-dist && npm run publish:token",
|
|
63
|
+
"release:minor": "npm version minor && npm run build && npm run docker:rust-dist && npm run publish:token",
|
|
64
|
+
"release:major": "npm version major && npm run build && npm run docker:rust-dist && npm run publish:token",
|
|
61
65
|
"reset:local": "brew uninstall opencode 2>/dev/null; rm -rf ~/.config/opencode ~/.opencode ~/.local/share/opencode ~/.cache/opencode/node_modules/opencode-orchestrator && echo '=== Clean done ===' && brew install opencode && echo '{\"plugin\": [\"opencode-orchestrator\"], \"$schema\": \"https://opencode.ai/config.json\"}' > ~/.config/opencode/opencode.json && echo '=== Reset (Dev) complete. Run: opencode ==='",
|
|
62
66
|
"reset:prod": "brew uninstall opencode 2>/dev/null; rm -rf ~/.config/opencode ~/.opencode ~/.local/share/opencode ~/.cache/opencode/node_modules/opencode-orchestrator && echo '=== Clean done ===' && brew install opencode && echo '{\"plugin\": [\"opencode-orchestrator\"], \"$schema\": \"https://opencode.ai/config.json\"}' > ~/.config/opencode/opencode.json && npm uninstall -g opencode-orchestrator && echo '=== Reset (Prod) complete. Run: opencode ==='",
|
|
63
67
|
"ginstall": "npm install -g opencode-orchestrator",
|
|
@@ -69,6 +73,7 @@
|
|
|
69
73
|
"dependencies": {
|
|
70
74
|
"@opencode-ai/plugin": "^1.1.35",
|
|
71
75
|
"@opencode-ai/sdk": "^1.1.35",
|
|
76
|
+
"jsonc-parser": "^3.3.1",
|
|
72
77
|
"zod": "^4.3.6"
|
|
73
78
|
},
|
|
74
79
|
"devDependencies": {
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
const VALID_HOOKS = new Set(["postinstall", "preuninstall"]);
|
|
9
|
+
|
|
10
|
+
function resolveRepoRoot() {
|
|
11
|
+
const scriptPath = fileURLToPath(import.meta.url);
|
|
12
|
+
return path.resolve(path.dirname(scriptPath), "..");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function resolveHookCommand(repoRoot, hookName) {
|
|
16
|
+
const distEntry = path.join(repoRoot, "dist", "scripts", `${hookName}.js`);
|
|
17
|
+
if (existsSync(distEntry)) {
|
|
18
|
+
return {
|
|
19
|
+
command: process.execPath,
|
|
20
|
+
args: [distEntry],
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const sourceEntry = path.join(repoRoot, "scripts", `${hookName}.ts`);
|
|
25
|
+
if (existsSync(sourceEntry)) {
|
|
26
|
+
return {
|
|
27
|
+
command: process.execPath,
|
|
28
|
+
args: ["--experimental-strip-types", sourceEntry],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function main() {
|
|
36
|
+
const hookName = process.argv[2];
|
|
37
|
+
if (!VALID_HOOKS.has(hookName)) {
|
|
38
|
+
console.error(`Unknown install hook: ${hookName ?? "(missing)"}`);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const repoRoot = resolveRepoRoot();
|
|
43
|
+
const hookCommand = resolveHookCommand(repoRoot, hookName);
|
|
44
|
+
|
|
45
|
+
if (!hookCommand) {
|
|
46
|
+
console.log(`⚠️ ${hookName} entrypoint not found. Skipping gracefully.`);
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const result = spawnSync(hookCommand.command, hookCommand.args, {
|
|
51
|
+
cwd: repoRoot,
|
|
52
|
+
stdio: "inherit",
|
|
53
|
+
env: process.env,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
if (typeof result.status === "number") {
|
|
57
|
+
process.exit(result.status);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (result.error) {
|
|
61
|
+
console.error(`Failed to run ${hookName}: ${result.error.message}`);
|
|
62
|
+
}
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
main();
|