@procedures/pnpm 0.0.0-stage → 0.2.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 +26 -0
- package/LICENSE +21 -0
- package/README.md +792 -2
- package/dist/.tsbuildinfo +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/module.d.ts +21 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +132 -0
- package/dist/module.js.map +1 -0
- package/dist/procedures/pnpm/add.d.ts +25 -0
- package/dist/procedures/pnpm/add.d.ts.map +1 -0
- package/dist/procedures/pnpm/add.js +34 -0
- package/dist/procedures/pnpm/add.js.map +1 -0
- package/dist/procedures/pnpm/index.d.ts +10 -0
- package/dist/procedures/pnpm/index.d.ts.map +1 -0
- package/dist/procedures/pnpm/index.js +10 -0
- package/dist/procedures/pnpm/index.js.map +1 -0
- package/dist/procedures/pnpm/install.d.ts +23 -0
- package/dist/procedures/pnpm/install.d.ts.map +1 -0
- package/dist/procedures/pnpm/install.js +36 -0
- package/dist/procedures/pnpm/install.js.map +1 -0
- package/dist/procedures/pnpm/link.d.ts +24 -0
- package/dist/procedures/pnpm/link.d.ts.map +1 -0
- package/dist/procedures/pnpm/link.js +35 -0
- package/dist/procedures/pnpm/link.js.map +1 -0
- package/dist/procedures/pnpm/remove.d.ts +18 -0
- package/dist/procedures/pnpm/remove.d.ts.map +1 -0
- package/dist/procedures/pnpm/remove.js +25 -0
- package/dist/procedures/pnpm/remove.js.map +1 -0
- package/dist/procedures/pnpm/run.d.ts +25 -0
- package/dist/procedures/pnpm/run.d.ts.map +1 -0
- package/dist/procedures/pnpm/run.js +33 -0
- package/dist/procedures/pnpm/run.js.map +1 -0
- package/dist/procedures/pnpm/shared.d.ts +25 -0
- package/dist/procedures/pnpm/shared.d.ts.map +1 -0
- package/dist/procedures/pnpm/shared.js +75 -0
- package/dist/procedures/pnpm/shared.js.map +1 -0
- package/dist/procedures/pnpm/store.d.ts +23 -0
- package/dist/procedures/pnpm/store.d.ts.map +1 -0
- package/dist/procedures/pnpm/store.js +85 -0
- package/dist/procedures/pnpm/store.js.map +1 -0
- package/dist/register.d.ts +7 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +9 -0
- package/dist/register.js.map +1 -0
- package/dist/types.d.ts +71 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +98 -0
- package/dist/types.js.map +1 -0
- package/package.json +79 -3
- package/src/index.ts +57 -0
- package/src/module.ts +162 -0
- package/src/procedures/pnpm/add.ts +40 -0
- package/src/procedures/pnpm/index.ts +10 -0
- package/src/procedures/pnpm/install.ts +43 -0
- package/src/procedures/pnpm/link.ts +43 -0
- package/src/procedures/pnpm/remove.ts +32 -0
- package/src/procedures/pnpm/run.ts +41 -0
- package/src/procedures/pnpm/shared.ts +85 -0
- package/src/procedures/pnpm/store.ts +97 -0
- package/src/register.ts +11 -0
- package/src/types.ts +180 -0
package/README.md
CHANGED
|
@@ -1,3 +1,793 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @procedures/pnpm
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@procedures/pnpm)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
> PNPM package manager wrapper - exposes `pnpm.install`, `pnpm.add`, `pnpm.remove`, `pnpm.link`, `pnpm.run`, and `pnpm.store.path` as type-safe RPC procedures.
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
`@procedures/pnpm` wraps pnpm package manager commands as RPC procedures through the client system. It provides 6 procedures for package management operations including installation, adding/removing packages, linking local packages, running scripts, and accessing the pnpm store.
|
|
11
|
+
|
|
12
|
+
This package follows the **CLI Wrapper Pattern** using `client-shell` for command execution with full type safety via Zod schemas.
|
|
13
|
+
|
|
14
|
+
## Architecture
|
|
15
|
+
|
|
16
|
+
```mermaid
|
|
17
|
+
graph TB
|
|
18
|
+
A[client-pnpm] -->|uses| B[client-shell]
|
|
19
|
+
A -->|depends on| C[@procedures/client]
|
|
20
|
+
A -->|validates with| D[zod]
|
|
21
|
+
|
|
22
|
+
E[Application] -->|calls| F[pnpm.* procedures]
|
|
23
|
+
F -->|builds command| G[pnpm CLI]
|
|
24
|
+
F -->|calls| H[shell.run]
|
|
25
|
+
H -->|executes| G
|
|
26
|
+
|
|
27
|
+
I[pnpm.install] -.-> F
|
|
28
|
+
J[pnpm.add/remove] -.-> F
|
|
29
|
+
K[pnpm.link] -.-> F
|
|
30
|
+
L[pnpm.run] -.-> F
|
|
31
|
+
M[pnpm.store.path] -.-> F
|
|
32
|
+
|
|
33
|
+
style A fill:#e1f5ff
|
|
34
|
+
style B fill:#ffe1e1
|
|
35
|
+
style F fill:#e1ffe1
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Procedure Categories
|
|
39
|
+
|
|
40
|
+
```mermaid
|
|
41
|
+
graph LR
|
|
42
|
+
A[client-pnpm<br/>6 Procedures] --> B[Package Management<br/>pnpm.install<br/>pnpm.add<br/>pnpm.remove]
|
|
43
|
+
A --> C[Development<br/>pnpm.link<br/>pnpm.run]
|
|
44
|
+
A --> D[Store Management<br/>pnpm.store.path]
|
|
45
|
+
|
|
46
|
+
style A fill:#e1f5ff
|
|
47
|
+
style B fill:#ffe1e1
|
|
48
|
+
style C fill:#fff4e1
|
|
49
|
+
style D fill:#e1ffe1
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Using pnpm (recommended)
|
|
56
|
+
pnpm add @procedures/pnpm
|
|
57
|
+
|
|
58
|
+
# Using npm
|
|
59
|
+
npm install @procedures/pnpm
|
|
60
|
+
|
|
61
|
+
# Using yarn
|
|
62
|
+
yarn add @procedures/pnpm
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Quick Start
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { Client, LocalTransport, PROCEDURE_REGISTRY } from "@procedures/client";
|
|
69
|
+
import "@procedures/pnpm/register"; // registers its procedures
|
|
70
|
+
|
|
71
|
+
const client = new Client(new LocalTransport({ registry: PROCEDURE_REGISTRY }));
|
|
72
|
+
|
|
73
|
+
// Install all dependencies
|
|
74
|
+
await client.exec(["pnpm", "install"], {
|
|
75
|
+
cwd: "/path/to/project",
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Add a dev dependency
|
|
79
|
+
await client.exec(["pnpm", "add"], {
|
|
80
|
+
packages: ["typescript", "@types/node"],
|
|
81
|
+
dev: true,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Run a script
|
|
85
|
+
await client.exec(["pnpm", "run"], {
|
|
86
|
+
script: "build",
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## API Reference
|
|
91
|
+
|
|
92
|
+
### Procedures
|
|
93
|
+
|
|
94
|
+
#### `pnpm.install`
|
|
95
|
+
|
|
96
|
+
Install dependencies from package.json or specific packages.
|
|
97
|
+
|
|
98
|
+
**Path:** `["pnpm", "install"]`
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
interface PnpmInstallInput {
|
|
102
|
+
/** Packages to install. If not provided, installs from package.json */
|
|
103
|
+
packages?: string[];
|
|
104
|
+
|
|
105
|
+
/** Save as dev dependency */
|
|
106
|
+
dev?: boolean;
|
|
107
|
+
|
|
108
|
+
/** Use frozen lockfile (--frozen-lockfile) */
|
|
109
|
+
frozen?: boolean;
|
|
110
|
+
|
|
111
|
+
/** Working directory */
|
|
112
|
+
cwd?: string;
|
|
113
|
+
|
|
114
|
+
/** Timeout in milliseconds */
|
|
115
|
+
timeout?: number;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
interface PnpmCommandOutput {
|
|
119
|
+
/** Exit code of the command */
|
|
120
|
+
exitCode: number;
|
|
121
|
+
|
|
122
|
+
/** Standard output */
|
|
123
|
+
stdout: string;
|
|
124
|
+
|
|
125
|
+
/** Standard error */
|
|
126
|
+
stderr: string;
|
|
127
|
+
|
|
128
|
+
/** Whether command succeeded (exit code 0) */
|
|
129
|
+
success: boolean;
|
|
130
|
+
|
|
131
|
+
/** Duration in milliseconds */
|
|
132
|
+
duration: number;
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Examples:**
|
|
137
|
+
```typescript
|
|
138
|
+
// Install all from lockfile (CI mode)
|
|
139
|
+
await client.exec(["pnpm", "install"], {
|
|
140
|
+
frozen: true,
|
|
141
|
+
cwd: "/my/project",
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Install specific packages
|
|
145
|
+
await client.exec(["pnpm", "install"], {
|
|
146
|
+
packages: ["lodash", "zod"],
|
|
147
|
+
dev: true,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Install all dependencies
|
|
151
|
+
await client.exec(["pnpm", "install"], {});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
#### `pnpm.add`
|
|
155
|
+
|
|
156
|
+
Add packages to the project.
|
|
157
|
+
|
|
158
|
+
**Path:** `["pnpm", "add"]`
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
interface PnpmAddInput {
|
|
162
|
+
/** Packages to add */
|
|
163
|
+
packages: string[];
|
|
164
|
+
|
|
165
|
+
/** Save as dev dependency */
|
|
166
|
+
dev?: boolean;
|
|
167
|
+
|
|
168
|
+
/** Install globally */
|
|
169
|
+
global?: boolean;
|
|
170
|
+
|
|
171
|
+
/** Working directory */
|
|
172
|
+
cwd?: string;
|
|
173
|
+
|
|
174
|
+
/** Timeout in milliseconds */
|
|
175
|
+
timeout?: number;
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Examples:**
|
|
180
|
+
```typescript
|
|
181
|
+
// Add production dependencies
|
|
182
|
+
await client.exec(["pnpm", "add"], {
|
|
183
|
+
packages: ["express", "cors"],
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// Add dev dependencies
|
|
187
|
+
await client.exec(["pnpm", "add"], {
|
|
188
|
+
packages: ["vitest", "@vitest/coverage-v8", "typescript"],
|
|
189
|
+
dev: true,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Add global tool
|
|
193
|
+
await client.exec(["pnpm", "add"], {
|
|
194
|
+
packages: ["typescript"],
|
|
195
|
+
global: true,
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Add with version
|
|
199
|
+
await client.exec(["pnpm", "add"], {
|
|
200
|
+
packages: ["react@18", "react-dom@18"],
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
#### `pnpm.remove`
|
|
205
|
+
|
|
206
|
+
Remove packages from the project.
|
|
207
|
+
|
|
208
|
+
**Path:** `["pnpm", "remove"]`
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
interface PnpmRemoveInput {
|
|
212
|
+
/** Packages to remove */
|
|
213
|
+
packages: string[];
|
|
214
|
+
|
|
215
|
+
/** Remove from global */
|
|
216
|
+
global?: boolean;
|
|
217
|
+
|
|
218
|
+
/** Working directory */
|
|
219
|
+
cwd?: string;
|
|
220
|
+
|
|
221
|
+
/** Timeout in milliseconds */
|
|
222
|
+
timeout?: number;
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Examples:**
|
|
227
|
+
```typescript
|
|
228
|
+
// Remove packages
|
|
229
|
+
await client.exec(["pnpm", "remove"], {
|
|
230
|
+
packages: ["old-package", "unused-lib"],
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Remove global package
|
|
234
|
+
await client.exec(["pnpm", "remove"], {
|
|
235
|
+
packages: ["typescript"],
|
|
236
|
+
global: true,
|
|
237
|
+
});
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
#### `pnpm.link`
|
|
241
|
+
|
|
242
|
+
Link local packages for development.
|
|
243
|
+
|
|
244
|
+
**Path:** `["pnpm", "link"]`
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
interface PnpmLinkInput {
|
|
248
|
+
/** Path to package to link. If not provided, links current directory globally */
|
|
249
|
+
path?: string;
|
|
250
|
+
|
|
251
|
+
/** Link globally */
|
|
252
|
+
global?: boolean;
|
|
253
|
+
|
|
254
|
+
/** Working directory */
|
|
255
|
+
cwd?: string;
|
|
256
|
+
|
|
257
|
+
/** Timeout in milliseconds */
|
|
258
|
+
timeout?: number;
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
**Examples:**
|
|
263
|
+
```typescript
|
|
264
|
+
// Link current directory globally
|
|
265
|
+
await client.exec(["pnpm", "link"], {
|
|
266
|
+
global: true,
|
|
267
|
+
cwd: "/path/to/my-package",
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// Link a local package into current project
|
|
271
|
+
await client.exec(["pnpm", "link"], {
|
|
272
|
+
path: "../my-local-package",
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
// Link from global to current project
|
|
276
|
+
await client.exec(["pnpm", "link"], {
|
|
277
|
+
path: "my-global-package",
|
|
278
|
+
global: true,
|
|
279
|
+
});
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
#### `pnpm.run`
|
|
283
|
+
|
|
284
|
+
Run package.json scripts.
|
|
285
|
+
|
|
286
|
+
**Path:** `["pnpm", "run"]`
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
interface PnpmRunInput {
|
|
290
|
+
/** Script name to run */
|
|
291
|
+
script: string;
|
|
292
|
+
|
|
293
|
+
/** Additional arguments to pass to the script */
|
|
294
|
+
args?: string[];
|
|
295
|
+
|
|
296
|
+
/** Working directory */
|
|
297
|
+
cwd?: string;
|
|
298
|
+
|
|
299
|
+
/** Timeout in milliseconds */
|
|
300
|
+
timeout?: number;
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
**Examples:**
|
|
305
|
+
```typescript
|
|
306
|
+
// Run build script
|
|
307
|
+
await client.exec(["pnpm", "run"], {
|
|
308
|
+
script: "build",
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// Run test with arguments
|
|
312
|
+
await client.exec(["pnpm", "run"], {
|
|
313
|
+
script: "test",
|
|
314
|
+
args: ["--coverage", "--watch"],
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
// Run custom script in specific directory
|
|
318
|
+
await client.exec(["pnpm", "run"], {
|
|
319
|
+
script: "deploy",
|
|
320
|
+
cwd: "/path/to/project",
|
|
321
|
+
timeout: 600000, // 10 minutes
|
|
322
|
+
});
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
#### `pnpm.store.path`
|
|
326
|
+
|
|
327
|
+
Get the pnpm store path for snapshot/restore operations.
|
|
328
|
+
|
|
329
|
+
**Path:** `["pnpm", "store", "path"]`
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
interface PnpmStorePathInput {
|
|
333
|
+
/** Working directory (affects store path on some configurations) */
|
|
334
|
+
cwd?: string;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
interface PnpmStorePathOutput {
|
|
338
|
+
/** Absolute path to the pnpm store */
|
|
339
|
+
path: string;
|
|
340
|
+
|
|
341
|
+
/** Whether store exists */
|
|
342
|
+
exists: boolean;
|
|
343
|
+
|
|
344
|
+
/** Platform (win32, darwin, linux) */
|
|
345
|
+
platform: string;
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
**Example:**
|
|
350
|
+
```typescript
|
|
351
|
+
const store = await client.exec(["pnpm", "store", "path"], {});
|
|
352
|
+
console.log(`PNPM store: ${store.path}`);
|
|
353
|
+
console.log(`Exists: ${store.exists}`);
|
|
354
|
+
console.log(`Platform: ${store.platform}`);
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
## Complete Procedure List
|
|
358
|
+
|
|
359
|
+
| Procedure | Description |
|
|
360
|
+
|-----------|-------------|
|
|
361
|
+
| `pnpm.install` | Install dependencies from package.json/lockfile |
|
|
362
|
+
| `pnpm.add` | Add packages to project |
|
|
363
|
+
| `pnpm.remove` | Remove packages from project |
|
|
364
|
+
| `pnpm.link` | Link local packages for development |
|
|
365
|
+
| `pnpm.run` | Run package.json scripts |
|
|
366
|
+
| `pnpm.store.path` | Get pnpm store path |
|
|
367
|
+
|
|
368
|
+
## Usage Examples
|
|
369
|
+
|
|
370
|
+
### CI/CD Pipeline
|
|
371
|
+
|
|
372
|
+
```typescript
|
|
373
|
+
// Frozen install for reproducible builds
|
|
374
|
+
const install = await client.exec(["pnpm", "install"], {
|
|
375
|
+
frozen: true,
|
|
376
|
+
cwd: "./project",
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
if (!install.success) {
|
|
380
|
+
throw new Error(`Install failed: ${install.stderr}`);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Run tests
|
|
384
|
+
await client.exec(["pnpm", "run"], {
|
|
385
|
+
script: "test",
|
|
386
|
+
args: ["--coverage"],
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
// Build
|
|
390
|
+
await client.exec(["pnpm", "run"], {
|
|
391
|
+
script: "build",
|
|
392
|
+
});
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Development Workflow
|
|
396
|
+
|
|
397
|
+
```typescript
|
|
398
|
+
// Add dependencies
|
|
399
|
+
await client.exec(["pnpm", "add"], {
|
|
400
|
+
packages: ["react", "react-dom"],
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
await client.exec(["pnpm", "add"], {
|
|
404
|
+
packages: ["@types/react", "@types/react-dom", "vite"],
|
|
405
|
+
dev: true,
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
// Link local packages
|
|
409
|
+
await client.exec(["pnpm", "link"], {
|
|
410
|
+
path: "../shared-components",
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
// Start dev server
|
|
414
|
+
await client.exec(["pnpm", "run"], {
|
|
415
|
+
script: "dev",
|
|
416
|
+
});
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Monorepo Package Management
|
|
420
|
+
|
|
421
|
+
```typescript
|
|
422
|
+
// Install all workspace packages
|
|
423
|
+
await client.exec(["pnpm", "install"], {
|
|
424
|
+
cwd: "/monorepo/root",
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
// Add dependency to specific package
|
|
428
|
+
await client.exec(["pnpm", "add"], {
|
|
429
|
+
packages: ["lodash"],
|
|
430
|
+
cwd: "/monorepo/root/packages/utils",
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
// Build all packages in dependency order
|
|
434
|
+
await client.exec(["pnpm", "run"], {
|
|
435
|
+
script: "build",
|
|
436
|
+
args: ["--recursive"],
|
|
437
|
+
cwd: "/monorepo/root",
|
|
438
|
+
});
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### Global Package Management
|
|
442
|
+
|
|
443
|
+
```typescript
|
|
444
|
+
// Install global tool
|
|
445
|
+
await client.exec(["pnpm", "add"], {
|
|
446
|
+
packages: ["typescript", "ts-node"],
|
|
447
|
+
global: true,
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
// Link package globally for testing
|
|
451
|
+
await client.exec(["pnpm", "link"], {
|
|
452
|
+
global: true,
|
|
453
|
+
cwd: "/path/to/my-cli-tool",
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
// Remove global package
|
|
457
|
+
await client.exec(["pnpm", "remove"], {
|
|
458
|
+
packages: ["old-cli"],
|
|
459
|
+
global: true,
|
|
460
|
+
});
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
### Store Management
|
|
464
|
+
|
|
465
|
+
```typescript
|
|
466
|
+
// Get store path for backup/restore
|
|
467
|
+
const store = await client.exec(["pnpm", "store", "path"], {});
|
|
468
|
+
console.log(`Backing up store: ${store.path}`);
|
|
469
|
+
|
|
470
|
+
// Could be used to:
|
|
471
|
+
// - Backup store for faster CI builds
|
|
472
|
+
// - Share store between CI jobs
|
|
473
|
+
// - Clean old cached packages
|
|
474
|
+
if (store.exists) {
|
|
475
|
+
// Perform backup/cleanup operations
|
|
476
|
+
}
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
## Types & Schemas
|
|
480
|
+
|
|
481
|
+
All input types have corresponding Zod schemas for validation:
|
|
482
|
+
|
|
483
|
+
```typescript
|
|
484
|
+
import {
|
|
485
|
+
PnpmInstallInputSchema,
|
|
486
|
+
PnpmAddInputSchema,
|
|
487
|
+
PnpmRemoveInputSchema,
|
|
488
|
+
PnpmLinkInputSchema,
|
|
489
|
+
PnpmRunInputSchema,
|
|
490
|
+
PnpmStorePathInputSchema,
|
|
491
|
+
type PnpmInstallInput,
|
|
492
|
+
type PnpmAddInput,
|
|
493
|
+
type PnpmRemoveInput,
|
|
494
|
+
type PnpmLinkInput,
|
|
495
|
+
type PnpmRunInput,
|
|
496
|
+
type PnpmStorePathInput,
|
|
497
|
+
type PnpmCommandOutput,
|
|
498
|
+
type PnpmStorePathOutput,
|
|
499
|
+
} from "@procedures/pnpm";
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
## Functions
|
|
503
|
+
|
|
504
|
+
```typescript
|
|
505
|
+
// Low-level procedure functions
|
|
506
|
+
export async function pnpmInstall(
|
|
507
|
+
input: PnpmInstallInput,
|
|
508
|
+
ctx: ProcedureContext
|
|
509
|
+
): Promise<PnpmCommandOutput>;
|
|
510
|
+
|
|
511
|
+
export async function pnpmAdd(
|
|
512
|
+
input: PnpmAddInput,
|
|
513
|
+
ctx: ProcedureContext
|
|
514
|
+
): Promise<PnpmCommandOutput>;
|
|
515
|
+
|
|
516
|
+
export async function pnpmRemove(
|
|
517
|
+
input: PnpmRemoveInput,
|
|
518
|
+
ctx: ProcedureContext
|
|
519
|
+
): Promise<PnpmCommandOutput>;
|
|
520
|
+
|
|
521
|
+
export async function pnpmLink(
|
|
522
|
+
input: PnpmLinkInput,
|
|
523
|
+
ctx: ProcedureContext
|
|
524
|
+
): Promise<PnpmCommandOutput>;
|
|
525
|
+
|
|
526
|
+
export async function pnpmRun(
|
|
527
|
+
input: PnpmRunInput,
|
|
528
|
+
ctx: ProcedureContext
|
|
529
|
+
): Promise<PnpmCommandOutput>;
|
|
530
|
+
|
|
531
|
+
export async function pnpmStorePath(
|
|
532
|
+
input: PnpmStorePathInput
|
|
533
|
+
): Promise<PnpmStorePathOutput>;
|
|
534
|
+
|
|
535
|
+
// Registration function
|
|
536
|
+
export function registerPnpmProcedures(): void;
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
## Configuration
|
|
540
|
+
|
|
541
|
+
### Package.json Client Field
|
|
542
|
+
|
|
543
|
+
```json
|
|
544
|
+
{
|
|
545
|
+
"client": {
|
|
546
|
+
"procedures": "./dist/register.js"
|
|
547
|
+
},
|
|
548
|
+
"scripts": {
|
|
549
|
+
"postinstall": "client-registry announce"
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
### Build Scripts
|
|
555
|
+
|
|
556
|
+
```bash
|
|
557
|
+
# Build the package
|
|
558
|
+
pnpm build
|
|
559
|
+
|
|
560
|
+
# Type check
|
|
561
|
+
pnpm typecheck
|
|
562
|
+
|
|
563
|
+
# Clean build artifacts
|
|
564
|
+
pnpm clean
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
## Dependencies
|
|
568
|
+
|
|
569
|
+
```mermaid
|
|
570
|
+
graph LR
|
|
571
|
+
A[@procedures/pnpm] --> B[@procedures/client]
|
|
572
|
+
A --> C[@procedures/shell]
|
|
573
|
+
A --> D[zod]
|
|
574
|
+
|
|
575
|
+
B -.->|provides| E[Client & Procedure System]
|
|
576
|
+
C -.->|provides| F[shell.run procedure]
|
|
577
|
+
D -.->|provides| G[Schema Validation]
|
|
578
|
+
|
|
579
|
+
style A fill:#e1f5ff
|
|
580
|
+
style B fill:#ffe1e1
|
|
581
|
+
style C fill:#ffe1e1
|
|
582
|
+
style D fill:#fff4e1
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
- **`@procedures/client`** - Core client library providing the procedure system
|
|
586
|
+
- **`@procedures/shell`** - Generic shell execution wrapper
|
|
587
|
+
- **`zod`** - Schema validation library
|
|
588
|
+
|
|
589
|
+
## Integration with Ecosystem
|
|
590
|
+
|
|
591
|
+
### Used By
|
|
592
|
+
|
|
593
|
+
```typescript
|
|
594
|
+
// bundle-dev/src/register.ts
|
|
595
|
+
import "@procedures/pnpm/register"; // registers its procedures
|
|
596
|
+
|
|
597
|
+
// client-lib uses pnpm procedures for package management
|
|
598
|
+
import { pnpmInstall, pnpmRun } from "@procedures/pnpm";
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
### Usage in client-lib
|
|
602
|
+
|
|
603
|
+
The `client-lib` package uses pnpm procedures for ecosystem package management:
|
|
604
|
+
|
|
605
|
+
```typescript
|
|
606
|
+
// Install dependencies in a package
|
|
607
|
+
await ctx.client.call(["pnpm", "install"], {
|
|
608
|
+
cwd: packagePath,
|
|
609
|
+
frozen: true,
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
// Build a package
|
|
613
|
+
await ctx.client.call(["pnpm", "run"], {
|
|
614
|
+
script: "build",
|
|
615
|
+
cwd: packagePath,
|
|
616
|
+
});
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
## CLI Wrapper Pattern
|
|
620
|
+
|
|
621
|
+
`client-pnpm` follows the ecosystem's **CLI Wrapper Pattern**:
|
|
622
|
+
|
|
623
|
+
1. **Multiple Focused Procedures** - Each procedure wraps a specific pnpm command
|
|
624
|
+
2. **Shell Delegation** - Uses `client-shell` for command execution
|
|
625
|
+
3. **Consistent Output** - Returns standardized `PnpmCommandOutput`
|
|
626
|
+
4. **Type Safety** - Full TypeScript types and Zod validation
|
|
627
|
+
|
|
628
|
+
This pattern is also used by:
|
|
629
|
+
- `client-cli` - Mark CLI wrapper
|
|
630
|
+
- `client-git` - Git operations wrapper
|
|
631
|
+
|
|
632
|
+
## Advanced Usage
|
|
633
|
+
|
|
634
|
+
### Direct Function Imports
|
|
635
|
+
|
|
636
|
+
The handlers start pnpm through `ctx.client.call(["shell", "run"], ...)`, so they need a procedure context. A `Client` is not a procedure context. Start the procedures through a client:
|
|
637
|
+
|
|
638
|
+
```typescript
|
|
639
|
+
import { Client, LocalTransport, PROCEDURE_REGISTRY } from "@procedures/client";
|
|
640
|
+
import "@procedures/pnpm/register"; // registers pnpm.* and shell.*
|
|
641
|
+
|
|
642
|
+
const client = new Client(new LocalTransport({ registry: PROCEDURE_REGISTRY }));
|
|
643
|
+
|
|
644
|
+
await client.exec(["pnpm", "install"], { frozen: true });
|
|
645
|
+
await client.exec(["pnpm", "add"], { packages: ["lodash"] });
|
|
646
|
+
await client.exec(["pnpm", "run"], { script: "build" });
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
### Custom Registration
|
|
650
|
+
|
|
651
|
+
```typescript
|
|
652
|
+
import { createProcedure, registerProcedures } from "@procedures/client";
|
|
653
|
+
import { pnpmInstall, PnpmInstallInputSchema } from "@procedures/pnpm";
|
|
654
|
+
|
|
655
|
+
// Register under custom namespace
|
|
656
|
+
const customInstallProcedure = createProcedure()
|
|
657
|
+
.path(["custom", "pnpm", "install"])
|
|
658
|
+
.input(PnpmInstallInputSchema)
|
|
659
|
+
.handler(pnpmInstall)
|
|
660
|
+
.build();
|
|
661
|
+
|
|
662
|
+
registerProcedures([customInstallProcedure]);
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
### Error Handling
|
|
666
|
+
|
|
667
|
+
```typescript
|
|
668
|
+
try {
|
|
669
|
+
const result = await client.exec(["pnpm", "install"], {
|
|
670
|
+
frozen: true,
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
if (!result.success) {
|
|
674
|
+
console.error(`Install failed with exit code ${result.exitCode}`);
|
|
675
|
+
console.error(`stderr: ${result.stderr}`);
|
|
676
|
+
|
|
677
|
+
if (result.stderr.includes("ERR_PNPM_OUTDATED_LOCKFILE")) {
|
|
678
|
+
console.log("Lockfile is outdated. Run pnpm install without --frozen-lockfile.");
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
} catch (error) {
|
|
682
|
+
console.error("Procedure call failed:", error);
|
|
683
|
+
}
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
## Performance Considerations
|
|
687
|
+
|
|
688
|
+
- **Process Spawning**: Each call spawns a pnpm process
|
|
689
|
+
- **Lockfile Parsing**: Large lockfiles may slow down operations
|
|
690
|
+
- **Frozen Installs**: Use `frozen: true` in CI for faster, reproducible installs
|
|
691
|
+
- **Workspace Filtering**: Use pnpm's native workspace filtering for monorepos
|
|
692
|
+
- **Store Location**: Consider store location for performance (local vs network drive)
|
|
693
|
+
|
|
694
|
+
## Troubleshooting
|
|
695
|
+
|
|
696
|
+
### PNPM Not Found
|
|
697
|
+
|
|
698
|
+
Ensure pnpm is installed and in PATH:
|
|
699
|
+
```bash
|
|
700
|
+
pnpm --version
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
Install pnpm:
|
|
704
|
+
```bash
|
|
705
|
+
npm install -g pnpm
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
### Lockfile Issues
|
|
709
|
+
|
|
710
|
+
If you get lockfile errors:
|
|
711
|
+
```typescript
|
|
712
|
+
// Update lockfile
|
|
713
|
+
await client.exec(["pnpm", "install"], {
|
|
714
|
+
// Don't use frozen: true
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
// Or delete lockfile and reinstall
|
|
718
|
+
await client.exec(["pnpm", "install"], {});
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
### Permission Errors
|
|
722
|
+
|
|
723
|
+
Check directory permissions:
|
|
724
|
+
```bash
|
|
725
|
+
ls -la node_modules
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
### Store Issues
|
|
729
|
+
|
|
730
|
+
Check store path and permissions:
|
|
731
|
+
```typescript
|
|
732
|
+
const store = await client.exec(["pnpm", "store", "path"], {});
|
|
733
|
+
console.log(`Store: ${store.path}, Exists: ${store.exists}`);
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
## PNPM Features
|
|
737
|
+
|
|
738
|
+
### Workspace Support
|
|
739
|
+
|
|
740
|
+
PNPM workspaces are supported through the `cwd` parameter:
|
|
741
|
+
|
|
742
|
+
```typescript
|
|
743
|
+
// Install all workspace packages
|
|
744
|
+
await client.exec(["pnpm", "install"], {
|
|
745
|
+
cwd: "/workspace/root",
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
// Add to specific workspace package
|
|
749
|
+
await client.exec(["pnpm", "add"], {
|
|
750
|
+
packages: ["lodash"],
|
|
751
|
+
cwd: "/workspace/root/packages/utils",
|
|
752
|
+
});
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
### Script Arguments
|
|
756
|
+
|
|
757
|
+
Pass arguments to pnpm scripts:
|
|
758
|
+
|
|
759
|
+
```typescript
|
|
760
|
+
await client.exec(["pnpm", "run"], {
|
|
761
|
+
script: "test",
|
|
762
|
+
args: ["--", "--coverage", "--watch"],
|
|
763
|
+
});
|
|
764
|
+
// Runs: pnpm run test -- --coverage --watch
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
### Version Specifiers
|
|
768
|
+
|
|
769
|
+
Use standard pnpm version syntax:
|
|
770
|
+
|
|
771
|
+
```typescript
|
|
772
|
+
await client.exec(["pnpm", "add"], {
|
|
773
|
+
packages: [
|
|
774
|
+
"react@^18.0.0",
|
|
775
|
+
"lodash@latest",
|
|
776
|
+
"@types/node@*",
|
|
777
|
+
"my-package@workspace:*", // Workspace package
|
|
778
|
+
],
|
|
779
|
+
});
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
## License
|
|
783
|
+
|
|
784
|
+
MIT
|
|
785
|
+
|
|
786
|
+
## Related Packages
|
|
787
|
+
|
|
788
|
+
- [@procedures/client](https://github.com/mark1russell7/client) - Core client library
|
|
789
|
+
- [@procedures/shell](https://github.com/mark1russell7/client-shell) - Shell execution wrapper
|
|
790
|
+
- [@procedures/lib](https://github.com/mark1russell7/client-lib) - Library management (uses pnpm procedures)
|
|
791
|
+
- [@procedures/cli-run](https://github.com/mark1russell7/client-cli) - CLI wrapper
|
|
792
|
+
- [@procedures/git](https://github.com/mark1russell7/client-git) - Git operations wrapper
|
|
793
|
+
- [@procedures/bundle-dev](https://github.com/mark1russell7/bundle-dev) - Development bundle
|