@delorenj/pjangler 1.3.0 → 1.3.7
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 +72 -0
- package/dist/index.js +4510 -2485
- package/dist/mcp-server.js +4166 -1959
- package/dist/prompt.js +404 -0
- package/package.json +7 -5
- package/templates/commonproject/copier.yml +6 -1
- package/templates/commonproject/template/.mise/scripts/provision-packs.py +14 -50
- package/templates/hermes-agent/copier.yml +8 -11
- package/templates/hermes-agent/template/.runtime-scaffold/.gitignore.jinja +44 -0
- package/templates/hermes-agent/template/.scripts/01-config.sh +9 -0
- package/templates/hermes-agent/template/.scripts/05-fleet-env.sh +18 -28
- package/templates/hermes-agent/template/.scripts/10-hermes-profile.sh +68 -4
- package/templates/hermes-agent/template/.scripts/42-ticket-provider.sh +18 -1
- package/templates/hermes-agent/template/.scripts/70-systemd.sh +73 -43
- package/templates/hermes-agent/template/.scripts/80-registry.sh +6 -0
- package/templates/hermes-agent/template/.scripts/_lib.sh +62 -6
- package/templates/hermes-agent/template/.scripts/checkpoint.sh +29 -1
- package/templates/hermes-agent/template/.scripts/heartbeat.sh +13 -1
- package/templates/hermes-agent/template/.scripts/lib/fleet-env.sh +202 -0
- package/templates/hermes-agent/template/.scripts/lib/parse-fleet-env.py +734 -0
- package/templates/hermes-agent/template/.scripts/lifecycle.sh +126 -0
- package/templates/hermes-agent/template/.scripts/providers/plane.sh +1 -1
- package/templates/hermes-agent/template/SOUL.md.jinja +44 -8
- package/templates/hermes-agent/template/hermes.jinja +20 -8
- package/templates/hermes-agent/template/momo.jinja +177 -0
- package/templates/hermes-agent/template/role.yaml.jinja +19 -19
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# shellcheck shell=bash
|
|
2
|
+
# Shared data-only fleet.env loader. This file is trusted template code; the
|
|
3
|
+
# fleet.env it reads is configuration data and is never evaluated by a shell.
|
|
4
|
+
|
|
5
|
+
if [[ "${__PJANGLER_FLEET_ENV_LIBRARY_LOADED:-0}" == "1" ]]; then
|
|
6
|
+
return 0
|
|
7
|
+
fi
|
|
8
|
+
__PJANGLER_FLEET_ENV_LIBRARY_LOADED=1
|
|
9
|
+
|
|
10
|
+
# fleet.env is shared configuration, not authority to inject code into Python,
|
|
11
|
+
# shell, Node, or dynamic-loader children. PATH remains intact so explicitly
|
|
12
|
+
# configured Hermes/PJangler/provider tools still resolve.
|
|
13
|
+
subprocess_injection_key_is_unsafe() {
|
|
14
|
+
local key="$1" loader_key="$1"
|
|
15
|
+
case "$key" in
|
|
16
|
+
PYTHONPATH|PYTHONHOME|PYTHONSTARTUP|PYTHONUSERBASE|\
|
|
17
|
+
BASH_ENV|ENV|BASHOPTS|SHELLOPTS|BASH_COMPAT|BASH_LOADABLES_PATH|\
|
|
18
|
+
BASH_XTRACEFD|PROMPT_COMMAND|PS0|PS1|PS2|PS3|PS4|\
|
|
19
|
+
NODE_OPTIONS|NODE_PATH|GLIBC_TUNABLES|BASH_FUNC_*|DYLD_*)
|
|
20
|
+
return 0
|
|
21
|
+
;;
|
|
22
|
+
esac
|
|
23
|
+
|
|
24
|
+
# GNU and multilib loaders consume the same control stem with an optional
|
|
25
|
+
# _32/_64 ABI suffix. Do not delete unrelated application keys such as
|
|
26
|
+
# LD_SDK_KEY merely because they share the LD_ prefix.
|
|
27
|
+
case "$loader_key" in
|
|
28
|
+
LD_*_32|LD_*_64) loader_key="${loader_key%_*}" ;;
|
|
29
|
+
esac
|
|
30
|
+
case "$loader_key" in
|
|
31
|
+
LD_ASSUME_KERNEL|LD_AUDIT|LD_BIND_NOT|LD_BIND_NOW|LD_DEBUG|\
|
|
32
|
+
LD_DEBUG_OUTPUT|LD_DYNAMIC_WEAK|LD_HWCAP_MASK|LD_LIBRARY_PATH|\
|
|
33
|
+
LD_ORIGIN_PATH|LD_POINTER_GUARD|LD_PREFER_MAP_32BIT_EXEC|LD_PRELOAD|\
|
|
34
|
+
LD_PROFILE|LD_PROFILE_OUTPUT|LD_SHOW_AUXV|LD_TRACE_LOADED_OBJECTS|\
|
|
35
|
+
LD_TRACE_PRELINKING|LD_USE_LOAD_BIAS|LD_VERBOSE|LD_WARN)
|
|
36
|
+
return 0
|
|
37
|
+
;;
|
|
38
|
+
esac
|
|
39
|
+
return 1
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
scrub_subprocess_interpreter_injection() {
|
|
43
|
+
local key declaration function_name
|
|
44
|
+
|
|
45
|
+
builtin set +x +v
|
|
46
|
+
while IFS= read -r key; do
|
|
47
|
+
if subprocess_injection_key_is_unsafe "$key"; then
|
|
48
|
+
case "$key" in
|
|
49
|
+
BASHOPTS|SHELLOPTS|BASH_XTRACEFD)
|
|
50
|
+
builtin export -n "$key" 2>/dev/null || true
|
|
51
|
+
;;
|
|
52
|
+
*)
|
|
53
|
+
builtin unset -v "$key" 2>/dev/null || true
|
|
54
|
+
;;
|
|
55
|
+
esac
|
|
56
|
+
fi
|
|
57
|
+
done < <(builtin compgen -A variable)
|
|
58
|
+
|
|
59
|
+
# Imported exported functions are live functions rather than ordinary
|
|
60
|
+
# BASH_FUNC_* variables. Remove the whole class before selecting any child.
|
|
61
|
+
while IFS= read -r declaration; do
|
|
62
|
+
function_name="${declaration##* }"
|
|
63
|
+
[[ -n "$function_name" ]] && builtin unset -f -- "$function_name"
|
|
64
|
+
done < <(builtin declare -Fx)
|
|
65
|
+
|
|
66
|
+
builtin export PYTHONNOUSERSITE=1 PYTHONSAFEPATH=1
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
# Apply staged records as one transaction. Existing variables always win. New
|
|
70
|
+
# variables are removed in reverse order if any assignment/export fails.
|
|
71
|
+
apply_fleet_environment_records() {
|
|
72
|
+
local -n __pjangler_fleet_keys_ref="$1"
|
|
73
|
+
local -n __pjangler_fleet_values_ref="$2"
|
|
74
|
+
local __pjangler_fleet_index __pjangler_fleet_key
|
|
75
|
+
local -a __pjangler_fleet_applied=()
|
|
76
|
+
|
|
77
|
+
if (( ${#__pjangler_fleet_keys_ref[@]} != ${#__pjangler_fleet_values_ref[@]} )); then
|
|
78
|
+
builtin printf 'fleet environment apply failed: mismatched staging arrays\n' >&2
|
|
79
|
+
return 1
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
for ((__pjangler_fleet_index = 0; __pjangler_fleet_index < ${#__pjangler_fleet_keys_ref[@]}; __pjangler_fleet_index++)); do
|
|
83
|
+
__pjangler_fleet_key="${__pjangler_fleet_keys_ref[__pjangler_fleet_index]}"
|
|
84
|
+
if [[ ! "$__pjangler_fleet_key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] \
|
|
85
|
+
|| subprocess_injection_key_is_unsafe "$__pjangler_fleet_key"; then
|
|
86
|
+
builtin printf 'fleet environment apply failed: rejected variable name\n' >&2
|
|
87
|
+
for ((__pjangler_fleet_index = ${#__pjangler_fleet_applied[@]} - 1; __pjangler_fleet_index >= 0; __pjangler_fleet_index--)); do
|
|
88
|
+
builtin unset -v "${__pjangler_fleet_applied[__pjangler_fleet_index]}" 2>/dev/null || true
|
|
89
|
+
done
|
|
90
|
+
return 1
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
if builtin declare -p "$__pjangler_fleet_key" >/dev/null 2>&1; then
|
|
94
|
+
continue
|
|
95
|
+
fi
|
|
96
|
+
if ! builtin printf -v "$__pjangler_fleet_key" '%s' \
|
|
97
|
+
"${__pjangler_fleet_values_ref[__pjangler_fleet_index]}"; then
|
|
98
|
+
builtin printf 'fleet environment apply failed: assignment rejected\n' >&2
|
|
99
|
+
for ((__pjangler_fleet_index = ${#__pjangler_fleet_applied[@]} - 1; __pjangler_fleet_index >= 0; __pjangler_fleet_index--)); do
|
|
100
|
+
builtin unset -v "${__pjangler_fleet_applied[__pjangler_fleet_index]}" 2>/dev/null || true
|
|
101
|
+
done
|
|
102
|
+
return 1
|
|
103
|
+
fi
|
|
104
|
+
__pjangler_fleet_applied+=("$__pjangler_fleet_key")
|
|
105
|
+
if ! builtin export "$__pjangler_fleet_key"; then
|
|
106
|
+
builtin printf 'fleet environment apply failed: export rejected\n' >&2
|
|
107
|
+
for ((__pjangler_fleet_index = ${#__pjangler_fleet_applied[@]} - 1; __pjangler_fleet_index >= 0; __pjangler_fleet_index--)); do
|
|
108
|
+
builtin unset -v "${__pjangler_fleet_applied[__pjangler_fleet_index]}" 2>/dev/null || true
|
|
109
|
+
done
|
|
110
|
+
return 1
|
|
111
|
+
fi
|
|
112
|
+
done
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
# Consume a parser child through a complete, double-NUL-terminated protocol.
|
|
116
|
+
# Nothing reaches this shell until child status and the entire frame validate.
|
|
117
|
+
import_fleet_environment_stream() {
|
|
118
|
+
local __pjangler_fleet_fd="$1" __pjangler_fleet_pid="$2"
|
|
119
|
+
local __pjangler_fleet_count __pjangler_fleet_index
|
|
120
|
+
local __pjangler_fleet_record __pjangler_fleet_key __pjangler_fleet_value
|
|
121
|
+
local -a __pjangler_fleet_records=() __pjangler_fleet_keys=() __pjangler_fleet_values=()
|
|
122
|
+
local -A __pjangler_fleet_seen=()
|
|
123
|
+
|
|
124
|
+
builtin mapfile -d '' -t -u "$__pjangler_fleet_fd" __pjangler_fleet_records || true
|
|
125
|
+
exec {__pjangler_fleet_fd}<&-
|
|
126
|
+
if ! builtin wait "$__pjangler_fleet_pid"; then
|
|
127
|
+
builtin printf 'fleet environment frame rejected: parser child failed\n' >&2
|
|
128
|
+
return 1
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
__pjangler_fleet_count="${#__pjangler_fleet_records[@]}"
|
|
132
|
+
if (( __pjangler_fleet_count < 3 )) \
|
|
133
|
+
|| [[ "${__pjangler_fleet_records[0]}" != "PJANGLER_FLEET_ENV_V1" ]] \
|
|
134
|
+
|| [[ "${__pjangler_fleet_records[__pjangler_fleet_count - 2]}" != "PJANGLER_FLEET_ENV_END" ]] \
|
|
135
|
+
|| [[ -n "${__pjangler_fleet_records[__pjangler_fleet_count - 1]}" ]]; then
|
|
136
|
+
builtin printf 'fleet environment frame rejected: incomplete framing\n' >&2
|
|
137
|
+
return 1
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
for ((__pjangler_fleet_index = 1; __pjangler_fleet_index < __pjangler_fleet_count - 2; __pjangler_fleet_index++)); do
|
|
141
|
+
__pjangler_fleet_record="${__pjangler_fleet_records[__pjangler_fleet_index]}"
|
|
142
|
+
if [[ "$__pjangler_fleet_record" != *=* ]]; then
|
|
143
|
+
builtin printf 'fleet environment frame rejected: malformed record\n' >&2
|
|
144
|
+
return 1
|
|
145
|
+
fi
|
|
146
|
+
__pjangler_fleet_key="${__pjangler_fleet_record%%=*}"
|
|
147
|
+
__pjangler_fleet_value="${__pjangler_fleet_record#*=}"
|
|
148
|
+
if [[ ! "$__pjangler_fleet_key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] \
|
|
149
|
+
|| subprocess_injection_key_is_unsafe "$__pjangler_fleet_key"; then
|
|
150
|
+
builtin printf 'fleet environment frame rejected: unsafe variable\n' >&2
|
|
151
|
+
return 1
|
|
152
|
+
fi
|
|
153
|
+
if [[ -n "${__pjangler_fleet_seen[$__pjangler_fleet_key]+present}" ]]; then
|
|
154
|
+
builtin printf 'fleet environment frame rejected: duplicate variable\n' >&2
|
|
155
|
+
return 1
|
|
156
|
+
fi
|
|
157
|
+
__pjangler_fleet_seen["$__pjangler_fleet_key"]=1
|
|
158
|
+
__pjangler_fleet_keys+=("$__pjangler_fleet_key")
|
|
159
|
+
__pjangler_fleet_values+=("$__pjangler_fleet_value")
|
|
160
|
+
done
|
|
161
|
+
|
|
162
|
+
apply_fleet_environment_records __pjangler_fleet_keys __pjangler_fleet_values
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
# fleet.env is parsed by an isolated interpreter. The parser path is explicit
|
|
166
|
+
# so every caller binds to its colocated, attested copy rather than PATH state.
|
|
167
|
+
import_fleet_environment() {
|
|
168
|
+
local __pjangler_fleet_path="$1" __pjangler_fleet_parser="$2"
|
|
169
|
+
local __pjangler_fleet_python __pjangler_fleet_fd __pjangler_fleet_pid
|
|
170
|
+
|
|
171
|
+
if [[ "$__pjangler_fleet_parser" != /* ]] \
|
|
172
|
+
|| [[ ! -f "$__pjangler_fleet_parser" || -L "$__pjangler_fleet_parser" ]]; then
|
|
173
|
+
builtin printf 'fleet environment frame rejected: trusted parser is unavailable\n' >&2
|
|
174
|
+
return 1
|
|
175
|
+
fi
|
|
176
|
+
__pjangler_fleet_python="$(builtin type -P python3)" || {
|
|
177
|
+
builtin printf 'fleet environment frame rejected: python3 is unavailable\n' >&2
|
|
178
|
+
return 1
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
exec {__pjangler_fleet_fd}< <(
|
|
182
|
+
"$__pjangler_fleet_python" -I "$__pjangler_fleet_parser" "$__pjangler_fleet_path"
|
|
183
|
+
)
|
|
184
|
+
__pjangler_fleet_pid=$!
|
|
185
|
+
import_fleet_environment_stream "$__pjangler_fleet_fd" "$__pjangler_fleet_pid"
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
# Public loader used by rendered provisioners, launchers, and maintenance
|
|
189
|
+
# scripts. Missing configuration remains optional; every existing path,
|
|
190
|
+
# including symlinks and non-regular files, must pass the parser's file checks.
|
|
191
|
+
load_fleet_environment() {
|
|
192
|
+
local __pjangler_fleet_path="$1" __pjangler_fleet_parser="$2"
|
|
193
|
+
scrub_subprocess_interpreter_injection
|
|
194
|
+
if [[ ! -e "$__pjangler_fleet_path" && ! -L "$__pjangler_fleet_path" ]]; then
|
|
195
|
+
return 0
|
|
196
|
+
fi
|
|
197
|
+
if ! import_fleet_environment "$__pjangler_fleet_path" "$__pjangler_fleet_parser"; then
|
|
198
|
+
builtin printf 'fleet environment import failed: %s\n' "$__pjangler_fleet_path" >&2
|
|
199
|
+
return 1
|
|
200
|
+
fi
|
|
201
|
+
scrub_subprocess_interpreter_injection
|
|
202
|
+
}
|