@delorenj/pjangler 1.4.5 → 1.5.2

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 (83) hide show
  1. package/README.md +41 -520
  2. package/dist/assets/project-notebook-skill/SHA256SUMS +5 -5
  3. package/dist/assets/project-notebook-skill/export-manifest.json +5 -5
  4. package/dist/assets/project-notebook-skill/hooks/session-end.sh +20 -1
  5. package/dist/assets/project-notebook-skill/hooks/session-start.sh +20 -1
  6. package/dist/assets/project-notebook-skill/references/configuration.md +2 -0
  7. package/dist/assets/project-notebook-skill/scripts/project-hooks.py +33 -3
  8. package/dist/assets/project-notebook-skill/tests/test_project_hooks.py +37 -0
  9. package/dist/index.js +5747 -13483
  10. package/dist/mcp-server.js +6853 -14059
  11. package/dist/notebook/journal-service-main.js +5682 -0
  12. package/dist/project-registry-service.js +748 -0
  13. package/dist/prompt.js +2 -1
  14. package/package.json +15 -10
  15. package/scripts/install-project-registry.mjs +34 -0
  16. package/scripts/migrate-project-registry.mjs +117 -0
  17. package/src/project/registryClient.ts +62 -0
  18. package/templates/commonproject/copier.yml +16 -19
  19. package/templates/commonproject/template/.agents/hooks/README.md +10 -4
  20. package/templates/commonproject/template/.agents/hooks/hermes/hindsight-hook.sh +12 -2
  21. package/templates/commonproject/template/.agents/hooks/hooks.master.json +10 -10
  22. package/templates/commonproject/template/.agents/hooks/lib/hook-guard.sh +13 -0
  23. package/templates/commonproject/template/.agents/hooks/sync.py +66 -17
  24. package/templates/commonproject/template/.agents/skills.json +0 -1
  25. package/templates/commonproject/template/.github/workflows/code-review.yml.jinja +7 -1
  26. package/templates/commonproject/template/.project.json.jinja +1 -1
  27. package/templates/commonproject/template/mise.toml.jinja +11 -21
  28. package/contracts/fleet-contract.yaml +0 -513
  29. package/templates/commonproject/template/.mise/scripts/provision-packs.py +0 -587
  30. package/templates/commonproject/template/.mise/scripts/sync-skills.py +0 -2183
  31. package/templates/hermes-agent/copier.yml +0 -186
  32. package/templates/hermes-agent/template/.gitignore.jinja +0 -11
  33. package/templates/hermes-agent/template/.runtime-scaffold/.gitattributes +0 -10
  34. package/templates/hermes-agent/template/.runtime-scaffold/.gitignore.jinja +0 -44
  35. package/templates/hermes-agent/template/.runtime-scaffold/README.md +0 -56
  36. package/templates/hermes-agent/template/.runtime-scaffold/decisions/.gitkeep +0 -2
  37. package/templates/hermes-agent/template/.runtime-scaffold/logs/.gitkeep +0 -1
  38. package/templates/hermes-agent/template/.runtime-scaffold/memories/MEMORY.md +0 -50
  39. package/templates/hermes-agent/template/.runtime-scaffold/memories/USER.md +0 -51
  40. package/templates/hermes-agent/template/.scripts/00-banner.sh +0 -21
  41. package/templates/hermes-agent/template/.scripts/01-config.sh +0 -60
  42. package/templates/hermes-agent/template/.scripts/05-fleet-env.sh +0 -42
  43. package/templates/hermes-agent/template/.scripts/10-hermes-profile.sh +0 -222
  44. package/templates/hermes-agent/template/.scripts/20-runtime-repo.sh +0 -199
  45. package/templates/hermes-agent/template/.scripts/30-telegram.sh +0 -363
  46. package/templates/hermes-agent/template/.scripts/31-slack.sh +0 -457
  47. package/templates/hermes-agent/template/.scripts/40-plane.sh +0 -60
  48. package/templates/hermes-agent/template/.scripts/42-ticket-provider.sh +0 -373
  49. package/templates/hermes-agent/template/.scripts/60-bloodbank.sh +0 -18
  50. package/templates/hermes-agent/template/.scripts/70-systemd.sh +0 -354
  51. package/templates/hermes-agent/template/.scripts/80-registry.sh +0 -185
  52. package/templates/hermes-agent/template/.scripts/99-summary.sh +0 -87
  53. package/templates/hermes-agent/template/.scripts/_lib.sh +0 -1138
  54. package/templates/hermes-agent/template/.scripts/channel-transaction.py +0 -2340
  55. package/templates/hermes-agent/template/.scripts/checkpoint.sh +0 -82
  56. package/templates/hermes-agent/template/.scripts/config.example.toml +0 -70
  57. package/templates/hermes-agent/template/.scripts/credential-launch.sh +0 -85
  58. package/templates/hermes-agent/template/.scripts/heartbeat.sh +0 -283
  59. package/templates/hermes-agent/template/.scripts/lib/fleet-env.sh +0 -202
  60. package/templates/hermes-agent/template/.scripts/lib/parse-fleet-env.py +0 -761
  61. package/templates/hermes-agent/template/.scripts/lib/profile-config-lock.py +0 -182
  62. package/templates/hermes-agent/template/.scripts/lib/profile-config-seed.py +0 -108
  63. package/templates/hermes-agent/template/.scripts/lib/ticket-provider.sh +0 -199
  64. package/templates/hermes-agent/template/.scripts/lib/voice-config.py +0 -546
  65. package/templates/hermes-agent/template/.scripts/lifecycle.sh +0 -126
  66. package/templates/hermes-agent/template/.scripts/momo-wip-lock.py +0 -137
  67. package/templates/hermes-agent/template/.scripts/providers/linear.sh +0 -329
  68. package/templates/hermes-agent/template/.scripts/providers/plane.sh +0 -671
  69. package/templates/hermes-agent/template/.scripts/providers/trello.sh +0 -241
  70. package/templates/hermes-agent/template/.scripts/reporter-watchdog.py +0 -242
  71. package/templates/hermes-agent/template/.scripts/secret-scan.py +0 -134
  72. package/templates/hermes-agent/template/.scripts/sentinel/bin/emit-event.py +0 -106
  73. package/templates/hermes-agent/template/.scripts/sentinel/bin/issue-autonomous-review.sh +0 -339
  74. package/templates/hermes-agent/template/.scripts/sentinel/bin/issue-close-gate.sh +0 -179
  75. package/templates/hermes-agent/template/.scripts/sentinel/docs/autonomous-delegated-review.md +0 -162
  76. package/templates/hermes-agent/template/.scripts/sentinel/docs/bloodbank-events.md +0 -42
  77. package/templates/hermes-agent/template/.scripts/sentinel/docs/continuous-ticket-orchestration.md +0 -77
  78. package/templates/hermes-agent/template/.scripts/sentinel.prompt.md.jinja +0 -116
  79. package/templates/hermes-agent/template/.scripts/store-onepassword-secret.py +0 -260
  80. package/templates/hermes-agent/template/SOUL.md.jinja +0 -197
  81. package/templates/hermes-agent/template/hermes.jinja +0 -109
  82. package/templates/hermes-agent/template/momo.jinja +0 -177
  83. package/templates/hermes-agent/template/role.yaml.jinja +0 -112
@@ -1,363 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Capture a BotFather token and wire it into the runtime profile.
3
- #
4
- # Telegram credentials are invocation-only inputs. Capture them before _lib.sh
5
- # sources fleet.env so a token parked in shared fleet state can never provision
6
- # or be silently reused by a profile. The non-secret allow-list may be shared.
7
- INVOCATION_TELEGRAM_BOT_TOKEN="${TELEGRAM_BOT_TOKEN-}"
8
- INVOCATION_TELEGRAM_ALLOWED_USERS="${TELEGRAM_ALLOWED_USERS-}"
9
- # Invocation credentials may have arrived as exported variables. Remove them
10
- # before even resolving/sourcing _lib.sh: that path invokes utilities and loads
11
- # fleet state, and no child involved in setup should inherit a raw token.
12
- unset TELEGRAM_BOT_TOKEN TELEGRAM_ALLOWED_USERS
13
-
14
- # Every channel write lands in the host-global profile root that 10-hermes-profile.sh
15
- # creates. When that step is deferred the root does not exist yet, so there is no
16
- # honest Telegram state to record -- not even the disabled state, which is itself a
17
- # write into the profile. Defer with it. This guard must precede _lib.sh because that
18
- # library creates the role log and reads fleet configuration.
19
- if [[ "${SKIP_HOST_STATE:-0}" == "1" ]]; then
20
- printf '%s\n' '[30] telegram — DEFERRED (SKIP_HOST_STATE=1)' >&2
21
- exit 0
22
- fi
23
-
24
- # shellcheck source=_lib.sh
25
- source "$(dirname "$0")/_lib.sh"
26
- load_role_env
27
-
28
- TELEGRAM_BOT_TOKEN="$INVOCATION_TELEGRAM_BOT_TOKEN"
29
- if [[ -n "$INVOCATION_TELEGRAM_ALLOWED_USERS" ]]; then
30
- TELEGRAM_ALLOWED_USERS="$INVOCATION_TELEGRAM_ALLOWED_USERS"
31
- else
32
- TELEGRAM_ALLOWED_USERS="${TELEGRAM_ALLOWED_USERS-}"
33
- fi
34
- unset INVOCATION_TELEGRAM_BOT_TOKEN INVOCATION_TELEGRAM_ALLOWED_USERS
35
-
36
- PROFILE_HOME="$HOME/.hermes/profiles/$PROFILE_NAME"
37
- profile_root_require_real "$PROFILE_HOME"
38
- RUNTIME="$ROLE_DIR/runtime"
39
- ENVF="$RUNTIME/.env"
40
- mkdir -p "$RUNTIME"
41
- [[ ! -L "$ENVF" ]] || die "refusing to write Telegram credentials through symlink: $ENVF"
42
-
43
- telegram_reconcile_existing() {
44
- # Registry first, then the transaction helper's profile lock. The helper
45
- # snapshots and validates refs plus role metadata only inside this window.
46
- local rc=0
47
- fleet_lock_acquire
48
- trap 'fleet_lock_release' EXIT
49
- channel_transaction_telegram_existing "$PROFILE_HOME" "$ENVF" || rc=$?
50
- fleet_lock_release
51
- trap - EXIT
52
- return "$rc"
53
- }
54
-
55
- telegram_defer_if_unconfigured() {
56
- # Prepare and, when already verified, reconcile under one registry-lock
57
- # window. The helpers independently take the profile lock second.
58
- local prepare_rc=0 rc=0
59
- fleet_lock_acquire
60
- trap 'fleet_lock_release' EXIT
61
- channel_transaction_telegram_prepare_unconfigured \
62
- "$PROFILE_HOME" "$ENVF" || prepare_rc=$?
63
- case "$prepare_rc" in
64
- 0)
65
- fleet_lock_release
66
- trap - EXIT
67
- return 2
68
- ;;
69
- 3)
70
- channel_transaction_telegram_existing "$PROFILE_HOME" "$ENVF" || rc=$?
71
- ;;
72
- *)
73
- die "Telegram deferred-state preparation transaction failed"
74
- ;;
75
- esac
76
- case "$rc" in
77
- 0)
78
- fleet_lock_release
79
- trap - EXIT
80
- return 0
81
- ;;
82
- 75)
83
- die "Telegram 1Password reference validation is temporarily unavailable; preserved existing verified wiring for retry"
84
- ;;
85
- *)
86
- die "Telegram verified wiring reconciliation transaction failed"
87
- ;;
88
- esac
89
- }
90
-
91
- telegram_prepare_for_attempt() {
92
- # A new profile becomes explicitly disabled before remote verification. A
93
- # verified profile is a no-op so a failed rotation preserves active wiring.
94
- local rc=0
95
- fleet_lock_acquire
96
- trap 'fleet_lock_release' EXIT
97
- channel_transaction_telegram_prepare_unconfigured \
98
- "$PROFILE_HOME" "$ENVF" || rc=$?
99
- fleet_lock_release
100
- trap - EXIT
101
- case "$rc" in
102
- 0|3) return 0 ;;
103
- *) die "Telegram deferred-state preparation transaction failed" ;;
104
- esac
105
- }
106
-
107
- # A valid durable mapping survives a transient 1Password outage. If the caller
108
- # supplied no rotation value, adopt/revalidate the complete current wiring
109
- # under registry -> profile locks. No ref or identity snapshot escapes that
110
- # window.
111
- if [[ -z "${TELEGRAM_BOT_TOKEN:-}" ]]; then
112
- telegram_reference_rc=0
113
- telegram_reconcile_existing || telegram_reference_rc=$?
114
- case "$telegram_reference_rc" in
115
- 0)
116
- log "[30] telegram — existing verified 1Password wiring reconciled"
117
- exit 0
118
- ;;
119
- 2) ;;
120
- 75)
121
- die "Telegram 1Password reference validation is temporarily unavailable; preserved existing verified wiring for retry"
122
- ;;
123
- *)
124
- die "Telegram verified wiring reconciliation transaction failed"
125
- ;;
126
- esac
127
- fi
128
-
129
- # Establish explicit disabled state for a first-time credential attempt. This
130
- # recheck is serialized with rotations: existing verified wiring is preserved,
131
- # while an unconfigured profile is disabled before any fallible remote check.
132
- if [[ -n "${TELEGRAM_BOT_TOKEN:-}" ]]; then
133
- telegram_prepare_for_attempt
134
- fi
135
-
136
- if [[ "${SKIP_TELEGRAM:-0}" == "1" ]]; then
137
- telegram_defer_rc=0
138
- telegram_defer_if_unconfigured || telegram_defer_rc=$?
139
- if [[ $telegram_defer_rc -eq 2 ]]; then
140
- log "[30] telegram — DEFERRED (SKIP_TELEGRAM=1; no verified 1Password reference)"
141
- else
142
- log "[30] telegram — existing verified 1Password wiring reconciled"
143
- fi
144
- exit 0
145
- fi
146
-
147
- if already_done 30-telegram; then
148
- log "[30] existing completion marker preserved while Telegram is reconciled"
149
- fi
150
-
151
- cat >&2 <<EOF
152
-
153
- ╭─ BotFather steps for @$BOT_HANDLE ─────────────────────────────────────╮
154
- │ 1. Open Telegram, message @BotFather │
155
- │ 2. /newbot │
156
- │ 3. Display name: $DISPLAY_NAME │
157
- │ 4. Username: $BOT_HANDLE (must end in _bot) │
158
- │ 5. Copy the HTTP API token from the reply. │
159
- │ 6. /setjoingroups → Disable │
160
- │ 7. /setprivacy → Disable │
161
- ╰────────────────────────────────────────────────────────────────────────╯
162
-
163
- EOF
164
-
165
- if [[ -z "${TELEGRAM_BOT_TOKEN:-}" && -t 0 ]]; then
166
- read -r -s -p "Paste the bot token for @$BOT_HANDLE (or empty to skip): " TELEGRAM_BOT_TOKEN
167
- echo >&2
168
- fi
169
-
170
- if [[ -z "${TELEGRAM_BOT_TOKEN:-}" ]]; then
171
- telegram_defer_rc=0
172
- telegram_defer_if_unconfigured || telegram_defer_rc=$?
173
- if [[ $telegram_defer_rc -eq 2 ]]; then
174
- warn " no token provided; Telegram step deferred"
175
- warn " re-run later with a profile-dedicated TELEGRAM_BOT_TOKEN invocation"
176
- else
177
- log "[30] telegram — existing verified 1Password wiring reconciled"
178
- fi
179
- exit 0
180
- fi
181
-
182
- # Sanity check
183
- if [[ ! "$TELEGRAM_BOT_TOKEN" =~ ^[0-9]+:[A-Za-z0-9_-]+$ ]]; then
184
- die "token doesn't look like a Telegram bot token"
185
- fi
186
- log " verifying token..."
187
- # Keep the credential out of process argv and environment. curl reads its
188
- # complete request description from an anonymous stdin pipe.
189
- info="$({
190
- printf 'url = "https://api.telegram.org/bot%s/getMe"\n' "$TELEGRAM_BOT_TOKEN"
191
- printf '%s\n' 'fail' 'silent' 'show-error'
192
- } | curl --config -)" \
193
- || die "Telegram getMe request failed"
194
- identity=$(printf '%s' "$info" | python3 -c '
195
- import json, sys
196
- try:
197
- data = json.load(sys.stdin)
198
- except Exception:
199
- raise SystemExit("Telegram getMe returned an invalid response")
200
- result = data.get("result") or {}
201
- if not data.get("ok") or not result.get("id") or not result.get("username"):
202
- raise SystemExit("Telegram rejected the bot token or omitted identity fields")
203
- print("{}\t{}".format(
204
- result.get("id"), str(result.get("username")).replace(chr(9), " ").replace(chr(10), " ")
205
- ))
206
- ') || die "Telegram bot identity verification failed"
207
- IFS=$'\t' read -r bot_id bot_username <<< "$identity"
208
- log " verified: @$bot_username (id=$bot_id)"
209
-
210
- # Resolve operator's allowed user id before taking the fleet claim lock.
211
- if [[ -z "${TELEGRAM_ALLOWED_USERS:-}" && -f "$HOME/.hermes/.env" ]]; then
212
- TELEGRAM_ALLOWED_USERS=$(grep -E '^[[:space:]]*#?[[:space:]]*TELEGRAM_ALLOWED_USERS=' "$HOME/.hermes/.env" \
213
- | tail -1 | sed -E 's/^[[:space:]]*#?[[:space:]]*TELEGRAM_ALLOWED_USERS=//; s/^"//; s/"$//')
214
- fi
215
- if [[ -z "${TELEGRAM_ALLOWED_USERS:-}" && -t 0 ]]; then
216
- read -r -p "Your Telegram user id (allow-list for this bot): " TELEGRAM_ALLOWED_USERS
217
- fi
218
- if [[ -z "${TELEGRAM_ALLOWED_USERS:-}" ]]; then
219
- warn " Telegram is wired but denies all inbound users until TELEGRAM_ALLOWED_USERS is set"
220
- fi
221
-
222
- # Reject token reuse, token rotation onto an identity owned by another agent,
223
- # and credentials parked in shared fleet/root env files. The scan, durable
224
- # identity claim, and profile credential write share one fleet-wide flock.
225
- fleet_lock_acquire
226
- trap 'fleet_lock_release' EXIT
227
- python3 /dev/fd/3 "$REGISTRY_FILE" "$FLEET_ENV" "$ENVF" "$AGENT_ID" "$bot_id" \
228
- "$ROLE_DIR" "$PROFILE_NAME" "$bot_username" \
229
- 3<<'PYEOF' <<<"$TELEGRAM_BOT_TOKEN"
230
- import os
231
- import pathlib
232
- import re
233
- import sys
234
- try:
235
- import yaml # type: ignore
236
- except ImportError:
237
- raise SystemExit("PyYAML is required for Telegram fleet claims")
238
-
239
- (
240
- registry_path,
241
- fleet_path,
242
- target_path,
243
- agent_id,
244
- bot_id,
245
- role_dir,
246
- profile_name,
247
- bot_username,
248
- ) = sys.argv[1:]
249
- token = sys.stdin.read()
250
- if token.endswith("\n"):
251
- token = token[:-1]
252
- if not token:
253
- raise SystemExit("Telegram ownership scan received no credential")
254
- for metadata_path in (pathlib.Path("/proc/self/cmdline"), pathlib.Path("/proc/self/environ")):
255
- if metadata_path.is_file() and token.encode() in metadata_path.read_bytes():
256
- raise SystemExit("Telegram ownership scan detected credential exposure in process metadata")
257
- target = pathlib.Path(target_path).resolve(strict=False)
258
-
259
- def env_token(path):
260
- try:
261
- text = path.read_text(encoding="utf-8")
262
- except (OSError, UnicodeError):
263
- return None
264
- match = re.search(
265
- r"(?m)^\s*(?:export\s+)?TELEGRAM_BOT_TOKEN\s*=\s*(.*)$", text
266
- )
267
- if not match:
268
- return None
269
- value = match.group(1).strip()
270
- if len(value) >= 2 and value[0] == value[-1] and value[0] in "\"'":
271
- value = value[1:-1]
272
- return value
273
-
274
- owners = [("shared fleet environment", pathlib.Path(fleet_path))]
275
- registry = pathlib.Path(registry_path)
276
- if registry.is_symlink():
277
- raise SystemExit(f"refusing to update registry symlink: {registry}")
278
- data = {"schema_version": 1, "agents": {}}
279
- if registry.is_file():
280
- try:
281
- data = yaml.safe_load(registry.read_text(encoding="utf-8")) or data
282
- except Exception as exc:
283
- raise SystemExit(f"cannot safely inspect Telegram ownership registry: {type(exc).__name__}")
284
- if not isinstance(data, dict) or not isinstance(data.get("agents", {}), dict):
285
- raise SystemExit("cannot safely inspect Telegram ownership registry: invalid agents mapping")
286
- agents = data.setdefault("agents", {})
287
- for other_id, entry in agents.items():
288
- if other_id == agent_id or not isinstance(entry, dict):
289
- continue
290
- telegram = entry.get("telegram") or {}
291
- if isinstance(telegram, dict) and str(telegram.get("bot_id") or "") == bot_id:
292
- raise SystemExit(f"Telegram bot identity is already assigned to agent {other_id}")
293
- other_role_dir = entry.get("role_dir")
294
- if other_role_dir:
295
- owners.append((f"agent {other_id}", pathlib.Path(str(other_role_dir)) / "runtime" / ".env"))
296
-
297
- home_value = os.environ.get("HOME", "")
298
- if home_value:
299
- home = pathlib.Path(home_value)
300
- owners.append(("shared Hermes root", home / ".hermes" / ".env"))
301
- profiles = home / ".hermes" / "profiles"
302
- if profiles.is_dir():
303
- for profile in profiles.iterdir():
304
- owners.append((f"profile {profile.name}", profile / ".env"))
305
-
306
- seen = set()
307
- for owner, path in owners:
308
- resolved = path.resolve(strict=False)
309
- if resolved == target or resolved in seen:
310
- continue
311
- seen.add(resolved)
312
- if env_token(path) == token:
313
- raise SystemExit(f"Telegram bot token is already assigned to {owner}")
314
-
315
- # This phase is intentionally read-only. The later channel transaction repeats
316
- # identity-conflict validation under the same lock before committing registry
317
- # metadata, so a failed vault stage cannot leave a false ownership claim.
318
- PYEOF
319
-
320
- # Stage the credential in a new immutable 1Password item. The helper verifies
321
- # the staged field and returns the immutable item id plus reference; no local
322
- # ownership/config state has changed yet.
323
- ONEPASSWORD_ITEM_PREFIX="${HERMES_ONEPASSWORD_ITEM_PREFIX:-$(config_get fleet.onepassword_item_prefix 'hermes-agent')}"
324
- telegram_stage="$(stage_onepassword_secret \
325
- "${ONEPASSWORD_ITEM_PREFIX}-${AGENT_ID}-telegram-bot-token" \
326
- telegram_bot_token "$TELEGRAM_BOT_TOKEN")" \
327
- || die "Telegram credential could not be staged and verified in 1Password"
328
- if [[ "$telegram_stage" != *$'\n'* ]]; then
329
- die "Telegram credential staging returned an invalid result"
330
- fi
331
- telegram_staged_item_id="${telegram_stage%%$'\n'*}"
332
- telegram_reference="${telegram_stage#*$'\n'}"
333
- [[ "$telegram_reference" != *$'\n'* ]] \
334
- || die "Telegram credential staging returned too many references"
335
- unset TELEGRAM_BOT_TOKEN
336
-
337
- # From here until commit, any failure archives the staged item by immutable id
338
- # and releases the fleet lock. The transaction itself keeps the platform
339
- # disabled while committing refs, role metadata, runtime policy, and registry;
340
- # activation and the done marker are its final writes.
341
- telegram_transaction_exit() {
342
- local rc=$?
343
- trap - EXIT
344
- if [[ -n "${telegram_staged_item_id:-}" ]]; then
345
- delete_staged_onepassword_item "$telegram_staged_item_id" >/dev/null 2>&1 \
346
- || warn " staged Telegram item cleanup failed; archive manually by immutable item id"
347
- fi
348
- fleet_lock_release
349
- exit "$rc"
350
- }
351
- trap telegram_transaction_exit EXIT
352
-
353
- channel_transaction_telegram \
354
- "$PROFILE_HOME" "$ENVF" "$telegram_reference" \
355
- "$bot_username" "$bot_id" "${TELEGRAM_ALLOWED_USERS:-}" \
356
- || die "Telegram local credential transaction failed"
357
-
358
- telegram_staged_item_id=""
359
-
360
- fleet_lock_release
361
- trap - EXIT
362
-
363
- log " wired @$bot_username (id=$bot_id) through 1Password reference"