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.
- package/build.schema.json +62 -1
- package/dist/cache/backends/local-cache-backend.js +10 -2
- package/dist/cache/backends/registry-cache-backend.js +2 -2
- package/dist/cache/explain.js +13 -11
- package/dist/cli.js +3 -0
- package/dist/docker/item-network.js +471 -0
- package/dist/docker/pull.js +4 -2
- package/dist/docker/remove-orphaned-containers.js +13 -6
- package/dist/environment/replace-env-variables.js +8 -6
- package/dist/executer/await-completed-dependencies.js +2 -1
- package/dist/executer/check-readiness.js +2 -2
- package/dist/executer/docker-service.js +24 -13
- package/dist/executer/docker-task.js +18 -29
- package/dist/executer/event-cache.js +24 -2
- package/dist/executer/execute-command.js +18 -5
- package/dist/executer/execute-docker.js +4 -1
- package/dist/executer/execution-steps.js +33 -7
- package/dist/executer/get-docker-executor.js +14 -7
- package/dist/executer/scheduler/enqueue-next.js +17 -3
- package/dist/executer/watch-loop.js +2 -2
- package/dist/executer/watch-state-key.js +1 -1
- package/dist/file/within-root.js +42 -0
- package/dist/harness/connect.js +99 -0
- package/dist/harness/format.js +73 -0
- package/dist/harness/mcp-command.js +59 -0
- package/dist/harness/mcp.js +432 -0
- package/dist/harness/opencode.js +492 -0
- package/dist/harness/pi.js +217 -0
- package/dist/harness/sandbox-client.js +411 -0
- package/dist/index.js +33 -36
- package/dist/kubernetes/apply.js +42 -1
- package/dist/kubernetes/await-running-state.js +33 -1
- package/dist/kubernetes/claim-layout.js +71 -0
- package/dist/kubernetes/ensure-http-route.js +1 -1
- package/dist/kubernetes/ensure-kubernetes-deployment-exists.js +46 -28
- package/dist/kubernetes/ensure-kubernetes-persistent-volume-claim-exists.js +132 -5
- package/dist/kubernetes/ensure-kubernetes-service-exists.js +27 -11
- package/dist/kubernetes/ensure-persistent-data.js +75 -24
- package/dist/kubernetes/get-service-ip.js +16 -2
- package/dist/kubernetes/job-placement.js +99 -0
- package/dist/kubernetes/job-secrets.js +320 -0
- package/dist/kubernetes/kept-claims.js +203 -0
- package/dist/kubernetes/kubernetes-instance.js +10 -2
- package/dist/kubernetes/network-gate.js +71 -0
- package/dist/kubernetes/network-policy.js +583 -0
- package/dist/kubernetes/remove-persistent-data.js +3 -1
- package/dist/kubernetes/resources.js +37 -4
- package/dist/kubernetes/restore-kubernetes-data.js +28 -7
- package/dist/kubernetes/secrets.js +7 -9
- package/dist/kubernetes/store-kubernetes-data.js +1 -1
- package/dist/kubernetes/volumes.js +104 -12
- package/dist/log.js +1 -1
- package/dist/main.js +41 -0
- package/dist/network/egress-proxy.js +407 -0
- package/dist/network/port-relay.js +35 -0
- package/dist/optimizer/get-work-cache-stats.js +16 -0
- package/dist/optimizer/work-task-cache-description.js +5 -2
- package/dist/planner/service-definition.js +5 -0
- package/dist/planner/utils/append-work-dependencies.js +5 -2
- package/dist/planner/utils/append-work-environment.js +2 -0
- package/dist/planner/utils/append-work-service.js +5 -0
- package/dist/planner/utils/append-work-task.js +20 -1
- package/dist/planner/utils/assert-item-paths.js +50 -0
- package/dist/planner/utils/hosted-volumes.js +35 -0
- package/dist/planner/utils/task-arguments.js +3 -0
- package/dist/planner/work-network.js +193 -0
- package/dist/planner/work-runtime-docker.js +43 -1
- package/dist/planner/work-runtime-kubernetes.js +370 -111
- package/dist/planner/work-runtime-local.js +2 -1
- package/dist/program.js +33 -5
- package/dist/remote/annotations.js +115 -0
- package/dist/remote/bundle-text.js +24 -0
- package/dist/remote/bundle.js +9 -1
- package/dist/remote/remote-commands.js +15 -3
- package/dist/remote/remote-work-commands.js +272 -71
- package/dist/remote/server-client.js +18 -5
- package/dist/remote/source-manifest.js +15 -2
- package/dist/remote/token-source.js +67 -0
- package/dist/schema/build-file-base-task-schema.js +7 -0
- package/dist/schema/build-file-container-service-schema.js +8 -0
- package/dist/schema/build-file-container-task-schema.js +3 -0
- package/dist/schema/build-file-environment-schema.js +9 -0
- package/dist/schema/network-schema.js +78 -0
- package/dist/schema/reference-parser.js +2 -0
- package/dist/schema/schema-parser.js +16 -3
- package/dist/schema/work-scope-parser.js +5 -0
- package/dist/secrets/command-secret-provider.js +73 -10
- package/dist/secrets/github-app-token-command.js +26 -0
- package/dist/secrets/github-app-token.js +191 -0
- package/dist/server/accounts-api.js +9 -2
- package/dist/server/definitions-api.js +69 -47
- package/dist/server/definitions.js +76 -51
- package/dist/server/executor.js +156 -41
- package/dist/server/git-checkout.js +72 -8
- package/dist/server/kubernetes-backend.js +603 -0
- package/dist/server/kubernetes-sandbox-storage.js +997 -0
- package/dist/server/oauth.js +12 -0
- package/dist/server/plan.js +88 -2
- package/dist/server/policy.js +104 -15
- package/dist/server/proposals-api.js +24 -40
- package/dist/server/proposals.js +12 -25
- package/dist/server/repo-access.js +37 -6
- package/dist/server/run-logs.js +217 -0
- package/dist/server/run-plan.js +48 -2
- package/dist/server/run-request.js +29 -10
- package/dist/server/run-store.js +5 -0
- package/dist/server/run-worker-command.js +13 -1
- package/dist/server/run-worker.js +121 -24
- package/dist/server/runs.js +191 -10
- package/dist/server/sandbox-docker.js +62 -0
- package/dist/server/sandbox-files-api.js +269 -0
- package/dist/server/sandbox-files.js +1054 -0
- package/dist/server/sandbox-patch.js +481 -0
- package/dist/server/sandbox-pod-command.js +15 -0
- package/dist/server/sandbox-pod.js +146 -0
- package/dist/server/sandbox-storage.js +462 -0
- package/dist/server/sandboxes-api.js +216 -0
- package/dist/server/sandboxes.js +519 -0
- package/dist/server/server-command.js +39 -20
- package/dist/server/server-config.js +443 -22
- package/dist/server/server.js +219 -40
- package/dist/utils/abort-on-signals.js +46 -6
- package/dist/utils/run-id.js +12 -0
- package/dist/utils/tar.js +25 -0
- package/harness/opencode.ts +11 -0
- package/harness/pi.ts +7 -0
- package/package.json +8 -2
- 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
|
|
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
|
-
|
|
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
|
package/dist/remote/bundle.js
CHANGED
|
@@ -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,
|
|
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, {
|
|
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
|