@dot-agent/language-server 0.2.0 → 0.4.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.
@@ -0,0 +1,28 @@
1
+ name: Publish to npm
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ id-token: write
9
+ contents: read
10
+
11
+ jobs:
12
+ publish:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - name: Checkout repository
16
+ uses: actions/checkout@v4
17
+
18
+ - name: Setup Node.js
19
+ uses: actions/setup-node@v4
20
+ with:
21
+ node-version: '24.x'
22
+ registry-url: 'https://registry.npmjs.org'
23
+
24
+ - name: Install dependencies
25
+ run: npm ci
26
+
27
+ - name: Publish package to npm
28
+ run: npm publish
package/AGENTS.md CHANGED
@@ -20,7 +20,7 @@ All structural analysis is performed on **tree-sitter ASTs** (not regex). `parse
20
20
  | `parser.js` | Tree-sitter engine — WASM initialization, per-document AST cache, and shared traversal helpers |
21
21
  | `features/hover.js` | Hover documentation for all DSL keywords (static lookup, no tree traversal) |
22
22
  | `features/completions.js` | Context-aware completions using `getContextNode` and `nodesOfType` for name lookups |
23
- | `features/diagnostics.js` | Linting — dangling transitions, dead-end interact (AST), deprecated keywords (line scan), undeclared types (AST) |
23
+ | `features/diagnostics.js` | Linting — dangling transitions, dead-end interact (AST), undeclared types (AST) |
24
24
  | `features/definition.js` | Go-to-definition via `state_decl` / `type_decl` node lookup |
25
25
  | `features/references.js` | Find all references via `transition_stmt`, `intent_trigger`, `type_ref` traversal |
26
26
  | `features/rename.js` | Rename symbol — same traversal as references, produces `TextEdit[]` |
@@ -153,4 +153,4 @@ The Apache 2.0 header:
153
153
  | Agent grammar (canonical) | [tree-sitter-agent/grammar.js](https://github.com/daniloborges/tree-sitter-agent/blob/main/grammar.js) |
154
154
  | Flow grammar (canonical) | [tree-sitter-agent/flow/grammar.js](https://github.com/daniloborges/tree-sitter-agent/blob/main/flow/grammar.js) |
155
155
  | VS Code extension | [vscode-dot-agent](https://github.com/daniloborges/vscode-dot-agent) |
156
- | WASM execution engine | [dot-agent-kernel](https://github.com/daniloborges/dot-agent-kernel) |
156
+ | WASM execution engine | [dot-agent-kernel](https://github.com/dot-agent-spec/kernel-dsl) |
package/README.md CHANGED
@@ -8,7 +8,7 @@ A standalone [Language Server Protocol (LSP)](https://microsoft.github.io/langua
8
8
  |---|---|---|
9
9
  | **Hover** | Keyword documentation | Keyword documentation |
10
10
  | **Completion** | Manifest keywords, custom types | Keywords, state names, memory domains (`context.`, `session.`, …) |
11
- | **Diagnostics** | Deprecated keywords, strict block lint, undeclared types | Dangling `transition` targets, dead-end `interact` |
11
+ | **Diagnostics** | Strict block lint, undeclared types | Dangling `transition` targets, dead-end `interact` |
12
12
  | **Go-to-Definition** | Type name → `type` declaration | `transition to stateName` → `state` declaration |
13
13
  | **Find References** | All uses of a type | All `transition` references to a state |
14
14
  | **Rename** | Type and its references | State and all `transition` references |
@@ -19,9 +19,9 @@
19
19
  const { CompletionItemKind } = require('vscode-languageserver');
20
20
  const { nodesOfType, positionToOffset, getContextNode } = require('../parser');
21
21
 
22
- const BEHAVIOR_TOP_KW = ['state', 'merge', 'on event', 'on intent', 'on offtopic', 'on fallback'];
23
- const BEHAVIOR_BLOCK_KW = ['guide', 'teach', 'goal', 'interact', 'run', 'transition', 'set', 'if', 'else', 'after', 'parallel', 'apply', 'remove', 'on intent', 'on offtopic', 'on fallback', 'on complete', 'on failed'];
24
- const AGENT_TOP_KW = ['agent', 'domain', 'license', 'terms', 'privacy', 'description', 'behavior', 'requires', 'input', 'capabilities', 'output', 'type', 'concept', 'schema'];
22
+ const BEHAVIOR_TOP_KW = ['state', 'merge', 'on event', 'on intent', 'on offtopic'];
23
+ const BEHAVIOR_BLOCK_KW = ['guide', 'teach', 'goal', 'interact', 'run', 'transition', 'set', 'if', 'else', 'end', 'after', 'parallel', 'apply', 'remove', 'on intent', 'on offtopic', 'on failure', 'on success'];
24
+ const DESCRIPTION_TOP_KW = ['agent', 'domain', 'license', 'terms', 'privacy', 'description', 'behavior', 'requires', 'input', 'capabilities', 'output', 'type', 'concept'];
25
25
  const STRICT_BLOCKS = new Set(['input_block', 'output_block', 'requires_block', 'capabilities_block']);
26
26
 
27
27
  function kw(label) {
@@ -59,7 +59,7 @@ function provideCompletions(langId, tree, text, position) {
59
59
  return ['script', 'subagent', 'tool'].map(kw);
60
60
  }
61
61
  if (/\bon\s+\S*$/.test(before)) {
62
- return ['event', 'intent', 'offtopic', 'fallback', 'complete', 'failed'].map(kw);
62
+ return ['event', 'intent', 'offtopic', 'failure', 'success'].map(kw);
63
63
  }
64
64
 
65
65
  // Context-aware: top-level vs. inside a block
@@ -72,9 +72,9 @@ function provideCompletions(langId, tree, text, position) {
72
72
  return (/^\s/.test(line) ? BEHAVIOR_BLOCK_KW : BEHAVIOR_TOP_KW).map(kw);
73
73
  }
74
74
 
75
- if (langId === 'agent') {
75
+ if (langId === 'description') {
76
76
  if (!/^\s/.test(line)) {
77
- return AGENT_TOP_KW.map(kw);
77
+ return DESCRIPTION_TOP_KW.map(kw);
78
78
  }
79
79
 
80
80
  // Inside a strict block → suggest declared types
@@ -29,7 +29,7 @@ function provideDefinition(langId, tree, text, uri, position) {
29
29
  if (langId === 'behavior') {
30
30
  targetNode = nodesOfType(tree, 'state_decl')
31
31
  .find(n => n.childForFieldName('name')?.text === word);
32
- } else if (langId === 'agent') {
32
+ } else if (langId === 'description') {
33
33
  if (!/^[A-Z]/.test(word) && !word.includes('.')) return null;
34
34
  targetNode = nodesOfType(tree, 'type_decl')
35
35
  .find(n => n.childForFieldName('name')?.text === word);
@@ -19,11 +19,6 @@
19
19
  const { DiagnosticSeverity } = require('vscode-languageserver');
20
20
  const { nodesOfType, nodeToRange } = require('../parser');
21
21
 
22
- const DEPRECATED_AGENT_KW = new Set([
23
- 'do', 'server', 'endpoint', 'author', 'version', 'requirements', 'step',
24
- 'softwareVersion', 'applicationCategory', 'character', 'publishingPrinciples',
25
- ]);
26
-
27
22
  const STRICT_BLOCK_TYPES = {
28
23
  input_block: 'input',
29
24
  output_block: 'output',
@@ -31,29 +26,9 @@ const STRICT_BLOCK_TYPES = {
31
26
  capabilities_block: 'capabilities',
32
27
  };
33
28
 
34
- function diagnoseAgent(tree, text) {
29
+ function diagnoseDescription(tree, text) {
35
30
  const diagnostics = [];
36
31
 
37
- // ── Deprecated keywords: line scan (no tree-sitter benefit here) ──────────
38
- const lines = text.split('\n');
39
- for (let i = 0; i < lines.length; i++) {
40
- const raw = lines[i];
41
- const stripped = raw.split('//')[0].trim();
42
- if (!stripped) continue;
43
- const wordM = stripped.match(/^([a-zA-Z0-9_.-]+)\b/);
44
- if (!wordM) continue;
45
- const word = wordM[1];
46
- if (DEPRECATED_AGENT_KW.has(word)) {
47
- const col = raw.indexOf(word);
48
- diagnostics.push({
49
- range: { start: { line: i, character: col }, end: { line: i, character: col + word.length } },
50
- message: `The keyword '${word}' is deprecated or invalid in the current .agent specification.`,
51
- severity: DiagnosticSeverity.Error,
52
- source: 'agent-dsl',
53
- });
54
- }
55
- }
56
-
57
32
  // ── Strict block validation ───────────────────────────────────────────────
58
33
  const declaredTypes = new Set(
59
34
  nodesOfType(tree, 'type_decl')
@@ -69,7 +44,7 @@ function diagnoseAgent(tree, text) {
69
44
  range: nodeToRange(errorNode),
70
45
  message: `Syntax error in '${blockName}' block. Expected: Type or Type "Description", or compact: Type1, Type2.`,
71
46
  severity: DiagnosticSeverity.Error,
72
- source: 'agent-dsl',
47
+ source: 'description-dsl',
73
48
  });
74
49
  }
75
50
 
@@ -84,7 +59,7 @@ function diagnoseAgent(tree, text) {
84
59
  range: nodeToRange(idNode),
85
60
  message: `Type '${typeName}' is not declared in this file (assuming native or external).`,
86
61
  severity: DiagnosticSeverity.Warning,
87
- source: 'agent-dsl',
62
+ source: 'description-dsl',
88
63
  });
89
64
  }
90
65
  }
@@ -95,10 +70,11 @@ function diagnoseAgent(tree, text) {
95
70
  return diagnostics;
96
71
  }
97
72
 
98
- function diagnoseFlow(tree) {
73
+ function diagnoseBehavior(tree) {
99
74
  const diagnostics = [];
100
75
 
101
76
  // ── Rule 1: Dangling transitions ──────────────────────────────────────────
77
+ // Collect all defined state names (from both oriented_state_body and setup_state_body)
102
78
  const definedStates = new Set(
103
79
  nodesOfType(tree, 'state_decl')
104
80
  .map(n => n.childForFieldName('name')?.text)
@@ -124,27 +100,26 @@ function diagnoseFlow(tree) {
124
100
  for (const n of nodesOfType(tree, 'transition_stmt')) {
125
101
  checkTransitionTarget(n.childForFieldName('state'));
126
102
  }
127
- for (const n of nodesOfType(tree, 'intent_trigger')) {
128
- // inline form: on intent "..." next <state>
129
- checkTransitionTarget(n.childForFieldName('state'));
130
- }
131
103
 
132
- // ── Rule 2: Dead-end interact ─────────────────────────────────────────────
104
+ // ── Rule 2: Dead-end interact (now redundant but kept for safety) ────────────
105
+ // With the new grammar, oriented_state_body requires repeat1(handlers),
106
+ // so dead-end interact is structurally impossible. But kept for edge cases.
133
107
  for (const interactNode of nodesOfType(tree, 'interact_stmt')) {
134
108
  let ancestor = interactNode.parent;
135
- while (ancestor && ancestor.type !== 'state_decl') {
109
+ while (ancestor && ancestor.type !== 'oriented_state_body' && ancestor.type !== 'state_decl') {
136
110
  ancestor = ancestor.parent;
137
111
  }
138
112
  if (!ancestor) continue;
139
113
 
140
- const hasNext = ancestor.descendantsOfType('transition_stmt').length > 0;
141
- const hasIntent = ancestor.descendantsOfType('intent_trigger').length > 0;
142
- const hasOfftopic = ancestor.descendantsOfType('offtopic_stmt').length > 0;
114
+ // With new grammar: oriented_state_body always has handlers after interact (repeat1)
115
+ // So this check should never trigger, but kept for robustness
116
+ const hasHandlers = ancestor.descendantsOfType('intent_handler').length +
117
+ ancestor.descendantsOfType('offtopic_handler').length > 0;
143
118
 
144
- if (!hasNext && !hasIntent && !hasOfftopic) {
119
+ if (!hasHandlers) {
145
120
  diagnostics.push({
146
121
  range: nodeToRange(interactNode),
147
- message: "This state calls interact but has no 'transition' or 'on intent/offtopic'. This will trap the agent.",
122
+ message: "This state calls interact but has no handlers (on intent/offtopic). This will trap the agent.",
148
123
  severity: DiagnosticSeverity.Warning,
149
124
  source: 'behavior-dsl',
150
125
  });
@@ -156,8 +131,8 @@ function diagnoseFlow(tree) {
156
131
 
157
132
  function diagnose(langId, tree, text) {
158
133
  if (!tree) return [];
159
- if (langId === 'agent') return diagnoseAgent(tree, text);
160
- if (langId === 'behavior') return diagnoseFlow(tree);
134
+ if (langId === 'description') return diagnoseDescription(tree, text);
135
+ if (langId === 'behavior') return diagnoseBehavior(tree);
161
136
  return [];
162
137
  }
163
138
 
@@ -16,7 +16,7 @@
16
16
 
17
17
  'use strict';
18
18
 
19
- const BLOCK_HEADERS = /^(on\s+(intent|offtopic|fallback|complete|failed)|if|else|after|parallel)\b/;
19
+ const BLOCK_HEADERS = /^(on\s+(intent|offtopic|failure|success)|if|else|after|parallel)\b/;
20
20
  const TOP_LEVEL_LINE = /^(state|merge)\s|^on\s+event\b/;
21
21
 
22
22
  function formatBehavior(text) {
@@ -39,7 +39,12 @@ function formatBehavior(text) {
39
39
  if (BLOCK_HEADERS.test(trimmed)) mode = 'NESTED_BODY';
40
40
  expectedIndent = 2;
41
41
  } else {
42
- expectedIndent = BLOCK_HEADERS.test(trimmed) ? 2 : 4;
42
+ if (/^end\b/.test(trimmed)) {
43
+ mode = 'STATE_BODY';
44
+ expectedIndent = 2;
45
+ } else {
46
+ expectedIndent = BLOCK_HEADERS.test(trimmed) ? 2 : 4;
47
+ }
43
48
  }
44
49
 
45
50
  const actualIndent = raw.length - raw.trimStart().length;
@@ -53,7 +58,7 @@ function formatBehavior(text) {
53
58
  return edits;
54
59
  }
55
60
 
56
- function formatAgent(text) {
61
+ function formatDescription(text) {
57
62
  const edits = [];
58
63
  const lines = text.split('\n');
59
64
  for (let i = 0; i < lines.length; i++) {
@@ -73,7 +78,7 @@ function formatAgent(text) {
73
78
 
74
79
  function format(langId, text) {
75
80
  if (langId === 'behavior') return formatBehavior(text);
76
- if (langId === 'agent') return formatAgent(text);
81
+ if (langId === 'description') return formatDescription(text);
77
82
  return [];
78
83
  }
79
84
 
package/features/hover.js CHANGED
@@ -18,7 +18,7 @@
18
18
 
19
19
  const { MarkupKind } = require('vscode-languageserver');
20
20
 
21
- const AGENT_DOCS = {
21
+ const DESCRIPTION_DOCS = {
22
22
  'agent': '**`agent name`**\n\nDeclares a new agent. The central node of the manifest.',
23
23
  'domain': '**`domain url`**\n\nDeclares the canonical domain for this agent, establishing cryptographic identity and ownership.',
24
24
  'license': '**`license type`**\n\nDeclares the license under which this agent is distributed (e.g., MIT, Copyright).',
@@ -32,30 +32,32 @@ const AGENT_DOCS = {
32
32
  'output': '**`output Type`**\n\nThe data type this agent returns.',
33
33
  'type': '**`type name`**\n\nDeclares a custom type to anchor custom typing to Wikidata or Schema.org.',
34
34
  'concept': '**`concept url`**\n\nThe Wikidata or Schema.org concept URL this type maps to.',
35
- 'schema': '**`schema file.json`**\n\nA JSON schema file for this type.',
36
35
  };
37
36
 
38
37
  const BEHAVIOR_DOCS = {
39
38
  'merge': '**`merge "file.behavior"`**\n\nIncludes another `.behavior` file. Must appear before any `state` or `on event` declarations (preamble-only, eager loading).',
40
39
  'state': '**`state name`**\n\nDeclares a named state. States contain the logic that runs while the agent is in that state.',
41
- 'on': '**`on event|intent|offtopic|fallback|complete|failed`**\n\nBinds a handler to a trigger. Top-level: `on event`. Inside a state: `on intent`, `on offtopic`, `on fallback`. After parallel: `on complete`, `on failed`.',
42
- 'run': '**`run script|subagent|tool "target"`**\n\nExecutes a script, subagent, or tool. Accepts optional modifiers: `silent`, `in background`, `each collection`.',
40
+ 'on': '**`on event|intent|offtopic|failure|success`**\n\nBinds a handler to a trigger. Top-level: `on event`. Inside a state: `on intent`, `on offtopic`. After `run`/`apply`/`remove`: `on failure`. Inside `parallel`: `on success` (optional), `on failure` (required).',
41
+ 'run': '**`run script|subagent|tool "target" ["parameters"]`**\n\nExecutes a script, subagent, or tool. Optionally followed by `on failure` to handle errors.',
43
42
  'guide': '**`guide "text"`**\n\nInjects a system-level instruction into the conversation context, shaping the agent\'s persona or approach without being visible as a reply.',
44
- 'teach': '**`teach "text"`**\n\nAdds a fact or constraint to the agent\'s working knowledge for the duration of this state.',
43
+ 'teach': '**`teach "file"`**\n\nLoads a file into the agent\'s working knowledge for the duration of this state.',
45
44
  'goal': '**`goal "text"`**\n\nSets the agent\'s objective for this state, used by the runtime for planning and alignment checks.',
46
- 'interact': '**`interact [requiring "text"]`**\n\nPauses execution and waits for user input. Optionally enforces a requirement before continuing.',
45
+ 'interact': '**`interact`**\n\nPauses execution and waits for user input.',
47
46
  'set': '**`set domain.var = value`**\n\nAssigns a value to a memory variable. Domains: `context`, `session`, `worksession`, `user`.',
48
47
  'context': '**`context`** memory domain — scoped to the current agent run.',
49
48
  'session': '**`session`** memory domain — persists for the user\'s current session.',
50
49
  'worksession': '**`worksession`** memory domain — persists across a task-oriented work session (isolated per task).',
51
50
  'user': '**`user`** memory domain — persists across sessions for a given user.',
52
51
  'transition': '**`transition to state`**\n\nTransitions immediately to the named state.',
53
- 'if': '**`if condition`**\n\nConditional execution. Condition can use `==`, `!=`, `>`, `<`, `>=`, `<=`, `and`, `or`.',
54
- 'else': '**`else`**\n\nAlternative branch of an `if` statement.',
52
+ 'if': '**`if condition`**\n\nConditional execution. Condition can use `==`, `!=`, `>`, `<`, `>=`, `<=`, `and`, `or`. Close the block with `end`.',
53
+ 'else': '**`else`**\n\nAlternative branch of an `if` statement. Close the block with `end`.',
54
+ 'end': '**`end`**\n\nCloses an `if`/`else` block.',
55
55
  'after': '**`after N prompts`**\n\n[Experimental] Executes a block after N user prompts have occurred in this state.',
56
- 'parallel': '**`parallel`**\n\n[Experimental] Runs a block of `run` statements concurrently. Follow with `on complete` and `on failed` handlers.',
57
- 'apply': '**`apply css|html|video "text"`**\n\nApplies a UI manipulation to a CSS selector, HTML element, or video element.',
58
- 'remove': '**`remove css|html|video "text"`**\n\nRemoves a UI element by selector or reference.',
56
+ 'parallel': '**`parallel`**\n\n[Experimental] Runs a block of `run` statements concurrently. Follow with optional `on success` and required `on failure` handlers.',
57
+ 'apply': '**`apply css "selector"`**\n\nApplies a UI manipulation to a CSS selector. Optionally followed by `on failure`.',
58
+ 'remove': '**`remove css "selector"`**\n\nRemoves a UI element by CSS selector. Optionally followed by `on failure`.',
59
+ 'failure': '**`on failure`**\n\nError handler block executed when a `run`, `apply`, `remove`, or `parallel` statement fails.',
60
+ 'success': '**`on success`**\n\nOptional success handler block inside a `parallel` statement.',
59
61
  };
60
62
 
61
63
  function provideHover(langId, text, position) {
@@ -70,7 +72,7 @@ function provideHover(langId, text, position) {
70
72
  const word = line.slice(start, end);
71
73
  if (!word) return null;
72
74
 
73
- const docs = langId === 'agent' ? AGENT_DOCS : BEHAVIOR_DOCS;
75
+ const docs = langId === 'description' ? DESCRIPTION_DOCS : BEHAVIOR_DOCS;
74
76
  const doc = docs[word];
75
77
  if (!doc) return null;
76
78
 
package/features/links.js CHANGED
@@ -41,15 +41,11 @@ function provideDocumentLinks(langId, tree, docUri) {
41
41
  });
42
42
  }
43
43
 
44
- if (langId === 'agent') {
44
+ if (langId === 'description') {
45
45
  for (const node of nodesOfType(tree, 'behavior_block')) {
46
46
  const fileNode = node.childForFieldName('file');
47
47
  if (fileNode) addLink(fileNode, fileNode.text);
48
48
  }
49
- for (const node of nodesOfType(tree, 'schema_prop')) {
50
- const fileNode = node.childForFieldName('file');
51
- if (fileNode) addLink(fileNode, fileNode.text);
52
- }
53
49
  }
54
50
 
55
51
  if (langId === 'behavior') {
@@ -58,7 +54,7 @@ function provideDocumentLinks(langId, tree, docUri) {
58
54
  if (pathNode) addLink(pathNode, pathNode.text);
59
55
  }
60
56
  for (const node of nodesOfType(tree, 'run_stmt')) {
61
- const runTypeNode = node.childForFieldName('run_type');
57
+ const runTypeNode = node.childForFieldName('type');
62
58
  if (runTypeNode?.text !== 'script') continue;
63
59
  const targetNode = node.childForFieldName('target');
64
60
  if (targetNode) addLink(targetNode, targetNode.text);
@@ -41,12 +41,7 @@ function provideReferences(langId, tree, text, uri, position) {
41
41
  const stateNode = n.childForFieldName('state');
42
42
  if (stateNode?.text === word) add(stateNode);
43
43
  }
44
- // Inline intent handlers: on intent "..." next <state>
45
- for (const n of nodesOfType(tree, 'intent_trigger')) {
46
- const stateNode = n.childForFieldName('state');
47
- if (stateNode?.text === word) add(stateNode);
48
- }
49
- } else if (langId === 'agent') {
44
+ } else if (langId === 'description') {
50
45
  // Declaration
51
46
  for (const n of nodesOfType(tree, 'type_decl')) {
52
47
  const nameNode = n.childForFieldName('name');
@@ -41,12 +41,7 @@ function provideRenameEdits(langId, tree, text, uri, position, newName) {
41
41
  const stateNode = n.childForFieldName('state');
42
42
  if (stateNode?.text === oldName) addEdit(stateNode);
43
43
  }
44
- // Rename inline intent handler targets
45
- for (const n of nodesOfType(tree, 'intent_trigger')) {
46
- const stateNode = n.childForFieldName('state');
47
- if (stateNode?.text === oldName) addEdit(stateNode);
48
- }
49
- } else if (langId === 'agent') {
44
+ } else if (langId === 'description') {
50
45
  // Rename type declarations
51
46
  for (const n of nodesOfType(tree, 'type_decl')) {
52
47
  const nameNode = n.childForFieldName('name');
@@ -49,7 +49,7 @@ function provideDocumentSymbols(langId, tree) {
49
49
  }
50
50
  }
51
51
 
52
- if (langId === 'agent') {
52
+ if (langId === 'description') {
53
53
  for (const node of nodesOfType(tree, 'agent_decl')) {
54
54
  const nameNode = node.childForFieldName('name');
55
55
  if (!nameNode) continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dot-agent/language-server",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "LSP server for .agent DSL files",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Danilo Borges <contato@daniloborg.es>",
@@ -12,7 +12,13 @@
12
12
  "bugs": {
13
13
  "url": "https://github.com/dot-agent-spec/language-server/issues"
14
14
  },
15
- "keywords": ["lsp", "language-server", "agent", "dsl", "flow"],
15
+ "keywords": [
16
+ "lsp",
17
+ "language-server",
18
+ "agent",
19
+ "dsl",
20
+ "flow"
21
+ ],
16
22
  "main": "server.js",
17
23
  "engines": {
18
24
  "node": ">=18"
@@ -21,10 +27,10 @@
21
27
  "start": "node server.js --stdio"
22
28
  },
23
29
  "dependencies": {
24
- "vscode-languageserver": "^9.0.1",
30
+ "@dot-agent/tree-sitter": "^0.3.4",
31
+ "vscode-languageserver": "^10.0.0",
25
32
  "vscode-languageserver-textdocument": "^1.0.12",
26
- "web-tree-sitter": "^0.25.0",
27
- "@dot-agent/tree-sitter": "^0.2.0"
33
+ "web-tree-sitter": "^0.26.9"
28
34
  },
29
35
  "publishConfig": {
30
36
  "access": "public"
package/parser.js CHANGED
@@ -21,17 +21,17 @@ const { Parser, Language } = require('web-tree-sitter');
21
21
  const grammar = require('@dot-agent/tree-sitter');
22
22
 
23
23
  // path.resolve ensures absolute paths survive vsix packaging and cwd changes
24
- const AGENT_WASM = path.resolve(grammar.agentWasmPath);
24
+ const DESCRIPTION_WASM = path.resolve(grammar.agentWasmPath);
25
25
  const BEHAVIOR_WASM = path.resolve(grammar.behaviorWasmPath);
26
26
 
27
- let agentParser, behaviorParser;
27
+ let descriptionParser, behaviorParser;
28
28
 
29
29
  async function initParsers() {
30
30
  await Parser.init();
31
- const Agent = await Language.load(AGENT_WASM);
31
+ const DescriptionLang = await Language.load(DESCRIPTION_WASM);
32
32
  const Behavior = await Language.load(BEHAVIOR_WASM);
33
- agentParser = new Parser();
34
- agentParser.setLanguage(Agent);
33
+ descriptionParser = new Parser();
34
+ descriptionParser.setLanguage(DescriptionLang);
35
35
  behaviorParser = new Parser();
36
36
  behaviorParser.setLanguage(Behavior);
37
37
  }
@@ -42,7 +42,7 @@ const cache = new Map();
42
42
  function parse(uri, langId, text, version) {
43
43
  const prev = cache.get(uri);
44
44
  if (prev?.version === version) return prev.tree;
45
- const parser = langId === 'behavior' ? behaviorParser : agentParser;
45
+ const parser = langId === 'behavior' ? behaviorParser : descriptionParser;
46
46
  if (!parser) return null;
47
47
  const tree = parser.parse(text, prev?.tree); // incremental reuse when possible
48
48
  cache.set(uri, { version, tree });
package/server.js CHANGED
@@ -71,7 +71,7 @@ function getTree(doc) {
71
71
 
72
72
  function validate(doc) {
73
73
  const langId = doc.languageId;
74
- if (langId !== 'agent' && langId !== 'behavior') return;
74
+ if (langId !== 'description' && langId !== 'behavior') return;
75
75
  const tree = getTree(doc);
76
76
  const diagnostics = diagnose(langId, tree, doc.getText());
77
77
  connection.sendDiagnostics({ uri: doc.uri, diagnostics });