@rigkit/runtime-client 0.2.7 → 0.2.8

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,6 @@
1
1
  {
2
2
  "name": "@rigkit/runtime-client",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
package/src/api.ts CHANGED
@@ -18,6 +18,7 @@ export const RuntimeControlHealthEffectSchema = Schema.Struct({
18
18
  projectDir: Schema.String,
19
19
  configPath: Schema.String,
20
20
  statePath: OptionalString,
21
+ globalFragmentRoot: OptionalString,
21
22
  engineVersion: Schema.String,
22
23
  runtimeVersion: Schema.String,
23
24
  expiresAt: Schema.String,
@@ -99,6 +100,41 @@ export const RuntimeControlSnapshotsResponseEffectSchema = Schema.Struct({
99
100
  snapshots: Schema.Array(Schema.Unknown),
100
101
  }).annotations({ identifier: "SnapshotsResponse" });
101
102
 
103
+ export const RuntimeControlCacheEntryEffectSchema = Schema.Struct({
104
+ scope: Schema.Literal("local", "global"),
105
+ workflow: Schema.String,
106
+ nodePath: Schema.String,
107
+ nodeName: Schema.String,
108
+ nodeKind: Schema.String,
109
+ runId: Schema.String,
110
+ invalidated: Schema.Boolean,
111
+ createdAt: Schema.String,
112
+ fragmentHash: Schema.optional(Schema.String),
113
+ }).annotations({ identifier: "CacheEntry" });
114
+
115
+ export const RuntimeControlCacheResponseEffectSchema = Schema.Struct({
116
+ entries: Schema.Array(RuntimeControlCacheEntryEffectSchema),
117
+ }).annotations({ identifier: "CacheResponse" });
118
+
119
+ export const RuntimeControlCacheClearRequestEffectSchema = Schema.Struct({
120
+ scope: Schema.optional(Schema.Literal("local", "global", "all")),
121
+ }).annotations({ identifier: "CacheClearRequest" });
122
+
123
+ export const RuntimeControlCacheClearResponseEffectSchema = Schema.Struct({
124
+ ok: Schema.Boolean,
125
+ deleted: Schema.Number,
126
+ }).annotations({ identifier: "CacheClearResponse" });
127
+
128
+ export const RuntimeControlCacheInvalidateRequestEffectSchema = Schema.Struct({
129
+ workflow: Schema.optional(Schema.String),
130
+ nodePaths: Schema.optional(Schema.Array(Schema.String)),
131
+ }).annotations({ identifier: "CacheInvalidateRequest" });
132
+
133
+ export const RuntimeControlCacheInvalidateResponseEffectSchema = Schema.Struct({
134
+ ok: Schema.Boolean,
135
+ invalidated: Schema.Number,
136
+ }).annotations({ identifier: "CacheInvalidateResponse" });
137
+
102
138
  export const RuntimeControlRunEffectSchema = Schema.Struct({
103
139
  runId: Schema.String,
104
140
  operation: Schema.String,
@@ -157,6 +193,12 @@ export type RuntimeControlWorkflowsResponse = Schema.Schema.Type<typeof RuntimeC
157
193
  export type RuntimeControlWorkspace = Schema.Schema.Type<typeof RuntimeControlWorkspaceEffectSchema>;
158
194
  export type RuntimeControlWorkspacesResponse = Schema.Schema.Type<typeof RuntimeControlWorkspacesResponseEffectSchema>;
159
195
  export type RuntimeControlSnapshotsResponse = Schema.Schema.Type<typeof RuntimeControlSnapshotsResponseEffectSchema>;
196
+ export type RuntimeControlCacheEntry = Schema.Schema.Type<typeof RuntimeControlCacheEntryEffectSchema>;
197
+ export type RuntimeControlCacheResponse = Schema.Schema.Type<typeof RuntimeControlCacheResponseEffectSchema>;
198
+ export type RuntimeControlCacheClearRequest = Schema.Schema.Type<typeof RuntimeControlCacheClearRequestEffectSchema>;
199
+ export type RuntimeControlCacheClearResponse = Schema.Schema.Type<typeof RuntimeControlCacheClearResponseEffectSchema>;
200
+ export type RuntimeControlCacheInvalidateRequest = Schema.Schema.Type<typeof RuntimeControlCacheInvalidateRequestEffectSchema>;
201
+ export type RuntimeControlCacheInvalidateResponse = Schema.Schema.Type<typeof RuntimeControlCacheInvalidateResponseEffectSchema>;
160
202
  export type RuntimeControlRunOperationRequest = Schema.Schema.Type<typeof RuntimeControlRunOperationRequestEffectSchema>;
161
203
  export type RuntimeControlRun = Schema.Schema.Type<typeof RuntimeControlRunEffectSchema>;
162
204
  export type RuntimeControlRunsResponse = Schema.Schema.Type<typeof RuntimeControlRunsResponseEffectSchema>;
@@ -180,6 +222,13 @@ export const runtimeControlApi = HttpApi.make("rigkit-runtime")
180
222
  .add(HttpApiEndpoint.get("workflows", "/workflows").addSuccess(RuntimeControlWorkflowsResponseEffectSchema))
181
223
  .add(HttpApiEndpoint.get("workspaces", "/workspaces").addSuccess(RuntimeControlWorkspacesResponseEffectSchema))
182
224
  .add(HttpApiEndpoint.get("snapshots", "/snapshots").addSuccess(RuntimeControlSnapshotsResponseEffectSchema))
225
+ .add(HttpApiEndpoint.get("cache", "/cache").addSuccess(RuntimeControlCacheResponseEffectSchema))
226
+ .add(HttpApiEndpoint.post("clearCache", "/cache/clear")
227
+ .setPayload(RuntimeControlCacheClearRequestEffectSchema)
228
+ .addSuccess(RuntimeControlCacheClearResponseEffectSchema))
229
+ .add(HttpApiEndpoint.post("invalidateCache", "/cache/invalidate")
230
+ .setPayload(RuntimeControlCacheInvalidateRequestEffectSchema)
231
+ .addSuccess(RuntimeControlCacheInvalidateResponseEffectSchema))
183
232
  .add(HttpApiEndpoint.get("runs", "/runs").addSuccess(RuntimeControlRunsResponseEffectSchema))
184
233
  .add(HttpApiEndpoint.post("startRun", "/runs")
185
234
  .setPayload(RuntimeControlRunOperationRequestEffectSchema)
package/src/client.ts CHANGED
@@ -22,6 +22,11 @@ import {
22
22
  runtimeControlApi,
23
23
  type RuntimeControlHealth,
24
24
  type RuntimeControlHostResponse,
25
+ type RuntimeControlCacheClearRequest,
26
+ type RuntimeControlCacheClearResponse,
27
+ type RuntimeControlCacheInvalidateRequest,
28
+ type RuntimeControlCacheInvalidateResponse,
29
+ type RuntimeControlCacheResponse,
25
30
  type RuntimeControlMetadata,
26
31
  type RuntimeControlOkResponse,
27
32
  type RuntimeControlOperationsManifest,
@@ -49,6 +54,9 @@ export type RuntimeHttpClient = {
49
54
  workflows(): Promise<RuntimeControlWorkflowsResponse>;
50
55
  workspaces(): Promise<RuntimeControlWorkspacesResponse>;
51
56
  snapshots(): Promise<RuntimeControlSnapshotsResponse>;
57
+ cache(): Promise<RuntimeControlCacheResponse>;
58
+ clearCache(body: RuntimeControlCacheClearRequest): Promise<RuntimeControlCacheClearResponse>;
59
+ invalidateCache(body: RuntimeControlCacheInvalidateRequest): Promise<RuntimeControlCacheInvalidateResponse>;
52
60
  runs(): Promise<RuntimeControlRunsResponse>;
53
61
  startRun(body: RuntimeControlRunOperationRequest): Promise<RuntimeControlRunStarted>;
54
62
  run(runId: string): Promise<RuntimeControlRun>;
@@ -125,6 +133,21 @@ function makeRuntimeHttpClient(options: RuntimeHttpClientOptions): RuntimeHttpCl
125
133
  method: "GET",
126
134
  path: "/snapshots",
127
135
  }),
136
+ cache: () =>
137
+ runRuntimeHttpRequest(withRuntimeControlClient(options, (client) => client.cache({ withResponse: true })), {
138
+ method: "GET",
139
+ path: "/cache",
140
+ }),
141
+ clearCache: (body) =>
142
+ runRuntimeHttpRequest(
143
+ withRuntimeControlClient(options, (client) => client.clearCache({ payload: body, withResponse: true })),
144
+ { method: "POST", path: "/cache/clear" },
145
+ ),
146
+ invalidateCache: (body) =>
147
+ runRuntimeHttpRequest(
148
+ withRuntimeControlClient(options, (client) => client.invalidateCache({ payload: body, withResponse: true })),
149
+ { method: "POST", path: "/cache/invalidate" },
150
+ ),
128
151
  runs: () =>
129
152
  runRuntimeHttpRequest(withRuntimeControlClient(options, (client) => client.runs({ withResponse: true })), {
130
153
  method: "GET",
package/src/index.ts CHANGED
@@ -31,6 +31,10 @@ export {
31
31
  RuntimeControlOperationCliEffectSchema,
32
32
  RuntimeControlOperationEffectSchema,
33
33
  RuntimeControlOperationsManifestEffectSchema,
34
+ RuntimeControlCacheEntryEffectSchema,
35
+ RuntimeControlCacheResponseEffectSchema,
36
+ RuntimeControlCacheClearRequestEffectSchema,
37
+ RuntimeControlCacheClearResponseEffectSchema,
34
38
  RuntimeControlProjectInfoEffectSchema,
35
39
  RuntimeControlRunEffectSchema,
36
40
  RuntimeControlRunOperationRequestEffectSchema,
@@ -49,6 +53,10 @@ export {
49
53
  type RuntimeControlOperation,
50
54
  type RuntimeControlOperationCli,
51
55
  type RuntimeControlOperationsManifest,
56
+ type RuntimeControlCacheEntry,
57
+ type RuntimeControlCacheResponse,
58
+ type RuntimeControlCacheClearRequest,
59
+ type RuntimeControlCacheClearResponse,
52
60
  type RuntimeControlProjectInfo,
53
61
  type RuntimeControlRun,
54
62
  type RuntimeControlRunOperationRequest,
package/src/manager.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
1
+ import { chmodSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, rmSync, statSync, writeFileSync } from "node:fs";
2
2
  import { spawn, type ChildProcessByStdio } from "node:child_process";
3
3
  import { createHash, randomUUID } from "node:crypto";
4
4
  import { dirname, join, resolve } from "node:path";
@@ -34,6 +34,7 @@ export type RuntimeProjectOptions = {
34
34
  projectDir: string;
35
35
  configPath: string;
36
36
  statePath?: string;
37
+ globalFragmentRoot?: string;
37
38
  source?: unknown;
38
39
  };
39
40
 
@@ -67,6 +68,9 @@ export type RuntimePaths = {
67
68
  handlePath: string;
68
69
  tokenPath: string;
69
70
  lockPath: string;
71
+ // Where the daemon's stderr is captured. The CLI tails this on run failure
72
+ // so users see real stack traces instead of "Internal server error".
73
+ runtimeLogPath: string;
70
74
  };
71
75
 
72
76
  const DEFAULT_IDLE_MS = 30 * 60 * 1000;
@@ -87,6 +91,9 @@ async function getOrStartRuntimeUnsafe(options: GetOrStartRuntimeOptions): Promi
87
91
  const projectDir = resolve(options.projectDir);
88
92
  const configPath = resolve(options.configPath);
89
93
  const statePath = options.statePath ? resolve(options.statePath) : undefined;
94
+ const globalFragmentRoot = options.globalFragmentRoot
95
+ ? resolve(options.globalFragmentRoot)
96
+ : join(options.rigkitHome ?? defaultRigkitHome(), "fragments");
90
97
  const projectId = projectIdFor({
91
98
  projectDir,
92
99
  configPath,
@@ -97,6 +104,7 @@ async function getOrStartRuntimeUnsafe(options: GetOrStartRuntimeOptions): Promi
97
104
  projectDir,
98
105
  configPath,
99
106
  statePath,
107
+ ...(options.globalFragmentRoot ? { globalFragmentRoot } : {}),
100
108
  source: options.source,
101
109
  });
102
110
  const paths = runtimePaths(projectId, options.rigkitHome);
@@ -112,6 +120,7 @@ async function getOrStartRuntimeUnsafe(options: GetOrStartRuntimeOptions): Promi
112
120
  projectDir,
113
121
  configPath,
114
122
  statePath,
123
+ globalFragmentRoot,
115
124
  projectId,
116
125
  runtimeFingerprint,
117
126
  paths,
@@ -145,6 +154,7 @@ export function runtimeFingerprintFor(options: RuntimeProjectOptions): string {
145
154
  const projectDir = resolve(options.projectDir);
146
155
  const configPath = resolve(options.configPath);
147
156
  const statePath = options.statePath ? resolve(options.statePath) : null;
157
+ const globalFragmentRoot = options.globalFragmentRoot ? resolve(options.globalFragmentRoot) : null;
148
158
  const hash = createHash("sha256");
149
159
 
150
160
  hash.update("project\0");
@@ -153,6 +163,8 @@ export function runtimeFingerprintFor(options: RuntimeProjectOptions): string {
153
163
  hash.update(configPath);
154
164
  hash.update("\0state\0");
155
165
  hash.update(statePath ?? "");
166
+ hash.update("\0global-fragment-root\0");
167
+ hash.update(globalFragmentRoot ?? "");
156
168
  hash.update("\0source\0");
157
169
  hash.update(JSON.stringify(options.source ?? null));
158
170
 
@@ -172,6 +184,7 @@ export function runtimePaths(projectId: string, rigkitHome = defaultRigkitHome()
172
184
  handlePath: join(root, `${projectId}.json`),
173
185
  tokenPath: join(root, `${projectId}.token`),
174
186
  lockPath: join(root, `${projectId}.lock`),
187
+ runtimeLogPath: join(root, `${projectId}.log`),
175
188
  };
176
189
  }
177
190
 
@@ -248,13 +261,22 @@ async function startRuntime(input: GetOrStartRuntimeOptions & {
248
261
  String(input.idleMs ?? DEFAULT_IDLE_MS),
249
262
  ];
250
263
  if (input.statePath) args.push("--state", input.statePath);
264
+ if (input.globalFragmentRoot) args.push("--global-fragment-root", input.globalFragmentRoot);
251
265
  if (input.source !== undefined) args.push("--source-json", JSON.stringify(input.source));
252
266
 
267
+ mkdirSync(input.paths.root, { recursive: true });
268
+ const stderrFd = openSync(input.paths.runtimeLogPath, "a");
253
269
  const proc = spawn(runtimeBin, args, {
254
270
  detached: true,
255
- stdio: ["ignore", "pipe", "inherit"],
271
+ stdio: ["ignore", "pipe", stderrFd],
256
272
  env: process.env,
257
- });
273
+ }) as ChildProcessByStdio<null, Readable, null>;
274
+ // The child inherits the fd; the parent can release its own handle.
275
+ try {
276
+ closeSync(stderrFd);
277
+ } catch {
278
+ // best-effort
279
+ }
258
280
 
259
281
  const line = await readReadyLine(proc, input.paths, input.projectDir);
260
282
  let ready: ReturnType<typeof RuntimeReadySchema.parse>;
@@ -535,16 +557,38 @@ function updateProjectSurfaceFingerprint(hash: ReturnType<typeof createHash>, pr
535
557
  }
536
558
 
537
559
  function updateRigkitPackageFingerprint(hash: ReturnType<typeof createHash>, scopeDir: string): void {
538
- if (!existsSync(scopeDir)) return;
539
- const packageDirs = readdirSync(scopeDir, { withFileTypes: true })
540
- .filter((entry) => entry.isDirectory() || entry.isSymbolicLink())
541
- .map((entry) => join(scopeDir, entry.name))
542
- .sort();
543
-
544
- for (const packageDir of packageDirs) {
545
- updateFileFingerprint(hash, "rigkit-package", join(packageDir, "package.json"));
546
- for (const file of collectFiles(join(packageDir, "src"))) {
547
- updateFileFingerprint(hash, "rigkit-source", file);
560
+ // Walk every @rigkit scope reachable from the project's node_modules. We
561
+ // recurse into each package's own `node_modules/@rigkit` so that nested
562
+ // installs (e.g. @rigkit/engine living under @rigkit/sdk/node_modules) are
563
+ // hashed too. Without this, edits to a transitive @rigkit package wouldn't
564
+ // shift the runtime fingerprint and the daemon wouldn't auto-restart.
565
+ const visited = new Set<string>();
566
+ const stack: string[] = [scopeDir];
567
+
568
+ while (stack.length > 0) {
569
+ const dir = stack.pop()!;
570
+ if (!existsSync(dir)) continue;
571
+ let canonical: string;
572
+ try {
573
+ canonical = realpathSync(dir);
574
+ } catch {
575
+ continue;
576
+ }
577
+ if (visited.has(canonical)) continue;
578
+ visited.add(canonical);
579
+
580
+ const packageDirs = readdirSync(dir, { withFileTypes: true })
581
+ .filter((entry) => entry.isDirectory() || entry.isSymbolicLink())
582
+ .map((entry) => join(dir, entry.name))
583
+ .sort();
584
+
585
+ for (const packageDir of packageDirs) {
586
+ updateFileFingerprint(hash, "rigkit-package", join(packageDir, "package.json"));
587
+ for (const file of collectFiles(join(packageDir, "src"))) {
588
+ updateFileFingerprint(hash, "rigkit-source", file);
589
+ }
590
+ // Recurse into this package's own @rigkit scope, if it has nested deps.
591
+ stack.push(join(packageDir, "node_modules", "@rigkit"));
548
592
  }
549
593
  }
550
594
  }
package/src/schemas.ts CHANGED
@@ -42,6 +42,7 @@ export const RuntimeHandleEffectSchema = Schema.Struct({
42
42
  projectDir: Schema.String,
43
43
  configPath: Schema.String,
44
44
  statePath: Schema.optional(Schema.String),
45
+ globalFragmentRoot: Schema.optional(Schema.String),
45
46
  pid: Schema.Int,
46
47
  url: Schema.String,
47
48
  tokenPath: Schema.String,
@@ -64,6 +65,7 @@ export const RuntimeHealthEffectSchema = Schema.Struct({
64
65
  projectDir: Schema.optional(Schema.String),
65
66
  configPath: Schema.optional(Schema.String),
66
67
  statePath: Schema.optional(Schema.String),
68
+ globalFragmentRoot: Schema.optional(Schema.String),
67
69
  engineVersion: Schema.optional(Schema.String),
68
70
  runtimeVersion: Schema.optional(Schema.String),
69
71
  expiresAt: Schema.optional(Schema.String),
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const RIGKIT_RUNTIME_CLIENT_VERSION = "0.2.7";
1
+ export const RIGKIT_RUNTIME_CLIENT_VERSION = "0.2.8";