hammerkit 1.26.0 → 1.27.0-next.10

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 (128) hide show
  1. package/build.schema.json +62 -1
  2. package/dist/cache/backends/local-cache-backend.js +10 -2
  3. package/dist/cache/backends/registry-cache-backend.js +2 -2
  4. package/dist/cache/explain.js +13 -11
  5. package/dist/cli.js +3 -0
  6. package/dist/docker/item-network.js +471 -0
  7. package/dist/docker/pull.js +4 -2
  8. package/dist/docker/remove-orphaned-containers.js +13 -6
  9. package/dist/environment/replace-env-variables.js +8 -6
  10. package/dist/executer/await-completed-dependencies.js +2 -1
  11. package/dist/executer/check-readiness.js +2 -2
  12. package/dist/executer/docker-service.js +24 -13
  13. package/dist/executer/docker-task.js +18 -29
  14. package/dist/executer/event-cache.js +24 -2
  15. package/dist/executer/execute-command.js +18 -5
  16. package/dist/executer/execute-docker.js +4 -1
  17. package/dist/executer/execution-steps.js +33 -7
  18. package/dist/executer/get-docker-executor.js +14 -7
  19. package/dist/executer/scheduler/enqueue-next.js +17 -3
  20. package/dist/executer/watch-loop.js +2 -2
  21. package/dist/executer/watch-state-key.js +1 -1
  22. package/dist/file/within-root.js +42 -0
  23. package/dist/harness/connect.js +99 -0
  24. package/dist/harness/format.js +73 -0
  25. package/dist/harness/mcp-command.js +59 -0
  26. package/dist/harness/mcp.js +432 -0
  27. package/dist/harness/opencode.js +492 -0
  28. package/dist/harness/pi.js +217 -0
  29. package/dist/harness/sandbox-client.js +411 -0
  30. package/dist/index.js +33 -36
  31. package/dist/kubernetes/apply.js +42 -1
  32. package/dist/kubernetes/await-running-state.js +33 -1
  33. package/dist/kubernetes/claim-layout.js +71 -0
  34. package/dist/kubernetes/ensure-http-route.js +1 -1
  35. package/dist/kubernetes/ensure-kubernetes-deployment-exists.js +46 -28
  36. package/dist/kubernetes/ensure-kubernetes-persistent-volume-claim-exists.js +132 -5
  37. package/dist/kubernetes/ensure-kubernetes-service-exists.js +27 -11
  38. package/dist/kubernetes/ensure-persistent-data.js +75 -24
  39. package/dist/kubernetes/get-service-ip.js +16 -2
  40. package/dist/kubernetes/job-placement.js +99 -0
  41. package/dist/kubernetes/job-secrets.js +320 -0
  42. package/dist/kubernetes/kept-claims.js +203 -0
  43. package/dist/kubernetes/kubernetes-instance.js +10 -2
  44. package/dist/kubernetes/network-gate.js +71 -0
  45. package/dist/kubernetes/network-policy.js +583 -0
  46. package/dist/kubernetes/remove-persistent-data.js +3 -1
  47. package/dist/kubernetes/resources.js +37 -4
  48. package/dist/kubernetes/restore-kubernetes-data.js +28 -7
  49. package/dist/kubernetes/secrets.js +7 -9
  50. package/dist/kubernetes/store-kubernetes-data.js +1 -1
  51. package/dist/kubernetes/volumes.js +104 -12
  52. package/dist/log.js +1 -1
  53. package/dist/main.js +41 -0
  54. package/dist/network/egress-proxy.js +407 -0
  55. package/dist/network/port-relay.js +35 -0
  56. package/dist/optimizer/get-work-cache-stats.js +16 -0
  57. package/dist/optimizer/work-task-cache-description.js +5 -2
  58. package/dist/planner/service-definition.js +5 -0
  59. package/dist/planner/utils/append-work-dependencies.js +5 -2
  60. package/dist/planner/utils/append-work-environment.js +2 -0
  61. package/dist/planner/utils/append-work-service.js +5 -0
  62. package/dist/planner/utils/append-work-task.js +20 -1
  63. package/dist/planner/utils/assert-item-paths.js +50 -0
  64. package/dist/planner/utils/hosted-volumes.js +35 -0
  65. package/dist/planner/utils/task-arguments.js +3 -0
  66. package/dist/planner/work-network.js +193 -0
  67. package/dist/planner/work-runtime-docker.js +43 -1
  68. package/dist/planner/work-runtime-kubernetes.js +370 -111
  69. package/dist/planner/work-runtime-local.js +2 -1
  70. package/dist/program.js +33 -5
  71. package/dist/remote/annotations.js +115 -0
  72. package/dist/remote/bundle-text.js +24 -0
  73. package/dist/remote/bundle.js +9 -1
  74. package/dist/remote/remote-commands.js +15 -3
  75. package/dist/remote/remote-work-commands.js +272 -71
  76. package/dist/remote/server-client.js +18 -5
  77. package/dist/remote/source-manifest.js +15 -2
  78. package/dist/remote/token-source.js +67 -0
  79. package/dist/schema/build-file-base-task-schema.js +7 -0
  80. package/dist/schema/build-file-container-service-schema.js +8 -0
  81. package/dist/schema/build-file-container-task-schema.js +3 -0
  82. package/dist/schema/build-file-environment-schema.js +9 -0
  83. package/dist/schema/network-schema.js +78 -0
  84. package/dist/schema/reference-parser.js +2 -0
  85. package/dist/schema/schema-parser.js +16 -3
  86. package/dist/schema/work-scope-parser.js +5 -0
  87. package/dist/secrets/command-secret-provider.js +73 -10
  88. package/dist/secrets/github-app-token-command.js +26 -0
  89. package/dist/secrets/github-app-token.js +191 -0
  90. package/dist/server/accounts-api.js +9 -2
  91. package/dist/server/definitions-api.js +69 -47
  92. package/dist/server/definitions.js +76 -51
  93. package/dist/server/executor.js +156 -41
  94. package/dist/server/git-checkout.js +72 -8
  95. package/dist/server/kubernetes-backend.js +603 -0
  96. package/dist/server/kubernetes-sandbox-storage.js +997 -0
  97. package/dist/server/oauth.js +12 -0
  98. package/dist/server/plan.js +88 -2
  99. package/dist/server/policy.js +104 -15
  100. package/dist/server/proposals-api.js +24 -40
  101. package/dist/server/proposals.js +12 -25
  102. package/dist/server/repo-access.js +37 -6
  103. package/dist/server/run-logs.js +217 -0
  104. package/dist/server/run-plan.js +48 -2
  105. package/dist/server/run-request.js +29 -10
  106. package/dist/server/run-store.js +5 -0
  107. package/dist/server/run-worker-command.js +13 -1
  108. package/dist/server/run-worker.js +121 -24
  109. package/dist/server/runs.js +191 -10
  110. package/dist/server/sandbox-docker.js +62 -0
  111. package/dist/server/sandbox-files-api.js +269 -0
  112. package/dist/server/sandbox-files.js +1054 -0
  113. package/dist/server/sandbox-patch.js +481 -0
  114. package/dist/server/sandbox-pod-command.js +15 -0
  115. package/dist/server/sandbox-pod.js +146 -0
  116. package/dist/server/sandbox-storage.js +462 -0
  117. package/dist/server/sandboxes-api.js +216 -0
  118. package/dist/server/sandboxes.js +519 -0
  119. package/dist/server/server-command.js +39 -20
  120. package/dist/server/server-config.js +443 -22
  121. package/dist/server/server.js +219 -40
  122. package/dist/utils/abort-on-signals.js +46 -6
  123. package/dist/utils/run-id.js +12 -0
  124. package/dist/utils/tar.js +25 -0
  125. package/harness/opencode.ts +11 -0
  126. package/harness/pi.ts +7 -0
  127. package/package.json +8 -2
  128. package/dist/remote/text-diff.js +0 -89
package/dist/program.js CHANGED
@@ -28,6 +28,8 @@ const cache_inventory_1 = require("./cache/cache-inventory");
28
28
  const remote_commands_1 = require("./remote/remote-commands");
29
29
  const server_command_1 = require("./server/server-command");
30
30
  const run_worker_command_1 = require("./server/run-worker-command");
31
+ const github_app_token_command_1 = require("./secrets/github-app-token-command");
32
+ const work_network_1 = require("./planner/work-network");
31
33
  const task_arguments_1 = require("./planner/utils/task-arguments");
32
34
  async function createCli(fileName, environment, workScope) {
33
35
  const { ctx, scope } = await (0, schema_parser_1.createParseContext)(fileName, environment);
@@ -82,7 +84,8 @@ function printTaskDefinition(environment, definition) {
82
84
  }
83
85
  }
84
86
  // `ls --json`: what a caller (an agent picking a task) needs to know, with the
85
- // command that arguments after `--` are appended to (null: it takes none).
87
+ // command that arguments after `--` are appended to (null: it takes none) and
88
+ // `args` as the build file says it (false: it refuses them).
86
89
  function getListJson(tasks, services) {
87
90
  return {
88
91
  tasks: tasks.map(({ item }) => ({
@@ -94,6 +97,7 @@ function getListJson(tasks, services) {
94
97
  needs: item.needs.map((n) => n.name),
95
98
  labels: item.data.labels,
96
99
  command: (0, task_arguments_1.getArgumentsTarget)(item.data)?.cmd ?? null,
100
+ args: item.data.args,
97
101
  })),
98
102
  services: services.map(({ item }) => ({
99
103
  name: item.name,
@@ -103,6 +107,7 @@ function getListJson(tasks, services) {
103
107
  ports: item.data.ports.map((p) => ({ host: p.hostPort, container: p.containerPort })),
104
108
  labels: item.data.labels,
105
109
  command: (0, task_arguments_1.getArgumentsTarget)(item.data)?.cmd ?? null,
110
+ args: item.data.type === 'container-service' ? item.data.args : null,
106
111
  })),
107
112
  };
108
113
  }
@@ -138,6 +143,8 @@ async function getProgram(environment, argv) {
138
143
  const program = new commander_1.Command();
139
144
  (0, server_command_1.registerServerCommand)(program, environment);
140
145
  (0, run_worker_command_1.registerRunWorkerCommand)(program, environment);
146
+ (0, run_worker_command_1.registerSandboxPodCommand)(program, environment);
147
+ (0, github_app_token_command_1.registerGithubAppTokenCommand)(program, environment);
141
148
  // What follows `--` belongs to the one task or service of a run or up, not to
142
149
  // hammerkit: a `--set` or `--file` there is an argument like any other.
143
150
  const separator = argv.indexOf('--');
@@ -145,16 +152,24 @@ async function getProgram(environment, argv) {
145
152
  const parsed = (0, parse_set_arguments_1.parseSetArguments)(separator >= 0 ? argv.slice(0, separator) : argv);
146
153
  const args = parsed.args;
147
154
  environment.processEnvs = { ...environment.processEnvs, ...parsed.values };
155
+ const remote = args.indexOf('remote');
156
+ if (remote >= 0 && args[remote + 1] === 'mcp') {
157
+ // `remote mcp` speaks its protocol on stdout: a warning there would break it
158
+ environment.console = (0, log_1.consoleContext)(environment.stderr);
159
+ }
148
160
  const fileIndex = args.indexOf('--file');
149
161
  const fileName = fileIndex >= 0 ? (0, path_1.join)(environment.cwd, args[fileIndex + 1]) : await (0, default_build_file_1.getBuildFilename)(environment.cwd, environment);
150
162
  if (fileIndex >= 0) {
151
163
  args.splice(fileIndex, 2);
152
164
  }
153
- (0, remote_commands_1.registerRemoteCommands)(program, environment, fileName);
165
+ (0, remote_commands_1.registerRemoteCommands)(program, environment, fileName, passthrough);
154
166
  program.hook('preAction', (_, actionCommand) => {
155
- const takesArguments = actionCommand.parent === program && ['run', 'up'].includes(actionCommand.name());
167
+ const takesArguments = (actionCommand.parent === program && ['run', 'up'].includes(actionCommand.name())) ||
168
+ (actionCommand.parent?.name() === 'remote' && actionCommand.name() === 'run');
156
169
  if (passthrough.length > 0 && !takesArguments) {
157
- program.error(`${actionCommand.name()} takes no arguments after --, only run and up do`, { exitCode: 1 });
170
+ program.error(`${actionCommand.name()} takes no arguments after --, only run, up and remote run do`, {
171
+ exitCode: 1,
172
+ });
158
173
  }
159
174
  });
160
175
  if (await environment.file.exists(fileName)) {
@@ -593,6 +608,7 @@ async function getProgram(environment, argv) {
593
608
  .choices(['checksum', 'modify-date', 'none']))
594
609
  .addOption(new commander_1.Option('--cache-read-only', `restore from cache backends but never push to them (or set ${read_only_1.CACHE_READ_ONLY_ENV}=1)`).default(false))
595
610
  .addOption(new commander_1.Option('--timeout <duration>', 'fail tasks without their own timeout after this long (e.g. 10m)').argParser(units_1.parseDuration))
611
+ .addOption(new commander_1.Option('--network <level>', 'the most any task or service reaches besides its needs: none, open or allow:<host>,<host>').argParser(parseNetworkArgument))
596
612
  .action(async (options, command) => {
597
613
  try {
598
614
  const scope = {
@@ -610,6 +626,7 @@ async function getProgram(environment, argv) {
610
626
  wait: options.wait,
611
627
  cacheReadOnly: (0, read_only_1.isCacheReadOnly)(options.cacheReadOnly, environment.processEnvs),
612
628
  timeout: options.timeout ?? null,
629
+ network: options.network ?? null,
613
630
  });
614
631
  if (!result.success) {
615
632
  program.error('Up was not successful', { exitCode: 1 });
@@ -671,6 +688,7 @@ async function getProgram(environment, argv) {
671
688
  .addOption(new commander_1.Option('--dry-run', 'print the execution plan with predicted cache hits/misses without running').default(false))
672
689
  .addOption(new commander_1.Option('--cache-read-only', `restore from cache backends but never push to them (or set ${read_only_1.CACHE_READ_ONLY_ENV}=1)`).default(false))
673
690
  .addOption(new commander_1.Option('--timeout <duration>', 'fail tasks without their own timeout after this long (e.g. 10m)').argParser(units_1.parseDuration))
691
+ .addOption(new commander_1.Option('--network <level>', 'the most any task or service reaches besides its needs: none, open or allow:<host>,<host>').argParser(parseNetworkArgument))
674
692
  .addOption(new commander_1.Option('--no-skip-deps', 'run dependencies even when nothing needing them has to run'))
675
693
  .action(async (task, options, command) => {
676
694
  try {
@@ -704,6 +722,7 @@ async function getProgram(environment, argv) {
704
722
  explain: options.explain,
705
723
  cacheReadOnly: (0, read_only_1.isCacheReadOnly)(options.cacheReadOnly, environment.processEnvs),
706
724
  timeout: options.timeout ?? null,
725
+ network: options.network ?? null,
707
726
  skipDeps: options.skipDeps !== false,
708
727
  });
709
728
  // Reporting only: the summary never changes the exit code or behavior.
@@ -767,7 +786,8 @@ tasks:
767
786
  program.option('--file', 'set build file', '.hammerkit.yaml');
768
787
  program.option('--set <NAME=value>', 'value for $NAME / ${NAME} references, ahead of the shell and .env (repeatable)');
769
788
  program.configureOutput({
770
- writeOut: (str) => environment.console.info(str),
789
+ // --version and --help as they are, so `VERSION=$(hammerkit --version)` works
790
+ writeOut: (str) => environment.stdout.write(str),
771
791
  writeErr: (str) => {
772
792
  environment.console.error(str);
773
793
  },
@@ -775,4 +795,12 @@ tasks:
775
795
  return { program, args };
776
796
  }
777
797
  exports.getProgram = getProgram;
798
+ function parseNetworkArgument(value) {
799
+ try {
800
+ return (0, work_network_1.parseNetworkOption)(value);
801
+ }
802
+ catch (e) {
803
+ throw new commander_1.InvalidArgumentError((0, log_1.getErrorMessage)(e));
804
+ }
805
+ }
778
806
  //# sourceMappingURL=program.js.map
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.applyAnnotations = exports.collectAnnotations = exports.readCheckout = exports.remoteRepo = void 0;
4
+ const child_process_1 = require("child_process");
5
+ const os_1 = require("os");
6
+ const path_1 = require("path");
7
+ const util_1 = require("util");
8
+ const repo_1 = require("../server/repo");
9
+ const bundle_1 = require("./bundle");
10
+ const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
11
+ async function git(cwd, ...args) {
12
+ try {
13
+ const value = (await execFileAsync('git', args, { cwd, timeout: 5000 })).stdout.trim();
14
+ return value || undefined;
15
+ }
16
+ catch {
17
+ return undefined;
18
+ }
19
+ }
20
+ // `host/path` of a remote, or nothing: a url that is neither https, ssh nor
21
+ // `user@host:path` is left out, so a credential in it never leaves the machine.
22
+ function remoteRepo(url) {
23
+ const scp = /^[\w.-]+@([\w.-]+):(?!\/)(.+)$/.exec(url);
24
+ if (scp) {
25
+ return (0, repo_1.normalizeRepo)(`${scp[1]}/${scp[2]}`) ?? undefined;
26
+ }
27
+ try {
28
+ const parsed = new URL(url);
29
+ if (!['https:', 'ssh:'].includes(parsed.protocol)) {
30
+ return undefined;
31
+ }
32
+ return (0, repo_1.normalizeRepo)(`${parsed.hostname}${parsed.pathname}`) ?? undefined;
33
+ }
34
+ catch {
35
+ return undefined;
36
+ }
37
+ }
38
+ exports.remoteRepo = remoteRepo;
39
+ // The checkout a directory is in: the repository of its `origin`, the branch it is on and
40
+ // its commit, what can be found of them.
41
+ async function readCheckout(cwd) {
42
+ if ((await git(cwd, 'rev-parse', '--is-inside-work-tree')) !== 'true') {
43
+ return {};
44
+ }
45
+ const remote = await git(cwd, 'remote', 'get-url', 'origin');
46
+ // a detached HEAD is on no branch
47
+ const branch = await git(cwd, 'symbolic-ref', '--quiet', '--short', 'HEAD');
48
+ return { repo: remote ? remoteRepo(remote) : undefined, branch, commit: await git(cwd, 'rev-parse', 'HEAD') };
49
+ }
50
+ exports.readCheckout = readCheckout;
51
+ // Where a build file is published from: its path in its repository (or on this
52
+ // machine, outside of one), the repository and commit, this machine and its user.
53
+ // `files` are the paths of the bundle, relative to the build file's directory: when
54
+ // one of them differs from the commit, `dirty=true` says the version is not that
55
+ // commit's. What can not be found is left out.
56
+ async function collectAnnotations(fileName, files = [(0, path_1.basename)(fileName)]) {
57
+ const path = (0, path_1.resolve)(fileName);
58
+ const cwd = (0, path_1.dirname)(path);
59
+ const annotations = {};
60
+ // git says where the directory is in the repository: comparing paths would trip on
61
+ // what the file system calls the same directory differently (symlinks, 8.3 names)
62
+ const inside = (await git(cwd, 'rev-parse', '--is-inside-work-tree')) === 'true';
63
+ const prefix = inside ? (await git(cwd, 'rev-parse', '--show-prefix')) ?? '' : undefined;
64
+ annotations.path = prefix !== undefined ? `${prefix}${(0, path_1.basename)(path)}` : path;
65
+ if (inside) {
66
+ const remote = await git(cwd, 'remote', 'get-url', 'origin');
67
+ const repo = remote ? remoteRepo(remote) : undefined;
68
+ const commit = await git(cwd, 'rev-parse', 'HEAD');
69
+ if (repo) {
70
+ annotations.repo = repo;
71
+ }
72
+ if (commit) {
73
+ annotations.commit = commit;
74
+ const changed = await git(cwd, '--literal-pathspecs', 'status', '--porcelain', '--untracked-files=all', '--', ...files);
75
+ if (changed) {
76
+ annotations.dirty = 'true';
77
+ }
78
+ }
79
+ }
80
+ annotations.machine = (0, os_1.hostname)();
81
+ try {
82
+ annotations.user = (0, os_1.userInfo)().username;
83
+ }
84
+ catch {
85
+ // a user without an entry in the password database
86
+ }
87
+ return Object.fromEntries(Object.entries(annotations).filter(([, value]) => value));
88
+ }
89
+ exports.collectAnnotations = collectAnnotations;
90
+ // `--annotation key=value` sets one, `key=` leaves it out.
91
+ function applyAnnotations(annotations, options) {
92
+ const result = { ...annotations };
93
+ for (const option of options) {
94
+ const index = option.indexOf('=');
95
+ if (index <= 0) {
96
+ throw new Error(`${option} is not an annotation, write it as key=value`);
97
+ }
98
+ const key = option.slice(0, index);
99
+ const value = option.slice(index + 1);
100
+ if (value) {
101
+ result[key] = value;
102
+ }
103
+ else {
104
+ delete result[key];
105
+ }
106
+ }
107
+ const parsed = bundle_1.annotationsSchema.safeParse(result);
108
+ if (!parsed.success) {
109
+ const issue = parsed.error.issues[0];
110
+ throw new Error(`${issue.path.length > 0 ? `annotation ${issue.path.join('.')}` : 'annotations'}: ${issue.message}`);
111
+ }
112
+ return parsed.data;
113
+ }
114
+ exports.applyAnnotations = applyAnnotations;
115
+ //# sourceMappingURL=annotations.js.map
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.showBundle = exports.visible = void 0;
4
+ // Text from a proposal is shown to somebody who decides on it, so nothing in it may
5
+ // rewrite the terminal or hide what it says: control and format characters (which
6
+ // include the ones that reorder text) are shown as `?`. Long lines are not cut,
7
+ // what is hidden behind a cut is what a reviewer needs to see.
8
+ function visible(line) {
9
+ return line.replace(/\t/g, ' ').replace(/[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/gu, '?');
10
+ }
11
+ exports.visible = visible;
12
+ const lines = (text) => (text === '' ? [] : text.replace(/\n$/, '').split('\n'));
13
+ // Every file of a version, whole: a version has no other one it could be read
14
+ // against, whoever decides on it reads all of it.
15
+ function showBundle(bundle) {
16
+ return Object.keys(bundle.files)
17
+ .sort()
18
+ .flatMap((path) => [
19
+ `--- ${visible(path)}${path === bundle.entry ? ' (entry)' : ''}`,
20
+ ...lines(bundle.files[path]).map((line) => ` ${visible(line)}`),
21
+ ]);
22
+ }
23
+ exports.showBundle = showBundle;
24
+ //# sourceMappingURL=bundle-text.js.map
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HASH_PATTERN = exports.hashBundle = exports.bundleSchema = exports.isBundlePath = exports.MAX_BUNDLE_BYTES = exports.MAX_BUNDLE_FILES = exports.DEFAULT_ENTRY = void 0;
3
+ exports.HASH_PATTERN = exports.hashBundle = exports.bundleSchema = exports.annotationsSchema = exports.MAX_ANNOTATIONS = exports.isBundlePath = exports.MAX_BUNDLE_BYTES = exports.MAX_BUNDLE_FILES = exports.DEFAULT_ENTRY = void 0;
4
4
  const crypto_1 = require("crypto");
5
5
  const zod_1 = require("zod");
6
6
  exports.DEFAULT_ENTRY = '.hammerkit.yaml';
@@ -16,6 +16,14 @@ function isBundlePath(path) {
16
16
  !path.split('/').some((part) => part === '' || part === '.' || part === '..'));
17
17
  }
18
18
  exports.isBundlePath = isBundlePath;
19
+ exports.MAX_ANNOTATIONS = 20;
20
+ exports.annotationsSchema = zod_1.z
21
+ .record(zod_1.z
22
+ .string()
23
+ .regex(/^[a-z][a-z0-9._-]{0,63}$/, 'use lower case letters, digits, ".", "_" and "-", starting with a letter'), zod_1.z.string().min(1).max(500))
24
+ .refine((annotations) => Object.keys(annotations).length <= exports.MAX_ANNOTATIONS, {
25
+ message: `at most ${exports.MAX_ANNOTATIONS} annotations`,
26
+ });
19
27
  exports.bundleSchema = zod_1.z
20
28
  .object({
21
29
  entry: zod_1.z.string().default(exports.DEFAULT_ENTRY),
@@ -10,11 +10,15 @@ const log_1 = require("../log");
10
10
  const host_config_1 = require("./host-config");
11
11
  const device_login_1 = require("./device-login");
12
12
  const credentials_1 = require("./credentials");
13
+ const token_source_1 = require("./token-source");
13
14
  const server_client_1 = require("./server-client");
14
15
  const remote_work_commands_1 = require("./remote-work-commands");
16
+ const mcp_command_1 = require("../harness/mcp-command");
15
17
  // Host-level commands: they only touch the machine's config file, so they work
16
18
  // with or without a build file in the working directory.
17
- function registerRemoteCommands(program, environment, buildFile) {
19
+ function registerRemoteCommands(program, environment, buildFile,
20
+ // what follows `--`, the arguments of `remote run`
21
+ passthrough = []) {
18
22
  const remote = program.command('remote').description('register the servers runs can be sent to');
19
23
  const guarded = (failure, fn) => {
20
24
  return async (...args) => {
@@ -129,7 +133,7 @@ function registerRemoteCommands(program, environment, buildFile) {
129
133
  .description('show who you are on a server and which service accounts you may use')
130
134
  .action(guarded('Remote accounts was not successful', async (name) => {
131
135
  const chosen = await getServer(name);
132
- const token = await (0, credentials_1.getAccessToken)(environment, chosen.name, chosen.server);
136
+ const token = await (0, token_source_1.getTokenSource)(environment, chosen.name, chosen.server).token();
133
137
  const me = await (0, server_client_1.getMe)(chosen.server, token);
134
138
  const { body } = await (0, server_client_1.callServer)(chosen.server, token, 'GET', '/v1/accounts');
135
139
  environment.stdout.write(`${chosen.name}: ${(0, server_client_1.printable)(me.sub)} (${(0, server_client_1.printable)(me.iss)})\n`);
@@ -152,7 +156,15 @@ function registerRemoteCommands(program, environment, buildFile) {
152
156
  environment.stdout.write(`repositories: ${me.repos.map(server_client_1.printable).join(', ')}\n`);
153
157
  }
154
158
  }));
155
- (0, remote_work_commands_1.registerWorkCommands)(remote, { environment, buildFile, getServer, guarded });
159
+ (0, remote_work_commands_1.registerWorkCommands)(remote, {
160
+ environment,
161
+ buildFile,
162
+ getServer,
163
+ guarded,
164
+ passthrough,
165
+ fail: (message, exitCode) => program.error(message, { exitCode }),
166
+ });
167
+ (0, mcp_command_1.registerMcpCommand)(remote, environment);
156
168
  }
157
169
  exports.registerRemoteCommands = registerRemoteCommands;
158
170
  //# sourceMappingURL=remote-commands.js.map