@movemama/opencode-legacy 1.0.0 → 1.0.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/README.md CHANGED
@@ -4,6 +4,25 @@ OpenCode legacy 文本处理插件,面向 `GB2312` 文本、脚本型 `.txt`
4
4
 
5
5
  当前主链路已经改为纯 JS 编码实现,不再依赖系统外部 `iconv.exe`。
6
6
 
7
+ ## 规则注入
8
+
9
+ 插件现在会在每轮对话自动读取并注入以下规则文件:
10
+
11
+ 1. 全局 `AGENTS.md`:根据当前环境变量 `USERPROFILE` 或 `HOME` 动态解析到 `~/.config/opencode/AGENTS.md`
12
+ 2. 项目 `AGENTS.md`:根据当前打开项目的 `worktree` 动态解析到 `<worktree>/AGENTS.md`
13
+
14
+ 注入后的硬规则会进入系统上下文,用于约束代理优先读取规则、完整读取目标文件、以及统一输出回执。
15
+
16
+ 另外,插件已为以下编辑类工具增加前置守卫:
17
+
18
+ - `edit`
19
+ - `write`
20
+ - `script-edit`
21
+ - `legacy_edit`
22
+ - `legacy_write`
23
+
24
+ 如果当前会话尚未完成 `AGENTS.md` 规则注入,上述工具会直接拒绝执行,以避免代理在未读取规则的情况下改文件。
25
+
7
26
  ## 安装
8
27
 
9
28
  在 OpenCode 配置中加入:
package/index.js CHANGED
@@ -4,18 +4,27 @@ import editTool from './tools/edit.js'
4
4
  import scriptEditTool from './tools/script-edit.js'
5
5
  import legacyStatusTool from './tools/legacy-status.js'
6
6
  import { edit as legacyEditTool, read as legacyReadTool, write as legacyWriteTool } from './tools/legacy.js'
7
+ import { createAgentsRuleHooks } from './tools/agents-rules.js'
7
8
 
8
- export const OpenCodeLegacyPlugin = async () => ({
9
- tool: {
10
- read: readTool,
11
- write: writeTool,
12
- edit: editTool,
13
- 'script-edit': scriptEditTool,
14
- legacy_read: legacyReadTool,
15
- legacy_write: legacyWriteTool,
16
- legacy_edit: legacyEditTool,
17
- legacy_status: legacyStatusTool,
18
- },
19
- })
9
+ export const OpenCodeLegacyPlugin = async (context, options = {}) => {
10
+ const agentsRuleHooks = createAgentsRuleHooks({
11
+ worktree: context.worktree,
12
+ globalAgentsPath: options.globalAgentsPath,
13
+ })
14
+
15
+ return {
16
+ tool: {
17
+ read: readTool,
18
+ write: writeTool,
19
+ edit: editTool,
20
+ 'script-edit': scriptEditTool,
21
+ legacy_read: legacyReadTool,
22
+ legacy_write: legacyWriteTool,
23
+ legacy_edit: legacyEditTool,
24
+ legacy_status: legacyStatusTool,
25
+ },
26
+ ...agentsRuleHooks,
27
+ }
28
+ }
20
29
 
21
30
  export default OpenCodeLegacyPlugin
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@movemama/opencode-legacy",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "OpenCode legacy text processing plugin for GB2312 and script-safe editing workflows.",
5
5
  "type": "module",
6
6
  "main": "./index.js",
package/plugin-meta.js CHANGED
@@ -10,5 +10,6 @@ export function getPluginMeta() {
10
10
  'legacy_write',
11
11
  'legacy_edit',
12
12
  ],
13
+ hookNames: ['experimental.chat.system.transform', 'tool.execute.before'],
13
14
  }
14
15
  }
@@ -0,0 +1,76 @@
1
+ import { existsSync, readFileSync } from 'node:fs'
2
+ import path from 'node:path'
3
+
4
+ const EDIT_GUARDED_TOOLS = new Set(['edit', 'write', 'script-edit', 'legacy_edit', 'legacy_write'])
5
+
6
+ function normalizeLineEndings(content) {
7
+ return content.replace(/\r\n/g, '\n').trim()
8
+ }
9
+
10
+ function getDefaultGlobalAgentsPath() {
11
+ const home = process.env.USERPROFILE || process.env.HOME || ''
12
+ return path.join(home, '.config', 'opencode', 'AGENTS.md')
13
+ }
14
+
15
+ function readAgentsFileIfExists(filePath) {
16
+ if (!filePath || !existsSync(filePath)) {
17
+ return null
18
+ }
19
+
20
+ return normalizeLineEndings(readFileSync(filePath, 'utf8'))
21
+ }
22
+
23
+ function buildInjectedRulesBlock(entries) {
24
+ const sections = entries
25
+ .filter((entry) => entry.content)
26
+ .map((entry) => [`## ${entry.label}`, entry.content].join('\n'))
27
+
28
+ return [
29
+ '[AGENTS Rules Bootstrap]',
30
+ '你必须在本轮严格遵守以下规则优先级:系统 > 开发者 > 全局 AGENTS.md > 项目 AGENTS.md > 用户临时偏好。',
31
+ '硬性要求:分析或编辑前先读取规则与目标文件完整内容;文件过长时连续分段读取;上下文不足前不得做结构判断或编辑判断。',
32
+ '硬性要求:所有用户可见输出必须使用简体中文;受限时必须说明受限原因、影响范围、备选方案;回复末尾必须输出规则执行回执。',
33
+ ...sections,
34
+ ].join('\n\n')
35
+ }
36
+
37
+ export function createAgentsRuleHooks(input = {}) {
38
+ const globalAgentsPath = input.globalAgentsPath || getDefaultGlobalAgentsPath()
39
+ const projectAgentsPath = path.join(input.worktree, 'AGENTS.md')
40
+ const sessionBootstrapState = new Set()
41
+
42
+ function loadRules() {
43
+ return [
44
+ {
45
+ label: 'Global AGENTS.md',
46
+ path: globalAgentsPath,
47
+ content: readAgentsFileIfExists(globalAgentsPath),
48
+ },
49
+ {
50
+ label: 'Project AGENTS.md',
51
+ path: projectAgentsPath,
52
+ content: readAgentsFileIfExists(projectAgentsPath),
53
+ },
54
+ ]
55
+ }
56
+
57
+ return {
58
+ 'experimental.chat.system.transform': async (hookInput, output) => {
59
+ const entries = loadRules()
60
+ const injected = buildInjectedRulesBlock(entries)
61
+ output.system.push(injected)
62
+ if (hookInput?.sessionID) {
63
+ sessionBootstrapState.add(hookInput.sessionID)
64
+ }
65
+ },
66
+ 'tool.execute.before': async (hookInput) => {
67
+ if (!EDIT_GUARDED_TOOLS.has(hookInput.tool)) {
68
+ return
69
+ }
70
+
71
+ if (!sessionBootstrapState.has(hookInput.sessionID)) {
72
+ throw new Error('当前会话尚未完成 AGENTS.md 规则注入,已禁止编辑类工具执行。请先让插件读取全局与项目 AGENTS.md。')
73
+ }
74
+ },
75
+ }
76
+ }