@procedures/pnpm 0.0.0-stage → 0.1.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.
Files changed (65) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/LICENSE +21 -0
  3. package/README.md +792 -2
  4. package/dist/.tsbuildinfo +1 -0
  5. package/dist/index.d.ts +30 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +32 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/module.d.ts +15 -0
  10. package/dist/module.d.ts.map +1 -0
  11. package/dist/module.js +113 -0
  12. package/dist/module.js.map +1 -0
  13. package/dist/procedures/pnpm/add.d.ts +25 -0
  14. package/dist/procedures/pnpm/add.d.ts.map +1 -0
  15. package/dist/procedures/pnpm/add.js +34 -0
  16. package/dist/procedures/pnpm/add.js.map +1 -0
  17. package/dist/procedures/pnpm/index.d.ts +10 -0
  18. package/dist/procedures/pnpm/index.d.ts.map +1 -0
  19. package/dist/procedures/pnpm/index.js +10 -0
  20. package/dist/procedures/pnpm/index.js.map +1 -0
  21. package/dist/procedures/pnpm/install.d.ts +23 -0
  22. package/dist/procedures/pnpm/install.d.ts.map +1 -0
  23. package/dist/procedures/pnpm/install.js +36 -0
  24. package/dist/procedures/pnpm/install.js.map +1 -0
  25. package/dist/procedures/pnpm/link.d.ts +24 -0
  26. package/dist/procedures/pnpm/link.d.ts.map +1 -0
  27. package/dist/procedures/pnpm/link.js +35 -0
  28. package/dist/procedures/pnpm/link.js.map +1 -0
  29. package/dist/procedures/pnpm/remove.d.ts +18 -0
  30. package/dist/procedures/pnpm/remove.d.ts.map +1 -0
  31. package/dist/procedures/pnpm/remove.js +25 -0
  32. package/dist/procedures/pnpm/remove.js.map +1 -0
  33. package/dist/procedures/pnpm/run.d.ts +25 -0
  34. package/dist/procedures/pnpm/run.d.ts.map +1 -0
  35. package/dist/procedures/pnpm/run.js +33 -0
  36. package/dist/procedures/pnpm/run.js.map +1 -0
  37. package/dist/procedures/pnpm/shared.d.ts +25 -0
  38. package/dist/procedures/pnpm/shared.d.ts.map +1 -0
  39. package/dist/procedures/pnpm/shared.js +75 -0
  40. package/dist/procedures/pnpm/shared.js.map +1 -0
  41. package/dist/procedures/pnpm/store.d.ts +23 -0
  42. package/dist/procedures/pnpm/store.d.ts.map +1 -0
  43. package/dist/procedures/pnpm/store.js +85 -0
  44. package/dist/procedures/pnpm/store.js.map +1 -0
  45. package/dist/register.d.ts +9 -0
  46. package/dist/register.d.ts.map +1 -0
  47. package/dist/register.js +16 -0
  48. package/dist/register.js.map +1 -0
  49. package/dist/types.d.ts +71 -0
  50. package/dist/types.d.ts.map +1 -0
  51. package/dist/types.js +98 -0
  52. package/dist/types.js.map +1 -0
  53. package/package.json +76 -3
  54. package/src/index.ts +57 -0
  55. package/src/module.ts +142 -0
  56. package/src/procedures/pnpm/add.ts +40 -0
  57. package/src/procedures/pnpm/index.ts +10 -0
  58. package/src/procedures/pnpm/install.ts +43 -0
  59. package/src/procedures/pnpm/link.ts +43 -0
  60. package/src/procedures/pnpm/remove.ts +32 -0
  61. package/src/procedures/pnpm/run.ts +41 -0
  62. package/src/procedures/pnpm/shared.ts +85 -0
  63. package/src/procedures/pnpm/store.ts +97 -0
  64. package/src/register.ts +20 -0
  65. package/src/types.ts +180 -0
package/README.md CHANGED
@@ -1,3 +1,793 @@
1
- # Temporary Holding Version
1
+ # @procedures/pnpm
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [![npm version](https://img.shields.io/npm/v/@procedures/pnpm.svg)](https://www.npmjs.com/package/@procedures/pnpm)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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"; // 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"; // 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"; // 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