@vostride/agent-qa-runner-local 0.2.3 → 0.2.4

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/dist/index.cjs CHANGED
@@ -55,6 +55,7 @@ __export(index_exports, {
55
55
  latestBuildOrdinal: () => latestBuildOrdinal,
56
56
  loadCompletedRunHandoff: () => loadCompletedRunHandoff,
57
57
  nextBuildOrdinal: () => nextBuildOrdinal,
58
+ purgeActionCache: () => purgeActionCache,
58
59
  readBuildTagMap: () => readBuildTagMap,
59
60
  recordBuildTag: () => recordBuildTag,
60
61
  reserveBuildOrdinalForProducts: () => reserveBuildOrdinalForProducts,
@@ -146,39 +147,56 @@ function shouldWrite(policy) {
146
147
  }
147
148
 
148
149
  // src/fs-action-cache.ts
149
- var CACHE_SCHEMA_VERSION = 2;
150
+ var CACHE_SCHEMA_VERSION = 3;
151
+ var CACHE_ENTRY_FILE_RE = /^[0-9a-f]{16}\.json$/;
150
152
  var FsActionCache = class {
151
153
  root;
152
154
  policy;
155
+ skipped = /* @__PURE__ */ new Set();
153
156
  constructor(config) {
154
157
  this.root = config.root;
155
158
  this.policy = config.policy;
156
159
  }
157
160
  async get(key) {
158
- if (this.policy.disableCache) return null;
161
+ if (this.policy.disableCache || this.skipped.has(key)) return null;
159
162
  const onCurrent = await this.readEntry(this.policy.currentBranch, key);
160
- if (onCurrent !== null) return onCurrent;
163
+ if (onCurrent?.kind === "suppressed") return null;
164
+ if (onCurrent?.kind === "value") return onCurrent.value;
161
165
  if (this.policy.currentBranch !== this.policy.defaultBranch) {
162
- return this.readEntry(this.policy.defaultBranch, key);
166
+ const onDefault = await this.readEntry(this.policy.defaultBranch, key);
167
+ return onDefault?.kind === "value" ? onDefault.value : null;
163
168
  }
164
169
  return null;
165
170
  }
166
171
  async set(key, value) {
167
172
  if (!shouldWrite(this.policy)) return;
168
- const dir = this.branchDir(this.policy.currentBranch);
169
- await (0, import_promises.mkdir)(dir, { recursive: true });
170
- const envelope = { schemaVersion: CACHE_SCHEMA_VERSION, value };
171
- await (0, import_promises.writeFile)(this.entryPath(dir, key), `${JSON.stringify(envelope, null, 2)}
172
- `, "utf-8");
173
+ await this.writeEnvelope(key, { schemaVersion: CACHE_SCHEMA_VERSION, value });
173
174
  }
174
175
  async invalidate(key) {
175
- const dir = this.branchDir(this.policy.currentBranch);
176
+ if (!shouldWrite(this.policy)) {
177
+ this.skipped.add(key);
178
+ return;
179
+ }
180
+ const { currentBranch, defaultBranch } = this.policy;
181
+ if (currentBranch !== defaultBranch) {
182
+ const onDefault = await this.readEntry(defaultBranch, key);
183
+ if (onDefault?.kind === "value") {
184
+ await this.writeEnvelope(key, { schemaVersion: CACHE_SCHEMA_VERSION, suppressed: true });
185
+ return;
186
+ }
187
+ }
176
188
  try {
177
- await (0, import_promises.unlink)(this.entryPath(dir, key));
189
+ await (0, import_promises.unlink)(this.entryPath(this.branchDir(currentBranch), key));
178
190
  } catch (err) {
179
- if (err.code !== "ENOENT") throw err;
191
+ if (!isMissing(err)) throw err;
180
192
  }
181
193
  }
194
+ async writeEnvelope(key, envelope) {
195
+ const dir = this.branchDir(this.policy.currentBranch);
196
+ await (0, import_promises.mkdir)(dir, { recursive: true });
197
+ await (0, import_promises.writeFile)(this.entryPath(dir, key), `${JSON.stringify(envelope, null, 2)}
198
+ `, "utf-8");
199
+ }
182
200
  branchDir(branch) {
183
201
  return (0, import_node_path2.join)(this.root, (0, import_agent_qa_schema.slugBranch)(branch));
184
202
  }
@@ -190,7 +208,7 @@ var FsActionCache = class {
190
208
  try {
191
209
  raw = await (0, import_promises.readFile)(this.entryPath(this.branchDir(branch), key), "utf-8");
192
210
  } catch (err) {
193
- if (err.code === "ENOENT") return null;
211
+ if (isMissing(err)) return null;
194
212
  throw err;
195
213
  }
196
214
  let envelope;
@@ -200,9 +218,44 @@ var FsActionCache = class {
200
218
  return null;
201
219
  }
202
220
  if (envelope?.schemaVersion !== CACHE_SCHEMA_VERSION) return null;
203
- return envelope.value ?? null;
221
+ if (envelope.suppressed === true) return { kind: "suppressed" };
222
+ return envelope.value ? { kind: "value", value: envelope.value } : null;
204
223
  }
205
224
  };
225
+ function isMissing(err) {
226
+ return err.code === "ENOENT";
227
+ }
228
+ async function purgeActionCache(root) {
229
+ let branches;
230
+ try {
231
+ branches = await (0, import_promises.readdir)(root, { withFileTypes: true });
232
+ } catch (err) {
233
+ if (isMissing(err)) return 0;
234
+ throw err;
235
+ }
236
+ let purged = 0;
237
+ for (const branch of branches) {
238
+ if (!branch.isDirectory() || (0, import_agent_qa_schema.slugBranch)(branch.name) !== branch.name) continue;
239
+ const dir = (0, import_node_path2.join)(root, branch.name);
240
+ const entries = await (0, import_promises.readdir)(dir, { withFileTypes: true });
241
+ let removed = 0;
242
+ for (const entry of entries) {
243
+ if (!entry.isFile() || !CACHE_ENTRY_FILE_RE.test(entry.name)) continue;
244
+ try {
245
+ await (0, import_promises.unlink)((0, import_node_path2.join)(dir, entry.name));
246
+ } catch (err) {
247
+ if (!isMissing(err)) throw err;
248
+ }
249
+ removed++;
250
+ }
251
+ purged += removed;
252
+ if (removed > 0 && removed === entries.length) {
253
+ await (0, import_promises.rmdir)(dir).catch(() => {
254
+ });
255
+ }
256
+ }
257
+ return purged;
258
+ }
206
259
 
207
260
  // src/storage-state-store.ts
208
261
  var import_promises2 = require("fs/promises");
@@ -898,9 +951,11 @@ var import_node_os = require("os");
898
951
  var import_agent_qa_runner = require("@vostride/agent-qa-runner");
899
952
  var DEFAULT_DOCKER_BIN = "docker";
900
953
  var DockerHookExecutor = class {
954
+ version;
901
955
  dockerBin;
902
956
  pullPolicy;
903
- constructor(config = {}) {
957
+ constructor(config) {
958
+ this.version = config.version;
904
959
  this.dockerBin = config.dockerBin ?? DEFAULT_DOCKER_BIN;
905
960
  this.pullPolicy = config.pullPolicy ?? "if-not-present";
906
961
  }
@@ -908,15 +963,15 @@ var DockerHookExecutor = class {
908
963
  const dockerBin = this.dockerBin;
909
964
  const pullPolicy = this.pullPolicy;
910
965
  const start = Date.now();
911
- const image = import_agent_qa_runner.RUNTIME_IMAGE_MAP[hook.runtime];
912
- if (pullPolicy === "always" || pullPolicy === "if-not-present") {
913
- const needsPull = pullPolicy === "always" || !await imageExists(dockerBin, image);
914
- if (needsPull) {
915
- await pullImage(dockerBin, image);
916
- }
917
- }
966
+ const image = (0, import_agent_qa_runner.hookRunnerImage)(hook.runtime, this.version);
918
967
  let workDir;
919
968
  try {
969
+ if (pullPolicy === "always" || pullPolicy === "if-not-present") {
970
+ const needsPull = pullPolicy === "always" || !await imageExists(dockerBin, image);
971
+ if (needsPull) {
972
+ await pullImage(dockerBin, image);
973
+ }
974
+ }
920
975
  workDir = await (0, import_promises3.mkdtemp)((0, import_node_path11.join)((0, import_node_os.tmpdir)(), "agent-qa-hook-"));
921
976
  await (0, import_promises3.mkdir)((0, import_node_path11.join)(workDir, "tmp"), { recursive: true });
922
977
  await (0, import_promises3.cp)(hook.file, (0, import_node_path11.join)(workDir, (0, import_node_path11.basename)(hook.file)));
@@ -1101,6 +1156,7 @@ function execDocker(dockerBin, args, timeout) {
1101
1156
  latestBuildOrdinal,
1102
1157
  loadCompletedRunHandoff,
1103
1158
  nextBuildOrdinal,
1159
+ purgeActionCache,
1104
1160
  readBuildTagMap,
1105
1161
  recordBuildTag,
1106
1162
  reserveBuildOrdinalForProducts,