@jenga-ai/agent 3.2.0 → 3.4.0
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 +52 -12
- package/agents/developer.md +16 -1
- package/agents/scrum-master.md +1 -0
- package/bin/jenga.js +10 -0
- package/lib/commands/dashboard.js +92 -0
- package/lib/skill-allow-list.json +6 -2
- package/package.json +21 -2
- package/project/app/api/lib/resolve-project-root.js +120 -0
- package/project/app/api/package.json +16 -0
- package/project/app/api/parsers/architecture.js +72 -0
- package/project/app/api/parsers/board.js +141 -0
- package/project/app/api/parsers/documentation.js +125 -0
- package/project/app/api/parsers/git-log.js +52 -0
- package/project/app/api/parsers/ideas.js +62 -0
- package/project/app/api/parsers/knowledge-graph.js +73 -0
- package/project/app/api/parsers/lib/markdown-dir-reader.js +163 -0
- package/project/app/api/parsers/rapports.js +148 -0
- package/project/app/api/parsers/todo.js +179 -0
- package/project/app/api/response.js +47 -0
- package/project/app/api/routes/architecture.js +23 -0
- package/project/app/api/routes/board.js +46 -0
- package/project/app/api/routes/documentation.js +24 -0
- package/project/app/api/routes/health.js +25 -0
- package/project/app/api/routes/history.js +55 -0
- package/project/app/api/routes/rapports.js +24 -0
- package/project/app/api/scripts/capture-snapshot.js +294 -0
- package/project/app/api/server.js +112 -0
- package/project/app/api/types.js +40 -0
- package/project/app/package.json +21 -0
- package/project/app/ui/dist/assets/index-7fj-vllY.js +104 -0
- package/project/app/ui/dist/assets/index-CdK3Qrep.css +1 -0
- package/project/app/ui/dist/index.html +13 -0
- package/project/app/ui/package.json +23 -0
- package/project/app/ui/scripts/build-snapshot-html.cjs +214 -0
- package/project/app/ui/scripts/dashboard-open.cjs +88 -0
- package/project/app/ui/scripts/dashboard-start.cjs +87 -0
- package/scripts/acquire-concurrency-slot.sh +220 -0
- package/scripts/compute-deploy-reconcile.sh +439 -0
- package/scripts/jenga-permission-level-switch.sh +19 -3
- package/scripts/mark-deployed.sh +532 -0
- package/scripts/populate-knowledge-graph.js +429 -0
- package/scripts/release-concurrency-slot.sh +129 -0
- package/scripts/validate-board.sh +60 -2
- package/scripts/verify-consumer-install.sh +470 -0
- package/skills/j-cloud-connect/SKILL.md +95 -0
- package/skills/j-cloud-connect/scripts/configure-backend.sh +267 -0
- package/skills/j-cloud-connect/scripts/install-rclone.sh +153 -0
- package/skills/j-dashboard/SKILL.md +144 -0
- package/skills/j-dashboard/scripts/launch.sh +121 -0
- package/skills/j-dashboard/scripts/resolve-app-dir.sh +164 -0
- package/skills/j-dashboard/scripts/snapshot.sh +267 -0
- package/skills/j-dashboard-share/SKILL.md +96 -0
- package/skills/j-dashboard-share/scripts/upload-snapshot.sh +173 -0
- package/skills/j-playbook/SKILL.md +12 -0
- package/skills/j-playbook-new/SKILL.md +155 -0
- package/skills/j-playbook-new/scripts/playbook-new.sh +332 -0
- package/skills/j-publish/scripts/npm_ci_pipeline.sh +6 -0
- package/skills/jenga/scripts/load-nl-catalog.js +22 -6
- package/skills/jenga/scripts/load-playbooks.sh +123 -24
- package/templates/SCRUM_BOARD_SCHEMA.md +18 -6
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# -----------------------------------------------------------------------------
|
|
3
|
+
# skills/j-cloud-connect/scripts/configure-backend.sh
|
|
4
|
+
#
|
|
5
|
+
# Core of the j-cloud-connect setup wizard (E60_S01_T02): dynamic backend
|
|
6
|
+
# selection, that backend's own `rclone config create` flow, an explicit
|
|
7
|
+
# wait for user confirmation of any auth step it produced, then independent
|
|
8
|
+
# post-confirmation verification.
|
|
9
|
+
#
|
|
10
|
+
# 1. Backend menu is sourced LIVE from `rclone config providers` — never a
|
|
11
|
+
# hardcoded list. This is true for both the printed menu and the
|
|
12
|
+
# validation of a backend name passed as an argument.
|
|
13
|
+
# 2. Once a backend type + remote name are known (from arguments, or from
|
|
14
|
+
# an interactive prompt driven by that same live menu), this script runs
|
|
15
|
+
# `rclone config create <remote> <backend>` with stdin/stdout/stderr
|
|
16
|
+
# fully inherited — no capturing, no re-formatting. Whatever that
|
|
17
|
+
# backend's own flow prints, including an OAuth auth URL, reaches the
|
|
18
|
+
# user exactly as rclone presents it. This script never parses or
|
|
19
|
+
# special-cases any backend's own prompts.
|
|
20
|
+
# 3. After `config create` returns, this script explicitly asks the user to
|
|
21
|
+
# confirm they've completed setup/authorization before doing anything
|
|
22
|
+
# else — it never just detects "not configured" and stops, and it never
|
|
23
|
+
# infers completion on its own.
|
|
24
|
+
# 4. Only after that confirmation, `rclone about <remote>:` is run to
|
|
25
|
+
# INDEPENDENTLY verify the remote actually works. The user's
|
|
26
|
+
# confirmation is never itself treated as success — a PASS/FAIL verdict
|
|
27
|
+
# always comes from this real check.
|
|
28
|
+
#
|
|
29
|
+
# The exact same code path runs regardless of which backend was selected;
|
|
30
|
+
# there is no per-backend branch anywhere below beyond what rclone's own
|
|
31
|
+
# `config create` already does internally per-backend.
|
|
32
|
+
#
|
|
33
|
+
# This script assumes `rclone` is already on PATH (see install-rclone.sh,
|
|
34
|
+
# E60_S01_T01) and that `jq` is available (already a repo-wide dependency
|
|
35
|
+
# used to parse rclone's JSON provider list).
|
|
36
|
+
#
|
|
37
|
+
# Invoked via `bash`, not executed directly — it intentionally ships without
|
|
38
|
+
# the executable bit, matching the convention already documented in this
|
|
39
|
+
# skill's install-rclone.sh and in skills/j-dashboard/scripts/resolve-app-dir.sh.
|
|
40
|
+
# Whatever wires this into the j-cloud-connect skill (E60_S01_T03) should
|
|
41
|
+
# invoke it as `bash skills/j-cloud-connect/scripts/configure-backend.sh`.
|
|
42
|
+
#
|
|
43
|
+
# Usage:
|
|
44
|
+
# configure-backend.sh --list
|
|
45
|
+
# configure-backend.sh [<backend-type> <remote-name>]
|
|
46
|
+
#
|
|
47
|
+
# --list Print the live backend menu and exit. No side
|
|
48
|
+
# effects.
|
|
49
|
+
# <backend-type> <remote-name>
|
|
50
|
+
# Skip interactive selection; configure the
|
|
51
|
+
# given backend under the given remote name.
|
|
52
|
+
# <backend-type> is still validated against the
|
|
53
|
+
# live provider list before use.
|
|
54
|
+
# (no arguments) Print the live menu, prompt for a numeric
|
|
55
|
+
# selection and a remote name, then proceed
|
|
56
|
+
# through the same configure/confirm/verify
|
|
57
|
+
# flow as the two-argument form above.
|
|
58
|
+
#
|
|
59
|
+
# Exit codes:
|
|
60
|
+
# 0 --list succeeded, OR the remote was configured, confirmed, and
|
|
61
|
+
# independently verified working (rclone about succeeded).
|
|
62
|
+
# 1 Any failure: rclone/jq missing, provider list unreadable, invalid
|
|
63
|
+
# backend/selection, `rclone config create` failed, the user declined
|
|
64
|
+
# to confirm setup was complete, or post-confirmation verification
|
|
65
|
+
# (`rclone about`) failed. A human-readable reason is always printed.
|
|
66
|
+
# -----------------------------------------------------------------------------
|
|
67
|
+
|
|
68
|
+
set -euo pipefail
|
|
69
|
+
|
|
70
|
+
usage() {
|
|
71
|
+
cat <<'EOF'
|
|
72
|
+
Usage:
|
|
73
|
+
configure-backend.sh --list
|
|
74
|
+
configure-backend.sh [<backend-type> <remote-name>]
|
|
75
|
+
|
|
76
|
+
Sources a backend menu live from `rclone config providers`, runs the
|
|
77
|
+
selected backend's own `rclone config create` flow (surfacing any auth URL
|
|
78
|
+
it produces directly, with stdio fully inherited), waits for explicit user
|
|
79
|
+
confirmation that setup/authorization is complete, then independently
|
|
80
|
+
verifies the remote via `rclone about <remote>:` and reports PASS/FAIL.
|
|
81
|
+
|
|
82
|
+
--list Print the live backend menu and exit.
|
|
83
|
+
<backend-type> <remote-name> Skip interactive selection.
|
|
84
|
+
(no arguments) Prompt interactively for both.
|
|
85
|
+
|
|
86
|
+
Exits 0 only once the remote is configured, confirmed, AND independently
|
|
87
|
+
verified working. Exits 1 on any failure, including a declined confirmation
|
|
88
|
+
or a failed post-confirmation verification — a user's confirmation alone is
|
|
89
|
+
never treated as success.
|
|
90
|
+
EOF
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
die() {
|
|
94
|
+
echo "Error: $*" >&2
|
|
95
|
+
exit 1
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
# -----------------------------------------------------------------------------
|
|
99
|
+
# Preflight — required tools.
|
|
100
|
+
# -----------------------------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
require_rclone() {
|
|
103
|
+
command -v rclone >/dev/null 2>&1 || die "rclone is not on PATH. Install it first (see skills/j-cloud-connect/scripts/install-rclone.sh) and re-run."
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
require_jq() {
|
|
107
|
+
command -v jq >/dev/null 2>&1 || die "'jq' is required to parse rclone's provider list but is not on PATH. Install jq and re-run."
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
# -----------------------------------------------------------------------------
|
|
111
|
+
# Live backend list — sourced from rclone itself, never hardcoded.
|
|
112
|
+
# -----------------------------------------------------------------------------
|
|
113
|
+
|
|
114
|
+
# Prints the raw `rclone config providers` JSON on stdout. Dies with rclone's
|
|
115
|
+
# own captured output on any failure (command failure or non-array JSON).
|
|
116
|
+
fetch_providers_json() {
|
|
117
|
+
local json
|
|
118
|
+
if ! json="$(rclone config providers 2>&1)"; then
|
|
119
|
+
die "'rclone config providers' failed: $json"
|
|
120
|
+
fi
|
|
121
|
+
if ! printf '%s' "$json" | jq -e 'type == "array"' >/dev/null 2>&1; then
|
|
122
|
+
die "'rclone config providers' did not return a valid JSON array of backends. Output: $json"
|
|
123
|
+
fi
|
|
124
|
+
printf '%s' "$json"
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
# print_backend_menu <providers-json>
|
|
128
|
+
print_backend_menu() {
|
|
129
|
+
printf '%s' "$1" | jq -r 'to_entries[] | "\(.key + 1)) \(.value.Name) — \(.value.Description)"'
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
# backend_name_at_index <providers-json> <1-based-index>
|
|
133
|
+
backend_name_at_index() {
|
|
134
|
+
local json="$1" index="$2"
|
|
135
|
+
printf '%s' "$json" | jq -r --argjson i "$((index - 1))" '.[$i].Name // empty'
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
# backend_exists <providers-json> <backend-name>
|
|
139
|
+
backend_exists() {
|
|
140
|
+
local json="$1" name="$2"
|
|
141
|
+
printf '%s' "$json" | jq -e --arg n "$name" 'any(.[]; .Name == $n)' >/dev/null 2>&1
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
# -----------------------------------------------------------------------------
|
|
145
|
+
# Argument parsing.
|
|
146
|
+
# -----------------------------------------------------------------------------
|
|
147
|
+
|
|
148
|
+
LIST_ONLY=0
|
|
149
|
+
BACKEND_TYPE=""
|
|
150
|
+
REMOTE_NAME=""
|
|
151
|
+
|
|
152
|
+
case "${1:-}" in
|
|
153
|
+
-h|--help)
|
|
154
|
+
usage
|
|
155
|
+
exit 0
|
|
156
|
+
;;
|
|
157
|
+
--list)
|
|
158
|
+
LIST_ONLY=1
|
|
159
|
+
if [ "$#" -gt 1 ]; then
|
|
160
|
+
usage >&2
|
|
161
|
+
die "unexpected extra arguments after --list"
|
|
162
|
+
fi
|
|
163
|
+
;;
|
|
164
|
+
"")
|
|
165
|
+
;;
|
|
166
|
+
*)
|
|
167
|
+
if [ "$#" -ne 2 ]; then
|
|
168
|
+
usage >&2
|
|
169
|
+
die "expected exactly two arguments (<backend-type> <remote-name>), got $#"
|
|
170
|
+
fi
|
|
171
|
+
BACKEND_TYPE="$1"
|
|
172
|
+
REMOTE_NAME="$2"
|
|
173
|
+
;;
|
|
174
|
+
esac
|
|
175
|
+
|
|
176
|
+
require_rclone
|
|
177
|
+
require_jq
|
|
178
|
+
|
|
179
|
+
PROVIDERS_JSON="$(fetch_providers_json)"
|
|
180
|
+
|
|
181
|
+
if [ "$LIST_ONLY" -eq 1 ]; then
|
|
182
|
+
echo "Backends supported by your installed rclone:"
|
|
183
|
+
print_backend_menu "$PROVIDERS_JSON"
|
|
184
|
+
exit 0
|
|
185
|
+
fi
|
|
186
|
+
|
|
187
|
+
# -----------------------------------------------------------------------------
|
|
188
|
+
# Step 1 — Resolve a backend type and remote name (from args, or
|
|
189
|
+
# interactively from the same live menu). Both paths converge below into the
|
|
190
|
+
# identical configure/confirm/verify flow.
|
|
191
|
+
# -----------------------------------------------------------------------------
|
|
192
|
+
|
|
193
|
+
if [ -z "$BACKEND_TYPE" ]; then
|
|
194
|
+
echo "Select a cloud storage backend:"
|
|
195
|
+
print_backend_menu "$PROVIDERS_JSON"
|
|
196
|
+
SELECTION=""
|
|
197
|
+
read -r -p "Enter the number of the backend to configure: " SELECTION || die "no input provided for the backend selection prompt (unexpected end of input)."
|
|
198
|
+
case "$SELECTION" in
|
|
199
|
+
''|*[!0-9]*) die "invalid selection '$SELECTION' — expected a number from the list above." ;;
|
|
200
|
+
esac
|
|
201
|
+
BACKEND_TYPE="$(backend_name_at_index "$PROVIDERS_JSON" "$SELECTION")"
|
|
202
|
+
[ -n "$BACKEND_TYPE" ] || die "invalid selection '$SELECTION' — no backend at that number."
|
|
203
|
+
|
|
204
|
+
REMOTE_NAME=""
|
|
205
|
+
read -r -p "Enter a name for this remote (e.g. 'gdrive'): " REMOTE_NAME || die "no input provided for the remote name prompt (unexpected end of input)."
|
|
206
|
+
[ -n "$REMOTE_NAME" ] || die "a remote name is required."
|
|
207
|
+
else
|
|
208
|
+
backend_exists "$PROVIDERS_JSON" "$BACKEND_TYPE" || die "'$BACKEND_TYPE' is not a backend your installed rclone supports. Run this script with --list to see the current list."
|
|
209
|
+
fi
|
|
210
|
+
|
|
211
|
+
# -----------------------------------------------------------------------------
|
|
212
|
+
# Step 2 — Run the backend's own `rclone config create` flow. stdio is fully
|
|
213
|
+
# inherited (no capture, no suppression): any prompts or auth URL this
|
|
214
|
+
# produces reach the user exactly as rclone presents them. Identical for
|
|
215
|
+
# every backend — no per-backend branch here.
|
|
216
|
+
# -----------------------------------------------------------------------------
|
|
217
|
+
|
|
218
|
+
echo ""
|
|
219
|
+
echo "Running: rclone config create $REMOTE_NAME $BACKEND_TYPE"
|
|
220
|
+
echo "Follow any prompts below, including opening any authorization link shown,"
|
|
221
|
+
echo "exactly as rclone presents them."
|
|
222
|
+
echo ""
|
|
223
|
+
|
|
224
|
+
CONFIG_EXIT=0
|
|
225
|
+
rclone config create "$REMOTE_NAME" "$BACKEND_TYPE" || CONFIG_EXIT=$?
|
|
226
|
+
if [ "$CONFIG_EXIT" -ne 0 ]; then
|
|
227
|
+
die "'rclone config create $REMOTE_NAME $BACKEND_TYPE' exited with status $CONFIG_EXIT. Remote was not configured — see rclone's output above for the reason."
|
|
228
|
+
fi
|
|
229
|
+
|
|
230
|
+
# -----------------------------------------------------------------------------
|
|
231
|
+
# Step 3 — Wait for EXPLICIT user confirmation before proceeding any further.
|
|
232
|
+
# Never inferred, never skipped.
|
|
233
|
+
# -----------------------------------------------------------------------------
|
|
234
|
+
|
|
235
|
+
echo ""
|
|
236
|
+
echo "If rclone showed an authorization link above, open it now and complete the"
|
|
237
|
+
echo "authorization before continuing."
|
|
238
|
+
CONFIRM=""
|
|
239
|
+
read -r -p "Have you finished completing setup/authorization for '$REMOTE_NAME'? [y/N] " CONFIRM || die "no input provided for the confirmation prompt (unexpected end of input)."
|
|
240
|
+
case "$CONFIRM" in
|
|
241
|
+
[Yy]|[Yy][Ee][Ss])
|
|
242
|
+
;;
|
|
243
|
+
*)
|
|
244
|
+
die "Setup was not confirmed complete. Re-run this script once you've finished authorization for '$REMOTE_NAME' — verification was skipped, so it has NOT been confirmed working."
|
|
245
|
+
;;
|
|
246
|
+
esac
|
|
247
|
+
|
|
248
|
+
# -----------------------------------------------------------------------------
|
|
249
|
+
# Step 4 — Independently verify the remote actually works. Confirmation
|
|
250
|
+
# alone is NEVER treated as success — this real check decides PASS/FAIL.
|
|
251
|
+
# -----------------------------------------------------------------------------
|
|
252
|
+
|
|
253
|
+
echo ""
|
|
254
|
+
echo "Verifying remote '$REMOTE_NAME'..."
|
|
255
|
+
|
|
256
|
+
VERIFY_EXIT=0
|
|
257
|
+
VERIFY_OUTPUT="$(rclone about "$REMOTE_NAME": 2>&1)" || VERIFY_EXIT=$?
|
|
258
|
+
|
|
259
|
+
if [ "$VERIFY_EXIT" -eq 0 ]; then
|
|
260
|
+
echo "PASS: remote '$REMOTE_NAME' is configured and verified working."
|
|
261
|
+
echo "$VERIFY_OUTPUT"
|
|
262
|
+
exit 0
|
|
263
|
+
else
|
|
264
|
+
echo "FAIL: remote '$REMOTE_NAME' did not verify — 'rclone about $REMOTE_NAME:' failed (exit $VERIFY_EXIT)." >&2
|
|
265
|
+
echo "$VERIFY_OUTPUT" >&2
|
|
266
|
+
exit 1
|
|
267
|
+
fi
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# -----------------------------------------------------------------------------
|
|
3
|
+
# skills/j-cloud-connect/scripts/install-rclone.sh
|
|
4
|
+
#
|
|
5
|
+
# Detects whether `rclone` is already on PATH and, if not, installs it
|
|
6
|
+
# automatically for the current OS:
|
|
7
|
+
# - macOS: via `brew install rclone` (requires Homebrew already installed)
|
|
8
|
+
# - Linux: via rclone's official install script
|
|
9
|
+
# (`curl https://rclone.org/install.sh | sudo bash`)
|
|
10
|
+
#
|
|
11
|
+
# This is standalone install-detection/automation ONLY (E60_S01_T01's scope).
|
|
12
|
+
# It does NOT configure any remote and does NOT run any auth flow — that is
|
|
13
|
+
# E60_S01_T02's scope, layered on top of this script later.
|
|
14
|
+
#
|
|
15
|
+
# Every failure path (unsupported OS, no package manager, sudo unavailable,
|
|
16
|
+
# network failure) exits non-zero with an actionable message. Success is
|
|
17
|
+
# NEVER reported without re-verifying, post-install, that `rclone` is both on
|
|
18
|
+
# PATH and actually runnable (`rclone version` succeeds) — this script never
|
|
19
|
+
# takes a package manager's reported success at face value.
|
|
20
|
+
#
|
|
21
|
+
# Invoked via `bash`, not executed directly: this script intentionally ships
|
|
22
|
+
# without the executable bit, matching the same convention documented in
|
|
23
|
+
# skills/j-dashboard/scripts/resolve-app-dir.sh's header — a shipped script
|
|
24
|
+
# losing its executable bit (e.g. during packaging/distribution) is exactly
|
|
25
|
+
# the class of failure this avoids by never depending on it in the first
|
|
26
|
+
# place. Whatever wires this into the j-cloud-connect skill (E60_S01_T03)
|
|
27
|
+
# should invoke it as `bash skills/j-cloud-connect/scripts/install-rclone.sh`.
|
|
28
|
+
#
|
|
29
|
+
# Usage:
|
|
30
|
+
# install-rclone.sh
|
|
31
|
+
#
|
|
32
|
+
# Exit codes:
|
|
33
|
+
# 0 rclone is on PATH and runnable (already present, or freshly installed
|
|
34
|
+
# and re-verified).
|
|
35
|
+
# 1 Installation could not proceed or could not be verified afterward.
|
|
36
|
+
# A human-readable reason is always printed to stderr.
|
|
37
|
+
# -----------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
set -euo pipefail
|
|
40
|
+
|
|
41
|
+
usage() {
|
|
42
|
+
cat <<'EOF'
|
|
43
|
+
Usage: install-rclone.sh
|
|
44
|
+
|
|
45
|
+
Detects whether `rclone` is on PATH. If missing, installs it automatically:
|
|
46
|
+
- macOS: `brew install rclone` (requires Homebrew)
|
|
47
|
+
- Linux: rclone's official install script (requires curl + sudo)
|
|
48
|
+
|
|
49
|
+
Exits 0 only once `rclone` is confirmed on PATH and runnable. Exits 1 with an
|
|
50
|
+
actionable message on every failure path (unsupported OS, no package manager,
|
|
51
|
+
sudo/curl unavailable, network failure, or post-install re-verification
|
|
52
|
+
failure).
|
|
53
|
+
EOF
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
die() {
|
|
57
|
+
echo "Error: $*" >&2
|
|
58
|
+
exit 1
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
case "${1:-}" in
|
|
62
|
+
-h|--help) usage; exit 0 ;;
|
|
63
|
+
"") ;;
|
|
64
|
+
*) usage >&2; die "unknown argument: $1" ;;
|
|
65
|
+
esac
|
|
66
|
+
|
|
67
|
+
# -----------------------------------------------------------------------------
|
|
68
|
+
# Step 1 — Detection: skip installation entirely if rclone is already present.
|
|
69
|
+
# -----------------------------------------------------------------------------
|
|
70
|
+
|
|
71
|
+
if command -v rclone >/dev/null 2>&1; then
|
|
72
|
+
RCLONE_PATH="$(command -v rclone)"
|
|
73
|
+
RCLONE_VERSION="$(rclone version 2>/dev/null | head -n 1 || echo "unknown version")"
|
|
74
|
+
echo "rclone is already installed at $RCLONE_PATH ($RCLONE_VERSION) — skipping install."
|
|
75
|
+
exit 0
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
echo "rclone not found on PATH. Attempting automatic install..."
|
|
79
|
+
|
|
80
|
+
# -----------------------------------------------------------------------------
|
|
81
|
+
# Step 2 — Post-install re-verification (defined up front, used by both OS
|
|
82
|
+
# branches below). Never report success without this check actually passing.
|
|
83
|
+
# -----------------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
verify_install() {
|
|
86
|
+
if ! command -v rclone >/dev/null 2>&1; then
|
|
87
|
+
die "install step ran but 'rclone' is still not on PATH. Installation did not succeed — see output above for details."
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
local rclone_bin
|
|
91
|
+
rclone_bin="$(command -v rclone)"
|
|
92
|
+
|
|
93
|
+
if ! rclone version >/dev/null 2>&1; then
|
|
94
|
+
die "'rclone' was found on PATH at $rclone_bin after install, but 'rclone version' failed to run. The binary is present but not usable — installation did not succeed."
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
local rclone_version
|
|
98
|
+
rclone_version="$(rclone version 2>/dev/null | head -n 1 || echo "unknown version")"
|
|
99
|
+
echo "rclone installed and verified successfully: $rclone_bin ($rclone_version)"
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# -----------------------------------------------------------------------------
|
|
103
|
+
# Step 3 — OS detection and OS-specific install.
|
|
104
|
+
# -----------------------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
OS_NAME="$(uname -s)"
|
|
107
|
+
|
|
108
|
+
case "$OS_NAME" in
|
|
109
|
+
Darwin)
|
|
110
|
+
if ! command -v brew >/dev/null 2>&1; then
|
|
111
|
+
die "rclone is not installed and Homebrew ('brew') is not available on this macOS machine, so it cannot be installed automatically. Install Homebrew (https://brew.sh) and re-run, or install rclone manually from https://rclone.org/downloads/."
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
echo "Installing rclone via Homebrew ('brew install rclone')..."
|
|
115
|
+
if ! brew install rclone; then
|
|
116
|
+
die "'brew install rclone' failed. This is commonly a network failure or a Homebrew environment issue — check the output above, then re-run. You can also install rclone manually from https://rclone.org/downloads/."
|
|
117
|
+
fi
|
|
118
|
+
;;
|
|
119
|
+
|
|
120
|
+
Linux)
|
|
121
|
+
if ! command -v curl >/dev/null 2>&1; then
|
|
122
|
+
die "rclone is not installed and 'curl' is not available on this Linux machine, so the official install script cannot be downloaded. Install curl (e.g. 'apt install curl' / 'yum install curl') and re-run, or install rclone manually from https://rclone.org/downloads/."
|
|
123
|
+
fi
|
|
124
|
+
if ! command -v sudo >/dev/null 2>&1; then
|
|
125
|
+
die "rclone is not installed and 'sudo' is not available on this Linux machine, but is required by rclone's official install script. Install rclone manually (as a privileged user) from https://rclone.org/downloads/, or make sudo available and re-run."
|
|
126
|
+
fi
|
|
127
|
+
|
|
128
|
+
echo "Installing rclone via the official install script (curl https://rclone.org/install.sh | sudo bash)..."
|
|
129
|
+
|
|
130
|
+
INSTALL_SCRIPT_TMP="$(mktemp)"
|
|
131
|
+
trap 'rm -f "$INSTALL_SCRIPT_TMP"' EXIT
|
|
132
|
+
|
|
133
|
+
if ! curl --fail --silent --show-error https://rclone.org/install.sh -o "$INSTALL_SCRIPT_TMP"; then
|
|
134
|
+
die "failed to download rclone's official install script from https://rclone.org/install.sh. This usually indicates no network access. Check your connection and re-run, or install rclone manually from https://rclone.org/downloads/."
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
INSTALL_EXIT_CODE=0
|
|
138
|
+
sudo bash "$INSTALL_SCRIPT_TMP" || INSTALL_EXIT_CODE=$?
|
|
139
|
+
if [ "$INSTALL_EXIT_CODE" -ne 0 ]; then
|
|
140
|
+
die "rclone's official install script downloaded successfully but failed to run (exit status $INSTALL_EXIT_CODE). This may indicate a sudo/permission issue or an unsupported Linux environment — check the output above. You can also install rclone manually from https://rclone.org/downloads/."
|
|
141
|
+
fi
|
|
142
|
+
;;
|
|
143
|
+
|
|
144
|
+
*)
|
|
145
|
+
die "unsupported OS '$OS_NAME' — this script only automates rclone install on macOS (via brew) and Linux (via rclone's official install script). Install rclone manually from https://rclone.org/downloads/."
|
|
146
|
+
;;
|
|
147
|
+
esac
|
|
148
|
+
|
|
149
|
+
# -----------------------------------------------------------------------------
|
|
150
|
+
# Step 4 — Re-verify before ever reporting success.
|
|
151
|
+
# -----------------------------------------------------------------------------
|
|
152
|
+
|
|
153
|
+
verify_install
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: j.dashboard
|
|
3
|
+
description: Launch the local Jenga project dashboard (API + UI) by delegating to project/app's existing npm scripts — no new server or build logic. Also supports --snapshot, a single self-contained HTML export with a point-in-time data snapshot baked in, and --data-url for remote/no-shared-filesystem delivery.
|
|
4
|
+
keywords:
|
|
5
|
+
- dashboard
|
|
6
|
+
- launch dashboard
|
|
7
|
+
- start dashboard
|
|
8
|
+
- open dashboard
|
|
9
|
+
- project dashboard
|
|
10
|
+
- snapshot dashboard
|
|
11
|
+
- export dashboard
|
|
12
|
+
examples:
|
|
13
|
+
- "open the dashboard"
|
|
14
|
+
- "launch the project dashboard"
|
|
15
|
+
- "j.dashboard"
|
|
16
|
+
- "start the dashboard on port 4000"
|
|
17
|
+
- "export a snapshot of the dashboard"
|
|
18
|
+
- "j.dashboard --snapshot"
|
|
19
|
+
- "j.dashboard --snapshot --data-url"
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# Dashboard — Local Launch & Single-File Snapshot Export
|
|
23
|
+
|
|
24
|
+
## Purpose
|
|
25
|
+
|
|
26
|
+
E05–E09 built a working local dashboard (Express API + Vite/React UI under `project/app/api` and
|
|
27
|
+
`project/app/ui`), already reachable via `npm run dashboard:start` / `npm run dashboard:open` at
|
|
28
|
+
the repo root (which shell into `project/app/ui/scripts/dashboard-start.cjs` /
|
|
29
|
+
`dashboard-open.cjs`). This skill is a thin, session-level entry point to those same scripts — it
|
|
30
|
+
introduces **no new server-launch, health-check, or build logic** of its own. All actual
|
|
31
|
+
implementation lives in the two `.cjs` scripts this skill wraps; do not duplicate it here or in
|
|
32
|
+
`scripts/launch.sh`.
|
|
33
|
+
|
|
34
|
+
`--snapshot` (E47_S04_T02/T03) is a second, independent mode: it captures the API's `/v1/board`,
|
|
35
|
+
`/v1/history`, and `/v1/architecture` responses once, bakes that data inline into the UI build, and
|
|
36
|
+
inlines all JS/CSS into a single, fully self-contained HTML file (default `jenga.html`) — viewable
|
|
37
|
+
via `file://` with no running server, so it can be handed to someone on another device. It does not
|
|
38
|
+
start a long-running server and does not open a browser; it is a one-shot export. `--data-url`
|
|
39
|
+
(E47_S04_T04) is an additive delivery mode for `--snapshot`: since the output file is already fully
|
|
40
|
+
self-contained, it can be base64-encoded into a `data:text/html;base64,...` URI that any browser can
|
|
41
|
+
open directly — no shared filesystem, hosting, or git round-trip needed, which matters when the
|
|
42
|
+
agent is running remotely (e.g. a cloud/remote session) and cannot hand the user a local path.
|
|
43
|
+
|
|
44
|
+
## Instructions
|
|
45
|
+
|
|
46
|
+
1. **Parse the invocation.** This skill accepts either:
|
|
47
|
+
- The **default/launch** form: an optional first word — `start`, `open`, or `both` — and an
|
|
48
|
+
optional `--port <n>` flag (forwarded unchanged to whichever underlying npm script runs).
|
|
49
|
+
`start` additionally accepts `--serve-app` (forwarded unchanged; has no effect on `open`).
|
|
50
|
+
- The **snapshot/export** form: `--snapshot`, optionally with `--out <path>` (default
|
|
51
|
+
`jenga.html` in the current working directory).
|
|
52
|
+
|
|
53
|
+
If the user's phrasing already makes the intent unambiguous (e.g. "start the dashboard", "open
|
|
54
|
+
the dashboard in my browser", "launch the dashboard and open it", "export a snapshot of the
|
|
55
|
+
dashboard"), map it directly and skip the prompt in step 2.
|
|
56
|
+
|
|
57
|
+
2. **No explicit mode given — ask.** If intent isn't already clear from the invocation, use
|
|
58
|
+
CLAUDE.md's standard Interaction Pattern rather than guessing:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
What would you like to do?
|
|
62
|
+
1. Start the dashboard server (npm run dashboard:start)
|
|
63
|
+
2. Open the dashboard in your browser (npm run dashboard:open) — assumes it's already running
|
|
64
|
+
3. Both — start the server, then open the browser
|
|
65
|
+
4. Export a single-file snapshot (--snapshot) — a portable, offline-viewable HTML file
|
|
66
|
+
5. Other (describe below)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Map option 1 -> `start`, option 2 -> `open`, option 3 -> `both`, option 4 -> `--snapshot`.
|
|
70
|
+
|
|
71
|
+
3. **Default/launch form — run the wrapper script.** Invoke `skills/j-dashboard/scripts/launch.sh
|
|
72
|
+
<mode> [--port <n>] [--serve-app]` with the resolved mode and any forwarded flags. The script:
|
|
73
|
+
- Delegates to `npm run dashboard:start` / `npm run dashboard:open` inside `project/app` — the
|
|
74
|
+
exact same commands `npm run dashboard:start` / `dashboard:open` at the repo root already run.
|
|
75
|
+
- For `both`, backgrounds the (long-running) server, waits briefly, then runs `open` — which
|
|
76
|
+
itself health-checks before opening the browser and always exits `0` regardless of outcome
|
|
77
|
+
(that is `dashboard-open.cjs`'s own documented contract, unchanged by this skill).
|
|
78
|
+
- Resolves `project/app` via the shared `resolve-app-dir.sh`, which checks this package's own
|
|
79
|
+
root, the git repo root, and `node_modules/@jenga-ai/agent/project/app` — the last of these is
|
|
80
|
+
where the dashboard actually lives in a **consumer install**, and assuming the repo root (as
|
|
81
|
+
this script originally did) broke `j.dashboard` on every consumer.
|
|
82
|
+
- Exits non-zero with a clear message if no `project/app` can be resolved, or if the underlying
|
|
83
|
+
npm script itself fails (e.g. `--port` validation, missing dependencies).
|
|
84
|
+
|
|
85
|
+
4. **`--snapshot` form — run the snapshot script.** Invoke
|
|
86
|
+
`skills/j-dashboard/scripts/snapshot.sh [--out <path>] [--data-url]`. The script:
|
|
87
|
+
- Captures the invoking directory (before any internal `cd`) so data is resolved against the
|
|
88
|
+
*invoking* project, per `E47_S02`'s generalized data-source resolution — not this repo's own
|
|
89
|
+
data, unless that happens to be the invoking project.
|
|
90
|
+
- Runs `E47_S04_T02`'s capture step
|
|
91
|
+
(`project/app/api/scripts/capture-snapshot.js`) to collect `/v1/board`, `/v1/history`, and
|
|
92
|
+
`/v1/architecture` into one JSON artifact.
|
|
93
|
+
- Runs `project/app/ui/scripts/build-snapshot-html.cjs`, which inlines the built `dist/`
|
|
94
|
+
(JS + CSS) into a single `index.html` and embeds that JSON as a
|
|
95
|
+
`<script id="jenga-dashboard-data">` tag. It has **zero dependencies**, so it behaves
|
|
96
|
+
identically here and in a consumer install — which only ever receives the prebuilt `dist/`.
|
|
97
|
+
Where the UI sources and `node_modules` are present, `dist/` is rebuilt first so a snapshot is
|
|
98
|
+
never taken from a stale build. (This replaced a `vite build --mode snapshot` step that could
|
|
99
|
+
only ever run inside this monorepo; the tarball ships no vite and no UI sources, so
|
|
100
|
+
`--snapshot` previously failed on 100% of consumer installs.)
|
|
101
|
+
- Copies the result to the final output path (default `jenga.html` in the invoking directory,
|
|
102
|
+
overridable via `--out <path>`).
|
|
103
|
+
- Fails loudly with no output file written if either the capture or bundling step fails — never
|
|
104
|
+
a partial/broken snapshot.
|
|
105
|
+
- With `--data-url` (E47_S04_T04): after the copy step above, base64-encodes the output file and
|
|
106
|
+
also prints a `data:text/html;base64,...` URI to stdout — additive to, not a replacement for,
|
|
107
|
+
the plain-path report. Refuses (non-zero exit, no URI printed) if the encoded size exceeds a
|
|
108
|
+
~25MB threshold rather than silently emitting an oversized URI.
|
|
109
|
+
|
|
110
|
+
5. **Relay output — pick the delivery mode based on filesystem sharing.** Before invoking the
|
|
111
|
+
snapshot script, judge whether this session can assume a shared filesystem with the user:
|
|
112
|
+
- **Shared filesystem (default — a normal local/IDE session):** run `snapshot.sh [--out <path>]`
|
|
113
|
+
without `--data-url` and report the local file path exactly as the script prints it (e.g.
|
|
114
|
+
"Snapshot dashboard written to: <path>") — the user can open that path directly.
|
|
115
|
+
- **No shared filesystem assumable (e.g. a remote/cloud agent session):** run `snapshot.sh
|
|
116
|
+
[--out <path>] --data-url` and relay the printed `data:text/html;base64,...` URI back to the
|
|
117
|
+
user as a **clickable markdown link**, e.g. `[Open dashboard snapshot](data:text/html;base64,...)`,
|
|
118
|
+
since the user has no way to fetch the file's bytes off this session's filesystem otherwise. If
|
|
119
|
+
the script refuses due to the size threshold, relay that refusal message as-is rather than
|
|
120
|
+
falling back to the plain path silently — the plain path is not reachable by this user in this
|
|
121
|
+
scenario either.
|
|
122
|
+
|
|
123
|
+
In both cases, print the rest of the script's stdout/stderr back to the user as-is — do not
|
|
124
|
+
reinterpret, summarize away, or suppress error output from the underlying scripts; they already
|
|
125
|
+
produce user-facing messages (e.g. "Dashboard API running at http://localhost:3001",
|
|
126
|
+
"⚠ Warning: Dashboard server does not appear to be running at ...", "Snapshot dashboard written
|
|
127
|
+
to: <path>").
|
|
128
|
+
|
|
129
|
+
6. **`start` mode is long-running.** `dashboard:start` runs a foreground server process that does
|
|
130
|
+
not exit on its own. When running `start` (not `both`) as part of an interactive session, make
|
|
131
|
+
sure the user understands the command will keep running until stopped (Ctrl-C) — don't silently
|
|
132
|
+
block the conversation waiting on it. `--snapshot` is a one-shot export and always terminates.
|
|
133
|
+
|
|
134
|
+
## Out of Scope
|
|
135
|
+
|
|
136
|
+
- Any change to `project/app/package.json`'s `dashboard:start`/`dashboard:open` scripts,
|
|
137
|
+
`dashboard-start.cjs`, or `dashboard-open.cjs` — this skill only invokes them. Fixes or feature
|
|
138
|
+
changes to the dashboard itself belong to those files' own epics (E05-E09, E47), not here.
|
|
139
|
+
- Resolving dashboard data against a *consumer* project's own `project/` directory rather than this
|
|
140
|
+
monorepo's — that's `E47_S02`'s scope (already reused, not duplicated, by both `launch.sh` and
|
|
141
|
+
`snapshot.sh`'s capture step).
|
|
142
|
+
- Any new capture/bundling logic beyond invoking `capture-snapshot.js` and
|
|
143
|
+
`build-snapshot-html.cjs` — those live in `project/app/api/scripts/capture-snapshot.js` and
|
|
144
|
+
`project/app/ui/scripts/build-snapshot-html.cjs` respectively.
|