delegation-layer 0.1.16 → 0.1.18
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/README.md +47 -4
- package/install.sh +37 -6
- package/package.json +2 -1
- package/plugins/delegation-layer/.claude-plugin/plugin.json +22 -0
- package/plugins/delegation-layer/.codex-plugin/plugin.json +33 -0
- package/plugins/delegation-layer/hooks/hooks.json +14 -0
- package/plugins/delegation-layer/scripts/ensure-delegate.sh +123 -0
- package/plugins/delegation-layer/scripts/install-cli.sh +108 -0
- package/plugins/delegation-layer/skills/agent-integration/SKILL.md +251 -0
- package/plugins/delegation-layer/skills/agent-integration/evals/evals.json +61 -0
- package/plugins/delegation-layer/skills/agent-integration/evals/routing.json +155 -0
- package/plugins/delegation-layer/skills/agent-integration/examples/json-results.md +14 -0
- package/plugins/delegation-layer/skills/agent-integration/examples/read-only-task.md +12 -0
- package/plugins/delegation-layer/skills/agent-integration/examples/workspace-write-task.md +14 -0
- package/plugins/delegation-layer/skills/agent-integration/references/command-reference.md +80 -0
- package/plugins/delegation-layer/skills/agent-integration/references/continuation.md +49 -0
- package/plugins/delegation-layer/skills/agent-integration/references/result-handling.md +44 -0
- package/skills/agent-integration/SKILL.md +80 -124
- package/skills/agent-integration/evals/routing.json +155 -0
- package/skills/agent-integration/references/command-reference.md +31 -1
- package/skills/agent-integration/references/continuation.md +4 -1
- package/skills/agent-integration/references/result-handling.md +14 -7
package/README.md
CHANGED
|
@@ -31,14 +31,56 @@ already use instead of replacing them.
|
|
|
31
31
|
|
|
32
32
|
## How it works
|
|
33
33
|
|
|
34
|
-
1. Install the
|
|
34
|
+
1. Install the plugin so the skill and self-contained CLI are available together.
|
|
35
35
|
2. The lead agent discovers the available provider capabilities.
|
|
36
36
|
3. Delegation Layer admits one bounded provider turn through the supervisor.
|
|
37
37
|
4. The lead agent collects the sealed result and evidence.
|
|
38
38
|
|
|
39
|
+
## Ask naturally
|
|
40
|
+
|
|
41
|
+
Try “Ask Codex to review this change”, “Get Antigravity’s opinion”, or
|
|
42
|
+
“Have Claude investigate this failure”. The skill routes external collaboration
|
|
43
|
+
through `delegate`, preserves a named destination, and collects task evidence.
|
|
44
|
+
Ordinary native subagents remain available for work inside the current harness,
|
|
45
|
+
even when you name that harness. Ask for a separate session when you want
|
|
46
|
+
Delegate to launch another instance of the same CLI.
|
|
47
|
+
|
|
48
|
+
Skill installation makes this workflow discoverable; it does not force a model
|
|
49
|
+
to choose it over another plugin. Selection depends on the harness, model, and
|
|
50
|
+
loaded instructions. No user rules, settings, or competing plugins are rewritten.
|
|
51
|
+
If an agent bypasses Delegate, that is a selection failure, not proof the
|
|
52
|
+
integration worked.
|
|
53
|
+
|
|
39
54
|
## Install
|
|
40
55
|
|
|
41
|
-
###
|
|
56
|
+
### Recommended for Codex and Claude Code
|
|
57
|
+
|
|
58
|
+
Install the plugin from this repository. It installs the provider-neutral skill
|
|
59
|
+
and runs a trusted session-start bootstrap that reuses the checksum-verified
|
|
60
|
+
Delegation Layer release installer when `delegate` is missing. The bootstrap
|
|
61
|
+
installs the CLI and its bundled supervisor; it does not install provider CLIs,
|
|
62
|
+
change provider authentication, or change provider configuration.
|
|
63
|
+
|
|
64
|
+
For Codex:
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
codex plugin marketplace add hishamkaram/delegation-layer
|
|
68
|
+
codex plugin add delegation-layer@delegation-layer
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
For Claude Code:
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
claude plugin marketplace add hishamkaram/delegation-layer
|
|
75
|
+
claude plugin install delegation-layer@delegation-layer
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Start a new harness session after installation. Plugin hooks require the
|
|
79
|
+
harness trust review before they run. If the bootstrap reports that the
|
|
80
|
+
install directory is not on `PATH`, add the reported directory to `PATH` and
|
|
81
|
+
start a new session; the skill never falls back to a provider-native CLI.
|
|
82
|
+
|
|
83
|
+
### Install the Agent Skill only
|
|
42
84
|
|
|
43
85
|
The standard Agent Skills installer works across popular coding agents. From
|
|
44
86
|
the project where you want the skill available, run:
|
|
@@ -68,8 +110,9 @@ npx --yes delegation-layer install \
|
|
|
68
110
|
--yes
|
|
69
111
|
```
|
|
70
112
|
|
|
71
|
-
|
|
72
|
-
|
|
113
|
+
This path installs guidance only. It does not install the CLI, change provider
|
|
114
|
+
logins, or run a task. Use the plugin path above when you want the skill and
|
|
115
|
+
CLI bootstrap together.
|
|
73
116
|
|
|
74
117
|
### Install the CLI
|
|
75
118
|
|
package/install.sh
CHANGED
|
@@ -10,13 +10,18 @@ fail() {
|
|
|
10
10
|
exit 1
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
for command_name in awk curl grep install mktemp tar uname; do
|
|
13
|
+
for command_name in awk curl grep install mkdir mktemp mv rm tar uname; do
|
|
14
14
|
command -v "$command_name" >/dev/null 2>&1 || fail "required command not found: $command_name"
|
|
15
15
|
done
|
|
16
16
|
|
|
17
|
+
case "$INSTALL_DIR" in
|
|
18
|
+
/*) ;;
|
|
19
|
+
*) fail "install directory must be an absolute path: $INSTALL_DIR" ;;
|
|
20
|
+
esac
|
|
21
|
+
|
|
17
22
|
if [ "$REQUESTED_VERSION" = "latest" ]; then
|
|
18
23
|
latest_url="https://github.com/${REPOSITORY}/releases/latest"
|
|
19
|
-
resolved_url="$(curl -fsSL -o /dev/null -w '%{url_effective}' "$latest_url")" || fail "could not resolve the latest release"
|
|
24
|
+
resolved_url="$(curl -fsSL --connect-timeout 5 --max-time 20 --retry 2 --retry-delay 1 --retry-max-time 30 -o /dev/null -w '%{url_effective}' "$latest_url")" || fail "could not resolve the latest release"
|
|
20
25
|
VERSION="${resolved_url##*/}"
|
|
21
26
|
else
|
|
22
27
|
VERSION="$REQUESTED_VERSION"
|
|
@@ -44,11 +49,21 @@ esac
|
|
|
44
49
|
ARCHIVE="delegation-layer_${VERSION#v}_${OS}_${ARCH}.tar.gz"
|
|
45
50
|
RELEASE_URL="https://github.com/${REPOSITORY}/releases/download/${VERSION}"
|
|
46
51
|
TEMP_DIR="$(mktemp -d)"
|
|
47
|
-
|
|
52
|
+
STAGE_DIR=""
|
|
48
53
|
|
|
49
|
-
|
|
54
|
+
cleanup() {
|
|
55
|
+
status=$?
|
|
56
|
+
trap - EXIT HUP INT TERM
|
|
57
|
+
set +e
|
|
58
|
+
[ -z "$STAGE_DIR" ] || rm -rf "$STAGE_DIR"
|
|
59
|
+
rm -rf "$TEMP_DIR"
|
|
60
|
+
exit "$status"
|
|
61
|
+
}
|
|
62
|
+
trap cleanup EXIT HUP INT TERM
|
|
63
|
+
|
|
64
|
+
curl -fsSL --connect-timeout 5 --max-time 20 --retry 2 --retry-delay 1 --retry-max-time 30 -o "$TEMP_DIR/$ARCHIVE" "$RELEASE_URL/$ARCHIVE" || \
|
|
50
65
|
fail "could not download $ARCHIVE"
|
|
51
|
-
curl -fsSL --retry
|
|
66
|
+
curl -fsSL --connect-timeout 5 --max-time 20 --retry 2 --retry-delay 1 --retry-max-time 30 -o "$TEMP_DIR/checksums.txt" "$RELEASE_URL/checksums.txt" || \
|
|
52
67
|
fail "could not download checksums.txt"
|
|
53
68
|
|
|
54
69
|
CHECKSUM_LINE="$(awk -v archive="$ARCHIVE" '$2 == archive { print; exit }' "$TEMP_DIR/checksums.txt")"
|
|
@@ -65,10 +80,26 @@ fi
|
|
|
65
80
|
|
|
66
81
|
tar -xzf "$ARCHIVE" -C "$TEMP_DIR" || fail "could not extract $ARCHIVE"
|
|
67
82
|
mkdir -p "$INSTALL_DIR"
|
|
83
|
+
STAGE_DIR="$(mktemp -d "$INSTALL_DIR/.delegation-layer-stage.XXXXXX")" || \
|
|
84
|
+
fail "could not create an installation staging directory"
|
|
68
85
|
for binary in delegate delegate-run pueue pueued; do
|
|
69
86
|
[ -f "$TEMP_DIR/$binary" ] || fail "release archive does not contain $binary"
|
|
70
|
-
install -m 0755 "$TEMP_DIR/$binary" "$
|
|
87
|
+
install -m 0755 "$TEMP_DIR/$binary" "$STAGE_DIR/$binary" || \
|
|
88
|
+
fail "could not stage $binary"
|
|
89
|
+
done
|
|
90
|
+
|
|
91
|
+
for binary in delegate delegate-run pueue pueued; do
|
|
92
|
+
[ -x "$STAGE_DIR/$binary" ] || fail "staged release bundle does not contain executable $binary"
|
|
93
|
+
done
|
|
94
|
+
|
|
95
|
+
# Rename staged files only after the complete bundle has been downloaded,
|
|
96
|
+
# verified, extracted, and checked. Keep delegate last so a fresh install never
|
|
97
|
+
# exposes the control command before its runner and supervisor are ready.
|
|
98
|
+
for binary in delegate-run pueue pueued delegate; do
|
|
99
|
+
mv "$STAGE_DIR/$binary" "$INSTALL_DIR/$binary" || fail "could not publish $binary"
|
|
71
100
|
done
|
|
101
|
+
rm -rf "$STAGE_DIR"
|
|
102
|
+
STAGE_DIR=""
|
|
72
103
|
|
|
73
104
|
printf 'Installed delegation-layer CLI and bundled supervisor %s in %s\n' "$VERSION" "$INSTALL_DIR"
|
|
74
105
|
case ":${PATH:-}:" in
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "delegation-layer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18",
|
|
4
4
|
"description": "Multi-provider AI agent delegation CLI and Agent Skill for running bounded coding tasks across provider CLIs.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-agents",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"docs/assets/delegation-layer-hero.jpg",
|
|
26
26
|
"install.sh",
|
|
27
27
|
"skills/agent-integration/",
|
|
28
|
+
"plugins/delegation-layer/",
|
|
28
29
|
"scripts/install-agent-integration.mjs",
|
|
29
30
|
"scripts/install-cli.mjs"
|
|
30
31
|
],
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "delegation-layer",
|
|
3
|
+
"displayName": "Delegation Layer",
|
|
4
|
+
"version": "0.1.18",
|
|
5
|
+
"description": "Consult external AI harnesses for reviews, research, implementation, and debate through the bounded, resumable Delegate CLI.",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Hesham Karam",
|
|
8
|
+
"url": "https://github.com/hishamkaram"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/hishamkaram/delegation-layer",
|
|
11
|
+
"repository": "https://github.com/hishamkaram/delegation-layer",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"agent-delegation",
|
|
15
|
+
"agent-skills",
|
|
16
|
+
"coding-agents",
|
|
17
|
+
"orchestration",
|
|
18
|
+
"task-lifecycle"
|
|
19
|
+
],
|
|
20
|
+
"defaultEnabled": true,
|
|
21
|
+
"skills": "./skills/"
|
|
22
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "delegation-layer",
|
|
3
|
+
"version": "0.1.18",
|
|
4
|
+
"description": "Consult external AI harnesses for reviews, research, implementation, and debate through the bounded, resumable Delegate CLI.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Hesham Karam",
|
|
7
|
+
"url": "https://github.com/hishamkaram"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/hishamkaram/delegation-layer",
|
|
10
|
+
"repository": "https://github.com/hishamkaram/delegation-layer",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"agent-delegation",
|
|
14
|
+
"agent-skills",
|
|
15
|
+
"coding-agents",
|
|
16
|
+
"orchestration",
|
|
17
|
+
"task-lifecycle"
|
|
18
|
+
],
|
|
19
|
+
"skills": "./skills/",
|
|
20
|
+
"interface": {
|
|
21
|
+
"displayName": "Delegation Layer",
|
|
22
|
+
"shortDescription": "Consult external AI harnesses",
|
|
23
|
+
"longDescription": "Routes external agent work through a bounded, resumable CLI with durable evidence and provider-neutral capability handling.",
|
|
24
|
+
"developerName": "Hesham Karam",
|
|
25
|
+
"category": "Productivity",
|
|
26
|
+
"capabilities": [
|
|
27
|
+
"Agent delegation",
|
|
28
|
+
"Bounded execution",
|
|
29
|
+
"Resumable tasks"
|
|
30
|
+
],
|
|
31
|
+
"defaultPrompt": "Use $agent-integration to consult another harness or model for review, research, implementation, testing, or debate."
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"SessionStart": [
|
|
4
|
+
{
|
|
5
|
+
"hooks": [
|
|
6
|
+
{
|
|
7
|
+
"type": "command",
|
|
8
|
+
"command": "/bin/sh -c 'plugin_root=\"${CLAUDE_PLUGIN_ROOT:-${PLUGIN_ROOT:?plugin root environment variable is missing}}\"; exec \"$plugin_root/scripts/ensure-delegate.sh\"'"
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
set -eu
|
|
3
|
+
|
|
4
|
+
fail() {
|
|
5
|
+
printf 'delegation-layer plugin: %s\n' "$1" >&2
|
|
6
|
+
exit 1
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
plugin_root="${PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT:-}}"
|
|
10
|
+
[ -n "$plugin_root" ] || fail 'the plugin root environment variable is missing'
|
|
11
|
+
|
|
12
|
+
installer="$plugin_root/scripts/install-cli.sh"
|
|
13
|
+
[ -x "$installer" ] || fail "the bundled CLI installer is missing: $installer"
|
|
14
|
+
|
|
15
|
+
resolve_command_path() {
|
|
16
|
+
path="$1"
|
|
17
|
+
case "$path" in
|
|
18
|
+
/*) ;;
|
|
19
|
+
*) path="$(cd -P "$(dirname "$path")" 2>/dev/null && pwd)/$(basename "$path")" || return 1 ;;
|
|
20
|
+
esac
|
|
21
|
+
while [ -L "$path" ]; do
|
|
22
|
+
link="$(readlink "$path")" || return 1
|
|
23
|
+
case "$link" in
|
|
24
|
+
/*) path="$link" ;;
|
|
25
|
+
*) path="$(dirname "$path")/$link" ;;
|
|
26
|
+
esac
|
|
27
|
+
done
|
|
28
|
+
path="$(cd -P "$(dirname "$path")" 2>/dev/null && pwd)/$(basename "$path")" || return 1
|
|
29
|
+
printf '%s\n' "$path"
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
valid_delegate() {
|
|
33
|
+
candidate="$1"
|
|
34
|
+
[ -f "$candidate" ] && [ -x "$candidate" ] || return 1
|
|
35
|
+
resolved_candidate="$(resolve_command_path "$candidate")" || return 1
|
|
36
|
+
resolved_bin_dir="$(dirname "$resolved_candidate")"
|
|
37
|
+
supervisor_dir="$resolved_bin_dir"
|
|
38
|
+
if [ ! -x "$supervisor_dir/pueue" ] || [ ! -x "$supervisor_dir/pueued" ]; then
|
|
39
|
+
supervisor_dir="$resolved_bin_dir/../libexec"
|
|
40
|
+
fi
|
|
41
|
+
delegate_run="$resolved_bin_dir/delegate-run"
|
|
42
|
+
pueue="$supervisor_dir/pueue"
|
|
43
|
+
pueued="$supervisor_dir/pueued"
|
|
44
|
+
[ -f "$delegate_run" ] && [ -x "$delegate_run" ] || return 1
|
|
45
|
+
[ -f "$pueue" ] && [ -x "$pueue" ] || return 1
|
|
46
|
+
[ -f "$pueued" ] && [ -x "$pueued" ] || return 1
|
|
47
|
+
|
|
48
|
+
delegate_version="$("$candidate" --version 2>/dev/null)" || return 1
|
|
49
|
+
case "$delegate_version" in
|
|
50
|
+
delegate\ *) ;;
|
|
51
|
+
*) return 1 ;;
|
|
52
|
+
esac
|
|
53
|
+
pueue_version="$("$pueue" --version 2>/dev/null)" || return 1
|
|
54
|
+
pueued_version="$("$pueued" --version 2>/dev/null)" || return 1
|
|
55
|
+
case "$pueue_version" in
|
|
56
|
+
pueue\ *) ;;
|
|
57
|
+
*) return 1 ;;
|
|
58
|
+
esac
|
|
59
|
+
case "$pueued_version" in
|
|
60
|
+
pueued\ *) ;;
|
|
61
|
+
*) return 1 ;;
|
|
62
|
+
esac
|
|
63
|
+
pueue_release="$(printf '%s\n' "$pueue_version" | awk 'NF { print $NF; exit }')"
|
|
64
|
+
pueued_release="$(printf '%s\n' "$pueued_version" | awk 'NF { print $NF; exit }')"
|
|
65
|
+
[ -n "$pueue_release" ] && [ "$pueue_release" = "$pueued_release" ]
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
path_points_to() {
|
|
69
|
+
expected="$1"
|
|
70
|
+
actual="$(command -v delegate 2>/dev/null || true)"
|
|
71
|
+
[ -n "$actual" ] || return 1
|
|
72
|
+
actual="$(resolve_command_path "$actual")" || return 1
|
|
73
|
+
expected="$(resolve_command_path "$expected")" || return 1
|
|
74
|
+
[ "$actual" = "$expected" ]
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
path_delegate="$(command -v delegate 2>/dev/null || true)"
|
|
78
|
+
if [ -n "$path_delegate" ] && valid_delegate "$path_delegate"; then
|
|
79
|
+
exit 0
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
existing_install_dir="${DELEGATION_LAYER_INSTALL_DIR:-$HOME/.local/bin}"
|
|
83
|
+
existing_delegate="$existing_install_dir/delegate"
|
|
84
|
+
if valid_delegate "$existing_delegate"; then
|
|
85
|
+
case ":${PATH:-}:" in
|
|
86
|
+
*:"$existing_install_dir":*)
|
|
87
|
+
path_points_to "$existing_delegate" && exit 0
|
|
88
|
+
shadowed_delegate="$(command -v delegate 2>/dev/null || true)"
|
|
89
|
+
fail "delegate is installed at $existing_install_dir but PATH resolves delegate to ${shadowed_delegate:-an unavailable command}; put $existing_install_dir before the shadowing entry and start a new harness session"
|
|
90
|
+
;;
|
|
91
|
+
*)
|
|
92
|
+
fail "delegate is installed at $existing_install_dir but that directory is not on PATH; add it to PATH and start a new harness session"
|
|
93
|
+
;;
|
|
94
|
+
esac
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
install_dir="$existing_install_dir"
|
|
98
|
+
case "$install_dir" in
|
|
99
|
+
/*) ;;
|
|
100
|
+
*) fail "the CLI install directory must be an absolute path: $install_dir" ;;
|
|
101
|
+
esac
|
|
102
|
+
|
|
103
|
+
if [ -e "$install_dir/delegate" ] || [ -L "$install_dir/delegate" ]; then
|
|
104
|
+
fail "refusing to overwrite an existing delegate at $install_dir/delegate; put a clean directory first in PATH or set DELEGATION_LAYER_INSTALL_DIR to a dedicated directory"
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
DELEGATION_LAYER_INSTALL_DIR="$install_dir" sh "$installer" ||
|
|
108
|
+
fail 'the checksum-verified CLI installation failed'
|
|
109
|
+
|
|
110
|
+
installed_delegate="$install_dir/delegate"
|
|
111
|
+
valid_delegate "$installed_delegate" ||
|
|
112
|
+
fail "the installer completed but delegate is not usable at $installed_delegate"
|
|
113
|
+
|
|
114
|
+
if path_points_to "$installed_delegate"; then
|
|
115
|
+
printf 'Delegation Layer CLI is ready at %s\n' "$installed_delegate"
|
|
116
|
+
exit 0
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
path_delegate="$(command -v delegate 2>/dev/null || true)"
|
|
120
|
+
if [ -n "$path_delegate" ]; then
|
|
121
|
+
fail "delegate was installed at $install_dir but PATH resolves delegate to $path_delegate; put $install_dir before the shadowing entry and start a new harness session"
|
|
122
|
+
fi
|
|
123
|
+
fail "delegate was installed at $install_dir but that directory is not on PATH; add it to PATH and start a new harness session"
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
set -eu
|
|
3
|
+
|
|
4
|
+
REPOSITORY="hishamkaram/delegation-layer"
|
|
5
|
+
REQUESTED_VERSION="${DELEGATION_LAYER_VERSION:-latest}"
|
|
6
|
+
INSTALL_DIR="${DELEGATION_LAYER_INSTALL_DIR:-$HOME/.local/bin}"
|
|
7
|
+
|
|
8
|
+
fail() {
|
|
9
|
+
printf 'delegation-layer: %s\n' "$1" >&2
|
|
10
|
+
exit 1
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
for command_name in awk curl grep install mkdir mktemp mv rm tar uname; do
|
|
14
|
+
command -v "$command_name" >/dev/null 2>&1 || fail "required command not found: $command_name"
|
|
15
|
+
done
|
|
16
|
+
|
|
17
|
+
case "$INSTALL_DIR" in
|
|
18
|
+
/*) ;;
|
|
19
|
+
*) fail "install directory must be an absolute path: $INSTALL_DIR" ;;
|
|
20
|
+
esac
|
|
21
|
+
|
|
22
|
+
if [ "$REQUESTED_VERSION" = "latest" ]; then
|
|
23
|
+
latest_url="https://github.com/${REPOSITORY}/releases/latest"
|
|
24
|
+
resolved_url="$(curl -fsSL --connect-timeout 5 --max-time 20 --retry 2 --retry-delay 1 --retry-max-time 30 -o /dev/null -w '%{url_effective}' "$latest_url")" || fail "could not resolve the latest release"
|
|
25
|
+
VERSION="${resolved_url##*/}"
|
|
26
|
+
else
|
|
27
|
+
VERSION="$REQUESTED_VERSION"
|
|
28
|
+
case "$VERSION" in
|
|
29
|
+
v*) ;;
|
|
30
|
+
*) VERSION="v${VERSION}" ;;
|
|
31
|
+
esac
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
printf '%s\n' "$VERSION" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+$' || \
|
|
35
|
+
fail "invalid version: $VERSION"
|
|
36
|
+
|
|
37
|
+
case "$(uname -s)" in
|
|
38
|
+
Linux) OS=Linux ;;
|
|
39
|
+
Darwin) OS=Darwin ;;
|
|
40
|
+
*) fail "unsupported operating system: $(uname -s)" ;;
|
|
41
|
+
esac
|
|
42
|
+
|
|
43
|
+
case "$(uname -m)" in
|
|
44
|
+
x86_64|amd64) ARCH=amd64 ;;
|
|
45
|
+
arm64|aarch64) ARCH=arm64 ;;
|
|
46
|
+
*) fail "unsupported architecture: $(uname -m)" ;;
|
|
47
|
+
esac
|
|
48
|
+
|
|
49
|
+
ARCHIVE="delegation-layer_${VERSION#v}_${OS}_${ARCH}.tar.gz"
|
|
50
|
+
RELEASE_URL="https://github.com/${REPOSITORY}/releases/download/${VERSION}"
|
|
51
|
+
TEMP_DIR="$(mktemp -d)"
|
|
52
|
+
STAGE_DIR=""
|
|
53
|
+
|
|
54
|
+
cleanup() {
|
|
55
|
+
status=$?
|
|
56
|
+
trap - EXIT HUP INT TERM
|
|
57
|
+
set +e
|
|
58
|
+
[ -z "$STAGE_DIR" ] || rm -rf "$STAGE_DIR"
|
|
59
|
+
rm -rf "$TEMP_DIR"
|
|
60
|
+
exit "$status"
|
|
61
|
+
}
|
|
62
|
+
trap cleanup EXIT HUP INT TERM
|
|
63
|
+
|
|
64
|
+
curl -fsSL --connect-timeout 5 --max-time 20 --retry 2 --retry-delay 1 --retry-max-time 30 -o "$TEMP_DIR/$ARCHIVE" "$RELEASE_URL/$ARCHIVE" || \
|
|
65
|
+
fail "could not download $ARCHIVE"
|
|
66
|
+
curl -fsSL --connect-timeout 5 --max-time 20 --retry 2 --retry-delay 1 --retry-max-time 30 -o "$TEMP_DIR/checksums.txt" "$RELEASE_URL/checksums.txt" || \
|
|
67
|
+
fail "could not download checksums.txt"
|
|
68
|
+
|
|
69
|
+
CHECKSUM_LINE="$(awk -v archive="$ARCHIVE" '$2 == archive { print; exit }' "$TEMP_DIR/checksums.txt")"
|
|
70
|
+
[ -n "$CHECKSUM_LINE" ] || fail "checksums.txt does not contain $ARCHIVE"
|
|
71
|
+
|
|
72
|
+
cd "$TEMP_DIR"
|
|
73
|
+
if command -v sha256sum >/dev/null 2>&1; then
|
|
74
|
+
printf '%s\n' "$CHECKSUM_LINE" | sha256sum -c - || fail "checksum verification failed"
|
|
75
|
+
elif command -v shasum >/dev/null 2>&1; then
|
|
76
|
+
printf '%s\n' "$CHECKSUM_LINE" | shasum -a 256 -c - || fail "checksum verification failed"
|
|
77
|
+
else
|
|
78
|
+
fail "sha256sum or shasum is required for checksum verification"
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
tar -xzf "$ARCHIVE" -C "$TEMP_DIR" || fail "could not extract $ARCHIVE"
|
|
82
|
+
mkdir -p "$INSTALL_DIR"
|
|
83
|
+
STAGE_DIR="$(mktemp -d "$INSTALL_DIR/.delegation-layer-stage.XXXXXX")" || \
|
|
84
|
+
fail "could not create an installation staging directory"
|
|
85
|
+
for binary in delegate delegate-run pueue pueued; do
|
|
86
|
+
[ -f "$TEMP_DIR/$binary" ] || fail "release archive does not contain $binary"
|
|
87
|
+
install -m 0755 "$TEMP_DIR/$binary" "$STAGE_DIR/$binary" || \
|
|
88
|
+
fail "could not stage $binary"
|
|
89
|
+
done
|
|
90
|
+
|
|
91
|
+
for binary in delegate delegate-run pueue pueued; do
|
|
92
|
+
[ -x "$STAGE_DIR/$binary" ] || fail "staged release bundle does not contain executable $binary"
|
|
93
|
+
done
|
|
94
|
+
|
|
95
|
+
# Rename staged files only after the complete bundle has been downloaded,
|
|
96
|
+
# verified, extracted, and checked. Keep delegate last so a fresh install never
|
|
97
|
+
# exposes the control command before its runner and supervisor are ready.
|
|
98
|
+
for binary in delegate-run pueue pueued delegate; do
|
|
99
|
+
mv "$STAGE_DIR/$binary" "$INSTALL_DIR/$binary" || fail "could not publish $binary"
|
|
100
|
+
done
|
|
101
|
+
rm -rf "$STAGE_DIR"
|
|
102
|
+
STAGE_DIR=""
|
|
103
|
+
|
|
104
|
+
printf 'Installed delegation-layer CLI and bundled supervisor %s in %s\n' "$VERSION" "$INSTALL_DIR"
|
|
105
|
+
case ":${PATH:-}:" in
|
|
106
|
+
*:"$INSTALL_DIR":*) ;;
|
|
107
|
+
*) printf 'Add %s to PATH if it is not already there.\n' "$INSTALL_DIR" ;;
|
|
108
|
+
esac
|