terminalhire 0.42.21 → 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.
@@ -2570,11 +2570,11 @@ function parseGitHubRef(url) {
2570
2570
  kind: m[3] === "pull" ? "pull" : "issue"
2571
2571
  };
2572
2572
  }
2573
- async function ghGraphQL(query, variables, token, signal, governor) {
2573
+ async function ghGraphQL(query2, variables, token, signal, governor) {
2574
2574
  const init = {
2575
2575
  method: "POST",
2576
2576
  headers: { ...ghHeaders(token), "Content-Type": "application/json" },
2577
- body: JSON.stringify({ query, variables }),
2577
+ body: JSON.stringify({ query: query2, variables }),
2578
2578
  signal
2579
2579
  };
2580
2580
  if (governor) {
@@ -12926,8 +12926,8 @@ var init_stringify = __esm({
12926
12926
  });
12927
12927
 
12928
12928
  // ../../node_modules/@anthropic-ai/sdk/internal/utils/query.mjs
12929
- function stringifyQuery(query) {
12930
- return stringify(query, { arrayFormat: "brackets" });
12929
+ function stringifyQuery(query2) {
12930
+ return stringify(query2, { arrayFormat: "brackets" });
12931
12931
  }
12932
12932
  var init_query = __esm({
12933
12933
  "../../node_modules/@anthropic-ai/sdk/internal/utils/query.mjs"() {
@@ -15011,9 +15011,9 @@ var init_deployment_runs = __esm({
15011
15011
  * ```
15012
15012
  */
15013
15013
  list(params = {}, options) {
15014
- const { betas, ...query } = params ?? {};
15014
+ const { betas, ...query2 } = params ?? {};
15015
15015
  return this._client.getAPIList("/v1/deployment_runs?beta=true", PageCursor, {
15016
- query,
15016
+ query: query2,
15017
15017
  ...options,
15018
15018
  headers: buildHeaders([
15019
15019
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -15125,9 +15125,9 @@ var init_deployments = __esm({
15125
15125
  * ```
15126
15126
  */
15127
15127
  list(params = {}, options) {
15128
- const { betas, ...query } = params ?? {};
15128
+ const { betas, ...query2 } = params ?? {};
15129
15129
  return this._client.getAPIList("/v1/deployments?beta=true", PageCursor, {
15130
- query,
15130
+ query: query2,
15131
15131
  ...options,
15132
15132
  headers: buildHeaders([
15133
15133
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -15287,9 +15287,9 @@ var init_dreams = __esm({
15287
15287
  * ```
15288
15288
  */
15289
15289
  list(params = {}, options) {
15290
- const { betas, ...query } = params ?? {};
15290
+ const { betas, ...query2 } = params ?? {};
15291
15291
  return this._client.getAPIList("/v1/dreams?beta=true", PageCursor, {
15292
- query,
15292
+ query: query2,
15293
15293
  ...options,
15294
15294
  headers: buildHeaders([
15295
15295
  { "anthropic-beta": [...betas ?? [], "dreaming-2026-04-21"].toString() },
@@ -15420,9 +15420,9 @@ var init_files = __esm({
15420
15420
  * ```
15421
15421
  */
15422
15422
  list(params = {}, options) {
15423
- const { betas, ...query } = params ?? {};
15423
+ const { betas, ...query2 } = params ?? {};
15424
15424
  return this._client.getAPIList("/v1/files?beta=true", Page, {
15425
- query,
15425
+ query: query2,
15426
15426
  ...options,
15427
15427
  headers: buildHeaders([
15428
15428
  { "anthropic-beta": [...betas ?? [], "files-api-2025-04-14"].toString() },
@@ -15570,9 +15570,9 @@ var init_models = __esm({
15570
15570
  * ```
15571
15571
  */
15572
15572
  list(params = {}, options) {
15573
- const { betas, ...query } = params ?? {};
15573
+ const { betas, ...query2 } = params ?? {};
15574
15574
  return this._client.getAPIList("/v1/models?beta=true", Page, {
15575
- query,
15575
+ query: query2,
15576
15576
  ...options,
15577
15577
  headers: buildHeaders([
15578
15578
  { ...betas?.toString() != null ? { "anthropic-beta": betas?.toString() } : void 0 },
@@ -15669,9 +15669,9 @@ var init_user_profiles = __esm({
15669
15669
  * ```
15670
15670
  */
15671
15671
  list(params = {}, options) {
15672
- const { betas, ...query } = params ?? {};
15672
+ const { betas, ...query2 } = params ?? {};
15673
15673
  return this._client.getAPIList("/v1/user_profiles?beta=true", PageCursor, {
15674
- query,
15674
+ query: query2,
15675
15675
  ...options,
15676
15676
  headers: buildHeaders([
15677
15677
  { "anthropic-beta": [...betas ?? [], "user-profiles-2026-03-24"].toString() },
@@ -16530,9 +16530,9 @@ var init_versions = __esm({
16530
16530
  * ```
16531
16531
  */
16532
16532
  list(agentID, params = {}, options) {
16533
- const { betas, ...query } = params ?? {};
16533
+ const { betas, ...query2 } = params ?? {};
16534
16534
  return this._client.getAPIList(path`/v1/agents/${agentID}/versions?beta=true`, PageCursor, {
16535
- query,
16535
+ query: query2,
16536
16536
  ...options,
16537
16537
  headers: buildHeaders([
16538
16538
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -16595,9 +16595,9 @@ var init_agents = __esm({
16595
16595
  * ```
16596
16596
  */
16597
16597
  retrieve(agentID, params = {}, options) {
16598
- const { betas, ...query } = params ?? {};
16598
+ const { betas, ...query2 } = params ?? {};
16599
16599
  return this._client.get(path`/v1/agents/${agentID}?beta=true`, {
16600
- query,
16600
+ query: query2,
16601
16601
  ...options,
16602
16602
  headers: buildHeaders([
16603
16603
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -16640,9 +16640,9 @@ var init_agents = __esm({
16640
16640
  * ```
16641
16641
  */
16642
16642
  list(params = {}, options) {
16643
- const { betas, ...query } = params ?? {};
16643
+ const { betas, ...query2 } = params ?? {};
16644
16644
  return this._client.getAPIList("/v1/agents?beta=true", PageCursor, {
16645
- query,
16645
+ query: query2,
16646
16646
  ...options,
16647
16647
  headers: buildHeaders([
16648
16648
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -18732,9 +18732,9 @@ var init_work = __esm({
18732
18732
  * ```
18733
18733
  */
18734
18734
  list(environmentID, params = {}, options) {
18735
- const { betas, ...query } = params ?? {};
18735
+ const { betas, ...query2 } = params ?? {};
18736
18736
  return this._client.getAPIList(path`/v1/environments/${environmentID}/work?beta=true`, PageCursor, {
18737
- query,
18737
+ query: query2,
18738
18738
  ...options,
18739
18739
  headers: buildHeaders([
18740
18740
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -18813,9 +18813,9 @@ var init_work = __esm({
18813
18813
  * ```
18814
18814
  */
18815
18815
  poll(environmentID, params = {}, options) {
18816
- const { betas, "Anthropic-Worker-ID": anthropicWorkerID, ...query } = params ?? {};
18816
+ const { betas, "Anthropic-Worker-ID": anthropicWorkerID, ...query2 } = params ?? {};
18817
18817
  return this._client.get(path`/v1/environments/${environmentID}/work/poll?beta=true`, {
18818
- query,
18818
+ query: query2,
18819
18819
  ...options,
18820
18820
  headers: buildHeaders([
18821
18821
  {
@@ -19012,9 +19012,9 @@ var init_environments = __esm({
19012
19012
  * ```
19013
19013
  */
19014
19014
  list(params = {}, options) {
19015
- const { betas, ...query } = params ?? {};
19015
+ const { betas, ...query2 } = params ?? {};
19016
19016
  return this._client.getAPIList("/v1/environments?beta=true", PageCursor, {
19017
- query,
19017
+ query: query2,
19018
19018
  ...options,
19019
19019
  headers: buildHeaders([
19020
19020
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -19117,9 +19117,9 @@ var init_memories = __esm({
19117
19117
  * ```
19118
19118
  */
19119
19119
  retrieve(memoryID, params, options) {
19120
- const { memory_store_id, betas, ...query } = params;
19120
+ const { memory_store_id, betas, ...query2 } = params;
19121
19121
  return this._client.get(path`/v1/memory_stores/${memory_store_id}/memories/${memoryID}?beta=true`, {
19122
- query,
19122
+ query: query2,
19123
19123
  ...options,
19124
19124
  headers: buildHeaders([
19125
19125
  { "anthropic-beta": [...betas ?? [], "agent-memory-2026-07-22"].toString() },
@@ -19165,9 +19165,9 @@ var init_memories = __esm({
19165
19165
  * ```
19166
19166
  */
19167
19167
  list(memoryStoreID, params = {}, options) {
19168
- const { betas, ...query } = params ?? {};
19168
+ const { betas, ...query2 } = params ?? {};
19169
19169
  return this._client.getAPIList(path`/v1/memory_stores/${memoryStoreID}/memories?beta=true`, PageCursor, {
19170
- query,
19170
+ query: query2,
19171
19171
  ...options,
19172
19172
  headers: buildHeaders([
19173
19173
  { "anthropic-beta": [...betas ?? [], "agent-memory-2026-07-22"].toString() },
@@ -19225,9 +19225,9 @@ var init_memory_versions = __esm({
19225
19225
  * ```
19226
19226
  */
19227
19227
  retrieve(memoryVersionID, params, options) {
19228
- const { memory_store_id, betas, ...query } = params;
19228
+ const { memory_store_id, betas, ...query2 } = params;
19229
19229
  return this._client.get(path`/v1/memory_stores/${memory_store_id}/memory_versions/${memoryVersionID}?beta=true`, {
19230
- query,
19230
+ query: query2,
19231
19231
  ...options,
19232
19232
  headers: buildHeaders([
19233
19233
  { "anthropic-beta": [...betas ?? [], "agent-memory-2026-07-22"].toString() },
@@ -19249,9 +19249,9 @@ var init_memory_versions = __esm({
19249
19249
  * ```
19250
19250
  */
19251
19251
  list(memoryStoreID, params = {}, options) {
19252
- const { betas, ...query } = params ?? {};
19252
+ const { betas, ...query2 } = params ?? {};
19253
19253
  return this._client.getAPIList(path`/v1/memory_stores/${memoryStoreID}/memory_versions?beta=true`, PageCursor, {
19254
- query,
19254
+ query: query2,
19255
19255
  ...options,
19256
19256
  headers: buildHeaders([
19257
19257
  { "anthropic-beta": [...betas ?? [], "agent-memory-2026-07-22"].toString() },
@@ -19377,9 +19377,9 @@ var init_memory_stores = __esm({
19377
19377
  * ```
19378
19378
  */
19379
19379
  list(params = {}, options) {
19380
- const { betas, ...query } = params ?? {};
19380
+ const { betas, ...query2 } = params ?? {};
19381
19381
  return this._client.getAPIList("/v1/memory_stores?beta=true", PageCursor, {
19382
- query,
19382
+ query: query2,
19383
19383
  ...options,
19384
19384
  headers: buildHeaders([
19385
19385
  { "anthropic-beta": [...betas ?? [], "agent-memory-2026-07-22"].toString() },
@@ -19577,9 +19577,9 @@ var init_batches = __esm({
19577
19577
  * ```
19578
19578
  */
19579
19579
  list(params = {}, options) {
19580
- const { betas, ...query } = params ?? {};
19580
+ const { betas, ...query2 } = params ?? {};
19581
19581
  return this._client.getAPIList("/v1/messages/batches?beta=true", Page, {
19582
- query,
19582
+ query: query2,
19583
19583
  ...options,
19584
19584
  headers: buildHeaders([
19585
19585
  { "anthropic-beta": [...betas ?? [], "message-batches-2024-09-24"].toString() },
@@ -21252,9 +21252,9 @@ var init_events = __esm({
21252
21252
  * ```
21253
21253
  */
21254
21254
  list(sessionID, params = {}, options) {
21255
- const { betas, ...query } = params ?? {};
21255
+ const { betas, ...query2 } = params ?? {};
21256
21256
  return this._client.getAPIList(path`/v1/sessions/${sessionID}/events?beta=true`, PageCursor, {
21257
- query,
21257
+ query: query2,
21258
21258
  ...options,
21259
21259
  headers: buildHeaders([
21260
21260
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -21309,9 +21309,9 @@ var init_events = __esm({
21309
21309
  * ```
21310
21310
  */
21311
21311
  stream(sessionID, params = {}, options) {
21312
- const { betas, ...query } = params ?? {};
21312
+ const { betas, ...query2 } = params ?? {};
21313
21313
  return this._client.get(path`/v1/sessions/${sessionID}/events/stream?beta=true`, {
21314
- query,
21314
+ query: query2,
21315
21315
  ...options,
21316
21316
  headers: buildHeaders([
21317
21317
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -21419,9 +21419,9 @@ var init_resources = __esm({
21419
21419
  * ```
21420
21420
  */
21421
21421
  list(sessionID, params = {}, options) {
21422
- const { betas, ...query } = params ?? {};
21422
+ const { betas, ...query2 } = params ?? {};
21423
21423
  return this._client.getAPIList(path`/v1/sessions/${sessionID}/resources?beta=true`, PageCursor, {
21424
- query,
21424
+ query: query2,
21425
21425
  ...options,
21426
21426
  headers: buildHeaders([
21427
21427
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -21506,9 +21506,9 @@ var init_events2 = __esm({
21506
21506
  * ```
21507
21507
  */
21508
21508
  list(threadID, params, options) {
21509
- const { session_id, betas, ...query } = params;
21509
+ const { session_id, betas, ...query2 } = params;
21510
21510
  return this._client.getAPIList(path`/v1/sessions/${session_id}/threads/${threadID}/events?beta=true`, PageCursor, {
21511
- query,
21511
+ query: query2,
21512
21512
  ...options,
21513
21513
  headers: buildHeaders([
21514
21514
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -21595,9 +21595,9 @@ var init_threads = __esm({
21595
21595
  * ```
21596
21596
  */
21597
21597
  list(sessionID, params = {}, options) {
21598
- const { betas, ...query } = params ?? {};
21598
+ const { betas, ...query2 } = params ?? {};
21599
21599
  return this._client.getAPIList(path`/v1/sessions/${sessionID}/threads?beta=true`, PageCursor, {
21600
- query,
21600
+ query: query2,
21601
21601
  ...options,
21602
21602
  headers: buildHeaders([
21603
21603
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -21732,9 +21732,9 @@ var init_sessions = __esm({
21732
21732
  * ```
21733
21733
  */
21734
21734
  list(params = {}, options) {
21735
- const { betas, ...query } = params ?? {};
21735
+ const { betas, ...query2 } = params ?? {};
21736
21736
  return this._client.getAPIList("/v1/sessions?beta=true", BidirectionalPageCursor, {
21737
- query,
21737
+ query: query2,
21738
21738
  ...options,
21739
21739
  headers: buildHeaders([
21740
21740
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -21859,9 +21859,9 @@ var init_versions2 = __esm({
21859
21859
  * ```
21860
21860
  */
21861
21861
  list(skillID, params = {}, options) {
21862
- const { betas, ...query } = params ?? {};
21862
+ const { betas, ...query2 } = params ?? {};
21863
21863
  return this._client.getAPIList(path`/v1/skills/${skillID}/versions?beta=true`, PageCursor, {
21864
- query,
21864
+ query: query2,
21865
21865
  ...options,
21866
21866
  headers: buildHeaders([
21867
21867
  { "anthropic-beta": [...betas ?? [], "skills-2025-10-02"].toString() },
@@ -21990,9 +21990,9 @@ var init_skills2 = __esm({
21990
21990
  * ```
21991
21991
  */
21992
21992
  list(params = {}, options) {
21993
- const { betas, ...query } = params ?? {};
21993
+ const { betas, ...query2 } = params ?? {};
21994
21994
  return this._client.getAPIList("/v1/skills?beta=true", PageCursor, {
21995
- query,
21995
+ query: query2,
21996
21996
  ...options,
21997
21997
  headers: buildHeaders([
21998
21998
  { "anthropic-beta": [...betas ?? [], "skills-2025-10-02"].toString() },
@@ -22110,9 +22110,9 @@ var init_certificates = __esm({
22110
22110
  * ```
22111
22111
  */
22112
22112
  list(tunnelID, params = {}, options) {
22113
- const { betas, ...query } = params ?? {};
22113
+ const { betas, ...query2 } = params ?? {};
22114
22114
  return this._client.getAPIList(path`/v1/tunnels/${tunnelID}/certificates?beta=true`, PageCursor, {
22115
- query,
22115
+ query: query2,
22116
22116
  ...options,
22117
22117
  headers: buildHeaders([
22118
22118
  { "anthropic-beta": [...betas ?? [], "mcp-tunnels-2026-06-22"].toString() },
@@ -22239,9 +22239,9 @@ var init_tunnels = __esm({
22239
22239
  * ```
22240
22240
  */
22241
22241
  list(params = {}, options) {
22242
- const { betas, ...query } = params ?? {};
22242
+ const { betas, ...query2 } = params ?? {};
22243
22243
  return this._client.getAPIList("/v1/tunnels?beta=true", PageCursor, {
22244
- query,
22244
+ query: query2,
22245
22245
  ...options,
22246
22246
  headers: buildHeaders([
22247
22247
  { "anthropic-beta": [...betas ?? [], "mcp-tunnels-2026-06-22"].toString() },
@@ -22435,9 +22435,9 @@ var init_credentials2 = __esm({
22435
22435
  * ```
22436
22436
  */
22437
22437
  list(vaultID, params = {}, options) {
22438
- const { betas, ...query } = params ?? {};
22438
+ const { betas, ...query2 } = params ?? {};
22439
22439
  return this._client.getAPIList(path`/v1/vaults/${vaultID}/credentials?beta=true`, PageCursor, {
22440
- query,
22440
+ query: query2,
22441
22441
  ...options,
22442
22442
  headers: buildHeaders([
22443
22443
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -22608,9 +22608,9 @@ var init_vaults = __esm({
22608
22608
  * ```
22609
22609
  */
22610
22610
  list(params = {}, options) {
22611
- const { betas, ...query } = params ?? {};
22611
+ const { betas, ...query2 } = params ?? {};
22612
22612
  return this._client.getAPIList("/v1/vaults?beta=true", PageCursor, {
22613
- query,
22613
+ query: query2,
22614
22614
  ...options,
22615
22615
  headers: buildHeaders([
22616
22616
  { "anthropic-beta": [...betas ?? [], "managed-agents-2026-04-01"].toString() },
@@ -23496,8 +23496,8 @@ var init_batches2 = __esm({
23496
23496
  * }
23497
23497
  * ```
23498
23498
  */
23499
- list(query = {}, options) {
23500
- return this._client.getAPIList("/v1/messages/batches", Page, { query, ...options });
23499
+ list(query2 = {}, options) {
23500
+ return this._client.getAPIList("/v1/messages/batches", Page, { query: query2, ...options });
23501
23501
  }
23502
23502
  /**
23503
23503
  * Delete a Message Batch.
@@ -23753,9 +23753,9 @@ var init_models2 = __esm({
23753
23753
  * use in the API. More recently released models are listed first.
23754
23754
  */
23755
23755
  list(params = {}, options) {
23756
- const { betas, ...query } = params ?? {};
23756
+ const { betas, ...query2 } = params ?? {};
23757
23757
  return this._client.getAPIList("/v1/models", Page, {
23758
- query,
23758
+ query: query2,
23759
23759
  ...options,
23760
23760
  headers: buildHeaders([
23761
23761
  { ...betas?.toString() != null ? { "anthropic-beta": betas?.toString() } : void 0 },
@@ -24104,8 +24104,8 @@ var init_client = __esm({
24104
24104
  }
24105
24105
  return buildHeaders([{ Authorization: `Bearer ${this.authToken}` }]);
24106
24106
  }
24107
- stringifyQuery(query) {
24108
- return stringifyQuery(query);
24107
+ stringifyQuery(query2) {
24108
+ return stringifyQuery(query2);
24109
24109
  }
24110
24110
  getUserAgent() {
24111
24111
  return `${this.constructor.name}/JS ${VERSION}`;
@@ -24116,16 +24116,16 @@ var init_client = __esm({
24116
24116
  makeStatusError(status, error2, message, headers) {
24117
24117
  return APIError.generate(status, error2, message, headers);
24118
24118
  }
24119
- buildURL(path5, query, defaultBaseURL) {
24119
+ buildURL(path5, query2, defaultBaseURL) {
24120
24120
  const baseURL = !__classPrivateFieldGet(this, _BaseAnthropic_instances, "m", _BaseAnthropic_baseURLOverridden).call(this) && defaultBaseURL || this.baseURL;
24121
24121
  const url = isAbsoluteURL(path5) ? new URL(path5) : new URL(baseURL + (baseURL.endsWith("/") && path5.startsWith("/") ? path5.slice(1) : path5));
24122
24122
  const defaultQuery = this.defaultQuery();
24123
24123
  const pathQuery = Object.fromEntries(url.searchParams);
24124
24124
  if (!isEmptyObj(defaultQuery) || !isEmptyObj(pathQuery)) {
24125
- query = { ...pathQuery, ...defaultQuery, ...query };
24125
+ query2 = { ...pathQuery, ...defaultQuery, ...query2 };
24126
24126
  }
24127
- if (typeof query === "object" && query && !Array.isArray(query)) {
24128
- url.search = this.stringifyQuery(query);
24127
+ if (typeof query2 === "object" && query2 && !Array.isArray(query2)) {
24128
+ url.search = this.stringifyQuery(query2);
24129
24129
  }
24130
24130
  return url.toString();
24131
24131
  }
@@ -24438,14 +24438,14 @@ var init_client = __esm({
24438
24438
  }
24439
24439
  async buildRequest(inputOptions, { retryCount = 0 } = {}) {
24440
24440
  const options = { ...inputOptions };
24441
- const { method, path: path5, query, defaultBaseURL } = options;
24441
+ const { method, path: path5, query: query2, defaultBaseURL } = options;
24442
24442
  if (this._authState.resolution) {
24443
24443
  await this._authState.resolution;
24444
24444
  }
24445
24445
  if (!this._baseURLIsExplicit && this._authState.baseURL && this.baseURL !== this._authState.baseURL) {
24446
24446
  this.baseURL = this._authState.baseURL;
24447
24447
  }
24448
- const url = this.buildURL(path5, query, defaultBaseURL);
24448
+ const url = this.buildURL(path5, query2, defaultBaseURL);
24449
24449
  if ("timeout" in options)
24450
24450
  validatePositiveInteger("timeout", options.timeout);
24451
24451
  options.timeout = options.timeout ?? this.timeout;
@@ -24563,8 +24563,8 @@ function stripFallbackBlocks(body) {
24563
24563
  function betaRefusalFallbackMiddleware(fallbacks, options = {}) {
24564
24564
  let warnedMissingState = false;
24565
24565
  return async (request, next, ctx) => {
24566
- const [path5, query] = (ctx.options?.path ?? "").split("?");
24567
- 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) {
24566
+ const [path5, query2] = (ctx.options?.path ?? "").split("?");
24567
+ 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) {
24568
24568
  return next(request);
24569
24569
  }
24570
24570
  if (ctx.options.body.fallbacks != null) {
@@ -26568,7 +26568,7 @@ ${facts.stderr}`))
26568
26568
  return null;
26569
26569
  }
26570
26570
  function isCommandUnavailable(facts, countsRead) {
26571
- if (facts.exitCode === 127 || facts.exitCode === 126)
26571
+ if (facts.exitCode === 127 || facts.exitCode === 126 || facts.exitCode === 125)
26572
26572
  return true;
26573
26573
  if (countsRead)
26574
26574
  return false;
@@ -26576,6 +26576,22 @@ function isCommandUnavailable(facts, countsRead) {
26576
26576
  return false;
26577
26577
  return facts.stdout.trim().length === 0 && EXEC_FAILURE.test(facts.stderr);
26578
26578
  }
26579
+ function isOfflineBuildGap(facts, counts) {
26580
+ if (facts.runtime !== "jvm")
26581
+ return null;
26582
+ if (counts !== null && counts.tests_failed > 0)
26583
+ return null;
26584
+ if (facts.exitCode === 0 || facts.exitCode === null)
26585
+ return null;
26586
+ const out = `${facts.stdout}
26587
+ ${facts.stderr}`;
26588
+ for (const pattern of OFFLINE_BUILD_GAP) {
26589
+ const hit = pattern.exec(out);
26590
+ if (hit)
26591
+ return hit[0];
26592
+ }
26593
+ return null;
26594
+ }
26579
26595
  function classifyVerification(facts) {
26580
26596
  if (facts.timedOut) {
26581
26597
  return {
@@ -26600,6 +26616,14 @@ function classifyVerification(facts) {
26600
26616
  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.`
26601
26617
  };
26602
26618
  }
26619
+ const gap = isOfflineBuildGap(facts, counts);
26620
+ if (gap !== null) {
26621
+ return {
26622
+ outcome: "test-command-unavailable",
26623
+ counts,
26624
+ 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.`
26625
+ };
26626
+ }
26603
26627
  if (counts !== null) {
26604
26628
  if (counts.tests_failed > 0) {
26605
26629
  return {
@@ -26654,10 +26678,19 @@ function isGreen(outcome) {
26654
26678
  function isOurFault(outcome) {
26655
26679
  return outcome === "test-command-unavailable" || outcome === "counts-unparsed";
26656
26680
  }
26657
- var int, withSuiteFailures, READERS, SUPPORTED_RUNNERS, COVERAGE_TABLE, EXEC_FAILURE, SUITE_REPORTED_FAILURE;
26681
+ var VERIFICATION_OUTCOMES, int, withSuiteFailures, READERS, SUPPORTED_RUNNERS, COVERAGE_TABLE, EXEC_FAILURE, SUITE_REPORTED_FAILURE, OFFLINE_BUILD_GAP;
26658
26682
  var init_classify2 = __esm({
26659
26683
  "../../packages/envrun/dist/classify.js"() {
26660
26684
  "use strict";
26685
+ VERIFICATION_OUTCOMES = [
26686
+ "completed",
26687
+ "tests-failed",
26688
+ "no-tests-observed",
26689
+ "counts-unparsed",
26690
+ "test-command-unavailable",
26691
+ "environment-exhausted",
26692
+ "budget-exceeded"
26693
+ ];
26661
26694
  int = (m, i = 1) => m ? Number(m[i]) : 0;
26662
26695
  withSuiteFailures = (counts, suiteLine) => {
26663
26696
  if (counts.tests_failed > 0 || !suiteLine)
@@ -26757,6 +26790,51 @@ var init_classify2 = __esm({
26757
26790
  return { tests_passed: int(passed), tests_failed: int(failed) + int(errors) };
26758
26791
  }
26759
26792
  },
26793
+ {
26794
+ // Maven surefire's per-module summary (TERM-1122), measured against surefire
26795
+ // 3.2.5 through `th run`:
26796
+ //
26797
+ // [INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
26798
+ //
26799
+ // The per-CLASS lines carry the same counts followed by `, Time elapsed: …`, so
26800
+ // the end anchor after `Skipped` is what keeps them out; counting both would
26801
+ // double every test. One summary prints per module, so they are SUMMED. An
26802
+ // error is a test that could not run to an assertion, counted as failed so a
26803
+ // green verdict is impossible while one is outstanding, as pytest's are.
26804
+ runner: "maven surefire",
26805
+ read: (out) => {
26806
+ const lines = [
26807
+ ...out.matchAll(/^(?:\[(?:INFO|WARNING|ERROR)\] )?Tests run: (\d+), Failures: (\d+), Errors: (\d+), Skipped: (\d+)(?:, Flakes: \d+)?\s*$/gm)
26808
+ ];
26809
+ if (lines.length === 0)
26810
+ return null;
26811
+ let passed = 0;
26812
+ let failed = 0;
26813
+ for (const m of lines) {
26814
+ const [run3, failures, errors, skipped] = [m[1], m[2], m[3], m[4]].map(Number);
26815
+ failed += failures + errors;
26816
+ passed += Math.max(0, run3 - failures - errors - skipped);
26817
+ }
26818
+ return { tests_passed: passed, tests_failed: failed };
26819
+ }
26820
+ },
26821
+ {
26822
+ // Gradle prints no test counts when every test passes, so envrun installs an
26823
+ // init script that prints one line per Test task (`gradleTestSummary.ts`,
26824
+ // TERM-1122). The marker is ours; its format is fixed there.
26825
+ runner: "gradle",
26826
+ read: (out) => {
26827
+ const lines = [
26828
+ ...out.matchAll(/^terminalhire-gradle-tests: task=\S+ total=(\d+) passed=(\d+) failed=(\d+) skipped=(\d+)\s*$/gm)
26829
+ ];
26830
+ if (lines.length === 0)
26831
+ return null;
26832
+ return {
26833
+ tests_passed: lines.reduce((sum, m) => sum + Number(m[2]), 0),
26834
+ tests_failed: lines.reduce((sum, m) => sum + Number(m[3]), 0)
26835
+ };
26836
+ }
26837
+ },
26760
26838
  {
26761
26839
  // mocha: ` 440 passing (1s)` and ` 2 failing`
26762
26840
  runner: "mocha",
@@ -26791,6 +26869,79 @@ var init_classify2 = __esm({
26791
26869
  const p = int(passed);
26792
26870
  return { tests_passed: p, tests_failed: Math.max(0, t - p) };
26793
26871
  }
26872
+ },
26873
+ {
26874
+ /**
26875
+ * BARE TAP — assertion lines with no plan and no summary comment (TERM-1138).
26876
+ *
26877
+ * LAST ON PURPOSE. It is the loosest reader here, so anything that a more specific
26878
+ * one can read must reach that one first: `node --test` and node-tap both emit `ok`
26879
+ * lines AND a closing summary, and their readers are ordered above for that reason.
26880
+ * Moving this up would have it answer for both.
26881
+ *
26882
+ * A hand-rolled harness prints neither summary — it emits its assertions and stops.
26883
+ * That is what morebetterltd/wheelhouse does: thirty `ok N - …` lines, exit 0, and
26884
+ * before this every one of those runs reported `counts-unparsed`, which the claim
26885
+ * page renders as "RESULT UNREADABLE — THE SUITE EXITED 0" over a suite that passed.
26886
+ *
26887
+ * ON THE MISSING PLAN LINE. TAP requires `1..N` so a reader can tell a finished
26888
+ * stream from a truncated one, and there is none here, so this cannot prove the
26889
+ * suite reached its end. That is a real limit and it is NOT a reason to refuse,
26890
+ * because it holds this format to a standard no reader in this file meets — the
26891
+ * jest reader greps a line out of stdout that a repository could `echo` without
26892
+ * running anything. These are format adapters, not a trust boundary; the boundary
26893
+ * is that the command is the repository's own or is refused a signature.
26894
+ *
26895
+ * CONTIGUOUS FROM 1, which buys self-consistency rather than security:
26896
+ *
26897
+ * - starting at 1 rejects a TRUNCATION. `testOutputTail` keeps the last lines, so
26898
+ * a stream beginning `ok 47` is the middle of a longer run and counting it would
26899
+ * report three tests for a suite that ran fifty.
26900
+ * - no gaps rejects prose that happens to carry the word, and a stream interleaved
26901
+ * with another's.
26902
+ * - anchored with no leading space rejects TAP SUBTESTS, which indent. Counting
26903
+ * those would double them against their parent.
26904
+ */
26905
+ runner: "bare TAP",
26906
+ read: (out) => {
26907
+ let n = 0;
26908
+ let failed = 0;
26909
+ let passed = 0;
26910
+ let plan = null;
26911
+ for (const line of out.split("\n")) {
26912
+ if (/^Bail out!/.test(line))
26913
+ return null;
26914
+ const p = /^(\d+)\.\.(\d+)\s*$/.exec(line);
26915
+ if (p) {
26916
+ const declared = Number(p[2]) - Number(p[1]) + 1;
26917
+ if (plan !== null && plan !== declared)
26918
+ return null;
26919
+ plan = declared;
26920
+ continue;
26921
+ }
26922
+ const m = /^(not )?ok (\d+)(?:\s|$)/.exec(line);
26923
+ if (!m)
26924
+ continue;
26925
+ if (Number(m[2]) !== n + 1)
26926
+ return null;
26927
+ n += 1;
26928
+ const directive = /#\s*(skip|todo)\b/i.exec(line);
26929
+ const kind = directive?.[1]?.toLowerCase();
26930
+ if (kind === "skip")
26931
+ continue;
26932
+ if (m[1] !== void 0) {
26933
+ if (kind !== "todo")
26934
+ failed += 1;
26935
+ continue;
26936
+ }
26937
+ passed += 1;
26938
+ }
26939
+ if (n === 0)
26940
+ return null;
26941
+ if (plan !== null && plan !== n)
26942
+ return null;
26943
+ return { tests_passed: passed, tests_failed: failed };
26944
+ }
26794
26945
  }
26795
26946
  ];
26796
26947
  SUPPORTED_RUNNERS = READERS.map((r) => r.runner);
@@ -26812,6 +26963,21 @@ var init_classify2 = __esm({
26812
26963
  "\\d+\\s+examples?,\\s+(?!0\\b)\\d+\\s+failures?"
26813
26964
  // rspec's summary line
26814
26965
  ].join("|"), "m");
26966
+ OFFLINE_BUILD_GAP = [
26967
+ // Maven, `-o`: `Cannot access central (…) in offline mode and the artifact … has
26968
+ // not been downloaded from it before.`
26969
+ /in offline mode and the artifact \S+ has not been downloaded from it before/,
26970
+ // Maven without `-o`, as a CI-derived `mvn test` runs: it tries the network.
26971
+ /Could not transfer artifact \S+ from\/to /,
26972
+ /Plugin \S+ or one of its dependencies could not be resolved/,
26973
+ // Gradle, `--offline`.
26974
+ /No cached version (?:listing )?(?:of|for) \S+ available for offline mode/,
26975
+ // Gradle without `--offline`, and the wrapper fetching its own distribution.
26976
+ /Could not GET 'https?:\/\//,
26977
+ /^Downloading https:\/\/services\.gradle\.org\/distributions\//m,
26978
+ /No matching toolchains found for requested specification/,
26979
+ /Cannot find a Java installation on your machine matching/
26980
+ ];
26815
26981
  }
26816
26982
  });
26817
26983
 
@@ -26877,6 +27043,12 @@ function scrubEnv(source, opts) {
26877
27043
  env["GOCACHE"] = join20(jailHome, ".cache", "go-build");
26878
27044
  env["GOFLAGS"] = "-modcacherw";
26879
27045
  env["CARGO_HOME"] = join20(jailHome, ".cargo");
27046
+ env["MAVEN_OPTS"] = `-Dmaven.repo.local=${join20(jailHome, ".m2", "repository")}`;
27047
+ env["GRADLE_USER_HOME"] = join20(jailHome, ".gradle");
27048
+ const bundle = join20(jailHome, ".bundle");
27049
+ env["GEM_HOME"] = bundle;
27050
+ env["BUNDLE_PATH"] = bundle;
27051
+ env["BUNDLE_APP_CONFIG"] = bundle;
26880
27052
  const proxy = opts.proxyUrl ?? DEAD_PROXY;
26881
27053
  env["HTTP_PROXY"] = proxy;
26882
27054
  env["HTTPS_PROXY"] = proxy;
@@ -27177,6 +27349,31 @@ var init_egressProxy = __esm({
27177
27349
  "static.crates.io",
27178
27350
  "index.crates.io",
27179
27351
  "crates.io",
27352
+ // TERM-1139. `ruby` has had an image since the mapping existed and `bundle install`
27353
+ // as its derived command, and this host was missing — so every ruby repo could start
27354
+ // and could never install. Install is the ONLY step with a network grant at all, so a
27355
+ // denial here is terminal, not a slow path.
27356
+ //
27357
+ // One entry, not two: `hostAllowed` is dot-anchored SUFFIX matching, so this covers
27358
+ // `index.rubygems.org` as well. Listing that separately would advertise the grant as
27359
+ // narrower than it is, which the `github.com` note below rejects for the same reason.
27360
+ "rubygems.org",
27361
+ // TERM-1139, added with the `dotnet` image mapping. `dotnet restore` fetches from
27362
+ // NuGet; the coupling test refuses a mapped runtime whose registry is unreachable, and
27363
+ // it caught this one the moment the image landed.
27364
+ "api.nuget.org",
27365
+ // TERM-1122, added with the `jvm` image mapping, each from a MEASURED denial
27366
+ // through `th run` (the proxy's 403 in the build's own output), not a guess:
27367
+ // - Maven Central, where both `mvn` and Gradle's `mavenCentral()` resolve.
27368
+ // - `services.gradle.org`, where a Gradle wrapper fetches its distribution.
27369
+ // - `release-assets.githubusercontent.com`, where that fetch LANDS. Measured
27370
+ // chain: services.gradle.org 307 -> github.com 302 -> this host 200. The
27371
+ // `github.com` note below keeps `githubusercontent.com` denied until a real
27372
+ // install needs it; this is that install. Only this one host: raw blobs and
27373
+ // `objects.githubusercontent.com` stay denied.
27374
+ "repo.maven.apache.org",
27375
+ "services.gradle.org",
27376
+ "release-assets.githubusercontent.com",
27180
27377
  // Git dependencies. Approved by Eric 2026-07-22 after a live run measured the
27181
27378
  // chokepoint working under load (20 events, 16 allowed / 4 denied by host).
27182
27379
  //
@@ -27468,6 +27665,9 @@ function containerArgs(spec, env, opts) {
27468
27665
  args.push(`--env=${k}=${url}`);
27469
27666
  }
27470
27667
  args.push("--env=NO_PROXY=", "--env=no_proxy=");
27668
+ const host = opts.net.proxyHost;
27669
+ const port = String(opts.net.proxyPort);
27670
+ args.push(`--env=JAVA_TOOL_OPTIONS=-Dhttp.proxyHost=${host} -Dhttp.proxyPort=${port} -Dhttps.proxyHost=${host} -Dhttps.proxyPort=${port} -Daether.connector.http.useSystemProperties=true`);
27471
27671
  }
27472
27672
  args.push("--");
27473
27673
  args.push(validateImage(opts.image ?? DEFAULT_CONTAINER_IMAGE));
@@ -27800,7 +28000,10 @@ var init_container = __esm({
27800
28000
  "http_proxy",
27801
28001
  "https_proxy",
27802
28002
  "NO_PROXY",
27803
- "no_proxy"
28003
+ "no_proxy",
28004
+ // Carries the JVM's copy of the proxy (below), so an inherited value is dropped
28005
+ // for the same reason as the rest.
28006
+ "JAVA_TOOL_OPTIONS"
27804
28007
  ]);
27805
28008
  WINDOWS_DRIVE_ROOT = /^[A-Za-z]:[\\/]/;
27806
28009
  IMAGE_HOST = "(?:[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)+(?::[0-9]+)?|localhost(?::[0-9]+)?)";
@@ -27850,11 +28053,17 @@ var init_dist = __esm({
27850
28053
  function censusTotal(c) {
27851
28054
  return c.containers.length + c.volumes.length + c.networks.length;
27852
28055
  }
27853
- function ids(docker3, args) {
28056
+ function query(docker3, args) {
27854
28057
  const res = docker3.sync([...args], { timeoutMs: 15e3 });
27855
- if (res.error || res.status !== 0)
27856
- return [];
27857
- return res.stdout.split("\n").map((s) => s.trim()).filter((s) => s.length > 0);
28058
+ if (res.error || res.status !== 0) {
28059
+ const why = res.error?.message ?? (res.stderr.trim() || `exit ${String(res.status)}`);
28060
+ return { ids: [], failure: `docker ${args.slice(0, 2).join(" ")}: ${why}` };
28061
+ }
28062
+ const ids2 = res.stdout.split("\n").map((s) => s.trim()).filter((s) => s.length > 0);
28063
+ return { ids: ids2, failure: null };
28064
+ }
28065
+ function ids(docker3, args) {
28066
+ return query(docker3, args).ids;
27858
28067
  }
27859
28068
  function census(docker3, label) {
27860
28069
  const filter = `label=${label}`;
@@ -27864,25 +28073,67 @@ function census(docker3, label) {
27864
28073
  networks: ids(docker3, ["network", "ls", "-q", "--filter", filter])
27865
28074
  };
27866
28075
  }
28076
+ function censusReport(docker3, label) {
28077
+ const filter = `label=${label}`;
28078
+ const failures = [];
28079
+ const ask2 = (args) => {
28080
+ const q = query(docker3, args);
28081
+ if (q.failure !== null)
28082
+ failures.push(q.failure);
28083
+ return q.ids;
28084
+ };
28085
+ const taken = {
28086
+ containers: ask2(["ps", "-aq", "--filter", filter]),
28087
+ volumes: ask2(["volume", "ls", "-q", "--filter", filter]),
28088
+ networks: ask2(["network", "ls", "-q", "--filter", filter])
28089
+ };
28090
+ return failures.length === 0 ? { observed: true, census: taken, unobservedReason: null } : { observed: false, census: taken, unobservedReason: failures.join("; ") };
28091
+ }
27867
28092
  function localCensus(label) {
27868
28093
  return census(localDockerClient(), label);
27869
28094
  }
27870
- function judgeLeaks(peak, after) {
28095
+ function judgeLeaks(peak, after, observation) {
27871
28096
  const labelObserved = peak.containers.length > 0;
28097
+ if (!observation.observed) {
28098
+ return {
28099
+ labelObserved,
28100
+ reaped: false,
28101
+ observed: false,
28102
+ clean: false,
28103
+ state: "unobserved",
28104
+ peak,
28105
+ after,
28106
+ 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.`
28107
+ };
28108
+ }
27872
28109
  const reaped = censusTotal(after) === 0;
27873
28110
  let note;
28111
+ let state;
27874
28112
  if (!labelObserved && reaped) {
28113
+ state = "inconclusive";
27875
28114
  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.";
27876
28115
  } else if (!labelObserved) {
28116
+ state = "leak";
27877
28117
  note = "no labelled container was observed alive AND objects remain \u2014 the label wiring is wrong.";
27878
28118
  } else if (!reaped) {
28119
+ state = "leak";
27879
28120
  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)}).`;
27880
28121
  } else {
28122
+ state = "clean";
27881
28123
  note = `clean: peak ${String(peak.containers.length)} labelled container(s) observed alive, 0 labelled objects remain after teardown.`;
27882
28124
  }
27883
- return { labelObserved, reaped, clean: labelObserved && reaped, peak, after, note };
28125
+ return {
28126
+ labelObserved,
28127
+ reaped,
28128
+ observed: true,
28129
+ clean: labelObserved && reaped,
28130
+ state,
28131
+ peak,
28132
+ after,
28133
+ note
28134
+ };
27884
28135
  }
27885
- var RUN_LABEL_KEY, LabelWatch;
28136
+ var RUN_LABEL_KEY, LabelWatch, LEAK_STATES;
27886
28137
  var init_labels = __esm({
27887
28138
  "../../packages/envrun/dist/labels.js"() {
27888
28139
  "use strict";
@@ -27937,6 +28188,7 @@ var init_labels = __esm({
27937
28188
  return this.#samples;
27938
28189
  }
27939
28190
  };
28191
+ LEAK_STATES = ["clean", "leak", "inconclusive", "unobserved"];
27940
28192
  }
27941
28193
  });
27942
28194
 
@@ -28421,7 +28673,7 @@ function acquireLocalLease(runId) {
28421
28673
  observed: false,
28422
28674
  census: { containers: [], volumes: [], networks: [] },
28423
28675
  unobservedReason: RELEASED_LEASE_CENSUS_REASON
28424
- } : { observed: true, census: census(docker3, label), unobservedReason: null }),
28676
+ } : censusReport(docker3, label)),
28425
28677
  publishPreview: (req) => startPreview({ ...req, docker: docker3 }),
28426
28678
  release: () => {
28427
28679
  if (released) {
@@ -28541,6 +28793,17 @@ caused by: ${frame}`;
28541
28793
  }
28542
28794
  return frames === 0 ? null : out;
28543
28795
  }
28796
+ function imageVariantFor(spec) {
28797
+ if (spec.runtime !== "jvm")
28798
+ return void 0;
28799
+ const callsGradle = /(?:^|[\s;&|(])gradle(?=\s|$)/;
28800
+ return [spec.installCommand, spec.testCommand].some((c) => c != null && callsGradle.test(c)) ? "gradle" : void 0;
28801
+ }
28802
+ function shapeFor(runtime, variant) {
28803
+ if (runtime === "jvm" && variant === "gradle")
28804
+ return JVM_GRADLE_IMAGE;
28805
+ return RUNTIME_IMAGES[runtime];
28806
+ }
28544
28807
  function atLeast(a, b) {
28545
28808
  const left = a.split(".").map(Number);
28546
28809
  const right = b.split(".").map(Number);
@@ -28553,19 +28816,19 @@ function atLeast(a, b) {
28553
28816
  }
28554
28817
  return true;
28555
28818
  }
28556
- function imageForRuntime(runtime, override, version2) {
28819
+ function imageForRuntime(runtime, override, version2, variant) {
28557
28820
  if (override)
28558
28821
  return override;
28559
- const shape = RUNTIME_IMAGES[runtime];
28822
+ const shape = shapeFor(runtime, variant);
28560
28823
  if (!shape) {
28561
- throw new RunRefusalError(`no container image is mapped for runtime ${JSON.stringify(runtime)}. Refusing to run it in the Node image: a missing interpreter surfaces as "command not found", which the classifier reads as tests-failed \u2014 a false red blamed on the repo.`);
28824
+ 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.`);
28562
28825
  }
28563
28826
  if (version2 === void 0 || version2 === null)
28564
28827
  return unversionedImage(shape);
28565
28828
  if (!TAG_VERSION.test(version2)) {
28566
28829
  throw new RunRefusalError(`runtime version ${JSON.stringify(version2)} 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.`);
28567
28830
  }
28568
- return `${shape.repository}:${version2}${shape.suffix}`;
28831
+ return `${shape.repository}:${shape.prefix ?? ""}${version2}${shape.suffix}`;
28569
28832
  }
28570
28833
  function setManifestProbe(probe) {
28571
28834
  const previous = manifestProbe;
@@ -28578,10 +28841,10 @@ function imageDefinitelyAbsent(image) {
28578
28841
  return false;
28579
28842
  return /manifest unknown|no such manifest/i.test(res.output);
28580
28843
  }
28581
- function resolvePublishedImage(image, runtime, version2) {
28844
+ function resolvePublishedImage(image, runtime, version2, variant) {
28582
28845
  if (!imageDefinitelyAbsent(image))
28583
28846
  return image;
28584
- const shape = RUNTIME_IMAGES[runtime];
28847
+ const shape = shapeFor(runtime, variant);
28585
28848
  if (shape && shape.declaredIsFloor && atLeast(shape.defaultVersion, version2)) {
28586
28849
  return unversionedImage(shape);
28587
28850
  }
@@ -28589,18 +28852,19 @@ function resolvePublishedImage(image, runtime, version2) {
28589
28852
  }
28590
28853
  function resolveImageForSpec(spec, override) {
28591
28854
  const declared = spec.runtimeVersion;
28592
- const image = imageForRuntime(spec.runtime, override, declared);
28855
+ const variant = imageVariantFor(spec);
28856
+ const image = imageForRuntime(spec.runtime, override, declared, variant);
28593
28857
  const constructed = (() => {
28594
28858
  if (declared === null)
28595
28859
  return null;
28596
28860
  try {
28597
- return imageForRuntime(spec.runtime, void 0, declared);
28861
+ return imageForRuntime(spec.runtime, void 0, declared, variant);
28598
28862
  } catch {
28599
28863
  return null;
28600
28864
  }
28601
28865
  })();
28602
28866
  if (constructed !== null && image === constructed && declared !== null) {
28603
- return resolvePublishedImage(image, spec.runtime, declared);
28867
+ return resolvePublishedImage(image, spec.runtime, declared, variant);
28604
28868
  }
28605
28869
  return image;
28606
28870
  }
@@ -28627,12 +28891,22 @@ function assertVenueOwnerDeclared(lease) {
28627
28891
  return;
28628
28892
  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.");
28629
28893
  }
28894
+ function refuseUnbuildableSpec(spec) {
28895
+ if (spec.runtime !== "jvm" || spec.installCommand !== null || spec.testCommand !== null)
28896
+ return;
28897
+ const why = spec.unresolved.find((r) => r.kind === "no-test-command")?.detail;
28898
+ if (why === void 0) {
28899
+ throw new EnvRunError("internal: a jvm spec with no test command carries no no-test-command reason");
28900
+ }
28901
+ throw new RunRefusalError(`refusing to run this repository: ${why}.`);
28902
+ }
28630
28903
  async function runEnvironmentSpec(req) {
28631
28904
  const startedAt = Date.now();
28632
28905
  const containment = req.lease.containment;
28633
28906
  if (containment.kind !== "container") {
28634
28907
  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.`);
28635
28908
  }
28909
+ refuseUnbuildableSpec(req.spec);
28636
28910
  assertVenueOwnerDeclared(req.lease);
28637
28911
  const image = resolveImageForSpec(req.spec, req.image);
28638
28912
  const { jail, tmp } = req;
@@ -28675,9 +28949,10 @@ async function runEnvironmentSpec(req) {
28675
28949
  installOk: false
28676
28950
  };
28677
28951
  } else if (req.spec.testCommand === null) {
28952
+ const why = req.spec.unresolved.find((r) => r.kind === "no-test-command")?.detail;
28678
28953
  result = {
28679
28954
  outcome: "no-tests-observed",
28680
- 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.",
28955
+ 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}.`),
28681
28956
  installOk: true
28682
28957
  };
28683
28958
  } else {
@@ -28700,7 +28975,7 @@ async function runEnvironmentSpec(req) {
28700
28975
  labels,
28701
28976
  timeoutMs: req.testTimeoutMs ?? 9e5
28702
28977
  });
28703
- const verdict = classifyVerification(toExecution(test));
28978
+ const verdict = classifyVerification({ ...toExecution(test), runtime: req.spec.runtime });
28704
28979
  result = { outcome: verdict.outcome, note: verdict.reason, installOk: true };
28705
28980
  }
28706
28981
  } finally {
@@ -28714,6 +28989,10 @@ async function runEnvironmentSpec(req) {
28714
28989
  volumes: [],
28715
28990
  networks: []
28716
28991
  };
28992
+ const observation = afterReport ?? {
28993
+ observed: false,
28994
+ unobservedReason: "the run carried no label, so there was nothing to count by"
28995
+ };
28717
28996
  return {
28718
28997
  outcome: result.outcome,
28719
28998
  tier: "container",
@@ -28722,7 +29001,7 @@ async function runEnvironmentSpec(req) {
28722
29001
  test,
28723
29002
  installOk: result.installOk,
28724
29003
  counts: test ? readCounts(test.stdout, test.stderr) : null,
28725
- leaks: judgeLeaks(peak, after),
29004
+ leaks: judgeLeaks(peak, after, observation),
28726
29005
  note: result.note,
28727
29006
  wallMs: Date.now() - startedAt
28728
29007
  };
@@ -28772,7 +29051,7 @@ async function runStep(containment, r) {
28772
29051
  wallMs: Date.now() - startedAt
28773
29052
  };
28774
29053
  }
28775
- var EnvRunError, RunRefusalError, MAX_CAUSE_FRAMES, CHAIN_UNREADABLE, CHAIN_TOO_DEEP, RUNTIME_IMAGES, unversionedImage, TAG_VERSION, dockerManifestProbe, manifestProbe, MISSING_IMAGE_SHAPE;
29054
+ var EnvRunError, RunRefusalError, MAX_CAUSE_FRAMES, CHAIN_UNREADABLE, CHAIN_TOO_DEEP, RUNTIME_IMAGES, JVM_GRADLE_IMAGE, unversionedImage, TAG_VERSION, dockerManifestProbe, manifestProbe, MISSING_IMAGE_SHAPE;
28776
29055
  var init_execute = __esm({
28777
29056
  "../../packages/envrun/dist/execute.js"() {
28778
29057
  "use strict";
@@ -28809,9 +29088,66 @@ var init_execute = __esm({
28809
29088
  },
28810
29089
  go: { repository: "golang", suffix: "-bookworm", defaultVersion: "1.23", declaredIsFloor: true },
28811
29090
  ruby: { repository: "ruby", suffix: "-bookworm", defaultVersion: "3.3", declaredIsFloor: false },
28812
- rust: { repository: "rust", suffix: "-bookworm", defaultVersion: "1", declaredIsFloor: true }
28813
- };
28814
- unversionedImage = (shape) => `${shape.repository}:${shape.defaultVersion}${shape.suffix}`;
29091
+ rust: { repository: "rust", suffix: "-bookworm", defaultVersion: "1", declaredIsFloor: true },
29092
+ /**
29093
+ * TERM-1139. `dotnet` was unmapped alongside `jvm`, and the recorded reason was that
29094
+ * neither had "a single obvious base image (gradle vs maven, sdk vs runtime)". That
29095
+ * reason holds for jvm and it does NOT hold here, which is why only this half moved.
29096
+ *
29097
+ * "sdk vs runtime" answers itself: the derived commands are `dotnet restore` and
29098
+ * `dotnet test`, and neither exists on the runtime image. There is no second build
29099
+ * tool competing for the slot the way maven and gradle compete for jvm's — and since
29100
+ * no official image carries both of those, jvm genuinely cannot be served by one key.
29101
+ *
29102
+ * MEASURED, not chosen by tag: `mcr.microsoft.com/dotnet/sdk:8.0` carries `git` and
29103
+ * `dotnet` (881MB). `git` is the property the whole `image-tooling-live` test exists
29104
+ * for, and `eclipse-temurin:21-jdk` was rejected here for lacking it.
29105
+ *
29106
+ * The tag shape fits without touching the builder: the SDK publishes a tag per
29107
+ * version, so `repository:VERSION` is a real image at every version envspec can
29108
+ * derive, with no suffix. That is NOT true of the maven images, where the leading
29109
+ * tag component is maven's version and Java's sits in the suffix.
29110
+ *
29111
+ * `declaredIsFloor` is true on the same reasoning as go and rust: an SDK builds
29112
+ * older target frameworks, so booting 8.0 for a repo asking 6.0 is the supported
29113
+ * case rather than a substitution. A repo asking for something NEWER than our
29114
+ * default still refuses, which is where TERM-643 put that line.
29115
+ */
29116
+ dotnet: {
29117
+ repository: "mcr.microsoft.com/dotnet/sdk",
29118
+ suffix: "",
29119
+ defaultVersion: "8.0",
29120
+ declaredIsFloor: true
29121
+ },
29122
+ /**
29123
+ * TERM-1122. Maven's image, and the one a Gradle WRAPPER repo gets too: the wrapper
29124
+ * downloads its own Gradle, so it needs a JDK and nothing else. MEASURED
29125
+ * 2026-09-18: `maven:3.9-eclipse-temurin-21` carries `git`, `mvn` and JDK 21 on
29126
+ * Ubuntu 24.04, which is why this is not `eclipse-temurin` (no `git`, rejected
29127
+ * under TERM-1139). The JDK sits AFTER maven's own version in the tag, hence
29128
+ * `prefix`, and the major is all envspec derives (`javaMajor`).
29129
+ *
29130
+ * `declaredIsFloor`: a JDK builds for older `--release` targets, so a repo asking
29131
+ * for 16, which has no image, runs on 21. A Gradle toolchain is stricter than a
29132
+ * floor and asks for its exact JDK; Gradle's refusal on the wrong one reads as
29133
+ * ours (`classify.ts`, `isOfflineBuildGap`), never as the repo's.
29134
+ */
29135
+ jvm: {
29136
+ repository: "maven",
29137
+ prefix: "3.9-eclipse-temurin-",
29138
+ suffix: "",
29139
+ defaultVersion: "21",
29140
+ declaredIsFloor: true
29141
+ }
29142
+ };
29143
+ JVM_GRADLE_IMAGE = {
29144
+ repository: "gradle",
29145
+ prefix: "jdk",
29146
+ suffix: "",
29147
+ defaultVersion: "21",
29148
+ declaredIsFloor: true
29149
+ };
29150
+ unversionedImage = (shape) => `${shape.repository}:${shape.prefix ?? ""}${shape.defaultVersion}${shape.suffix}`;
28815
29151
  TAG_VERSION = /^\d+(?:\.\d+){0,2}$/;
28816
29152
  dockerManifestProbe = (image) => {
28817
29153
  const res = spawnSync4("docker", ["manifest", "inspect", image], {
@@ -29503,14 +29839,31 @@ function answerDidItPass(r) {
29503
29839
  const passed = r.status === "verified" && r.outcome !== null && isGreen(r.outcome);
29504
29840
  return { passed, summary: renderVerdictLine(r), lookAt: r.preview?.url ?? null };
29505
29841
  }
29506
- var RUN_TEST_COMMAND_SOURCES, RUN_RESULT_SCHEMA, RUN_RESULT_FIELDS, RENDER_NONE, FIELD_VIEWS;
29842
+ function exitCodeFor(r) {
29843
+ if (r.status === "refused")
29844
+ return 2;
29845
+ if (r.outcome === null)
29846
+ return 2;
29847
+ return OUTCOME_EXIT_CODES[r.outcome];
29848
+ }
29849
+ var RUN_TEST_COMMAND_SOURCES, RUN_IMAGE_SOURCES, RUN_RESULT_SCHEMA, RUN_RESULT_FIELDS, RENDER_NONE, FIELD_VIEWS, OUTCOME_EXIT_CODES;
29507
29850
  var init_result = __esm({
29508
29851
  "../../packages/envrun/dist/result.js"() {
29509
29852
  "use strict";
29510
29853
  init_dist2();
29511
29854
  init_classify2();
29512
29855
  init_venueDescriptor();
29513
- RUN_TEST_COMMAND_SOURCES = [...TEST_COMMAND_SOURCES, "developer-declared"];
29856
+ RUN_TEST_COMMAND_SOURCES = [
29857
+ ...TEST_COMMAND_SOURCES,
29858
+ "developer-declared",
29859
+ "operator-declared"
29860
+ ];
29861
+ RUN_IMAGE_SOURCES = [
29862
+ "detected",
29863
+ "none",
29864
+ "operator-declared",
29865
+ "developer-declared"
29866
+ ];
29514
29867
  RUN_RESULT_SCHEMA = "terminalhire.verification-run/1";
29515
29868
  RUN_RESULT_FIELDS = [
29516
29869
  "schema",
@@ -29535,7 +29888,9 @@ var init_result = __esm({
29535
29888
  "preview",
29536
29889
  "containerImage",
29537
29890
  "containerImageDigest",
29891
+ "imageSource",
29538
29892
  "leaksClean",
29893
+ "leakState",
29539
29894
  "venue"
29540
29895
  ];
29541
29896
  RENDER_NONE = null;
@@ -29567,12 +29922,42 @@ var init_result = __esm({
29567
29922
  preview: (r) => r.preview === null ? null : `preview ${r.preview.url}`,
29568
29923
  containerImage: (r) => r.containerImage === null ? null : `image ${r.containerImage}`,
29569
29924
  containerImageDigest: (r) => r.containerImageDigest === null ? null : `image digest ${r.containerImageDigest}`,
29570
- leaksClean: (r) => r.leaksClean === null ? null : r.leaksClean ? null : "WARNING labelled Docker objects survived teardown",
29925
+ // Shown only when a human chose the environment. `detected` is the ordinary case and
29926
+ // saying so on every run would train the reader to skip the line that matters.
29927
+ imageSource: (r) => r.imageSource === "detected" || r.imageSource === "none" ? null : `image source ${r.imageSource} (not signed)`,
29928
+ // Printed through `leakState` below, which knows WHY a false is false. Rendering both would
29929
+ // print the leak warning on a run where we merely could not look (TERM-1144).
29930
+ leaksClean: RENDER_NONE,
29931
+ // Silent when clean and when refused, as the boolean's line was. The two not-a-leak states
29932
+ // get their own sentence, because "we could not check" read as "we found a leak" is the
29933
+ // exact confusion this field exists to end.
29934
+ leakState: (r) => {
29935
+ switch (r.leakState) {
29936
+ case null:
29937
+ case "clean":
29938
+ return null;
29939
+ case "leak":
29940
+ return "WARNING labelled Docker objects survived teardown";
29941
+ case "inconclusive":
29942
+ return "leak check inconclusive \u2014 no labelled container was seen while the run was live, so finding nothing afterwards proves nothing";
29943
+ case "unobserved":
29944
+ return "leak check not taken \u2014 we could not check what was left after teardown";
29945
+ }
29946
+ },
29571
29947
  // Absent on most runs, so it prints only when there is something to say. Silence
29572
29948
  // here is the honest rendering of "no venue answered": a placeholder line would
29573
29949
  // invite a reader to treat an unanswered probe as a described venue.
29574
29950
  venue: (r) => r.venue === null ? null : renderVenueLine(r.venue)
29575
29951
  };
29952
+ OUTCOME_EXIT_CODES = {
29953
+ completed: 0,
29954
+ "tests-failed": 1,
29955
+ "no-tests-observed": 1,
29956
+ "budget-exceeded": 1,
29957
+ "counts-unparsed": 2,
29958
+ "test-command-unavailable": 2,
29959
+ "environment-exhausted": 2
29960
+ };
29576
29961
  }
29577
29962
  });
29578
29963
 
@@ -29693,12 +30078,23 @@ function toAcceptancePredicate(pair, opts = {}) {
29693
30078
  if (why !== null)
29694
30079
  return refuse3("test-command-origin-unattested", `the ${side} run ${why}`);
29695
30080
  }
29696
- if (patched.testCommandSource === "developer-declared") {
29697
- return refuse3("test-command-origin-unattested", "the developer supplied the test command (unreachable \u2014 the source rules above cover it)");
30081
+ if (patched.testCommandSource === "developer-declared" || patched.testCommandSource === "operator-declared") {
30082
+ return refuse3("test-command-origin-unattested", `${patched.testCommandSource === "developer-declared" ? "the developer" : "an operator"} supplied the test command (unreachable \u2014 the source rules above cover it)`);
29698
30083
  }
29699
30084
  if (baseline.testCommandSource !== patched.testCommandSource) {
29700
30085
  return refuse3("test-command-origin-unattested", `the pair disagrees on where the command came from: baseline ${baseline.testCommandSource}, patched ${patched.testCommandSource}. One signed value cannot describe both.`);
29701
30086
  }
30087
+ for (const [side, source, image] of [
30088
+ ["patched", patched.imageSource, patched.containerImage],
30089
+ ["baseline", baseline.imageSource, baseline.containerImage]
30090
+ ]) {
30091
+ const why = IMAGE_SOURCE_IS_SIGNABLE[source](image);
30092
+ if (why !== null)
30093
+ return refuse3("image-origin-unattested", `the ${side} run ${why}`);
30094
+ }
30095
+ if (baseline.imageSource !== patched.imageSource) {
30096
+ return refuse3("image-origin-unattested", `the pair disagrees on where the image came from: baseline ${baseline.imageSource}, patched ${patched.imageSource}. The environment is part of what the statement says was held constant.`);
30097
+ }
29702
30098
  if (baseline.containerImage !== patched.containerImage) {
29703
30099
  return refuse3("pair-disagrees-on-image", `baseline ran in ${String(baseline.containerImage)} and patched in ${String(patched.containerImage)}. The signed measurement names one image, so a pair from two environments would attribute to the patch whatever the image changed.`);
29704
30100
  }
@@ -29755,7 +30151,7 @@ function signRunStatement(predicate, privateKey, keyid) {
29755
30151
  const statement = createAcceptanceStatement(predicate);
29756
30152
  return { statement, envelope: signStatement(statement, privateKey, keyid) };
29757
30153
  }
29758
- var OUTCOME_TO_BUDGET, BASELINE_IS_A_VERDICT, CONTRADICTS_COUNTS, SOURCE_IS_SIGNABLE, ATTEST_REFUSAL_REASONS, refuse3, LOCAL_MEASUREMENT_PREFIX, REFERENCE_DOMAIN_COMPONENT, REFERENCE_DOMAIN_NAME, REFERENCE_IPV6, REFERENCE_DOMAIN, REFERENCE_PATH_COMPONENT, REPO_DIGEST_RE;
30154
+ var OUTCOME_TO_BUDGET, BASELINE_IS_A_VERDICT, CONTRADICTS_COUNTS, SOURCE_IS_SIGNABLE, IMAGE_SOURCE_IS_SIGNABLE, ATTEST_REFUSAL_REASONS, refuse3, LOCAL_MEASUREMENT_PREFIX, REFERENCE_DOMAIN_COMPONENT, REFERENCE_DOMAIN_NAME, REFERENCE_IPV6, REFERENCE_DOMAIN, REFERENCE_PATH_COMPONENT, REPO_DIGEST_RE;
29759
30155
  var init_attestation2 = __esm({
29760
30156
  "../../packages/envrun/dist/attestation.js"() {
29761
30157
  "use strict";
@@ -29811,11 +30207,25 @@ var init_attestation2 = __esm({
29811
30207
  // The party under verification chose it, and no signed member can say so. Per ADR-005
29812
30208
  // Decision 2, emit nothing rather than pick the closest word.
29813
30209
  "developer-declared": () => "had its test command supplied by the developer whose work is under verification, and the signed vocabulary has no member for that. `founder-declared` would attribute the choice to the other party; `detected` would claim the repo chose it. Both are false.",
30210
+ // US, out of band, per posting — the twin of `IMAGE_SOURCE_IS_SIGNABLE['operator-declared']`
30211
+ // and refusing for the same reason. `founder-declared` is the nearest signed member and it
30212
+ // is still false: the poster did not choose this, we did, and signing our own choice under
30213
+ // the counterparty's name is the specific false attribution the `developer-declared` entry
30214
+ // above exists to refuse. Decision 2 — emit nothing rather than pick the closest word.
30215
+ "operator-declared": () => "had its test command chosen by an operator out of band, and the signed vocabulary has no member for that. Signing it would present a hand-picked command as one the repository chose for itself.",
29814
30216
  // `none` means nobody chose a command, so a command beside it is a contradiction. Shadowed
29815
30217
  // today — `thrun.ts` sets `none` only when the derived command is null, and `no-test-command`
29816
30218
  // fires first — but that coupling runs through `runEnvironmentSpec` and lives in no type.
29817
30219
  none: (command) => command === null ? null : `records its command source as \`none\` \u2014 nobody chose one \u2014 beside the command ${JSON.stringify(command)}`
29818
30220
  };
30221
+ IMAGE_SOURCE_IS_SIGNABLE = {
30222
+ detected: () => null,
30223
+ "operator-declared": () => "had its container image chosen by an operator out of band, and the signed vocabulary has no member for that. Signing it would present a hand-picked environment as the one the runtime mapping selected.",
30224
+ "developer-declared": () => "had its container image supplied by the developer whose work is under verification. A chosen interpreter turns a red suite green as surely as a chosen test command.",
30225
+ // `none` means no image was booted, so an image name beside it is a contradiction — the
30226
+ // `SOURCE_IS_SIGNABLE.none` argument, applied to the other field.
30227
+ none: (image) => image === null ? null : `records its image source as \`none\` \u2014 nothing was booted \u2014 beside the image ${JSON.stringify(image)}`
30228
+ };
29819
30229
  ATTEST_REFUSAL_REASONS = [
29820
30230
  "our-environment-failed",
29821
30231
  "run-was-refused",
@@ -29857,7 +30267,11 @@ var init_attestation2 = __esm({
29857
30267
  // The signed triple must be reproducible from what it names — see the guard.
29858
30268
  "patch-binding-incomplete",
29859
30269
  "outcome-contradicts-counts",
29860
- "test-command-origin-unattested"
30270
+ "test-command-origin-unattested",
30271
+ // The environment half of the pair above. `pair-disagrees-on-image` compares image NAMES;
30272
+ // this one asks who CHOSE the name, which no comparison of the two halves can reveal when
30273
+ // both were handed the same override.
30274
+ "image-origin-unattested"
29861
30275
  ];
29862
30276
  refuse3 = (reason, detail) => ({
29863
30277
  ok: false,
@@ -30361,13 +30775,20 @@ function gcpBootArgv(p) {
30361
30775
  // steal". Attaching an account removes that, so the safety now rests on two things,
30362
30776
  // and this change MUST land together with proof #2 — never ahead of it:
30363
30777
  //
30364
- // 1. `--no-scopes` + ZERO project roles bound the BLAST RADIUS of a lifted token.
30365
- // No scopes → the OAuth access-token endpoint serves nothing (measured,
30366
- // TERM-706); zero roles → the token authorizes no GCP API. But it is NOT
30367
- // valueless: it is the attestation evidence itself, so a lifted token still
30368
- // authorizes a false claim about WHERE a run happened (the steal-a-true-token
30369
- // attack in the item-2 spike). `--no-scopes` stays because it removes lateral
30370
- // GCP access; it does not make losing the identity token cheap.
30778
+ // 1. `--no-scopes` and a NARROW grant set bound the BLAST RADIUS of a lifted
30779
+ // token. No scopes → the OAuth access-token endpoint serves nothing
30780
+ // (measured, TERM-706). This said "ZERO project roles" until 2026-09-18, and
30781
+ // that was never true of the account we ship: measured live, `venue-identity@`
30782
+ // holds `roles/confidentialcomputing.workloadUser` on the project and
30783
+ // `roles/artifactregistry.reader` on the `venue-images` repository alone —
30784
+ // the same two grants the Confidential Space note below already named, so this
30785
+ // file contradicted itself. Neither reaches a second repository, a bucket or
30786
+ // another VM, which is the property "zero roles" was reaching for. But the
30787
+ // token is NOT valueless: it is the attestation evidence itself, so a lifted
30788
+ // token still authorizes a false claim about WHERE a run happened (the
30789
+ // steal-a-true-token attack in the item-2 spike). `--no-scopes` stays because
30790
+ // it removes lateral GCP access; it does not make losing the identity token
30791
+ // cheap.
30371
30792
  // 2. The untrusted code cannot reach the metadata server to lift the token at all.
30372
30793
  // The test step runs `--network=none`; the install step runs on an `--internal`
30373
30794
  // network whose only egress is a CONNECT-only, registry-allowlisted proxy that
@@ -31847,11 +32268,7 @@ function makeLease(p) {
31847
32268
  }
31848
32269
  try {
31849
32270
  check("counting what the run left behind");
31850
- return Promise.resolve({
31851
- observed: true,
31852
- census: census(p.docker, label),
31853
- unobservedReason: null
31854
- });
32271
+ return Promise.resolve(censusReport(p.docker, label));
31855
32272
  } catch (err) {
31856
32273
  return Promise.resolve({
31857
32274
  observed: false,
@@ -32119,7 +32536,7 @@ function localDockerPlacement() {
32119
32536
  kind: "local-docker",
32120
32537
  refusal: null,
32121
32538
  venue: () => localVenue(),
32122
- imageFor: (runtime, override, version2) => imageForRuntime(runtime, override, version2)
32539
+ imageFor: (runtime, override, version2, variant) => imageForRuntime(runtime, override, version2, variant)
32123
32540
  };
32124
32541
  }
32125
32542
  function hostedPoolPlacement() {
@@ -32127,7 +32544,7 @@ function hostedPoolPlacement() {
32127
32544
  kind: "hosted-pool",
32128
32545
  refusal: null,
32129
32546
  venue: () => hostedVenue(),
32130
- imageFor: (runtime, override, version2) => imageForRuntime(runtime, override, version2)
32547
+ imageFor: (runtime, override, version2, variant) => imageForRuntime(runtime, override, version2, variant)
32131
32548
  };
32132
32549
  }
32133
32550
  function placementFor(kind) {
@@ -32692,6 +33109,9 @@ function detectRuntime(repo) {
32692
33109
  if (repo.listNames("").some((name) => /\.(?:csproj|fsproj|sln)$/.test(name))) {
32693
33110
  candidates.push("dotnet");
32694
33111
  }
33112
+ if (candidates.length === 0 && repo.listFiles("").some((f) => f.endsWith(".java"))) {
33113
+ candidates.push("jvm");
33114
+ }
32695
33115
  return { runtime: candidates[0] ?? "unknown", candidates };
32696
33116
  }
32697
33117
  function readJsonObject(repo, path5) {
@@ -32839,6 +33259,11 @@ function basePythonInstallCommand(repo) {
32839
33259
  }
32840
33260
  return null;
32841
33261
  }
33262
+ function rehearse(command) {
33263
+ const copy = '"$R/.terminalhire-rehearsal"';
33264
+ const home = '"$R/.terminalhire-rehearsal-home"';
33265
+ 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; }`;
33266
+ }
32842
33267
  function otherRuntimeCommands(repo, runtime) {
32843
33268
  switch (runtime) {
32844
33269
  case "go":
@@ -32866,10 +33291,21 @@ function otherRuntimeCommands(repo, runtime) {
32866
33291
  case "dotnet":
32867
33292
  return { install: "dotnet restore", test: "dotnet test" };
32868
33293
  case "jvm": {
32869
- if (repo.exists("pom.xml"))
32870
- return { install: "mvn -B dependency:go-offline", test: "mvn -B test" };
33294
+ if (!JVM_BUILD_FILES.some((file) => repo.exists(file)))
33295
+ return { install: null, test: null };
33296
+ if (repo.exists("pom.xml")) {
33297
+ return {
33298
+ install: `mvn -B dependency:go-offline && ${rehearse('mvn -B test -Dmaven.test.failure.ignore=true -Dmaven.repo.local="$R/.m2/repository"')}`,
33299
+ test: "mvn -B -o test"
33300
+ };
33301
+ }
32871
33302
  const wrapper = repo.exists("gradlew") ? "./gradlew" : "gradle";
32872
- return { install: `${wrapper} dependencies`, test: `${wrapper} test` };
33303
+ return {
33304
+ install: `${wrapper} dependencies && ${rehearse(`${wrapper} test --continue`)}`,
33305
+ // `--no-build-cache`: the rehearsal above can fill Gradle's build cache, and a
33306
+ // test task restored FROM-CACHE runs nothing and prints no count.
33307
+ test: `${wrapper} test --offline --no-build-cache`
33308
+ };
32873
33309
  }
32874
33310
  default:
32875
33311
  return { install: null, test: null };
@@ -32901,6 +33337,15 @@ function searchRuntimeVersion(repo, runtime) {
32901
33337
  push(".ruby-version", repo.readText(".ruby-version"));
32902
33338
  } else if (runtime === "dotnet") {
32903
33339
  push("global.json sdk.version", readStringField(readObjectField(readJsonObject(repo, "global.json"), "sdk"), "version"));
33340
+ } else if (runtime === "jvm") {
33341
+ const pom = repo.readText("pom.xml");
33342
+ const gradle = repo.readText("build.gradle") ?? repo.readText("build.gradle.kts");
33343
+ push("build.gradle toolchain languageVersion", javaMajor(matchFirst(gradle, /JavaLanguageVersion\.of\(\s*["']?(\d+)["']?\s*\)/) ?? matchFirst(gradle, /jvmToolchain\(\s*(\d+)\s*\)/)));
33344
+ push(".java-version", javaMajor(repo.readText(".java-version")));
33345
+ push("pom.xml maven.compiler.release", javaMajor(matchFirst(pom, /<maven\.compiler\.release>\s*([^<\s]+)\s*</)));
33346
+ push("pom.xml java.version", javaMajor(matchFirst(pom, /<java\.version>\s*([^<\s]+)\s*</)));
33347
+ push("pom.xml maven.compiler.source", javaMajor(matchFirst(pom, /<maven\.compiler\.source>\s*([^<\s]+)\s*</)));
33348
+ push("build.gradle sourceCompatibility", javaMajor(matchFirst(gradle, /sourceCompatibility\s*=\s*JavaVersion\.VERSION_([\d_]+)/)?.replace("_", ".") ?? matchFirst(gradle, /sourceCompatibility\s*=\s*["']?([\d.]+)["']?/)));
32904
33349
  }
32905
33350
  let rangeFound = null;
32906
33351
  for (const source of sources) {
@@ -32914,13 +33359,21 @@ function searchRuntimeVersion(repo, runtime) {
32914
33359
  }
32915
33360
  return { version: null, searched: sources.map((s) => s.label), rangeFound };
32916
33361
  }
33362
+ function javaMajor(text) {
33363
+ if (text === null)
33364
+ return null;
33365
+ const match2 = /^(?:1\.(\d+)|(\d+))(?:[._][\d_.]*)?$/.exec(text.trim());
33366
+ if (match2 === null)
33367
+ return null;
33368
+ return match2[1] ?? match2[2] ?? null;
33369
+ }
32917
33370
  function matchFirst(text, pattern) {
32918
33371
  if (text === null)
32919
33372
  return null;
32920
33373
  const match2 = pattern.exec(text);
32921
33374
  return match2 === null ? null : match2[1];
32922
33375
  }
32923
- var RUNTIME_MANIFESTS, MANIFEST_FILENAMES, NPM_PLACEHOLDER_TEST, REQUIREMENT_SPECIFIER, EXACT_VERSION;
33376
+ var RUNTIME_MANIFESTS, MANIFEST_FILENAMES, JVM_BUILD_FILES, NPM_PLACEHOLDER_TEST, REQUIREMENT_SPECIFIER, EXACT_VERSION;
32924
33377
  var init_manifest2 = __esm({
32925
33378
  "../../packages/envspec/dist/manifest.js"() {
32926
33379
  "use strict";
@@ -32934,6 +33387,7 @@ var init_manifest2 = __esm({
32934
33387
  { runtime: "dotnet", files: [] }
32935
33388
  ];
32936
33389
  MANIFEST_FILENAMES = RUNTIME_MANIFESTS.flatMap((m) => m.files).concat(["*.csproj", "*.fsproj", "*.sln"]).sort();
33390
+ JVM_BUILD_FILES = ["build.gradle", "build.gradle.kts", "pom.xml"];
32937
33391
  NPM_PLACEHOLDER_TEST = /^echo\s+["']?Error:\s*no test specified["']?\s*&&\s*exit\s+1$/;
32938
33392
  REQUIREMENT_SPECIFIER = /^[A-Za-z0-9._-]+(\[[A-Za-z0-9._,-]+\])?([<>=!~]=?[A-Za-z0-9._*+-]+(,[<>=!~]=?[A-Za-z0-9._*+-]+)*)?$/;
32939
33393
  EXACT_VERSION = /^v?(\d+(?:\.\d+){0,2})$/;
@@ -33330,7 +33784,7 @@ function deriveFromReader(repo) {
33330
33784
  searched: MANIFEST_FILENAMES,
33331
33785
  detail: `no ecosystem manifest was found at the repo root (looked for ${MANIFEST_FILENAMES.join(", ")}), so the language runtime could not be identified`
33332
33786
  });
33333
- } else {
33787
+ } else if (runtime !== "jvm" || JVM_BUILD_FILES.some((file) => repo.exists(file))) {
33334
33788
  derivedFrom.add("manifest");
33335
33789
  }
33336
33790
  if (detection.candidates.length > 1) {
@@ -33494,12 +33948,13 @@ function deriveRuntimeVersion(repo, runtime, job) {
33494
33948
  const setup = SETUP_ACTIONS[runtime];
33495
33949
  const searched = [];
33496
33950
  let rangeFound = null;
33951
+ const pin = (raw) => runtime === "jvm" ? javaMajor(raw) : exactVersion(raw);
33497
33952
  if (job !== null && setup !== void 0) {
33498
33953
  const direct = findActionInput(job, setup.action, setup.input);
33499
33954
  if (direct !== null) {
33500
33955
  searched.push(`${job.file} ${setup.action} ${setup.input}`);
33501
33956
  const reduced = reduceExpression(direct.command, job.singletons);
33502
- const exact = exactVersion(reduced);
33957
+ const exact = pin(reduced);
33503
33958
  if (exact !== null)
33504
33959
  return { value: exact, searched, rangeFound: null };
33505
33960
  if (reduced !== null)
@@ -33508,7 +33963,7 @@ function deriveRuntimeVersion(repo, runtime, job) {
33508
33963
  const viaFile = findActionInput(job, setup.action, setup.fileInput);
33509
33964
  if (viaFile !== null) {
33510
33965
  searched.push(`${job.file} ${setup.action} ${setup.fileInput} -> ${viaFile.command}`);
33511
- const exact = exactVersion(repo.readText(viaFile.command));
33966
+ const exact = pin(repo.readText(viaFile.command));
33512
33967
  if (exact !== null)
33513
33968
  return { value: exact, searched, rangeFound: null };
33514
33969
  }
@@ -33533,6 +33988,8 @@ function testSearchPaths(runtime, workflowFiles) {
33533
33988
  paths.push("**/*_test.go");
33534
33989
  if (runtime === "ruby")
33535
33990
  paths.push("Gemfile", "Rakefile");
33991
+ if (runtime === "jvm")
33992
+ paths.push(...JVM_BUILD_FILES);
33536
33993
  if (runtime === "unknown")
33537
33994
  paths.push(...MANIFEST_FILENAMES);
33538
33995
  return [...new Set(paths)].sort();
@@ -33550,6 +34007,9 @@ function describeTestSearch(repo, runtime, workflowFiles) {
33550
34007
  if (runtime === "python") {
33551
34008
  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`;
33552
34009
  }
34010
+ if (runtime === "jvm" && !JVM_BUILD_FILES.some((file) => repo.exists(file))) {
34011
+ 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`;
34012
+ }
33553
34013
  return `${ciPart}, and no ${runtime} test convention applies to this tree`;
33554
34014
  }
33555
34015
  function installSearchPaths(runtime, workflowFiles) {
@@ -33558,6 +34018,8 @@ function installSearchPaths(runtime, workflowFiles) {
33558
34018
  paths.push("package-lock.json", "pnpm-lock.yaml", "yarn.lock");
33559
34019
  if (runtime === "python")
33560
34020
  paths.push("poetry.lock", "pyproject.toml", "requirements.txt", "uv.lock");
34021
+ if (runtime === "jvm")
34022
+ paths.push(...JVM_BUILD_FILES);
33561
34023
  if (runtime === "unknown")
33562
34024
  paths.push(...MANIFEST_FILENAMES);
33563
34025
  return [...new Set(paths)].sort();
@@ -33636,12 +34098,41 @@ var init_dist3 = __esm({
33636
34098
  }
33637
34099
  });
33638
34100
 
34101
+ // ../../packages/envrun/dist/gradleTestSummary.js
34102
+ import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync16 } from "fs";
34103
+ import { join as join28 } from "path";
34104
+ function stageGradleTestSummary(jailHome) {
34105
+ const dir = join28(jailHome, ".gradle", "init.d");
34106
+ mkdirSync5(dir, { recursive: true });
34107
+ writeFileSync16(join28(dir, "terminalhire-test-summary.gradle"), GRADLE_TEST_SUMMARY_INIT);
34108
+ }
34109
+ var GRADLE_TEST_MARKER, GRADLE_TEST_SUMMARY_INIT;
34110
+ var init_gradleTestSummary = __esm({
34111
+ "../../packages/envrun/dist/gradleTestSummary.js"() {
34112
+ "use strict";
34113
+ GRADLE_TEST_MARKER = "terminalhire-gradle-tests:";
34114
+ GRADLE_TEST_SUMMARY_INIT = `// Written by terminalhire (TERM-1122): prints each Test task's counts, because
34115
+ // Gradle prints none when every test passes.
34116
+ allprojects {
34117
+ tasks.withType(Test).configureEach { task ->
34118
+ def label = task.path
34119
+ task.afterSuite { desc, result ->
34120
+ if (desc.parent == null) {
34121
+ println "${GRADLE_TEST_MARKER} task=\${label} total=\${result.testCount} passed=\${result.successfulTestCount} failed=\${result.failedTestCount} skipped=\${result.skippedTestCount}"
34122
+ }
34123
+ }
34124
+ }
34125
+ }
34126
+ `;
34127
+ }
34128
+ });
34129
+
33639
34130
  // ../../packages/envrun/dist/thrun.js
33640
34131
  import { execFileSync, spawnSync as spawnSync6 } from "child_process";
33641
- import { existsSync as existsSync12, mkdirSync as mkdirSync5, mkdtempSync as mkdtempSync4, rmSync as rmSync9 } from "fs";
34132
+ import { existsSync as existsSync12, mkdirSync as mkdirSync6, mkdtempSync as mkdtempSync4, rmSync as rmSync9 } from "fs";
33642
34133
  import { randomUUID as randomUUID3 } from "crypto";
33643
34134
  import { tmpdir as tmpdir4 } from "os";
33644
- import { join as join28 } from "path";
34135
+ import { join as join29 } from "path";
33645
34136
  function git(repoDir, args, allowNonZero = false) {
33646
34137
  const res = spawnSync6("git", [...args], {
33647
34138
  cwd: repoDir,
@@ -33656,7 +34147,7 @@ function git(repoDir, args, allowNonZero = false) {
33656
34147
  return res.stdout ?? "";
33657
34148
  }
33658
34149
  function collectWorkingDiff(repoDir, opts = {}) {
33659
- if (!existsSync12(join28(repoDir, ".git"))) {
34150
+ if (!existsSync12(join29(repoDir, ".git"))) {
33660
34151
  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.`);
33661
34152
  }
33662
34153
  const headSha = git(repoDir, ["rev-parse", "HEAD"]).trim();
@@ -33804,7 +34295,7 @@ function credentialFreeHome() {
33804
34295
  return credentialFreeHomeDir;
33805
34296
  let made;
33806
34297
  try {
33807
- made = mkdtempSync4(join28(tmpdir4(), "th-run-nohome-"));
34298
+ made = mkdtempSync4(join29(tmpdir4(), "th-run-nohome-"));
33808
34299
  } catch (err) {
33809
34300
  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 });
33810
34301
  }
@@ -33879,7 +34370,7 @@ function cloneTargetAtUnguarded(opts) {
33879
34370
  if (persisted !== null) {
33880
34371
  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.`);
33881
34372
  }
33882
- mkdirSync5(opts.dest, { recursive: true });
34373
+ mkdirSync6(opts.dest, { recursive: true });
33883
34374
  const runOut = (args) => execFileSync("git", [...gitConfigArgs(), ...args], {
33884
34375
  cwd: opts.dest,
33885
34376
  encoding: "utf8",
@@ -33918,7 +34409,7 @@ function cloneTargetAtUnguarded(opts) {
33918
34409
  }
33919
34410
  function scrubCloneSource(dest, run3) {
33920
34411
  run3(["remote", "remove", "origin"]);
33921
- rmSync9(join28(dest, ".git", "FETCH_HEAD"), { force: true });
34412
+ rmSync9(join29(dest, ".git", "FETCH_HEAD"), { force: true });
33922
34413
  }
33923
34414
  function publishableTarget(url) {
33924
34415
  if (separatorInTarget(url) !== null)
@@ -34057,12 +34548,18 @@ function refusedRun(fields) {
34057
34548
  treeDigest: null,
34058
34549
  baselinePatchSha256: null,
34059
34550
  testCommandSource: "none",
34551
+ // Nothing was booted, so nobody chose an image. Same reasoning as `containerImage: null`
34552
+ // below: it must not read as an image we picked and cannot name.
34553
+ imageSource: "none",
34060
34554
  boundaryRefusals: fields.boundaryRefusals,
34061
34555
  touchedPaths: fields.touchedPaths,
34062
34556
  preview: null,
34063
34557
  containerImage: null,
34064
34558
  containerImageDigest: null,
34065
34559
  leaksClean: null,
34560
+ // Null for the same reason, and never `unobserved`: that word says we tried to take a
34561
+ // census and could not, and here there was nothing to take one of (TERM-1144).
34562
+ leakState: null,
34066
34563
  // A refused run never held a lease, so there is no venue to describe. Same
34067
34564
  // reasoning as `leaksClean` above: null because nothing happened, and it must
34068
34565
  // not read as a venue we looked at and could not name.
@@ -34290,10 +34787,10 @@ async function runVerification(req, ctx) {
34290
34787
  venueIdentity: null
34291
34788
  };
34292
34789
  }
34293
- const stage = join28(req.scratchRoot, runId);
34294
- const cloneDir = join28(stage, "clone");
34295
- const scratch = join28(stage, "scratch");
34296
- mkdirSync5(scratch, { recursive: true });
34790
+ const stage = join29(req.scratchRoot, runId);
34791
+ const cloneDir = join29(stage, "clone");
34792
+ const scratch = join29(stage, "scratch");
34793
+ mkdirSync6(scratch, { recursive: true });
34297
34794
  assertSafeTargetSha(req.targetSha);
34298
34795
  progress("clone", `${publishableTarget(req.targetRepo)} @ ${req.targetSha.slice(0, 12)}`);
34299
34796
  cloneTargetAt({
@@ -34320,7 +34817,8 @@ async function runVerification(req, ctx) {
34320
34817
  const derived = deriveEnvironmentSpec(cloneDir);
34321
34818
  const spec = req.testCommandOverride === void 0 ? derived : { ...derived, testCommand: req.testCommandOverride };
34322
34819
  progress("derive", `runtime=${spec.runtime} install=${String(spec.installCommand)} test=${String(spec.testCommand)}`);
34323
- const image = placement.imageFor(spec.runtime, req.image, spec.runtimeVersion);
34820
+ refuseUnbuildableSpec(spec);
34821
+ const image = placement.imageFor(spec.runtime, req.image, spec.runtimeVersion, imageVariantFor(spec));
34324
34822
  const resolved = await resolveLease(placement, runId);
34325
34823
  if (!resolved.ok) {
34326
34824
  return {
@@ -34355,10 +34853,12 @@ async function runVerification(req, ctx) {
34355
34853
  const lease = resolved.lease;
34356
34854
  try {
34357
34855
  buildJail(scratch);
34856
+ if (spec.runtime === "jvm")
34857
+ stageGradleTestSummary(localJailPaths(scratch).jail);
34358
34858
  const venuePaths = await lease.stage({
34359
34859
  cloneDir,
34360
34860
  scratchRoot: scratch,
34361
- previewDir: join28(stage, "preview"),
34861
+ previewDir: join29(stage, "preview"),
34362
34862
  // On a dispatched run the commit is the statement of what was tested, so
34363
34863
  // it rides with the tree and the venue seam refuses a tree that is not
34364
34864
  // that commit (design §6 item 4, TERM-892 — the guard lives in
@@ -34405,7 +34905,7 @@ async function runVerification(req, ctx) {
34405
34905
  // that `founder-declared` (as this did for one review round) signs the counterparty's
34406
34906
  // name onto the developer's choice, which is worse than laundering it as `detected`:
34407
34907
  // it is a specific false attribution inside a field a reviewer trusts.
34408
- testCommandSource: req.testCommandOverride !== void 0 ? req.testCommandOverrideOrigin === "founder" ? "founder-declared" : "developer-declared" : derived.testCommand === null ? "none" : "detected",
34908
+ testCommandSource: req.testCommandOverride !== void 0 ? req.testCommandOverrideOrigin === "founder" ? "founder-declared" : req.testCommandOverrideOrigin === "operator" ? "operator-declared" : "developer-declared" : derived.testCommand === null ? "none" : "detected",
34409
34909
  boundaryRefusals: [],
34410
34910
  touchedPaths: pre.touchedPaths,
34411
34911
  preview: null,
@@ -34415,7 +34915,14 @@ async function runVerification(req, ctx) {
34415
34915
  // that measures one; a run without it is recordable but not attestable —
34416
34916
  // `toAcceptancePredicate` refuses `missing-image-digest` (TERM-893).
34417
34917
  containerImageDigest: null,
34918
+ // The image half of the provenance pair above. `detected` means the runtime mapping
34919
+ // chose the environment; an override names the human. Defaulting an unstated origin to
34920
+ // `developer-declared` is deliberate and matches `testCommandSource`: `th run --image`
34921
+ // runs on the developer's machine, judging the developer's work, so attributing it to
34922
+ // the operator would sign our name onto their choice.
34923
+ imageSource: req.image === void 0 ? "detected" : req.imageOrigin === "operator" ? "operator-declared" : "developer-declared",
34418
34924
  leaksClean: verdict.leaks.clean,
34925
+ leakState: verdict.leaks.state,
34419
34926
  // Built from the LEASE, over the client that ran the steps — never from
34420
34927
  // `req.placement`, which is a request. `venueDescriptor.ts` carries the
34421
34928
  // reasoning and the #735 failure that makes the distinction load-bearing.
@@ -34473,6 +34980,7 @@ var init_thrun = __esm({
34473
34980
  init_execute();
34474
34981
  init_placement();
34475
34982
  init_venue();
34983
+ init_gradleTestSummary();
34476
34984
  init_venueDescriptor();
34477
34985
  init_result();
34478
34986
  ThRunError = class extends Error {
@@ -34716,7 +35224,7 @@ var init_dbplan = __esm({
34716
35224
  // ../../packages/envrun/dist/dbstack.js
34717
35225
  import { spawnSync as spawnSync7 } from "child_process";
34718
35226
  import { randomBytes as randomBytes11 } from "crypto";
34719
- import { mkdirSync as mkdirSync6 } from "fs";
35227
+ import { mkdirSync as mkdirSync7 } from "fs";
34720
35228
  function installCommandFor(runner) {
34721
35229
  switch (runner) {
34722
35230
  case "sql":
@@ -34947,7 +35455,7 @@ function startDatabase(req) {
34947
35455
  if (!ready.ok) {
34948
35456
  throw new DbStackError(`INFRASTRUCTURE/INCONCLUSIVE: Postgres never accepted queries at 127.0.0.1:${String(creds.port)} within the readiness window: ${ready.detail}`);
34949
35457
  }
34950
- const query = (sql) => {
35458
+ const query2 = (sql) => {
34951
35459
  const res = docker2([
34952
35460
  "exec",
34953
35461
  `--env=PGPASSWORD=${creds.password}`,
@@ -34995,7 +35503,7 @@ function startDatabase(req) {
34995
35503
  credentials: creds,
34996
35504
  image,
34997
35505
  readyMs: ready.ms,
34998
- query,
35506
+ query: query2,
34999
35507
  runOnNetwork,
35000
35508
  teardown
35001
35509
  };
@@ -35058,8 +35566,8 @@ async function installLocalMigrationTooling(opts) {
35058
35566
  };
35059
35567
  }
35060
35568
  const { jail, tmp } = buildJail(opts.scratchRoot);
35061
- mkdirSync6(jail, { recursive: true });
35062
- mkdirSync6(tmp, { recursive: true });
35569
+ mkdirSync7(jail, { recursive: true });
35570
+ mkdirSync7(tmp, { recursive: true });
35063
35571
  const spec = {
35064
35572
  profile: "install",
35065
35573
  clone: opts.repoDir,
@@ -35354,6 +35862,7 @@ __export(dist_exports, {
35354
35862
  GOOGLE_JWKS_URL: () => GOOGLE_JWKS_URL,
35355
35863
  HostedVenueError: () => HostedVenueError,
35356
35864
  JWKS_FETCH_TIMEOUT_MS: () => JWKS_FETCH_TIMEOUT_MS,
35865
+ LEAK_STATES: () => LEAK_STATES,
35357
35866
  LOCAL_MEASUREMENT_PREFIX: () => LOCAL_MEASUREMENT_PREFIX,
35358
35867
  LabelWatch: () => LabelWatch,
35359
35868
  MIN_GIT_VERSION_FOR_END_OF_OPTIONS: () => MIN_GIT_VERSION_FOR_END_OF_OPTIONS,
@@ -35370,6 +35879,7 @@ __export(dist_exports, {
35370
35879
  REDACTED_TARGET_SHA: () => REDACTED_TARGET_SHA,
35371
35880
  RELEASED_LEASE_CENSUS_REASON: () => RELEASED_LEASE_CENSUS_REASON,
35372
35881
  REPO_DIGEST_RE: () => REPO_DIGEST_RE,
35882
+ RUN_IMAGE_SOURCES: () => RUN_IMAGE_SOURCES,
35373
35883
  RUN_LABEL_KEY: () => RUN_LABEL_KEY,
35374
35884
  RUN_RESULT_FIELDS: () => RUN_RESULT_FIELDS,
35375
35885
  RUN_RESULT_SCHEMA: () => RUN_RESULT_SCHEMA,
@@ -35386,6 +35896,7 @@ __export(dist_exports, {
35386
35896
  VENUE_GCLOUD_CONFIG: () => VENUE_GCLOUD_CONFIG,
35387
35897
  VENUE_SSH_USER: () => VENUE_SSH_USER,
35388
35898
  VENV_DIR: () => VENV_DIR,
35899
+ VERIFICATION_OUTCOMES: () => VERIFICATION_OUTCOMES,
35389
35900
  VenueRollbackError: () => VenueRollbackError,
35390
35901
  acquireTransactionally: () => acquireTransactionally,
35391
35902
  alembicChainPosition: () => alembicChainPosition,
@@ -35399,6 +35910,7 @@ __export(dist_exports, {
35399
35910
  assertVenueOwnerDeclared: () => assertVenueOwnerDeclared,
35400
35911
  bookkeepingFor: () => bookkeepingFor,
35401
35912
  census: () => census,
35913
+ censusReport: () => censusReport,
35402
35914
  censusTotal: () => censusTotal,
35403
35915
  classifyBootFailure: () => classifyBootFailure,
35404
35916
  classifyProbeFailure: () => classifyProbeFailure,
@@ -35418,6 +35930,7 @@ __export(dist_exports, {
35418
35930
  detectRunner: () => detectRunner,
35419
35931
  endOfOptionsUnsupported: () => endOfOptionsUnsupported,
35420
35932
  ensureVenueServiceCredentials: () => ensureVenueServiceCredentials,
35933
+ exitCodeFor: () => exitCodeFor,
35421
35934
  failureSourceOf: () => failureSourceOf,
35422
35935
  findRunRefusal: () => findRunRefusal,
35423
35936
  gcpBootArgv: () => gcpBootArgv,
@@ -35432,6 +35945,7 @@ __export(dist_exports, {
35432
35945
  identityProbeCommand: () => identityProbeCommand,
35433
35946
  imageForRuntime: () => imageForRuntime,
35434
35947
  imageRepo: () => imageRepo,
35948
+ imageVariantFor: () => imageVariantFor,
35435
35949
  installCommandFor: () => installCommandFor,
35436
35950
  installLocalMigrationTooling: () => installLocalMigrationTooling,
35437
35951
  isBookkeepingTable: () => isBookkeepingTable,
@@ -35461,6 +35975,7 @@ __export(dist_exports, {
35461
35975
  readSchema: () => readSchema,
35462
35976
  recordedApplied: () => recordedApplied,
35463
35977
  refuseSshTransport: () => refuseSshTransport,
35978
+ refuseUnbuildableSpec: () => refuseUnbuildableSpec,
35464
35979
  renderRunReport: () => renderRunReport,
35465
35980
  renderVenueLine: () => renderVenueLine,
35466
35981
  renderVerdictLine: () => renderVerdictLine,
@@ -35842,8 +36357,8 @@ __export(jpi_claim_exports, {
35842
36357
  });
35843
36358
  import {
35844
36359
  readFileSync as readFileSync15,
35845
- writeFileSync as writeFileSync16,
35846
- mkdirSync as mkdirSync7,
36360
+ writeFileSync as writeFileSync17,
36361
+ mkdirSync as mkdirSync8,
35847
36362
  mkdtempSync as mkdtempSync5,
35848
36363
  renameSync as renameSync7,
35849
36364
  existsSync as existsSync13,
@@ -35852,7 +36367,7 @@ import {
35852
36367
  rmSync as rmSync10,
35853
36368
  readdirSync as readdirSync3
35854
36369
  } from "fs";
35855
- import { join as join29, dirname as dirname9, isAbsolute as isAbsolute4, resolve as pathResolve } from "path";
36370
+ import { join as join30, dirname as dirname9, isAbsolute as isAbsolute4, resolve as pathResolve } from "path";
35856
36371
  import { createHash as createHash10 } from "crypto";
35857
36372
  import { homedir as homedir15, hostname as osHostname } from "os";
35858
36373
  import { execFile as execFile3, execFileSync as execFileSync2, spawnSync as spawnSync8 } from "child_process";
@@ -35871,7 +36386,7 @@ function markClaimNudged(id) {
35871
36386
  const ids2 = readNudgedClaimIds();
35872
36387
  ids2.add(id);
35873
36388
  ensureStateDir(TERMINALHIRE_DIR11);
35874
- writeFileSync16(REPO_CONTINUITY_NUDGE_MARKER, JSON.stringify({ claimIds: [...ids2] }), "utf8");
36389
+ writeFileSync17(REPO_CONTINUITY_NUDGE_MARKER, JSON.stringify({ claimIds: [...ids2] }), "utf8");
35875
36390
  } catch {
35876
36391
  }
35877
36392
  }
@@ -38136,7 +38651,7 @@ async function cmdAttach(id, worktree, branch) {
38136
38651
  function workDirFor(repoFullName, issueNumber) {
38137
38652
  const [owner, repo] = String(repoFullName).split("/");
38138
38653
  const suffix = issueNumber ? `-${issueNumber}` : "";
38139
- return join29(homedir15(), "terminalhire", "work", `${owner}-${repo}${suffix}`);
38654
+ return join30(homedir15(), "terminalhire", "work", `${owner}-${repo}${suffix}`);
38140
38655
  }
38141
38656
  function startBranchFor(repoFullName, issueNumber) {
38142
38657
  const repo = String(repoFullName).split("/")[1] || "claim";
@@ -38392,7 +38907,7 @@ terminalhire claim: not started \u2014 starting forks ${claim.repoFullName} to y
38392
38907
  );
38393
38908
  process.exit(1);
38394
38909
  }
38395
- mkdirSync7(join29(homedir15(), "terminalhire", "work"), { recursive: true });
38910
+ mkdirSync8(join30(homedir15(), "terminalhire", "work"), { recursive: true });
38396
38911
  const { createProgress: createProgress2, parseGitProgress: parseGitProgress2, splitProgressChunk: splitProgressChunk2, shStream: shStream2 } = await Promise.resolve().then(() => (init_progress(), progress_exports));
38397
38912
  const progress = createProgress2();
38398
38913
  let forkFullName;
@@ -38518,7 +39033,7 @@ function founderPostingIdOf(claim) {
38518
39033
  }
38519
39034
  function sliceWorkDirFor(claimLocalId) {
38520
39035
  const safe = String(claimLocalId).replace(/[^A-Za-z0-9._-]/g, "-");
38521
- return join29(homedir15(), "terminalhire", "work", `slice-${safe}`);
39036
+ return join30(homedir15(), "terminalhire", "work", `slice-${safe}`);
38522
39037
  }
38523
39038
  function assertNoBooleanPath(dest, flagName) {
38524
39039
  const last = String(dest).split(/[\\/]/).filter(Boolean).pop();
@@ -38635,9 +39150,9 @@ function writeSliceFiles(destDir, files) {
38635
39150
  const unavailable = [];
38636
39151
  for (const f of files) {
38637
39152
  if (typeof f.content === "string") {
38638
- const abs = join29(destDir, f.path);
38639
- mkdirSync7(dirname9(abs), { recursive: true });
38640
- writeFileSync16(abs, f.content, "utf8");
39153
+ const abs = join30(destDir, f.path);
39154
+ mkdirSync8(dirname9(abs), { recursive: true });
39155
+ writeFileSync17(abs, f.content, "utf8");
38641
39156
  written.push(f.path);
38642
39157
  } else {
38643
39158
  unavailable.push({ path: f.path, reason: f.unavailableReason || "(no reason given)" });
@@ -38666,7 +39181,7 @@ function writeDeliveredBrief(destDir, spec) {
38666
39181
  function ensureExcludedPackDir(destDir) {
38667
39182
  let occupant = null;
38668
39183
  try {
38669
- occupant = lstatSync3(join29(destDir, BRIEF_DIR));
39184
+ occupant = lstatSync3(join30(destDir, BRIEF_DIR));
38670
39185
  } catch (err) {
38671
39186
  if (err?.code !== "ENOENT") {
38672
39187
  return {
@@ -38681,12 +39196,12 @@ function ensureExcludedPackDir(destDir) {
38681
39196
  reason: `${BRIEF_DIR}/ already exists in the delivered tree, and excluding it would hide that content from your patch`
38682
39197
  };
38683
39198
  }
38684
- const excludeFile = join29(destDir, ".git", "info", "exclude");
39199
+ const excludeFile = join30(destDir, ".git", "info", "exclude");
38685
39200
  try {
38686
39201
  const existing = existsSync13(excludeFile) ? readFileSync15(excludeFile, "utf8") : "";
38687
39202
  if (!existing.split("\n").includes(BRIEF_EXCLUDE_LINE)) {
38688
- mkdirSync7(dirname9(excludeFile), { recursive: true });
38689
- writeFileSync16(
39203
+ mkdirSync8(dirname9(excludeFile), { recursive: true });
39204
+ writeFileSync17(
38690
39205
  excludeFile,
38691
39206
  `${existing}${existing === "" || existing.endsWith("\n") ? "" : "\n"}${BRIEF_EXCLUDE_LINE}
38692
39207
  `,
@@ -38700,9 +39215,9 @@ function ensureExcludedPackDir(destDir) {
38700
39215
  }
38701
39216
  function writePackFile(destDir, relPath, content, what) {
38702
39217
  try {
38703
- const abs = join29(destDir, relPath);
38704
- mkdirSync7(dirname9(abs), { recursive: true });
38705
- writeFileSync16(abs, content, { encoding: "utf8", flag: "wx" });
39218
+ const abs = join30(destDir, relPath);
39219
+ mkdirSync8(dirname9(abs), { recursive: true });
39220
+ writeFileSync17(abs, content, { encoding: "utf8", flag: "wx" });
38706
39221
  } catch (err) {
38707
39222
  return { written: false, reason: `the ${what} could not be written (${err.message})` };
38708
39223
  }
@@ -39103,7 +39618,7 @@ async function cmdSliceFullTier(claims, id, local, fullTierBody, flags, cloneRep
39103
39618
  if (resolvedDir.suffixed) {
39104
39619
  console.log(`terminalhire claim: the usual directory has content \u2014 using ${dest}`);
39105
39620
  }
39106
- mkdirSync7(dest, { recursive: true });
39621
+ mkdirSync8(dest, { recursive: true });
39107
39622
  const branch = `claim/${String(claim.id).replace(/[^A-Za-z0-9._-]/g, "-")}`;
39108
39623
  let engine;
39109
39624
  try {
@@ -39285,7 +39800,7 @@ async function attemptSliceDelivery(id, flags = {}) {
39285
39800
  if (resolvedDir.suffixed) {
39286
39801
  console.log(`terminalhire claim: the usual directory has content \u2014 using ${finalDest}`);
39287
39802
  }
39288
- mkdirSync7(dirname9(finalDest), { recursive: true });
39803
+ mkdirSync8(dirname9(finalDest), { recursive: true });
39289
39804
  let dest = mkdtempSync5(`${finalDest}.tmp-`);
39290
39805
  const { written, unavailable } = writeSliceFiles(dest, body.files);
39291
39806
  const branch = `claim/${String(claim.id).replace(/[^A-Za-z0-9._-]/g, "-")}`;
@@ -39826,7 +40341,7 @@ async function cmdSubmit(id, flags = {}) {
39826
40341
  const head = `${ghUser}:${claim.branch}`;
39827
40342
  const title = flags.title || claim.title;
39828
40343
  const noBody = Boolean(flags["no-body"]);
39829
- const prBodyPath = join29(wt, "PR-BODY.md");
40344
+ const prBodyPath = join30(wt, "PR-BODY.md");
39830
40345
  const bodySource = pickBodySource({
39831
40346
  bodyFileFlag: flags["body-file"],
39832
40347
  noBody,
@@ -40066,7 +40581,7 @@ function readClaimPushMarker() {
40066
40581
  }
40067
40582
  function writeClaimPushMarker(marker) {
40068
40583
  ensureStateDir(TERMINALHIRE_DIR11);
40069
- writeFileSync16(CLAIM_PUSH_MARKER, JSON.stringify(marker, null, 2) + "\n", "utf8");
40584
+ writeFileSync17(CLAIM_PUSH_MARKER, JSON.stringify(marker, null, 2) + "\n", "utf8");
40070
40585
  }
40071
40586
  function clearClaimPushMarker() {
40072
40587
  try {
@@ -40980,10 +41495,10 @@ var init_jpi_claim = __esm({
40980
41495
  init_claim_push_bg();
40981
41496
  init_founder_verdict_sync();
40982
41497
  init_founder_note_sync();
40983
- TERMINALHIRE_DIR11 = process.env.TERMINALHIRE_DIR || join29(homedir15(), ".terminalhire");
40984
- INDEX_CACHE_FILE2 = join29(TERMINALHIRE_DIR11, "index-cache.json");
40985
- CLAIM_PUSH_MARKER = join29(TERMINALHIRE_DIR11, "claim-push.json");
40986
- REPO_CONTINUITY_NUDGE_MARKER = join29(TERMINALHIRE_DIR11, "repo-continuity-nudged.json");
41498
+ TERMINALHIRE_DIR11 = process.env.TERMINALHIRE_DIR || join30(homedir15(), ".terminalhire");
41499
+ INDEX_CACHE_FILE2 = join30(TERMINALHIRE_DIR11, "index-cache.json");
41500
+ CLAIM_PUSH_MARKER = join30(TERMINALHIRE_DIR11, "claim-push.json");
41501
+ REPO_CONTINUITY_NUDGE_MARKER = join30(TERMINALHIRE_DIR11, "repo-continuity-nudged.json");
40987
41502
  API_URL = resolveApiBase();
40988
41503
  CLAIM_SYNC_BASE4 = API_URL;
40989
41504
  CLAIM_CONSENT_VERSION = 1;
@@ -53227,9 +53742,9 @@ var require_schemes = __commonJS({
53227
53742
  wsComponent.secure = void 0;
53228
53743
  }
53229
53744
  if (wsComponent.resourceName) {
53230
- const [path5, query] = wsComponent.resourceName.split("?");
53745
+ const [path5, query2] = wsComponent.resourceName.split("?");
53231
53746
  wsComponent.path = path5 && path5 !== "/" ? path5 : void 0;
53232
- wsComponent.query = query;
53747
+ wsComponent.query = query2;
53233
53748
  wsComponent.resourceName = void 0;
53234
53749
  }
53235
53750
  wsComponent.fragment = void 0;
@@ -63184,8 +63699,8 @@ __export(config_exports, {
63184
63699
  readConfig: () => readConfig,
63185
63700
  writeConfig: () => writeConfig
63186
63701
  });
63187
- import { readFileSync as readFileSync16, writeFileSync as writeFileSync17, existsSync as existsSync14 } from "fs";
63188
- import { join as join30 } from "path";
63702
+ import { readFileSync as readFileSync16, writeFileSync as writeFileSync18, existsSync as existsSync14 } from "fs";
63703
+ import { join as join31 } from "path";
63189
63704
  import { homedir as homedir16 } from "os";
63190
63705
  function readConfig() {
63191
63706
  try {
@@ -63207,7 +63722,7 @@ function writeConfig(config2) {
63207
63722
  }
63208
63723
  delete merged.contributePrompted;
63209
63724
  }
63210
- writeFileSync17(CONFIG_FILE, JSON.stringify(merged, null, 2) + "\n", "utf8");
63725
+ writeFileSync18(CONFIG_FILE, JSON.stringify(merged, null, 2) + "\n", "utf8");
63211
63726
  }
63212
63727
  function parseNudgeMode(raw) {
63213
63728
  if (raw === "session" || raw === "always") return raw;
@@ -63268,8 +63783,8 @@ var init_config = __esm({
63268
63783
  "src/config.ts"() {
63269
63784
  "use strict";
63270
63785
  init_state_dir();
63271
- TERMINALHIRE_DIR12 = process.env.TERMINALHIRE_DIR || join30(homedir16(), ".terminalhire");
63272
- CONFIG_FILE = join30(TERMINALHIRE_DIR12, "config.json");
63786
+ TERMINALHIRE_DIR12 = process.env.TERMINALHIRE_DIR || join31(homedir16(), ".terminalhire");
63787
+ CONFIG_FILE = join31(TERMINALHIRE_DIR12, "config.json");
63273
63788
  DEFAULT_CONFIG = {
63274
63789
  nudge: "session",
63275
63790
  peerConnect: false,
@@ -63773,7 +64288,7 @@ async function claimWorkspaceResult(args = {}) {
63773
64288
  try {
63774
64289
  const claims = await Promise.resolve().then(() => (init_claims(), claims_exports));
63775
64290
  const { existsSync: existsSync15, readFileSync: readFileSync17, lstatSync: lstatSync4 } = await import("fs");
63776
- const { join: join31 } = await import("path");
64291
+ const { join: join32 } = await import("path");
63777
64292
  const { BRIEF_REL_PATH: BRIEF_REL_PATH2, VERIFY_REL_PATH: VERIFY_REL_PATH2, AGENTS_REL_PATH: AGENTS_REL_PATH2, sha256OfUtf8: sha256OfUtf82 } = await Promise.resolve().then(() => (init_jpi_claim(), jpi_claim_exports));
63778
64293
  const packPaths = (c) => {
63779
64294
  const p = {};
@@ -63786,7 +64301,7 @@ async function claimWorkspaceResult(args = {}) {
63786
64301
  if (c.workspacePack?.[member] !== true) continue;
63787
64302
  const digest = c.packDigests?.[member];
63788
64303
  if (typeof digest !== "string" || digest === "") continue;
63789
- const abs = join31(c.worktreePath, rel);
64304
+ const abs = join32(c.worktreePath, rel);
63790
64305
  try {
63791
64306
  const st = lstatSync4(abs);
63792
64307
  if (!st.isFile() || st.size > 1024 * 1024) continue;
@@ -63805,7 +64320,7 @@ async function claimWorkspaceResult(args = {}) {
63805
64320
  hint: `No workspace has been delivered for this claim yet. A human runs: terminalhire claim start ${c.id} --watch`
63806
64321
  };
63807
64322
  }
63808
- if (!existsSync15(c.worktreePath) || !existsSync15(join31(c.worktreePath, ".git"))) {
64323
+ if (!existsSync15(c.worktreePath) || !existsSync15(join32(c.worktreePath, ".git"))) {
63809
64324
  return {
63810
64325
  status: "not_ready",
63811
64326
  claimId: c.id,
@@ -64011,10 +64526,10 @@ async function run2() {
64011
64526
  let version2 = "0.0.0";
64012
64527
  try {
64013
64528
  const { readFileSync: readFileSync17, existsSync: existsSync15 } = await import("fs");
64014
- const { join: join31 } = await import("path");
64529
+ const { join: join32 } = await import("path");
64015
64530
  const { fileURLToPath: fileURLToPath4 } = await import("url");
64016
64531
  const here = fileURLToPath4(new URL(".", import.meta.url));
64017
- for (const p of [join31(here, "..", "..", "package.json"), join31(here, "..", "package.json")]) {
64532
+ for (const p of [join32(here, "..", "..", "package.json"), join32(here, "..", "package.json")]) {
64018
64533
  if (existsSync15(p)) {
64019
64534
  const pkg = JSON.parse(readFileSync17(p, "utf8"));
64020
64535
  if (pkg.version) {