cortico-world-coding-agent-notify 0.1.0 → 0.1.1
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/CHANGELOG.md +9 -0
- package/README.md +6 -4
- package/index.ts +25 -11
- package/package.json +2 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## 0.1.1
|
|
6
|
+
|
|
7
|
+
- 修复桌面环境 `spawn codex ENOENT`:四个 Agent 的接入无需手动指定命令路径,CLI 由用户 shell / PowerShell 自动查找;需要外部 Node.js 的 hook 和所有测试按钮使用自动找到的 Node.js 绝对路径。无新增依赖。
|
|
8
|
+
- Resolve CLIs through the user shell or PowerShell and use the discovered absolute Node.js path for command hooks and delivery tests; no manual executable-path settings or new dependencies.
|
|
9
|
+
- 纠正隐私说明并移除误声明的 `sensitive-data` 标签:只转交任务结论及定位信息,不采集截图、麦克风或窗口数据;市场历史警示标签另行申请撤销。
|
|
10
|
+
- Correct the data disclosure and remove the mistakenly declared `sensitive-data` tag. Only final reports and workspace/session metadata are forwarded; no screen, microphone or foreground-window capture. Existing market warnings require a separate withdrawal request.
|
|
11
|
+
- 本次按用户要求未运行测试或类型检查,Windows 兼容性仍待验证。
|
|
12
|
+
- Tests and type checks were not run for this release, as requested; Windows compatibility remains unverified.
|
|
13
|
+
|
|
5
14
|
## 0.1.0
|
|
6
15
|
|
|
7
16
|
- 为 Codex、Claude Code、OpenCode、DSH 提供独立的安装 hook 和测试按钮;启动 World 不安装 hook。
|
package/README.md
CHANGED
|
@@ -19,22 +19,24 @@ ThermalEng 维护的第三方 Coopanion World 扩展,非 Pal AI Lab 官方扩
|
|
|
19
19
|
|
|
20
20
|
Codex、Claude hook 与配置页的测试需要 `node`(22+)在 PATH 中;Codex、DSH 的安装分别需要 `codex`、`dsh` 在 PATH 中。OpenCode、DSH 插件直接使用自身运行时发送报告。生成的 Agent 插件只是本扩展的入口,不会安装第三方插件。
|
|
21
21
|
|
|
22
|
-
World 运行时开启带令牌的 `127.0.0.1` 临时接口;hook 将最终报告发来,由 Coopanion 当前连接的模型总结,再使用其内置桌宠能力通知。因此需要 Coopanion
|
|
22
|
+
World 运行时开启带令牌的 `127.0.0.1` 临时接口;hook 将最终报告发来,由 Coopanion 当前连接的模型总结,再使用其内置桌宠能力通知。因此需要 Coopanion 正在运行并已连接模型,模型调用会产生正常用量。**任务结论会进入 Coopanion 当前配置的模型上下文和事件历史**。通知只转交最终回复/任务结论及项目路径、会话标识,不转交完整对话,不采集屏幕截图、麦克风音频或前台窗口信息。结论本身仍可能包含项目信息,请按所用模型服务的数据政策使用。
|
|
23
23
|
|
|
24
24
|
「测试」验证共用发送器 → World 事件入口,收到后由 Coo 通知;它不替代一次真实 Agent 任务对原生回调的验证。不提供离线队列;Coopanion 关闭时通知跳过,不影响 Agent 完成任务。重新点击安装不会重复添加 hook。
|
|
25
25
|
|
|
26
|
-
默认生成目录:`~/.coopanion/agent-hooks`。可通过 `COOPANION_AGENT_HOOK_HOME` 更改;DSH 支持 `COOPANION_DSH_PROFILE`、`
|
|
26
|
+
默认生成目录:`~/.coopanion/agent-hooks`。可通过 `COOPANION_AGENT_HOOK_HOME` 更改;DSH 支持 `COOPANION_DSH_PROFILE`、`DSH_HOME`。也尊重 Agent 自带的 `CODEX_HOME`、`CLAUDE_CONFIG_DIR` 和 `XDG_CONFIG_HOME`。使用多个配置时,应让 Coopanion 启动环境与对应 Agent 一致。
|
|
27
27
|
|
|
28
28
|
Codex 的 TOML 配置由自身 CLI 修改。已有 JSON 设置保留其他键;无效 JSON 会报错,不会覆盖。
|
|
29
29
|
|
|
30
|
+
四个 Agent 均不需要手动填写可执行文件路径。需要调用 CLI 时,Linux/macOS 使用用户的交互式登录 shell 查找命令,Windows 使用 PowerShell `Get-Command` 查找,兼容 npm 的 `.cmd` 入口。Codex、DSH 的安装通过各自 CLI 完成;Claude Code、OpenCode 直接使用原生配置或插件目录,不额外启动其 CLI。需要外部 Node.js 的 hook 与四个 Agent 的「测试」按钮共用自动查找,并使用找到的 Node.js 绝对路径,避免桌面进程 PATH 不完整导致 `ENOENT`;OpenCode、DSH 的正常回调继续使用自身运行时。未安装所需程序时会报错,不自动安装程序。
|
|
31
|
+
|
|
30
32
|
## Windows
|
|
31
33
|
|
|
32
34
|
面向 Windows 原生运行的 Agent;WSL 中的 Agent 按 Linux 环境部署,不混用两侧的 hook 路径。默认 hook 目录为 `%USERPROFILE%\.coopanion\agent-hooks`,Agent 配置路径仍尊重上述环境变量。
|
|
33
35
|
|
|
34
36
|
- 安装 Codex、DSH hook 时,通过 Windows PowerShell 调用原生 CLI,兼容 npm 的 `.cmd` 入口和带空格、中文的路径。
|
|
35
|
-
- Claude Code 使用原生 `command` + `args`
|
|
37
|
+
- Claude Code 使用原生 `command` + `args` 形式直接启动自动找到的 `node.exe`;需使用支持该形式的版本。
|
|
36
38
|
- Codex 使用 `commandWindows`,通过编码后的 PowerShell 命令转交 UTF-8 报告;需使用支持该字段的版本。
|
|
37
|
-
- OpenCode、DSH
|
|
39
|
+
- OpenCode、DSH 仍直接导入共用发送模块;配置页的测试直接启动自动找到的 `node.exe`,不弹出额外控制台窗口。
|
|
38
40
|
|
|
39
41
|
Windows 需要 PATH 中有 Node.js 22+ 和对应 Agent CLI,以及系统自带的 `powershell.exe`。本次 Windows 适配未运行测试。
|
|
40
42
|
|
package/index.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { execFile, spawn } from 'node:child_process';
|
|
|
3
3
|
import { randomBytes, timingSafeEqual } from 'node:crypto';
|
|
4
4
|
import { createServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http';
|
|
5
5
|
import { access, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
|
|
6
|
-
import { homedir } from 'node:os';
|
|
6
|
+
import { homedir, userInfo } from 'node:os';
|
|
7
7
|
import { dirname, join } from 'node:path';
|
|
8
8
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
9
9
|
import { promisify } from 'node:util';
|
|
@@ -39,6 +39,13 @@ function powershellArgs(command: string, args: string[], forwardInput = false) {
|
|
|
39
39
|
return ['-NoLogo', '-NoProfile', '-NonInteractive', '-WindowStyle', 'Hidden', '-EncodedCommand', Buffer.from(script, 'utf16le').toString('base64')];
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
// Let the OS shell resolve CLI paths, including those added by shell startup files.
|
|
43
|
+
function nativeCommand(command: string, args: string[], env: NodeJS.ProcessEnv, timeout = 120_000) {
|
|
44
|
+
return exec(WINDOWS ? 'powershell.exe' : env.SHELL || userInfo().shell || '/bin/sh',
|
|
45
|
+
WINDOWS ? powershellArgs(command, args) : ['-ilc', `exec ${[command, ...args].map(shellQuote).join(' ')}`],
|
|
46
|
+
{ timeout, windowsHide: true, env: { ...process.env, ...env } });
|
|
47
|
+
}
|
|
48
|
+
|
|
42
49
|
async function exists(file: string) {
|
|
43
50
|
try { await access(file); return true; } catch { return false; }
|
|
44
51
|
}
|
|
@@ -109,11 +116,16 @@ export class HookManager {
|
|
|
109
116
|
dsh: join(this.dir, 'dsh-plugin'),
|
|
110
117
|
};
|
|
111
118
|
this.dshManifest = join(this.env.DSH_HOME || join(home, '.dsh'), 'profiles', this.profile, 'package.json');
|
|
112
|
-
this.run = options.run ?? (async (command, args) => {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
119
|
+
this.run = options.run ?? (async (command, args) => { await nativeCommand(command, args, this.env); });
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private async nodePath() {
|
|
123
|
+
const marker = '__COOPANION_NODE__';
|
|
124
|
+
// Base64 keeps non-ASCII Windows paths intact across PowerShell output encodings.
|
|
125
|
+
const { stdout } = await nativeCommand(NODE, ['-p', `${JSON.stringify(marker)} + Buffer.from(process.execPath).toString('base64')`], this.env, 10_000);
|
|
126
|
+
const line = stdout.split(/\r?\n/).reverse().find((value) => value.startsWith(marker));
|
|
127
|
+
if (!line) throw new Error('Cannot locate Node.js. Install Node.js 22+ before installing or testing hooks.');
|
|
128
|
+
return Buffer.from(line.slice(marker.length), 'base64').toString('utf8');
|
|
117
129
|
}
|
|
118
130
|
|
|
119
131
|
async status(agent: Agent): Promise<HookStatus> {
|
|
@@ -142,13 +154,14 @@ export class HookManager {
|
|
|
142
154
|
const path = this.paths[agent];
|
|
143
155
|
const settings = await readJson(path);
|
|
144
156
|
const entries = stopHooks(settings);
|
|
145
|
-
const
|
|
157
|
+
const node = await this.nodePath();
|
|
158
|
+
const hook: CommandHook = { type: 'command', command: `${shellQuote(node)} ${shellQuote(this.runner)} ${agent}`, async: true };
|
|
146
159
|
if (WINDOWS) {
|
|
147
160
|
if (agent === 'claude') {
|
|
148
|
-
hook.command =
|
|
161
|
+
hook.command = node;
|
|
149
162
|
hook.args = [this.runner, agent];
|
|
150
163
|
} else {
|
|
151
|
-
hook.commandWindows = `powershell.exe ${powershellArgs(
|
|
164
|
+
hook.commandWindows = `powershell.exe ${powershellArgs(node, [this.runner, agent], true).join(' ')}`;
|
|
152
165
|
}
|
|
153
166
|
}
|
|
154
167
|
const existing = managedHook(entries);
|
|
@@ -169,15 +182,16 @@ export class HookManager {
|
|
|
169
182
|
dsh: { bundle: { patch: './cordis.patch.yml' } },
|
|
170
183
|
}, null, 2));
|
|
171
184
|
await writeAtomic(join(dir, 'cordis.patch.yml'), `- insert:\n - id: ${DSH_NAME}\n name: ${DSH_NAME}\n`);
|
|
172
|
-
await this.run(
|
|
185
|
+
await this.run('dsh', ['plugin', '--profile', this.profile, 'add', `link:${dir}`]);
|
|
173
186
|
}
|
|
174
187
|
if (!(await this.status(agent)).installed) throw new Error(`${LABELS[agent]} hook was not registered`);
|
|
175
188
|
}
|
|
176
189
|
|
|
177
190
|
async test(agent: Agent) {
|
|
178
191
|
if (!(await this.status(agent)).installed) throw new Error(`Install the ${LABELS[agent]} hook first.`);
|
|
192
|
+
const node = await this.nodePath();
|
|
179
193
|
await new Promise<void>((resolve, reject) => {
|
|
180
|
-
const child = spawn(
|
|
194
|
+
const child = spawn(node, [this.runner, agent], {
|
|
181
195
|
env: { ...process.env, ...this.env }, stdio: ['pipe', 'ignore', 'pipe'], timeout: 5000, windowsHide: true,
|
|
182
196
|
});
|
|
183
197
|
let error = '';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cortico-world-coding-agent-notify",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Coopanion World for short coding-agent completion notifications",
|
|
6
6
|
"license": "AGPL-3.0-or-later",
|
|
@@ -17,8 +17,7 @@
|
|
|
17
17
|
"tags": [
|
|
18
18
|
"apps",
|
|
19
19
|
"external-setup",
|
|
20
|
-
"experimental"
|
|
21
|
-
"sensitive-data"
|
|
20
|
+
"experimental"
|
|
22
21
|
],
|
|
23
22
|
"locales": {
|
|
24
23
|
"zh": {
|