delimit-cli 2.3.1 → 2.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,33 @@
1
+ # Changelog
2
+
3
+ ## [2.4.0] - 2026-03-15
4
+
5
+ ### Added
6
+ - 29 real CLI tests covering init, lint, diff, explain, doctor, presets, and error handling
7
+ - Auto-write GitHub Actions workflow file on `delimit init`
8
+
9
+ ### Improved
10
+ - Version now read from package.json instead of hardcoded
11
+ - Error handling across all commands
12
+
13
+ ## [2.3.2] - 2026-03-09
14
+
15
+ ### Fixed
16
+ - Clean --help output (legacy commands hidden)
17
+ - File existence checks before lint/diff operations
18
+ - --policy flag accepts preset names (strict, default, relaxed)
19
+
20
+ ## [2.3.0] - 2026-03-07
21
+
22
+ ### Added
23
+ - Policy presets: strict (all errors), default (balanced), relaxed (warnings only)
24
+ - `delimit doctor` command for environment diagnostics
25
+ - `delimit explain` command with 7 output templates
26
+
27
+ ## [2.0.0] - 2026-02-28
28
+
29
+ ### Added
30
+ - Deterministic diff engine (23 change types, 10 breaking)
31
+ - Policy enforcement with exit code 1 on violations
32
+ - Semver classification (MAJOR/MINOR/PATCH/NONE)
33
+ - Zero-Spec extraction for FastAPI, NestJS, Express
package/README.md CHANGED
@@ -1,141 +1,108 @@
1
- # delimit-cli
1
+ # delimit
2
2
 
3
- **Prevent breaking API changes before they reach production.**
4
-
5
- Deterministic diff engine + policy enforcement + semver classification for OpenAPI specs. The independent successor to Optic.
3
+ Catch breaking API changes before they ship.
6
4
 
7
5
  [![npm](https://img.shields.io/npm/v/delimit-cli)](https://www.npmjs.com/package/delimit-cli)
6
+ [![GitHub Action](https://img.shields.io/badge/Marketplace-Delimit-blue)](https://github.com/marketplace/actions/delimit-api-governance)
8
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
8
+ [![Tests](https://img.shields.io/badge/tests-299%20passing-brightgreen)](#)
9
9
 
10
- ## Install
10
+ Deterministic diff engine for OpenAPI specs. Detects breaking changes, classifies semver, enforces policy, and posts PR comments with migration guides. No API keys, no external services.
11
11
 
12
- ```bash
13
- npm install -g delimit-cli
14
- ```
12
+ ---
15
13
 
16
- ## Quick Start (Under 5 Minutes)
14
+ ## GitHub Action (recommended)
17
15
 
18
- ```bash
19
- # 1. Initialize with a policy preset
20
- delimit init --preset default
16
+ Add `.github/workflows/api-check.yml`:
21
17
 
22
- # 2. Detect breaking changes
23
- delimit lint api/openapi-old.yaml api/openapi-new.yaml
18
+ ```yaml
19
+ name: API Contract Check
20
+ on: pull_request
24
21
 
25
- # 3. Add the GitHub Action for automated PR checks
26
- # Copy .github/workflows/api-governance.yml (see CI section below)
22
+ jobs:
23
+ delimit:
24
+ runs-on: ubuntu-latest
25
+ permissions:
26
+ pull-requests: write
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+ - uses: actions/checkout@v4
30
+ with:
31
+ ref: ${{ github.event.pull_request.base.sha }}
32
+ path: base
33
+ - uses: delimit-ai/delimit-action@v1
34
+ with:
35
+ old_spec: base/api/openapi.yaml
36
+ new_spec: api/openapi.yaml
27
37
  ```
28
38
 
29
- ## What It Catches
30
-
31
- Delimit deterministically detects 23 types of API changes, including 10 breaking patterns:
32
-
33
- - Endpoint or method removal
34
- - Required parameter addition
35
- - Response field removal
36
- - Type changes
37
- - Enum value removal
38
- - And more
39
-
40
- Every change is classified as `MAJOR`, `MINOR`, `PATCH`, or `NONE` per semver.
41
-
42
- ## Commands
43
-
44
- | Command | Description |
45
- |---------|-------------|
46
- | `delimit init` | Create `.delimit/policies.yml` with a policy preset |
47
- | `delimit lint <old> <new>` | Diff + policy check — returns exit code 1 on violations |
48
- | `delimit diff <old> <new>` | Raw diff with `[BREAKING]`/`[safe]` tags |
49
- | `delimit explain <old> <new>` | Human-readable change explanation |
39
+ Runs in **advisory mode** by default -- posts a PR comment but never fails your build. Set `mode: enforce` when you are ready to block merges on breaking changes.
50
40
 
51
- ## Policy Presets
41
+ ---
52
42
 
53
- Choose a preset that fits your team:
43
+ ## CLI
54
44
 
55
45
  ```bash
56
- delimit init --preset strict # Public APIs, payments — zero tolerance
57
- delimit init --preset default # Most teams — balanced rules
58
- delimit init --preset relaxed # Internal APIs, startups — warnings only
46
+ npx delimit-cli lint api/openapi.yaml
47
+ npx delimit-cli diff old.yaml new.yaml
48
+ npx delimit-cli explain old.yaml new.yaml --template migration
59
49
  ```
60
50
 
61
- | Preset | Breaking changes | Type changes | Field removal |
62
- |--------|-----------------|--------------|---------------|
63
- | `strict` | Error (blocks) | Error (blocks) | Error (blocks) |
64
- | `default` | Error (blocks) | Warning | Error (blocks) |
65
- | `relaxed` | Warning | Warning | Info |
66
-
67
- Pass a preset directly to lint:
51
+ Or install globally:
68
52
 
69
53
  ```bash
70
- delimit lint --policy strict old.yaml new.yaml
54
+ npm install -g delimit-cli
55
+ delimit init --preset default
56
+ delimit lint old.yaml new.yaml
71
57
  ```
72
58
 
73
- ## Options
59
+ ### Commands
74
60
 
75
- ```bash
76
- # Semver classification with version bump
77
- delimit lint old.yaml new.yaml --current-version 1.0.0
61
+ | Command | What it does |
62
+ |---------|-------------|
63
+ | `delimit init [--preset]` | Create `.delimit/policies.yml` |
64
+ | `delimit lint <old> <new>` | Diff + policy check. Exit 1 on violations. |
65
+ | `delimit diff <old> <new>` | Raw diff with `[BREAKING]` / `[safe]` tags |
66
+ | `delimit explain <old> <new>` | Human-readable explanation (7 templates) |
78
67
 
79
- # Explainer templates
80
- delimit explain old.yaml new.yaml -t migration
81
- delimit explain old.yaml new.yaml -t pr_comment
82
- delimit explain old.yaml new.yaml -t changelog
68
+ ---
83
69
 
84
- # JSON output for scripting
85
- delimit lint old.yaml new.yaml --json
86
- ```
70
+ ## What it catches
87
71
 
88
- ### Explainer Templates
72
+ 10 breaking change types, detected deterministically:
89
73
 
90
- | Template | Audience |
91
- |----------|----------|
92
- | `developer` | Technical details for engineers |
93
- | `team_lead` | Summary for engineering managers |
94
- | `product` | Non-technical overview for PMs |
95
- | `migration` | Step-by-step migration guide |
96
- | `changelog` | Ready-to-paste changelog entry |
97
- | `pr_comment` | GitHub PR comment format |
98
- | `slack` | Slack message format |
74
+ | Breaking change | Example |
75
+ |----------------|---------|
76
+ | Endpoint removed | `DELETE /users/{id}` path deleted |
77
+ | Method removed | `PATCH` dropped from `/orders` |
78
+ | Required parameter added | New required query param on existing endpoint |
79
+ | Parameter removed | `?filter` param deleted |
80
+ | Response removed | `200` response code dropped |
81
+ | Required field added | New required field in request body |
82
+ | Response field removed | `email` field removed from response |
83
+ | Type changed | `age` changed from `string` to `integer` |
84
+ | Format changed | `date` changed to `date-time` |
85
+ | Enum value removed | `status: "pending"` no longer allowed |
99
86
 
100
- ## CI/CD Integration
87
+ Plus 7 non-breaking types (endpoint added, optional field added, etc.) for full change visibility. Every change is classified as `MAJOR`, `MINOR`, `PATCH`, or `NONE`.
101
88
 
102
- Add this workflow to `.github/workflows/api-governance.yml`:
89
+ ---
103
90
 
104
- ```yaml
105
- name: API Governance
106
- on:
107
- pull_request:
108
- paths:
109
- - 'path/to/openapi.yaml' # adjust to your spec path
110
- permissions:
111
- contents: read
112
- pull-requests: write
113
- jobs:
114
- api-governance:
115
- runs-on: ubuntu-latest
116
- steps:
117
- - uses: actions/checkout@v4
118
- - uses: actions/checkout@v4
119
- with:
120
- ref: ${{ github.event.pull_request.base.sha }}
121
- path: _base
122
- - uses: delimit-ai/delimit@v1
123
- with:
124
- old_spec: _base/path/to/openapi.yaml
125
- new_spec: path/to/openapi.yaml
126
- mode: advisory # or 'enforce' to block PRs
91
+ ## Policy presets
92
+
93
+ ```bash
94
+ delimit init --preset strict # All breaking changes are errors. For public/payment APIs.
95
+ delimit init --preset default # Breaking changes error, type changes warn. For most teams.
96
+ delimit init --preset relaxed # Everything is a warning. For internal APIs and prototyping.
127
97
  ```
128
98
 
129
- The action posts a PR comment with:
130
- - Semver badge (`MAJOR` / `MINOR` / `PATCH`)
131
- - Violation table with severity
132
- - Expandable migration guide for breaking changes
99
+ Or pass inline: `delimit lint --policy strict old.yaml new.yaml`
133
100
 
134
- See [Delimit API Governance](https://github.com/marketplace/actions/delimit-api-governance) on the GitHub Marketplace.
101
+ ---
135
102
 
136
- ## Custom Policies
103
+ ## Custom policies
137
104
 
138
- Create `.delimit/policies.yml` or start from a preset:
105
+ Create `.delimit/policies.yml`:
139
106
 
140
107
  ```yaml
141
108
  override_defaults: false
@@ -151,17 +118,22 @@ rules:
151
118
  message: "V1 API is frozen. Make changes in V2."
152
119
  ```
153
120
 
154
- ## Supported Specs
121
+ ---
155
122
 
156
- - OpenAPI 3.0.x and 3.1.x
123
+ ## Supported formats
124
+
125
+ - OpenAPI 3.0 and 3.1
157
126
  - Swagger 2.0
158
- - YAML and JSON formats
127
+ - YAML and JSON
128
+
129
+ ---
159
130
 
160
131
  ## Links
161
132
 
162
- - [GitHub Action](https://github.com/marketplace/actions/delimit-api-governance) Automated PR checks
163
- - [GitHub](https://github.com/delimit-ai/delimit) Source code
164
- - [Issues](https://github.com/delimit-ai/delimit/issues) Bug reports and feature requests
133
+ - [delimit.ai](https://delimit.ai) -- Project home
134
+ - [GitHub Action on Marketplace](https://github.com/marketplace/actions/delimit-api-governance) -- Install in one click
135
+ - [delimit-cli on npm](https://www.npmjs.com/package/delimit-cli) -- CLI package
136
+ - [Quickstart repo](https://github.com/delimit-ai/delimit-quickstart) -- Try it in 2 minutes
165
137
 
166
138
  ## License
167
139
 
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Delimit™ Codex Forge Adapter
4
+ * Layer: Forge (execution governance)
5
+ * Surfaces test failures, deploy state, and release gates before accepting code.
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ const axios = require('axios');
11
+ const AGENT_URL = `http://127.0.0.1:${process.env.DELIMIT_AGENT_PORT || 7823}`;
12
+
13
+ class DelimitCodexForge {
14
+ constructor() {
15
+ this.name = 'delimit-forge';
16
+ this.version = '1.0.0';
17
+ }
18
+
19
+ /**
20
+ * Before accepting code: check test gate and deploy state.
21
+ */
22
+ async onBeforeSuggestion(context) {
23
+ const [testState, deployState] = await Promise.allSettled([
24
+ this._getTestGate(),
25
+ this._getDeployState(),
26
+ ]);
27
+
28
+ const warnings = [];
29
+
30
+ if (testState.status === 'fulfilled' && testState.value.failing > 0) {
31
+ warnings.push(`[FORGE] ${testState.value.failing} test(s) failing — fix before accepting`);
32
+ }
33
+
34
+ if (deployState.status === 'fulfilled' && deployState.value.locked) {
35
+ warnings.push(`[FORGE] Deploy locked: ${deployState.value.reason || 'release in progress'}`);
36
+ }
37
+
38
+ if (warnings.length > 0) {
39
+ return { allow: true, warning: warnings.join(' | ') };
40
+ }
41
+
42
+ return { allow: true };
43
+ }
44
+
45
+ async onAfterAccept(context) {
46
+ try {
47
+ await axios.post(`${AGENT_URL}/audit`, {
48
+ action: 'forge_accept',
49
+ context,
50
+ timestamp: new Date().toISOString(),
51
+ }, { timeout: 2000 });
52
+ } catch (_) { /* silent */ }
53
+ }
54
+
55
+ async _getTestGate() {
56
+ const r = await axios.get(`${AGENT_URL}/test/status`, { timeout: 3000 });
57
+ return r.data;
58
+ }
59
+
60
+ async _getDeployState() {
61
+ const r = await axios.get(`${AGENT_URL}/deploy/status`, { timeout: 3000 });
62
+ return r.data;
63
+ }
64
+
65
+ async handleCommand(command, _args) {
66
+ const { execSync } = require('child_process');
67
+ const cmds = {
68
+ 'forge': 'delimit status --layer=forge',
69
+ 'tests': 'delimit test --summary',
70
+ 'deploy': 'delimit deploy --status',
71
+ 'release': 'delimit release --status',
72
+ };
73
+ if (cmds[command]) {
74
+ try {
75
+ return execSync(cmds[command], { timeout: 10000 }).toString();
76
+ } catch (e) {
77
+ return `[FORGE] Command failed: ${e.message}`;
78
+ }
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Returns structured Forge context for consensus use.
84
+ */
85
+ async getContext() {
86
+ const [tests, deploy, release] = await Promise.allSettled([
87
+ axios.get(`${AGENT_URL}/test/status`, { timeout: 3000 }),
88
+ axios.get(`${AGENT_URL}/deploy/status`, { timeout: 3000 }),
89
+ axios.get(`${AGENT_URL}/release/status`, { timeout: 3000 }),
90
+ ]);
91
+
92
+ return {
93
+ layer: 'forge',
94
+ tests: tests.status === 'fulfilled' ? tests.value.data : null,
95
+ deploy: deploy.status === 'fulfilled' ? deploy.value.data : null,
96
+ release: release.status === 'fulfilled' ? release.value.data : null,
97
+ };
98
+ }
99
+ }
100
+
101
+ if (typeof module !== 'undefined' && module.exports) {
102
+ module.exports = new DelimitCodexForge();
103
+ }
104
+
105
+ if (typeof registerSkill === 'function') {
106
+ registerSkill(new DelimitCodexForge());
107
+ }
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Delimit™ Codex Jamsons Adapter
4
+ * Layer: Jamsons OS (strategy + operational governance)
5
+ * Injects portfolio context, logs decisions, surfaces venture/priority state.
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ const axios = require('axios');
11
+ const AGENT_URL = `http://127.0.0.1:${process.env.DELIMIT_AGENT_PORT || 7823}`;
12
+ const JAMSONS_URL = `http://localhost:${process.env.JAMSONS_PORT || 8091}`;
13
+
14
+ const VENTURES = {
15
+ delimit: { priority: 'P0', status: 'active' },
16
+ domainvested: { priority: 'P2', status: 'maintenance' },
17
+ 'wire.report': { priority: 'held', status: 'held' },
18
+ 'livetube.ai': { priority: 'held', status: 'held' },
19
+ };
20
+
21
+ class DelimitCodexJamsons {
22
+ constructor() {
23
+ this.name = 'delimit-jamsons';
24
+ this.version = '1.0.0';
25
+ }
26
+
27
+ /**
28
+ * Before suggestion: inject portfolio context so the model has strategic awareness.
29
+ */
30
+ async onBeforeSuggestion(context) {
31
+ try {
32
+ const portfolioCtx = await this._getPortfolioContext(context);
33
+ // Attach context metadata — Codex passes this through to the model
34
+ context._jamsons = portfolioCtx;
35
+ } catch (_) { /* fail open */ }
36
+ return { allow: true };
37
+ }
38
+
39
+ async onAfterAccept(context) {
40
+ // Log accepted suggestion to Jamsons decision ledger
41
+ try {
42
+ await axios.post(`${JAMSONS_URL}/api/chatops/decisions`, {
43
+ type: 'task',
44
+ title: `Codex: accepted suggestion in ${context.file || 'unknown file'}`,
45
+ detail: `Language: ${context.language || 'unknown'} | Tool: codex`,
46
+ user_id: 'codex-adapter',
47
+ tags: ['delimit', 'chatops'],
48
+ }, {
49
+ headers: { Authorization: `Bearer ${process.env.CHATOPS_AUTH_TOKEN}` },
50
+ timeout: 2000,
51
+ });
52
+ } catch (_) { /* silent */ }
53
+ }
54
+
55
+ async _getPortfolioContext(context) {
56
+ const [memory, decisions] = await Promise.allSettled([
57
+ this._searchMemory(context.file || context.language || 'delimit'),
58
+ this._getPendingDecisions(),
59
+ ]);
60
+
61
+ return {
62
+ ventures: VENTURES,
63
+ activeVenture: this._detectVenture(context),
64
+ memory: memory.status === 'fulfilled' ? memory.value : [],
65
+ pendingDecisions: decisions.status === 'fulfilled' ? decisions.value : [],
66
+ timestamp: new Date().toISOString(),
67
+ };
68
+ }
69
+
70
+ _detectVenture(context) {
71
+ const path = (context.file || '').toLowerCase();
72
+ if (path.includes('delimit')) return 'delimit';
73
+ if (path.includes('domainvested')) return 'domainvested';
74
+ return 'delimit'; // default active venture
75
+ }
76
+
77
+ async _searchMemory(query) {
78
+ const r = await axios.get(`${JAMSONS_URL}/api/memory/search`, {
79
+ params: { q: query, limit: 5 },
80
+ timeout: 2000,
81
+ });
82
+ return r.data?.results || [];
83
+ }
84
+
85
+ async _getPendingDecisions() {
86
+ const r = await axios.get(`${JAMSONS_URL}/api/chatops/decisions`, {
87
+ params: { status: 'pending', limit: 5 },
88
+ headers: { Authorization: `Bearer ${process.env.CHATOPS_AUTH_TOKEN}` },
89
+ timeout: 2000,
90
+ });
91
+ return r.data?.decisions || r.data || [];
92
+ }
93
+
94
+ async handleCommand(command, _args) {
95
+ const { execSync } = require('child_process');
96
+ const cmds = {
97
+ 'jamsons': 'delimit status --layer=jamsons',
98
+ 'portfolio': 'delimit portfolio --summary',
99
+ 'decisions': 'delimit decisions --pending',
100
+ 'memory': 'delimit memory --recent',
101
+ };
102
+ if (cmds[command]) {
103
+ try {
104
+ return execSync(cmds[command], { timeout: 10000 }).toString();
105
+ } catch (e) {
106
+ return `[JAMSONS] Command failed: ${e.message}`;
107
+ }
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Returns structured Jamsons context for consensus use.
113
+ */
114
+ async getContext() {
115
+ const [memory, decisions] = await Promise.allSettled([
116
+ axios.get(`${JAMSONS_URL}/api/memory/search`, {
117
+ params: { q: 'delimit strategy', limit: 5 },
118
+ timeout: 3000,
119
+ }),
120
+ axios.get(`${JAMSONS_URL}/api/chatops/decisions`, {
121
+ params: { status: 'pending' },
122
+ headers: { Authorization: `Bearer ${process.env.CHATOPS_AUTH_TOKEN}` },
123
+ timeout: 3000,
124
+ }),
125
+ ]);
126
+
127
+ return {
128
+ layer: 'jamsons',
129
+ ventures: VENTURES,
130
+ memory: memory.status === 'fulfilled' ? (memory.value.data?.results || []) : null,
131
+ pendingDecisions: decisions.status === 'fulfilled' ? (decisions.value.data || []) : null,
132
+ };
133
+ }
134
+ }
135
+
136
+ if (typeof module !== 'undefined' && module.exports) {
137
+ module.exports = new DelimitCodexJamsons();
138
+ }
139
+
140
+ if (typeof registerSkill === 'function') {
141
+ registerSkill(new DelimitCodexJamsons());
142
+ }
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Delimit™ Codex Security Skill Adapter
4
+ * Layer: Delimit (code governance) — Security surface
5
+ * Triggered on pre-code-generation and pre-suggestion events
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ const axios = require('axios');
11
+ const AGENT_URL = `http://127.0.0.1:${process.env.DELIMIT_AGENT_PORT || 7823}`;
12
+
13
+ class DelimitCodexSecurity {
14
+ constructor() {
15
+ this.name = 'delimit-security';
16
+ this.version = '1.0.0';
17
+ }
18
+
19
+ async onBeforeSuggestion(context) {
20
+ try {
21
+ const { code, language, file } = context;
22
+ const response = await axios.post(`${AGENT_URL}/security`, {
23
+ action: 'codex_suggestion',
24
+ code,
25
+ language,
26
+ file,
27
+ tool: 'codex',
28
+ }, { timeout: 3000 });
29
+
30
+ const { severity, findings } = response.data;
31
+
32
+ if (severity === 'critical') {
33
+ return {
34
+ allow: false,
35
+ message: `[DELIMIT SECURITY] Blocked — critical finding: ${findings?.[0]?.message || 'see audit log'}`,
36
+ };
37
+ }
38
+
39
+ if (severity === 'high') {
40
+ return {
41
+ allow: true,
42
+ warning: `[DELIMIT SECURITY] High-severity finding: ${findings?.[0]?.message || 'review before accepting'}`,
43
+ };
44
+ }
45
+
46
+ return { allow: true };
47
+ } catch (err) {
48
+ if (err.response?.data?.action === 'block') {
49
+ return { allow: false, message: `[DELIMIT SECURITY] ${err.response.data.reason}` };
50
+ }
51
+ // Fail open — security service unavailable
52
+ console.warn('[DELIMIT SECURITY] Scan unavailable:', err.message);
53
+ return { allow: true };
54
+ }
55
+ }
56
+
57
+ async onAfterAccept(context) {
58
+ try {
59
+ await axios.post(`${AGENT_URL}/audit`, {
60
+ action: 'codex_security_accept',
61
+ context,
62
+ timestamp: new Date().toISOString(),
63
+ }, { timeout: 2000 });
64
+ } catch (_) { /* silent */ }
65
+ }
66
+
67
+ async handleCommand(command, _args) {
68
+ if (command === 'security') {
69
+ const { execSync } = require('child_process');
70
+ try {
71
+ return execSync('delimit security --verbose', { timeout: 10000 }).toString();
72
+ } catch (e) {
73
+ return `[DELIMIT SECURITY] Command failed: ${e.message}`;
74
+ }
75
+ }
76
+ }
77
+
78
+ async getContext() {
79
+ try {
80
+ const r = await axios.get(`${AGENT_URL}/security/status`, { timeout: 3000 });
81
+ return { layer: 'delimit-security', status: 'ok', data: r.data };
82
+ } catch (_) {
83
+ return { layer: 'delimit-security', status: 'unavailable' };
84
+ }
85
+ }
86
+ }
87
+
88
+ if (typeof module !== 'undefined' && module.exports) {
89
+ module.exports = new DelimitCodexSecurity();
90
+ }
91
+
92
+ if (typeof registerSkill === 'function') {
93
+ registerSkill(new DelimitCodexSecurity());
94
+ }