terminalhire 0.42.22 → 0.42.23

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.
@@ -1893,11 +1893,11 @@ function parseGitHubRef(url) {
1893
1893
  kind: m[3] === "pull" ? "pull" : "issue"
1894
1894
  };
1895
1895
  }
1896
- async function ghGraphQL(query, variables, token, signal, governor) {
1896
+ async function ghGraphQL(query2, variables, token, signal, governor) {
1897
1897
  const init = {
1898
1898
  method: "POST",
1899
1899
  headers: { ...ghHeaders(token), "Content-Type": "application/json" },
1900
- body: JSON.stringify({ query, variables }),
1900
+ body: JSON.stringify({ query: query2, variables }),
1901
1901
  signal
1902
1902
  };
1903
1903
  if (governor) {
@@ -12408,8 +12408,8 @@ var init_stringify = __esm({
12408
12408
  });
12409
12409
 
12410
12410
  // ../../node_modules/@anthropic-ai/sdk/internal/utils/query.mjs
12411
- function stringifyQuery(query) {
12412
- return stringify(query, { arrayFormat: "brackets" });
12411
+ function stringifyQuery(query2) {
12412
+ return stringify(query2, { arrayFormat: "brackets" });
12413
12413
  }
12414
12414
  var init_query = __esm({
12415
12415
  "../../node_modules/@anthropic-ai/sdk/internal/utils/query.mjs"() {
@@ -14493,9 +14493,9 @@ var init_deployment_runs = __esm({
14493
14493
  * ```
14494
14494
  */
14495
14495
  list(params = {}, options) {
14496
- const { betas, ...query } = params ?? {};
14496
+ const { betas, ...query2 } = params ?? {};
14497
14497
  return this._client.getAPIList("/v1/deployment_runs?beta=true", PageCursor, {
14498
- query,
14498
+ query: query2,
14499
14499
  ...options,
14500
14500
  headers: buildHeaders([
14501
14501
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -14607,9 +14607,9 @@ var init_deployments = __esm({
14607
14607
  * ```
14608
14608
  */
14609
14609
  list(params = {}, options) {
14610
- const { betas, ...query } = params ?? {};
14610
+ const { betas, ...query2 } = params ?? {};
14611
14611
  return this._client.getAPIList("/v1/deployments?beta=true", PageCursor, {
14612
- query,
14612
+ query: query2,
14613
14613
  ...options,
14614
14614
  headers: buildHeaders([
14615
14615
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -14769,9 +14769,9 @@ var init_dreams = __esm({
14769
14769
  * ```
14770
14770
  */
14771
14771
  list(params = {}, options) {
14772
- const { betas, ...query } = params ?? {};
14772
+ const { betas, ...query2 } = params ?? {};
14773
14773
  return this._client.getAPIList("/v1/dreams?beta=true", PageCursor, {
14774
- query,
14774
+ query: query2,
14775
14775
  ...options,
14776
14776
  headers: buildHeaders([
14777
14777
  { "anthropic-beta": [...betas ?? [], "dreaming-2026-04-21"].toString() },
@@ -14902,9 +14902,9 @@ var init_files = __esm({
14902
14902
  * ```
14903
14903
  */
14904
14904
  list(params = {}, options) {
14905
- const { betas, ...query } = params ?? {};
14905
+ const { betas, ...query2 } = params ?? {};
14906
14906
  return this._client.getAPIList("/v1/files?beta=true", Page, {
14907
- query,
14907
+ query: query2,
14908
14908
  ...options,
14909
14909
  headers: buildHeaders([
14910
14910
  { "anthropic-beta": [...betas ?? [], "files-api-2025-04-14"].toString() },
@@ -15052,9 +15052,9 @@ var init_models = __esm({
15052
15052
  * ```
15053
15053
  */
15054
15054
  list(params = {}, options) {
15055
- const { betas, ...query } = params ?? {};
15055
+ const { betas, ...query2 } = params ?? {};
15056
15056
  return this._client.getAPIList("/v1/models?beta=true", Page, {
15057
- query,
15057
+ query: query2,
15058
15058
  ...options,
15059
15059
  headers: buildHeaders([
15060
15060
  { ...betas?.toString() != null ? { "anthropic-beta": betas?.toString() } : void 0 },
@@ -15151,9 +15151,9 @@ var init_user_profiles = __esm({
15151
15151
  * ```
15152
15152
  */
15153
15153
  list(params = {}, options) {
15154
- const { betas, ...query } = params ?? {};
15154
+ const { betas, ...query2 } = params ?? {};
15155
15155
  return this._client.getAPIList("/v1/user_profiles?beta=true", PageCursor, {
15156
- query,
15156
+ query: query2,
15157
15157
  ...options,
15158
15158
  headers: buildHeaders([
15159
15159
  { "anthropic-beta": [...betas ?? [], "user-profiles-2026-03-24"].toString() },
@@ -16012,9 +16012,9 @@ var init_versions = __esm({
16012
16012
  * ```
16013
16013
  */
16014
16014
  list(agentID, params = {}, options) {
16015
- const { betas, ...query } = params ?? {};
16015
+ const { betas, ...query2 } = params ?? {};
16016
16016
  return this._client.getAPIList(path`/v1/agents/${agentID}/versions?beta=true`, PageCursor, {
16017
- query,
16017
+ query: query2,
16018
16018
  ...options,
16019
16019
  headers: buildHeaders([
16020
16020
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -16077,9 +16077,9 @@ var init_agents = __esm({
16077
16077
  * ```
16078
16078
  */
16079
16079
  retrieve(agentID, params = {}, options) {
16080
- const { betas, ...query } = params ?? {};
16080
+ const { betas, ...query2 } = params ?? {};
16081
16081
  return this._client.get(path`/v1/agents/${agentID}?beta=true`, {
16082
- query,
16082
+ query: query2,
16083
16083
  ...options,
16084
16084
  headers: buildHeaders([
16085
16085
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -16122,9 +16122,9 @@ var init_agents = __esm({
16122
16122
  * ```
16123
16123
  */
16124
16124
  list(params = {}, options) {
16125
- const { betas, ...query } = params ?? {};
16125
+ const { betas, ...query2 } = params ?? {};
16126
16126
  return this._client.getAPIList("/v1/agents?beta=true", PageCursor, {
16127
- query,
16127
+ query: query2,
16128
16128
  ...options,
16129
16129
  headers: buildHeaders([
16130
16130
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -18214,9 +18214,9 @@ var init_work = __esm({
18214
18214
  * ```
18215
18215
  */
18216
18216
  list(environmentID, params = {}, options) {
18217
- const { betas, ...query } = params ?? {};
18217
+ const { betas, ...query2 } = params ?? {};
18218
18218
  return this._client.getAPIList(path`/v1/environments/${environmentID}/work?beta=true`, PageCursor, {
18219
- query,
18219
+ query: query2,
18220
18220
  ...options,
18221
18221
  headers: buildHeaders([
18222
18222
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -18295,9 +18295,9 @@ var init_work = __esm({
18295
18295
  * ```
18296
18296
  */
18297
18297
  poll(environmentID, params = {}, options) {
18298
- const { betas, "Anthropic-Worker-ID": anthropicWorkerID, ...query } = params ?? {};
18298
+ const { betas, "Anthropic-Worker-ID": anthropicWorkerID, ...query2 } = params ?? {};
18299
18299
  return this._client.get(path`/v1/environments/${environmentID}/work/poll?beta=true`, {
18300
- query,
18300
+ query: query2,
18301
18301
  ...options,
18302
18302
  headers: buildHeaders([
18303
18303
  {
@@ -18494,9 +18494,9 @@ var init_environments = __esm({
18494
18494
  * ```
18495
18495
  */
18496
18496
  list(params = {}, options) {
18497
- const { betas, ...query } = params ?? {};
18497
+ const { betas, ...query2 } = params ?? {};
18498
18498
  return this._client.getAPIList("/v1/environments?beta=true", PageCursor, {
18499
- query,
18499
+ query: query2,
18500
18500
  ...options,
18501
18501
  headers: buildHeaders([
18502
18502
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -18599,9 +18599,9 @@ var init_memories = __esm({
18599
18599
  * ```
18600
18600
  */
18601
18601
  retrieve(memoryID, params, options) {
18602
- const { memory_store_id, betas, ...query } = params;
18602
+ const { memory_store_id, betas, ...query2 } = params;
18603
18603
  return this._client.get(path`/v1/memory_stores/${memory_store_id}/memories/${memoryID}?beta=true`, {
18604
- query,
18604
+ query: query2,
18605
18605
  ...options,
18606
18606
  headers: buildHeaders([
18607
18607
  { "anthropic-beta": [...betas ?? [], "agent-memory-2026-07-22"].toString() },
@@ -18647,9 +18647,9 @@ var init_memories = __esm({
18647
18647
  * ```
18648
18648
  */
18649
18649
  list(memoryStoreID, params = {}, options) {
18650
- const { betas, ...query } = params ?? {};
18650
+ const { betas, ...query2 } = params ?? {};
18651
18651
  return this._client.getAPIList(path`/v1/memory_stores/${memoryStoreID}/memories?beta=true`, PageCursor, {
18652
- query,
18652
+ query: query2,
18653
18653
  ...options,
18654
18654
  headers: buildHeaders([
18655
18655
  { "anthropic-beta": [...betas ?? [], "agent-memory-2026-07-22"].toString() },
@@ -18707,9 +18707,9 @@ var init_memory_versions = __esm({
18707
18707
  * ```
18708
18708
  */
18709
18709
  retrieve(memoryVersionID, params, options) {
18710
- const { memory_store_id, betas, ...query } = params;
18710
+ const { memory_store_id, betas, ...query2 } = params;
18711
18711
  return this._client.get(path`/v1/memory_stores/${memory_store_id}/memory_versions/${memoryVersionID}?beta=true`, {
18712
- query,
18712
+ query: query2,
18713
18713
  ...options,
18714
18714
  headers: buildHeaders([
18715
18715
  { "anthropic-beta": [...betas ?? [], "agent-memory-2026-07-22"].toString() },
@@ -18731,9 +18731,9 @@ var init_memory_versions = __esm({
18731
18731
  * ```
18732
18732
  */
18733
18733
  list(memoryStoreID, params = {}, options) {
18734
- const { betas, ...query } = params ?? {};
18734
+ const { betas, ...query2 } = params ?? {};
18735
18735
  return this._client.getAPIList(path`/v1/memory_stores/${memoryStoreID}/memory_versions?beta=true`, PageCursor, {
18736
- query,
18736
+ query: query2,
18737
18737
  ...options,
18738
18738
  headers: buildHeaders([
18739
18739
  { "anthropic-beta": [...betas ?? [], "agent-memory-2026-07-22"].toString() },
@@ -18859,9 +18859,9 @@ var init_memory_stores = __esm({
18859
18859
  * ```
18860
18860
  */
18861
18861
  list(params = {}, options) {
18862
- const { betas, ...query } = params ?? {};
18862
+ const { betas, ...query2 } = params ?? {};
18863
18863
  return this._client.getAPIList("/v1/memory_stores?beta=true", PageCursor, {
18864
- query,
18864
+ query: query2,
18865
18865
  ...options,
18866
18866
  headers: buildHeaders([
18867
18867
  { "anthropic-beta": [...betas ?? [], "agent-memory-2026-07-22"].toString() },
@@ -19059,9 +19059,9 @@ var init_batches = __esm({
19059
19059
  * ```
19060
19060
  */
19061
19061
  list(params = {}, options) {
19062
- const { betas, ...query } = params ?? {};
19062
+ const { betas, ...query2 } = params ?? {};
19063
19063
  return this._client.getAPIList("/v1/messages/batches?beta=true", Page, {
19064
- query,
19064
+ query: query2,
19065
19065
  ...options,
19066
19066
  headers: buildHeaders([
19067
19067
  { "anthropic-beta": [...betas ?? [], "message-batches-2024-09-24"].toString() },
@@ -20734,9 +20734,9 @@ var init_events = __esm({
20734
20734
  * ```
20735
20735
  */
20736
20736
  list(sessionID, params = {}, options) {
20737
- const { betas, ...query } = params ?? {};
20737
+ const { betas, ...query2 } = params ?? {};
20738
20738
  return this._client.getAPIList(path`/v1/sessions/${sessionID}/events?beta=true`, PageCursor, {
20739
- query,
20739
+ query: query2,
20740
20740
  ...options,
20741
20741
  headers: buildHeaders([
20742
20742
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -20791,9 +20791,9 @@ var init_events = __esm({
20791
20791
  * ```
20792
20792
  */
20793
20793
  stream(sessionID, params = {}, options) {
20794
- const { betas, ...query } = params ?? {};
20794
+ const { betas, ...query2 } = params ?? {};
20795
20795
  return this._client.get(path`/v1/sessions/${sessionID}/events/stream?beta=true`, {
20796
- query,
20796
+ query: query2,
20797
20797
  ...options,
20798
20798
  headers: buildHeaders([
20799
20799
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -20901,9 +20901,9 @@ var init_resources = __esm({
20901
20901
  * ```
20902
20902
  */
20903
20903
  list(sessionID, params = {}, options) {
20904
- const { betas, ...query } = params ?? {};
20904
+ const { betas, ...query2 } = params ?? {};
20905
20905
  return this._client.getAPIList(path`/v1/sessions/${sessionID}/resources?beta=true`, PageCursor, {
20906
- query,
20906
+ query: query2,
20907
20907
  ...options,
20908
20908
  headers: buildHeaders([
20909
20909
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -20988,9 +20988,9 @@ var init_events2 = __esm({
20988
20988
  * ```
20989
20989
  */
20990
20990
  list(threadID, params, options) {
20991
- const { session_id, betas, ...query } = params;
20991
+ const { session_id, betas, ...query2 } = params;
20992
20992
  return this._client.getAPIList(path`/v1/sessions/${session_id}/threads/${threadID}/events?beta=true`, PageCursor, {
20993
- query,
20993
+ query: query2,
20994
20994
  ...options,
20995
20995
  headers: buildHeaders([
20996
20996
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -21077,9 +21077,9 @@ var init_threads = __esm({
21077
21077
  * ```
21078
21078
  */
21079
21079
  list(sessionID, params = {}, options) {
21080
- const { betas, ...query } = params ?? {};
21080
+ const { betas, ...query2 } = params ?? {};
21081
21081
  return this._client.getAPIList(path`/v1/sessions/${sessionID}/threads?beta=true`, PageCursor, {
21082
- query,
21082
+ query: query2,
21083
21083
  ...options,
21084
21084
  headers: buildHeaders([
21085
21085
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -21214,9 +21214,9 @@ var init_sessions = __esm({
21214
21214
  * ```
21215
21215
  */
21216
21216
  list(params = {}, options) {
21217
- const { betas, ...query } = params ?? {};
21217
+ const { betas, ...query2 } = params ?? {};
21218
21218
  return this._client.getAPIList("/v1/sessions?beta=true", BidirectionalPageCursor, {
21219
- query,
21219
+ query: query2,
21220
21220
  ...options,
21221
21221
  headers: buildHeaders([
21222
21222
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -21341,9 +21341,9 @@ var init_versions2 = __esm({
21341
21341
  * ```
21342
21342
  */
21343
21343
  list(skillID, params = {}, options) {
21344
- const { betas, ...query } = params ?? {};
21344
+ const { betas, ...query2 } = params ?? {};
21345
21345
  return this._client.getAPIList(path`/v1/skills/${skillID}/versions?beta=true`, PageCursor, {
21346
- query,
21346
+ query: query2,
21347
21347
  ...options,
21348
21348
  headers: buildHeaders([
21349
21349
  { "anthropic-beta": [...betas ?? [], "skills-2025-10-02"].toString() },
@@ -21472,9 +21472,9 @@ var init_skills2 = __esm({
21472
21472
  * ```
21473
21473
  */
21474
21474
  list(params = {}, options) {
21475
- const { betas, ...query } = params ?? {};
21475
+ const { betas, ...query2 } = params ?? {};
21476
21476
  return this._client.getAPIList("/v1/skills?beta=true", PageCursor, {
21477
- query,
21477
+ query: query2,
21478
21478
  ...options,
21479
21479
  headers: buildHeaders([
21480
21480
  { "anthropic-beta": [...betas ?? [], "skills-2025-10-02"].toString() },
@@ -21592,9 +21592,9 @@ var init_certificates = __esm({
21592
21592
  * ```
21593
21593
  */
21594
21594
  list(tunnelID, params = {}, options) {
21595
- const { betas, ...query } = params ?? {};
21595
+ const { betas, ...query2 } = params ?? {};
21596
21596
  return this._client.getAPIList(path`/v1/tunnels/${tunnelID}/certificates?beta=true`, PageCursor, {
21597
- query,
21597
+ query: query2,
21598
21598
  ...options,
21599
21599
  headers: buildHeaders([
21600
21600
  { "anthropic-beta": [...betas ?? [], "mcp-tunnels-2026-06-22"].toString() },
@@ -21721,9 +21721,9 @@ var init_tunnels = __esm({
21721
21721
  * ```
21722
21722
  */
21723
21723
  list(params = {}, options) {
21724
- const { betas, ...query } = params ?? {};
21724
+ const { betas, ...query2 } = params ?? {};
21725
21725
  return this._client.getAPIList("/v1/tunnels?beta=true", PageCursor, {
21726
- query,
21726
+ query: query2,
21727
21727
  ...options,
21728
21728
  headers: buildHeaders([
21729
21729
  { "anthropic-beta": [...betas ?? [], "mcp-tunnels-2026-06-22"].toString() },
@@ -21917,9 +21917,9 @@ var init_credentials2 = __esm({
21917
21917
  * ```
21918
21918
  */
21919
21919
  list(vaultID, params = {}, options) {
21920
- const { betas, ...query } = params ?? {};
21920
+ const { betas, ...query2 } = params ?? {};
21921
21921
  return this._client.getAPIList(path`/v1/vaults/${vaultID}/credentials?beta=true`, PageCursor, {
21922
- query,
21922
+ query: query2,
21923
21923
  ...options,
21924
21924
  headers: buildHeaders([
21925
21925
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -22090,9 +22090,9 @@ var init_vaults = __esm({
22090
22090
  * ```
22091
22091
  */
22092
22092
  list(params = {}, options) {
22093
- const { betas, ...query } = params ?? {};
22093
+ const { betas, ...query2 } = params ?? {};
22094
22094
  return this._client.getAPIList("/v1/vaults?beta=true", PageCursor, {
22095
- query,
22095
+ query: query2,
22096
22096
  ...options,
22097
22097
  headers: buildHeaders([
22098
22098
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -22978,8 +22978,8 @@ var init_batches2 = __esm({
22978
22978
  * }
22979
22979
  * ```
22980
22980
  */
22981
- list(query = {}, options) {
22982
- return this._client.getAPIList("/v1/messages/batches", Page, { query, ...options });
22981
+ list(query2 = {}, options) {
22982
+ return this._client.getAPIList("/v1/messages/batches", Page, { query: query2, ...options });
22983
22983
  }
22984
22984
  /**
22985
22985
  * Delete a Message Batch.
@@ -23235,9 +23235,9 @@ var init_models2 = __esm({
23235
23235
  * use in the API. More recently released models are listed first.
23236
23236
  */
23237
23237
  list(params = {}, options) {
23238
- const { betas, ...query } = params ?? {};
23238
+ const { betas, ...query2 } = params ?? {};
23239
23239
  return this._client.getAPIList("/v1/models", Page, {
23240
- query,
23240
+ query: query2,
23241
23241
  ...options,
23242
23242
  headers: buildHeaders([
23243
23243
  { ...betas?.toString() != null ? { "anthropic-beta": betas?.toString() } : void 0 },
@@ -23586,8 +23586,8 @@ var init_client = __esm({
23586
23586
  }
23587
23587
  return buildHeaders([{ Authorization: `Bearer ${this.authToken}` }]);
23588
23588
  }
23589
- stringifyQuery(query) {
23590
- return stringifyQuery(query);
23589
+ stringifyQuery(query2) {
23590
+ return stringifyQuery(query2);
23591
23591
  }
23592
23592
  getUserAgent() {
23593
23593
  return `${this.constructor.name}/JS ${VERSION}`;
@@ -23598,16 +23598,16 @@ var init_client = __esm({
23598
23598
  makeStatusError(status, error, message, headers) {
23599
23599
  return APIError.generate(status, error, message, headers);
23600
23600
  }
23601
- buildURL(path5, query, defaultBaseURL) {
23601
+ buildURL(path5, query2, defaultBaseURL) {
23602
23602
  const baseURL = !__classPrivateFieldGet(this, _BaseAnthropic_instances, "m", _BaseAnthropic_baseURLOverridden).call(this) && defaultBaseURL || this.baseURL;
23603
23603
  const url = isAbsoluteURL(path5) ? new URL(path5) : new URL(baseURL + (baseURL.endsWith("/") && path5.startsWith("/") ? path5.slice(1) : path5));
23604
23604
  const defaultQuery = this.defaultQuery();
23605
23605
  const pathQuery = Object.fromEntries(url.searchParams);
23606
23606
  if (!isEmptyObj(defaultQuery) || !isEmptyObj(pathQuery)) {
23607
- query = { ...pathQuery, ...defaultQuery, ...query };
23607
+ query2 = { ...pathQuery, ...defaultQuery, ...query2 };
23608
23608
  }
23609
- if (typeof query === "object" && query && !Array.isArray(query)) {
23610
- url.search = this.stringifyQuery(query);
23609
+ if (typeof query2 === "object" && query2 && !Array.isArray(query2)) {
23610
+ url.search = this.stringifyQuery(query2);
23611
23611
  }
23612
23612
  return url.toString();
23613
23613
  }
@@ -23920,14 +23920,14 @@ var init_client = __esm({
23920
23920
  }
23921
23921
  async buildRequest(inputOptions, { retryCount = 0 } = {}) {
23922
23922
  const options = { ...inputOptions };
23923
- const { method, path: path5, query, defaultBaseURL } = options;
23923
+ const { method, path: path5, query: query2, defaultBaseURL } = options;
23924
23924
  if (this._authState.resolution) {
23925
23925
  await this._authState.resolution;
23926
23926
  }
23927
23927
  if (!this._baseURLIsExplicit && this._authState.baseURL && this.baseURL !== this._authState.baseURL) {
23928
23928
  this.baseURL = this._authState.baseURL;
23929
23929
  }
23930
- const url = this.buildURL(path5, query, defaultBaseURL);
23930
+ const url = this.buildURL(path5, query2, defaultBaseURL);
23931
23931
  if ("timeout" in options)
23932
23932
  validatePositiveInteger("timeout", options.timeout);
23933
23933
  options.timeout = options.timeout ?? this.timeout;
@@ -24045,8 +24045,8 @@ function stripFallbackBlocks(body) {
24045
24045
  function betaRefusalFallbackMiddleware(fallbacks, options = {}) {
24046
24046
  let warnedMissingState = false;
24047
24047
  return async (request, next, ctx) => {
24048
- const [path5, query] = (ctx.options?.path ?? "").split("?");
24049
- if (fallbacks.length === 0 || ctx.options?.method !== "post" || path5 !== "/v1/messages" || new URLSearchParams(query).get("beta") !== "true" || typeof ctx.options.body !== "object" || ctx.options.body == null) {
24048
+ const [path5, query2] = (ctx.options?.path ?? "").split("?");
24049
+ if (fallbacks.length === 0 || ctx.options?.method !== "post" || path5 !== "/v1/messages" || new URLSearchParams(query2).get("beta") !== "true" || typeof ctx.options.body !== "object" || ctx.options.body == null) {
24050
24050
  return next(request);
24051
24051
  }
24052
24052
  if (ctx.options.body.fallbacks != null) {
@@ -26058,6 +26058,22 @@ function isCommandUnavailable(facts, countsRead) {
26058
26058
  return false;
26059
26059
  return facts.stdout.trim().length === 0 && EXEC_FAILURE.test(facts.stderr);
26060
26060
  }
26061
+ function isOfflineBuildGap(facts, counts) {
26062
+ if (facts.runtime !== "jvm")
26063
+ return null;
26064
+ if (counts !== null && counts.tests_failed > 0)
26065
+ return null;
26066
+ if (facts.exitCode === 0 || facts.exitCode === null)
26067
+ return null;
26068
+ const out = `${facts.stdout}
26069
+ ${facts.stderr}`;
26070
+ for (const pattern of OFFLINE_BUILD_GAP) {
26071
+ const hit = pattern.exec(out);
26072
+ if (hit)
26073
+ return hit[0];
26074
+ }
26075
+ return null;
26076
+ }
26061
26077
  function classifyVerification(facts) {
26062
26078
  if (facts.timedOut) {
26063
26079
  return {
@@ -26082,6 +26098,14 @@ function classifyVerification(facts) {
26082
26098
  reason: `the test command could not be invoked (exit ${String(facts.exitCode)}). This is an environment failure on our side \u2014 a missing interpreter, a binary outside PATH, or a dependency installed somewhere the command cannot see it. The repo has not been judged.`
26083
26099
  };
26084
26100
  }
26101
+ const gap = isOfflineBuildGap(facts, counts);
26102
+ if (gap !== null) {
26103
+ return {
26104
+ outcome: "test-command-unavailable",
26105
+ counts,
26106
+ reason: `the build stopped on something our install step did not fetch (${gap}). The test step has no network, so this is a gap in our environment, not a failure in the repo. The repo has not been judged.`
26107
+ };
26108
+ }
26085
26109
  if (counts !== null) {
26086
26110
  if (counts.tests_failed > 0) {
26087
26111
  return {
@@ -26136,10 +26160,19 @@ function isGreen(outcome) {
26136
26160
  function isOurFault(outcome) {
26137
26161
  return outcome === "test-command-unavailable" || outcome === "counts-unparsed";
26138
26162
  }
26139
- var int, withSuiteFailures, READERS, SUPPORTED_RUNNERS, COVERAGE_TABLE, EXEC_FAILURE, SUITE_REPORTED_FAILURE;
26163
+ var VERIFICATION_OUTCOMES, int, withSuiteFailures, READERS, SUPPORTED_RUNNERS, COVERAGE_TABLE, EXEC_FAILURE, SUITE_REPORTED_FAILURE, OFFLINE_BUILD_GAP;
26140
26164
  var init_classify2 = __esm({
26141
26165
  "../../packages/envrun/dist/classify.js"() {
26142
26166
  "use strict";
26167
+ VERIFICATION_OUTCOMES = [
26168
+ "completed",
26169
+ "tests-failed",
26170
+ "no-tests-observed",
26171
+ "counts-unparsed",
26172
+ "test-command-unavailable",
26173
+ "environment-exhausted",
26174
+ "budget-exceeded"
26175
+ ];
26143
26176
  int = (m, i = 1) => m ? Number(m[i]) : 0;
26144
26177
  withSuiteFailures = (counts, suiteLine) => {
26145
26178
  if (counts.tests_failed > 0 || !suiteLine)
@@ -26239,6 +26272,51 @@ var init_classify2 = __esm({
26239
26272
  return { tests_passed: int(passed), tests_failed: int(failed) + int(errors) };
26240
26273
  }
26241
26274
  },
26275
+ {
26276
+ // Maven surefire's per-module summary (TERM-1122), measured against surefire
26277
+ // 3.2.5 through `th run`:
26278
+ //
26279
+ // [INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
26280
+ //
26281
+ // The per-CLASS lines carry the same counts followed by `, Time elapsed: …`, so
26282
+ // the end anchor after `Skipped` is what keeps them out; counting both would
26283
+ // double every test. One summary prints per module, so they are SUMMED. An
26284
+ // error is a test that could not run to an assertion, counted as failed so a
26285
+ // green verdict is impossible while one is outstanding, as pytest's are.
26286
+ runner: "maven surefire",
26287
+ read: (out) => {
26288
+ const lines = [
26289
+ ...out.matchAll(/^(?:\[(?:INFO|WARNING|ERROR)\] )?Tests run: (\d+), Failures: (\d+), Errors: (\d+), Skipped: (\d+)(?:, Flakes: \d+)?\s*$/gm)
26290
+ ];
26291
+ if (lines.length === 0)
26292
+ return null;
26293
+ let passed = 0;
26294
+ let failed = 0;
26295
+ for (const m of lines) {
26296
+ const [run2, failures, errors, skipped] = [m[1], m[2], m[3], m[4]].map(Number);
26297
+ failed += failures + errors;
26298
+ passed += Math.max(0, run2 - failures - errors - skipped);
26299
+ }
26300
+ return { tests_passed: passed, tests_failed: failed };
26301
+ }
26302
+ },
26303
+ {
26304
+ // Gradle prints no test counts when every test passes, so envrun installs an
26305
+ // init script that prints one line per Test task (`gradleTestSummary.ts`,
26306
+ // TERM-1122). The marker is ours; its format is fixed there.
26307
+ runner: "gradle",
26308
+ read: (out) => {
26309
+ const lines = [
26310
+ ...out.matchAll(/^terminalhire-gradle-tests: task=\S+ total=(\d+) passed=(\d+) failed=(\d+) skipped=(\d+)\s*$/gm)
26311
+ ];
26312
+ if (lines.length === 0)
26313
+ return null;
26314
+ return {
26315
+ tests_passed: lines.reduce((sum, m) => sum + Number(m[2]), 0),
26316
+ tests_failed: lines.reduce((sum, m) => sum + Number(m[3]), 0)
26317
+ };
26318
+ }
26319
+ },
26242
26320
  {
26243
26321
  // mocha: ` 440 passing (1s)` and ` 2 failing`
26244
26322
  runner: "mocha",
@@ -26367,6 +26445,21 @@ var init_classify2 = __esm({
26367
26445
  "\\d+\\s+examples?,\\s+(?!0\\b)\\d+\\s+failures?"
26368
26446
  // rspec's summary line
26369
26447
  ].join("|"), "m");
26448
+ OFFLINE_BUILD_GAP = [
26449
+ // Maven, `-o`: `Cannot access central (…) in offline mode and the artifact … has
26450
+ // not been downloaded from it before.`
26451
+ /in offline mode and the artifact \S+ has not been downloaded from it before/,
26452
+ // Maven without `-o`, as a CI-derived `mvn test` runs: it tries the network.
26453
+ /Could not transfer artifact \S+ from\/to /,
26454
+ /Plugin \S+ or one of its dependencies could not be resolved/,
26455
+ // Gradle, `--offline`.
26456
+ /No cached version (?:listing )?(?:of|for) \S+ available for offline mode/,
26457
+ // Gradle without `--offline`, and the wrapper fetching its own distribution.
26458
+ /Could not GET 'https?:\/\//,
26459
+ /^Downloading https:\/\/services\.gradle\.org\/distributions\//m,
26460
+ /No matching toolchains found for requested specification/,
26461
+ /Cannot find a Java installation on your machine matching/
26462
+ ];
26370
26463
  }
26371
26464
  });
26372
26465
 
@@ -26432,6 +26525,8 @@ function scrubEnv(source, opts) {
26432
26525
  env["GOCACHE"] = join18(jailHome, ".cache", "go-build");
26433
26526
  env["GOFLAGS"] = "-modcacherw";
26434
26527
  env["CARGO_HOME"] = join18(jailHome, ".cargo");
26528
+ env["MAVEN_OPTS"] = `-Dmaven.repo.local=${join18(jailHome, ".m2", "repository")}`;
26529
+ env["GRADLE_USER_HOME"] = join18(jailHome, ".gradle");
26435
26530
  const bundle = join18(jailHome, ".bundle");
26436
26531
  env["GEM_HOME"] = bundle;
26437
26532
  env["BUNDLE_PATH"] = bundle;
@@ -26749,6 +26844,18 @@ var init_egressProxy = __esm({
26749
26844
  // NuGet; the coupling test refuses a mapped runtime whose registry is unreachable, and
26750
26845
  // it caught this one the moment the image landed.
26751
26846
  "api.nuget.org",
26847
+ // TERM-1122, added with the `jvm` image mapping, each from a MEASURED denial
26848
+ // through `th run` (the proxy's 403 in the build's own output), not a guess:
26849
+ // - Maven Central, where both `mvn` and Gradle's `mavenCentral()` resolve.
26850
+ // - `services.gradle.org`, where a Gradle wrapper fetches its distribution.
26851
+ // - `release-assets.githubusercontent.com`, where that fetch LANDS. Measured
26852
+ // chain: services.gradle.org 307 -> github.com 302 -> this host 200. The
26853
+ // `github.com` note below keeps `githubusercontent.com` denied until a real
26854
+ // install needs it; this is that install. Only this one host: raw blobs and
26855
+ // `objects.githubusercontent.com` stay denied.
26856
+ "repo.maven.apache.org",
26857
+ "services.gradle.org",
26858
+ "release-assets.githubusercontent.com",
26752
26859
  // Git dependencies. Approved by Eric 2026-07-22 after a live run measured the
26753
26860
  // chokepoint working under load (20 events, 16 allowed / 4 denied by host).
26754
26861
  //
@@ -27040,6 +27147,9 @@ function containerArgs(spec, env, opts) {
27040
27147
  args.push(`--env=${k}=${url}`);
27041
27148
  }
27042
27149
  args.push("--env=NO_PROXY=", "--env=no_proxy=");
27150
+ const host = opts.net.proxyHost;
27151
+ const port = String(opts.net.proxyPort);
27152
+ args.push(`--env=JAVA_TOOL_OPTIONS=-Dhttp.proxyHost=${host} -Dhttp.proxyPort=${port} -Dhttps.proxyHost=${host} -Dhttps.proxyPort=${port} -Daether.connector.http.useSystemProperties=true`);
27043
27153
  }
27044
27154
  args.push("--");
27045
27155
  args.push(validateImage(opts.image ?? DEFAULT_CONTAINER_IMAGE));
@@ -27372,7 +27482,10 @@ var init_container = __esm({
27372
27482
  "http_proxy",
27373
27483
  "https_proxy",
27374
27484
  "NO_PROXY",
27375
- "no_proxy"
27485
+ "no_proxy",
27486
+ // Carries the JVM's copy of the proxy (below), so an inherited value is dropped
27487
+ // for the same reason as the rest.
27488
+ "JAVA_TOOL_OPTIONS"
27376
27489
  ]);
27377
27490
  WINDOWS_DRIVE_ROOT = /^[A-Za-z]:[\\/]/;
27378
27491
  IMAGE_HOST = "(?:[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)+(?::[0-9]+)?|localhost(?::[0-9]+)?)";
@@ -27422,11 +27535,17 @@ var init_dist = __esm({
27422
27535
  function censusTotal(c) {
27423
27536
  return c.containers.length + c.volumes.length + c.networks.length;
27424
27537
  }
27425
- function ids(docker3, args) {
27538
+ function query(docker3, args) {
27426
27539
  const res = docker3.sync([...args], { timeoutMs: 15e3 });
27427
- if (res.error || res.status !== 0)
27428
- return [];
27429
- return res.stdout.split("\n").map((s) => s.trim()).filter((s) => s.length > 0);
27540
+ if (res.error || res.status !== 0) {
27541
+ const why = res.error?.message ?? (res.stderr.trim() || `exit ${String(res.status)}`);
27542
+ return { ids: [], failure: `docker ${args.slice(0, 2).join(" ")}: ${why}` };
27543
+ }
27544
+ const ids2 = res.stdout.split("\n").map((s) => s.trim()).filter((s) => s.length > 0);
27545
+ return { ids: ids2, failure: null };
27546
+ }
27547
+ function ids(docker3, args) {
27548
+ return query(docker3, args).ids;
27430
27549
  }
27431
27550
  function census(docker3, label) {
27432
27551
  const filter = `label=${label}`;
@@ -27436,25 +27555,67 @@ function census(docker3, label) {
27436
27555
  networks: ids(docker3, ["network", "ls", "-q", "--filter", filter])
27437
27556
  };
27438
27557
  }
27558
+ function censusReport(docker3, label) {
27559
+ const filter = `label=${label}`;
27560
+ const failures = [];
27561
+ const ask2 = (args) => {
27562
+ const q = query(docker3, args);
27563
+ if (q.failure !== null)
27564
+ failures.push(q.failure);
27565
+ return q.ids;
27566
+ };
27567
+ const taken = {
27568
+ containers: ask2(["ps", "-aq", "--filter", filter]),
27569
+ volumes: ask2(["volume", "ls", "-q", "--filter", filter]),
27570
+ networks: ask2(["network", "ls", "-q", "--filter", filter])
27571
+ };
27572
+ return failures.length === 0 ? { observed: true, census: taken, unobservedReason: null } : { observed: false, census: taken, unobservedReason: failures.join("; ") };
27573
+ }
27439
27574
  function localCensus(label) {
27440
27575
  return census(localDockerClient(), label);
27441
27576
  }
27442
- function judgeLeaks(peak, after) {
27577
+ function judgeLeaks(peak, after, observation) {
27443
27578
  const labelObserved = peak.containers.length > 0;
27579
+ if (!observation.observed) {
27580
+ return {
27581
+ labelObserved,
27582
+ reaped: false,
27583
+ observed: false,
27584
+ clean: false,
27585
+ state: "unobserved",
27586
+ peak,
27587
+ after,
27588
+ note: `UNOBSERVED, not clean: we could not look at what survived teardown (${observation.unobservedReason ?? "no reason given"}), so nothing is known about leaks on this run, in either direction.`
27589
+ };
27590
+ }
27444
27591
  const reaped = censusTotal(after) === 0;
27445
27592
  let note;
27593
+ let state;
27446
27594
  if (!labelObserved && reaped) {
27595
+ state = "inconclusive";
27447
27596
  note = "INCONCLUSIVE, not clean: nothing labelled was ever seen alive, so an empty final census is equally consistent with the label never being applied. The control failed, so the denial proves nothing.";
27448
27597
  } else if (!labelObserved) {
27598
+ state = "leak";
27449
27599
  note = "no labelled container was observed alive AND objects remain \u2014 the label wiring is wrong.";
27450
27600
  } else if (!reaped) {
27601
+ state = "leak";
27451
27602
  note = `LEAK: ${String(censusTotal(after))} labelled object(s) survived teardown (containers=${String(after.containers.length)} volumes=${String(after.volumes.length)} networks=${String(after.networks.length)}).`;
27452
27603
  } else {
27604
+ state = "clean";
27453
27605
  note = `clean: peak ${String(peak.containers.length)} labelled container(s) observed alive, 0 labelled objects remain after teardown.`;
27454
27606
  }
27455
- return { labelObserved, reaped, clean: labelObserved && reaped, peak, after, note };
27607
+ return {
27608
+ labelObserved,
27609
+ reaped,
27610
+ observed: true,
27611
+ clean: labelObserved && reaped,
27612
+ state,
27613
+ peak,
27614
+ after,
27615
+ note
27616
+ };
27456
27617
  }
27457
- var RUN_LABEL_KEY, LabelWatch;
27618
+ var RUN_LABEL_KEY, LabelWatch, LEAK_STATES;
27458
27619
  var init_labels = __esm({
27459
27620
  "../../packages/envrun/dist/labels.js"() {
27460
27621
  "use strict";
@@ -27509,6 +27670,7 @@ var init_labels = __esm({
27509
27670
  return this.#samples;
27510
27671
  }
27511
27672
  };
27673
+ LEAK_STATES = ["clean", "leak", "inconclusive", "unobserved"];
27512
27674
  }
27513
27675
  });
27514
27676
 
@@ -27993,7 +28155,7 @@ function acquireLocalLease(runId) {
27993
28155
  observed: false,
27994
28156
  census: { containers: [], volumes: [], networks: [] },
27995
28157
  unobservedReason: RELEASED_LEASE_CENSUS_REASON
27996
- } : { observed: true, census: census(docker3, label), unobservedReason: null }),
28158
+ } : censusReport(docker3, label)),
27997
28159
  publishPreview: (req) => startPreview({ ...req, docker: docker3 }),
27998
28160
  release: () => {
27999
28161
  if (released) {
@@ -28113,6 +28275,17 @@ caused by: ${frame}`;
28113
28275
  }
28114
28276
  return frames === 0 ? null : out;
28115
28277
  }
28278
+ function imageVariantFor(spec) {
28279
+ if (spec.runtime !== "jvm")
28280
+ return void 0;
28281
+ const callsGradle = /(?:^|[\s;&|(])gradle(?=\s|$)/;
28282
+ return [spec.installCommand, spec.testCommand].some((c) => c != null && callsGradle.test(c)) ? "gradle" : void 0;
28283
+ }
28284
+ function shapeFor(runtime, variant) {
28285
+ if (runtime === "jvm" && variant === "gradle")
28286
+ return JVM_GRADLE_IMAGE;
28287
+ return RUNTIME_IMAGES[runtime];
28288
+ }
28116
28289
  function atLeast(a, b) {
28117
28290
  const left = a.split(".").map(Number);
28118
28291
  const right = b.split(".").map(Number);
@@ -28125,10 +28298,10 @@ function atLeast(a, b) {
28125
28298
  }
28126
28299
  return true;
28127
28300
  }
28128
- function imageForRuntime(runtime, override, version) {
28301
+ function imageForRuntime(runtime, override, version, variant) {
28129
28302
  if (override)
28130
28303
  return override;
28131
- const shape = RUNTIME_IMAGES[runtime];
28304
+ const shape = shapeFor(runtime, variant);
28132
28305
  if (!shape) {
28133
28306
  throw new RunRefusalError(`no container image is mapped for runtime ${JSON.stringify(runtime)}. Refusing to run it in the Node image: a bare "command not found" exits 127, which classifyVerification already owns as ours \u2014 but a test script that RUNS and fails inside on the missing tool exits with its own status and prints to stdout, and that falls through to tests-failed \u2014 a false red blamed on the repo.`);
28134
28307
  }
@@ -28137,7 +28310,7 @@ function imageForRuntime(runtime, override, version) {
28137
28310
  if (!TAG_VERSION.test(version)) {
28138
28311
  throw new RunRefusalError(`runtime version ${JSON.stringify(version)} is not a bare version, so no image tag can be built from it. Refusing rather than booting the default: the repo asked for a version, and supplying a different one silently is what TERM-643 fixed.`);
28139
28312
  }
28140
- return `${shape.repository}:${version}${shape.suffix}`;
28313
+ return `${shape.repository}:${shape.prefix ?? ""}${version}${shape.suffix}`;
28141
28314
  }
28142
28315
  function setManifestProbe(probe) {
28143
28316
  const previous = manifestProbe;
@@ -28150,10 +28323,10 @@ function imageDefinitelyAbsent(image) {
28150
28323
  return false;
28151
28324
  return /manifest unknown|no such manifest/i.test(res.output);
28152
28325
  }
28153
- function resolvePublishedImage(image, runtime, version) {
28326
+ function resolvePublishedImage(image, runtime, version, variant) {
28154
28327
  if (!imageDefinitelyAbsent(image))
28155
28328
  return image;
28156
- const shape = RUNTIME_IMAGES[runtime];
28329
+ const shape = shapeFor(runtime, variant);
28157
28330
  if (shape && shape.declaredIsFloor && atLeast(shape.defaultVersion, version)) {
28158
28331
  return unversionedImage(shape);
28159
28332
  }
@@ -28161,18 +28334,19 @@ function resolvePublishedImage(image, runtime, version) {
28161
28334
  }
28162
28335
  function resolveImageForSpec(spec, override) {
28163
28336
  const declared = spec.runtimeVersion;
28164
- const image = imageForRuntime(spec.runtime, override, declared);
28337
+ const variant = imageVariantFor(spec);
28338
+ const image = imageForRuntime(spec.runtime, override, declared, variant);
28165
28339
  const constructed = (() => {
28166
28340
  if (declared === null)
28167
28341
  return null;
28168
28342
  try {
28169
- return imageForRuntime(spec.runtime, void 0, declared);
28343
+ return imageForRuntime(spec.runtime, void 0, declared, variant);
28170
28344
  } catch {
28171
28345
  return null;
28172
28346
  }
28173
28347
  })();
28174
28348
  if (constructed !== null && image === constructed && declared !== null) {
28175
- return resolvePublishedImage(image, spec.runtime, declared);
28349
+ return resolvePublishedImage(image, spec.runtime, declared, variant);
28176
28350
  }
28177
28351
  return image;
28178
28352
  }
@@ -28199,12 +28373,22 @@ function assertVenueOwnerDeclared(lease) {
28199
28373
  return;
28200
28374
  throw new RunRefusalError("this venue did not say which account owns the tree it staged, so the guest would run under this machine's uid and could not write its own clone. We refuse rather than report that permission error as the repo's tests failing.");
28201
28375
  }
28376
+ function refuseUnbuildableSpec(spec) {
28377
+ if (spec.runtime !== "jvm" || spec.installCommand !== null || spec.testCommand !== null)
28378
+ return;
28379
+ const why = spec.unresolved.find((r) => r.kind === "no-test-command")?.detail;
28380
+ if (why === void 0) {
28381
+ throw new EnvRunError("internal: a jvm spec with no test command carries no no-test-command reason");
28382
+ }
28383
+ throw new RunRefusalError(`refusing to run this repository: ${why}.`);
28384
+ }
28202
28385
  async function runEnvironmentSpec(req) {
28203
28386
  const startedAt = Date.now();
28204
28387
  const containment = req.lease.containment;
28205
28388
  if (containment.kind !== "container") {
28206
28389
  throw new EnvRunError(`phase 2 requires the container tier, got ${containment.kind}. Refusing: a container phase that silently ran under seatbelt would make every container claim vacuous.`);
28207
28390
  }
28391
+ refuseUnbuildableSpec(req.spec);
28208
28392
  assertVenueOwnerDeclared(req.lease);
28209
28393
  const image = resolveImageForSpec(req.spec, req.image);
28210
28394
  const { jail, tmp } = req;
@@ -28247,9 +28431,10 @@ async function runEnvironmentSpec(req) {
28247
28431
  installOk: false
28248
28432
  };
28249
28433
  } else if (req.spec.testCommand === null) {
28434
+ const why = req.spec.unresolved.find((r) => r.kind === "no-test-command")?.detail;
28250
28435
  result = {
28251
28436
  outcome: "no-tests-observed",
28252
- note: "the spec derived no test command, so nothing was executed: nothing failed and nothing ran. Certain, not inferred \u2014 no command was ever invoked.",
28437
+ note: "the spec derived no test command, so nothing was executed: nothing failed and nothing ran. Certain, not inferred \u2014 no command was ever invoked." + (why === void 0 ? "" : ` Why: ${why}.`),
28253
28438
  installOk: true
28254
28439
  };
28255
28440
  } else {
@@ -28272,7 +28457,7 @@ async function runEnvironmentSpec(req) {
28272
28457
  labels,
28273
28458
  timeoutMs: req.testTimeoutMs ?? 9e5
28274
28459
  });
28275
- const verdict = classifyVerification(toExecution(test));
28460
+ const verdict = classifyVerification({ ...toExecution(test), runtime: req.spec.runtime });
28276
28461
  result = { outcome: verdict.outcome, note: verdict.reason, installOk: true };
28277
28462
  }
28278
28463
  } finally {
@@ -28286,6 +28471,10 @@ async function runEnvironmentSpec(req) {
28286
28471
  volumes: [],
28287
28472
  networks: []
28288
28473
  };
28474
+ const observation = afterReport ?? {
28475
+ observed: false,
28476
+ unobservedReason: "the run carried no label, so there was nothing to count by"
28477
+ };
28289
28478
  return {
28290
28479
  outcome: result.outcome,
28291
28480
  tier: "container",
@@ -28294,7 +28483,7 @@ async function runEnvironmentSpec(req) {
28294
28483
  test,
28295
28484
  installOk: result.installOk,
28296
28485
  counts: test ? readCounts(test.stdout, test.stderr) : null,
28297
- leaks: judgeLeaks(peak, after),
28486
+ leaks: judgeLeaks(peak, after, observation),
28298
28487
  note: result.note,
28299
28488
  wallMs: Date.now() - startedAt
28300
28489
  };
@@ -28344,7 +28533,7 @@ async function runStep(containment, r) {
28344
28533
  wallMs: Date.now() - startedAt
28345
28534
  };
28346
28535
  }
28347
- var EnvRunError, RunRefusalError, MAX_CAUSE_FRAMES, CHAIN_UNREADABLE, CHAIN_TOO_DEEP, RUNTIME_IMAGES, unversionedImage, TAG_VERSION, dockerManifestProbe, manifestProbe, MISSING_IMAGE_SHAPE;
28536
+ var EnvRunError, RunRefusalError, MAX_CAUSE_FRAMES, CHAIN_UNREADABLE, CHAIN_TOO_DEEP, RUNTIME_IMAGES, JVM_GRADLE_IMAGE, unversionedImage, TAG_VERSION, dockerManifestProbe, manifestProbe, MISSING_IMAGE_SHAPE;
28348
28537
  var init_execute = __esm({
28349
28538
  "../../packages/envrun/dist/execute.js"() {
28350
28539
  "use strict";
@@ -28411,9 +28600,36 @@ var init_execute = __esm({
28411
28600
  suffix: "",
28412
28601
  defaultVersion: "8.0",
28413
28602
  declaredIsFloor: true
28603
+ },
28604
+ /**
28605
+ * TERM-1122. Maven's image, and the one a Gradle WRAPPER repo gets too: the wrapper
28606
+ * downloads its own Gradle, so it needs a JDK and nothing else. MEASURED
28607
+ * 2026-09-18: `maven:3.9-eclipse-temurin-21` carries `git`, `mvn` and JDK 21 on
28608
+ * Ubuntu 24.04, which is why this is not `eclipse-temurin` (no `git`, rejected
28609
+ * under TERM-1139). The JDK sits AFTER maven's own version in the tag, hence
28610
+ * `prefix`, and the major is all envspec derives (`javaMajor`).
28611
+ *
28612
+ * `declaredIsFloor`: a JDK builds for older `--release` targets, so a repo asking
28613
+ * for 16, which has no image, runs on 21. A Gradle toolchain is stricter than a
28614
+ * floor and asks for its exact JDK; Gradle's refusal on the wrong one reads as
28615
+ * ours (`classify.ts`, `isOfflineBuildGap`), never as the repo's.
28616
+ */
28617
+ jvm: {
28618
+ repository: "maven",
28619
+ prefix: "3.9-eclipse-temurin-",
28620
+ suffix: "",
28621
+ defaultVersion: "21",
28622
+ declaredIsFloor: true
28414
28623
  }
28415
28624
  };
28416
- unversionedImage = (shape) => `${shape.repository}:${shape.defaultVersion}${shape.suffix}`;
28625
+ JVM_GRADLE_IMAGE = {
28626
+ repository: "gradle",
28627
+ prefix: "jdk",
28628
+ suffix: "",
28629
+ defaultVersion: "21",
28630
+ declaredIsFloor: true
28631
+ };
28632
+ unversionedImage = (shape) => `${shape.repository}:${shape.prefix ?? ""}${shape.defaultVersion}${shape.suffix}`;
28417
28633
  TAG_VERSION = /^\d+(?:\.\d+){0,2}$/;
28418
28634
  dockerManifestProbe = (image) => {
28419
28635
  const res = spawnSync4("docker", ["manifest", "inspect", image], {
@@ -29105,7 +29321,14 @@ function answerDidItPass(r) {
29105
29321
  const passed = r.status === "verified" && r.outcome !== null && isGreen(r.outcome);
29106
29322
  return { passed, summary: renderVerdictLine(r), lookAt: r.preview?.url ?? null };
29107
29323
  }
29108
- var RUN_TEST_COMMAND_SOURCES, RUN_IMAGE_SOURCES, RUN_RESULT_SCHEMA, RUN_RESULT_FIELDS, RENDER_NONE, FIELD_VIEWS;
29324
+ function exitCodeFor(r) {
29325
+ if (r.status === "refused")
29326
+ return 2;
29327
+ if (r.outcome === null)
29328
+ return 2;
29329
+ return OUTCOME_EXIT_CODES[r.outcome];
29330
+ }
29331
+ var RUN_TEST_COMMAND_SOURCES, RUN_IMAGE_SOURCES, RUN_RESULT_SCHEMA, RUN_RESULT_FIELDS, RENDER_NONE, FIELD_VIEWS, OUTCOME_EXIT_CODES;
29109
29332
  var init_result = __esm({
29110
29333
  "../../packages/envrun/dist/result.js"() {
29111
29334
  "use strict";
@@ -29149,6 +29372,7 @@ var init_result = __esm({
29149
29372
  "containerImageDigest",
29150
29373
  "imageSource",
29151
29374
  "leaksClean",
29375
+ "leakState",
29152
29376
  "venue"
29153
29377
  ];
29154
29378
  RENDER_NONE = null;
@@ -29183,12 +29407,39 @@ var init_result = __esm({
29183
29407
  // Shown only when a human chose the environment. `detected` is the ordinary case and
29184
29408
  // saying so on every run would train the reader to skip the line that matters.
29185
29409
  imageSource: (r) => r.imageSource === "detected" || r.imageSource === "none" ? null : `image source ${r.imageSource} (not signed)`,
29186
- leaksClean: (r) => r.leaksClean === null ? null : r.leaksClean ? null : "WARNING labelled Docker objects survived teardown",
29410
+ // Printed through `leakState` below, which knows WHY a false is false. Rendering both would
29411
+ // print the leak warning on a run where we merely could not look (TERM-1144).
29412
+ leaksClean: RENDER_NONE,
29413
+ // Silent when clean and when refused, as the boolean's line was. The two not-a-leak states
29414
+ // get their own sentence, because "we could not check" read as "we found a leak" is the
29415
+ // exact confusion this field exists to end.
29416
+ leakState: (r) => {
29417
+ switch (r.leakState) {
29418
+ case null:
29419
+ case "clean":
29420
+ return null;
29421
+ case "leak":
29422
+ return "WARNING labelled Docker objects survived teardown";
29423
+ case "inconclusive":
29424
+ return "leak check inconclusive \u2014 no labelled container was seen while the run was live, so finding nothing afterwards proves nothing";
29425
+ case "unobserved":
29426
+ return "leak check not taken \u2014 we could not check what was left after teardown";
29427
+ }
29428
+ },
29187
29429
  // Absent on most runs, so it prints only when there is something to say. Silence
29188
29430
  // here is the honest rendering of "no venue answered": a placeholder line would
29189
29431
  // invite a reader to treat an unanswered probe as a described venue.
29190
29432
  venue: (r) => r.venue === null ? null : renderVenueLine(r.venue)
29191
29433
  };
29434
+ OUTCOME_EXIT_CODES = {
29435
+ completed: 0,
29436
+ "tests-failed": 1,
29437
+ "no-tests-observed": 1,
29438
+ "budget-exceeded": 1,
29439
+ "counts-unparsed": 2,
29440
+ "test-command-unavailable": 2,
29441
+ "environment-exhausted": 2
29442
+ };
29192
29443
  }
29193
29444
  });
29194
29445
 
@@ -31499,11 +31750,7 @@ function makeLease(p) {
31499
31750
  }
31500
31751
  try {
31501
31752
  check("counting what the run left behind");
31502
- return Promise.resolve({
31503
- observed: true,
31504
- census: census(p.docker, label),
31505
- unobservedReason: null
31506
- });
31753
+ return Promise.resolve(censusReport(p.docker, label));
31507
31754
  } catch (err) {
31508
31755
  return Promise.resolve({
31509
31756
  observed: false,
@@ -31771,7 +32018,7 @@ function localDockerPlacement() {
31771
32018
  kind: "local-docker",
31772
32019
  refusal: null,
31773
32020
  venue: () => localVenue(),
31774
- imageFor: (runtime, override, version) => imageForRuntime(runtime, override, version)
32021
+ imageFor: (runtime, override, version, variant) => imageForRuntime(runtime, override, version, variant)
31775
32022
  };
31776
32023
  }
31777
32024
  function hostedPoolPlacement() {
@@ -31779,7 +32026,7 @@ function hostedPoolPlacement() {
31779
32026
  kind: "hosted-pool",
31780
32027
  refusal: null,
31781
32028
  venue: () => hostedVenue(),
31782
- imageFor: (runtime, override, version) => imageForRuntime(runtime, override, version)
32029
+ imageFor: (runtime, override, version, variant) => imageForRuntime(runtime, override, version, variant)
31783
32030
  };
31784
32031
  }
31785
32032
  function placementFor(kind) {
@@ -32344,6 +32591,9 @@ function detectRuntime(repo) {
32344
32591
  if (repo.listNames("").some((name) => /\.(?:csproj|fsproj|sln)$/.test(name))) {
32345
32592
  candidates.push("dotnet");
32346
32593
  }
32594
+ if (candidates.length === 0 && repo.listFiles("").some((f) => f.endsWith(".java"))) {
32595
+ candidates.push("jvm");
32596
+ }
32347
32597
  return { runtime: candidates[0] ?? "unknown", candidates };
32348
32598
  }
32349
32599
  function readJsonObject(repo, path5) {
@@ -32491,6 +32741,11 @@ function basePythonInstallCommand(repo) {
32491
32741
  }
32492
32742
  return null;
32493
32743
  }
32744
+ function rehearse(command) {
32745
+ const copy = '"$R/.terminalhire-rehearsal"';
32746
+ const home = '"$R/.terminalhire-rehearsal-home"';
32747
+ return `{ R="$HOME"; rm -rf ${copy} ${home}; mkdir -p ${home} && cp -R . ${copy} && (cd ${copy} && HOME=${home} GRADLE_USER_HOME="$R/.gradle" JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -Duser.home=$R/.terminalhire-rehearsal-home" ${command}); rm -rf ${copy} ${home}; true; }`;
32748
+ }
32494
32749
  function otherRuntimeCommands(repo, runtime) {
32495
32750
  switch (runtime) {
32496
32751
  case "go":
@@ -32518,10 +32773,21 @@ function otherRuntimeCommands(repo, runtime) {
32518
32773
  case "dotnet":
32519
32774
  return { install: "dotnet restore", test: "dotnet test" };
32520
32775
  case "jvm": {
32521
- if (repo.exists("pom.xml"))
32522
- return { install: "mvn -B dependency:go-offline", test: "mvn -B test" };
32776
+ if (!JVM_BUILD_FILES.some((file) => repo.exists(file)))
32777
+ return { install: null, test: null };
32778
+ if (repo.exists("pom.xml")) {
32779
+ return {
32780
+ install: `mvn -B dependency:go-offline && ${rehearse('mvn -B test -Dmaven.test.failure.ignore=true -Dmaven.repo.local="$R/.m2/repository"')}`,
32781
+ test: "mvn -B -o test"
32782
+ };
32783
+ }
32523
32784
  const wrapper = repo.exists("gradlew") ? "./gradlew" : "gradle";
32524
- return { install: `${wrapper} dependencies`, test: `${wrapper} test` };
32785
+ return {
32786
+ install: `${wrapper} dependencies && ${rehearse(`${wrapper} test --continue`)}`,
32787
+ // `--no-build-cache`: the rehearsal above can fill Gradle's build cache, and a
32788
+ // test task restored FROM-CACHE runs nothing and prints no count.
32789
+ test: `${wrapper} test --offline --no-build-cache`
32790
+ };
32525
32791
  }
32526
32792
  default:
32527
32793
  return { install: null, test: null };
@@ -32553,6 +32819,15 @@ function searchRuntimeVersion(repo, runtime) {
32553
32819
  push(".ruby-version", repo.readText(".ruby-version"));
32554
32820
  } else if (runtime === "dotnet") {
32555
32821
  push("global.json sdk.version", readStringField(readObjectField(readJsonObject(repo, "global.json"), "sdk"), "version"));
32822
+ } else if (runtime === "jvm") {
32823
+ const pom = repo.readText("pom.xml");
32824
+ const gradle = repo.readText("build.gradle") ?? repo.readText("build.gradle.kts");
32825
+ push("build.gradle toolchain languageVersion", javaMajor(matchFirst(gradle, /JavaLanguageVersion\.of\(\s*["']?(\d+)["']?\s*\)/) ?? matchFirst(gradle, /jvmToolchain\(\s*(\d+)\s*\)/)));
32826
+ push(".java-version", javaMajor(repo.readText(".java-version")));
32827
+ push("pom.xml maven.compiler.release", javaMajor(matchFirst(pom, /<maven\.compiler\.release>\s*([^<\s]+)\s*</)));
32828
+ push("pom.xml java.version", javaMajor(matchFirst(pom, /<java\.version>\s*([^<\s]+)\s*</)));
32829
+ push("pom.xml maven.compiler.source", javaMajor(matchFirst(pom, /<maven\.compiler\.source>\s*([^<\s]+)\s*</)));
32830
+ push("build.gradle sourceCompatibility", javaMajor(matchFirst(gradle, /sourceCompatibility\s*=\s*JavaVersion\.VERSION_([\d_]+)/)?.replace("_", ".") ?? matchFirst(gradle, /sourceCompatibility\s*=\s*["']?([\d.]+)["']?/)));
32556
32831
  }
32557
32832
  let rangeFound = null;
32558
32833
  for (const source of sources) {
@@ -32566,13 +32841,21 @@ function searchRuntimeVersion(repo, runtime) {
32566
32841
  }
32567
32842
  return { version: null, searched: sources.map((s) => s.label), rangeFound };
32568
32843
  }
32844
+ function javaMajor(text) {
32845
+ if (text === null)
32846
+ return null;
32847
+ const match2 = /^(?:1\.(\d+)|(\d+))(?:[._][\d_.]*)?$/.exec(text.trim());
32848
+ if (match2 === null)
32849
+ return null;
32850
+ return match2[1] ?? match2[2] ?? null;
32851
+ }
32569
32852
  function matchFirst(text, pattern) {
32570
32853
  if (text === null)
32571
32854
  return null;
32572
32855
  const match2 = pattern.exec(text);
32573
32856
  return match2 === null ? null : match2[1];
32574
32857
  }
32575
- var RUNTIME_MANIFESTS, MANIFEST_FILENAMES, NPM_PLACEHOLDER_TEST, REQUIREMENT_SPECIFIER, EXACT_VERSION;
32858
+ var RUNTIME_MANIFESTS, MANIFEST_FILENAMES, JVM_BUILD_FILES, NPM_PLACEHOLDER_TEST, REQUIREMENT_SPECIFIER, EXACT_VERSION;
32576
32859
  var init_manifest2 = __esm({
32577
32860
  "../../packages/envspec/dist/manifest.js"() {
32578
32861
  "use strict";
@@ -32586,6 +32869,7 @@ var init_manifest2 = __esm({
32586
32869
  { runtime: "dotnet", files: [] }
32587
32870
  ];
32588
32871
  MANIFEST_FILENAMES = RUNTIME_MANIFESTS.flatMap((m) => m.files).concat(["*.csproj", "*.fsproj", "*.sln"]).sort();
32872
+ JVM_BUILD_FILES = ["build.gradle", "build.gradle.kts", "pom.xml"];
32589
32873
  NPM_PLACEHOLDER_TEST = /^echo\s+["']?Error:\s*no test specified["']?\s*&&\s*exit\s+1$/;
32590
32874
  REQUIREMENT_SPECIFIER = /^[A-Za-z0-9._-]+(\[[A-Za-z0-9._,-]+\])?([<>=!~]=?[A-Za-z0-9._*+-]+(,[<>=!~]=?[A-Za-z0-9._*+-]+)*)?$/;
32591
32875
  EXACT_VERSION = /^v?(\d+(?:\.\d+){0,2})$/;
@@ -32982,7 +33266,7 @@ function deriveFromReader(repo) {
32982
33266
  searched: MANIFEST_FILENAMES,
32983
33267
  detail: `no ecosystem manifest was found at the repo root (looked for ${MANIFEST_FILENAMES.join(", ")}), so the language runtime could not be identified`
32984
33268
  });
32985
- } else {
33269
+ } else if (runtime !== "jvm" || JVM_BUILD_FILES.some((file) => repo.exists(file))) {
32986
33270
  derivedFrom.add("manifest");
32987
33271
  }
32988
33272
  if (detection.candidates.length > 1) {
@@ -33146,12 +33430,13 @@ function deriveRuntimeVersion(repo, runtime, job) {
33146
33430
  const setup = SETUP_ACTIONS[runtime];
33147
33431
  const searched = [];
33148
33432
  let rangeFound = null;
33433
+ const pin = (raw) => runtime === "jvm" ? javaMajor(raw) : exactVersion(raw);
33149
33434
  if (job !== null && setup !== void 0) {
33150
33435
  const direct = findActionInput(job, setup.action, setup.input);
33151
33436
  if (direct !== null) {
33152
33437
  searched.push(`${job.file} ${setup.action} ${setup.input}`);
33153
33438
  const reduced = reduceExpression(direct.command, job.singletons);
33154
- const exact = exactVersion(reduced);
33439
+ const exact = pin(reduced);
33155
33440
  if (exact !== null)
33156
33441
  return { value: exact, searched, rangeFound: null };
33157
33442
  if (reduced !== null)
@@ -33160,7 +33445,7 @@ function deriveRuntimeVersion(repo, runtime, job) {
33160
33445
  const viaFile = findActionInput(job, setup.action, setup.fileInput);
33161
33446
  if (viaFile !== null) {
33162
33447
  searched.push(`${job.file} ${setup.action} ${setup.fileInput} -> ${viaFile.command}`);
33163
- const exact = exactVersion(repo.readText(viaFile.command));
33448
+ const exact = pin(repo.readText(viaFile.command));
33164
33449
  if (exact !== null)
33165
33450
  return { value: exact, searched, rangeFound: null };
33166
33451
  }
@@ -33185,6 +33470,8 @@ function testSearchPaths(runtime, workflowFiles) {
33185
33470
  paths.push("**/*_test.go");
33186
33471
  if (runtime === "ruby")
33187
33472
  paths.push("Gemfile", "Rakefile");
33473
+ if (runtime === "jvm")
33474
+ paths.push(...JVM_BUILD_FILES);
33188
33475
  if (runtime === "unknown")
33189
33476
  paths.push(...MANIFEST_FILENAMES);
33190
33477
  return [...new Set(paths)].sort();
@@ -33202,6 +33489,9 @@ function describeTestSearch(repo, runtime, workflowFiles) {
33202
33489
  if (runtime === "python") {
33203
33490
  return `${ciPart}, and nothing in the repo names a test runner \u2014 no \`[tool.pytest.ini_options]\`, no \`pytest.ini\`, and no pytest dependency in \`pyproject.toml\` or a requirements file`;
33204
33491
  }
33492
+ if (runtime === "jvm" && !JVM_BUILD_FILES.some((file) => repo.exists(file))) {
33493
+ return `${ciPart}, and the repo has Java sources but no build file (${JVM_BUILD_FILES.join(", ")}), so there is no build to run tests with. Compiling the sources with \`javac\` alone would run no tests`;
33494
+ }
33205
33495
  return `${ciPart}, and no ${runtime} test convention applies to this tree`;
33206
33496
  }
33207
33497
  function installSearchPaths(runtime, workflowFiles) {
@@ -33210,6 +33500,8 @@ function installSearchPaths(runtime, workflowFiles) {
33210
33500
  paths.push("package-lock.json", "pnpm-lock.yaml", "yarn.lock");
33211
33501
  if (runtime === "python")
33212
33502
  paths.push("poetry.lock", "pyproject.toml", "requirements.txt", "uv.lock");
33503
+ if (runtime === "jvm")
33504
+ paths.push(...JVM_BUILD_FILES);
33213
33505
  if (runtime === "unknown")
33214
33506
  paths.push(...MANIFEST_FILENAMES);
33215
33507
  return [...new Set(paths)].sort();
@@ -33288,12 +33580,41 @@ var init_dist3 = __esm({
33288
33580
  }
33289
33581
  });
33290
33582
 
33583
+ // ../../packages/envrun/dist/gradleTestSummary.js
33584
+ import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync14 } from "fs";
33585
+ import { join as join26 } from "path";
33586
+ function stageGradleTestSummary(jailHome) {
33587
+ const dir = join26(jailHome, ".gradle", "init.d");
33588
+ mkdirSync5(dir, { recursive: true });
33589
+ writeFileSync14(join26(dir, "terminalhire-test-summary.gradle"), GRADLE_TEST_SUMMARY_INIT);
33590
+ }
33591
+ var GRADLE_TEST_MARKER, GRADLE_TEST_SUMMARY_INIT;
33592
+ var init_gradleTestSummary = __esm({
33593
+ "../../packages/envrun/dist/gradleTestSummary.js"() {
33594
+ "use strict";
33595
+ GRADLE_TEST_MARKER = "terminalhire-gradle-tests:";
33596
+ GRADLE_TEST_SUMMARY_INIT = `// Written by terminalhire (TERM-1122): prints each Test task's counts, because
33597
+ // Gradle prints none when every test passes.
33598
+ allprojects {
33599
+ tasks.withType(Test).configureEach { task ->
33600
+ def label = task.path
33601
+ task.afterSuite { desc, result ->
33602
+ if (desc.parent == null) {
33603
+ println "${GRADLE_TEST_MARKER} task=\${label} total=\${result.testCount} passed=\${result.successfulTestCount} failed=\${result.failedTestCount} skipped=\${result.skippedTestCount}"
33604
+ }
33605
+ }
33606
+ }
33607
+ }
33608
+ `;
33609
+ }
33610
+ });
33611
+
33291
33612
  // ../../packages/envrun/dist/thrun.js
33292
33613
  import { execFileSync, spawnSync as spawnSync6 } from "child_process";
33293
- import { existsSync as existsSync12, mkdirSync as mkdirSync5, mkdtempSync as mkdtempSync4, rmSync as rmSync9 } from "fs";
33614
+ import { existsSync as existsSync12, mkdirSync as mkdirSync6, mkdtempSync as mkdtempSync4, rmSync as rmSync9 } from "fs";
33294
33615
  import { randomUUID as randomUUID3 } from "crypto";
33295
33616
  import { tmpdir as tmpdir4 } from "os";
33296
- import { join as join26 } from "path";
33617
+ import { join as join27 } from "path";
33297
33618
  function git(repoDir, args, allowNonZero = false) {
33298
33619
  const res = spawnSync6("git", [...args], {
33299
33620
  cwd: repoDir,
@@ -33308,7 +33629,7 @@ function git(repoDir, args, allowNonZero = false) {
33308
33629
  return res.stdout ?? "";
33309
33630
  }
33310
33631
  function collectWorkingDiff(repoDir, opts = {}) {
33311
- if (!existsSync12(join26(repoDir, ".git"))) {
33632
+ if (!existsSync12(join27(repoDir, ".git"))) {
33312
33633
  throw new ThRunError(`${repoDir} is not a git checkout (no .git). \`th run\` ships the working diff, so it needs a repository to read one from.`);
33313
33634
  }
33314
33635
  const headSha = git(repoDir, ["rev-parse", "HEAD"]).trim();
@@ -33456,7 +33777,7 @@ function credentialFreeHome() {
33456
33777
  return credentialFreeHomeDir;
33457
33778
  let made;
33458
33779
  try {
33459
- made = mkdtempSync4(join26(tmpdir4(), "th-run-nohome-"));
33780
+ made = mkdtempSync4(join27(tmpdir4(), "th-run-nohome-"));
33460
33781
  } catch (err) {
33461
33782
  throw new RunRefusalError("could not create the empty directory this clone uses as its home, so the clone would read the credentials on this machine instead. That is our environment failing, not your tests: check that the temp directory is writable.", { cause: err });
33462
33783
  }
@@ -33531,7 +33852,7 @@ function cloneTargetAtUnguarded(opts) {
33531
33852
  if (persisted !== null) {
33532
33853
  throw new RunRefusalError(`refusing to clone from a URL carrying ${persisted}: \`git remote add\` writes the source verbatim into .git/config, which is mounted where the repo\u2019s own test command runs. Fetch with the credential out of band so it is never written to disk \u2014 this runner takes one as an HTTP header, which is never persisted.`);
33533
33854
  }
33534
- mkdirSync5(opts.dest, { recursive: true });
33855
+ mkdirSync6(opts.dest, { recursive: true });
33535
33856
  const runOut = (args) => execFileSync("git", [...gitConfigArgs(), ...args], {
33536
33857
  cwd: opts.dest,
33537
33858
  encoding: "utf8",
@@ -33570,7 +33891,7 @@ function cloneTargetAtUnguarded(opts) {
33570
33891
  }
33571
33892
  function scrubCloneSource(dest, run2) {
33572
33893
  run2(["remote", "remove", "origin"]);
33573
- rmSync9(join26(dest, ".git", "FETCH_HEAD"), { force: true });
33894
+ rmSync9(join27(dest, ".git", "FETCH_HEAD"), { force: true });
33574
33895
  }
33575
33896
  function publishableTarget(url) {
33576
33897
  if (separatorInTarget(url) !== null)
@@ -33718,6 +34039,9 @@ function refusedRun(fields) {
33718
34039
  containerImage: null,
33719
34040
  containerImageDigest: null,
33720
34041
  leaksClean: null,
34042
+ // Null for the same reason, and never `unobserved`: that word says we tried to take a
34043
+ // census and could not, and here there was nothing to take one of (TERM-1144).
34044
+ leakState: null,
33721
34045
  // A refused run never held a lease, so there is no venue to describe. Same
33722
34046
  // reasoning as `leaksClean` above: null because nothing happened, and it must
33723
34047
  // not read as a venue we looked at and could not name.
@@ -33945,10 +34269,10 @@ async function runVerification(req, ctx) {
33945
34269
  venueIdentity: null
33946
34270
  };
33947
34271
  }
33948
- const stage = join26(req.scratchRoot, runId);
33949
- const cloneDir = join26(stage, "clone");
33950
- const scratch = join26(stage, "scratch");
33951
- mkdirSync5(scratch, { recursive: true });
34272
+ const stage = join27(req.scratchRoot, runId);
34273
+ const cloneDir = join27(stage, "clone");
34274
+ const scratch = join27(stage, "scratch");
34275
+ mkdirSync6(scratch, { recursive: true });
33952
34276
  assertSafeTargetSha(req.targetSha);
33953
34277
  progress("clone", `${publishableTarget(req.targetRepo)} @ ${req.targetSha.slice(0, 12)}`);
33954
34278
  cloneTargetAt({
@@ -33975,7 +34299,8 @@ async function runVerification(req, ctx) {
33975
34299
  const derived = deriveEnvironmentSpec(cloneDir);
33976
34300
  const spec = req.testCommandOverride === void 0 ? derived : { ...derived, testCommand: req.testCommandOverride };
33977
34301
  progress("derive", `runtime=${spec.runtime} install=${String(spec.installCommand)} test=${String(spec.testCommand)}`);
33978
- const image = placement.imageFor(spec.runtime, req.image, spec.runtimeVersion);
34302
+ refuseUnbuildableSpec(spec);
34303
+ const image = placement.imageFor(spec.runtime, req.image, spec.runtimeVersion, imageVariantFor(spec));
33979
34304
  const resolved = await resolveLease(placement, runId);
33980
34305
  if (!resolved.ok) {
33981
34306
  return {
@@ -34010,10 +34335,12 @@ async function runVerification(req, ctx) {
34010
34335
  const lease = resolved.lease;
34011
34336
  try {
34012
34337
  buildJail(scratch);
34338
+ if (spec.runtime === "jvm")
34339
+ stageGradleTestSummary(localJailPaths(scratch).jail);
34013
34340
  const venuePaths = await lease.stage({
34014
34341
  cloneDir,
34015
34342
  scratchRoot: scratch,
34016
- previewDir: join26(stage, "preview"),
34343
+ previewDir: join27(stage, "preview"),
34017
34344
  // On a dispatched run the commit is the statement of what was tested, so
34018
34345
  // it rides with the tree and the venue seam refuses a tree that is not
34019
34346
  // that commit (design §6 item 4, TERM-892 — the guard lives in
@@ -34077,6 +34404,7 @@ async function runVerification(req, ctx) {
34077
34404
  // the operator would sign our name onto their choice.
34078
34405
  imageSource: req.image === void 0 ? "detected" : req.imageOrigin === "operator" ? "operator-declared" : "developer-declared",
34079
34406
  leaksClean: verdict.leaks.clean,
34407
+ leakState: verdict.leaks.state,
34080
34408
  // Built from the LEASE, over the client that ran the steps — never from
34081
34409
  // `req.placement`, which is a request. `venueDescriptor.ts` carries the
34082
34410
  // reasoning and the #735 failure that makes the distinction load-bearing.
@@ -34134,6 +34462,7 @@ var init_thrun = __esm({
34134
34462
  init_execute();
34135
34463
  init_placement();
34136
34464
  init_venue();
34465
+ init_gradleTestSummary();
34137
34466
  init_venueDescriptor();
34138
34467
  init_result();
34139
34468
  ThRunError = class extends Error {
@@ -34377,7 +34706,7 @@ var init_dbplan = __esm({
34377
34706
  // ../../packages/envrun/dist/dbstack.js
34378
34707
  import { spawnSync as spawnSync7 } from "child_process";
34379
34708
  import { randomBytes as randomBytes11 } from "crypto";
34380
- import { mkdirSync as mkdirSync6 } from "fs";
34709
+ import { mkdirSync as mkdirSync7 } from "fs";
34381
34710
  function installCommandFor(runner) {
34382
34711
  switch (runner) {
34383
34712
  case "sql":
@@ -34608,7 +34937,7 @@ function startDatabase(req) {
34608
34937
  if (!ready.ok) {
34609
34938
  throw new DbStackError(`INFRASTRUCTURE/INCONCLUSIVE: Postgres never accepted queries at 127.0.0.1:${String(creds.port)} within the readiness window: ${ready.detail}`);
34610
34939
  }
34611
- const query = (sql) => {
34940
+ const query2 = (sql) => {
34612
34941
  const res = docker2([
34613
34942
  "exec",
34614
34943
  `--env=PGPASSWORD=${creds.password}`,
@@ -34656,7 +34985,7 @@ function startDatabase(req) {
34656
34985
  credentials: creds,
34657
34986
  image,
34658
34987
  readyMs: ready.ms,
34659
- query,
34988
+ query: query2,
34660
34989
  runOnNetwork,
34661
34990
  teardown
34662
34991
  };
@@ -34719,8 +35048,8 @@ async function installLocalMigrationTooling(opts) {
34719
35048
  };
34720
35049
  }
34721
35050
  const { jail, tmp } = buildJail(opts.scratchRoot);
34722
- mkdirSync6(jail, { recursive: true });
34723
- mkdirSync6(tmp, { recursive: true });
35051
+ mkdirSync7(jail, { recursive: true });
35052
+ mkdirSync7(tmp, { recursive: true });
34724
35053
  const spec = {
34725
35054
  profile: "install",
34726
35055
  clone: opts.repoDir,
@@ -35015,6 +35344,7 @@ __export(dist_exports, {
35015
35344
  GOOGLE_JWKS_URL: () => GOOGLE_JWKS_URL,
35016
35345
  HostedVenueError: () => HostedVenueError,
35017
35346
  JWKS_FETCH_TIMEOUT_MS: () => JWKS_FETCH_TIMEOUT_MS,
35347
+ LEAK_STATES: () => LEAK_STATES,
35018
35348
  LOCAL_MEASUREMENT_PREFIX: () => LOCAL_MEASUREMENT_PREFIX,
35019
35349
  LabelWatch: () => LabelWatch,
35020
35350
  MIN_GIT_VERSION_FOR_END_OF_OPTIONS: () => MIN_GIT_VERSION_FOR_END_OF_OPTIONS,
@@ -35048,6 +35378,7 @@ __export(dist_exports, {
35048
35378
  VENUE_GCLOUD_CONFIG: () => VENUE_GCLOUD_CONFIG,
35049
35379
  VENUE_SSH_USER: () => VENUE_SSH_USER,
35050
35380
  VENV_DIR: () => VENV_DIR,
35381
+ VERIFICATION_OUTCOMES: () => VERIFICATION_OUTCOMES,
35051
35382
  VenueRollbackError: () => VenueRollbackError,
35052
35383
  acquireTransactionally: () => acquireTransactionally,
35053
35384
  alembicChainPosition: () => alembicChainPosition,
@@ -35061,6 +35392,7 @@ __export(dist_exports, {
35061
35392
  assertVenueOwnerDeclared: () => assertVenueOwnerDeclared,
35062
35393
  bookkeepingFor: () => bookkeepingFor,
35063
35394
  census: () => census,
35395
+ censusReport: () => censusReport,
35064
35396
  censusTotal: () => censusTotal,
35065
35397
  classifyBootFailure: () => classifyBootFailure,
35066
35398
  classifyProbeFailure: () => classifyProbeFailure,
@@ -35080,6 +35412,7 @@ __export(dist_exports, {
35080
35412
  detectRunner: () => detectRunner,
35081
35413
  endOfOptionsUnsupported: () => endOfOptionsUnsupported,
35082
35414
  ensureVenueServiceCredentials: () => ensureVenueServiceCredentials,
35415
+ exitCodeFor: () => exitCodeFor,
35083
35416
  failureSourceOf: () => failureSourceOf,
35084
35417
  findRunRefusal: () => findRunRefusal,
35085
35418
  gcpBootArgv: () => gcpBootArgv,
@@ -35094,6 +35427,7 @@ __export(dist_exports, {
35094
35427
  identityProbeCommand: () => identityProbeCommand,
35095
35428
  imageForRuntime: () => imageForRuntime,
35096
35429
  imageRepo: () => imageRepo,
35430
+ imageVariantFor: () => imageVariantFor,
35097
35431
  installCommandFor: () => installCommandFor,
35098
35432
  installLocalMigrationTooling: () => installLocalMigrationTooling,
35099
35433
  isBookkeepingTable: () => isBookkeepingTable,
@@ -35123,6 +35457,7 @@ __export(dist_exports, {
35123
35457
  readSchema: () => readSchema,
35124
35458
  recordedApplied: () => recordedApplied,
35125
35459
  refuseSshTransport: () => refuseSshTransport,
35460
+ refuseUnbuildableSpec: () => refuseUnbuildableSpec,
35126
35461
  renderRunReport: () => renderRunReport,
35127
35462
  renderVenueLine: () => renderVenueLine,
35128
35463
  renderVerdictLine: () => renderVerdictLine,
@@ -35209,8 +35544,8 @@ __export(cache_store_exports, {
35209
35544
  updateIndexCache: () => updateIndexCache,
35210
35545
  writeIndexCache: () => writeIndexCache
35211
35546
  });
35212
- import { readFileSync as readFileSync13, writeFileSync as writeFileSync14, renameSync as renameSync5 } from "fs";
35213
- import { join as join27 } from "path";
35547
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync15, renameSync as renameSync5 } from "fs";
35548
+ import { join as join28 } from "path";
35214
35549
  import { homedir as homedir13 } from "os";
35215
35550
  function readCacheEntry() {
35216
35551
  try {
@@ -35229,7 +35564,7 @@ function updateIndexCache(patch) {
35229
35564
  ts: Date.now()
35230
35565
  };
35231
35566
  const tmp = `${INDEX_CACHE_FILE}.${process.pid}.${tmpCounter++}.tmp`;
35232
- writeFileSync14(tmp, JSON.stringify(entry), "utf8");
35567
+ writeFileSync15(tmp, JSON.stringify(entry), "utf8");
35233
35568
  renameSync5(tmp, INDEX_CACHE_FILE);
35234
35569
  return entry;
35235
35570
  }
@@ -35241,8 +35576,8 @@ var init_cache_store = __esm({
35241
35576
  "bin/cache-store.js"() {
35242
35577
  "use strict";
35243
35578
  init_state_dir();
35244
- TERMINALHIRE_DIR10 = process.env.TERMINALHIRE_DIR || join27(homedir13(), ".terminalhire");
35245
- INDEX_CACHE_FILE = join27(TERMINALHIRE_DIR10, "index-cache.json");
35579
+ TERMINALHIRE_DIR10 = process.env.TERMINALHIRE_DIR || join28(homedir13(), ".terminalhire");
35580
+ INDEX_CACHE_FILE = join28(TERMINALHIRE_DIR10, "index-cache.json");
35246
35581
  SCHEMA_VERSION2 = 1;
35247
35582
  tmpCounter = 0;
35248
35583
  }
@@ -35442,8 +35777,8 @@ var init_audit2 = __esm({
35442
35777
  init_src();
35443
35778
  import {
35444
35779
  readFileSync as readFileSync14,
35445
- writeFileSync as writeFileSync15,
35446
- mkdirSync as mkdirSync7,
35780
+ writeFileSync as writeFileSync16,
35781
+ mkdirSync as mkdirSync8,
35447
35782
  mkdtempSync as mkdtempSync5,
35448
35783
  renameSync as renameSync6,
35449
35784
  existsSync as existsSync13,
@@ -35452,7 +35787,7 @@ import {
35452
35787
  rmSync as rmSync10,
35453
35788
  readdirSync as readdirSync3
35454
35789
  } from "fs";
35455
- import { join as join28, dirname as dirname8, isAbsolute as isAbsolute4, resolve as pathResolve } from "path";
35790
+ import { join as join29, dirname as dirname8, isAbsolute as isAbsolute4, resolve as pathResolve } from "path";
35456
35791
  import { createHash as createHash10 } from "crypto";
35457
35792
  import { homedir as homedir14, hostname as osHostname } from "os";
35458
35793
  import { execFile as execFile3, execFileSync as execFileSync2, spawnSync as spawnSync8 } from "child_process";
@@ -35899,10 +36234,10 @@ async function syncFounderVerdicts({
35899
36234
 
35900
36235
  // bin/jpi-claim.js
35901
36236
  init_founder_note_sync();
35902
- var TERMINALHIRE_DIR11 = process.env.TERMINALHIRE_DIR || join28(homedir14(), ".terminalhire");
35903
- var INDEX_CACHE_FILE2 = join28(TERMINALHIRE_DIR11, "index-cache.json");
35904
- var CLAIM_PUSH_MARKER = join28(TERMINALHIRE_DIR11, "claim-push.json");
35905
- var REPO_CONTINUITY_NUDGE_MARKER = join28(TERMINALHIRE_DIR11, "repo-continuity-nudged.json");
36237
+ var TERMINALHIRE_DIR11 = process.env.TERMINALHIRE_DIR || join29(homedir14(), ".terminalhire");
36238
+ var INDEX_CACHE_FILE2 = join29(TERMINALHIRE_DIR11, "index-cache.json");
36239
+ var CLAIM_PUSH_MARKER = join29(TERMINALHIRE_DIR11, "claim-push.json");
36240
+ var REPO_CONTINUITY_NUDGE_MARKER = join29(TERMINALHIRE_DIR11, "repo-continuity-nudged.json");
35906
36241
  function readNudgedClaimIds() {
35907
36242
  try {
35908
36243
  const raw = JSON.parse(readFileSync14(REPO_CONTINUITY_NUDGE_MARKER, "utf8"));
@@ -35916,7 +36251,7 @@ function markClaimNudged(id) {
35916
36251
  const ids2 = readNudgedClaimIds();
35917
36252
  ids2.add(id);
35918
36253
  ensureStateDir(TERMINALHIRE_DIR11);
35919
- writeFileSync15(REPO_CONTINUITY_NUDGE_MARKER, JSON.stringify({ claimIds: [...ids2] }), "utf8");
36254
+ writeFileSync16(REPO_CONTINUITY_NUDGE_MARKER, JSON.stringify({ claimIds: [...ids2] }), "utf8");
35920
36255
  } catch {
35921
36256
  }
35922
36257
  }
@@ -38249,7 +38584,7 @@ async function cmdAttach(id, worktree, branch) {
38249
38584
  function workDirFor(repoFullName, issueNumber) {
38250
38585
  const [owner, repo] = String(repoFullName).split("/");
38251
38586
  const suffix = issueNumber ? `-${issueNumber}` : "";
38252
- return join28(homedir14(), "terminalhire", "work", `${owner}-${repo}${suffix}`);
38587
+ return join29(homedir14(), "terminalhire", "work", `${owner}-${repo}${suffix}`);
38253
38588
  }
38254
38589
  function startBranchFor(repoFullName, issueNumber) {
38255
38590
  const repo = String(repoFullName).split("/")[1] || "claim";
@@ -38505,7 +38840,7 @@ terminalhire claim: not started \u2014 starting forks ${claim.repoFullName} to y
38505
38840
  );
38506
38841
  process.exit(1);
38507
38842
  }
38508
- mkdirSync7(join28(homedir14(), "terminalhire", "work"), { recursive: true });
38843
+ mkdirSync8(join29(homedir14(), "terminalhire", "work"), { recursive: true });
38509
38844
  const { createProgress: createProgress2, parseGitProgress: parseGitProgress2, splitProgressChunk: splitProgressChunk2, shStream: shStream2 } = await Promise.resolve().then(() => (init_progress(), progress_exports));
38510
38845
  const progress = createProgress2();
38511
38846
  let forkFullName;
@@ -38633,7 +38968,7 @@ function founderPostingIdOf(claim) {
38633
38968
  }
38634
38969
  function sliceWorkDirFor(claimLocalId) {
38635
38970
  const safe = String(claimLocalId).replace(/[^A-Za-z0-9._-]/g, "-");
38636
- return join28(homedir14(), "terminalhire", "work", `slice-${safe}`);
38971
+ return join29(homedir14(), "terminalhire", "work", `slice-${safe}`);
38637
38972
  }
38638
38973
  function assertNoBooleanPath(dest, flagName) {
38639
38974
  const last = String(dest).split(/[\\/]/).filter(Boolean).pop();
@@ -38758,9 +39093,9 @@ function writeSliceFiles(destDir, files) {
38758
39093
  const unavailable = [];
38759
39094
  for (const f of files) {
38760
39095
  if (typeof f.content === "string") {
38761
- const abs = join28(destDir, f.path);
38762
- mkdirSync7(dirname8(abs), { recursive: true });
38763
- writeFileSync15(abs, f.content, "utf8");
39096
+ const abs = join29(destDir, f.path);
39097
+ mkdirSync8(dirname8(abs), { recursive: true });
39098
+ writeFileSync16(abs, f.content, "utf8");
38764
39099
  written.push(f.path);
38765
39100
  } else {
38766
39101
  unavailable.push({ path: f.path, reason: f.unavailableReason || "(no reason given)" });
@@ -38794,7 +39129,7 @@ function writeDeliveredBrief(destDir, spec) {
38794
39129
  function ensureExcludedPackDir(destDir) {
38795
39130
  let occupant = null;
38796
39131
  try {
38797
- occupant = lstatSync3(join28(destDir, BRIEF_DIR));
39132
+ occupant = lstatSync3(join29(destDir, BRIEF_DIR));
38798
39133
  } catch (err) {
38799
39134
  if (err?.code !== "ENOENT") {
38800
39135
  return {
@@ -38809,12 +39144,12 @@ function ensureExcludedPackDir(destDir) {
38809
39144
  reason: `${BRIEF_DIR}/ already exists in the delivered tree, and excluding it would hide that content from your patch`
38810
39145
  };
38811
39146
  }
38812
- const excludeFile = join28(destDir, ".git", "info", "exclude");
39147
+ const excludeFile = join29(destDir, ".git", "info", "exclude");
38813
39148
  try {
38814
39149
  const existing = existsSync13(excludeFile) ? readFileSync14(excludeFile, "utf8") : "";
38815
39150
  if (!existing.split("\n").includes(BRIEF_EXCLUDE_LINE)) {
38816
- mkdirSync7(dirname8(excludeFile), { recursive: true });
38817
- writeFileSync15(
39151
+ mkdirSync8(dirname8(excludeFile), { recursive: true });
39152
+ writeFileSync16(
38818
39153
  excludeFile,
38819
39154
  `${existing}${existing === "" || existing.endsWith("\n") ? "" : "\n"}${BRIEF_EXCLUDE_LINE}
38820
39155
  `,
@@ -38828,9 +39163,9 @@ function ensureExcludedPackDir(destDir) {
38828
39163
  }
38829
39164
  function writePackFile(destDir, relPath, content, what) {
38830
39165
  try {
38831
- const abs = join28(destDir, relPath);
38832
- mkdirSync7(dirname8(abs), { recursive: true });
38833
- writeFileSync15(abs, content, { encoding: "utf8", flag: "wx" });
39166
+ const abs = join29(destDir, relPath);
39167
+ mkdirSync8(dirname8(abs), { recursive: true });
39168
+ writeFileSync16(abs, content, { encoding: "utf8", flag: "wx" });
38834
39169
  } catch (err) {
38835
39170
  return { written: false, reason: `the ${what} could not be written (${err.message})` };
38836
39171
  }
@@ -39245,7 +39580,7 @@ async function cmdSliceFullTier(claims, id, local, fullTierBody, flags, cloneRep
39245
39580
  if (resolvedDir.suffixed) {
39246
39581
  console.log(`terminalhire claim: the usual directory has content \u2014 using ${dest}`);
39247
39582
  }
39248
- mkdirSync7(dest, { recursive: true });
39583
+ mkdirSync8(dest, { recursive: true });
39249
39584
  const branch = `claim/${String(claim.id).replace(/[^A-Za-z0-9._-]/g, "-")}`;
39250
39585
  let engine;
39251
39586
  try {
@@ -39427,7 +39762,7 @@ async function attemptSliceDelivery(id, flags = {}) {
39427
39762
  if (resolvedDir.suffixed) {
39428
39763
  console.log(`terminalhire claim: the usual directory has content \u2014 using ${finalDest}`);
39429
39764
  }
39430
- mkdirSync7(dirname8(finalDest), { recursive: true });
39765
+ mkdirSync8(dirname8(finalDest), { recursive: true });
39431
39766
  let dest = mkdtempSync5(`${finalDest}.tmp-`);
39432
39767
  const { written, unavailable } = writeSliceFiles(dest, body.files);
39433
39768
  const branch = `claim/${String(claim.id).replace(/[^A-Za-z0-9._-]/g, "-")}`;
@@ -39968,7 +40303,7 @@ async function cmdSubmit(id, flags = {}) {
39968
40303
  const head = `${ghUser}:${claim.branch}`;
39969
40304
  const title = flags.title || claim.title;
39970
40305
  const noBody = Boolean(flags["no-body"]);
39971
- const prBodyPath = join28(wt, "PR-BODY.md");
40306
+ const prBodyPath = join29(wt, "PR-BODY.md");
39972
40307
  const bodySource = pickBodySource({
39973
40308
  bodyFileFlag: flags["body-file"],
39974
40309
  noBody,
@@ -40208,7 +40543,7 @@ function readClaimPushMarker() {
40208
40543
  }
40209
40544
  function writeClaimPushMarker(marker) {
40210
40545
  ensureStateDir(TERMINALHIRE_DIR11);
40211
- writeFileSync15(CLAIM_PUSH_MARKER, JSON.stringify(marker, null, 2) + "\n", "utf8");
40546
+ writeFileSync16(CLAIM_PUSH_MARKER, JSON.stringify(marker, null, 2) + "\n", "utf8");
40212
40547
  }
40213
40548
  function clearClaimPushMarker() {
40214
40549
  try {