@jenga-ai/agent 3.2.0 → 3.5.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.
Files changed (68) hide show
  1. package/README.md +52 -12
  2. package/agents/developer.md +16 -1
  3. package/agents/scrum-master.md +1 -0
  4. package/bin/jenga.js +10 -0
  5. package/lib/commands/dashboard.js +92 -0
  6. package/lib/skill-allow-list.json +6 -2
  7. package/package.json +21 -2
  8. package/project/app/api/lib/resolve-project-root.js +120 -0
  9. package/project/app/api/package.json +16 -0
  10. package/project/app/api/parsers/architecture.js +72 -0
  11. package/project/app/api/parsers/board.js +141 -0
  12. package/project/app/api/parsers/documentation.js +125 -0
  13. package/project/app/api/parsers/git-log.js +52 -0
  14. package/project/app/api/parsers/ideas.js +62 -0
  15. package/project/app/api/parsers/knowledge-graph.js +73 -0
  16. package/project/app/api/parsers/lib/markdown-dir-reader.js +163 -0
  17. package/project/app/api/parsers/rapports.js +148 -0
  18. package/project/app/api/parsers/todo.js +179 -0
  19. package/project/app/api/response.js +47 -0
  20. package/project/app/api/routes/architecture.js +23 -0
  21. package/project/app/api/routes/board.js +46 -0
  22. package/project/app/api/routes/documentation.js +24 -0
  23. package/project/app/api/routes/health.js +25 -0
  24. package/project/app/api/routes/history.js +55 -0
  25. package/project/app/api/routes/rapports.js +24 -0
  26. package/project/app/api/scripts/capture-snapshot.js +294 -0
  27. package/project/app/api/server.js +112 -0
  28. package/project/app/api/types.js +40 -0
  29. package/project/app/package.json +21 -0
  30. package/project/app/ui/dist/assets/index-7fj-vllY.js +104 -0
  31. package/project/app/ui/dist/assets/index-CdK3Qrep.css +1 -0
  32. package/project/app/ui/dist/index.html +13 -0
  33. package/project/app/ui/package.json +23 -0
  34. package/project/app/ui/scripts/build-snapshot-html.cjs +214 -0
  35. package/project/app/ui/scripts/dashboard-open.cjs +88 -0
  36. package/project/app/ui/scripts/dashboard-start.cjs +87 -0
  37. package/scripts/acquire-concurrency-slot.sh +220 -0
  38. package/scripts/compute-deploy-reconcile.sh +439 -0
  39. package/scripts/jenga-permission-level-switch.sh +19 -3
  40. package/scripts/mark-deployed.sh +532 -0
  41. package/scripts/populate-knowledge-graph.js +429 -0
  42. package/scripts/release-concurrency-slot.sh +129 -0
  43. package/scripts/validate-board.sh +60 -2
  44. package/scripts/verify-consumer-install.sh +470 -0
  45. package/skills/j-cloud-connect/SKILL.md +95 -0
  46. package/skills/j-cloud-connect/scripts/configure-backend.sh +267 -0
  47. package/skills/j-cloud-connect/scripts/install-rclone.sh +153 -0
  48. package/skills/j-dashboard/SKILL.md +144 -0
  49. package/skills/j-dashboard/scripts/launch.sh +121 -0
  50. package/skills/j-dashboard/scripts/resolve-app-dir.sh +164 -0
  51. package/skills/j-dashboard/scripts/snapshot.sh +267 -0
  52. package/skills/j-dashboard-share/SKILL.md +96 -0
  53. package/skills/j-dashboard-share/scripts/upload-snapshot.sh +173 -0
  54. package/skills/j-init/SKILL.md +52 -13
  55. package/skills/j-init/assets/.gitignore_template +1 -2
  56. package/skills/j-init/scripts/apply-scaffold-visibility.sh +192 -0
  57. package/skills/j-init/scripts/init.sh +19 -5
  58. package/skills/j-playbook/SKILL.md +12 -0
  59. package/skills/j-playbook-new/SKILL.md +155 -0
  60. package/skills/j-playbook-new/scripts/playbook-new.sh +332 -0
  61. package/skills/j-publish/scripts/npm_ci_pipeline.sh +6 -0
  62. package/skills/j-skillify/assets/init-new/assets/.gitignore_template +1 -2
  63. package/skills/j-uncharted/SKILL.md +54 -7
  64. package/skills/j-uncharted/assets/NODE_QUESTION_TEMPLATE.md +69 -0
  65. package/skills/j-uncharted/scripts/elicitation-state.sh +45 -7
  66. package/skills/jenga/scripts/load-nl-catalog.js +22 -6
  67. package/skills/jenga/scripts/load-playbooks.sh +146 -35
  68. 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.