@procedures/playground 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.
package/package.json CHANGED
@@ -1,6 +1,65 @@
1
1
  {
2
+ "$schema": "https://json.schemastore.org/package",
2
3
  "name": "@procedures/playground",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
4
+ "version": "0.1.0",
5
+ "description": "A typed fluent API to write procedure programs in TypeScript (proc, ref, run) with autocomplete, then run them with the client.",
6
+ "keywords": [
7
+ "dsl",
8
+ "fluent-api",
9
+ "procedures",
10
+ "typescript",
11
+ "workflow"
12
+ ],
13
+ "homepage": "https://mark1russell7.github.io/client/",
14
+ "bugs": {
15
+ "url": "https://github.com/mark1russell7/client/issues"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/mark1russell7/client.git",
20
+ "directory": "packages/client-playground"
21
+ },
22
+ "license": "MIT",
23
+ "author": "Mark Russell (https://github.com/mark1russell7)",
24
+ "type": "module",
25
+ "main": "./dist/index.js",
26
+ "types": "./dist/index.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "import": "./dist/index.js"
31
+ }
32
+ },
33
+ "files": [
34
+ "dist",
35
+ "src",
36
+ "!src/**/*.test.ts",
37
+ "!src/**/*.test.tsx",
38
+ "!src/**/__tests__",
39
+ "CHANGELOG.md"
40
+ ],
41
+ "sideEffects": false,
42
+ "engines": {
43
+ "node": ">=22"
44
+ },
45
+ "publishConfig": {
46
+ "access": "public",
47
+ "provenance": true
48
+ },
49
+ "dependencies": {
50
+ "@procedures/client": "0.1.0"
51
+ },
52
+ "devDependencies": {
53
+ "typescript": "^7.0.2",
54
+ "@types/node": "^22.0.0",
55
+ "@mark1russell7/cue": "^1.0.0",
56
+ "vitest": "^5.0.3"
57
+ },
58
+ "scripts": {
59
+ "build": "tsc -b",
60
+ "typecheck": "tsc --noEmit",
61
+ "clean": "rm -rf dist .tsbuildinfo",
62
+ "test": "vitest run --passWithNoTests",
63
+ "test:watch": "vitest"
64
+ }
6
65
  }
package/src/index.ts ADDED
@@ -0,0 +1,219 @@
1
+ /**
2
+ * Client Playground
3
+ *
4
+ * Type-safe aggregation building for procedure compositions.
5
+ * Write aggregations in TypeScript with full autocomplete, then run them.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * // my-agg.play.ts
10
+ * import { proc, ref, run } from "@procedures/playground";
11
+ *
12
+ * run(
13
+ * proc(["dag", "traverse"]).input({
14
+ * visit: [
15
+ * proc(["pnpm", "install"]).ref,
16
+ * proc(["git", "hasChanges"]).name("changes").ref,
17
+ * proc(["client", "conditional"]).input({
18
+ * condition: ref("changes.value"),
19
+ * then: proc(["git", "add"]).input({ all: true }).ref,
20
+ * }).ref,
21
+ * ],
22
+ * }).ref
23
+ * );
24
+ * ```
25
+ *
26
+ * Run with: `npx tsx my-agg.play.ts`
27
+ */
28
+
29
+ import type { ProcedurePath, ProcedureRefJson } from "@procedures/client";
30
+
31
+ // =============================================================================
32
+ // Output Reference
33
+ // =============================================================================
34
+
35
+ /**
36
+ * An output reference for referencing named stage outputs.
37
+ */
38
+ export interface OutputRef {
39
+ readonly $ref: string;
40
+ }
41
+
42
+ /**
43
+ * Create an output reference.
44
+ *
45
+ * @param path - Reference path (e.g., "stageName.value" or "$last.value")
46
+ * @returns Output reference object
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * ref("changes.value") // Reference the .value field of "changes" output
51
+ * ref("$last") // Reference the previous step's output
52
+ * ref("$last.success") // Reference the .success field of previous output
53
+ * ```
54
+ */
55
+ export function ref(path: string): OutputRef {
56
+ return { $ref: path };
57
+ }
58
+
59
+ // =============================================================================
60
+ // Procedure Reference Builder
61
+ // =============================================================================
62
+
63
+ /**
64
+ * Builder for creating procedure references with a fluent API.
65
+ */
66
+ export interface ProcBuilder<TInput = unknown> {
67
+ /**
68
+ * Set the input for this procedure.
69
+ */
70
+ input<T>(input: T): ProcBuilder<T>;
71
+
72
+ /**
73
+ * Name this stage for later reference with $ref.
74
+ */
75
+ name(name: string): ProcBuilder<TInput>;
76
+
77
+ /**
78
+ * Set when this reference should be executed.
79
+ * @param when - "$immediate", "$never", "$parent", or a named context
80
+ */
81
+ when(when: string): ProcBuilder<TInput>;
82
+
83
+ /**
84
+ * Get the procedure reference object.
85
+ */
86
+ readonly ref: ProcedureRefJson<TInput>;
87
+ }
88
+
89
+ /**
90
+ * Create a procedure reference builder.
91
+ *
92
+ * @param path - Path to the procedure (e.g., ["git", "add"])
93
+ * @returns Builder for the procedure reference
94
+ *
95
+ * @example
96
+ * ```typescript
97
+ * // Simple reference
98
+ * proc(["git", "add"]).input({ all: true }).ref
99
+ *
100
+ * // Named reference for $ref
101
+ * proc(["git", "hasChanges"]).name("changes").ref
102
+ *
103
+ * // With execution timing
104
+ * proc(["git", "add"]).input({ all: true }).when("$parent").ref
105
+ * ```
106
+ */
107
+ export function proc(path: ProcedurePath): ProcBuilder<unknown> {
108
+ let _input: unknown = {};
109
+ let _name: string | undefined;
110
+ let _when: string | undefined;
111
+
112
+ const builder: ProcBuilder<unknown> = {
113
+ input<T>(input: T): ProcBuilder<T> {
114
+ _input = input;
115
+ return builder as ProcBuilder<T>;
116
+ },
117
+
118
+ name(name: string): ProcBuilder<unknown> {
119
+ _name = name;
120
+ return builder;
121
+ },
122
+
123
+ when(when: string): ProcBuilder<unknown> {
124
+ _when = when;
125
+ return builder;
126
+ },
127
+
128
+ get ref(): ProcedureRefJson<unknown> {
129
+ const result: ProcedureRefJson<unknown> = {
130
+ $proc: path,
131
+ input: _input,
132
+ };
133
+
134
+ if (_name) {
135
+ (result as { $name?: string }).$name = _name;
136
+ }
137
+ if (_when) {
138
+ (result as { $when?: string }).$when = _when;
139
+ }
140
+
141
+ return result;
142
+ },
143
+ };
144
+
145
+ return builder;
146
+ }
147
+
148
+ // =============================================================================
149
+ // Execution
150
+ // =============================================================================
151
+
152
+ /**
153
+ * Options for running a procedure.
154
+ */
155
+ export interface RunOptions {
156
+ /** Whether to print the result (default: true) */
157
+ print?: boolean;
158
+
159
+ /** Output format (default: "json") */
160
+ format?: "json" | "text";
161
+ }
162
+
163
+ /**
164
+ * Run a procedure reference.
165
+ *
166
+ * This function executes the procedure and prints the result.
167
+ * Use this in your playground files to execute aggregations.
168
+ *
169
+ * @param procedureRef - The procedure reference to execute
170
+ * @param options - Execution options
171
+ * @returns The result of the procedure
172
+ *
173
+ * @example
174
+ * ```typescript
175
+ * // Run and print result
176
+ * await run(proc(["git", "status"]).ref);
177
+ *
178
+ * // Run without printing
179
+ * const result = await run(proc(["git", "status"]).ref, { print: false });
180
+ * ```
181
+ */
182
+ export async function run<T = unknown>(
183
+ procedureRef: ProcedureRefJson,
184
+ options: RunOptions = {}
185
+ ): Promise<T> {
186
+ const { print: shouldPrint = true, format = "json" } = options;
187
+
188
+ // Dynamic import to avoid bundling all of client
189
+ const { Client, LocalTransport, PROCEDURE_REGISTRY } = await import(
190
+ "@procedures/client"
191
+ );
192
+
193
+ // The transport runs each procedure of the registry through invokeProcedure()
194
+ // (ARCHITECTURE-PROPOSALS P1). Before, this file had its own copy of the bridge, without
195
+ // input validation.
196
+ const transport = new LocalTransport({ registry: PROCEDURE_REGISTRY });
197
+
198
+ const client = new Client({ transport });
199
+
200
+ // Execute the procedure
201
+ const result = await client.exec(procedureRef);
202
+
203
+ // Print result
204
+ if (shouldPrint) {
205
+ if (format === "json") {
206
+ console.log(JSON.stringify(result, null, 2));
207
+ } else {
208
+ console.log(result);
209
+ }
210
+ }
211
+
212
+ return result as T;
213
+ }
214
+
215
+ // =============================================================================
216
+ // Convenience Exports
217
+ // =============================================================================
218
+
219
+ export type { ProcedurePath, ProcedureRefJson } from "@procedures/client";