@7n/rules 1.6.0 → 1.7.0
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 +6 -0
- package/package.json +1 -2
- package/scripts/docs/skills-cli.md +3 -3
- package/scripts/lib/acp-runner.mjs +23 -28
- package/scripts/skills-cli.mjs +35 -26
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.7.0] - 2026-07-16
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- `skill cursor/codex` тепер виконуються через `@7n/llm-lib/acp` (napi-міст до Rust `llm_cascade::acp`) замість власного JS ACP-клієнта; deprecated `skill claude` лишається окремим JS-шимом (`acp-runner.mjs`), бо Rust-крейт `claude` не моделює
|
|
8
|
+
|
|
3
9
|
## [1.6.0] - 2026-07-16
|
|
4
10
|
|
|
5
11
|
### Changed
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@7n/rules",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "CLI еталонних правил і skills (префікс n-): синк у репозиторій, дельта-lint, конформність",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -85,7 +85,6 @@
|
|
|
85
85
|
},
|
|
86
86
|
"optionalDependencies": {
|
|
87
87
|
"@agentclientprotocol/claude-agent-acp": "^0.59.0",
|
|
88
|
-
"@agentclientprotocol/codex-acp": "^1.1.2",
|
|
89
88
|
"@earendil-works/pi-ai": "0.80.2",
|
|
90
89
|
"@earendil-works/pi-coding-agent": "0.80.2"
|
|
91
90
|
},
|
|
@@ -3,7 +3,7 @@ type: JS Module
|
|
|
3
3
|
title: skills-cli.mjs
|
|
4
4
|
resource: npm/scripts/skills-cli.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
6
|
+
crc: 1a8f83e4
|
|
7
7
|
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -30,7 +30,7 @@ runSkillsCli виконує логіку командного інтерфейс
|
|
|
30
30
|
|
|
31
31
|
## Гарантії поведінки
|
|
32
32
|
|
|
33
|
-
- Сам модуль лише читає файли й збирає промпт; **виконання** делегується агенту: `pi` (вбудований, мутує дерево, запускає bash) або зовнішньому ACP-агенту `cursor`/`codex`/`claude` через `runAcpRunner` (`./lib/acp-runner.mjs`) — JSON-RPC поверх stdio (`cursor-agent acp`,
|
|
33
|
+
- Сам модуль лише читає файли й збирає промпт; **виконання** делегується агенту: `pi` (вбудований, мутує дерево, запускає bash) або зовнішньому ACP-агенту `cursor`/`codex`/`claude` через `runAcpRunner` (`./lib/acp-runner.mjs`) — JSON-RPC поверх stdio (`cursor-agent acp`, бандловані адаптери `@agentclientprotocol/codex-acp` і `@agentclientprotocol/claude-agent-acp`), а не сирий `stdin`/`stdout`-піпінг.
|
|
34
34
|
- Тира моделі для `pi`-runner береться з `main.json.tier` скіла (дефолт `max`).
|
|
35
|
-
- ACP-раннер
|
|
35
|
+
- ACP-раннер автоапрувляє `session/request_permission` (без інтерактивних питань) — паритет із колишнім non-interactive режимом; `Client`-реалізація читає/пише файли напряму через `node:fs`.
|
|
36
36
|
- Лише `claude` — deprecated: друкує попередження й лишається як fallback, доки не налаштовано pi-модель. `cursor`/`codex` — повноцінні раннери без попередження.
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* agentclientprotocol.com) — JSON-RPC поверх stdio
|
|
4
|
-
* `stdin`/`stdout`-передавання через pipe CLI.
|
|
2
|
+
* Deprecated JS ACP-шим для `skill claude` (Agent Client Protocol,
|
|
3
|
+
* agentclientprotocol.com) — JSON-RPC поверх stdio.
|
|
5
4
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* `cursor`/`codex` мігрували на `@7n/llm-lib/acp` (napi-міст до
|
|
6
|
+
* `llm_cascade::acp` — та сама протокольна логіка, але в Rust, без
|
|
7
|
+
* дублювання в JS). `claude` лишається тут як окремий JS-шим, бо Rust-крейт
|
|
8
|
+
* `AcpAgentKind` його не моделює (лише `Cursor`/`Codex`); підʼєднання йде
|
|
9
|
+
* через офіційний TS SDK `@zed-industries/agent-client-protocol`, а дозволи
|
|
10
|
+
* на tool-calls (`session/request_permission`) автоматично схвалюються без
|
|
11
|
+
* участі людини — паритет із колишнім non-interactive `-p`-режимом
|
|
12
|
+
* (full user-trust, без write-guard, як задокументовано в `@7n/llm-lib/agent-skill`).
|
|
11
13
|
*
|
|
12
|
-
* `
|
|
13
|
-
* `
|
|
14
|
-
* `@agentclientprotocol/claude-agent-acp`), що вбудовують свій рушій — зовнішній
|
|
15
|
-
* бінарник `codex`/`claude` у PATH більше не потрібен.
|
|
14
|
+
* `claude` — офіційний адаптер (`@agentclientprotocol/claude-agent-acp`), що
|
|
15
|
+
* вбудовує свій рушій — зовнішній бінарник `claude` у PATH не потрібен.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import { spawn } from 'node:child_process'
|
|
@@ -25,13 +25,11 @@ import { Readable, Writable } from 'node:stream'
|
|
|
25
25
|
const require = createRequire(import.meta.url)
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* Команда запуску ACP-агента на провайдер.
|
|
29
|
-
*
|
|
30
|
-
* @type {Record<'
|
|
28
|
+
* Команда запуску ACP-агента на провайдер. Резолвиться з `bin`-запису
|
|
29
|
+
* вбудованого npm-пакета-адаптера.
|
|
30
|
+
* @type {Record<'claude', { adapterPackage: string }>}
|
|
31
31
|
*/
|
|
32
32
|
export const ACP_AGENT_COMMANDS = {
|
|
33
|
-
cursor: { bin: 'cursor-agent', args: ['acp'] },
|
|
34
|
-
codex: { adapterPackage: '@agentclientprotocol/codex-acp' },
|
|
35
33
|
claude: { adapterPackage: '@agentclientprotocol/claude-agent-acp' }
|
|
36
34
|
}
|
|
37
35
|
|
|
@@ -46,7 +44,7 @@ export function stopReasonToExitCode(stopReason) {
|
|
|
46
44
|
|
|
47
45
|
/**
|
|
48
46
|
* Резолвить абсолютний шлях до bin-файлу вбудованого ACP-адаптера з його `package.json`.
|
|
49
|
-
* @param {string} adapterPackage назва npm-пакета адаптера (`@agentclientprotocol/
|
|
47
|
+
* @param {string} adapterPackage назва npm-пакета адаптера (`@agentclientprotocol/claude-agent-acp`)
|
|
50
48
|
* @returns {string} абсолютний шлях до виконуваного файлу адаптера
|
|
51
49
|
*/
|
|
52
50
|
export function resolveAdapterBin(adapterPackage) {
|
|
@@ -121,12 +119,13 @@ class AcpSkillClient {
|
|
|
121
119
|
}
|
|
122
120
|
|
|
123
121
|
/**
|
|
124
|
-
* Виконує скіл через зовнішнього ACP
|
|
125
|
-
*
|
|
122
|
+
* Виконує скіл через зовнішнього ACP-агента. Єдиний лишений провайдер —
|
|
123
|
+
* deprecated `claude` (`cursor`/`codex` — див. `@7n/llm-lib/acp`).
|
|
124
|
+
* @param {'claude'} kind провайдер
|
|
126
125
|
* @param {string} prompt готовий промпт скіла
|
|
127
126
|
* @param {string} projectDir робочий каталог сесії агента
|
|
128
127
|
* @param {(line: string) => void} logError вивід помилок
|
|
129
|
-
* @param {{ acp?: object, spawnFn?: typeof spawn, out?: (chunk: string) => void, resolveAdapterBin?: (pkg: string) => string
|
|
128
|
+
* @param {{ acp?: object, spawnFn?: typeof spawn, out?: (chunk: string) => void, resolveAdapterBin?: (pkg: string) => string }} [deps] інжекти для тестів
|
|
130
129
|
* @returns {Promise<number>} exit code (0 — `end_turn`, 1 — інакше)
|
|
131
130
|
*/
|
|
132
131
|
export async function runAcpRunner(kind, prompt, projectDir, logError, deps = {}) {
|
|
@@ -134,13 +133,9 @@ export async function runAcpRunner(kind, prompt, projectDir, logError, deps = {}
|
|
|
134
133
|
const out = deps.out ?? (chunk => stdout.write(chunk))
|
|
135
134
|
const resolveBin = deps.resolveAdapterBin ?? resolveAdapterBin
|
|
136
135
|
|
|
137
|
-
const
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if ('bin' in command && deps.isBinaryInPath && !deps.isBinaryInPath(command.bin)) {
|
|
142
|
-
throw new Error(`\`${command.bin}\` not found in PATH. Install ${kind} CLI (ACP mode) or use \`skill pi\`.`)
|
|
143
|
-
}
|
|
136
|
+
const { adapterPackage } = ACP_AGENT_COMMANDS[kind]
|
|
137
|
+
const bin = process.execPath
|
|
138
|
+
const args = [resolveBin(adapterPackage)]
|
|
144
139
|
|
|
145
140
|
const acp = deps.acp ?? (await import('@zed-industries/agent-client-protocol'))
|
|
146
141
|
const child = spawnFn(bin, args, { cwd: projectDir, stdio: ['pipe', 'pipe', 'inherit'], env: process.env })
|
package/scripts/skills-cli.mjs
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* Скіли читаються з `npm/skills/<id>/SKILL.md` установленого пакета (або кешу `npx`).
|
|
5
5
|
* Промпт збирає інструкцію скілу + контекст поточного CWD (`package.json`, `tsconfig.json`,
|
|
6
6
|
* `.n-rules.json`) — далі stdout або виконання через один з раннерів: вбудований
|
|
7
|
-
* pi-агент, чи зовнішній ACP
|
|
7
|
+
* pi-агент, чи зовнішній ACP-агент. `cursor`/`codex` — через `@7n/llm-lib/acp`
|
|
8
|
+
* (napi-міст до `llm_cascade::acp`, без власного JSON-RPC у JS); deprecated
|
|
9
|
+
* `claude` — окремий JS-шим (`./lib/acp-runner.mjs`), бо Rust-крейт його не моделює.
|
|
8
10
|
*
|
|
9
11
|
* Підтримувані формати:
|
|
10
12
|
* `npx \@7n/rules skill list`
|
|
@@ -12,14 +14,14 @@
|
|
|
12
14
|
* `npx \@7n/rules skill pi taze` — виконати через вбудований pi-агент (рекомендовано)
|
|
13
15
|
* `npx \@7n/rules skill pi taze "онови залежності"`
|
|
14
16
|
* `npx \@7n/rules skill cursor taze` — Cursor CLI через ACP (`cursor-agent acp`)
|
|
15
|
-
* `npx \@7n/rules skill codex taze` — Codex через ACP
|
|
17
|
+
* `npx \@7n/rules skill codex taze` — Codex через ACP (napi-міст `@7n/llm-lib/acp`, Rust спавнить `npx \@agentclientprotocol/codex-acp`)
|
|
16
18
|
* `npx \@7n/rules skill claude taze` — deprecated: Claude Code через ACP-адаптер
|
|
17
19
|
*/
|
|
18
20
|
|
|
19
|
-
import {
|
|
21
|
+
import { runAcpAgent } from '@7n/llm-lib/acp'
|
|
20
22
|
import { existsSync, readFileSync, readdirSync } from 'node:fs'
|
|
21
23
|
import { dirname, join } from 'node:path'
|
|
22
|
-
import { cwd } from 'node:process'
|
|
24
|
+
import { cwd, stdout } from 'node:process'
|
|
23
25
|
import { fileURLToPath } from 'node:url'
|
|
24
26
|
|
|
25
27
|
import { runAcpRunner } from './lib/acp-runner.mjs'
|
|
@@ -28,7 +30,11 @@ import { readSkillMetaRaw, skillTier } from './lib/skill-meta.mjs'
|
|
|
28
30
|
/** Виконавці скіла. `pi` — вбудований (рекомендований); `cursor`/`codex`/`claude` — зовнішні ACP-агенти (`claude` — deprecated). */
|
|
29
31
|
const RUNNERS = new Set(['pi', 'cursor', 'codex', 'claude'])
|
|
30
32
|
|
|
31
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* Раннери, що йдуть через зовнішнього ACP-агента, і чи deprecated (друкує попередження
|
|
35
|
+
* перед запуском). `cursor`/`codex` — napi-міст `@7n/llm-lib/acp`; `claude` — окремий
|
|
36
|
+
* JS-шим `runAcpRunner` (Rust-крейт `llm_cascade::acp` `claude` не моделює).
|
|
37
|
+
*/
|
|
32
38
|
const ACP_RUNNERS = {
|
|
33
39
|
claude: { deprecated: true },
|
|
34
40
|
cursor: { deprecated: false },
|
|
@@ -47,17 +53,6 @@ const USAGE_LINES = [
|
|
|
47
53
|
'Skill id: каталог у пакеті (lint, taze, …) або з префіксом n- (n-lint → lint).'
|
|
48
54
|
]
|
|
49
55
|
|
|
50
|
-
/**
|
|
51
|
-
* @param {string} name ім'я бінарника
|
|
52
|
-
* @returns {boolean} чи знайдено бінарник у PATH
|
|
53
|
-
*/
|
|
54
|
-
function isBinaryInPath(name) {
|
|
55
|
-
// Явний `env: process.env` — Bun без нього дає дітям snapshot оточення зі старту процесу
|
|
56
|
-
// і не бачить runtime-змін `process.env.PATH` (та сама причина, що в resolve-cmd.mjs).
|
|
57
|
-
const probe = spawnSync('command', ['-v', name], { shell: true, encoding: 'utf8', env: process.env })
|
|
58
|
-
return probe.status === 0
|
|
59
|
-
}
|
|
60
|
-
|
|
61
56
|
/**
|
|
62
57
|
* @param {string} name ім'я скілу з CLI або каталогу `.cursor/skills/n-*`
|
|
63
58
|
* @returns {string} id каталогу в `npm/skills/<id>/`
|
|
@@ -170,27 +165,41 @@ async function runPiRunner(prompt, rawSkillName, skillsRoot, projectDir, logErro
|
|
|
170
165
|
}
|
|
171
166
|
|
|
172
167
|
/**
|
|
173
|
-
* Делегує виконання скіла зовнішньому ACP
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
168
|
+
* Делегує виконання скіла зовнішньому ACP-агенту. `cursor`/`codex` — через
|
|
169
|
+
* `@7n/llm-lib/acp` (napi-міст до `llm_cascade::acp`: спавн, `session/prompt`,
|
|
170
|
+
* автоапрув дозволів — усе в Rust, без JSON-RPC у JS). `claude` — deprecated
|
|
171
|
+
* JS-шим `runAcpRunner` (Rust його не моделює); буде прибрано (мігруй на `skill pi`).
|
|
172
|
+
* На відміну від колишнього стрімінгу по чанках, napi-шлях повертає повний текст
|
|
173
|
+
* лише по завершенню ходу — Rust-функція не стрімить проміжні токени в JS.
|
|
178
174
|
* @param {'claude' | 'cursor' | 'codex'} kind якого ACP-агента запускати
|
|
179
175
|
* @param {string} prompt промпт скіла
|
|
180
176
|
* @param {string} projectDir робочий каталог агента
|
|
181
177
|
* @param {(line: string) => void} logError вивід попередження/помилок
|
|
182
|
-
* @param {{ runAcpRunner?: typeof runAcpRunner }} [deps]
|
|
183
|
-
* @returns {Promise<number>} exit code (0 —
|
|
178
|
+
* @param {{ runAcpRunner?: typeof runAcpRunner, runAcpAgent?: typeof runAcpAgent, out?: (chunk: string) => void }} [deps] інжекти для тестів
|
|
179
|
+
* @returns {Promise<number>} exit code (0 — успіх, 1 — інакше)
|
|
184
180
|
*/
|
|
185
|
-
function runLlmCli(kind, prompt, projectDir, logError, deps = {}) {
|
|
181
|
+
async function runLlmCli(kind, prompt, projectDir, logError, deps = {}) {
|
|
186
182
|
const runner = ACP_RUNNERS[kind]
|
|
187
|
-
const runAcp = deps.runAcpRunner ?? runAcpRunner
|
|
188
183
|
|
|
189
184
|
if (runner.deprecated) {
|
|
190
185
|
logError(`[deprecated] skill ${kind} → use 'skill pi'; зовнішній ACP-агент буде прибрано`)
|
|
191
186
|
}
|
|
192
187
|
|
|
193
|
-
|
|
188
|
+
if (kind === 'claude') {
|
|
189
|
+
const runAcp = deps.runAcpRunner ?? runAcpRunner
|
|
190
|
+
return runAcp(kind, prompt, projectDir, logError)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const runNativeAcp = deps.runAcpAgent ?? runAcpAgent
|
|
194
|
+
const out = deps.out ?? (chunk => stdout.write(chunk))
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
out(await runNativeAcp(kind, prompt, projectDir))
|
|
198
|
+
return 0
|
|
199
|
+
} catch (error) {
|
|
200
|
+
logError(error instanceof Error ? error.message : String(error))
|
|
201
|
+
return 1
|
|
202
|
+
}
|
|
194
203
|
}
|
|
195
204
|
|
|
196
205
|
/**
|