@mrpan12345/verx 2.0.0-rc.2 → 2.0.0-rc.3

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.
Files changed (27) hide show
  1. package/README.md +11 -5
  2. package/node_modules/tree-sitter/binding.gyp +12 -4
  3. package/node_modules/tree-sitter/index.js +60 -26
  4. package/node_modules/tree-sitter/package.json +14 -14
  5. package/node_modules/tree-sitter/prebuilds/darwin-arm64/tree-sitter.node +0 -0
  6. package/node_modules/tree-sitter/prebuilds/darwin-x64/tree-sitter.node +0 -0
  7. package/node_modules/tree-sitter/prebuilds/linux-arm64/tree-sitter.node +0 -0
  8. package/node_modules/tree-sitter/prebuilds/linux-x64/tree-sitter.node +0 -0
  9. package/node_modules/tree-sitter/prebuilds/win32-arm64/tree-sitter.node +0 -0
  10. package/node_modules/tree-sitter/prebuilds/win32-x64/tree-sitter.node +0 -0
  11. package/node_modules/tree-sitter/src/language.cc +3 -4
  12. package/node_modules/tree-sitter/src/node.cc +1 -1
  13. package/node_modules/tree-sitter/src/parser.cc +36 -10
  14. package/node_modules/tree-sitter/src/query.cc +29 -1
  15. package/node_modules/tree-sitter/tree-sitter.d.ts +93 -52
  16. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/get_changed_ranges.c +6 -6
  17. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/language.c +1 -1
  18. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/parser.c +33 -29
  19. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/portable/endian.h +3 -1
  20. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/query.c +161 -164
  21. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/stack.c +33 -32
  22. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/subtree.c +7 -7
  23. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/tree_cursor.c +12 -13
  24. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm/stdlib.c +26 -2
  25. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm_store.c +8 -6
  26. package/package.json +2 -2
  27. package/verx.mjs +420 -84
package/README.md CHANGED
@@ -4,6 +4,10 @@
4
4
 
5
5
  TTY 工作时间线保留工具、审批、验证结果及过程说明,最终回复不会擦除执行证据;推理临时面板仍在正文出现时收起。运行状态显示步骤、工具成功/失败数和当前上下文估算(不是累计计费用量),最终用量以会话汇总为准。工具参数流式碎片不触发状态栏重绘。`exec` 即使连接 TTY 也不询问首次遥测偏好。
6
6
 
7
+ P1-08 工作过程呈现:状态动画每 120ms 原地换帧,显示当前模型请求/工具执行耗时;审批、预算和计划对话框、正文输出时让出终端,结束或取消订阅后释放定时器。窗口宽度变化时重新量宽,非 TTY/`TERM=dumb` 不启动动画。动画只表示活动中,不虚构完成百分比。
8
+
9
+ TTY 收到 `file.changed` 后通过 core 的只读文件历史接口展示**本次**前后快照,而非重复累计差异:绿色 `+` 表示新增,红色 `-` 表示删除,未改动内容作为上下文。禁用颜色时仍保留符号。单次预览最多显示 18 行内容和一行折叠提示;大文件或复杂对比提示使用 `verx diff`,不会无限刷屏。快照先脱敏再分行,预览失败仅显示安全提示、不改变已完成写操作的结果。NDJSON 保持既定事件,不附加差异正文。
10
+
7
11
  Verx is a local-first, model-agnostic terminal coding agent.
8
12
 
9
13
  ```bash
@@ -11,15 +15,16 @@ npm install --global @mrpan12345/verx@next --registry=https://registry.npmjs.org
11
15
  verx --version
12
16
  ```
13
17
 
14
- The `next` channel distributes `2.0.0-rc.2`, a release candidate, not a GA release. Gate 4 remains NO-GO. The current
18
+ The `next` channel distributes `2.0.0-rc.3`, a release candidate, not a GA release. Gate 4 remains NO-GO. The current
15
19
  known limitation is that MiniMax-M3 can still select a non-approved verification command in
16
20
  non-interactive mode; the permission engine rejects that command without executing it. This
17
21
  candidate has release-install validation only on macOS arm64. Cross-platform execution, the
18
22
  14-day Beta, and independent signoffs remain unverified under the Owner-approved RC waiver.
19
23
 
20
- The npm channel requires Node.js 22.23 or newer. The package bundles the audited `tree-sitter@0.25.0`
21
- source with the upstream Node 22+ C++ standard fix, so Node 24 does not fall back to the published
22
- C++17 build. npm-managed installations are upgraded with
24
+ The npm channel requires Node.js 22.23 or newer. The package bundles `tree-sitter@0.25.1` and its
25
+ prebuilt native runtimes for macOS, Debian 12-compatible glibc Linux, and Windows x64/ARM64. These supported
26
+ targets do not need a local compiler for tree-sitter; Windows prebuilds avoid Visual Studio C++
27
+ Build Tools. Linux musl/Alpine is not covered by these prebuilds. npm-managed installations are upgraded with
23
28
  `npm install --global @mrpan12345/verx@next --registry=https://registry.npmjs.org`; `verx upgrade` is reserved for the signed
24
29
  standalone binary.
25
30
 
@@ -35,6 +40,7 @@ atomically renamed into place.
35
40
  Repository build commands:
36
41
 
37
42
  ```bash
43
+ pnpm build:linux-prebuilds # Docker required; rebuild after native dependency upgrades
38
44
  pnpm package:npm
39
45
  pnpm package:sea
40
46
  ```
@@ -65,7 +71,7 @@ TTY 启动时展示紧凑横幅:状态点 + 版本,随后是模型、服务
65
71
  上下文。NDJSON 仍按协议原样输出 `model.streamed` 事件,供程序化消费者
66
72
  处理。TTY 会把标题、强调、行内代码、列表和代码围栏渲染为紧凑终端样式,不直接暴露 Markdown
67
73
  标记,并压缩连续空行。同一轮的前导文字、工具、审批、计划与验证时间线在执行期间实时可见;
68
- 下一段正文开始时会统一收起该临时区域,只保留正文和终态摘要。没有正文的失败或取消保留过程,便于诊断。
74
+ 下一段正文开始时仅收起推理临时面板,工具、审批、文件差异与验证时间线继续保留,便于审查和诊断。
69
75
 
70
76
  时间线按层级组织:一次工具调用只占一行 `● tool(args)`,其结果、审批结论与文件变更作为从属行
71
77
  挂在其下(`⎿` gutter),交互式下不再重复打印工具名。文件变更的增删数、验证失败与错误码按语义
@@ -61,13 +61,21 @@
61
61
  "vendor/tree-sitter/lib/src",
62
62
  "vendor/tree-sitter/lib/include",
63
63
  ],
64
- "cflags": [
65
- "-std=c11"
66
- ],
67
64
  "defines": [
68
65
  "_POSIX_C_SOURCE=200112L",
69
66
  "_DEFAULT_SOURCE",
70
- ]
67
+ ],
68
+ "conditions": [
69
+ ["OS!='win'", {
70
+ "cflags_c": [
71
+ "-std=c11",
72
+ ],
73
+ }, { # OS == "win"
74
+ "cflags_c": [
75
+ "/std:c11",
76
+ ],
77
+ }],
78
+ ],
71
79
  }
72
80
  ],
73
81
  "variables": {
@@ -18,10 +18,10 @@ Object.defineProperty(Tree.prototype, 'rootNode', {
18
18
  Due to a race condition arising from Jest's worker pool, "this"
19
19
  has no knowledge of the native extension if the extension has not
20
20
  yet loaded when multiple Jest tests are being run simultaneously.
21
- If the extension has correctly loaded, "this" should be an instance
21
+ If the extension has correctly loaded, "this" should be an instance
22
22
  of the class whose prototype we are acting on (in this case, Tree).
23
- Furthermore, the race condition sometimes results in the function in
24
- question being undefined even when the context is correct, so we also
23
+ Furthermore, the race condition sometimes results in the function in
24
+ question being undefined even when the context is correct, so we also
25
25
  perform a null function check.
26
26
  */
27
27
  if (this instanceof Tree && rootNode) {
@@ -61,7 +61,10 @@ Tree.prototype.walk = function() {
61
61
 
62
62
  class SyntaxNode {
63
63
  constructor(tree) {
64
- this.tree = tree;
64
+ Object.defineProperty(this, 'tree', {
65
+ value: tree,
66
+ enumerable: true
67
+ });
65
68
  }
66
69
 
67
70
  [util.inspect.custom]() {
@@ -239,6 +242,15 @@ class SyntaxNode {
239
242
  return NodeMethods.toString(this.tree);
240
243
  }
241
244
 
245
+ toJSON() {
246
+ return {
247
+ type: this.type,
248
+ startPosition: this.startPosition,
249
+ endPosition: this.endPosition,
250
+ childCount: this.childCount,
251
+ }
252
+ }
253
+
242
254
  child(index) {
243
255
  marshalNode(this);
244
256
  return unmarshalNode(NodeMethods.child(this.tree, index), this.tree);
@@ -361,7 +373,7 @@ Parser.prototype.getLanguage = function(_language) {
361
373
  return this[languageSymbol] || null;
362
374
  };
363
375
 
364
- Parser.prototype.parse = function(input, oldTree, {bufferSize, includedRanges}={}) {
376
+ Parser.prototype.parse = function(input, oldTree, {bufferSize, includedRanges, progressCallback}={}) {
365
377
  let getText, treeInput = input
366
378
  if (typeof input === 'string') {
367
379
  const inputString = input;
@@ -377,6 +389,7 @@ Parser.prototype.parse = function(input, oldTree, {bufferSize, includedRanges}={
377
389
  oldTree,
378
390
  bufferSize,
379
391
  includedRanges,
392
+ progressCallback,
380
393
  )
381
394
  : undefined;
382
395
 
@@ -684,13 +697,13 @@ Query.prototype.captures = function(
684
697
  matchLimit = 0xFFFFFFFF,
685
698
  maxStartDepth = 0xFFFFFFFF,
686
699
  timeoutMicros = 0,
700
+ progressCallback = undefined,
687
701
  } = {}
688
702
  ) {
689
703
  marshalNode(node);
690
704
  const [returnedMatches, returnedNodes] = _captures.call(this, node.tree,
691
- startPosition.row, startPosition.column,
692
- endPosition.row, endPosition.column,
693
- startIndex, endIndex, matchLimit, maxStartDepth, timeoutMicros
705
+ startPosition.row, startPosition.column, endPosition.row, endPosition.column,
706
+ startIndex, endIndex, matchLimit, maxStartDepth, timeoutMicros, progressCallback
694
707
  );
695
708
  const nodes = unmarshalNodes(returnedNodes, node.tree);
696
709
  const results = [];
@@ -855,7 +868,8 @@ function initializeLanguageNodeClasses(language) {
855
868
  const nodeTypeInfo = language.nodeTypeInfo || [];
856
869
 
857
870
  const nodeSubclasses = [];
858
- for (let id = 0, n = nodeTypeNamesById.length; id < n; id++) {
871
+
872
+ for (let id = 0, n = nodeTypeNamesById.length; id < n; ++id) {
859
873
  nodeSubclasses[id] = SyntaxNode;
860
874
 
861
875
  const typeName = nodeTypeNamesById[id];
@@ -865,7 +879,8 @@ function initializeLanguageNodeClasses(language) {
865
879
  if (!typeInfo) continue;
866
880
 
867
881
  const fieldNames = [];
868
- let classBody = '\n';
882
+ const fieldGetters = {};
883
+
869
884
  if (typeInfo.fields) {
870
885
  for (const fieldName in typeInfo.fields) {
871
886
  const fieldId = nodeFieldNamesById.indexOf(fieldName);
@@ -873,35 +888,54 @@ function initializeLanguageNodeClasses(language) {
873
888
  if (typeInfo.fields[fieldName].multiple) {
874
889
  const getterName = camelCase(fieldName) + 'Nodes';
875
890
  fieldNames.push(getterName);
876
- classBody += `
877
- get ${getterName}() {
891
+ fieldGetters[getterName] = {
892
+ get: function () {
878
893
  marshalNode(this);
879
- return unmarshalNodes(NodeMethods.childNodesForFieldId(this.tree, ${fieldId}), this.tree);
880
- }
881
- `.replace(/\s+/g, ' ') + '\n';
894
+ return unmarshalNodes(
895
+ NodeMethods.childNodesForFieldId(this.tree, fieldId),
896
+ this.tree
897
+ );
898
+ },
899
+ enumerable: true
900
+ };
882
901
  } else {
883
902
  const getterName = camelCase(fieldName, false) + 'Node';
884
903
  fieldNames.push(getterName);
885
- classBody += `
886
- get ${getterName}() {
904
+ fieldGetters[getterName] = {
905
+ get: function () {
887
906
  marshalNode(this);
888
- return unmarshalNode(NodeMethods.childNodeForFieldId(this.tree, ${fieldId}), this.tree);
889
- }
890
- `.replace(/\s+/g, ' ') + '\n';
907
+ return unmarshalNode(
908
+ NodeMethods.childNodeForFieldId(this.tree, fieldId),
909
+ this.tree
910
+ );
911
+ },
912
+ enumerable: true
913
+ };
891
914
  }
892
915
  }
893
916
  }
894
917
 
895
- const className = camelCase(typeName, true) + 'Node';
896
- const nodeSubclass = eval(`class ${className} extends SyntaxNode {${classBody}}; ${className}`);
897
- nodeSubclass.prototype.type = typeName;
898
- nodeSubclass.prototype.fields = Object.freeze(fieldNames.sort())
899
- nodeSubclasses[id] = nodeSubclass;
918
+ nodeSubclasses[id] = new Function('SyntaxNode', `
919
+ return class ${camelCase(typeName, true)}Node extends SyntaxNode {}
920
+ `)(SyntaxNode);
921
+
922
+ Object.defineProperties(nodeSubclasses[id].prototype, {
923
+ type: {
924
+ value: typeName,
925
+ enumerable: true
926
+ },
927
+ fields: {
928
+ value: Object.freeze(fieldNames.sort()),
929
+ enumerable: true
930
+ },
931
+ ...fieldGetters
932
+ });
900
933
  }
901
934
 
902
- language.nodeSubclasses = nodeSubclasses
935
+ language.nodeSubclasses = nodeSubclasses;
903
936
  }
904
937
 
938
+
905
939
  function camelCase(name, upperCase) {
906
940
  name = name.replace(/_(\w)/g, (_match, letter) => letter.toUpperCase());
907
941
  if (upperCase) name = name[0].toUpperCase() + name.slice(1);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tree-sitter",
3
- "version": "0.25.0",
3
+ "version": "0.25.1",
4
4
  "description": "Node.js bindings to the Tree-sitter parsing library",
5
5
  "repository": "http://github.com/tree-sitter/node-tree-sitter",
6
6
  "publishConfig": {
@@ -43,28 +43,28 @@
43
43
  "vendor/tree-sitter/lib/src/*"
44
44
  ],
45
45
  "dependencies": {
46
- "node-addon-api": "^8.3.0",
46
+ "node-addon-api": "^8.5.0",
47
47
  "node-gyp-build": "^4.8.4"
48
48
  },
49
49
  "devDependencies": {
50
- "@types/node": "^22.10.2",
50
+ "@types/node": "^25.0.3",
51
51
  "@types/tmp": "^0.2.6",
52
- "glob": "^11.0.0",
53
- "node-gyp": "^11.0.0",
52
+ "glob": "^13.0.0",
53
+ "node-gyp": "^12.1.0",
54
54
  "prebuildify": "^6.0.1",
55
- "tmp": "^0.2.3",
56
- "tree-sitter-c": "^0.23.4",
57
- "tree-sitter-embedded-template": "^0.23.2",
55
+ "tmp": "^0.2.5",
56
+ "tree-sitter-c": "^0.24.1",
57
+ "tree-sitter-embedded-template": "^0.25.0",
58
58
  "tree-sitter-html": "^0.23.2",
59
59
  "tree-sitter-java": "^0.23.5",
60
- "tree-sitter-javascript": "^0.23.1",
60
+ "tree-sitter-javascript": "^0.25.0",
61
61
  "tree-sitter-json": "^0.24.8",
62
- "tree-sitter-python": "^0.23.6",
62
+ "tree-sitter-python": "^0.25.0",
63
63
  "tree-sitter-ruby": "^0.23.1",
64
- "tree-sitter-rust": "^0.23.2",
65
- "typedoc": "^0.27.6",
66
- "typedoc-plugin-rename-defaults": "^0.7.2",
67
- "typescript": "^5.7.2"
64
+ "tree-sitter-rust": "^0.24.0",
65
+ "typedoc": "^0.28.15",
66
+ "typedoc-plugin-rename-defaults": "^0.7.3",
67
+ "typescript": "^5.9.3"
68
68
  },
69
69
  "scripts": {
70
70
  "docs": "typedoc --out docs/api tree-sitter.d.ts --readme README.md",
@@ -30,7 +30,7 @@ const TSLanguage *UnwrapLanguage(Napi::Value value) {
30
30
  if (arg.IsExternal() && arg.CheckTypeTag(&LANGUAGE_TYPE_TAG)) {
31
31
  const TSLanguage *language = arg.Data();
32
32
  if (language != nullptr) {
33
- uint16_t version = ts_language_version(language);
33
+ uint16_t version = ts_language_abi_version(language);
34
34
  if (
35
35
  version < TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION ||
36
36
  version > TREE_SITTER_LANGUAGE_VERSION
@@ -39,9 +39,8 @@ const TSLanguage *UnwrapLanguage(Napi::Value value) {
39
39
  "Incompatible language version. Compatible range: " +
40
40
  std::to_string(TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION) + " - " +
41
41
  std::to_string(TREE_SITTER_LANGUAGE_VERSION) + ". Got: " +
42
- std::to_string(ts_language_version(language));
43
- RangeError::New(env, message.c_str());
44
- return nullptr;
42
+ std::to_string(ts_language_abi_version(language));
43
+ throw RangeError::New(env, message.c_str());
45
44
  }
46
45
  return language;
47
46
  }
@@ -793,7 +793,7 @@ Napi::Value ChildWithDescendant(const Napi::CallbackInfo &info) {
793
793
  const Tree *child_tree = Tree::UnwrapTree(info[1]);
794
794
  TSNode child_node = UnmarshalNode(env, child_tree, 1);
795
795
  if (self.id != nullptr && child_node.id != nullptr) {
796
- return MarshalNode(info, tree, ts_node_child_with_descendant(self, child_node));
796
+ return MarshalNode(info, tree, ts_node_child_with_descendant(self, child_node));
797
797
  }
798
798
  return MarshalNullNode(env);
799
799
  }
@@ -109,6 +109,29 @@ class CallbackInput final {
109
109
  ObjectReference partial_string;
110
110
  };
111
111
 
112
+ class CallbackProgress final {
113
+ public:
114
+ static TSParseOptions Make(const Napi::Function &func) {
115
+ TSParseOptions options;
116
+ auto *callback = new CallbackProgress();
117
+ callback->func = Napi::Persistent(func);
118
+ options.payload = static_cast<void *>(callback);
119
+ options.progress_callback = Cancel;
120
+ return options;
121
+ }
122
+
123
+ private:
124
+ Napi::FunctionReference func;
125
+
126
+ static bool Cancel(TSParseState *state) {
127
+ auto *callback = static_cast<CallbackProgress *>(state->payload);
128
+ Env env = callback->func.Env();
129
+ Number index = Number::New(env, state->current_byte_offset);
130
+ Boolean has_error = Boolean::New(env, state->has_error);
131
+ return callback->func({ index, has_error }).As<Boolean>();
132
+ }
133
+ };
134
+
112
135
  void Parser::Init(Napi::Env env, Napi::Object exports) {
113
136
  auto *data = env.GetInstanceData<AddonData>();
114
137
 
@@ -203,19 +226,22 @@ Napi::Value Parser::Parse(const CallbackInfo &info) {
203
226
  old_tree = tree->tree_;
204
227
  }
205
228
 
206
- Napi::Value buffer_size = env.Null();
207
- if (info.Length() > 2) {
208
- buffer_size = info[2];
209
- }
229
+ CallbackInput callback_input(callback, info.Length() > 2 ? info[2] : env.Null());
210
230
 
211
- if (!handle_included_ranges(env, parser_, info[3])) {
212
- return env.Undefined();
231
+ if (info.Length() > 3) {
232
+ if (!handle_included_ranges(env, parser_, info[3])) {
233
+ return env.Undefined();
234
+ }
213
235
  }
214
236
 
215
- CallbackInput callback_input(callback, buffer_size);
216
- TSTree *tree = ts_parser_parse(parser_, old_tree, callback_input.Input());
217
- Napi::Value result = Tree::NewInstance(env, tree);
218
- return result;
237
+ TSTree *tree;
238
+ if (info.Length() > 4 && info[4].IsFunction()) {
239
+ TSParseOptions options = CallbackProgress::Make(info[4].As<Function>());
240
+ tree = ts_parser_parse_with_options(parser_, old_tree, callback_input.Input(), options);
241
+ } else {
242
+ tree = ts_parser_parse(parser_, old_tree, callback_input.Input());
243
+ }
244
+ return Tree::NewInstance(env, tree);
219
245
  }
220
246
 
221
247
  Napi::Value Parser::IncludedRanges(const Napi::CallbackInfo &info) {
@@ -31,6 +31,29 @@ const char *query_error_names[] = {
31
31
  "TSQueryErrorStructure",
32
32
  };
33
33
 
34
+ class CallbackProgress final {
35
+ public:
36
+ static TSQueryCursorOptions Make(const Napi::Function &func) {
37
+ TSQueryCursorOptions options;
38
+ auto *callback = new CallbackProgress();
39
+ callback->func = Napi::Persistent(func);
40
+ options.payload = static_cast<void *>(callback);
41
+ options.progress_callback = Cancel;
42
+ return options;
43
+ }
44
+
45
+ private:
46
+ Napi::FunctionReference func;
47
+
48
+ static bool Cancel(TSQueryCursorState *state) {
49
+ auto *callback = static_cast<CallbackProgress *>(state->payload);
50
+ Env env = callback->func.Env();
51
+ Number index = Number::New(env, state->current_byte_offset);
52
+ return callback->func({ index }).As<Boolean>();
53
+ }
54
+ };
55
+
56
+
34
57
  void Query::Init(Napi::Env env, Napi::Object exports) {
35
58
  auto *data = env.GetInstanceData<AddonData>();
36
59
  data->ts_query_cursor = ts_query_cursor_new();
@@ -219,7 +242,12 @@ Napi::Value Query::Matches(const Napi::CallbackInfo &info) {
219
242
  ts_query_cursor_set_match_limit(data->ts_query_cursor, match_limit);
220
243
  ts_query_cursor_set_max_start_depth(data->ts_query_cursor, max_start_depth);
221
244
  ts_query_cursor_set_timeout_micros(data->ts_query_cursor, timeout_micros);
222
- ts_query_cursor_exec(data->ts_query_cursor, ts_query, root_node);
245
+ if (info.Length() > 10 && info[10].IsFunction()) {
246
+ TSQueryCursorOptions options = CallbackProgress::Make(info[10].As<Function>());
247
+ ts_query_cursor_exec_with_options(data->ts_query_cursor, ts_query, root_node, &options);
248
+ } else {
249
+ ts_query_cursor_exec(data->ts_query_cursor, ts_query, root_node);
250
+ }
223
251
 
224
252
  Array js_matches = Array::New(env);
225
253
  unsigned index = 0;