@unlimitechcloud/devlink 1.0.2
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/AGENTS.md +880 -0
- package/LICENSE +21 -0
- package/README.md +335 -0
- package/dist/__tests__/e2e.spec.d.ts +8 -0
- package/dist/__tests__/e2e.spec.d.ts.map +1 -0
- package/dist/__tests__/e2e.spec.js +253 -0
- package/dist/__tests__/e2e.spec.js.map +1 -0
- package/dist/__tests__/integration.spec.d.ts +8 -0
- package/dist/__tests__/integration.spec.d.ts.map +1 -0
- package/dist/__tests__/integration.spec.js +274 -0
- package/dist/__tests__/integration.spec.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +610 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/consumers.d.ts +37 -0
- package/dist/commands/consumers.d.ts.map +1 -0
- package/dist/commands/consumers.js +107 -0
- package/dist/commands/consumers.js.map +1 -0
- package/dist/commands/docs.d.ts +59 -0
- package/dist/commands/docs.d.ts.map +1 -0
- package/dist/commands/docs.js +262 -0
- package/dist/commands/docs.js.map +1 -0
- package/dist/commands/docs.spec.d.ts +5 -0
- package/dist/commands/docs.spec.d.ts.map +1 -0
- package/dist/commands/docs.spec.js +213 -0
- package/dist/commands/docs.spec.js.map +1 -0
- package/dist/commands/index.d.ts +13 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +13 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/install.d.ts +31 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +234 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/list.d.ts +22 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +45 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/list.spec.d.ts +5 -0
- package/dist/commands/list.spec.d.ts.map +1 -0
- package/dist/commands/list.spec.js +95 -0
- package/dist/commands/list.spec.js.map +1 -0
- package/dist/commands/prune.d.ts +27 -0
- package/dist/commands/prune.d.ts.map +1 -0
- package/dist/commands/prune.js +74 -0
- package/dist/commands/prune.js.map +1 -0
- package/dist/commands/publish.d.ts +16 -0
- package/dist/commands/publish.d.ts.map +1 -0
- package/dist/commands/publish.js +225 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/publish.spec.d.ts +5 -0
- package/dist/commands/publish.spec.d.ts.map +1 -0
- package/dist/commands/publish.spec.js +98 -0
- package/dist/commands/publish.spec.js.map +1 -0
- package/dist/commands/push.d.ts +16 -0
- package/dist/commands/push.d.ts.map +1 -0
- package/dist/commands/push.js +164 -0
- package/dist/commands/push.js.map +1 -0
- package/dist/commands/remove.d.ts +24 -0
- package/dist/commands/remove.d.ts.map +1 -0
- package/dist/commands/remove.js +80 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/remove.spec.d.ts +5 -0
- package/dist/commands/remove.spec.d.ts.map +1 -0
- package/dist/commands/remove.spec.js +87 -0
- package/dist/commands/remove.spec.js.map +1 -0
- package/dist/commands/resolve.d.ts +20 -0
- package/dist/commands/resolve.d.ts.map +1 -0
- package/dist/commands/resolve.js +52 -0
- package/dist/commands/resolve.js.map +1 -0
- package/dist/commands/resolve.spec.d.ts +5 -0
- package/dist/commands/resolve.spec.d.ts.map +1 -0
- package/dist/commands/resolve.spec.js +87 -0
- package/dist/commands/resolve.spec.js.map +1 -0
- package/dist/commands/verify.d.ts +32 -0
- package/dist/commands/verify.d.ts.map +1 -0
- package/dist/commands/verify.js +127 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/config.d.ts +22 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +70 -0
- package/dist/config.js.map +1 -0
- package/dist/constants.d.ts +65 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +116 -0
- package/dist/constants.js.map +1 -0
- package/dist/constants.spec.d.ts +5 -0
- package/dist/constants.spec.d.ts.map +1 -0
- package/dist/constants.spec.js +72 -0
- package/dist/constants.spec.js.map +1 -0
- package/dist/core/index.d.ts +9 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +9 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/installations.d.ts +79 -0
- package/dist/core/installations.d.ts.map +1 -0
- package/dist/core/installations.js +207 -0
- package/dist/core/installations.js.map +1 -0
- package/dist/core/installations.spec.d.ts +5 -0
- package/dist/core/installations.spec.d.ts.map +1 -0
- package/dist/core/installations.spec.js +261 -0
- package/dist/core/installations.spec.js.map +1 -0
- package/dist/core/lock.d.ts +37 -0
- package/dist/core/lock.d.ts.map +1 -0
- package/dist/core/lock.js +198 -0
- package/dist/core/lock.js.map +1 -0
- package/dist/core/lock.spec.d.ts +5 -0
- package/dist/core/lock.spec.d.ts.map +1 -0
- package/dist/core/lock.spec.js +161 -0
- package/dist/core/lock.spec.js.map +1 -0
- package/dist/core/registry.d.ts +80 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/core/registry.js +231 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/registry.spec.d.ts +5 -0
- package/dist/core/registry.spec.d.ts.map +1 -0
- package/dist/core/registry.spec.js +281 -0
- package/dist/core/registry.spec.js.map +1 -0
- package/dist/core/resolver.d.ts +55 -0
- package/dist/core/resolver.d.ts.map +1 -0
- package/dist/core/resolver.js +127 -0
- package/dist/core/resolver.js.map +1 -0
- package/dist/core/resolver.spec.d.ts +5 -0
- package/dist/core/resolver.spec.d.ts.map +1 -0
- package/dist/core/resolver.spec.js +202 -0
- package/dist/core/resolver.spec.js.map +1 -0
- package/dist/core/store.d.ts +65 -0
- package/dist/core/store.d.ts.map +1 -0
- package/dist/core/store.js +245 -0
- package/dist/core/store.js.map +1 -0
- package/dist/core/store.spec.d.ts +5 -0
- package/dist/core/store.spec.d.ts.map +1 -0
- package/dist/core/store.spec.js +195 -0
- package/dist/core/store.spec.js.map +1 -0
- package/dist/formatters/flat.d.ts +41 -0
- package/dist/formatters/flat.d.ts.map +1 -0
- package/dist/formatters/flat.js +131 -0
- package/dist/formatters/flat.js.map +1 -0
- package/dist/formatters/flat.spec.d.ts +5 -0
- package/dist/formatters/flat.spec.d.ts.map +1 -0
- package/dist/formatters/flat.spec.js +130 -0
- package/dist/formatters/flat.spec.js.map +1 -0
- package/dist/formatters/index.d.ts +6 -0
- package/dist/formatters/index.d.ts.map +1 -0
- package/dist/formatters/index.js +6 -0
- package/dist/formatters/index.js.map +1 -0
- package/dist/formatters/tree.d.ts +29 -0
- package/dist/formatters/tree.d.ts.map +1 -0
- package/dist/formatters/tree.js +256 -0
- package/dist/formatters/tree.js.map +1 -0
- package/dist/formatters/tree.spec.d.ts +5 -0
- package/dist/formatters/tree.spec.d.ts.map +1 -0
- package/dist/formatters/tree.spec.js +127 -0
- package/dist/formatters/tree.spec.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/installer.d.ts +13 -0
- package/dist/installer.d.ts.map +1 -0
- package/dist/installer.js +171 -0
- package/dist/installer.js.map +1 -0
- package/dist/store.d.ts +78 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +344 -0
- package/dist/store.js.map +1 -0
- package/dist/types.d.ts +235 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/docs/README.md +68 -0
- package/docs/inspection/consumers.md +178 -0
- package/docs/inspection/list.md +182 -0
- package/docs/inspection/resolve.md +172 -0
- package/docs/installation/configuration.md +238 -0
- package/docs/installation/install.md +184 -0
- package/docs/maintenance/prune.md +159 -0
- package/docs/maintenance/remove.md +174 -0
- package/docs/maintenance/verify.md +174 -0
- package/docs/publishing/publish.md +146 -0
- package/docs/publishing/push.md +146 -0
- package/docs/store/locking.md +118 -0
- package/docs/store/namespaces.md +141 -0
- package/docs/store/structure.md +163 -0
- package/package.json +58 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,880 @@
|
|
|
1
|
+
# DevLink - Agent Guide
|
|
2
|
+
|
|
3
|
+
Complete reference for AI agents to use DevLink, a local package development and linking tool with namespace support.
|
|
4
|
+
|
|
5
|
+
## What is DevLink?
|
|
6
|
+
|
|
7
|
+
DevLink is a tool for managing npm packages during local development. Instead of publishing to npm registry, packages are published to a local store and linked into consumer projects. This enables:
|
|
8
|
+
|
|
9
|
+
- Instant updates during development (no npm publish cycle)
|
|
10
|
+
- Multiple versions of the same package coexisting
|
|
11
|
+
- Isolated namespaces for feature branches
|
|
12
|
+
- Automatic propagation of changes to all consumers
|
|
13
|
+
|
|
14
|
+
## Core Concepts
|
|
15
|
+
|
|
16
|
+
### Store
|
|
17
|
+
|
|
18
|
+
The store is a centralized repository for locally published packages.
|
|
19
|
+
|
|
20
|
+
**Default location**: `~/.devlink/`
|
|
21
|
+
|
|
22
|
+
**Custom location**: Use `--repo <path>` flag or `DEVLINK_REPO` environment variable.
|
|
23
|
+
|
|
24
|
+
**Structure**:
|
|
25
|
+
```
|
|
26
|
+
~/.devlink/
|
|
27
|
+
├── .lock # Write serialization lock
|
|
28
|
+
├── registry.json # Package metadata index
|
|
29
|
+
├── installations.json # Consumer project tracking
|
|
30
|
+
└── namespaces/
|
|
31
|
+
├── global/ # Default namespace (reserved, cannot be deleted)
|
|
32
|
+
│ ├── @scope/ # Scoped packages
|
|
33
|
+
│ │ └── package/
|
|
34
|
+
│ │ └── 1.0.0/ # Version directory
|
|
35
|
+
│ │ ├── package.json
|
|
36
|
+
│ │ ├── devlink.sig # Content signature (MD5)
|
|
37
|
+
│ │ └── dist/ # Package files
|
|
38
|
+
│ └── simple-pkg/ # Non-scoped packages
|
|
39
|
+
│ └── 1.0.0/
|
|
40
|
+
└── feature-branch/ # Custom namespaces
|
|
41
|
+
└── @scope/
|
|
42
|
+
└── package/
|
|
43
|
+
└── 1.0.0/ # Same version, different content
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Namespaces
|
|
47
|
+
|
|
48
|
+
Namespaces are isolated containers for packages. Key points:
|
|
49
|
+
|
|
50
|
+
- **`global`** is the default namespace and cannot be deleted
|
|
51
|
+
- Same package@version can exist in multiple namespaces with different content
|
|
52
|
+
- Namespaces are created automatically when publishing to them
|
|
53
|
+
- Useful for feature branches, team isolation, or version testing
|
|
54
|
+
|
|
55
|
+
**Precedence**: When resolving packages, namespaces are searched in order:
|
|
56
|
+
```javascript
|
|
57
|
+
namespaces: ["feature-v2", "global"]
|
|
58
|
+
// 1. Search feature-v2 first
|
|
59
|
+
// 2. If not found, search global
|
|
60
|
+
// 3. If not found anywhere, error
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Registry (registry.json)
|
|
64
|
+
|
|
65
|
+
Index of all published packages:
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"version": "1.0.0",
|
|
69
|
+
"namespaces": {
|
|
70
|
+
"global": {
|
|
71
|
+
"created": "2026-02-12T10:00:00Z",
|
|
72
|
+
"packages": {
|
|
73
|
+
"@scope/package": {
|
|
74
|
+
"versions": {
|
|
75
|
+
"1.0.0": {
|
|
76
|
+
"signature": "6761ca1fefdde1b6e9ea372e7d6931e4",
|
|
77
|
+
"published": "2026-02-12T10:00:00Z",
|
|
78
|
+
"files": 15
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Installations (installations.json)
|
|
89
|
+
|
|
90
|
+
Tracks which projects have installed packages (used by `push` command):
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"version": "1.0.0",
|
|
94
|
+
"projects": {
|
|
95
|
+
"/home/user/my-project": {
|
|
96
|
+
"registered": "2026-02-12T10:00:00Z",
|
|
97
|
+
"packages": {
|
|
98
|
+
"@scope/package": {
|
|
99
|
+
"version": "1.0.0",
|
|
100
|
+
"namespace": "global",
|
|
101
|
+
"signature": "6761ca1f...",
|
|
102
|
+
"installedAt": "2026-02-12T10:05:00Z"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### File Locking
|
|
111
|
+
|
|
112
|
+
Write operations acquire an exclusive lock to prevent corruption:
|
|
113
|
+
|
|
114
|
+
| Operation | Lock Required | Reason |
|
|
115
|
+
|-----------|---------------|--------|
|
|
116
|
+
| `publish` | ✓ | Modifies registry, writes files |
|
|
117
|
+
| `push` | ✓ | Modifies registry, installations |
|
|
118
|
+
| `install` | ✓ | Modifies installations |
|
|
119
|
+
| `remove` | ✓ | Modifies registry, deletes files |
|
|
120
|
+
| `verify --fix` | ✓ | Modifies registry |
|
|
121
|
+
| `prune` | ✓ | Modifies registry, deletes files |
|
|
122
|
+
| `consumers --prune` | ✓ | Modifies installations |
|
|
123
|
+
| `list` | ✗ | Read-only |
|
|
124
|
+
| `resolve` | ✗ | Read-only |
|
|
125
|
+
| `verify` | ✗ | Read-only |
|
|
126
|
+
| `consumers` | ✗ | Read-only |
|
|
127
|
+
|
|
128
|
+
Lock parameters: 30s timeout, 100ms retry interval, stale lock detection (removes locks from dead processes).
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## CLI Reference
|
|
133
|
+
|
|
134
|
+
### Global Options
|
|
135
|
+
|
|
136
|
+
All commands support:
|
|
137
|
+
|
|
138
|
+
| Option | Description |
|
|
139
|
+
|--------|-------------|
|
|
140
|
+
| `--repo <path>` | Use custom store path instead of `~/.devlink` |
|
|
141
|
+
| `-h, --help` | Show help |
|
|
142
|
+
| `-v, --version` | Show version |
|
|
143
|
+
|
|
144
|
+
Environment: `DEVLINK_REPO` can be used instead of `--repo`.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Commands
|
|
149
|
+
|
|
150
|
+
### devlink publish
|
|
151
|
+
|
|
152
|
+
Publishes the package in the current directory to the store.
|
|
153
|
+
|
|
154
|
+
**Usage**:
|
|
155
|
+
```bash
|
|
156
|
+
devlink publish [options]
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Options**:
|
|
160
|
+
| Option | Description |
|
|
161
|
+
|--------|-------------|
|
|
162
|
+
| `-n, --namespace <name>` | Target namespace (default: `global`) |
|
|
163
|
+
|
|
164
|
+
**Requirements**: `package.json` must have `name`, `version`, and `files` fields.
|
|
165
|
+
|
|
166
|
+
**What it does**:
|
|
167
|
+
1. Reads `package.json` from current directory
|
|
168
|
+
2. Validates name and version exist
|
|
169
|
+
3. Copies files specified in `files` field to store
|
|
170
|
+
4. Generates content signature (MD5 hash)
|
|
171
|
+
5. Updates registry.json
|
|
172
|
+
|
|
173
|
+
**Examples**:
|
|
174
|
+
```bash
|
|
175
|
+
# Publish to global namespace
|
|
176
|
+
cd /path/to/my-package
|
|
177
|
+
devlink publish
|
|
178
|
+
|
|
179
|
+
# Publish to custom namespace
|
|
180
|
+
devlink publish -n feature-v2
|
|
181
|
+
|
|
182
|
+
# Publish to custom repo
|
|
183
|
+
devlink publish --repo /tmp/my-repo
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**Output**:
|
|
187
|
+
```
|
|
188
|
+
📦 @scope/my-package@1.0.0 published to global
|
|
189
|
+
Signature: 6761ca1fefdde1b6e9ea372e7d6931e4
|
|
190
|
+
Files: 15
|
|
191
|
+
Path: ~/.devlink/namespaces/global/@scope/my-package/1.0.0
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
### devlink push
|
|
197
|
+
|
|
198
|
+
Publishes the package AND automatically updates all consumer projects.
|
|
199
|
+
|
|
200
|
+
**Usage**:
|
|
201
|
+
```bash
|
|
202
|
+
devlink push [options]
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Options**:
|
|
206
|
+
| Option | Description |
|
|
207
|
+
|--------|-------------|
|
|
208
|
+
| `-n, --namespace <name>` | Target namespace (default: `global`) |
|
|
209
|
+
|
|
210
|
+
**What it does**:
|
|
211
|
+
1. Publishes package (same as `devlink publish`)
|
|
212
|
+
2. Finds all projects in installations.json that use this package
|
|
213
|
+
3. Re-links the package in each consumer's node_modules
|
|
214
|
+
4. Updates signatures in installations.json
|
|
215
|
+
5. Updates devlink.lock in each consumer project
|
|
216
|
+
|
|
217
|
+
**Examples**:
|
|
218
|
+
```bash
|
|
219
|
+
# Push to global, update all consumers
|
|
220
|
+
devlink push
|
|
221
|
+
|
|
222
|
+
# Push to feature namespace
|
|
223
|
+
devlink push -n feature-v2
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Output**:
|
|
227
|
+
```
|
|
228
|
+
📦 @scope/core@1.0.0 published to global
|
|
229
|
+
Signature: abc123new
|
|
230
|
+
|
|
231
|
+
🔄 Pushing to 2 project(s):
|
|
232
|
+
✓ /home/user/project-a
|
|
233
|
+
✓ /home/user/project-b
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**Use case**: During active development, use `push` instead of `publish` to automatically propagate changes.
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
### devlink install
|
|
241
|
+
|
|
242
|
+
Installs packages from the store into a project based on configuration.
|
|
243
|
+
|
|
244
|
+
**Usage**:
|
|
245
|
+
```bash
|
|
246
|
+
devlink install [options]
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
**Options**:
|
|
250
|
+
| Option | Description |
|
|
251
|
+
|--------|-------------|
|
|
252
|
+
| `-n, --namespaces <list>` | Override namespace precedence (comma-separated) |
|
|
253
|
+
| `-c, --config <path>` | Path to config file |
|
|
254
|
+
| `--dev` | Force dev mode |
|
|
255
|
+
| `--prod` | Force prod mode |
|
|
256
|
+
|
|
257
|
+
**Configuration file** (`devlink.config.mjs`):
|
|
258
|
+
```javascript
|
|
259
|
+
export default {
|
|
260
|
+
// Packages to manage with versions per mode
|
|
261
|
+
packages: {
|
|
262
|
+
"@scope/core": { dev: "1.0.0", prod: "1.0.0" },
|
|
263
|
+
"@scope/utils": { dev: "2.0.0", prod: "1.5.0" },
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
// Development mode configuration
|
|
267
|
+
dev: (ctx) => ({
|
|
268
|
+
manager: "store", // Use DevLink store
|
|
269
|
+
namespaces: ["feature-v2", "global"], // Search order
|
|
270
|
+
}),
|
|
271
|
+
|
|
272
|
+
// Production mode configuration
|
|
273
|
+
prod: (ctx) => ({
|
|
274
|
+
manager: "npm", // Use npm registry
|
|
275
|
+
args: ["--no-save"], // npm arguments
|
|
276
|
+
}),
|
|
277
|
+
|
|
278
|
+
// Mode detection logic
|
|
279
|
+
detectMode: (ctx) => {
|
|
280
|
+
// ctx.env - environment variables
|
|
281
|
+
// ctx.args - command line arguments
|
|
282
|
+
// ctx.cwd - current working directory
|
|
283
|
+
if (ctx.env.NODE_ENV === "development") return "dev";
|
|
284
|
+
if (ctx.args.includes("--dev")) return "dev";
|
|
285
|
+
return "prod";
|
|
286
|
+
},
|
|
287
|
+
};
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**What it does**:
|
|
291
|
+
1. Reads devlink.config.mjs
|
|
292
|
+
2. Determines mode (dev/prod)
|
|
293
|
+
3. For each package, resolves using namespace precedence
|
|
294
|
+
4. Creates symlinks in node_modules
|
|
295
|
+
5. Registers project in installations.json
|
|
296
|
+
6. Creates/updates devlink.lock
|
|
297
|
+
|
|
298
|
+
**Examples**:
|
|
299
|
+
```bash
|
|
300
|
+
# Install using config file
|
|
301
|
+
devlink install
|
|
302
|
+
|
|
303
|
+
# Force dev mode
|
|
304
|
+
devlink install --dev
|
|
305
|
+
|
|
306
|
+
# Override namespaces
|
|
307
|
+
devlink install -n feature-v2,global
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
**Lock file** (`devlink.lock`):
|
|
311
|
+
```json
|
|
312
|
+
{
|
|
313
|
+
"packages": {
|
|
314
|
+
"@scope/core": {
|
|
315
|
+
"version": "1.0.0",
|
|
316
|
+
"namespace": "global",
|
|
317
|
+
"signature": "6761ca1f...",
|
|
318
|
+
"resolved": "~/.devlink/namespaces/global/@scope/core/1.0.0"
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
### devlink list
|
|
327
|
+
|
|
328
|
+
Lists packages in the store.
|
|
329
|
+
|
|
330
|
+
**Usage**:
|
|
331
|
+
```bash
|
|
332
|
+
devlink list [options]
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
**Options**:
|
|
336
|
+
| Option | Description |
|
|
337
|
+
|--------|-------------|
|
|
338
|
+
| `-n, --namespaces <list>` | Filter by namespaces (comma-separated) |
|
|
339
|
+
| `-p, --packages [list]` | Group by package, optionally filter |
|
|
340
|
+
| `--flat` | Flat output format (default: tree) |
|
|
341
|
+
|
|
342
|
+
**Examples**:
|
|
343
|
+
```bash
|
|
344
|
+
# List all packages (tree format)
|
|
345
|
+
devlink list
|
|
346
|
+
|
|
347
|
+
# Flat format (good for scripting)
|
|
348
|
+
devlink list --flat
|
|
349
|
+
|
|
350
|
+
# Filter by namespace
|
|
351
|
+
devlink list -n global
|
|
352
|
+
|
|
353
|
+
# Filter by scope
|
|
354
|
+
devlink list -p @myorg
|
|
355
|
+
|
|
356
|
+
# Group by package instead of namespace
|
|
357
|
+
devlink list -p
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
**Tree output**:
|
|
361
|
+
```
|
|
362
|
+
📦 Dev-Link Store
|
|
363
|
+
|
|
364
|
+
global/
|
|
365
|
+
├── @scope/
|
|
366
|
+
│ ├── core/
|
|
367
|
+
│ │ ├── 1.0.0 (6761ca1f)
|
|
368
|
+
│ │ └── 2.0.0 (a1b2c3d4)
|
|
369
|
+
│ └── utils/
|
|
370
|
+
│ └── 1.0.0 (b2c3d4e5)
|
|
371
|
+
└── simple-pkg/
|
|
372
|
+
└── 1.0.0 (c3d4e5f6)
|
|
373
|
+
|
|
374
|
+
feature-v2/
|
|
375
|
+
└── @scope/
|
|
376
|
+
└── core/
|
|
377
|
+
└── 1.0.0 (different1)
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
**Flat output**:
|
|
381
|
+
```
|
|
382
|
+
global @scope/core@1.0.0 6761ca1f
|
|
383
|
+
global @scope/core@2.0.0 a1b2c3d4
|
|
384
|
+
global @scope/utils@1.0.0 b2c3d4e5
|
|
385
|
+
feature-v2 @scope/core@1.0.0 different1
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
### devlink resolve
|
|
391
|
+
|
|
392
|
+
Debug package resolution - shows where packages would be found.
|
|
393
|
+
|
|
394
|
+
**Usage**:
|
|
395
|
+
```bash
|
|
396
|
+
devlink resolve <pkg@version> [...] [options]
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
**Options**:
|
|
400
|
+
| Option | Description |
|
|
401
|
+
|--------|-------------|
|
|
402
|
+
| `-n, --namespaces <list>` | Namespace precedence (comma-separated) |
|
|
403
|
+
| `--flat` | Flat output format |
|
|
404
|
+
|
|
405
|
+
**Examples**:
|
|
406
|
+
```bash
|
|
407
|
+
# Resolve single package
|
|
408
|
+
devlink resolve @scope/core@1.0.0
|
|
409
|
+
|
|
410
|
+
# Resolve with namespace precedence
|
|
411
|
+
devlink resolve @scope/core@1.0.0 -n feature-v2,global
|
|
412
|
+
|
|
413
|
+
# Resolve multiple packages
|
|
414
|
+
devlink resolve @scope/core@1.0.0 @scope/utils@2.0.0 -n feature-v2,global
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
**Output**:
|
|
418
|
+
```
|
|
419
|
+
Resolving with precedence: feature-v2 → global
|
|
420
|
+
|
|
421
|
+
@scope/core@1.0.0
|
|
422
|
+
✓ Found in: feature-v2
|
|
423
|
+
Path: ~/.devlink/namespaces/feature-v2/@scope/core/1.0.0
|
|
424
|
+
Signature: different123456
|
|
425
|
+
|
|
426
|
+
@scope/utils@2.0.0
|
|
427
|
+
⊘ Not in: feature-v2
|
|
428
|
+
✓ Found in: global
|
|
429
|
+
Path: ~/.devlink/namespaces/global/@scope/utils/2.0.0
|
|
430
|
+
Signature: a1b2c3d4
|
|
431
|
+
|
|
432
|
+
Summary: 2/2 resolved
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
**Not found**:
|
|
436
|
+
```
|
|
437
|
+
@scope/missing@1.0.0
|
|
438
|
+
⊘ Not in: feature-v2
|
|
439
|
+
⊘ Not in: global
|
|
440
|
+
✗ Not found in any namespace
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
### devlink consumers
|
|
446
|
+
|
|
447
|
+
Lists projects that have installed packages from the store.
|
|
448
|
+
|
|
449
|
+
**Usage**:
|
|
450
|
+
```bash
|
|
451
|
+
devlink consumers [options]
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
**Options**:
|
|
455
|
+
| Option | Description |
|
|
456
|
+
|--------|-------------|
|
|
457
|
+
| `-p, --package <name>` | Filter by package name |
|
|
458
|
+
| `-n, --namespace <name>` | Filter by namespace |
|
|
459
|
+
| `--prune` | Remove projects that no longer exist |
|
|
460
|
+
| `--flat` | Flat output format |
|
|
461
|
+
|
|
462
|
+
**Examples**:
|
|
463
|
+
```bash
|
|
464
|
+
# List all consumers
|
|
465
|
+
devlink consumers
|
|
466
|
+
|
|
467
|
+
# Filter by package
|
|
468
|
+
devlink consumers -p @scope/core
|
|
469
|
+
|
|
470
|
+
# Filter by namespace
|
|
471
|
+
devlink consumers -n feature-v2
|
|
472
|
+
|
|
473
|
+
# Remove dead projects
|
|
474
|
+
devlink consumers --prune
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
**Output**:
|
|
478
|
+
```
|
|
479
|
+
📦 Consumer Projects
|
|
480
|
+
|
|
481
|
+
/home/user/project-a
|
|
482
|
+
├── @scope/core@1.0.0 (global)
|
|
483
|
+
├── @scope/utils@1.0.0 (global)
|
|
484
|
+
└── Registered: 2026-02-12T10:00:00Z
|
|
485
|
+
|
|
486
|
+
/home/user/project-b
|
|
487
|
+
├── @scope/core@1.0.0 (feature-v2)
|
|
488
|
+
└── Registered: 2026-02-12T11:00:00Z
|
|
489
|
+
|
|
490
|
+
Total: 2 projects, 3 installations
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
---
|
|
494
|
+
|
|
495
|
+
### devlink remove
|
|
496
|
+
|
|
497
|
+
Removes packages, versions, or namespaces from the store.
|
|
498
|
+
|
|
499
|
+
**Usage**:
|
|
500
|
+
```bash
|
|
501
|
+
devlink remove <target> [options]
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
**Options**:
|
|
505
|
+
| Option | Description |
|
|
506
|
+
|--------|-------------|
|
|
507
|
+
| `-n, --namespace <name>` | Target namespace (required for packages) |
|
|
508
|
+
|
|
509
|
+
**Target types**:
|
|
510
|
+
|
|
511
|
+
| Target | Example | Description |
|
|
512
|
+
|--------|---------|-------------|
|
|
513
|
+
| Version | `@scope/pkg@1.0.0` | Remove specific version |
|
|
514
|
+
| Package | `@scope/pkg` | Remove all versions |
|
|
515
|
+
| Namespace | `feature-v2` | Remove entire namespace |
|
|
516
|
+
|
|
517
|
+
**Examples**:
|
|
518
|
+
```bash
|
|
519
|
+
# Remove specific version
|
|
520
|
+
devlink remove @scope/core@1.0.0 -n global
|
|
521
|
+
|
|
522
|
+
# Remove all versions of a package
|
|
523
|
+
devlink remove @scope/core -n global
|
|
524
|
+
|
|
525
|
+
# Remove entire namespace
|
|
526
|
+
devlink remove feature-v2
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
**Restrictions**:
|
|
530
|
+
- Cannot remove `global` namespace (reserved)
|
|
531
|
+
- Must specify `-n` when removing packages
|
|
532
|
+
|
|
533
|
+
**Output**:
|
|
534
|
+
```
|
|
535
|
+
✓ Removed @scope/core@1.0.0 from namespace 'global'
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
---
|
|
539
|
+
|
|
540
|
+
### devlink verify
|
|
541
|
+
|
|
542
|
+
Verifies store integrity - checks for inconsistencies between registry and disk.
|
|
543
|
+
|
|
544
|
+
**Usage**:
|
|
545
|
+
```bash
|
|
546
|
+
devlink verify [options]
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
**Options**:
|
|
550
|
+
| Option | Description |
|
|
551
|
+
|--------|-------------|
|
|
552
|
+
| `--fix` | Automatically fix issues found |
|
|
553
|
+
|
|
554
|
+
**Checks performed**:
|
|
555
|
+
- **Orphans in registry**: Entries without corresponding files on disk
|
|
556
|
+
- **Orphans on disk**: Files without registry entries
|
|
557
|
+
- **Signature mismatches**: Content doesn't match recorded signature
|
|
558
|
+
|
|
559
|
+
**Examples**:
|
|
560
|
+
```bash
|
|
561
|
+
# Check only
|
|
562
|
+
devlink verify
|
|
563
|
+
|
|
564
|
+
# Check and fix
|
|
565
|
+
devlink verify --fix
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
**Output (issues found)**:
|
|
569
|
+
```
|
|
570
|
+
🔍 Verifying store integrity...
|
|
571
|
+
|
|
572
|
+
global/
|
|
573
|
+
✓ @scope/core@1.0.0
|
|
574
|
+
✗ @scope/data@1.0.0 - In registry, not on disk
|
|
575
|
+
✓ @scope/utils@1.0.0
|
|
576
|
+
⚠ @scope/orphan@1.0.0 - On disk, not in registry
|
|
577
|
+
|
|
578
|
+
─────────────────────────────────
|
|
579
|
+
Summary:
|
|
580
|
+
✓ Valid: 2
|
|
581
|
+
✗ Orphans in registry: 1
|
|
582
|
+
⚠ Orphans on disk: 1
|
|
583
|
+
|
|
584
|
+
Run 'devlink verify --fix' to repair
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
---
|
|
588
|
+
|
|
589
|
+
### devlink prune
|
|
590
|
+
|
|
591
|
+
Removes orphaned packages from disk (files not in registry).
|
|
592
|
+
|
|
593
|
+
**Usage**:
|
|
594
|
+
```bash
|
|
595
|
+
devlink prune [options]
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
**Options**:
|
|
599
|
+
| Option | Description |
|
|
600
|
+
|--------|-------------|
|
|
601
|
+
| `-n, --namespace <name>` | Only prune in specific namespace |
|
|
602
|
+
| `--dry-run` | Show what would be removed without removing |
|
|
603
|
+
|
|
604
|
+
**Examples**:
|
|
605
|
+
```bash
|
|
606
|
+
# Remove all orphans
|
|
607
|
+
devlink prune
|
|
608
|
+
|
|
609
|
+
# Preview only
|
|
610
|
+
devlink prune --dry-run
|
|
611
|
+
|
|
612
|
+
# Prune specific namespace
|
|
613
|
+
devlink prune -n feature-v2
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
**Output**:
|
|
617
|
+
```
|
|
618
|
+
🧹 Pruning orphaned packages...
|
|
619
|
+
|
|
620
|
+
Removed:
|
|
621
|
+
✓ global/@scope/orphan@1.0.0
|
|
622
|
+
✓ feature-v2/@scope/old-pkg@2.0.0
|
|
623
|
+
|
|
624
|
+
Pruned 2 package(s), freed 15.2 MB
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
---
|
|
628
|
+
|
|
629
|
+
### devlink docs
|
|
630
|
+
|
|
631
|
+
Display embedded documentation directly from the CLI.
|
|
632
|
+
|
|
633
|
+
**Usage**:
|
|
634
|
+
```bash
|
|
635
|
+
devlink docs [document]
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
**Arguments**:
|
|
639
|
+
| Argument | Description |
|
|
640
|
+
|----------|-------------|
|
|
641
|
+
| `[document]` | Document or directory path (case insensitive, .md optional) |
|
|
642
|
+
|
|
643
|
+
**Behavior**:
|
|
644
|
+
- No argument: shows documentation tree
|
|
645
|
+
- Directory path: lists documents in that directory
|
|
646
|
+
- File path: displays document content
|
|
647
|
+
|
|
648
|
+
**Examples**:
|
|
649
|
+
```bash
|
|
650
|
+
# Show documentation tree
|
|
651
|
+
devlink docs
|
|
652
|
+
|
|
653
|
+
# Show AI agent guide (comprehensive)
|
|
654
|
+
devlink docs agents
|
|
655
|
+
|
|
656
|
+
# List store documents
|
|
657
|
+
devlink docs store
|
|
658
|
+
|
|
659
|
+
# Show specific document
|
|
660
|
+
devlink docs store/namespaces
|
|
661
|
+
devlink docs STORE/NAMESPACES # Case insensitive
|
|
662
|
+
devlink docs publishing/push
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
**Output (tree)**:
|
|
666
|
+
```
|
|
667
|
+
📚 DevLink Documentation
|
|
668
|
+
|
|
669
|
+
├── agents
|
|
670
|
+
├── inspection/
|
|
671
|
+
│ ├── consumers
|
|
672
|
+
│ ├── list
|
|
673
|
+
│ └── resolve
|
|
674
|
+
├── installation/
|
|
675
|
+
│ ├── configuration
|
|
676
|
+
│ └── install
|
|
677
|
+
├── maintenance/
|
|
678
|
+
│ ├── prune
|
|
679
|
+
│ ├── remove
|
|
680
|
+
│ └── verify
|
|
681
|
+
├── publishing/
|
|
682
|
+
│ ├── publish
|
|
683
|
+
│ └── push
|
|
684
|
+
└── store/
|
|
685
|
+
├── locking
|
|
686
|
+
├── namespaces
|
|
687
|
+
└── structure
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
**Special documents**:
|
|
691
|
+
- `agents` - Complete self-contained guide for AI agents (this document)
|
|
692
|
+
|
|
693
|
+
---
|
|
694
|
+
|
|
695
|
+
## Common Workflows
|
|
696
|
+
|
|
697
|
+
### Initial Setup: Publish a Library
|
|
698
|
+
|
|
699
|
+
```bash
|
|
700
|
+
cd /path/to/my-library
|
|
701
|
+
# Ensure package.json has name, version, files fields
|
|
702
|
+
devlink publish
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
### Setup Consumer Project
|
|
706
|
+
|
|
707
|
+
1. Create `devlink.config.mjs`:
|
|
708
|
+
```javascript
|
|
709
|
+
export default {
|
|
710
|
+
packages: {
|
|
711
|
+
"@myorg/core": { dev: "1.0.0" },
|
|
712
|
+
"@myorg/utils": { dev: "1.0.0" },
|
|
713
|
+
},
|
|
714
|
+
dev: () => ({
|
|
715
|
+
manager: "store",
|
|
716
|
+
namespaces: ["global"],
|
|
717
|
+
}),
|
|
718
|
+
};
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
2. Install:
|
|
722
|
+
```bash
|
|
723
|
+
devlink install --dev
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
### Development Cycle
|
|
727
|
+
|
|
728
|
+
```bash
|
|
729
|
+
# Make changes to library
|
|
730
|
+
cd /path/to/my-library
|
|
731
|
+
vim src/index.ts
|
|
732
|
+
npm run build
|
|
733
|
+
|
|
734
|
+
# Push to all consumers
|
|
735
|
+
devlink push
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
### Feature Branch Development
|
|
739
|
+
|
|
740
|
+
```bash
|
|
741
|
+
# Publish to feature namespace
|
|
742
|
+
cd /path/to/my-library
|
|
743
|
+
devlink publish -n feature-auth-v2
|
|
744
|
+
|
|
745
|
+
# Consumer uses feature namespace first
|
|
746
|
+
# devlink.config.mjs: namespaces: ["feature-auth-v2", "global"]
|
|
747
|
+
cd /path/to/consumer
|
|
748
|
+
devlink install --dev
|
|
749
|
+
|
|
750
|
+
# After feature is merged, clean up
|
|
751
|
+
devlink remove feature-auth-v2
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
### Debug Resolution Issues
|
|
755
|
+
|
|
756
|
+
```bash
|
|
757
|
+
# Check where package would be resolved from
|
|
758
|
+
devlink resolve @myorg/core@1.0.0 -n feature-v2,global
|
|
759
|
+
|
|
760
|
+
# List all packages to see what's available
|
|
761
|
+
devlink list
|
|
762
|
+
|
|
763
|
+
# Check who's using a package
|
|
764
|
+
devlink consumers -p @myorg/core
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
### Store Maintenance
|
|
768
|
+
|
|
769
|
+
```bash
|
|
770
|
+
# Verify store health
|
|
771
|
+
devlink verify
|
|
772
|
+
|
|
773
|
+
# Fix any issues
|
|
774
|
+
devlink verify --fix
|
|
775
|
+
|
|
776
|
+
# Clean up orphaned files
|
|
777
|
+
devlink prune --dry-run # Preview first
|
|
778
|
+
devlink prune # Actually clean
|
|
779
|
+
|
|
780
|
+
# Remove dead consumer projects
|
|
781
|
+
devlink consumers --prune
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
### Multiple Repos
|
|
785
|
+
|
|
786
|
+
```bash
|
|
787
|
+
# Use different repos for different contexts
|
|
788
|
+
devlink --repo ~/repos/team-a publish
|
|
789
|
+
devlink --repo ~/repos/team-b publish
|
|
790
|
+
|
|
791
|
+
# Or via environment variable
|
|
792
|
+
export DEVLINK_REPO=~/repos/team-a
|
|
793
|
+
devlink list
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
---
|
|
797
|
+
|
|
798
|
+
## Error Handling
|
|
799
|
+
|
|
800
|
+
### Package Not Found
|
|
801
|
+
```
|
|
802
|
+
Error: @scope/core@1.0.0 not found in namespaces: feature-v2, global
|
|
803
|
+
```
|
|
804
|
+
**Solution**: Publish the package first, or check namespace configuration.
|
|
805
|
+
|
|
806
|
+
### Missing package.json
|
|
807
|
+
```
|
|
808
|
+
Error: package.json not found
|
|
809
|
+
```
|
|
810
|
+
**Solution**: Run from a directory with a valid package.json.
|
|
811
|
+
|
|
812
|
+
### Missing name or version
|
|
813
|
+
```
|
|
814
|
+
Error: package.json must have name and version fields
|
|
815
|
+
```
|
|
816
|
+
**Solution**: Add required fields to package.json.
|
|
817
|
+
|
|
818
|
+
### Cannot remove global namespace
|
|
819
|
+
```
|
|
820
|
+
Error: Cannot delete reserved namespace 'global'
|
|
821
|
+
```
|
|
822
|
+
**Solution**: The global namespace cannot be deleted. Remove individual packages instead.
|
|
823
|
+
|
|
824
|
+
### Lock timeout
|
|
825
|
+
```
|
|
826
|
+
Error: Lock timeout after 30000ms
|
|
827
|
+
```
|
|
828
|
+
**Solution**: Another process is holding the lock. Wait or check for stale locks.
|
|
829
|
+
|
|
830
|
+
---
|
|
831
|
+
|
|
832
|
+
## Source Code Structure
|
|
833
|
+
|
|
834
|
+
```
|
|
835
|
+
src/
|
|
836
|
+
├── cli-new.ts # CLI entry point, argument parsing
|
|
837
|
+
├── constants.ts # Paths, defaults, repo configuration
|
|
838
|
+
├── types.ts # TypeScript type definitions
|
|
839
|
+
├── core/
|
|
840
|
+
│ ├── lock.ts # File locking implementation
|
|
841
|
+
│ ├── registry.ts # Registry read/write operations
|
|
842
|
+
│ ├── installations.ts # Consumer tracking operations
|
|
843
|
+
│ ├── store.ts # Filesystem operations (copy, delete, etc.)
|
|
844
|
+
│ └── resolver.ts # Package resolution algorithm
|
|
845
|
+
├── commands/
|
|
846
|
+
│ ├── publish.ts # Publish command
|
|
847
|
+
│ ├── push.ts # Push command
|
|
848
|
+
│ ├── install.ts # Install command
|
|
849
|
+
│ ├── list.ts # List command
|
|
850
|
+
│ ├── resolve.ts # Resolve command
|
|
851
|
+
│ ├── consumers.ts # Consumers command
|
|
852
|
+
│ ├── remove.ts # Remove command
|
|
853
|
+
│ ├── verify.ts # Verify command
|
|
854
|
+
│ └── prune.ts # Prune command
|
|
855
|
+
└── formatters/
|
|
856
|
+
├── tree.ts # Tree output format
|
|
857
|
+
└── flat.ts # Flat output format
|
|
858
|
+
```
|
|
859
|
+
|
|
860
|
+
---
|
|
861
|
+
|
|
862
|
+
## Testing
|
|
863
|
+
|
|
864
|
+
```bash
|
|
865
|
+
npm test # Run all tests
|
|
866
|
+
npm run test:coverage # With coverage report
|
|
867
|
+
```
|
|
868
|
+
|
|
869
|
+
Test fixtures are in `fixtures/packages/` for integration testing.
|
|
870
|
+
|
|
871
|
+
---
|
|
872
|
+
|
|
873
|
+
## Further Reading
|
|
874
|
+
|
|
875
|
+
For detailed documentation on specific topics, see the `docs/` directory:
|
|
876
|
+
- `docs/store/` - Store structure, namespaces, locking
|
|
877
|
+
- `docs/publishing/` - Publish and push commands
|
|
878
|
+
- `docs/installation/` - Install command and configuration
|
|
879
|
+
- `docs/inspection/` - List, resolve, consumers commands
|
|
880
|
+
- `docs/maintenance/` - Remove, verify, prune commands
|