npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sf-agentscript/agentforce

v2.5.31

Published

Batteries-included AgentScript SDK for Agentforce — parse, mutate, emit, lint

Readme

@agentscript/agentforce

Batteries-included AgentScript SDK for Agentforce — parse, mutate, emit, and lint .agent files with a single import.

Uses parser-javascript by default — a pure TypeScript parser with zero native dependencies. Tree-sitter is available as an optional backend for environments that need it.

Installation

pnpm add @agentscript/agentforce

No additional dependencies are needed. The default parser (parser-javascript) is pure TypeScript and works in Node.js and browsers out of the box.

Optional: Tree-sitter Backend

If you need tree-sitter as the parser backend (e.g., for compatibility or performance testing), use the tree-sitter build:

pnpm build:tree-sitter

This passes the tree-sitter exports condition to esbuild, which resolves @agentscript/parser to its native tree-sitter entry point.

Node.js — install native bindings:

pnpm add tree-sitter @agentscript/parser

Browser — install the WASM-based web-tree-sitter package:

pnpm add web-tree-sitter

Quick Start

Node.js

import { parse } from '@agentscript/agentforce';

const doc = parse(`
system:
    instructions: "You are a helpful agent."

topic billing:
    description: "Handle billing inquiries"
`);

console.log(doc.hasErrors);   // false
console.log(doc.diagnostics); // []
console.log(doc.emit());      // formatted source

Browser (Default — parser-javascript)

The default parser is pure TypeScript, so no WASM or native modules are needed in the browser. Just import and use:

import { parse } from '@agentscript/agentforce';

const doc = parse(source);
console.log(doc.emit());

Browser (Tree-sitter WASM)

When using tree-sitter in the browser, call init() to load WASM binaries before parsing:

import { init, parse } from '@agentscript/agentforce';

await init();  // loads tree-sitter WASM — required before first parse
const doc = parse(source);
console.log(doc.emit());

Build Modes

  • pnpm build — default build using parser-javascript. Produces a simple Node.js ESM bundle with no native dependencies.
  • pnpm build:tree-sitter — tree-sitter mode. Generates browser ESM, browser IIFE, and WASM constants bundles.

Package Exports

| Export Path | Description | |-------------|-------------| | @agentscript/agentforce | Default entry point (parser-javascript) | | @agentscript/agentforce/browser | Browser ESM bundle with web-tree-sitter support | | @agentscript/agentforce/browser.iife.js | Self-contained IIFE bundle (includes web-tree-sitter) | | @agentscript/agentforce/wasm | WASM constants (TREE_SITTER_ENGINE_BASE64, TREE_SITTER_AGENTSCRIPT_BASE64) |

API Reference

parse(source): Document

Parse a complete AgentScript source string into a Document.

const doc = parse(source);

| Parameter | Type | Description | |-----------|------|-------------| | source | string | AgentScript source text |

Never throws — if parsing fails, returns a Document with an empty AST and a diagnostic describing the error.

Returns a Document with the parsed AST, diagnostics, and full mutation API.


parseComponent(source, kind, parser)

Parse an isolated block, statement, or expression. The result is suitable for plugging into Document.addEntry() or Document.setField().

// Parse a block — return type is inferred from the kind
const topic = parseComponent(
  'topic billing:\n    description: "Handle billing"',
  'topic',
  parser,
);

// Parse statements
const stmts = parseComponent('run MyAction()', 'statement', parser);

// Parse an expression
const expr = parseComponent('"hello " + name', 'expression', parser);

Block kinds — any key from the Agentforce schema:

| Kind | Returns | |------|---------| | 'config' | ParsedConfig | | 'system' | System block | | 'topic' | ParsedTopic | | 'variables' | Variables block | | 'actions' | Actions block | | 'knowledge' | ParsedKnowledge | | 'connection' | ParsedConnection | | 'related_agent' | ParsedRelatedAgent | | 'language' | Language block | | 'model_config' | Model config block | | 'before_reasoning' | Before reasoning block | | 'reasoning' | Reasoning block | | 'after_reasoning' | After reasoning block | | 'security' | Security block | | 'modality' | Modality block |

Special kinds:

| Kind | Returns | |------|---------| | 'statement' | Statement[] | | 'expression' | Expression \| undefined |


emitComponent(component, options?): string

Emit a standalone component (block, statement array, single statement, or expression) back to AgentScript source text.

emitComponent automatically syncs block properties before emitting, so directly assigned fields are always emitted correctly:

import { parseComponent, emitComponent } from '@agentscript/agentforce';
import { StringLiteral } from '@agentscript/agentforce';

const topic = parseComponent(
  'topic billing:\n    description: "Handle billing"',
  'topic',
  parser,
);

// Assign fields directly — emitComponent auto-syncs
topic.description = new StringLiteral('Updated billing');
topic.source = new StringLiteral('billing_v2');       // new schema field
topic.custom_field = new StringLiteral('custom');      // non-schema field — also works

emitComponent(topic);      // all three fields are emitted correctly
emitComponent(topic, { tabSize: 2 }); // with custom indentation

Also works with statements and expressions:

const stmts = parseComponent('run MyAction()', 'statement', parser);
emitComponent(stmts);           // 'run MyAction()'

const expr = parseComponent('"hello"', 'expression', parser);
emitComponent(expr);            // '"hello"'

emitComponent(undefined);       // ''

| Parameter | Type | Description | |-----------|------|-------------| | component | BlockCore \| Statement[] \| Statement \| Expression \| undefined | Anything returned by parseComponent() | | options.tabSize | number | Indentation width (default: 4) |


mutateComponent(block, fn): block

For operations that can't be expressed as simple property assignment — removing fields and NamedMap add/remove — use mutateComponent():

import { parseComponent, emitComponent, mutateComponent } from '@agentscript/agentforce';

const topic = parseComponent(
  'topic billing:\n    description: "Handle billing"\n    source: "v1"',
  'topic',
  parser,
);

mutateComponent(topic!, (block, helpers) => {
  helpers.removeField('source');
  helpers.addEntry('actions', 'myAction', actionBlock);
  helpers.removeEntry('actions', 'oldAction');
});

emitComponent(topic);

| Method | Description | |--------|-------------| | setField(key, value) | Set a field value (new or existing). | | removeField(key) | Remove a field and its accessor. | | addEntry(key, name, value) | Add a named entry to a NamedMap field. | | removeEntry(key, name) | Remove a named entry from a NamedMap field. |

Returns the same block instance for chaining.


Document

The primary return type of parse(). Wraps the parsed AST with mutation helpers, undo/redo, and emission.

Properties

| Property | Type | Description | |----------|------|-------------| | ast | ParsedAgentforce | The parsed AST root | | diagnostics | readonly Diagnostic[] | All parse, schema, and lint diagnostics | | hasErrors | boolean | true if any diagnostic is Error severity | | errors | Diagnostic[] | Error-severity diagnostics only | | warnings | Diagnostic[] | Warning-severity diagnostics only | | isDirty | boolean | true if mutations have been applied since parse | | canUndo | boolean | true if undo history is available | | canRedo | boolean | true if redo stack is available | | history | readonly HistoryEntry[] | Array of mutation snapshots | | historyIndex | number | Current position in history |

emit(options?): string

Emit the current AST back to AgentScript source code.

const source = doc.emit();
const source = doc.emit({ tabSize: 2 });

mutate(fn, label?): this

Apply a mutation to the AST. Creates an undo point automatically.

doc.mutate((ast, helpers) => {
  helpers.setField('system', newSystemBlock);
  helpers.addEntry('topic', 'billing', billingTopic);
}, 'add billing topic');

Convenience Mutations

doc.setField('config', configBlock);         // Add/replace a singular block
doc.removeField('system');                   // Remove a singular block
doc.addEntry('topic', 'billing', topic);     // Add a named entry
doc.removeEntry('topic', 'billing');          // Remove a named entry

All return this for chaining.

undo() / redo(): this

Navigate mutation history.

doc.undo();
doc.redo();

getDiff(fromIndex?, toIndex?): { before, after }

Get before/after source strings for diffing. Defaults to comparing the state before the last mutation to the current state.

const { before, after } = doc.getDiff();

generateParser(engineBase64, languageBase64): Promise<TreeSitterParser>

Generate a tree-sitter parser from base64-encoded WASM binaries. This is the simplest way to use tree-sitter in browser environments, as it bundles the WASM binaries directly into your JavaScript bundle.

import { generateParser } from '@agentscript/agentforce';
import {
  TREE_SITTER_ENGINE_BASE64,
  TREE_SITTER_AGENTSCRIPT_BASE64
} from '@agentscript/agentforce/wasm';

const parser = await generateParser(
  TREE_SITTER_ENGINE_BASE64,
  TREE_SITTER_AGENTSCRIPT_BASE64
);

| Parameter | Type | Description | |-----------|------|-------------| | engineBase64 | string | Base64-encoded tree-sitter runtime WASM binary | | languageBase64 | string | Base64-encoded AgentScript language grammar WASM binary |

Returns a Promise<TreeSitterParser> that resolves to a parser compatible with parse().

Note: The WASM constants are only available after building the package with pnpm run build.


adaptWebTreeSitterNode(node): SyntaxNode

Converts a web-tree-sitter Node to the SyntaxNode interface expected by the parser. Uses lazy evaluation and a WeakMap cache internally. Only needed when using the tree-sitter backend with web-tree-sitter in custom browser setups.


Expression Constructors

For programmatic AST construction without parsing from source:

import {
  StringLiteral,
  NumberLiteral,
  BooleanLiteral,
  NoneLiteral,
  Identifier,
  AtIdentifier,
  MemberExpression,
  TemplateExpression,
  ListLiteral,
  DictLiteral,
} from '@agentscript/agentforce';

Diagnostics

Diagnostics follow the LSP 3.17 specification:

import { DiagnosticSeverity, DiagnosticTag } from '@agentscript/agentforce';
import type { Diagnostic, Range, Position } from '@agentscript/agentforce';

for (const d of doc.diagnostics) {
  console.log(d.severity);  // DiagnosticSeverity.Error | Warning | Information | Hint
  console.log(d.message);   // Human-readable message
  console.log(d.range);     // { start: { line, character }, end: { line, character } }
  console.log(d.code);      // "syntax-error", "undefined-reference", etc.
  console.log(d.source);    // "agentscript" | "agentscript-schema" | "agentscript-lint"
}

Three diagnostic sources:

| Source | Description | |--------|-------------| | "agentscript" | Syntax errors from tree-sitter parsing | | "agentscript-schema" | Schema validation (unknown blocks, type mismatches, missing fields) | | "agentscript-lint" | Linting (unused variables, undefined references, unreachable code) |


What Changed from @agentscript/sf-client-parsing

Architecture

| | Old (sf-client-parsing) | New (agentforce) | |---|---|---| | Parser | ANTLR (bundled internally) | Tree-sitter (consumer-provided) | | Module format | UMD/ESM via Webpack | ESM only | | Bundle | Single webpack bundle with Node polyfills | esbuild bundle, no polyfills needed | | Type safety | Loose — component parse returns any | Fully typed with generics and overloads | | AST mutation | Not supported — parse-only | Full mutation API with undo/redo | | Version | 1.2.10 | 0.1.0 |

New Capabilities

These features did not exist in the old package:

  • Document class — wraps AST with lifecycle management (mutate → emit)
  • AST mutationmutate(), setField(), addEntry(), removeEntry() with automatic __children sync
  • Undo/Redo — full history stack with labeled snapshots
  • DiffinggetDiff() for before/after comparisons
  • Dirty trackingisDirty flag after mutations
  • Web tree-sitter adapter — explicit adaptWebTreeSitterNode() for browser environments
  • Chaining — all mutations return this

New Block Types

Block types added in the new schema that were not in the old parser:

| Block | Description | |-------|-------------| | related_agent | Reference to related agents with protocol and target | | security | Security and sharing policy settings | | modality | Modality configuration (e.g., voice) |

Removed Features

| Old Feature | Replacement | |---|---| | detectIndentationForClient() | Not included. Use emit({ tabSize }) for consistent formatting. | | isScriptRecoverableForClient() | Not included. Equivalent: parse(source, parser).emit() === source | | UMD/CommonJS default export | ESM only. Use named imports. | | AgentScriptComponent enum (70+ values) | Replaced by schema-derived component kinds (~16 block types + statement + expression) | | Granular sub-component parsing (e.g., actionParameter, actionInputs) | Parse the parent block and traverse the AST |

Complete COMPONENT_TYPE / AgentScriptComponent Migration Reference

The old package exposed 70+ component types via COMPONENT_TYPE (frozen object) and AgentScriptComponent (enum). The new package replaces these with ~16 schema-derived block kinds plus 'statement' and 'expression'.

Every old constant is listed below with its exact migration path.

Top-Level Blocks (Direct Mapping)

These map 1:1 to a new parseComponent() kind:

| Old Constant | Old Value | New parseComponent() Kind | |---|---|---| | AGENT_SCRIPT | 'agentScript' | Use parse() directly | | SYSTEM_BLOCK | 'systemBlock' | 'system' | | CONFIG_BLOCK | 'configBlock' | 'config' | | VARIABLES_BLOCK | 'variablesBlock' | 'variables' | | ACTIONS_BLOCK | 'actionsBlock' | 'actions' | | FUNCTIONS_BLOCK | 'functionsBlock' | 'actions' | | KNOWLEDGE_BLOCK | 'knowledgeBlock' | 'knowledge' | | LANGUAGE_BLOCK | 'languageBlock' | 'language' | | BLOCK | 'block' | 'topic' | | BEFORE_REASONING_DIRECTIVES | 'beforeReasoningDirectives' | 'before_reasoning' | | AFTER_REASONING_DIRECTIVES | 'afterReasoningDirectives' | 'after_reasoning' | | PROCEDURE_BLOCK | 'procedureBlock' | No longer a top-level block — procedures are inline ProcedureValue fields (see below) | | STATEMENT | 'statement' | 'statement' | | STATEMENT_LIST | 'statementList' | 'statement' | | EXPRESSION | 'expression' | 'expression' |

Action Components → Parse 'actions' Block

These are no longer standalone parse targets. Parse the 'actions' block and access the AST:

| Old Constant | Old Value | New Approach | |---|---|---| | ACTION | 'action' | parseComponent(src, 'actions', parser) → iterate entries | | ACTION_DEFINITION | 'actionDefinition' | Same as ACTION | | ACTION_BODY | 'actionBody' | Access action entry's body/instructions | | ACTION_CALL | 'actionCall' | Parse as 'statement'run statements are action calls | | ACTION_DESCRIPTION | 'actionDescription' | Access action entry's .description | | ACTION_INPUTS | 'actionInputs' | Access action entry's .inputs | | ACTION_OUTPUTS | 'actionOutputs' | Access action entry's .outputs | | ACTION_PARAMETER | 'actionParameter' | Iterate .inputs or .outputs entries | | ACTION_TARGET | 'actionTarget' | Access action entry's .target | | REASONING_ACTIONS_DECLARATION | 'reasoningActionsDeclaration' | Parse 'topic' block, access .reasoning.actions |

Variable Components → Parse 'variables' Block

| Old Constant | Old Value | New Approach | |---|---|---| | VARIABLE_DECLARATION | 'variableDeclaration' | parseComponent(src, 'variables', parser) → iterate entries | | VARIABLE_DECLARATION_LIST | 'variableDeclarationList' | Same — result contains all declarations | | VARIABLE_ASSIGNMENT | 'variableAssignment' | Parse as 'statement' | | VARIABLES_BODY | 'variablesBody' | Access variables block's __children |

Config Components → Parse 'config' Block

| Old Constant | Old Value | New Approach | |---|---|---| | CONFIG_BODY | 'configBody' | parseComponent(src, 'config', parser) → access properties | | CONFIG_STATEMENT | 'configStatement' | Access config block's individual properties | | CONFIG_KEY_VALUE | 'configKeyValue' | Same as CONFIG_STATEMENT | | CONFIG_VALUE | 'configValue' | Access specific property value | | PREDEFINED_CONFIG_KEY | 'predefinedConfigKey' | Config property names are schema-defined |

System Components → Parse 'system' Block

| Old Constant | Old Value | New Approach | |---|---|---| | SYSTEM_BODY | 'systemBody' | parseComponent(src, 'system', parser) → access properties | | SYSTEM_STATEMENT | 'systemStatement' | Access system block's properties | | SYSTEM_MESSAGE | 'systemMessage' | Access .messages on system block | | SYSTEM_MESSAGES | 'systemMessages' | Same as SYSTEM_MESSAGE | | TOPIC_SYSTEM_BLOCK | 'topicSystemBlock' | Parse 'topic' block, access .system | | TOPIC_SYSTEM_INSTRUCTIONS | 'topicSystemInstructions' | Parse 'topic' block, access .system.instructions |

Block Sub-Components → Parse Parent Block

| Old Constant | Old Value | New Approach | |---|---|---| | BLOCK_BODY | 'blockBody' | Parse 'topic' block, access __children | | BLOCK_DESCRIPTION | 'blockDescription' | Parse parent block, access .description | | BLOCK_INSTRUCTIONS | 'blockInstructions' | Parse parent block, access .instructions | | INSTRUCTIONS | 'instructions' | Parse parent block, access .instructions | | REASONING_INSTRUCTIONS | 'reasoningInstructions' | Parse 'topic' block, access .reasoning.instructions | | REASONING_BLOCK | 'reasoningBlock' | Parse 'topic' block, access .reasoning — or use 'reasoning' kind for standalone |

Statement Components → Parse as 'statement'

| Old Constant | Old Value | New Approach | |---|---|---| | CONDITIONAL_STATEMENT | 'conditionalStatement' | parseComponent(src, 'statement', parser) — returns Statement[] with if nodes | | TRANSITION_STATEMENT | 'transitionStatement' | Parse as 'statement' — transitions are statements | | DIRECTIVE | 'directive' | Parse as 'statement' | | DIRECTIVES | 'directives' | Parse as 'statement' | | UTILS_TRANSITION_DECLARATION | 'utilsTransitionDeclaration' | Parse as 'statement' | | UTILS_ESCALATION_DECLARATION | 'utilsEscalationDeclaration' | Parse as 'statement' |

Expression / Literal Components → Parse as 'expression'

| Old Constant | Old Value | New Approach | |---|---|---| | LITERAL | 'literal' | parseComponent(src, 'expression', parser) | | ARRAY_LITERAL | 'arrayLiteral' | Parse as 'expression' — returns ListLiteral | | OBJECT_LITERAL | 'objectLiteral' | Parse as 'expression' — returns DictLiteral | | OBJECT_PROPERTY | 'objectProperty' | Parse as 'expression', access DictLiteral entries | | BOOL_VALUE | 'boolValue' | Parse as 'expression' — returns BooleanLiteral | | PROMPT_TEXT | 'promptText' | Parse as 'expression' — returns TemplateExpression or StringLiteral | | TEMPLATE | 'Template' | Parse as 'expression' — returns TemplateExpression |

Parameter / Type Components → Access via Parent

| Old Constant | Old Value | New Approach | |---|---|---| | PARAMETER | 'parameter' | Access via parent block's inputs/outputs entries | | PARAMETER_DEFINITION | 'parameterDefinition' | Same as PARAMETER | | PARAMETER_DEFINITION_LIST | 'parameterDefinitionList' | Access .inputs or .outputs on parent block | | PARAMETER_LIST | 'parameterList' | Same as PARAMETER_DEFINITION_LIST | | RETURN_DEFINITION | 'returnDefinition' | Access .outputs on action block | | RETURN_DEFINITION_LIST | 'returnDefinitionList' | Same as RETURN_DEFINITION | | TYPE | 'type' | Type info is on variable/parameter declarations | | DEFAULT_VALUE | 'defaultValue' | Access .defaultValue on variable declarations |

Language Components → Parse 'language' Block

| Old Constant | Old Value | New Approach | |---|---|---| | LANGUAGE_BODY | 'languageBody' | parseComponent(src, 'language', parser) → access properties | | LANGUAGE_STATEMENT | 'languageStatement' | Access language block's individual properties |

Other

| Old Constant | Old Value | New Approach | |---|---|---| | AGENT_TASK | 'agentTask' | Not in Agentforce schema | | OVERRIDE | 'override' | Not in Agentforce schema | | KNOWLEDGE_ACTION | 'knowledgeAction' | Parse 'knowledge' block, access entries | | CONNECTION | 'connection' | parseComponent(src, 'connection', parser) | | MODEL_CONFIG_BLOCK | 'modelConfigBlock' | parseComponent(src, 'model_config', parser) — or access .model_config on topic |

Procedures (PROCEDURE_BLOCK)

Procedures are not removed — the -> arrow syntax is used extensively. What changed is that procedures are no longer a standalone top-level block. They are now inline ProcedureValue fields that appear inside other blocks:

| Location | Syntax | Description | |---|---|---| | topic.reasoning.instructions | instructions: -> | Reasoning loop procedure (with arrow) | | topic.before_reasoning | before_reasoning: | Pre-reasoning procedure (arrow omitted) | | topic.after_reasoning | after_reasoning: | Post-reasoning procedure (arrow omitted) | | connection.response_actions.body | body: -> | Connection response procedure (with arrow) |

Procedures contain the same statement types as before (if, run, templates, transitions, etc.).

- // Old: parse a standalone procedure block
- const proc = parseAgentScriptComponentForClient(src, COMPONENT_TYPE.PROCEDURE_BLOCK);

+ // New: procedures are inline — access via parent block
+ const doc = parse(fullSource, parser);
+ // Access reasoning instructions (ProcedureValue with ->)
+ const instructions = doc.ast.topic?.get('myTopic')?.reasoning?.instructions;
+ // instructions.statements is Statement[]
+
+ // Or parse a topic and access its before/after reasoning
+ const topic = parseComponent(topicSource, 'topic', parser);
+ const beforeReasoning = topic?.before_reasoning; // ProcedureValue
+ const afterReasoning = topic?.after_reasoning;    // ProcedureValue

Summary Pattern

The migration follows one principle: parse the nearest top-level block, then traverse.

// Old: parse any sub-component directly
const result = parseAgentScriptComponentForClient(src, COMPONENT_TYPE.ACTION_INPUTS);

// New: parse the parent block, access the property
const actions = parseComponent(actionsSource, 'actions', parser);
const inputs = actions?.inputs;

Migration Guide

1. Update Imports

- import {
-   parseAgentScriptForClient,
-   safeParseAgentScriptForClient,
-   parseAgentScriptComponentForClient,
-   generateAgentScriptForClient,
-   AgentScriptComponent,
- } from '@agentscript/sf-client-parsing';
- import type { Diagnostic, DiagnosticSeverity } from '@agentscript/sf-client-parsing';
+ import { parse, parseComponent, Document } from '@agentscript/agentforce';
+ import type { Diagnostic } from '@agentscript/agentforce';
+ import { DiagnosticSeverity } from '@agentscript/agentforce';

2. Set Up the Parser

The new package does not bundle a parser. You provide one:

// Node.js
import Parser from 'tree-sitter';
import AgentScript from '@agentscript/parser-tree-sitter';

const parser = new Parser();
parser.setLanguage(AgentScript);

Create the parser once and reuse it for all parse calls.

3. Migrate parseAgentScriptForClient

- const result = parseAgentScriptForClient(script);
+ const doc = parse(script, parser);
+ const result = doc.ast;

4. Migrate safeParseAgentScriptForClient

The new parse() never throws and always returns diagnostics — it is inherently "safe":

- const { result, diagnostics } = safeParseAgentScriptForClient(script);
- if (diagnostics.length > 0) { /* handle errors */ }
+ const doc = parse(script, parser);
+ const result = doc.ast;
+ const diagnostics = doc.diagnostics;
+ if (doc.hasErrors) { /* handle errors */ }

5. Migrate generateAgentScriptForClient

Code generation is now doc.emit():

- const source = generateAgentScriptForClient(astJson);
+ const source = doc.emit();

If you need to generate from a modified AST:

doc.mutate((ast) => {
  // modify ast...
});
const source = doc.emit();

6. Migrate parseAgentScriptComponentForClient

- import { AgentScriptComponent } from '@agentscript/sf-client-parsing';
-
- const topic = parseAgentScriptComponentForClient(script, AgentScriptComponent.block);
- const config = parseAgentScriptComponentForClient(script, AgentScriptComponent.configBlock);
- const expr = parseAgentScriptComponentForClient(script, AgentScriptComponent.expression);
+ const topic = parseComponent(topicSource, 'topic', parser);
+ const config = parseComponent(configSource, 'config', parser);
+ const expr = parseComponent(exprSource, 'expression', parser);

7. Migrate generateAgentScriptComponentForClient

Individual blocks can emit themselves via __emit():

- const source = generateAgentScriptComponentForClient(parsedTopic, AgentScriptComponent.block);
+ const source = topic.__emit();

8. Migrate Sub-Component Parsing

For fine-grained components that no longer have their own parse kind, parse the parent block and traverse:

- // Old: parse individual action inputs
- const inputs = parseAgentScriptComponentForClient(script, AgentScriptComponent.actionInputs);
+ // New: parse the actions block, access inputs from the result
+ const actions = parseComponent(actionsSource, 'actions', parser);
+ const inputs = actions?.inputs;
- // Old: parse a variable declaration
- const decl = parseAgentScriptComponentForClient(script, AgentScriptComponent.variableDeclaration);
+ // New: parse the variables block, iterate entries
+ const doc = parse(fullSource, parser);
+ const variables = doc.ast.variables;

9. Migrate detectIndentationForClient

Use emit() with a tabSize option for consistent formatting instead:

- const { type, amount, indent } = detectIndentationForClient(content);
+ const formatted = doc.emit({ tabSize: 4 });

10. Migrate isScriptRecoverableForClient

- const recoverable = isScriptRecoverableForClient(script, AgentScriptComponent.block);
+ const recoverable = parse(script, parser).emit() === script;

11. Migrate Diagnostic Handling

The diagnostic format is largely the same (LSP 3.17), with minor differences:

  // Severity enum — same values, different import
- import { DiagnosticSeverityEnum } from '@agentscript/sf-client-parsing';
+ import { DiagnosticSeverity } from '@agentscript/agentforce';

  // Range format — same structure
  // { start: { line, character }, end: { line, character } }

  // New: diagnostics now include a `code` string and `source` field
  for (const d of doc.diagnostics) {
    console.log(d.code);    // e.g., "syntax-error", "undefined-reference"
    console.log(d.source);  // "agentscript", "agentscript-schema", or "agentscript-lint"
+   console.log(d.tags);    // DiagnosticTag[] — Unnecessary, Deprecated
  }

- // Old: isSemanticError flag
- if (d.isSemanticError) { ... }
+ // New: check source field
+ if (d.source === 'agentscript-schema' || d.source === 'agentscript-lint') { ... }

- // Old: data.rawContent, data.offendingContent, data.suggestion
+ // New: data.context, data.expected, data.found

12. Migrate UMD/CommonJS Consumers

The old package provided a UMD default export. The new package is ESM only:

- const AgentScript = require('@agentscript/sf-client-parsing');
- AgentScript.parseAgentScriptForClient(script);
+ // Must use ESM imports
+ import { parse } from '@agentscript/agentforce';

If your consumer requires CommonJS, use dynamic import():

const { parse } = await import('@agentscript/agentforce');