opencode-orchestrator 1.2.67 → 1.2.69
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 +22 -1
- package/dist/core/notification/task-toast-manager.d.ts +3 -0
- package/dist/core/notification/toast-sanitizer.d.ts +3 -0
- package/dist/index.js +123 -59
- package/dist/scripts/postinstall.js +1407 -176
- package/dist/scripts/preuninstall.js +1407 -176
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
[](LICENSE)
|
|
10
10
|
[](https://www.npmjs.com/package/opencode-orchestrator)
|
|
11
11
|
<!-- VERSION:START -->
|
|
12
|
-
**Version:** `1.2.
|
|
12
|
+
**Version:** `1.2.69`
|
|
13
13
|
<!-- VERSION:END -->
|
|
14
14
|
</div>
|
|
15
15
|
|
|
@@ -24,6 +24,15 @@ npm install -g opencode-orchestrator
|
|
|
24
24
|
|
|
25
25
|
Install hooks are source-checkout safe, prefer `opencode.jsonc` when present, preserve sibling plugin entries, and skip automatic config mutation in CI environments.
|
|
26
26
|
|
|
27
|
+
To remove the plugin safely later, run:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm explore -g opencode-orchestrator -- npm run cleanup:plugin
|
|
31
|
+
npm uninstall -g opencode-orchestrator
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`npm uninstall -g` does not run dependency uninstall hooks in the npm 11 flow verified for this repo, so config cleanup is explicit.
|
|
35
|
+
|
|
27
36
|
Inside an OpenCode environment:
|
|
28
37
|
```bash
|
|
29
38
|
/task "Implement a new authentication module with JWT and audit logs"
|
|
@@ -284,6 +293,18 @@ The installation process is **production-safe** with multiple protection layers:
|
|
|
284
293
|
7. ✅ **Timeout protection** — 30s timeout prevents hanging
|
|
285
294
|
8. ✅ **Graceful degradation** — exits 0 on non-critical failures
|
|
286
295
|
|
|
296
|
+
### Safe Removal
|
|
297
|
+
OpenCode config cleanup is provided as an explicit command because global package uninstall does not invoke dependency uninstall hooks in the npm flow validated for this package.
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
npm explore -g opencode-orchestrator -- npm run cleanup:plugin
|
|
301
|
+
npm uninstall -g opencode-orchestrator
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Manual fallback:
|
|
305
|
+
- Open `~/.config/opencode/opencode.json` or `opencode.jsonc`
|
|
306
|
+
- Remove `"opencode-orchestrator"` from the `plugin` array
|
|
307
|
+
|
|
287
308
|
### Configuration Logs
|
|
288
309
|
- Unix: `/tmp/opencode-orchestrator.log`
|
|
289
310
|
- Windows: `%TEMP%\opencode-orchestrator.log`
|
package/dist/index.js
CHANGED
|
@@ -939,6 +939,77 @@ var init_types4 = __esm({
|
|
|
939
939
|
}
|
|
940
940
|
});
|
|
941
941
|
|
|
942
|
+
// src/core/notification/toast-sanitizer.ts
|
|
943
|
+
function stripTerminalSequences(value) {
|
|
944
|
+
return value.replace(/\r\n?/g, "\n").replace(ANSI_PATTERN, "").replace(C0_CONTROL_PATTERN, "");
|
|
945
|
+
}
|
|
946
|
+
function truncate(value, maxLength) {
|
|
947
|
+
if (value.length <= maxLength) {
|
|
948
|
+
return value;
|
|
949
|
+
}
|
|
950
|
+
return `${value.slice(0, Math.max(0, maxLength - 1)).trimEnd()}\u2026`;
|
|
951
|
+
}
|
|
952
|
+
function sanitizeInternal(value, options) {
|
|
953
|
+
const stripped = stripTerminalSequences(value);
|
|
954
|
+
if (options.singleLine) {
|
|
955
|
+
const singleLine = stripped.replace(/\s+/g, " ").trim();
|
|
956
|
+
return singleLine ? truncate(singleLine, options.maxLength) : "";
|
|
957
|
+
}
|
|
958
|
+
const rawLines = stripped.split("\n");
|
|
959
|
+
const lines = [];
|
|
960
|
+
for (const rawLine of rawLines) {
|
|
961
|
+
const normalizedLine = rawLine.replace(/\t/g, " ").replace(/[^\S\n]+/g, " ").trim();
|
|
962
|
+
if (normalizedLine.length === 0) {
|
|
963
|
+
if (!options.singleLine && lines.length > 0 && lines[lines.length - 1] !== "") {
|
|
964
|
+
lines.push("");
|
|
965
|
+
}
|
|
966
|
+
continue;
|
|
967
|
+
}
|
|
968
|
+
lines.push(normalizedLine);
|
|
969
|
+
if (lines.length >= options.maxLines) {
|
|
970
|
+
break;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
const collapsed = lines.join("\n").trim();
|
|
974
|
+
if (!collapsed) {
|
|
975
|
+
return "";
|
|
976
|
+
}
|
|
977
|
+
const truncated = truncate(collapsed, options.maxLength);
|
|
978
|
+
if (rawLines.length > options.maxLines && !truncated.endsWith("\u2026")) {
|
|
979
|
+
return truncate(`${truncated}
|
|
980
|
+
\u2026`, options.maxLength);
|
|
981
|
+
}
|
|
982
|
+
return truncated;
|
|
983
|
+
}
|
|
984
|
+
function sanitizeToastTitle(value) {
|
|
985
|
+
return sanitizeInternal(value, {
|
|
986
|
+
maxLength: 80,
|
|
987
|
+
maxLines: 1,
|
|
988
|
+
singleLine: true
|
|
989
|
+
});
|
|
990
|
+
}
|
|
991
|
+
function sanitizeToastInline(value, maxLength = 120) {
|
|
992
|
+
return sanitizeInternal(value, {
|
|
993
|
+
maxLength,
|
|
994
|
+
maxLines: 1,
|
|
995
|
+
singleLine: true
|
|
996
|
+
});
|
|
997
|
+
}
|
|
998
|
+
function sanitizeToastMessage(value, maxLength = 600, maxLines = 10) {
|
|
999
|
+
return sanitizeInternal(value, {
|
|
1000
|
+
maxLength,
|
|
1001
|
+
maxLines
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
var ANSI_PATTERN, C0_CONTROL_PATTERN;
|
|
1005
|
+
var init_toast_sanitizer = __esm({
|
|
1006
|
+
"src/core/notification/toast-sanitizer.ts"() {
|
|
1007
|
+
"use strict";
|
|
1008
|
+
ANSI_PATTERN = /\u001B(?:\][^\u0007\u001B]*(?:\u0007|\u001B\\)|[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
|
|
1009
|
+
C0_CONTROL_PATTERN = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g;
|
|
1010
|
+
}
|
|
1011
|
+
});
|
|
1012
|
+
|
|
942
1013
|
// src/core/notification/toast-core.ts
|
|
943
1014
|
function initToastClient(client) {
|
|
944
1015
|
tuiClient = client;
|
|
@@ -950,10 +1021,12 @@ function initToastClient(client) {
|
|
|
950
1021
|
return cleanup;
|
|
951
1022
|
}
|
|
952
1023
|
function show(options) {
|
|
1024
|
+
const title = sanitizeToastTitle(options.title);
|
|
1025
|
+
const message = sanitizeToastMessage(options.message);
|
|
953
1026
|
const toast = {
|
|
954
1027
|
id: `toast_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`,
|
|
955
|
-
title
|
|
956
|
-
message
|
|
1028
|
+
title,
|
|
1029
|
+
message,
|
|
957
1030
|
variant: options.variant || "info",
|
|
958
1031
|
timestamp: /* @__PURE__ */ new Date(),
|
|
959
1032
|
duration: options.duration ?? 5e3,
|
|
@@ -1009,6 +1082,7 @@ var init_toast_core = __esm({
|
|
|
1009
1082
|
"src/core/notification/toast-core.ts"() {
|
|
1010
1083
|
"use strict";
|
|
1011
1084
|
init_shared();
|
|
1085
|
+
init_toast_sanitizer();
|
|
1012
1086
|
tuiClient = null;
|
|
1013
1087
|
toasts = [];
|
|
1014
1088
|
handlers = [];
|
|
@@ -6488,11 +6562,30 @@ init_shared();
|
|
|
6488
6562
|
|
|
6489
6563
|
// src/core/notification/task-toast-manager.ts
|
|
6490
6564
|
init_shared();
|
|
6565
|
+
init_toast_sanitizer();
|
|
6491
6566
|
var TaskToastManager = class {
|
|
6492
6567
|
tasks = /* @__PURE__ */ new Map();
|
|
6493
6568
|
client = null;
|
|
6494
6569
|
concurrency = null;
|
|
6495
6570
|
todoSync = null;
|
|
6571
|
+
getSafeTaskDescription(task) {
|
|
6572
|
+
return sanitizeToastInline(task.description, 100) || "Untitled task";
|
|
6573
|
+
}
|
|
6574
|
+
getSafeAgent(agent) {
|
|
6575
|
+
return sanitizeToastInline(agent, 32) || "unknown";
|
|
6576
|
+
}
|
|
6577
|
+
showToast(title, message, variant, duration5) {
|
|
6578
|
+
if (!this.client || !this.client.tui) return;
|
|
6579
|
+
this.client.tui.showToast({
|
|
6580
|
+
body: {
|
|
6581
|
+
title: sanitizeToastTitle(title) || "Notification",
|
|
6582
|
+
message: sanitizeToastMessage(message),
|
|
6583
|
+
variant,
|
|
6584
|
+
duration: duration5
|
|
6585
|
+
}
|
|
6586
|
+
}).catch(() => {
|
|
6587
|
+
});
|
|
6588
|
+
}
|
|
6496
6589
|
/**
|
|
6497
6590
|
* Initialize the manager with OpenCode client
|
|
6498
6591
|
*/
|
|
@@ -6607,7 +6700,7 @@ var TaskToastManager = class {
|
|
|
6607
6700
|
const duration5 = this.formatDuration(task.startedAt);
|
|
6608
6701
|
const bgTag = task.isBackground ? TUI_TAGS.BACKGROUND : TUI_TAGS.FOREGROUND;
|
|
6609
6702
|
const isNew = newTask && task.id === newTask.id ? TUI_ICONS.NEW : "";
|
|
6610
|
-
lines.push(`${bgTag} ${task
|
|
6703
|
+
lines.push(`${bgTag} ${this.getSafeTaskDescription(task)} (${this.getSafeAgent(task.agent)}) - ${duration5}${isNew}`);
|
|
6611
6704
|
}
|
|
6612
6705
|
}
|
|
6613
6706
|
if (queued.length > 0) {
|
|
@@ -6615,7 +6708,7 @@ var TaskToastManager = class {
|
|
|
6615
6708
|
lines.push(`${TUI_ICONS.QUEUED} Queued (${queued.length}):`);
|
|
6616
6709
|
for (const task of queued) {
|
|
6617
6710
|
const bgTag = task.isBackground ? TUI_TAGS.WAITING : TUI_TAGS.PENDING;
|
|
6618
|
-
lines.push(`${bgTag} ${task
|
|
6711
|
+
lines.push(`${bgTag} ${this.getSafeTaskDescription(task)} (${this.getSafeAgent(task.agent)})`);
|
|
6619
6712
|
}
|
|
6620
6713
|
}
|
|
6621
6714
|
return lines.join("\n");
|
|
@@ -6624,40 +6717,37 @@ var TaskToastManager = class {
|
|
|
6624
6717
|
* Show consolidated toast with all running/queued tasks
|
|
6625
6718
|
*/
|
|
6626
6719
|
showTaskListToast(newTask) {
|
|
6627
|
-
if (!this.client || !this.client.tui) return;
|
|
6628
6720
|
const message = this.buildTaskListMessage(newTask);
|
|
6629
6721
|
const running = this.getRunningTasks();
|
|
6630
6722
|
const queued = this.getQueuedTasks();
|
|
6631
6723
|
const title = newTask.isBackground ? `Background Task Started` : `Task Started`;
|
|
6632
|
-
this.
|
|
6633
|
-
|
|
6634
|
-
|
|
6635
|
-
|
|
6636
|
-
|
|
6637
|
-
|
|
6638
|
-
}
|
|
6639
|
-
}).catch(() => {
|
|
6640
|
-
});
|
|
6724
|
+
this.showToast(
|
|
6725
|
+
title,
|
|
6726
|
+
message || `${this.getSafeTaskDescription(newTask)} (${this.getSafeAgent(newTask.agent)})`,
|
|
6727
|
+
STATUS_LABEL.INFO,
|
|
6728
|
+
running.length + queued.length > 2 ? 5e3 : 3e3
|
|
6729
|
+
);
|
|
6641
6730
|
}
|
|
6642
6731
|
/**
|
|
6643
6732
|
* Show task completion toast
|
|
6644
6733
|
*/
|
|
6645
6734
|
showCompletionToast(info) {
|
|
6646
|
-
if (!this.client || !this.client.tui) return;
|
|
6647
6735
|
this.removeTask(info.id);
|
|
6648
6736
|
const remaining = this.getRunningTasks();
|
|
6649
6737
|
const queued = this.getQueuedTasks();
|
|
6650
6738
|
let message;
|
|
6651
6739
|
let title;
|
|
6652
6740
|
let variant;
|
|
6741
|
+
const safeDescription = sanitizeToastInline(info.description, 100) || "Untitled task";
|
|
6742
|
+
const safeError = info.error ? sanitizeToastMessage(info.error, 240, 4) : "";
|
|
6653
6743
|
if (info.status === STATUS_LABEL.ERROR || info.status === STATUS_LABEL.CANCELLED || info.status === STATUS_LABEL.FAILED) {
|
|
6654
6744
|
title = info.status === STATUS_LABEL.ERROR ? "Task Failed" : "Task Cancelled";
|
|
6655
|
-
message = `[FAIL] "${
|
|
6656
|
-
${
|
|
6745
|
+
message = `[FAIL] "${safeDescription}" ${info.status}
|
|
6746
|
+
${safeError}`;
|
|
6657
6747
|
variant = STATUS_LABEL.ERROR;
|
|
6658
6748
|
} else {
|
|
6659
6749
|
title = "Task Completed";
|
|
6660
|
-
message = `[DONE] "${
|
|
6750
|
+
message = `[DONE] "${safeDescription}" finished in ${info.duration}`;
|
|
6661
6751
|
variant = STATUS_LABEL.SUCCESS;
|
|
6662
6752
|
}
|
|
6663
6753
|
if (remaining.length > 0 || queued.length > 0) {
|
|
@@ -6665,41 +6755,28 @@ ${info.error || ""}`;
|
|
|
6665
6755
|
|
|
6666
6756
|
Still running: ${remaining.length} | Queued: ${queued.length}`;
|
|
6667
6757
|
}
|
|
6668
|
-
this.
|
|
6669
|
-
body: {
|
|
6670
|
-
title,
|
|
6671
|
-
message,
|
|
6672
|
-
variant,
|
|
6673
|
-
duration: 5e3
|
|
6674
|
-
}
|
|
6675
|
-
}).catch(() => {
|
|
6676
|
-
});
|
|
6758
|
+
this.showToast(title, message, variant, 5e3);
|
|
6677
6759
|
}
|
|
6678
6760
|
/**
|
|
6679
6761
|
* Show all-tasks-complete summary toast
|
|
6680
6762
|
*/
|
|
6681
6763
|
showAllCompleteToast(parentSessionID, completedTasks) {
|
|
6682
|
-
if (!this.client || !this.client.tui) return;
|
|
6683
6764
|
const successCount = completedTasks.filter((t) => t.status === STATUS_LABEL.COMPLETED).length;
|
|
6684
6765
|
const failCount = completedTasks.filter((t) => t.status === STATUS_LABEL.ERROR || t.status === STATUS_LABEL.CANCELLED || t.status === STATUS_LABEL.FAILED).length;
|
|
6685
|
-
const taskList = completedTasks.map((t) => `- [${t.status === STATUS_LABEL.COMPLETED ? "OK" : "FAIL"}] ${t.description} (${t.duration})`).join("\n");
|
|
6686
|
-
this.
|
|
6687
|
-
|
|
6688
|
-
|
|
6689
|
-
message: `${successCount} succeeded, ${failCount} failed
|
|
6766
|
+
const taskList = completedTasks.map((t) => `- [${t.status === STATUS_LABEL.COMPLETED ? "OK" : "FAIL"}] ${sanitizeToastInline(t.description, 80) || "Untitled task"} (${t.duration})`).join("\n");
|
|
6767
|
+
this.showToast(
|
|
6768
|
+
"All Tasks Completed",
|
|
6769
|
+
`${successCount} succeeded, ${failCount} failed
|
|
6690
6770
|
|
|
6691
6771
|
${taskList}`,
|
|
6692
|
-
|
|
6693
|
-
|
|
6694
|
-
|
|
6695
|
-
}).catch(() => {
|
|
6696
|
-
});
|
|
6772
|
+
failCount > 0 ? STATUS_LABEL.WARNING : STATUS_LABEL.SUCCESS,
|
|
6773
|
+
7e3
|
|
6774
|
+
);
|
|
6697
6775
|
}
|
|
6698
6776
|
/**
|
|
6699
6777
|
* Show Mission Complete toast (Grand Finale)
|
|
6700
6778
|
*/
|
|
6701
6779
|
showMissionCompleteToast(title = "Mission Complete", message = "All tasks completed successfully.") {
|
|
6702
|
-
if (!this.client || !this.client.tui) return;
|
|
6703
6780
|
const decoratedMessage = `
|
|
6704
6781
|
${TUI_ICONS.MISSION_COMPLETE} ${TUI_MESSAGES.MISSION_COMPLETE_TITLE} ${TUI_ICONS.MISSION_COMPLETE}
|
|
6705
6782
|
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
@@ -6707,36 +6784,23 @@ ${message}
|
|
|
6707
6784
|
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
6708
6785
|
${TUI_MESSAGES.MISSION_COMPLETE_SUBTITLE}
|
|
6709
6786
|
`.trim();
|
|
6710
|
-
this.
|
|
6711
|
-
body: {
|
|
6712
|
-
title: `${TUI_ICONS.SHIELD} ${title}`,
|
|
6713
|
-
message: decoratedMessage,
|
|
6714
|
-
variant: STATUS_LABEL.SUCCESS,
|
|
6715
|
-
duration: 1e4
|
|
6716
|
-
// Longer duration for the finale
|
|
6717
|
-
}
|
|
6718
|
-
}).catch(() => {
|
|
6719
|
-
});
|
|
6787
|
+
this.showToast(`${TUI_ICONS.SHIELD} ${title}`, decoratedMessage, STATUS_LABEL.SUCCESS, 1e4);
|
|
6720
6788
|
}
|
|
6721
6789
|
/**
|
|
6722
6790
|
* Show progress toast (for long-running tasks)
|
|
6723
6791
|
*/
|
|
6724
6792
|
showProgressToast(taskId, progress) {
|
|
6725
|
-
if (!this.client || !this.client.tui) return;
|
|
6726
6793
|
const task = this.tasks.get(taskId);
|
|
6727
6794
|
if (!task) return;
|
|
6728
6795
|
const percentage = Math.round(progress.current / progress.total * 100);
|
|
6729
6796
|
const progressBar = `[${"#".repeat(Math.floor(percentage / 10))}${"-".repeat(10 - Math.floor(percentage / 10))}]`;
|
|
6730
|
-
this.
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
message: `${progressBar} ${percentage}%
|
|
6797
|
+
this.showToast(
|
|
6798
|
+
`Task Progress: ${this.getSafeTaskDescription(task)}`,
|
|
6799
|
+
`${progressBar} ${percentage}%
|
|
6734
6800
|
${progress.message || ""}`,
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
}).catch(() => {
|
|
6739
|
-
});
|
|
6801
|
+
STATUS_LABEL.INFO,
|
|
6802
|
+
2e3
|
|
6803
|
+
);
|
|
6740
6804
|
}
|
|
6741
6805
|
/**
|
|
6742
6806
|
* Clear all tracked tasks
|