oh-my-opencode-cohub 1.0.15 → 1.0.16
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
CHANGED
|
@@ -72,6 +72,34 @@ CLI 会精确清理所有 `co-*` 代理和相关配置,不影响其他插件
|
|
|
72
72
|
- 可用代理列表中出现 12 个 `co-*` 前缀代理(`co-orchestrator`、`co-oracle`、`co-librarian`、`co-explorer`、`co-designer`、`co-fixer`、`co-observer`、`co-council`、`co-rule-user`、`co-rule-project`、`co-rule-app`、`co-planner`)
|
|
73
73
|
- Orchestrator 自动进入纯调度模式(只做规划、委派、验证,不直接操作文件)
|
|
74
74
|
|
|
75
|
+
### 从源码安装(本地开发)
|
|
76
|
+
|
|
77
|
+
如果需要修改源码或使用开发版本:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# 1. 克隆项目
|
|
81
|
+
git clone <repo-url> && cd oh-my-opencode-cohub
|
|
82
|
+
|
|
83
|
+
# 2. 安装依赖
|
|
84
|
+
npm install
|
|
85
|
+
|
|
86
|
+
# 3. 构建(需要系统已安装 Bun)
|
|
87
|
+
npm run build
|
|
88
|
+
|
|
89
|
+
# 4. 方式 A:npm link 全局链接(推荐)
|
|
90
|
+
npm link
|
|
91
|
+
bunx oh-my-opencode-cohub install
|
|
92
|
+
# 重启 OpenCode 即可。之后修改源码只需重新 npm run build
|
|
93
|
+
|
|
94
|
+
# 4. 方式 B:手动配置绝对路径
|
|
95
|
+
# 编辑 ~/.config/opencode/opencode.json,在 plugin 数组中写入项目绝对路径:
|
|
96
|
+
# { "plugin": ["/absolute/path/to/oh-my-opencode-cohub"] }
|
|
97
|
+
# 然后手动运行 CLI 注册代理:
|
|
98
|
+
# node dist/cli/index.js install
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
> **构建依赖**:`npm run build` 使用 `bun build` 和 `tsc`。系统需安装 [Bun](https://bun.sh)(构建工具)和 Node.js(类型声明生成)。所有 `@opencode-ai/*`、`@opentui/*`、`zod` 均为 external,不打包进 `dist/`。
|
|
102
|
+
|
|
75
103
|
## 代理一览
|
|
76
104
|
|
|
77
105
|
### 代理(12 个,全中文提示词)
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAqClD,wBAAwB;AACxB,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAalD,CAAC;AAwEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,wrBAA+B,CAAC;AAEhE,QAAA,MAAM,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAqClD,wBAAwB;AACxB,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAalD,CAAC;AAwEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,wrBAA+B,CAAC;AAEhE,QAAA,MAAM,WAAW,EAAE,MAiSlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -443,11 +443,12 @@ class TaskTracker {
|
|
|
443
443
|
const label = typeof args.description === "string" ? args.description : alias;
|
|
444
444
|
this.jobs.set(alias, {
|
|
445
445
|
alias,
|
|
446
|
-
sessionId: "",
|
|
446
|
+
sessionId: args.task_id ?? "",
|
|
447
447
|
parentSessionId,
|
|
448
448
|
agent,
|
|
449
449
|
label,
|
|
450
450
|
status: "running",
|
|
451
|
+
background: args.background ?? false,
|
|
451
452
|
terminalReconciled: false,
|
|
452
453
|
createdAt: Date.now()
|
|
453
454
|
});
|
|
@@ -462,11 +463,24 @@ class TaskTracker {
|
|
|
462
463
|
}
|
|
463
464
|
}
|
|
464
465
|
if (latest) {
|
|
466
|
+
if (latest.background) {
|
|
467
|
+
if (sessionId)
|
|
468
|
+
latest.sessionId = sessionId;
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
465
471
|
latest.status = status;
|
|
466
472
|
if (sessionId)
|
|
467
473
|
latest.sessionId = sessionId;
|
|
468
474
|
}
|
|
469
475
|
}
|
|
476
|
+
updateByChildSessionId(sessionId, status) {
|
|
477
|
+
for (const job of this.jobs.values()) {
|
|
478
|
+
if (job.sessionId === sessionId && job.background && job.status === "running") {
|
|
479
|
+
job.status = status;
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
470
484
|
getBoardText(parentSessionId) {
|
|
471
485
|
const pid = parentSessionId || this._currentParentSessionId;
|
|
472
486
|
const activeJobs = [];
|
|
@@ -513,6 +527,14 @@ class TaskTracker {
|
|
|
513
527
|
job.terminalReconciled = true;
|
|
514
528
|
}
|
|
515
529
|
}
|
|
530
|
+
cleanupStaleJobs(timeoutMs) {
|
|
531
|
+
const now = Date.now();
|
|
532
|
+
for (const job of this.jobs.values()) {
|
|
533
|
+
if (job.background && job.status === "running" && now - job.createdAt > timeoutMs) {
|
|
534
|
+
job.status = "errored";
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
516
538
|
isReusable(alias) {
|
|
517
539
|
const job = this.jobs.get(alias);
|
|
518
540
|
return job?.status === "completed" && job.terminalReconciled;
|
|
@@ -732,6 +754,46 @@ var CoHubPlugin = async (input, options) => {
|
|
|
732
754
|
}
|
|
733
755
|
}
|
|
734
756
|
syncAgentConfig();
|
|
757
|
+
function extractChildSessionId(output) {
|
|
758
|
+
if (!output || typeof output !== "object")
|
|
759
|
+
return;
|
|
760
|
+
const o = output;
|
|
761
|
+
const meta = o.metadata;
|
|
762
|
+
if (meta) {
|
|
763
|
+
if (typeof meta.sessionId === "string")
|
|
764
|
+
return meta.sessionId;
|
|
765
|
+
if (typeof meta.taskId === "string")
|
|
766
|
+
return meta.taskId;
|
|
767
|
+
if (typeof meta.task_id === "string")
|
|
768
|
+
return meta.task_id;
|
|
769
|
+
if (typeof meta.id === "string")
|
|
770
|
+
return meta.id;
|
|
771
|
+
}
|
|
772
|
+
const text = typeof o.output === "string" ? o.output : "";
|
|
773
|
+
const m = text.match(/\b(session|task)[_\s]?(?:id|ID)[:\s]+(\S+)/i);
|
|
774
|
+
if (m)
|
|
775
|
+
return m[2];
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
function extractSessionIdFromEvent(props) {
|
|
779
|
+
if (!props || typeof props !== "object")
|
|
780
|
+
return;
|
|
781
|
+
const p = props;
|
|
782
|
+
const info = p.info;
|
|
783
|
+
if (info?.id)
|
|
784
|
+
return info.id;
|
|
785
|
+
if (typeof p.sessionID === "string")
|
|
786
|
+
return p.sessionID;
|
|
787
|
+
if (typeof p.sessionId === "string")
|
|
788
|
+
return p.sessionId;
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
const STALE_TIMEOUT_MS = 30 * 60 * 1000;
|
|
792
|
+
const cleanupTimer = setInterval(() => {
|
|
793
|
+
try {
|
|
794
|
+
tracker.cleanupStaleJobs(STALE_TIMEOUT_MS);
|
|
795
|
+
} catch {}
|
|
796
|
+
}, 30000);
|
|
735
797
|
const agentConfigs = {};
|
|
736
798
|
for (const agent of agents) {
|
|
737
799
|
agentConfigs[agent.name] = {
|
|
@@ -767,14 +829,41 @@ var CoHubPlugin = async (input, options) => {
|
|
|
767
829
|
}
|
|
768
830
|
} catch {}
|
|
769
831
|
},
|
|
770
|
-
"tool.execute.after": async (input2,
|
|
832
|
+
"tool.execute.after": async (input2, output) => {
|
|
771
833
|
try {
|
|
772
834
|
if (input2.tool === "task") {
|
|
773
|
-
|
|
835
|
+
try {
|
|
836
|
+
const debugDir = path2.join(os2.homedir(), ".local", "share", "opencode", "storage", "oh-my-opencode-cohub");
|
|
837
|
+
if (!fs2.existsSync(debugDir))
|
|
838
|
+
fs2.mkdirSync(debugDir, { recursive: true });
|
|
839
|
+
fs2.writeFileSync(path2.join(debugDir, "task-output-debug.json"), JSON.stringify({
|
|
840
|
+
time: new Date().toISOString(),
|
|
841
|
+
callID: input2.callID,
|
|
842
|
+
output_keys: Object.keys(output || {}),
|
|
843
|
+
output: JSON.parse(JSON.stringify(output))
|
|
844
|
+
}, null, 2), "utf-8");
|
|
845
|
+
} catch {}
|
|
846
|
+
const childSessionId = extractChildSessionId(output);
|
|
847
|
+
tracker.updateAfterTask(input2.sessionID, "completed", childSessionId);
|
|
774
848
|
syncTrackerState(input2.sessionID ?? "");
|
|
775
849
|
}
|
|
776
850
|
} catch {}
|
|
777
851
|
},
|
|
852
|
+
event: async (input2) => {
|
|
853
|
+
try {
|
|
854
|
+
const e = input2.event;
|
|
855
|
+
const sessionId = extractSessionIdFromEvent(e.properties);
|
|
856
|
+
if (!sessionId)
|
|
857
|
+
return;
|
|
858
|
+
if (e.type === "session.idle") {
|
|
859
|
+
tracker.updateByChildSessionId(sessionId, "completed");
|
|
860
|
+
syncTrackerState(tracker.currentParentSessionId);
|
|
861
|
+
} else if (e.type === "session.deleted" || e.type === "session.error") {
|
|
862
|
+
tracker.updateByChildSessionId(sessionId, "errored");
|
|
863
|
+
syncTrackerState(tracker.currentParentSessionId);
|
|
864
|
+
}
|
|
865
|
+
} catch {}
|
|
866
|
+
},
|
|
778
867
|
"experimental.chat.messages.transform": async (_input, output) => {
|
|
779
868
|
try {
|
|
780
869
|
const board = tracker.getBoardText();
|
|
@@ -799,6 +888,9 @@ var CoHubPlugin = async (input, options) => {
|
|
|
799
888
|
},
|
|
800
889
|
"experimental.chat.system.transform": async (_input, output) => {
|
|
801
890
|
output.system.push(CHINESE_LANGUAGE_INSTRUCTION);
|
|
891
|
+
},
|
|
892
|
+
dispose: async () => {
|
|
893
|
+
clearInterval(cleanupTimer);
|
|
802
894
|
}
|
|
803
895
|
};
|
|
804
896
|
};
|
|
@@ -13,9 +13,14 @@ export declare class TaskTracker {
|
|
|
13
13
|
registerBeforeTask(parentSessionId: string, args: TaskArgs): string;
|
|
14
14
|
/**
|
|
15
15
|
* 在 tool.execute.after 中调用,更新任务完成状态
|
|
16
|
-
*
|
|
16
|
+
* 非背景任务:立即标 completed;背景任务:不更新(等 session.idle 事件)
|
|
17
17
|
*/
|
|
18
18
|
updateAfterTask(parentSessionId: string, status: TaskStatus, sessionId?: string): void;
|
|
19
|
+
/**
|
|
20
|
+
* 根据子 session ID 更新任务状态(供 event hook 使用)
|
|
21
|
+
* 当背景任务的 session 变为 idle 时调用
|
|
22
|
+
*/
|
|
23
|
+
updateByChildSessionId(sessionId: string, status: TaskStatus): void;
|
|
19
24
|
/**
|
|
20
25
|
* 生成 Background Job Board 文本
|
|
21
26
|
*/
|
|
@@ -24,6 +29,10 @@ export declare class TaskTracker {
|
|
|
24
29
|
* 标记任务已调和(不再显示在 Unreconciled 中)
|
|
25
30
|
*/
|
|
26
31
|
reconcileJob(alias: string): void;
|
|
32
|
+
/**
|
|
33
|
+
* 清理超时的背景任务(超过 timeoutMs 仍 running 的标为 errored)
|
|
34
|
+
*/
|
|
35
|
+
cleanupStaleJobs(timeoutMs: number): void;
|
|
27
36
|
/**
|
|
28
37
|
* 检查任务是否可复用
|
|
29
38
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/task-manager/tracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE/D,qBAAa,WAAW;IACtB,OAAO,CAAC,IAAI,CAAgC;IAC5C,OAAO,CAAC,QAAQ,CAA6B;IAC7C,yCAAyC;IACzC,OAAO,CAAC,uBAAuB,CAAM;IAErC,IAAI,sBAAsB,IAAI,MAAM,CAEnC;IAED,mDAAmD;IACnD,OAAO,CAAC,KAAK;IAOb;;OAEG;IACH,kBAAkB,CAAC,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,MAAM;
|
|
1
|
+
{"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/task-manager/tracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE/D,qBAAa,WAAW;IACtB,OAAO,CAAC,IAAI,CAAgC;IAC5C,OAAO,CAAC,QAAQ,CAA6B;IAC7C,yCAAyC;IACzC,OAAO,CAAC,uBAAuB,CAAM;IAErC,IAAI,sBAAsB,IAAI,MAAM,CAEnC;IAED,mDAAmD;IACnD,OAAO,CAAC,KAAK;IAOb;;OAEG;IACH,kBAAkB,CAAC,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,MAAM;IAqBnE;;;OAGG;IACH,eAAe,CAAC,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI;IAwBtF;;;OAGG;IACH,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IASnE;;OAEG;IACH,YAAY,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IA4CrD;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAOjC;;OAEG;IACH,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IASzC;;OAEG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAKlC,2BAA2B;IAC3B,gBAAgB,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,EAAE;IAUnD,uBAAuB;IACvB,eAAe,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM;CASjD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/task-manager/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,WAAW,CAAC;AAE3E,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,QAAQ;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/task-manager/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,WAAW,CAAC;AAE3E,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,QAAQ;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB"}
|