@outerlayer/cli 0.8.6 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +24 -14
  3. package/dist/{agent-setup-LEQF4V5F.js → agent-setup-ODTDC3US.js} +8 -7
  4. package/dist/{build-3FSJR5OO.js → build-LELVCWHV.js} +2 -2
  5. package/dist/build-info.json +1 -1
  6. package/dist/{builder-5UFAF5LW.js → builder-5DKTBWT3.js} +5 -5
  7. package/dist/{check-443BADSD.js → check-VJRJ2KQ4.js} +69 -34
  8. package/dist/{chunk-Y7UQHKFY.js → chunk-3FMPZPJQ.js} +1 -4
  9. package/dist/chunk-3JVYMD4G.js +18 -0
  10. package/dist/{chunk-K4MGMSMN.js → chunk-4HMXH2OA.js} +8 -2
  11. package/dist/{chunk-H6IGIE3I.js → chunk-543OT6V5.js} +4 -4
  12. package/dist/chunk-5K3IUOPJ.js +178 -0
  13. package/dist/{chunk-HWMYGAKF.js → chunk-6CXYORUS.js} +1 -1
  14. package/dist/{inspect-XAUSB7L3.js → chunk-6MZSX4M7.js} +12 -6
  15. package/dist/{chunk-IS4DIGBQ.js → chunk-ABIWDUMS.js} +1 -13
  16. package/dist/{chunk-WLV4KCAW.js → chunk-BGWTYRSS.js} +1 -1
  17. package/dist/{chunk-2MFYKH3C.js → chunk-BMX3L7CR.js} +1 -1
  18. package/dist/{chunk-HKMPVPO7.js → chunk-BYT5O5RV.js} +7 -1
  19. package/dist/{chunk-WGLWDX5J.js → chunk-FKFGQJNN.js} +1 -1
  20. package/dist/{chunk-MSV44EB5.js → chunk-KPUJGBA4.js} +2 -2
  21. package/dist/{chunk-TY7EZC7U.js → chunk-KWCJLAHQ.js} +5 -5
  22. package/dist/{chunk-GJ3OWUFO.js → chunk-LBU4CLK5.js} +113 -24
  23. package/dist/{chunk-CDISNKM4.js → chunk-LTJPX7TX.js} +93 -13
  24. package/dist/{chunk-TFJGK4UB.js → chunk-LYESSQUA.js} +22 -4
  25. package/dist/{chunk-7KI224YS.js → chunk-M2PBLRB7.js} +1 -1
  26. package/dist/{chunk-2FWL7CE2.js → chunk-M6G7TJVF.js} +1 -1
  27. package/dist/{chunk-CRLAB4PM.js → chunk-NTLGWCWK.js} +1 -1
  28. package/dist/{chunk-ALCXFVUV.js → chunk-OSKO3PAL.js} +25 -19
  29. package/dist/{chunk-AIW6GLET.js → chunk-PDTSUOVT.js} +1 -1
  30. package/dist/{chunk-LKUUQ3XV.js → chunk-QPPPUKQJ.js} +1 -1
  31. package/dist/{chunk-6AFQOYO3.js → chunk-RWQWPZB4.js} +10 -6
  32. package/dist/{chunk-2E2MG3KW.js → chunk-S6IUUNCD.js} +1 -1
  33. package/dist/{chunk-AGMIJ725.js → chunk-SUMWRA7K.js} +1 -1
  34. package/dist/{chunk-NKU5OPYP.js → chunk-TB7EP24C.js} +1 -1
  35. package/dist/{chunk-DE4GLH3P.js → chunk-TV36SKEN.js} +2 -2
  36. package/dist/{chunk-J5DPVNL3.js → chunk-V42JY4F6.js} +2 -2
  37. package/dist/{chunk-FCDET2U5.js → chunk-VMK7I3TB.js} +3 -3
  38. package/dist/{chunk-IOG6LPEI.js → chunk-WJBJY5DQ.js} +2 -2
  39. package/dist/{chunk-SWGQAURM.js → chunk-XGCJNSI7.js} +26 -7
  40. package/dist/{chunk-FTW6C2E7.js → chunk-XZNO4QED.js} +10 -10
  41. package/dist/{chunk-NQWTCX3A.js → chunk-YCPV7FN6.js} +31 -19
  42. package/dist/{chunk-PK5NANMT.js → chunk-YT35WGIP.js} +5 -3
  43. package/dist/{chunk-DSPYQUH4.js → chunk-YU5GL7QS.js} +2 -2
  44. package/dist/{chunk-BL63NBJZ.js → chunk-ZEQMTBRD.js} +1 -1
  45. package/dist/{cli-PNMCZVQ4.js → cli-77URFYI7.js} +83 -83
  46. package/dist/{command-WKRTL3JQ.js → command-2LYWVGIK.js} +21 -21
  47. package/dist/{config-OOBPCY7Q.js → config-X45X7AS4.js} +3 -3
  48. package/dist/{connect-cmd-YEO7WRSL.js → connect-cmd-MPZWSEKY.js} +4 -4
  49. package/dist/{context-adopt-3REPEEQR.js → context-adopt-A77G67CP.js} +6 -5
  50. package/dist/{context-materialize-DU6B6RXF.js → context-materialize-KQZYATQZ.js} +6 -5
  51. package/dist/{dist-PKBWZAAL.js → dist-QY5CL5LB.js} +2 -2
  52. package/dist/{docker-5DUNHNOH.js → docker-V7B6UKPF.js} +6 -6
  53. package/dist/{doctor-FEIBPZL7.js → doctor-PUAL5LTL.js} +46 -35
  54. package/dist/{emit-artifact-cmd-S3CASUQK.js → emit-artifact-cmd-P3IWNSQY.js} +7 -7
  55. package/dist/{emit-cmd-ETI47BA6.js → emit-cmd-SU62J2PB.js} +4 -4
  56. package/dist/{emit-criteria-cmd-ZTUP7OGA.js → emit-criteria-cmd-GOSP6X74.js} +5 -5
  57. package/dist/{emit-finding-cmd-TTXBZ4B7.js → emit-finding-cmd-D554IQKU.js} +5 -5
  58. package/dist/{emit-result-cmd-34OC6TI5.js → emit-result-cmd-QACXTIBV.js} +7 -7
  59. package/dist/{exec-client-2UX6NHAO.js → exec-client-QTUO6TZT.js} +4 -4
  60. package/dist/{guest-init-VHQNFCFS.js → guest-init-4UW4HM6N.js} +4 -4
  61. package/dist/{hook-fast-CFLLVMSV.js → hook-fast-AQCAQIA6.js} +1 -1
  62. package/dist/{import-capture-cmd-Z3232HR4.js → import-capture-cmd-5NJVL2HN.js} +3 -3
  63. package/dist/{import-ruler-cmd-2PLXZXM7.js → import-ruler-cmd-TUK3MRPC.js} +2 -2
  64. package/dist/index.js +3 -3
  65. package/dist/{init-AHQHM56A.js → init-TMBE3BRN.js} +20 -20
  66. package/dist/{init-UZ5TXACM.js → init-WX5XE6L3.js} +47 -23
  67. package/dist/{init-cmd-F4FS5AVC.js → init-cmd-4FQKQLJ5.js} +14 -14
  68. package/dist/inspect-6UYAAXH7.js +6 -0
  69. package/dist/{install-C33LT5KQ.js → install-PYNCWSTV.js} +4 -4
  70. package/dist/{loop-U7GLISBM.js → loop-QLL4DKRF.js} +31 -30
  71. package/dist/{machine-Y3TBDMXD.js → machine-7T7FBSUL.js} +19 -19
  72. package/dist/{real-deps-AKVGIDPZ.js → real-deps-LS64D3M6.js} +2 -1
  73. package/dist/{session-sender-LKVVLAUP.js → session-sender-HVWTYG35.js} +6 -6
  74. package/dist/{starter-pack-L5WPXL4Q.js → starter-pack-I35VNYAR.js} +4 -4
  75. package/dist/{status-OQ23WOUP.js → status-SMF5JG2K.js} +24 -24
  76. package/dist/{sync-cmd-VH6HSMG5.js → sync-cmd-SLMPCUXO.js} +5 -5
  77. package/dist/{watch-HUKDEFUX.js → watch-TLM5QN5X.js} +5 -5
  78. package/dist/{work-claim-cmd-JLCU5SPP.js → work-claim-cmd-VSSZDFY5.js} +34 -12
  79. package/dist/{work-cmd-SBKQJBJ2.js → work-cmd-TK4VOOHL.js} +6 -6
  80. package/dist/{work-comment-cmd-TNUDUUAT.js → work-comment-cmd-VQCG72ZQ.js} +6 -6
  81. package/dist/{work-open-pr-cmd-IB57SMAD.js → work-open-pr-cmd-YESMWATB.js} +17 -9
  82. package/dist/{work-pr-cmd-HDDNFSKA.js → work-pr-cmd-6TMSCO3Q.js} +7 -6
  83. package/package.json +1 -1
  84. package/skill-pack/maintained/amend/SKILL.md +22 -12
  85. package/skill-pack/template/build/SKILL.md +13 -2
  86. package/skill-pack/template/build/references/evidence.md +2 -2
  87. package/dist/chunk-PVC36MFI.js +0 -103
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import './chunk-Z5GEFMRW.js';
4
3
  import { spawnSync } from 'child_process';
5
4
  import { statSync, readFileSync } from 'fs';
6
5
  import { join } from 'path';
@@ -15,11 +14,18 @@ function holdsGroup(status, gid) {
15
14
  const supplementary = /^Groups:[ \t]*(.*)$/m.exec(status)?.[1]?.trim().split(/\s+/).filter((g) => g !== "") ?? [];
16
15
  return [primary, ...supplementary].some((g) => g !== void 0 && Number(g) === gid);
17
16
  }
17
+ function parseRunnerEnv(text) {
18
+ const env = {};
19
+ for (const line of text.split("\n")) {
20
+ const match = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)=(.*)$/.exec(line);
21
+ if (match === null) continue;
22
+ env[match[1]] = match[2].trim().replace(/^(["'])(.*)\1$/, "$2");
23
+ }
24
+ return env;
25
+ }
18
26
  function credentialNames(env) {
19
- const set = new Set(
20
- (env ?? "").split("\n").map((line) => /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)=(.+)$/.exec(line)).flatMap((m) => m === null || m[2].trim() === "" ? [] : [m[1]])
21
- );
22
- return CREDENTIAL_VARIABLES.filter((name) => set.has(name));
27
+ const set = parseRunnerEnv(env ?? "");
28
+ return CREDENTIAL_VARIABLES.filter((name) => (set[name] ?? "").trim() !== "");
23
29
  }
24
30
  function inspectService(unit, configDir, probes) {
25
31
  const shown = probes.show(unit);
@@ -60,4 +66,4 @@ function realInspectProbes() {
60
66
  };
61
67
  }
62
68
 
63
- export { inspectService, realInspectProbes };
69
+ export { inspectService, parseRunnerEnv, realInspectProbes };
@@ -6,18 +6,6 @@ import { join, dirname } from 'path';
6
6
  import { createHash } from 'crypto';
7
7
 
8
8
  createRequire(import.meta.url);
9
-
10
- // src/runner/update/installed-switch.ts
11
- function decideInstalledSwitch(input) {
12
- const to = input.current;
13
- if (to === void 0 || to === input.own || !input.fromCurrent) return { kind: "none" };
14
- if (!input.installed) return { kind: "missing", to };
15
- if (!input.underService) return { kind: "foreground", to };
16
- return { kind: "restart", to };
17
- }
18
- function startedByService(env, parentPid) {
19
- return (env.INVOCATION_ID ?? "") !== "" && parentPid === 1;
20
- }
21
9
  var REGISTRY_URL = "https://registry.npmjs.org";
22
10
  var PACKAGE_NAME = "@outerlayer/cli";
23
11
  var PACKAGE_PATH = "@outerlayer%2fcli";
@@ -113,4 +101,4 @@ async function auditSignatures(runNpm, dir) {
113
101
  return { ok: true };
114
102
  }
115
103
 
116
- export { auditSignatures, decideInstalledSwitch, fetchProvenance, fetchTarballDigest, fetchVersionMeta, installVersion, npmSupportsProvenance, npmVersion, realRunNode, realRunNpm, startedByService };
104
+ export { auditSignatures, fetchProvenance, fetchTarballDigest, fetchVersionMeta, installVersion, npmSupportsProvenance, npmVersion, realRunNode, realRunNpm };
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { splitRawFile } from './chunk-NKU5OPYP.js';
3
+ import { splitRawFile } from './chunk-TB7EP24C.js';
4
4
  import { resolvePackageVersion } from './chunk-RA3O54FC.js';
5
5
  import { existsSync, readFileSync, mkdirSync, writeFileSync, readdirSync } from 'fs';
6
6
  import { join, dirname } from 'path';
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { CONTEXT_PIN_SCHEMA_VERSION, CONTEXT_PIN_FILENAME } from './chunk-NKU5OPYP.js';
3
+ import { CONTEXT_PIN_SCHEMA_VERSION, CONTEXT_PIN_FILENAME } from './chunk-TB7EP24C.js';
4
4
  import { readFileSync, existsSync, writeFileSync, mkdirSync, utimesSync, statSync, unlinkSync } from 'fs';
5
5
  import { join, dirname } from 'path';
6
6
 
@@ -42,6 +42,12 @@ function withGitConfig(env, key, value) {
42
42
  [`GIT_CONFIG_VALUE_${at}`]: value
43
43
  };
44
44
  }
45
+ function tokenHeader(token) {
46
+ return `Authorization: Basic ${Buffer.from(`x-access-token:${token}`).toString("base64")}`;
47
+ }
48
+ function withTokenHeader(env, url, token) {
49
+ return withGitConfig(env, `http.${url}.extraHeader`, tokenHeader(token));
50
+ }
45
51
  function withHooksPath(env, dir) {
46
52
  return withGitConfig(env, "core.hooksPath", dir);
47
53
  }
@@ -52,4 +58,4 @@ function commitIdentityRecord(identity) {
52
58
  };
53
59
  }
54
60
 
55
- export { authorEnvironment, commitIdentityRecord, parseClaimIdentity, withGitConfig, withHooksPath };
61
+ export { authorEnvironment, commitIdentityRecord, parseClaimIdentity, tokenHeader, withGitConfig, withHooksPath, withTokenHeader };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
3
  import { RecipeError } from './chunk-QOZKPLVJ.js';
4
- import { trackImageBuild, isOutOfMemory, ensureBuilder } from './chunk-DE4GLH3P.js';
4
+ import { trackImageBuild, isOutOfMemory, ensureBuilder } from './chunk-TV36SKEN.js';
5
5
  import { spawn } from 'child_process';
6
6
  import { existsSync, mkdirSync, createWriteStream, rmSync, readFileSync } from 'fs';
7
7
  import { join, dirname } from 'path';
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { fetchFactories, selectFactory, saveFactoryConnection, autoConnectedLine } from './chunk-TFJGK4UB.js';
4
- import { resolveRepoIdentity } from './chunk-CDISNKM4.js';
3
+ import { fetchFactories, selectFactory, saveFactoryConnection, autoConnectedLine } from './chunk-LYESSQUA.js';
4
+ import { resolveRepoIdentity } from './chunk-LTJPX7TX.js';
5
5
  import { resolveGatewayCredentials } from './chunk-PLMTLGYH.js';
6
6
  import { findGitDirs, readRepoConnection } from './chunk-BJ3KTMDH.js';
7
7
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { autoConnect } from './chunk-MSV44EB5.js';
3
+ import { autoConnect } from './chunk-KPUJGBA4.js';
4
4
  import { detectActiveSession } from './chunk-BFESLKPP.js';
5
- import { sanitizeTerminal } from './chunk-BL63NBJZ.js';
6
- import { resolveRepoIdentity } from './chunk-CDISNKM4.js';
5
+ import { sanitizeTerminal } from './chunk-ZEQMTBRD.js';
6
+ import { resolveRepoIdentity } from './chunk-LTJPX7TX.js';
7
7
  import { parseTrackerNumber, trackerNumberError } from './chunk-WZBHBH3J.js';
8
8
  import { defaultFetch } from './chunk-YO4PSLVB.js';
9
9
  import { resolveGatewayCredentials, unauthorizedMessage } from './chunk-PLMTLGYH.js';
@@ -347,7 +347,7 @@ async function runWorkLinkSession(opts) {
347
347
  return await linkSession(opts);
348
348
  } catch (err) {
349
349
  if (opts.logFailures) {
350
- const { logHookError } = await import('./hook-fast-CFLLVMSV.js');
350
+ const { logHookError } = await import('./hook-fast-AQCAQIA6.js');
351
351
  const reason = err instanceof Error ? err.message : String(err);
352
352
  logHookError(opts.home ?? homeFromEnv(opts.env ?? process.env), new Error(`work link-session #${opts.number} failed: ${reason}`));
353
353
  }
@@ -505,4 +505,4 @@ async function runWorkList(opts) {
505
505
  return { data, output };
506
506
  }
507
507
 
508
- export { WorkCommandError, findLiveItem, getJson, isSignatureRefusal, parsePositiveInt, postJson, resolveCredentials, resolveRepository, runWorkBuild, runWorkLinkSession, runWorkList, runWorkRemove, runWorkStatus, signatureRefusalMessage };
508
+ export { WorkCommandError, environmentFacts, findLiveItem, getJson, isSignatureRefusal, parsePositiveInt, postJson, resolveCredentials, resolveRepository, runWorkBuild, runWorkLinkSession, runWorkList, runWorkRemove, runWorkStatus, signatureRefusalMessage };
@@ -1,24 +1,24 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { readDefaultBranchHead, cloneRepository, buildRepositoryImage } from './chunk-Y7UQHKFY.js';
3
+ import { readDefaultBranchHead, cloneRepository, buildRepositoryImage } from './chunk-3FMPZPJQ.js';
4
4
  import { startTimeOf, isSameProcess } from './chunk-N5FOE5PS.js';
5
5
  import { currentCliBuild } from './chunk-OGFGZQA3.js';
6
- import { createDockerHost, childEnvironment, spawnRun } from './chunk-WGLWDX5J.js';
6
+ import { createDockerHost, childEnvironment, spawnRun } from './chunk-FKFGQJNN.js';
7
7
  import { RecipeError } from './chunk-QOZKPLVJ.js';
8
- import { builderSpec, runnerLabelValue, RUNNER_LABEL, BUILD_LABEL, prepareRunArgs, containerRunArgs, containerExecArgs } from './chunk-DE4GLH3P.js';
8
+ import { builderSpec, runnerLabelValue, RUNNER_LABEL, BUILD_LABEL, prepareRunArgs, containerRunArgs, containerExecArgs } from './chunk-TV36SKEN.js';
9
9
  import { CLAUDE_CODE_VERSION, firecrackerArch, MICROVM_ARCHES, DEFAULT_BASE_IMAGE, GUEST_HELPER_SHA256, GUEST_ASSETS_BASE_URL, GUEST_KERNEL_SHA256, FIRECRACKER_BINARY_SHA256, FIRECRACKER_SHA256, FIRECRACKER_VERSION, GUEST_ASSETS_VERSION } from './chunk-CX22S5BA.js';
10
- import { execCapture } from './chunk-HWMYGAKF.js';
11
- import { GUEST_CID } from './chunk-2E2MG3KW.js';
12
- import { WorkCommandError, postJson } from './chunk-TY7EZC7U.js';
13
- import { setCustomScrubbers, setLocalIdentity, setRepoRoot, parseTranscript, scrubDeep, scrubText } from './chunk-CDISNKM4.js';
10
+ import { execCapture } from './chunk-6CXYORUS.js';
11
+ import { GUEST_CID } from './chunk-S6IUUNCD.js';
12
+ import { WorkCommandError, postJson } from './chunk-KWCJLAHQ.js';
13
+ import { setCustomScrubbers, setLocalIdentity, setRepoRoot, parseTranscript, scrubDeep, scrubText } from './chunk-LTJPX7TX.js';
14
14
  import { hostAllowed } from './chunk-UXYLWVTQ.js';
15
15
  import { parseDuKilobytes } from './chunk-7RQ73DLO.js';
16
- import { RELAY_PORT, CHECKOUT_DIR, JOB_MOUNT, claudeCredential, buildEnvironment, startBuildServices, checkEnvironment, AGENT_CREDENTIAL_MISSING } from './chunk-2FWL7CE2.js';
17
- import { defaultGitRunner, materializeContext } from './chunk-6AFQOYO3.js';
18
- import { readContextManifest, readSourceCache } from './chunk-2MFYKH3C.js';
19
- import { orderSessions, extractFacts, sessionsToTimeline } from './chunk-NKU5OPYP.js';
16
+ import { RELAY_PORT, CHECKOUT_DIR, JOB_MOUNT, claudeCredential, buildEnvironment, startBuildServices, checkEnvironment, AGENT_CREDENTIAL_MISSING } from './chunk-M6G7TJVF.js';
17
+ import { defaultGitRunner, materializeContext } from './chunk-RWQWPZB4.js';
18
+ import { readContextManifest, readSourceCache } from './chunk-BMX3L7CR.js';
19
+ import { orderSessions, extractFacts, sessionsToTimeline } from './chunk-TB7EP24C.js';
20
20
  import { signingFetchFor } from './chunk-YO4PSLVB.js';
21
- import { downconvertSession } from './chunk-PK5NANMT.js';
21
+ import { downconvertSession } from './chunk-YT35WGIP.js';
22
22
  import { signerFor } from './chunk-V7NIVOFD.js';
23
23
  import { rootfsPathFor, diskTemplatesDir, RUNNER_FILE_MODE, stagedContextDir, contextHomeDir, ghConfigDir, runnerDirOfBuild, spoolDir, mirrorDir, buildDir, RUNNER_DIR_MODE, vmAssetsDir } from './chunk-ZM2IMMYN.js';
24
24
  import { relative, join, dirname, basename } from 'path';
@@ -125,6 +125,7 @@ function classifyRefusal(err) {
125
125
  if (!(err instanceof WorkCommandError)) return { kind: "retry" };
126
126
  if (err.status === 401 || err.code === "claim_expired" || err.code === "claim_not_held") return { kind: "lease_lost" };
127
127
  if (err.code === "github_unavailable") return { kind: "retry" };
128
+ if (err.code === "github_request_failed") return { kind: "failed", reason: refusalCode(err) };
128
129
  if (err.retryable && err.code !== "repository_tokens_unavailable") return { kind: "retry" };
129
130
  return { kind: "failed", reason: refusalCode(err) };
130
131
  }
@@ -140,6 +141,7 @@ var BuildTokens = class {
140
141
  this.issued = [];
141
142
  this.usedKinds = /* @__PURE__ */ new Set();
142
143
  this.revoked = false;
144
+ this.controlPlaneRetry = false;
143
145
  }
144
146
  now() {
145
147
  return (this.options.now ?? (() => /* @__PURE__ */ new Date()))();
@@ -165,9 +167,10 @@ var BuildTokens = class {
165
167
  throw err;
166
168
  }
167
169
  }
168
- async issue(kind) {
170
+ /** Asks the gateway for a token with `body`, retrying a failure about the moment. */
171
+ ask(body) {
169
172
  const { config, item, fetchImpl } = this.options;
170
- const asked = await retrySend(
173
+ return retrySend(
171
174
  async () => {
172
175
  try {
173
176
  return await postJson(
@@ -175,20 +178,51 @@ var BuildTokens = class {
175
178
  `/v1/work-items/${item}/claim/tokens`,
176
179
  config.apiKey,
177
180
  config.appId,
178
- { access: kind },
181
+ body,
179
182
  fetchImpl,
180
183
  void 0,
181
184
  await signerFor(config.configPath)
182
185
  );
183
- } catch (err2) {
184
- if (err2 instanceof WorkCommandError && err2.code === "repository_tokens_unavailable") {
185
- throw new WorkCommandError(err2.message, false, err2.status, err2.code);
186
+ } catch (err) {
187
+ if (err instanceof WorkCommandError && (err.code === "repository_tokens_unavailable" || err.code === "github_request_failed")) {
188
+ throw new WorkCommandError(err.message, false, err.status, err.code);
186
189
  }
187
- throw err2;
190
+ throw err;
188
191
  }
189
192
  },
190
193
  { now: this.options.now, sleep: this.options.sleep, windowMs: ISSUE_RETRY_WINDOW_MS }
191
194
  );
195
+ }
196
+ /**
197
+ * A read-only token for the repository that governs the item's, which the
198
+ * runner uses on the host to fetch its context. It is revoked with the
199
+ * others when the attempt ends. It is not held or renewed: nothing uses it
200
+ * after the fetch. A refusal is thrown with the gateway's code. A lost
201
+ * lease is kept for `refusal()`, and a failure about the moment for
202
+ * `controlPlaneUnavailable()`, as the read token's are.
203
+ */
204
+ async controlPlane() {
205
+ const asked = await this.ask({ access: "read", target: "control_plane" });
206
+ if (!asked.ok) {
207
+ const err = new WorkCommandError(asked.message ?? asked.reason, asked.retryable, asked.status, asked.code);
208
+ const refusal = classifyRefusal(err);
209
+ if (refusal.kind === "lease_lost") this.failure = refusal;
210
+ if (refusal.kind === "retry") this.controlPlaneRetry = true;
211
+ throw err;
212
+ }
213
+ const { token, expiresAt, repository } = asked.value.data;
214
+ if (typeof token !== "string" || token === "" || typeof expiresAt !== "string" || typeof repository !== "string" || repository === "") {
215
+ throw new WorkCommandError("the gateway's token answer carried no token, expiry or repository", false, void 0, "malformed_token_response");
216
+ }
217
+ if (this.revoked) {
218
+ await this.revoke([token]);
219
+ throw new WorkCommandError("the build's tokens were already revoked", false, void 0, "tokens_revoked");
220
+ }
221
+ this.issued.push(token);
222
+ return { token, expiresAt, repository };
223
+ }
224
+ async issue(kind) {
225
+ const asked = await this.ask({ access: kind });
192
226
  let err;
193
227
  if (!asked.ok) {
194
228
  err = new WorkCommandError(asked.message ?? asked.reason, asked.retryable, asked.status, asked.code);
@@ -236,6 +270,10 @@ var BuildTokens = class {
236
270
  refusal() {
237
271
  return this.failure;
238
272
  }
273
+ /** Whether a control plane token request failed for a reason about the moment, which a later attempt may not meet. */
274
+ controlPlaneUnavailable() {
275
+ return this.controlPlaneRetry;
276
+ }
239
277
  /** Revokes every token this holder was issued, the superseded ones too, at GitHub with the token itself. A failure is not an error: the token lapses within the hour. */
240
278
  async revokeAll() {
241
279
  this.revoked = true;
@@ -1152,6 +1190,17 @@ async function resolveAgentUser(input) {
1152
1190
  if (uid === null) throw new AgentUserError(`the user "${candidate}" is not in the image, so no command can run as it`);
1153
1191
  return uid === 0 ? ADDED_USER : candidate;
1154
1192
  }
1193
+ var TokenRefused = class extends Error {
1194
+ constructor(code, detail) {
1195
+ super(code);
1196
+ this.code = code;
1197
+ this.detail = detail;
1198
+ }
1199
+ };
1200
+ var NoControlPlane = class extends Error {
1201
+ };
1202
+ var GatewayConflict = class extends Error {
1203
+ };
1155
1204
  var unavailable = (why) => ({ kind: "refused", reason: `context_unavailable: ${why}` });
1156
1205
  function makeReadable(tree, dir, files) {
1157
1206
  chmodSync(dir, 493);
@@ -1181,6 +1230,9 @@ async function stageGovernedContext(input) {
1181
1230
  if (!done.ok) return finish(unavailable(`the staging directory could not be prepared: ${done.stderr.trim().split("\n")[0] ?? ""}`));
1182
1231
  }
1183
1232
  const { url, apiKey, appId, configPath } = input.config;
1233
+ let tokenRepository;
1234
+ const credentialFor = (repository) => tokenRepository !== void 0 && tokenRepository.toLowerCase() === repository.toLowerCase() ? "the token the gateway issued" : "the host's git login";
1235
+ const unreadable = (repositories) => repositories.map((repository) => `${credentialFor(repository)} cannot read ${repository}`).join(" and ");
1184
1236
  const result = await materializeContext({
1185
1237
  cwd: tree,
1186
1238
  sessionId: `build-${input.buildId}`,
@@ -1189,12 +1241,17 @@ async function stageGovernedContext(input) {
1189
1241
  fetchImpl: signingFetchFor(input.fetchImpl, configPath, apiKey),
1190
1242
  git: git2,
1191
1243
  now: input.now,
1192
- resolveControlPlaneUrl: (repository) => input.controlPlaneUrl(repository)
1244
+ resolveControlPlaneUrl: (repository) => input.controlPlaneUrl(repository),
1245
+ controlPlaneAccess: input.controlPlaneToken === void 0 ? void 0 : async (candidates) => {
1246
+ const access = await controlPlaneAccess(input.controlPlaneToken, candidates, input.repository, input.log, input.tag);
1247
+ tokenRepository = access?.repository;
1248
+ return access;
1249
+ }
1193
1250
  });
1194
1251
  switch (result.status) {
1195
1252
  case "materialized": {
1196
1253
  if (result.unfetched !== void 0 && result.unfetched.length > 0) {
1197
- return finish(unavailable(`the host's git login cannot read ${result.unfetched.join(" or ")}, a control plane named for ${input.repository}, so it cannot be ruled out as a second claimant`));
1254
+ return finish(unavailable(`${unreadable(result.unfetched)}, a control plane named for ${input.repository}, so it cannot be ruled out as a second claimant`));
1198
1255
  }
1199
1256
  const manifest = readContextManifest(join(tree, ".git"));
1200
1257
  const source = readSourceCache(join(tree, ".git"));
@@ -1211,7 +1268,7 @@ async function stageGovernedContext(input) {
1211
1268
  }
1212
1269
  case "self":
1213
1270
  if (result.unfetched !== void 0 && result.unfetched.length > 0) {
1214
- return finish(unavailable(`the host's git login cannot read ${result.unfetched.join(" or ")}, the control plane named for ${input.repository}`));
1271
+ return finish(unavailable(`${unreadable(result.unfetched)}, the control plane named for ${input.repository}`));
1215
1272
  }
1216
1273
  if (result.designation === "answered") return finish({ kind: "none" });
1217
1274
  if (result.authRejected === true) {
@@ -1224,9 +1281,38 @@ async function stageGovernedContext(input) {
1224
1281
  return finish(unavailable(result.message ?? `the context of ${input.repository} could not be materialized (${result.status})`));
1225
1282
  }
1226
1283
  } catch (err) {
1284
+ if (err instanceof NoControlPlane) return finish({ kind: "none" });
1285
+ if (err instanceof GatewayConflict) return finish({ kind: "refused", reason: `context_conflict: ${err.message}` });
1286
+ if (err instanceof TokenRefused) {
1287
+ return finish(
1288
+ unavailable(
1289
+ err.detail === void 0 ? `the gateway refused a token for the control plane named for ${input.repository} (${err.code})` : `the token request for the control plane named for ${input.repository} failed: ${err.detail}`
1290
+ )
1291
+ );
1292
+ }
1227
1293
  return finish(unavailable(`the context of ${input.repository} could not be staged: ${err instanceof Error ? err.message : String(err)}`));
1228
1294
  }
1229
1295
  }
1296
+ async function controlPlaneAccess(ask, candidates, repository, log, tag) {
1297
+ let answer;
1298
+ try {
1299
+ answer = await ask();
1300
+ } catch (err) {
1301
+ const code = refusalCode(err);
1302
+ if (code === "repository_tokens_unavailable") return void 0;
1303
+ if (code === "no_control_plane") throw new NoControlPlane(code);
1304
+ if (code === "context_conflict") throw new GatewayConflict(err instanceof Error ? err.message : code);
1305
+ throw new TokenRefused(code, err instanceof WorkCommandError && err.code === void 0 && err.status === void 0 ? describeCallFailure(err) : void 0);
1306
+ }
1307
+ const named = candidates.some((candidate) => candidate.repository.toLowerCase() === answer.repository.toLowerCase());
1308
+ if (!named) {
1309
+ log?.line(
1310
+ `${tag === void 0 ? "" : `${tag} `}the gateway issued a control plane token for ${answer.repository}, which is none of the repositories named for ${repository} (${candidates.map((candidate) => candidate.repository).join(", ")}) \xB7 fetching with the host's git login`
1311
+ );
1312
+ return void 0;
1313
+ }
1314
+ return answer;
1315
+ }
1230
1316
  function removeStagedContext(buildDir2) {
1231
1317
  rmSync(stagedContextDir(buildDir2), { recursive: true, force: true });
1232
1318
  }
@@ -2396,14 +2482,17 @@ async function provisionContainer(input) {
2396
2482
  log,
2397
2483
  tag,
2398
2484
  aborted: input.aborted,
2399
- // The control plane is read on the host, with the host's git login. The container reads the staged files from its mount of the build's directory.
2485
+ // The control plane is read on the host, with a token the gateway issues (or the host's git login when it has no GitHub App). The container reads the staged files from its mount of the build's directory.
2400
2486
  stageContext: () => stageGovernedContext({
2401
2487
  config,
2402
2488
  repository,
2403
2489
  buildId,
2404
2490
  buildDir: buildDir2,
2405
2491
  fetchImpl: input.fetchImpl,
2406
- controlPlaneUrl: (controlPlane) => runtime.remoteFor?.(controlPlane) ?? `${runtime.github.gitUrl}/${controlPlane}.git`
2492
+ controlPlaneUrl: (controlPlane) => runtime.remoteFor?.(controlPlane) ?? `${runtime.github.gitUrl}/${controlPlane}.git`,
2493
+ controlPlaneToken: () => tokens.controlPlane(),
2494
+ log,
2495
+ tag
2407
2496
  }),
2408
2497
  removeStagedContext: () => removeStagedContext(buildDir2)
2409
2498
  });
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { EVENT_TYPES, isHumanUserTurn, parseAgentSession, SCHEMA_VERSION, SPEED_MAX_LENGTH, inputBandOf, BUCKET_MODEL_MAX_LENGTH } from './chunk-PK5NANMT.js';
3
+ import { EVENT_TYPES, isHumanUserTurn, parseAgentSession, SCHEMA_VERSION, SPEED_MAX_LENGTH, inputBandOf, BUCKET_MODEL_MAX_LENGTH } from './chunk-YT35WGIP.js';
4
4
  import { createHash } from 'crypto';
5
5
  import { readFileSync, readdirSync, statSync, mkdirSync, copyFileSync, renameSync, unlinkSync, writeFileSync, stat as stat$1, unwatchFile, watchFile, watch as watch$1 } from 'fs';
6
6
  import { type, homedir } from 'os';
@@ -21971,14 +21971,14 @@ var ModelRegistryImpl = class {
21971
21971
  };
21972
21972
  var models_default = {
21973
21973
  version: "1.0.0",
21974
- generatedAt: "2026-10-05T04:49:52.578Z",
21974
+ generatedAt: "2026-10-06T05:36:56.720Z",
21975
21975
  sources: {
21976
21976
  litellm: {
21977
- fetchedAt: "2026-10-05T04:49:52.578Z",
21978
- modelCount: 1887
21977
+ fetchedAt: "2026-10-06T05:36:56.720Z",
21978
+ modelCount: 1890
21979
21979
  },
21980
21980
  openrouter: {
21981
- fetchedAt: "2026-10-05T04:49:52.578Z",
21981
+ fetchedAt: "2026-10-06T05:36:56.720Z",
21982
21982
  modelCount: 198
21983
21983
  }
21984
21984
  },
@@ -22849,7 +22849,8 @@ var models_default = {
22849
22849
  parallelFunctionCalling: true,
22850
22850
  audioInput: true,
22851
22851
  audioOutput: true
22852
- }
22852
+ },
22853
+ deprecationDate: "2025-03-26"
22853
22854
  },
22854
22855
  "eu/gpt-4o-realtime-preview-2024-12-17": {
22855
22856
  provider: "azure",
@@ -24268,7 +24269,8 @@ var models_default = {
24268
24269
  parallelFunctionCalling: true,
24269
24270
  audioInput: true,
24270
24271
  audioOutput: true
24271
- }
24272
+ },
24273
+ deprecationDate: "2025-03-26"
24272
24274
  },
24273
24275
  "gpt-4o-realtime-preview-2024-12-17": {
24274
24276
  provider: "azure",
@@ -26309,7 +26311,8 @@ var models_default = {
26309
26311
  parallelFunctionCalling: true,
26310
26312
  audioInput: true,
26311
26313
  audioOutput: true
26312
- }
26314
+ },
26315
+ deprecationDate: "2025-03-26"
26313
26316
  },
26314
26317
  "us/gpt-4o-realtime-preview-2024-12-17": {
26315
26318
  provider: "azure",
@@ -43131,7 +43134,6 @@ var models_default = {
43131
43134
  supportedParameters: [
43132
43135
  "frequency_penalty",
43133
43136
  "max_tokens",
43134
- "presence_penalty",
43135
43137
  "temperature",
43136
43138
  "top_k",
43137
43139
  "top_p"
@@ -48576,7 +48578,8 @@ var models_default = {
48576
48578
  context: {
48577
48579
  maxInputTokens: 7e4,
48578
48580
  maxOutputTokens: 4096
48579
- }
48581
+ },
48582
+ deprecationDate: "2025-03-01"
48580
48583
  },
48581
48584
  "kimi-k2.5": {
48582
48585
  provider: "azure",
@@ -51841,6 +51844,7 @@ var models_default = {
51841
51844
  reasoning: false,
51842
51845
  pdfInput: true
51843
51846
  },
51847
+ deprecationDate: "2027-06-28",
51844
51848
  supportedParameters: [
51845
51849
  "max_tokens",
51846
51850
  "temperature",
@@ -55463,7 +55467,8 @@ var models_default = {
55463
55467
  promptCaching: true,
55464
55468
  reasoning: false,
55465
55469
  pdfInput: true
55466
- }
55470
+ },
55471
+ deprecationDate: "2027-06-28"
55467
55472
  },
55468
55473
  "grok-4.6": {
55469
55474
  provider: "azure",
@@ -65893,6 +65898,68 @@ var models_default = {
65893
65898
  reasoning: true
65894
65899
  },
65895
65900
  deprecationDate: "2026-03-29"
65901
+ },
65902
+ "global.zai.glm-5.3": {
65903
+ provider: "bedrock",
65904
+ displayName: "Global.zai.glm 5.3",
65905
+ mode: "chat",
65906
+ source: "litellm",
65907
+ pricing: {
65908
+ inputCostPerToken: 168e-8,
65909
+ outputCostPerToken: 528e-8,
65910
+ cacheCreationCostPerToken: 21e-7,
65911
+ cacheReadCostPerToken: 312e-9
65912
+ },
65913
+ context: {
65914
+ maxInputTokens: 1e6,
65915
+ maxOutputTokens: 128e3
65916
+ },
65917
+ capabilities: {
65918
+ vision: false,
65919
+ functionCalling: true,
65920
+ structuredOutput: true,
65921
+ promptCaching: true,
65922
+ reasoning: true,
65923
+ audioInput: false
65924
+ }
65925
+ },
65926
+ "us.zai.glm-5.3": {
65927
+ provider: "bedrock",
65928
+ displayName: "Us.zai.glm 5.3",
65929
+ mode: "chat",
65930
+ source: "litellm",
65931
+ pricing: {
65932
+ inputCostPerToken: 1848e-9,
65933
+ outputCostPerToken: 5808e-9,
65934
+ cacheCreationCostPerToken: 231e-8,
65935
+ cacheReadCostPerToken: 3432e-10
65936
+ },
65937
+ context: {
65938
+ maxInputTokens: 1e6,
65939
+ maxOutputTokens: 128e3
65940
+ },
65941
+ capabilities: {
65942
+ vision: false,
65943
+ functionCalling: true,
65944
+ structuredOutput: true,
65945
+ promptCaching: true,
65946
+ reasoning: true,
65947
+ audioInput: false
65948
+ }
65949
+ },
65950
+ "amazon.nova-2-5-sonic": {
65951
+ provider: "bedrock",
65952
+ displayName: "Amazon.nova 2 5 Sonic",
65953
+ mode: "chat",
65954
+ source: "litellm",
65955
+ pricing: {
65956
+ inputCostPerToken: 33e-8,
65957
+ outputCostPerToken: 275e-8
65958
+ },
65959
+ capabilities: {
65960
+ audioInput: true,
65961
+ audioOutput: true
65962
+ }
65896
65963
  }
65897
65964
  }
65898
65965
  };
@@ -68227,13 +68294,26 @@ function git(cwd, args) {
68227
68294
  return void 0;
68228
68295
  }
68229
68296
  }
68297
+ function hasLoopbackHost(url2) {
68298
+ var _a5;
68299
+ const authority = url2.replace(/^[a-z][a-z0-9+.-]*:\/\//i, "").replace(/^[^@/]+@/, "");
68300
+ const host = authority.startsWith("[") ? authority.slice(1, authority.indexOf("]")) : (_a5 = authority.split(/[:/]/, 1)[0]) != null ? _a5 : "";
68301
+ return /^(localhost|127(\.\d{1,3}){3}|::1)$/i.test(host);
68302
+ }
68303
+ function remoteGetUrl(cwd, name) {
68304
+ var _a5, _b;
68305
+ const url2 = git(cwd, ["remote", "get-url", name]);
68306
+ if (!url2 || !hasLoopbackHost(url2)) return url2;
68307
+ const configured = (_b = (_a5 = git(cwd, ["config", "--get-all", `remote.${name}.url`])) == null ? void 0 : _a5.split("\n")[0]) == null ? void 0 : _b.trim();
68308
+ return configured || url2;
68309
+ }
68230
68310
  function remoteUrl(cwd) {
68231
68311
  var _a5;
68232
- const origin = git(cwd, ["remote", "get-url", "origin"]);
68312
+ const origin = remoteGetUrl(cwd, "origin");
68233
68313
  if (origin) return origin;
68234
68314
  const names = ((_a5 = git(cwd, ["remote"])) != null ? _a5 : "").split("\n").map((n) => n.trim()).filter(Boolean);
68235
68315
  const name = names.includes("upstream") ? "upstream" : names[0];
68236
- return name === void 0 ? void 0 : git(cwd, ["remote", "get-url", name]);
68316
+ return name === void 0 ? void 0 : remoteGetUrl(cwd, name);
68237
68317
  }
68238
68318
  function remoteLookupFailed(cwd) {
68239
68319
  try {
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { sanitizeTerminal } from './chunk-BL63NBJZ.js';
4
- import { remoteLookupFailed } from './chunk-CDISNKM4.js';
3
+ import { sanitizeTerminal } from './chunk-ZEQMTBRD.js';
4
+ import { remoteLookupFailed } from './chunk-LTJPX7TX.js';
5
5
  import { DEFAULT_DASHBOARD } from './chunk-USO2DKBD.js';
6
6
  import { resolveGatewayCredentials } from './chunk-PLMTLGYH.js';
7
7
  import { readCloudConfig } from './chunk-EABW6AJQ.js';
8
8
  import { writeRepoConnection, findGitDirs, readRepoConnection } from './chunk-BJ3KTMDH.js';
9
+ import { execFileSync } from 'child_process';
9
10
  import { createInterface } from 'readline/promises';
10
11
 
11
12
  createRequire(import.meta.url);
@@ -58,6 +59,20 @@ Then run \`outerlayer connect\` again.
58
59
 
59
60
  // src/connect-cmd.ts
60
61
  var REQUEST_TIMEOUT_MS = 15e3;
62
+ var COMMIT_LINE = "Commit and push .outerlayer/ so the factory reads your policy and skills. No checks run on your pull requests until the policy is on your default branch.";
63
+ function hasUncommittedPolicy(cwd) {
64
+ try {
65
+ const status = execFileSync("git", ["status", "--porcelain", "--untracked-files=all", "--", ":/.outerlayer"], {
66
+ cwd,
67
+ encoding: "utf8",
68
+ stdio: "pipe",
69
+ timeout: REQUEST_TIMEOUT_MS
70
+ });
71
+ return status !== "";
72
+ } catch {
73
+ return false;
74
+ }
75
+ }
61
76
  var EXIT_NOT_LINKED = 2;
62
77
  var REASON_TEXT = {
63
78
  flag: "you passed --factory",
@@ -281,7 +296,10 @@ function connectDocument(r) {
281
296
  };
282
297
  }
283
298
  async function runConnectCommand(flags, deps, out) {
284
- const r = await runConnect(flags, deps);
299
+ const base = await runConnect(flags, deps);
300
+ const r = base.outcome === "done" && hasUncommittedPolicy(deps.cwd) ? { ...base, text: `${base.text}
301
+ ${COMMIT_LINE}
302
+ ` } : base;
285
303
  if (flags.json) {
286
304
  out.stdout.write(`${JSON.stringify(connectDocument(r), null, 2)}
287
305
  `);
@@ -292,4 +310,4 @@ async function runConnectCommand(flags, deps, out) {
292
310
  return r.code;
293
311
  }
294
312
 
295
- export { autoConnectedLine, fetchFactories, isLinkedRepository, promptOnTerminal, realConnectDeps, runConnect, runConnectCommand, saveFactoryConnection, selectFactory };
313
+ export { COMMIT_LINE, autoConnectedLine, fetchFactories, isLinkedRepository, promptOnTerminal, realConnectDeps, runConnect, runConnectCommand, saveFactoryConnection, selectFactory };
@@ -2,7 +2,7 @@
2
2
  import { createRequire } from 'node:module';
3
3
  import { MAX_ALLOW_HOSTS, allowHostProblem } from './chunk-UXYLWVTQ.js';
4
4
  import { parseSize } from './chunk-7RQ73DLO.js';
5
- import { isRefusedInConfig, resolveDestinations, isReservedVariable } from './chunk-2FWL7CE2.js';
5
+ import { isRefusedInConfig, resolveDestinations, isReservedVariable } from './chunk-M6G7TJVF.js';
6
6
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
7
7
  import { existsSync, statSync, accessSync, constants, readFileSync } from 'fs';
8
8
  import { hostname } from 'os';
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { authorEnvironment, withHooksPath } from './chunk-HKMPVPO7.js';
3
+ import { authorEnvironment, withHooksPath } from './chunk-BYT5O5RV.js';
4
4
  import { existsSync, unlinkSync, chmodSync } from 'fs';
5
5
  import { request as request$1, createServer } from 'http';
6
6
  import { request } from 'https';