deepseek-coordination 0.12.0 → 0.13.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
@@ -4,7 +4,7 @@
4
4
 
5
5
  A dual-face Cordis plugin for DeepSeek Harness: the host half owns a coordination SQLite database, seven model-facing tools and an HTTP surface; the web half mounts five composer dropdowns, a settings catalog and the service-level takeover dialog.
6
6
 
7
- **Status: v0.12.0 (2026-10-18).** This release adds a domain-concept layer split by ecosystem — tex, book, markdown, html, five programming languages, maven/npm and Office — plus a `kind` filter on the chain query, a directory layer, and the canonical `NodeRecord`. It builds on v0.11.0 (durable settings, DSH-owned reasoning, experimental cache proxy). The package version, changelog and release tarball are the same tree; claims below were checked against source, not against the design documents alone.
7
+ **Status: v0.13.0 (2026-10-18).** This release makes `interface`, `type`, `enumeration` and `namespace` first-class declaration kinds across TypeScript, Java, Rust and PHP. It adds a domain-concept layer split by ecosystem — tex, book, markdown, html, five programming languages, maven/npm and Office — plus a `kind` filter on the chain query, a directory layer, and the canonical `NodeRecord`. It builds on v0.11.0 (durable settings, DSH-owned reasoning, experimental cache proxy). The package version, changelog and release tarball are the same tree; claims below were checked against source, not against the design documents alone.
8
8
 
9
9
  | Status | Meaning in this README |
10
10
  |---|---|
@@ -60,7 +60,7 @@ Install the packed tarball, not the GitHub source:
60
60
 
61
61
  ```powershell
62
62
  npm pack
63
- dsh plugin --profile <name> add .\deepseek-coordination-0.12.0.tgz
63
+ dsh plugin --profile <name> add .\deepseek-coordination-0.13.0.tgz
64
64
  dsh --profile <name> --dump-config # expect a deepseek-coordination layer
65
65
  ```
66
66
 
@@ -198,12 +198,12 @@ The file layer is not one parser with a bag of node kinds. Each system owns a mo
198
198
  | book | `book.ts` | `book`, `part`, `chapter`, `article`, `section`, `person`, `venue` — the only producer of `article` |
199
199
  | markdown | `markup.ts` | `document`, `chapter`, `heading`, `paragraph`, `div`, `link`, `code`, `section`, `sheet`, `cell`, `range`, `condition` |
200
200
  | html | `markup.ts` | `document`, `section` (`<article>` maps here), `chapter` (`<h1>`), `link`, `code` |
201
- | js/ts | `javascript.ts` | `class`, `function`, `method`, `variable`, `interface`, `type`, `enum`, `namespace`, `importation`, `exportation`, `condition` |
202
- | java | `java.ts` | `module`, `class`, `method`, `variable`, `importation` |
201
+ | js/ts | `javascript.ts` | `class`, `function`, `method`, `variable`, `interface`, `type`, `enumeration`, `namespace`, `importation`, `exportation`, `condition` |
202
+ | java | `java.ts` | `module`, `class`, `interface`, `enumeration`, `method`, `variable`, `importation` |
203
203
  | python | `python.ts` | `class`, `function`, `method`, `variable`, `importation` |
204
204
  | c/c++ | `c-family.ts` | `module`, `class`, `function`, `method`, `variable`, `importation` |
205
- | rust | `rust.ts` | `module`, `class`, `function`, `method`, `variable`, `importation` |
206
- | php | `php.ts` | `module`, `class`, `function`, `method`, `variable`, `importation` |
205
+ | rust | `rust.ts` | `module`, `class`, `enumeration`, `function`, `method`, `variable`, `importation` |
206
+ | php | `php.ts` | `module`, `class`, `interface`, `enumeration`, `function`, `method`, `variable`, `importation` |
207
207
  | maven | `maven.ts` | `project`, `module`, `dependency` (parent is a dependency with `label: 'parent'`) |
208
208
  | npm | `npm.ts` | `project`, `dependency`, `script` (the command body is never stored) |
209
209
  | office | `office.ts` | docx: `document`, `chapter`, `section`, `paragraph`, `link`; xlsx: `workbook`, `sheet`, `range`, `formula`; pptx: `document`, `slide`; pub/accdb: no nodes, one `unsupported-format` diagnostic |
package/README.zh-CN.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  一个面向 DeepSeek Harness 的双端 Cordis 插件:宿主端持有协调 SQLite 数据库、7 个模型可见工具和一组 HTTP 路由;浏览器端在输入框挂载五个下拉框,并提供设置目录与服务级接管对话框。
6
6
 
7
- **当前版本:v0.12.0(2026-10-18)。** 本版新增按体系拆分的领域概念层——tex、book、markdown、html、五种编程语言、maven/npm 与 Office——并为 chain 查询加上 `kind` 过滤、加入目录层与规范 `NodeRecord`。它建立在 v0.11.0(持久设置、推理交还 DSH、实验性缓存代理)之上。包版本、更新日志和发布 tarball 来自同一棵树;下文按源码核对,不以设计文档代替实现。
7
+ **当前版本:v0.13.0(2026-10-18)。** 本版让 `interface`、`type`、`enumeration`、`namespace` 成为 TypeScript、Java、Rust、PHP 的一等声明 kind,并新增按体系拆分的领域概念层——tex、book、markdown、html、五种编程语言、maven/npm 与 Office——并为 chain 查询加上 `kind` 过滤、加入目录层与规范 `NodeRecord`。它建立在 v0.11.0(持久设置、推理交还 DSH、实验性缓存代理)之上。包版本、更新日志和发布 tarball 来自同一棵树;下文按源码核对,不以设计文档代替实现。
8
8
 
9
9
  | 状态 | 含义 |
10
10
  |---|---|
@@ -198,12 +198,12 @@ deepseek-coordination/
198
198
  | book | `book.ts` | `book`、`part`、`chapter`、`article`、`section`、`person`、`venue`——`article` 的唯一产出者 |
199
199
  | markdown | `markup.ts` | `document`、`chapter`、`heading`、`paragraph`、`div`、`link`、`code`、`section`、`sheet`、`cell`、`range`、`condition` |
200
200
  | html | `markup.ts` | `document`、`section`(`<article>` 映射于此)、`chapter`(`<h1>`)、`link`、`code` |
201
- | js/ts | `javascript.ts` | `class`、`function`、`method`、`variable`、`interface`、`type`、`enum`、`namespace`、`importation`、`exportation`、`condition` |
202
- | java | `java.ts` | `module`、`class`、`method`、`variable`、`importation` |
201
+ | js/ts | `javascript.ts` | `class`、`function`、`method`、`variable`、`interface`、`type`、`enumeration`、`namespace`、`importation`、`exportation`、`condition` |
202
+ | java | `java.ts` | `module`、`class`、`interface`、`enumeration`、`method`、`variable`、`importation` |
203
203
  | python | `python.ts` | `class`、`function`、`method`、`variable`、`importation` |
204
204
  | c/c++ | `c-family.ts` | `module`、`class`、`function`、`method`、`variable`、`importation` |
205
- | rust | `rust.ts` | `module`、`class`、`function`、`method`、`variable`、`importation` |
206
- | php | `php.ts` | `module`、`class`、`function`、`method`、`variable`、`importation` |
205
+ | rust | `rust.ts` | `module`、`class`、`enumeration`、`function`、`method`、`variable`、`importation` |
206
+ | php | `php.ts` | `module`、`class`、`interface`、`enumeration`、`function`、`method`、`variable`、`importation` |
207
207
  | maven | `maven.ts` | `project`、`module`、`dependency`(parent 是 `label: 'parent'` 的 dependency) |
208
208
  | npm | `npm.ts` | `project`、`dependency`、`script`(命令体永不入库) |
209
209
  | office | `office.ts` | docx:`document`、`chapter`、`section`、`paragraph`、`link`;xlsx:`workbook`、`sheet`、`range`、`formula`;pptx:`document`、`slide`;pub/accdb:无节点,只出一条 `unsupported-format` 诊断 |
package/lib/index.mjs CHANGED
@@ -23765,9 +23765,8 @@ function handleFunction(ctx, sig, position, symbols, exported, newline, scope, r
23765
23765
  return endPosition + 1;
23766
23766
  }
23767
23767
  /**
23768
- * TypeScript `interface`. `NodeKind` has no `interface` spelling, so the
23769
- * closest existing kind (`class`, a named member-bearing type declaration) is
23770
- * used and the binding is the type name (`identifier`).
23768
+ * TypeScript `interface`. The symbol kind is `interface`; the binding is the
23769
+ * type name (`identifier`).
23771
23770
  */
23772
23771
  function handleInterface(ctx, sig, position, symbols, exported, scope) {
23773
23772
  const nameToken = sig[position + 1];
@@ -23781,15 +23780,14 @@ function handleInterface(ctx, sig, position, symbols, exported, scope) {
23781
23780
  const endPosition = close < 0 ? open : close;
23782
23781
  if (close < 0) ctx.unverifiable("unterminated interface body", sig[open].token.span);
23783
23782
  const span = spanBetween(sig[declarationStartPosition(sig, position)].token, sig[endPosition].token);
23784
- symbols.push(newSymbol("class", nameToken.token.text, span, declarationStart(sig, position), sig[endPosition].index, exported.has(position), {
23783
+ symbols.push(newSymbol("interface", nameToken.token.text, span, declarationStart(sig, position), sig[endPosition].index, exported.has(position), {
23785
23784
  scope,
23786
23785
  binding: "identifier"
23787
23786
  }));
23788
23787
  return endPosition + 1;
23789
23788
  }
23790
23789
  /**
23791
- * TypeScript `type` alias. `NodeKind` has no `type` spelling; `definition` is
23792
- * the closest existing kind for a named type/value definition.
23790
+ * TypeScript `type` alias. The symbol kind is `type`.
23793
23791
  */
23794
23792
  function handleTypeAlias(ctx, sig, position, symbols, exported, newline, scope) {
23795
23793
  const nameToken = sig[position + 1];
@@ -23803,15 +23801,14 @@ function handleTypeAlias(ctx, sig, position, symbols, exported, newline, scope)
23803
23801
  if (sig[cursor]?.token.text !== "=") return position + 1;
23804
23802
  const endPosition = typeAliasEnd(sig, cursor + 1, newline);
23805
23803
  const span = spanBetween(sig[declarationStartPosition(sig, position)].token, sig[endPosition].token);
23806
- symbols.push(newSymbol("definition", nameToken.token.text, span, declarationStart(sig, position), sig[endPosition].index, exported.has(position), {
23804
+ symbols.push(newSymbol("type", nameToken.token.text, span, declarationStart(sig, position), sig[endPosition].index, exported.has(position), {
23807
23805
  scope,
23808
23806
  binding: "identifier"
23809
23807
  }));
23810
23808
  return endPosition + 1;
23811
23809
  }
23812
23810
  /**
23813
- * TypeScript `enum` (including `const enum`). `NodeKind` has no `enum`
23814
- * spelling; `definition` is the closest existing kind.
23811
+ * TypeScript `enum` (including `const enum`). The symbol kind is `enumeration`.
23815
23812
  */
23816
23813
  function handleEnum(ctx, sig, position, symbols, exported, scope) {
23817
23814
  const nameToken = sig[position + 1];
@@ -23824,15 +23821,14 @@ function handleEnum(ctx, sig, position, symbols, exported, scope) {
23824
23821
  const exportedEnum = exported.has(position) || sig[position - 1]?.token.text === "const" && exported.has(position - 1);
23825
23822
  const startPosition = sig[position - 1]?.token.text === "const" ? declarationStartPosition(sig, position - 1) : declarationStartPosition(sig, position);
23826
23823
  const span = spanBetween(sig[startPosition].token, sig[endPosition].token);
23827
- symbols.push(newSymbol("definition", nameToken.token.text, span, sig[startPosition].index, sig[endPosition].index, exportedEnum, {
23824
+ symbols.push(newSymbol("enumeration", nameToken.token.text, span, sig[startPosition].index, sig[endPosition].index, exportedEnum, {
23828
23825
  scope,
23829
23826
  binding: "identifier"
23830
23827
  }));
23831
23828
  return endPosition + 1;
23832
23829
  }
23833
23830
  /**
23834
- * TypeScript `namespace` / `module` block. `module` is the existing `NodeKind`
23835
- * spelling for a declaration container, so both map to it.
23831
+ * TypeScript `namespace` / `module` block. Both map to the `namespace` kind.
23836
23832
  */
23837
23833
  function handleNamespace$1(ctx, sig, position, symbols, exported, scope) {
23838
23834
  const nameToken = sig[position + 1];
@@ -23856,7 +23852,7 @@ function handleNamespace$1(ctx, sig, position, symbols, exported, scope) {
23856
23852
  const endPosition = close < 0 ? open : close;
23857
23853
  if (close < 0) ctx.unverifiable("unterminated namespace body", sig[open].token.span);
23858
23854
  const span = spanBetween(sig[declarationStartPosition(sig, position)].token, sig[endPosition].token);
23859
- symbols.push(newSymbol("module", name, span, declarationStart(sig, position), sig[endPosition].index, exported.has(position), {
23855
+ symbols.push(newSymbol("namespace", name, span, declarationStart(sig, position), sig[endPosition].index, exported.has(position), {
23860
23856
  scope,
23861
23857
  binding: "identifier"
23862
23858
  }));
@@ -26742,7 +26738,8 @@ function buildAst(ctx, declarations) {
26742
26738
  * `importation` node each, so the dependency layer can build `depends`
26743
26739
  * edges from the same reference shape the JavaScript parser emits;
26744
26740
  * - `class`, `interface`, `enum`, `record` and `@interface` declarations
26745
- * (including nested types) -> one `class` node each;
26741
+ * (including nested types) -> one node each, using the precise declaration
26742
+ * kind (`class`, `interface` or `enumeration`);
26746
26743
  * - methods and constructors (including abstract/interface methods and
26747
26744
  * compact record constructors) -> one `method` node each, with a
26748
26745
  * declaration-signature span (modifiers/annotations through the body `{` or
@@ -26755,9 +26752,11 @@ function buildAst(ctx, declarations) {
26755
26752
  * |-----------------------------------|---------------------|------|
26756
26753
  * | `package` | `module` | existing kind |
26757
26754
  * | `import` / `import static` | `importation` | existing kind |
26758
- * | `class` | `class` | exact |
26759
- * | `interface` / `enum` / `record` | `class` | no dedicated NodeKind exists; `class` is the closest declaration kind |
26760
- * | `@interface` | `class` | same mapping as `interface` |
26755
+ * | `class` | `class` | exact, no label |
26756
+ * | `interface` | `interface` | exact, no label |
26757
+ * | `enum` | `enumeration` | exact, no label |
26758
+ * | `record` | `class` | `label: 'record'` (a record is a final class) |
26759
+ * | `@interface` | `interface` | `label: 'annotation'` |
26761
26760
  * | method / constructor | `method` | exact |
26762
26761
  * | field / constant | `variable` | existing kind; `label: 'constant'` only for an explicit `static final` |
26763
26762
  *
@@ -27379,6 +27378,28 @@ function typeDeclarationAt(tokens, position) {
27379
27378
  };
27380
27379
  }
27381
27380
  }
27381
+ /**
27382
+ * Map a Java type form onto its precise `NodeMetadata.kind`.
27383
+ *
27384
+ * `record` stays `class` (Java records are final classes) and `@interface`
27385
+ * stays `interface` (an annotation type is an interface); the distinction is
27386
+ * preserved in `label` rather than folding every declaration into `class`.
27387
+ */
27388
+ function javaTypeNode(form) {
27389
+ switch (form) {
27390
+ case "class": return { kind: "class" };
27391
+ case "interface": return { kind: "interface" };
27392
+ case "enum": return { kind: "enumeration" };
27393
+ case "record": return {
27394
+ kind: "class",
27395
+ label: "record"
27396
+ };
27397
+ case "@interface": return {
27398
+ kind: "interface",
27399
+ label: "annotation"
27400
+ };
27401
+ }
27402
+ }
27382
27403
  /** Scan one type declaration and its members; returns the position after it. */
27383
27404
  function scanType(state, declaration, startPosition, depth) {
27384
27405
  const { ctx, tokens } = state;
@@ -27396,17 +27417,20 @@ function scanType(state, declaration, startPosition, depth) {
27396
27417
  const open = findTypeBodyOpen(tokens, declaration.name + 1, tokens.length);
27397
27418
  const close = open < 0 ? -1 : braceClose(state, open);
27398
27419
  const startToken = tokens[startPosition] ?? nameToken;
27420
+ const span = {
27421
+ start: startToken.span.start,
27422
+ end: open >= 0 ? tokens[open].span.start : nameToken.span.end,
27423
+ line: startToken.span.line,
27424
+ column: startToken.span.column
27425
+ };
27426
+ const typeNode = javaTypeNode(declaration.form);
27399
27427
  emitNode$1(state, {
27400
- kind: "class",
27428
+ kind: typeNode.kind,
27401
27429
  name,
27402
- span: {
27403
- start: startToken.span.start,
27404
- end: open >= 0 ? tokens[open].span.start : nameToken.span.end,
27405
- line: startToken.span.line,
27406
- column: startToken.span.column
27407
- },
27408
- locatorKind: "class",
27409
- target: `${PARSER_ID$3}:class:${name}`
27430
+ span,
27431
+ locatorKind: typeNode.kind,
27432
+ target: `${PARSER_ID$3}:${typeNode.kind}:${name}`,
27433
+ ...typeNode.label === void 0 ? {} : { label: typeNode.label }
27410
27434
  });
27411
27435
  if (open < 0) {
27412
27436
  ctx.unverifiable(`type declaration "${name}" has no body`, startToken.span);
@@ -27914,9 +27938,10 @@ function signatureSpan(tokens, startPosition, endPosition) {
27914
27938
  * goes through the shared lexical classifier);
27915
27939
  * - `mod name;` and `mod name { ... }` → one `module` node (`label: 'mod'`);
27916
27940
  * the body of an inline module is scanned for module-level items;
27917
- * - `struct`/`enum`/`trait` declarations → one `class` node whose `label` is
27918
- * the Rust keyword; the declared type name is the `name`. Bodies are
27919
- * skipped (fields, variants and trait signatures are not projected);
27941
+ * - `struct`/`trait` declarations → one `class` node whose `label` is the
27942
+ * Rust keyword; `enum` declarations → one `enumeration` node (`label:
27943
+ * 'enum'`). The declared type name is the `name`. Bodies are skipped
27944
+ * (fields, variants and trait signatures are not projected);
27920
27945
  * - `impl Type { ... }` → one `class` node with `label: 'implementation'` and
27921
27946
  * `name` = the implemented type (`Type` in `impl Trait for Type`); the body
27922
27947
  * is scanned for direct members only;
@@ -27929,11 +27954,11 @@ function signatureSpan(tokens, startPosition, endPosition) {
27929
27954
  * nodes; attributes (`#[...]`, `#![...]`) and doc comments are skipped
27930
27955
  * without breaking the scan; `type` aliases are skipped.
27931
27956
  *
27932
- * The taxonomy is strict: only existing `NodeKind` spellings are emitted
27933
- * (`class`, `module`, `function`, `method`, `variable`, `importation`). Rust
27934
- * nuance lives in `label`, never in a new kind. Bodies are never returned: a
27935
- * node carries only a body-free span, fragment coordinates and (when a path is
27936
- * known) a `NodeReference`.
27957
+ * The taxonomy uses the precise `NodeKind` spellings (`class`, `enumeration`,
27958
+ * `module`, `function`, `method`, `variable`, `importation`). Rust nuance that
27959
+ * has no dedicated kind lives in `label`, never in a new kind. Bodies are never
27960
+ * returned: a node carries only a body-free span, fragment coordinates and
27961
+ * (when a path is known) a `NodeReference`.
27937
27962
  *
27938
27963
  * Conservative gaps, documented rather than guessed:
27939
27964
  *
@@ -28306,7 +28331,22 @@ function handleRustMod(ctx, tokens, position, sink) {
28306
28331
  ctx.parseError("mod declaration has neither a body nor a semicolon", tokenSpan$1(keyword));
28307
28332
  return position + 2;
28308
28333
  }
28309
- /** `struct`/`enum`/`trait` declarations; the body is skipped. */
28334
+ /**
28335
+ * Map a class-like Rust item keyword onto its precise node kind.
28336
+ *
28337
+ * `struct` and `trait` stay `class` with the keyword as label; `enum` has a
28338
+ * dedicated `enumeration` kind and keeps `label: 'enum'`.
28339
+ */
28340
+ function rustClassLikeNode(keyword) {
28341
+ return keyword === "enum" ? {
28342
+ kind: "enumeration",
28343
+ label: "enum"
28344
+ } : {
28345
+ kind: "class",
28346
+ label: keyword
28347
+ };
28348
+ }
28349
+ /** `struct`/`trait` (a `class`) and `enum` (an `enumeration`); bodies are skipped. */
28310
28350
  function handleRustClassLike(ctx, tokens, position, sink) {
28311
28351
  const keyword = tokens[position];
28312
28352
  const kind = keyword.text;
@@ -28349,10 +28389,11 @@ function handleRustClassLike(ctx, tokens, position, sink) {
28349
28389
  endPosition = Math.min(tokens.length - 1, position + 1);
28350
28390
  next = Math.min(tokens.length, position + 2);
28351
28391
  }
28392
+ const node = rustClassLikeNode(kind);
28352
28393
  if (!sink.addSymbol({
28353
- kind: "class",
28394
+ kind: node.kind,
28354
28395
  name: nameToken.text,
28355
- label: kind,
28396
+ label: node.label,
28356
28397
  span: tokenRangeSpan$1(keyword, tokens[endPosition])
28357
28398
  })) return tokens.length;
28358
28399
  return next;
@@ -29077,8 +29118,9 @@ function buildRustAst(ctx, declarations) {
29077
29118
  * path (optionally parenthesized) → one `import` reference and one
29078
29119
  * `importation` node whose `label` is the keyword. Non-literal include
29079
29120
  * targets produce no reference and one `unverifiable` diagnostic;
29080
- * - `class`, `interface`, `trait` and `enum` → one `class` node whose
29081
- * `label` is the keyword; the body is scanned for methods. Anonymous
29121
+ * - `class`, `interface`, `trait` and `enum` → one node each, using the
29122
+ * precise declaration kind (`class`, `interface` or `enumeration`) with the
29123
+ * PHP keyword as `label`; the body is scanned for methods. Anonymous
29082
29124
  * classes (`new class { ... }`) are skipped without a node;
29083
29125
  * - `function name(` at top level → `function`; a direct member of a
29084
29126
  * class-like body → `method`. Bodies are skipped, so closures and nested
@@ -29087,11 +29129,11 @@ function buildRustAst(ctx, declarations) {
29087
29129
  * keeps the leading `$` exactly as written. Assignments inside class,
29088
29130
  * function, closure and control-flow bodies are not projected.
29089
29131
  *
29090
- * The taxonomy is strict: only existing `NodeKind` spellings are emitted
29091
- * (`module`, `class`, `function`, `method`, `variable`, `importation`). PHP
29092
- * nuance lives in `label`, never in a new kind. Bodies are never returned: a
29093
- * node carries only a body-free span, fragment coordinates and (when a path is
29094
- * known) a `NodeReference`.
29132
+ * The taxonomy uses the precise `NodeKind` spellings (`module`, `class`,
29133
+ * `interface`, `enumeration`, `function`, `method`, `variable`,
29134
+ * `importation`). PHP nuance that has no dedicated kind lives in `label`, never
29135
+ * in a new kind. Bodies are never returned: a node carries only a body-free
29136
+ * span, fragment coordinates and (when a path is known) a `NodeReference`.
29095
29137
  *
29096
29138
  * Conservative gaps, documented rather than guessed:
29097
29139
  *
@@ -29465,7 +29507,27 @@ function handlePhpInclude(ctx, tokens, position, sink) {
29465
29507
  if (!sink.addReference(reference, keyword.text)) return tokens.length;
29466
29508
  return skipPhpToSemicolon(tokens, cursor + 1);
29467
29509
  }
29468
- /** `class`/`interface`/`trait`/`enum`; the body is scanned for methods. */
29510
+ /**
29511
+ * Map a PHP class-like keyword onto its precise node kind.
29512
+ *
29513
+ * `class` and `trait` stay `class` with the keyword as label; `interface` and
29514
+ * `enum` use their dedicated kinds.
29515
+ */
29516
+ function phpClassLikeNode(keyword) {
29517
+ if (keyword === "interface") return {
29518
+ kind: "interface",
29519
+ label: keyword
29520
+ };
29521
+ if (keyword === "enum") return {
29522
+ kind: "enumeration",
29523
+ label: keyword
29524
+ };
29525
+ return {
29526
+ kind: "class",
29527
+ label: keyword
29528
+ };
29529
+ }
29530
+ /** `class`/`trait` (`class`), `interface`, `enum`; the body is scanned for methods. */
29469
29531
  function handlePhpClassLike(ctx, tokens, position, sink) {
29470
29532
  const keyword = tokens[position];
29471
29533
  const kind = keyword.text;
@@ -29500,20 +29562,21 @@ function handlePhpClassLike(ctx, tokens, position, sink) {
29500
29562
  return Math.min(tokens.length, position + 2);
29501
29563
  }
29502
29564
  const close = findMatching$1(tokens, open, "{", "}");
29565
+ const node = phpClassLikeNode(kind);
29503
29566
  if (close < 0) {
29504
29567
  ctx.parseError(`${kind} body is unterminated`, tokenSpan(tokens[open]));
29505
29568
  if (!sink.addSymbol({
29506
- kind: "class",
29569
+ kind: node.kind,
29507
29570
  name: next.text,
29508
- label: kind,
29571
+ label: node.label,
29509
29572
  span: tokenRangeSpan(keyword, tokens[open])
29510
29573
  })) return tokens.length;
29511
29574
  return tokens.length;
29512
29575
  }
29513
29576
  if (!sink.addSymbol({
29514
- kind: "class",
29577
+ kind: node.kind,
29515
29578
  name: next.text,
29516
- label: kind,
29579
+ label: node.label,
29517
29580
  span: tokenRangeSpan(keyword, tokens[close])
29518
29581
  })) return tokens.length;
29519
29582
  scanPhpClassBody(ctx, tokens, open, close, next.text, sink);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepseek-coordination",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "A dual-face Cordis plugin for DeepSeek Harness: the host half owns a coordination SQLite database, seven model-facing tools and an HTTP surface; the web half mounts five composer dropdowns, a settings catalog and the service-level takeover dialog.",
5
5
  "keywords": [
6
6
  "deepseek-harness",