aura-basetools 0.13.3 → 0.15.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/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # aura-basetools 0.13.3
1
+ # aura-basetools 0.15.0
2
2
 
3
- Byte-exact file tools for coding agents: read by intent, edit by intent, and write whole files without corrupting bytes. One engine shared by a standalone CLI and an MCP server.
3
+ Byte-exact file tools for coding agents: read by intent, edit by address, and write whole files without corrupting bytes. One engine shared by a standalone CLI and an MCP server.
4
4
 
5
- 面向 coding agent 的逐字节文件工具:按意图读取、按意图编辑、整文件写入;CLI 与 MCP 共用同一套引擎。
5
+ 面向 coding agent 的逐字节文件工具:按意图读取、按地址编辑、整文件写入;CLI 与 MCP 共用同一套引擎。
6
6
 
7
7
  ---
8
8
 
@@ -21,7 +21,7 @@ The engine is intentionally not a general file manager: it reads and edits UTF-8
21
21
  ### Install
22
22
 
23
23
  ```bash
24
- npm i -g aura-basetools@0.13.3
24
+ npm i -g aura-basetools@0.15.0
25
25
  aura --version
26
26
  ```
27
27
 
@@ -31,8 +31,6 @@ aura --version
31
31
  aura basetools read --file src/app.ts --mode map
32
32
  aura basetools edit --file src/app.ts --hunks '[{"target":"main","replace":"..."}]'
33
33
  aura basetools write --file generated.ts --content @body.ts
34
- aura basetools undo
35
- aura basetools transactions
36
34
  aura basetools mcp
37
35
  ```
38
36
 
@@ -77,10 +75,10 @@ The server exposes:
77
75
  | Tool | Purpose |
78
76
  |---|---|
79
77
  | `aura_basetools_read` | Intent-based views: `map`, `digest`, `full`, `around`, `lines`, `search`, `changed`, `auto` |
80
- | `aura_basetools_edit` | Anchored multi-hunk edits; `old` + `replace_all`; optional transaction |
78
+ | `aura_basetools_edit` | Anchored multi-hunk edits; `old` + `replace_all` |
81
79
  | `aura_basetools_write` | Whole-file create/overwrite with read-before-write and read-back verification |
82
- | `aura_basetools_undo` | Undo the latest or a named write transaction |
83
- | `aura_basetools_transactions` | List write transactions for the current workspace |
80
+
81
+ 0.14.0 removed the public `undo` / `transactions` tools (0 uses in 642 sessions); failure rollback remains internal and automatic.
84
82
 
85
83
  The older tool names (`aura_read`, `aura_edit`, `aura_write`, ...) are no longer exposed by MCP or DSH.
86
84
 
@@ -92,6 +90,7 @@ Compared with the DSH built-in `dsh-tool-fs` tools, the differences are delibera
92
90
  - **Read by intent, not whole file.** `map` / `digest` / `lines` / `search` return the structural slice you ask for; the customer comparison measured about 1/24 of the context for the same file.
93
91
  - **Edits refuse stale bases.** A region-level gate rejects an edit when the addressed region changed after the read that authorized it, and points at the lines to re-read; `expect` makes the intended text explicit.
94
92
  - **Writes are verified, not assumed.** Every write goes through a temp file, flush, rename, and a byte-for-byte read-back; multi-target edits plan first and write nothing if any target fails.
93
+ - **Changes can prove themselves.** `edit` / `write` accept an explicit `verify` command; a non-zero exit or timeout rolls the transaction back and returns the command output plus the rollback state. No auto-discovery of repo scripts.
95
94
  - **Addressing is structural.** `target` / `lines` / `old` / `expect` / handles replace "copy the literal text exactly"; failure receipts include ready-to-use retry addresses.
96
95
  - **The core is DSH-free.** `aura-basetools` has no runtime dependencies and no DSH imports; the DSH adapter is a separate optional package.
97
96
 
@@ -128,7 +127,7 @@ MIT.
128
127
  `aura-basetools` 是一个 Node.js(>=18)包,运行时零依赖,提供:
129
128
 
130
129
  - **CLI**:`aura basetools <verb>`
131
- - **MCP 服务**:stdio 上的五个工具
130
+ - **MCP 服务**:stdio 上的三个工具
132
131
  - **不依赖 DSH**:DeepSeek Harness 适配器是独立的可选包 `aura-basetools-dsh`
133
132
 
134
133
  它不是通用文件管理器:只处理 UTF-8 文本,保留字节级格式;如果被寻址区域在“授权读取”之后被改动,编辑会被拒绝。
@@ -136,7 +135,7 @@ MIT.
136
135
  ### 安装
137
136
 
138
137
  ```bash
139
- npm i -g aura-basetools@0.13.3
138
+ npm i -g aura-basetools@0.15.0
140
139
  aura --version
141
140
  ```
142
141
 
@@ -146,8 +145,6 @@ aura --version
146
145
  aura basetools read --file src/app.ts --mode map
147
146
  aura basetools edit --file src/app.ts --hunks '[{"target":"main","replace":"..."}]'
148
147
  aura basetools write --file generated.ts --content @body.ts
149
- aura basetools undo
150
- aura basetools transactions
151
148
  aura basetools mcp
152
149
  ```
153
150
 
@@ -192,10 +189,10 @@ npx -y --package aura-basetools aura basetools mcp
192
189
  | 工具 | 作用 |
193
190
  |---|---|
194
191
  | `aura_basetools_read` | `map` / `digest` / `full` / `around` / `lines` / `search` / `changed` / `auto` |
195
- | `aura_basetools_edit` | 多 hunk 锚点编辑;`old` + `replace_all`;可选事务 |
192
+ | `aura_basetools_edit` | 多 hunk 锚点编辑;`old` + `replace_all` |
196
193
  | `aura_basetools_write` | 整文件新建/覆写;覆写默认要求先读,写后回读校验 |
197
- | `aura_basetools_undo` | 撤销最近一次或指定写事务 |
198
- | `aura_basetools_transactions` | 列出当前工作区写事务 |
194
+
195
+ 0.14.0 移除了公开 `undo` / `transactions`(642 个会话中 0 次使用);失败回滚仍是内部自动行为。
199
196
 
200
197
  旧工具名(`aura_read`、`aura_edit`、`aura_write` 等)不再由 MCP/DSH 暴露。
201
198
 
@@ -207,6 +204,7 @@ npx -y --package aura-basetools aura basetools mcp
207
204
  - **按意图读,不读整份。** `map` / `digest` / `lines` / `search` 只返回你要的结构切片;客户版对照实测同一文件上下文约 1/24。
208
205
  - **依据过期就拒绝。** 区域级陈旧闸门在“授权读取之后该区域被改过”时拒绝,并指出重读哪几行;`expect` 让目标原文显式化。
209
206
  - **写完要验,不靠相信。** 每次写盘走临时文件、flush、rename,再做逐字节回读;多目标先全量规划,任一失败则一个字节都不写。
207
+ - **变更可以自证。** `edit` / `write` 接受显式 `verify` 命令;非零退出或超时会把整个事务回滚,回执带命令输出与回滚状态。不自动发现仓库脚本。
210
208
  - **寻址是结构化的。** `target` / `lines` / `old` / `expect` / 句柄替代“把原文一字不差抄对”;失败回执带可直接用的重试地址。
211
209
  - **核心不依赖 DSH。** `aura-basetools` 零运行时依赖、无 DSH import;DSH 适配器是独立可选包。
212
210
 
package/bin/aura-mcp.mjs CHANGED
@@ -5,12 +5,10 @@
5
5
  * 为什么是它:Codex / Claude Code / Cursor / Zed 这些 agent 都吃 MCP —— 一次写壳,到处能用,
6
6
  * 且**不要求对方装 DSH**(本文件只依赖 node:fs 与本包的引擎)。
7
7
  *
8
- * 暴露五个工具:
8
+ * 暴露三个工具:
9
9
  * aura_basetools_read 七种取景(map/digest/full/around/lines/search/changed)+ 版本令牌
10
10
  * aura_basetools_edit 四层寻址 + expect + dry_run;逐字节写回 + 陈旧区域闸门 + 落盘后回读校验
11
- * aura_basetools_write 整份写入(对应内置 Write):新建或整文件替换,同走事务与回读校验
12
- * aura_basetools_undo 撤销最近一次/指定写事务(默认拒绝覆盖后续编辑)
13
- * aura_basetools_transactions 列出当前工作区写事务
11
+ * aura_basetools_write 整份写入(对应内置 Write):新建或整文件替换,同走原子写与回读校验
14
12
  *
15
13
  * 接法(写进各家的 MCP 配置即可):
16
14
  * codex: codex mcp add aura -- npx -y --package aura-basetools aura basetools mcp
@@ -21,9 +19,9 @@
21
19
  * `aura-basetools`;npx 在"多个 bin 且没有与包名同名的"时候会拒绝猜,直接报
22
20
  * `could not determine executable to run`(实测)。`--package` 明确指定包,`aura` 才是命令。
23
21
  */
24
- import { readFileSync } from 'node:fs'
22
+ import { readFileSync, realpathSync } from 'node:fs'
25
23
  import process from 'node:process'
26
- import { pathToFileURL } from 'node:url'
24
+ import { fileURLToPath, pathToFileURL } from 'node:url'
27
25
  import {
28
26
  openProvider,
29
27
  readEnvelope,
@@ -32,8 +30,6 @@ import {
32
30
  // 多目标(fs-contract-v2)的引擎绑定:与单目标同一处(`lib/ops.mjs`),bin 里不另找引擎。
33
31
  readManyWith,
34
32
  editManyEnvelope,
35
- undoEnvelope,
36
- transactionsEnvelope,
37
33
  assertReadTargets,
38
34
  assertEditTargets,
39
35
  assertTargetShape,
@@ -81,11 +77,6 @@ const HUNK_SCHEMA = {
81
77
  type: 'object',
82
78
  properties: {
83
79
  target: { type: 'string', description: '符号名,如 `toTodoList` 或 `function:apply`;跳过全部文本匹配' },
84
- intent: {
85
- type: 'string',
86
- description:
87
- '模糊意图地址:符号名片段、短语或近似原文(如 `parseConfig`、`config loader`、`// retry the upload`),由引擎确定性地落成一个精确区间;歧义时报候选并拒绝(不猜)。单独使用(不与 target/lines/line_cue/anchor/old/context/handle 同用);可用 near 与 expect',
88
- },
89
80
  lines: {
90
81
  oneOf: [
91
82
  { type: 'array' },
@@ -137,7 +128,7 @@ const HUNK_SCHEMA = {
137
128
  replace_all: {
138
129
  type: 'boolean',
139
130
  description:
140
- '与 old 同用:替换全部非重叠出现(从左到右),不再要求唯一。不能与 target/intent/lines/line_cue/anchor/context/handle/near 同用;读取后出现次数变了会整体拒绝。',
131
+ '与 old 同用:替换全部非重叠出现(从左到右),不再要求唯一。不能与 target/lines/line_cue/anchor/context/handle/near 同用;读取后出现次数变了会整体拒绝。',
141
132
  },
142
133
  eol: {
143
134
  type: 'string',
@@ -198,18 +189,21 @@ const TOOLS = [
198
189
  {
199
190
  name: 'aura_basetools_edit',
200
191
  description:
201
- 'Edit or create a UTF-8 text file with hunks in one call. Address each hunk by intent (fuzzy name/phrase), target (symbol), lines, line_cue, anchor, or old (verbatim content + optional context). With `old`, set `replace_all: true` to replace every non-overlapping occurrence. Writes back byte-for-byte (BOM and per-line endings preserved), refuses a hunk whose addressed region changed since your last read, and reads the file back to verify. All hunks must locate or nothing is written.',
192
+ 'Edit or create a UTF-8 text file with hunks in one call. Address each hunk by target (symbol), lines, line_cue, anchor, or old (verbatim content + optional context). With `old`, set `replace_all: true` to replace every non-overlapping occurrence. Writes back byte-for-byte (BOM and per-line endings preserved), refuses a hunk whose addressed region changed since your last read, and reads the file back to verify. All hunks must locate or nothing is written.',
202
193
  inputSchema: {
203
194
  type: 'object',
204
195
  properties: {
205
196
  file_path: { type: 'string' },
206
197
  hunks: { type: 'array', items: HUNK_SCHEMA },
207
198
  dry_run: { type: 'boolean', description: '只定位不落盘' },
208
- include_transaction: { type: 'boolean', description: '在回执里返回 transaction id(默认不返回,保持输出稳定)' },
209
199
  require_observation: {
210
200
  type: 'boolean',
211
201
  description: '严格新鲜度:要求这一版文件在本会话里被读过(或由本工具写过);否则 PATCH_UNOBSERVED。create 不受影响;dry_run 同样执行这条判决。',
212
202
  },
203
+ verify: {
204
+ type: 'string',
205
+ description: '写后验证命令(显式给出才执行;在 workspace 根下、受超时/输出上限约束)。非零退出 ⇒ 自动回滚并返回 PATCH_VERIFY_FAILED。不自动发现/执行仓库脚本。',
206
+ },
213
207
  create: { type: 'string', description: '文件不存在时用它创建(整份内容)' },
214
208
  targets: TARGETS_SCHEMA,
215
209
  },
@@ -230,7 +224,7 @@ const TOOLS = [
230
224
  {
231
225
  name: 'aura_basetools_write',
232
226
  description:
233
- 'Write a whole UTF-8 text file at once (create or overwrite), matching a plain Write tool. Preserves an existing file\'s BOM and line endings, goes through the same transaction/undo path as aura_basetools_edit, and reads the file back to verify bytes. Prefer aura_basetools_edit for partial changes.',
227
+ 'Write a whole UTF-8 text file at once (create or overwrite), matching a plain Write tool. Preserves an existing file\'s BOM and line endings, goes through the same atomic write path as aura_basetools_edit, and reads the file back to verify bytes. Prefer aura_basetools_edit for partial changes.',
234
228
  inputSchema: {
235
229
  type: 'object',
236
230
  properties: {
@@ -247,28 +241,14 @@ const TOOLS = [
247
241
  enum: ['auto', 'preserve', 'lf', 'crlf'],
248
242
  description: '覆写时的换行风格:auto(默认)适配文件已有风格;preserve 按 content 原样写;lf/crlf 强制。新建文件始终按 content 原样写(非 auto 会被拒绝)。',
249
243
  },
250
- include_transaction: { type: 'boolean', description: '在回执里返回 transaction id(默认不返回)' },
244
+ verify: {
245
+ type: 'string',
246
+ description: '写后验证命令(显式给出才执行;非零退出 ⇒ 自动回滚并返回 PATCH_VERIFY_FAILED)。',
247
+ },
251
248
  },
252
249
  required: ['file_path', 'content'],
253
250
  },
254
251
  },
255
- {
256
- name: 'aura_basetools_undo',
257
- description:
258
- 'Undo the latest committed write transaction, or the transaction with the given id. Refuses if a file changed after the transaction; pass force=true to override. Restores the exact bytes captured before the write.',
259
- inputSchema: {
260
- type: 'object',
261
- properties: {
262
- id: { type: 'string', description: '事务 id;省略则撤销最近一条 committed 事务' },
263
- force: { type: 'boolean', description: '即使文件在事务后又被改过也强制恢复' },
264
- },
265
- },
266
- },
267
- {
268
- name: 'aura_basetools_transactions',
269
- description: 'List write transactions for the current workspace (id, status, file count, time).',
270
- inputSchema: { type: 'object', properties: {} },
271
- },
272
252
  ]
273
253
 
274
254
  /**
@@ -351,8 +331,8 @@ async function editTargetsCall(provider, args) {
351
331
  return await editManyEnvelope(provider, {
352
332
  targets,
353
333
  dryRun: args.dry_run === true,
354
- includeTransaction: args.include_transaction === true,
355
334
  ...(args.require_observation === true ? { requireObservation: true } : {}),
335
+ ...(typeof args.verify === 'string' ? { verify: args.verify } : {}),
356
336
  })
357
337
  }
358
338
 
@@ -436,8 +416,8 @@ async function callTool(provider, name, args = {}) {
436
416
  hunks: Array.isArray(args.hunks) ? args.hunks : [],
437
417
  dryRun: args.dry_run === true,
438
418
  create: creating ? args.create : undefined,
439
- includeTransaction: args.include_transaction === true,
440
419
  ...(args.require_observation === true ? { requireObservation: true } : {}),
420
+ ...(typeof args.verify === 'string' ? { verify: args.verify } : {}),
441
421
  })
442
422
  }
443
423
  if (name === 'aura_basetools_write') {
@@ -446,13 +426,11 @@ async function callTool(provider, name, args = {}) {
446
426
  content: args.content,
447
427
  dryRun: args.dry_run === true,
448
428
  noOverwrite: args.no_overwrite === true,
449
- includeTransaction: args.include_transaction === true,
450
429
  allowUnobserved: args.allow_unobserved === true,
451
430
  ...(typeof args.eol === 'string' ? { eol: args.eol } : {}),
431
+ ...(typeof args.verify === 'string' ? { verify: args.verify } : {}),
452
432
  })
453
433
  }
454
- if (name === 'aura_basetools_undo') return await undoEnvelope(provider, { id: args.id, force: args.force === true })
455
- if (name === 'aura_basetools_transactions') return transactionsEnvelope(provider)
456
434
  return { ok: false, error: `unknown tool ${JSON.stringify(name)}`, code: 'UNKNOWN_TOOL' }
457
435
  }
458
436
 
@@ -561,6 +539,25 @@ export async function serve() {
561
539
 
562
540
  // 直接运行本文件(`aura-mcp`,package.json 里声明的第二个 bin)也要起服务,与 `aura basetools mcp` 等价。
563
541
  // 用 pathToFileURL 比手拼 file:// 靠得住(Windows 盘符就是那种手拼会踩的地方)。
564
- if (process.argv[1] !== undefined && import.meta.url === pathToFileURL(process.argv[1]).href) {
542
+ /**
543
+ * 直接执行本文件才起 stdio 服务。
544
+ *
545
+ * 不能只比 `import.meta.url === pathToFileURL(argv[1])`:macOS 的临时目录
546
+ * `/var/folders/...` 是 `/private/var/folders/...` 的符号链接,Node 给模块的 URL 与
547
+ * argv 的写法可能一侧已 realpath、另一侧没有 ⇒ 服务静默退出,客户端看到 0 个工具
548
+ * (post-publish / split-package 在 macOS 上正是这条)。两边都过 realpath 再比。
549
+ */
550
+ function isDirectRun() {
551
+ const invoked = process.argv[1]
552
+ if (invoked === undefined) return false
553
+ if (import.meta.url === pathToFileURL(invoked).href) return true
554
+ try {
555
+ return realpathSync.native(fileURLToPath(import.meta.url)) === realpathSync.native(invoked)
556
+ } catch {
557
+ return false
558
+ }
559
+ }
560
+
561
+ if (isDirectRun()) {
565
562
  await serve()
566
563
  }
package/bin/aura.mjs CHANGED
@@ -3,11 +3,9 @@
3
3
  * aura CLI(薄壳):参数解析 → `lib/ops.mjs` → 一行 JSON。
4
4
  *
5
5
  * aura basetools read --file F [--mode …] [--around X] [--lines a,b] [--search S] [--since V] [--max-chars N]
6
- * aura basetools edit --file F (--hunks '<json>' | --hunks-file P) [--dry-run] [--create <文本|@文件>]
6
+ * aura basetools edit --file F (--hunks '<json>' | --hunks-file P) [--dry-run] [--verify "命令"] [--create <文本|@文件>]
7
7
  * aura basetools read --targets '[...]|@spec.json' 一次读多个目标(与 --file 互斥)
8
8
  * aura basetools edit --targets '[...]|@spec.json' 一次改多个文件(与 --file 互斥;任一规划失败 ⇒ 零写入)
9
- * aura basetools undo [--id <事务 id>] [--force] 撤销最近一次/指定写事务
10
- * aura basetools transactions 列出当前工作区写事务
11
9
  * aura basetools mcp
12
10
  * aura --help | --version
13
11
  *
@@ -27,8 +25,6 @@ import {
27
25
  // 多目标(fs-contract-v2)的引擎绑定:与单目标同一处(`lib/ops.mjs`),bin 里不另找引擎。
28
26
  readManyWith,
29
27
  editManyEnvelope,
30
- undoEnvelope,
31
- transactionsEnvelope,
32
28
  capabilitiesEnvelope,
33
29
  writeEnvelope,
34
30
  assertReadTargets,
@@ -74,7 +70,7 @@ let command = argv[0]
74
70
  * 有了这份名单,“下一个是已知布尔旗标”才当没带值,**其它以 `--` 开头的东西都当值**。
75
71
  * 代价是名单要维护;收益是那个静默丢值的路径从根上消失,而不是靠叫用户改写法。
76
72
  */
77
- const BOOLEAN_FLAGS = new Set(['pretty', 'dry-run', 'plan', 'transaction', 'force', 'no-overwrite', 'replace-all', 'require-observation', 'allow-unobserved', 'json'])
73
+ const BOOLEAN_FLAGS = new Set(['pretty', 'dry-run', 'plan', 'no-overwrite', 'replace-all', 'require-observation', 'allow-unobserved', 'json'])
78
74
  const isBooleanFlag = (token) => typeof token === 'string' && BOOLEAN_FLAGS.has(token.replace(/^--/, ''))
79
75
 
80
76
  /**
@@ -90,15 +86,13 @@ const COMMAND_FLAGS = {
90
86
  bool: ['pretty'],
91
87
  },
92
88
  edit: {
93
- value: ['cwd', 'file', 'targets', 'hunks', 'hunks-file', 'create', 'target', 'intent', 'lines', 'start-line', 'end-line', 'line-cue', 'anchor', 'old', 'context', 'handle', 'line', 'position', 'replace', 'expect', 'near', 'eol'],
94
- bool: ['pretty', 'dry-run', 'plan', 'transaction', 'replace-all', 'require-observation'],
89
+ value: ['cwd', 'file', 'targets', 'hunks', 'hunks-file', 'create', 'target', 'lines', 'start-line', 'end-line', 'line-cue', 'anchor', 'old', 'context', 'handle', 'line', 'position', 'replace', 'expect', 'near', 'eol', 'verify'],
90
+ bool: ['pretty', 'dry-run', 'plan', 'replace-all', 'require-observation'],
95
91
  },
96
92
  write: {
97
- value: ['cwd', 'file', 'content', 'eol'],
98
- bool: ['pretty', 'dry-run', 'plan', 'transaction', 'no-overwrite', 'allow-unobserved'],
93
+ value: ['cwd', 'file', 'content', 'eol', 'verify'],
94
+ bool: ['pretty', 'dry-run', 'plan', 'no-overwrite', 'allow-unobserved'],
99
95
  },
100
- undo: { value: ['cwd', 'id'], bool: ['pretty', 'force'] },
101
- transactions: { value: ['cwd'], bool: ['pretty'] },
102
96
  doctor: { value: ['cwd'], bool: ['pretty', 'json'] },
103
97
  capabilities: { value: ['cwd'], bool: ['pretty'] },
104
98
  mcp: { value: ['cwd'], bool: ['pretty'] },
@@ -172,25 +166,25 @@ const USAGE = [
172
166
  // `--file` 指向**目录**时直接给一张仓库地图(模块/目录/依赖方向),不需要额外旗标。
173
167
  ' (--file 传目录 ⇒ 仓库地图:模块清单 + 目录骨架 + 被依赖最多的模块 + 入口点)',
174
168
  ' aura basetools read --targets <json|@文件> # 一次读多个目标(≤32 项;与 --file 互斥)',
175
- ' aura basetools edit --targets <json|@文件> [--dry-run|--plan] # 一次改多个文件(先全量规划,任一失败则零写入)',
169
+ ' aura basetools edit --targets <json|@文件> [--dry-run|--plan] [--verify "命令"] # 一次改多个文件(先全量规划,任一失败则零写入)',
176
170
  " aura basetools edit --file <路径> --create <内容|@文件> # 建文件(不必再给 --hunks)",
177
- " aura basetools edit --file <路径> (--hunks '<json>' | --hunks-file <路径>) [--dry-run|--plan] [--eol auto|preserve|lf|crlf] [--require-observation]",
171
+ " aura basetools edit --file <路径> (--hunks '<json>' | --hunks-file <路径>) [--dry-run|--plan] [--verify \"命令\"] [--eol auto|preserve|lf|crlf] [--require-observation]",
178
172
  ' aura basetools edit --file <路径> --lines <a,b> --replace <文本> [--expect <文本>] [--near <n>]',
179
173
  ' aura basetools edit --file <路径> --old <原文> --replace <文本> --replace-all # 改全部非重叠出现',
180
- " (只改一处时不必包成 JSON:--target / --intent / --lines / --start-line+--end-line / --line-cue / --anchor 任选其一)",
174
+ " (只改一处时不必包成 JSON:--target / --lines / --start-line+--end-line / --line-cue / --anchor 任选其一)",
181
175
  // 句柄(fs-contract-v2 §5):读侧发的柄 + 三种定位写法。下面三行是三种**用法**,不是三种键。
182
176
  ' aura basetools edit --file <路径> --handle <h…> --replace <文本> # 整段替换:区间由柄定,不靠转述',
183
177
  ' aura basetools edit --file <路径> --handle <h…> --line <段内行号> --replace <文本> # 只换区间内第 k 行(1-based,从区间首行数起)',
184
178
  ' aura basetools edit --file <路径> --handle <h…> --position before|after --replace <文本> # 在区间边界插入,区间本身不动',
185
179
  " (--line / --position 是从属键:只有与 --handle 同时给才成立,单独给不构成一次编辑)",
186
180
  ' aura basetools mcp 启动 MCP stdio 服务',
187
- ' aura basetools write --file <路径> --content <文本|@文件> [--no-overwrite] [--dry-run|--plan] [--transaction] [--allow-unobserved] [--eol auto|preserve|lf|crlf]',
181
+ ' aura basetools write --file <路径> --content <文本|@文件> [--no-overwrite] [--dry-run|--plan] [--verify "命令"] [--allow-unobserved] [--eol auto|preserve|lf|crlf]',
188
182
  ' (覆写默认要求先读过这一版;--allow-unobserved 才允许盲写)',
189
183
  ' aura basetools doctor [--json] 自检:Node/版本/MCP 握手/缓存与锁目录可写',
190
184
  ' aura basetools capabilities [--pretty] 能力清单:读模式/地址档/语言/限制(JSON)',
191
185
  ' aura --help | --version',
192
186
  '',
193
- 'hunks 形状:[{"target":"符号名"|"intent":"模糊意图(符号片段/短语/近似原文)"|"lines":[a,b]|"line_cue":"唯一词"|"anchor":"记得的原文",',
187
+ 'hunks 形状:[{"target":"符号名"|"lines":[a,b]|"line_cue":"唯一词"|"anchor":"记得的原文",',
194
188
  ' "replace":"替换文本","expect":"该处应是什么","near":行号}]',
195
189
  '',
196
190
  '例:',
@@ -311,7 +305,7 @@ if (command === '--version' || command === '-v') emit({ ok: true, version: VERSI
311
305
  * 旧顶层动词只给**迁移提示**,不再作为别名执行——保留别名等于保留未来的撞名。
312
306
  * 只提示、不执行:`aura basetools read` 不会偷偷改文件。
313
307
  */
314
- const MOVED_COMMANDS = new Set(['read', 'outline', 'edit', 'write', 'undo', 'transactions', 'mcp', 'doctor', 'capabilities'])
308
+ const MOVED_COMMANDS = new Set(['read', 'outline', 'edit', 'write', 'mcp', 'doctor', 'capabilities'])
315
309
  if (!namespaced && MOVED_COMMANDS.has(command)) {
316
310
  emit(
317
311
  {
@@ -356,26 +350,13 @@ if (command === 'write') {
356
350
  content,
357
351
  dryRun: has('dry-run') || has('plan'),
358
352
  noOverwrite: has('no-overwrite'),
359
- includeTransaction: has('transaction'),
360
353
  allowUnobserved: has('allow-unobserved'),
361
354
  ...(typeof eol === 'string' ? { eol } : {}),
355
+ ...(typeof flag('verify') === 'string' ? { verify: flag('verify') } : {}),
362
356
  })
363
357
  emit(env, env.ok ? 0 : 2)
364
358
  }
365
359
 
366
- if (command === 'undo') {
367
- const env = await undoEnvelope(provider, {
368
- id: typeof flag('id') === 'string' ? flag('id') : undefined,
369
- force: has('force'),
370
- })
371
- emit(env, env.ok ? 0 : 2)
372
- }
373
-
374
- if (command === 'transactions') {
375
- const env = transactionsEnvelope(provider)
376
- emit(env, 0)
377
- }
378
-
379
360
  if (command === 'doctor') {
380
361
  /**
381
362
  * `aura basetools doctor`:把“装完能不能用”的机械检查放在 CLI 自己身上。
@@ -492,8 +473,8 @@ if (command === 'edit') {
492
473
  const env = await editManyEnvelope(provider, {
493
474
  targets: spec.targets,
494
475
  dryRun: has('dry-run') || has('plan') || spec.dryRun,
495
- includeTransaction: has('transaction'),
496
476
  ...(has('require-observation') ? { requireObservation: true } : {}),
477
+ ...(typeof flag('verify') === 'string' ? { verify: flag('verify') } : {}),
497
478
  })
498
479
  emit(env, env.ok ? 0 : 2)
499
480
  }
@@ -509,8 +490,6 @@ if (command === 'edit') {
509
490
  */
510
491
  const flat = flatHunk({
511
492
  target: flag('target'),
512
- // 意图地址(T16):`--intent 'config loader'` 一句话定位一处改动,不要求符号全名或原文。
513
- intent: flag('intent'),
514
493
  lines: flag('lines'),
515
494
  start_line: flag('start-line'),
516
495
  end_line: flag('end-line'),
@@ -593,7 +572,7 @@ if (command === 'edit') {
593
572
  {
594
573
  ok: false,
595
574
  error:
596
- 'edit 需要 --hunks/--hunks-file,或平铺一组地址旗标(--target / --intent / --lines / --start-line+--end-line / --line-cue / --anchor / --handle(配 --line 或 --position),外加 --replace),或 --create <整份内容>',
575
+ 'edit 需要 --hunks/--hunks-file,或平铺一组地址旗标(--target / --lines / --start-line+--end-line / --line-cue / --anchor / --handle(配 --line 或 --position),外加 --replace),或 --create <整份内容>',
597
576
  code: 'USAGE',
598
577
  },
599
578
  1,
@@ -607,8 +586,8 @@ if (command === 'edit') {
607
586
  hunks: hunks ?? [],
608
587
  dryRun: has('dry-run') || has('plan'),
609
588
  create,
610
- includeTransaction: has('transaction'),
611
589
  ...(has('require-observation') ? { requireObservation: true } : {}),
590
+ ...(typeof flag('verify') === 'string' ? { verify: flag('verify') } : {}),
612
591
  })
613
592
  emit(env, env.ok ? 0 : 2)
614
593
  }