@jenga-ai/agent 3.4.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.
- package/lib/skill-allow-list.json +1 -1
- package/package.json +1 -1
- package/skills/j-init/SKILL.md +52 -13
- package/skills/j-init/assets/.gitignore_template +1 -2
- package/skills/j-init/scripts/apply-scaffold-visibility.sh +192 -0
- package/skills/j-init/scripts/init.sh +19 -5
- package/skills/j-skillify/assets/init-new/assets/.gitignore_template +1 -2
- package/skills/j-uncharted/SKILL.md +54 -7
- package/skills/j-uncharted/assets/NODE_QUESTION_TEMPLATE.md +69 -0
- package/skills/j-uncharted/scripts/elicitation-state.sh +45 -7
- package/skills/jenga/scripts/load-playbooks.sh +23 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jenga-ai/agent",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.0",
|
|
4
4
|
"description": "An agentic development workflow for Claude Code, Copilot, and Codex — with a persistent Epic/Story/Task board, an isolated git worktree per task, and a separate tester agent that runs your test suite before anything is marked done.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
package/skills/j-init/SKILL.md
CHANGED
|
@@ -104,10 +104,41 @@ run can never silently relocate directories or edit `.gitignore`.
|
|
|
104
104
|
> `skills/distribute/CONFIG_SCHEMA.md` for the root-cause note and the tracked
|
|
105
105
|
> follow-up to reintroduce it once fixed.
|
|
106
106
|
|
|
107
|
-
Carry the chosen value into step
|
|
107
|
+
Carry the chosen value into step 4. Do not apply it yourself — the script owns all
|
|
108
108
|
of the mechanical work.
|
|
109
109
|
|
|
110
|
-
### 3.
|
|
110
|
+
### 3. Ask whether the distributed scaffold should be committed
|
|
111
|
+
|
|
112
|
+
This is a **distinct** question from step 2 — `project_files_visibility` (step 2)
|
|
113
|
+
covers only the `project/` working tree (the scrum board, `todo.md`, `queue/`,
|
|
114
|
+
`rapports/`, `logs/`). It has no effect on `.claude/`/`.agents/`, the distributed
|
|
115
|
+
framework scaffold (skill and agent definitions), which is a separate tree with a
|
|
116
|
+
separate lifecycle — it gets overwritten wholesale by every `/distribute` run or npm
|
|
117
|
+
upgrade, unlike `project/`. Kept as its own flag (`scaffold_visibility`) rather than
|
|
118
|
+
folded into `project_files_visibility`'s enum; see
|
|
119
|
+
`skills/distribute/CONFIG_SCHEMA.md`'s "Scaffold visibility" section for the full
|
|
120
|
+
rationale.
|
|
121
|
+
|
|
122
|
+
Ask the user this question, verbatim, before running any script:
|
|
123
|
+
|
|
124
|
+
Should the distributed .claude/.agents Jenga AI framework scaffold (skills, agent
|
|
125
|
+
definitions — implementation detail, not your own code) be committed into this
|
|
126
|
+
project's git history?
|
|
127
|
+
1. Yes, commit it — keep it tracked and visible, exactly like today
|
|
128
|
+
2. No, keep it on disk but add it to .gitignore so it's never committed
|
|
129
|
+
3. Not sure — explain the trade-offs and ask me again
|
|
130
|
+
|
|
131
|
+
If the user picks option 3, explain the trade-offs and re-ask. Do not proceed until
|
|
132
|
+
the answer maps to one of `visible` (option 1) or `ignored` (option 2).
|
|
133
|
+
|
|
134
|
+
If the run is non-interactive (no user available to answer), use the default:
|
|
135
|
+
**`visible`**. It is the only choice that changes nothing on disk, so an unattended
|
|
136
|
+
run reproduces exactly today's behavior — the scaffold is still committed by default.
|
|
137
|
+
|
|
138
|
+
Carry the chosen value into step 4 as well. Do not apply it yourself — the script
|
|
139
|
+
owns all of the mechanical work.
|
|
140
|
+
|
|
141
|
+
### 4. Run the scaffold script
|
|
111
142
|
|
|
112
143
|
`init.sh` is not guaranteed to live at a single fixed path: in a project that
|
|
113
144
|
installed Jenga via npm, it was mirrored to `.claude/skills/j-init/scripts/`
|
|
@@ -117,7 +148,7 @@ source checkout, where it lives at the bare `skills/j-init/scripts/` path
|
|
|
117
148
|
instead. This step runs before `CLAUDE.md`/`AGENTS.md` exist, so it cannot
|
|
118
149
|
rely on either file's routing instructions to resolve the path — it must
|
|
119
150
|
locate its own script directly. Execute the init script from the project
|
|
120
|
-
root, passing the
|
|
151
|
+
root, passing the choices from steps 2 and 3:
|
|
121
152
|
|
|
122
153
|
```bash
|
|
123
154
|
INIT_SCRIPT=""
|
|
@@ -128,11 +159,14 @@ if [[ -z "$INIT_SCRIPT" ]]; then
|
|
|
128
159
|
echo "Error: could not locate init.sh under .claude/skills/, .agents/skills/, or skills/" >&2
|
|
129
160
|
exit 1
|
|
130
161
|
fi
|
|
131
|
-
chmod +x "$INIT_SCRIPT" && "$INIT_SCRIPT" --visibility <visible|ignored>
|
|
162
|
+
chmod +x "$INIT_SCRIPT" && "$INIT_SCRIPT" --visibility <visible|ignored> --scaffold-visibility <visible|ignored>
|
|
132
163
|
```
|
|
133
164
|
|
|
134
165
|
Omitting `--visibility` falls back to the `JENGA_PROJECT_FILES_VISIBILITY`
|
|
135
|
-
environment variable, then to `visible`.
|
|
166
|
+
environment variable, then to `visible`. Omitting `--scaffold-visibility` falls
|
|
167
|
+
back to the `JENGA_SCAFFOLD_VISIBILITY` environment variable, then to `visible`
|
|
168
|
+
— the same default-preserving fallback chain, applied independently to the
|
|
169
|
+
distributed-scaffold question from step 3.
|
|
136
170
|
|
|
137
171
|
This script handles all scaffolding in one step:
|
|
138
172
|
1. Initializes the git repository
|
|
@@ -148,22 +182,27 @@ This script handles all scaffolding in one step:
|
|
|
148
182
|
11. Creates `docs/STRATEGY.md` — a strategic brief stub intended for investors, partners, and the product team
|
|
149
183
|
12. Creates `CHANGELOG.md` from the shared template — a running log of notable changes, seeded with an `[Unreleased]` section
|
|
150
184
|
13. Applies the chosen visibility mode via `scripts/apply-project-visibility.sh`, which records it as `project_files_visibility` in `jenga.config.json` and performs any `.gitignore` change
|
|
151
|
-
14.
|
|
185
|
+
14. Applies the chosen scaffold visibility mode via `scripts/apply-scaffold-visibility.sh`, which records it as `scaffold_visibility` in `jenga.config.json` and, when `ignored`, adds `.claude/` and `.agents/` to `.gitignore`
|
|
186
|
+
15. Stages and commits all files with the message `init: scaffold project structure and workflow config`
|
|
152
187
|
|
|
153
|
-
|
|
154
|
-
value fails fast and leaves nothing behind.
|
|
155
|
-
|
|
188
|
+
Both visibility modes are validated before any scaffolding happens, so an invalid
|
|
189
|
+
value fails fast and leaves nothing behind. Both are applied before the commit, so
|
|
190
|
+
any resulting `.gitignore` entries are captured in the initial commit — this is what
|
|
191
|
+
lets `scaffold_visibility: ignored` keep `.claude/`/`.agents/` out of the commit even
|
|
192
|
+
though they may already exist on disk (from npm postinstall or a prior `/distribute`
|
|
193
|
+
run) by the time `/init` runs `git add -A`.
|
|
156
194
|
|
|
157
195
|
If the script fails, check that you are in the project root and that git and `jq`
|
|
158
196
|
are available.
|
|
159
197
|
|
|
160
|
-
See `skills/distribute/CONFIG_SCHEMA.md` for the full `project_files_visibility`
|
|
161
|
-
field reference.
|
|
198
|
+
See `skills/distribute/CONFIG_SCHEMA.md` for the full `project_files_visibility` and
|
|
199
|
+
`scaffold_visibility` field reference.
|
|
162
200
|
|
|
163
|
-
###
|
|
201
|
+
### 5. Prompt next step
|
|
164
202
|
|
|
165
203
|
Inform the user that setup is complete, and state which visibility mode was applied
|
|
166
|
-
|
|
204
|
+
for both `project_files_visibility` and `scaffold_visibility`, and where the working
|
|
205
|
+
files and scaffold now live. Mention that `docs/STRATEGY.md` was created as
|
|
167
206
|
a strategic brief stub for investors, partners, and the product team — they can fill
|
|
168
207
|
it in now or return to it later. Suggest running `/pi-plan` to define project goals
|
|
169
208
|
and epics.
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# apply-scaffold-visibility.sh — apply the `scaffold_visibility` mode to a project.
|
|
4
|
+
#
|
|
5
|
+
# This is a DISTINCT flag from `project_files_visibility` (see
|
|
6
|
+
# apply-project-visibility.sh). `project_files_visibility` covers the
|
|
7
|
+
# project/ working tree (scrum board, todo.md, queue/, rapports/, logs/) —
|
|
8
|
+
# E31_S05's own Background section scopes it to that tree only. This script
|
|
9
|
+
# instead covers the *distributed framework scaffold* — `.claude/` and
|
|
10
|
+
# `.agents/` — which is a different tree with a different lifecycle (it is
|
|
11
|
+
# overwritten wholesale by every `/distribute` run or npm upgrade; project/
|
|
12
|
+
# is not). Filed as new, adjacent scope under E31_S07 rather than folded
|
|
13
|
+
# silently into project_files_visibility's existing enum. See
|
|
14
|
+
# skills/distribute/CONFIG_SCHEMA.md's "Scaffold visibility" section for the
|
|
15
|
+
# full rationale.
|
|
16
|
+
#
|
|
17
|
+
# This is skills/j-init/'s own copy of skills/init/scripts/apply-scaffold-visibility.sh
|
|
18
|
+
# (E31_S07_T03) — skills/j-init/ is a separate, hand-maintained directory, not
|
|
19
|
+
# auto-synced with skills/init/ (scripts/generate-j-alias.sh explicitly excludes
|
|
20
|
+
# this pair), and is the copy that actually ships to public-GitHub-mirror and
|
|
21
|
+
# npm-package consumers. Keep this file's logic in lockstep with skills/init/'s
|
|
22
|
+
# copy — any behavioral change made there should be mirrored here.
|
|
23
|
+
#
|
|
24
|
+
# Usage:
|
|
25
|
+
# apply-scaffold-visibility.sh <mode> [project_root]
|
|
26
|
+
# apply-scaffold-visibility.sh --check-only <mode>
|
|
27
|
+
#
|
|
28
|
+
# Modes:
|
|
29
|
+
# visible Scaffold directories stay where they are. No-op on disk beyond
|
|
30
|
+
# the config write. This is the default — matches the behavior
|
|
31
|
+
# of every /init run before this flag existed.
|
|
32
|
+
# ignored .claude/ and .agents/ are added to the project's .gitignore —
|
|
33
|
+
# present on disk (whenever npm postinstall or /distribute
|
|
34
|
+
# places them, whether that happens before or after this runs),
|
|
35
|
+
# never committed. Entries are written unconditionally, the same
|
|
36
|
+
# way apply-project-visibility.sh gitignores project/ whether or
|
|
37
|
+
# not it exists yet, so a scaffold created by a later
|
|
38
|
+
# /distribute run is covered too, not just one already on disk.
|
|
39
|
+
#
|
|
40
|
+
# Exit codes:
|
|
41
|
+
# 0 Success
|
|
42
|
+
# 1 Bad usage or missing prerequisite
|
|
43
|
+
# 2 Invalid mode (outside the two-value enum)
|
|
44
|
+
# 3 Filesystem apply failure
|
|
45
|
+
# 4 jenga.config.json write failure
|
|
46
|
+
|
|
47
|
+
# Do NOT use set -e globally — each step handles its own errors.
|
|
48
|
+
set -uo pipefail
|
|
49
|
+
|
|
50
|
+
info() { echo "[scaffold-visibility] $*"; }
|
|
51
|
+
warn() { echo "[scaffold-visibility] WARNING: $*"; }
|
|
52
|
+
err() { echo "[scaffold-visibility] ERROR: $*" >&2; }
|
|
53
|
+
|
|
54
|
+
usage() {
|
|
55
|
+
echo "Usage: $(basename "$0") <visible|ignored> [project_root]" >&2
|
|
56
|
+
echo " $(basename "$0") --check-only <visible|ignored>" >&2
|
|
57
|
+
exit 1
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# The distributed framework scaffold — mirrored copies of skills/agents for
|
|
61
|
+
# Claude Code and Copilot/other agents. Distinct from JENGA_WORKING_PATHS in
|
|
62
|
+
# apply-project-visibility.sh, which covers project/ only.
|
|
63
|
+
JENGA_SCAFFOLD_PATHS=(".claude" ".agents")
|
|
64
|
+
|
|
65
|
+
VALID_MODES="visible ignored"
|
|
66
|
+
|
|
67
|
+
validate_mode() {
|
|
68
|
+
local mode="$1"
|
|
69
|
+
for valid in $VALID_MODES; do
|
|
70
|
+
[ "$mode" = "$valid" ] && return 0
|
|
71
|
+
done
|
|
72
|
+
err "Invalid scaffold_visibility value: '${mode}'"
|
|
73
|
+
err "Allowed values are: ${VALID_MODES// /, }"
|
|
74
|
+
exit 2
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
# ---------------------------------------------------------------------------
|
|
78
|
+
# Argument parsing
|
|
79
|
+
# ---------------------------------------------------------------------------
|
|
80
|
+
|
|
81
|
+
CHECK_ONLY=0
|
|
82
|
+
if [ "${1:-}" = "--check-only" ]; then
|
|
83
|
+
CHECK_ONLY=1
|
|
84
|
+
shift
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
MODE="${1:-}"
|
|
88
|
+
[ -n "$MODE" ] || usage
|
|
89
|
+
|
|
90
|
+
validate_mode "$MODE"
|
|
91
|
+
|
|
92
|
+
if [ "$CHECK_ONLY" -eq 1 ]; then
|
|
93
|
+
info "Mode '$MODE' is valid."
|
|
94
|
+
exit 0
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
PROJECT_ROOT="${2:-$PWD}"
|
|
98
|
+
if [ ! -d "$PROJECT_ROOT" ]; then
|
|
99
|
+
err "Project root does not exist: $PROJECT_ROOT"
|
|
100
|
+
exit 1
|
|
101
|
+
fi
|
|
102
|
+
cd "$PROJECT_ROOT" || { err "Cannot enter project root: $PROJECT_ROOT"; exit 1; }
|
|
103
|
+
|
|
104
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
105
|
+
err "jq is required to write jenga.config.json but was not found on PATH."
|
|
106
|
+
exit 1
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
# ---------------------------------------------------------------------------
|
|
110
|
+
# ignored — append to .gitignore, without ever duplicating an entry
|
|
111
|
+
# ---------------------------------------------------------------------------
|
|
112
|
+
|
|
113
|
+
gitignore_append() {
|
|
114
|
+
local entry="$1"
|
|
115
|
+
local gitignore=".gitignore"
|
|
116
|
+
|
|
117
|
+
if [ -f "$gitignore" ] && grep -qxF -- "$entry" "$gitignore"; then
|
|
118
|
+
info "'$entry' already present in .gitignore — skipping."
|
|
119
|
+
return 0
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
# Don't glue our entry onto a final line that lacks a newline.
|
|
123
|
+
if [ -s "$gitignore" ] && [ -n "$(tail -c 1 "$gitignore")" ]; then
|
|
124
|
+
printf '\n' >> "$gitignore"
|
|
125
|
+
fi
|
|
126
|
+
|
|
127
|
+
if ! printf '%s\n' "$entry" >> "$gitignore"; then
|
|
128
|
+
err "Failed to append '$entry' to .gitignore"
|
|
129
|
+
exit 3
|
|
130
|
+
fi
|
|
131
|
+
info "Added '$entry' to .gitignore"
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
# ---------------------------------------------------------------------------
|
|
135
|
+
# jenga.config.json — merge the field in, written atomically (temp + mv)
|
|
136
|
+
# ---------------------------------------------------------------------------
|
|
137
|
+
|
|
138
|
+
write_scaffold_config() {
|
|
139
|
+
local mode="$1"
|
|
140
|
+
local config="jenga.config.json"
|
|
141
|
+
local tmp="${config}.tmp"
|
|
142
|
+
local existing='{}'
|
|
143
|
+
|
|
144
|
+
# /init normally runs before any /distribute, so the file usually does not
|
|
145
|
+
# exist yet. Merge rather than overwrite so other fields survive.
|
|
146
|
+
if [ -f "$config" ]; then
|
|
147
|
+
if ! jq empty "$config" 2>/dev/null; then
|
|
148
|
+
err "$config exists but contains malformed JSON — refusing to overwrite it."
|
|
149
|
+
exit 4
|
|
150
|
+
fi
|
|
151
|
+
existing="$(cat "$config")"
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
local content
|
|
155
|
+
content="$(jq --arg v "$mode" '.scaffold_visibility = $v' <<< "$existing")"
|
|
156
|
+
if [ -z "$content" ]; then
|
|
157
|
+
err "Failed to construct $config content."
|
|
158
|
+
exit 4
|
|
159
|
+
fi
|
|
160
|
+
|
|
161
|
+
if ! printf '%s\n' "$content" > "$tmp"; then
|
|
162
|
+
err "Failed to write temporary config file: $tmp"
|
|
163
|
+
exit 4
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
if ! mv "$tmp" "$config"; then
|
|
167
|
+
err "Failed to atomically move $tmp to $config"
|
|
168
|
+
rm -f "$tmp"
|
|
169
|
+
exit 4
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
info "Wrote scaffold_visibility = \"$mode\" to $config"
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
# ---------------------------------------------------------------------------
|
|
176
|
+
# Apply
|
|
177
|
+
# ---------------------------------------------------------------------------
|
|
178
|
+
|
|
179
|
+
case "$MODE" in
|
|
180
|
+
visible)
|
|
181
|
+
info "Mode 'visible' — scaffold directories stay in place; nothing to change on disk."
|
|
182
|
+
;;
|
|
183
|
+
ignored)
|
|
184
|
+
for path in "${JENGA_SCAFFOLD_PATHS[@]}"; do
|
|
185
|
+
gitignore_append "${path}/"
|
|
186
|
+
done
|
|
187
|
+
;;
|
|
188
|
+
esac
|
|
189
|
+
|
|
190
|
+
write_scaffold_config "$MODE"
|
|
191
|
+
|
|
192
|
+
info "Applied scaffold_visibility '$MODE' to $PROJECT_ROOT"
|
|
@@ -4,6 +4,7 @@ set -euo pipefail
|
|
|
4
4
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
5
|
ASSETS_DIR="$SCRIPT_DIR/../assets"
|
|
6
6
|
VISIBILITY_SCRIPT="$SCRIPT_DIR/apply-project-visibility.sh"
|
|
7
|
+
SCAFFOLD_VISIBILITY_SCRIPT="$SCRIPT_DIR/apply-scaffold-visibility.sh"
|
|
7
8
|
|
|
8
9
|
# ─── Resolve the package root that owns templates/ and lib/ ──────────────────
|
|
9
10
|
# postinstall.js mirrors only skills/ and agents/ into .claude/ and .agents/ —
|
|
@@ -22,23 +23,33 @@ else
|
|
|
22
23
|
exit 1
|
|
23
24
|
fi
|
|
24
25
|
|
|
25
|
-
# ─── 0. Resolve project_files_visibility
|
|
26
|
+
# ─── 0. Resolve project_files_visibility and scaffold_visibility ─────────────
|
|
26
27
|
# Defaults to `visible` — the only value that touches nothing on disk — so an
|
|
27
28
|
# unattended run can never silently relocate directories or edit .gitignore.
|
|
29
|
+
# project_files_visibility covers the project/ working tree (board, todo.md,
|
|
30
|
+
# queue/, rapports/, logs/). scaffold_visibility is a distinct, independent
|
|
31
|
+
# flag (E31_S07_T01, ported here in E31_S07_T03) covering the distributed
|
|
32
|
+
# .claude/.agents framework scaffold — kept separate per
|
|
33
|
+
# skills/distribute/CONFIG_SCHEMA.md's "Scaffold visibility" section, rather
|
|
34
|
+
# than folded into project_files_visibility's existing enum.
|
|
28
35
|
VISIBILITY="${JENGA_PROJECT_FILES_VISIBILITY:-visible}"
|
|
36
|
+
SCAFFOLD_VISIBILITY="${JENGA_SCAFFOLD_VISIBILITY:-visible}"
|
|
29
37
|
|
|
30
38
|
while [[ $# -gt 0 ]]; do
|
|
31
39
|
case "$1" in
|
|
32
40
|
--visibility) VISIBILITY="${2:-}"; shift 2 ;;
|
|
33
41
|
--visibility=*) VISIBILITY="${1#*=}"; shift ;;
|
|
42
|
+
--scaffold-visibility) SCAFFOLD_VISIBILITY="${2:-}"; shift 2 ;;
|
|
43
|
+
--scaffold-visibility=*) SCAFFOLD_VISIBILITY="${1#*=}"; shift ;;
|
|
34
44
|
*) echo "Unknown argument: $1" >&2
|
|
35
|
-
echo "Usage: $(basename "$0") [--visibility <visible|ignored>]" >&2
|
|
45
|
+
echo "Usage: $(basename "$0") [--visibility <visible|ignored>] [--scaffold-visibility <visible|ignored>]" >&2
|
|
36
46
|
exit 1 ;;
|
|
37
47
|
esac
|
|
38
48
|
done
|
|
39
49
|
|
|
40
50
|
# Validate before scaffolding so a typo cannot leave a half-initialised project.
|
|
41
51
|
bash "$VISIBILITY_SCRIPT" --check-only "$VISIBILITY"
|
|
52
|
+
bash "$SCAFFOLD_VISIBILITY_SCRIPT" --check-only "$SCAFFOLD_VISIBILITY"
|
|
42
53
|
|
|
43
54
|
# ─── 1. Initialize git repository ────────────────────────────────────────────
|
|
44
55
|
echo "→ Initializing git repository..."
|
|
@@ -101,11 +112,14 @@ cp "$ASSETS_DIR/strategy_stub_template.md" docs/STRATEGY.md
|
|
|
101
112
|
echo "→ Creating CHANGELOG.md from template..."
|
|
102
113
|
cp "$PKG_ROOT/templates/CHANGELOG_TEMPLATE.md" CHANGELOG.md
|
|
103
114
|
|
|
104
|
-
# ─── 11. Apply project_files_visibility
|
|
105
|
-
#
|
|
106
|
-
# initial commit
|
|
115
|
+
# ─── 11. Apply project_files_visibility and scaffold_visibility ─────────────
|
|
116
|
+
# Both run before the commit so any resulting .gitignore entries (ignored)
|
|
117
|
+
# are captured in the initial commit rather than left for the user to notice
|
|
118
|
+
# after the fact.
|
|
107
119
|
echo "→ Applying project files visibility ($VISIBILITY)..."
|
|
108
120
|
bash "$VISIBILITY_SCRIPT" "$VISIBILITY" "$PWD"
|
|
121
|
+
echo "→ Applying scaffold visibility ($SCAFFOLD_VISIBILITY)..."
|
|
122
|
+
bash "$SCAFFOLD_VISIBILITY_SCRIPT" "$SCAFFOLD_VISIBILITY" "$PWD"
|
|
109
123
|
|
|
110
124
|
# ─── 12. Generate CLAUDE.md / AGENTS.md ──────────────────────────────────────
|
|
111
125
|
# Unconditional — never gated on agentTarget (E41_S04). Applies the J-
|
|
@@ -168,6 +168,7 @@ For genuinely undocumented code, there is often no reliable human oracle to conf
|
|
|
168
168
|
|
|
169
169
|
- **The deterministic pipeline remains the tool of record for zero-oracle codebases.** `onboard --legacy` and `segment --mode delivery` never depend on anyone confirming intent — they ground everything in mechanical evidence (file structure, dependencies, test coverage) and say so explicitly under `Open Questions` when the evidence doesn't support a conclusion. When there is no one left who understands the code, reach for one of those, not the conversational flow.
|
|
170
170
|
- **When running the conversational flow, do not manufacture confidence.** If the user's answer is uncertain, hedged, or contradicts what discovery/Investigative Mode found, write the node honestly — do not round an uncertain answer up to a confirmed one. There is no schema field yet to tag confidence (the stub schema is intentionally minimal); until one exists, say so in the node's `description` text itself (e.g. "per the user, this module retries failed charges — unconfirmed against the code, which shows only a single retry attempt") rather than silently dropping the caveat.
|
|
171
|
+
- **`verification_depth: strict` is this guidance's concrete implementation, not a separate idea (E40_S06_T02).** When a candidate's Familiarity Check answer is `No` (Convergence Loop Step 1), Step 4's risk-weighted gating never lets an escalating finding round up to a false confirmation by asking the user to bless it — it auto-flags the node with exactly the hedged-`description` convention this bullet describes and converges it without a prompt. This bullet states the principle; Step 4's `strict` branch is what enforces it mechanically, so the two sections should be read as one mechanism, not two independently-arrived-at claims.
|
|
171
172
|
- **A confidently wrong answer is not detectable by this flow.** Corroboration against a second signal (commit history, existing docs, a second person) is the only mitigation, and it is not built here — this is the accepted residual risk, not a gap to engineer around mid-conversation.
|
|
172
173
|
|
|
173
174
|
### Directory Triage
|
|
@@ -213,10 +214,56 @@ Silence, a counter-question, or an ambiguous reply is not consent — re-ask, th
|
|
|
213
214
|
|
|
214
215
|
Runs once per surviving candidate (a subsystem, a named flow, a directory) after Directory Triage. This is the "propose understanding, ask the user to confirm or correct" cycle at the center of the redesign — and the one the scrutiny flagged as having no termination bound and no defense against confirmation fatigue. Both gaps are closed mechanically, not by agent discipline alone:
|
|
215
216
|
|
|
216
|
-
1. **
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
217
|
+
1. **Familiarity Check — once per candidate, before Investigative Mode dispatch.** Ask (per the Interaction Pattern in `CLAUDE.md` — numbered list, free-text last):
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
Are you familiar with this service/segment?
|
|
221
|
+
1. Yes
|
|
222
|
+
2. A little
|
|
223
|
+
3. No
|
|
224
|
+
4. Other (describe below)
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Silence, a counter-question, or an ambiguous reply is not consent — re-ask, the same convention used at every other confirmation gate in this skill. Map the answer to a `verification_depth` scoped to this candidate only — `Yes` → `shallow`, `A little` → `moderate`, `No` → `strict` — and persist it immediately, keyed by this candidate's node id, via `elicitation-state.sh`'s checkpoint mechanism (see Multi-Session Persistence below for the exact call and merge semantics):
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
printf '{"verification_depth": {"%s": "%s"}}' "<candidate-id>" "<shallow|moderate|strict>" \
|
|
231
|
+
| bash skills/j-uncharted/scripts/elicitation-state.sh checkpoint --id <elicitation-id> --json -
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**Check before asking.** A candidate whose `verification_depth` is already present in the state file's `checkpoint.verification_depth` (per Multi-Session Persistence below) has already answered this — do not re-ask it, on a fresh session or otherwise.
|
|
235
|
+
|
|
236
|
+
This question operationalizes the Human-Oracle-Availability Limitation above — it is the mechanism for finding out, per candidate, how much weight the user's own confirmations should carry, rather than assuming a uniform level of trust for every candidate in one run. **`verification_depth` is read back and consumed by Step 4's risk-weighted gating below (`E40_S06_T02`)**, which branches its auto-accept/confirm/auto-flag behavior per depth. The fixed internal/external question template used whenever shallow/moderate gating does decide to prompt (Step 5) is `skills/j-uncharted/assets/NODE_QUESTION_TEMPLATE.md` (`E40_S06_T03`) — this step's job remains asking the question and making the answer durable for those steps to read.
|
|
237
|
+
2. **Dispatch Investigative Mode.** Per `agents/developer.md`'s and `agents/tester.md`'s Investigative Mode sections (E20_S08_T02), dispatch the developer to trace what the code actually does for the candidate, and the tester to trace what the test suite actually exercises and verifies for the same candidate — two distinct vantage points, not two names for the same read. Both are read-only, worktree-sandboxed, no commits, no board writes.
|
|
238
|
+
3. **Propose understanding.** From both traces, draft the candidate's coarse graph node(s)/edge(s) (per the stub schema) and a plain-language summary of what they represent.
|
|
239
|
+
4. **Risk-weighted gating — not every finding gets a prompt, and `verification_depth` (Step 1) decides how gating itself behaves, not just what counts as risky.** This is the fix for confirmation fatigue (solution assessment, Problem 6, Solution B — RECOMMENDED). The baseline escalation criteria — the three triggers that force an explicit confirmation — are unchanged from before `E40_S06`:
|
|
240
|
+
|
|
241
|
+
- **T1 — inference-dependent:** the node's description depends on an inference the traces don't fully support.
|
|
242
|
+
- **T2 — structurally central:** the node has many outgoing edges.
|
|
243
|
+
- **T3 — already-flagged uncertain:** the Human-Oracle-Availability Limitation above already flagged this finding as uncertain.
|
|
244
|
+
|
|
245
|
+
A finding tripping none of T1-T3 is **low-risk** and auto-accepts regardless of depth. A finding tripping any of T1-T3 is **escalating**, and what happens to it now branches on the current candidate's `verification_depth` (read from `checkpoint.verification_depth.<candidate-id>`, per Step 1):
|
|
246
|
+
|
|
247
|
+
- **`moderate` (the default, unchanged calibration)** — exactly today's behavior: every escalating finding (any of T1-T3) forces a confirm prompt (Step 5); every low-risk finding auto-accepts without a prompt. **Log every auto-accepted node** in the elicitation state's checkpoint data (see Multi-Session Persistence below) so the decision is auditable later, per that solution's own mitigation for "the scoring mechanism itself misjudges impact."
|
|
248
|
+
- **`shallow` (widened auto-accept)** — the concrete widening rule: **drop T2 (structurally central) as an escalation trigger.** A finding tripping T2 alone — structurally central, but not inference-dependent and not already flagged uncertain — is reclassified low-risk and auto-accepted (still logged, same as above) instead of escalating. T1 and T3 still force a confirm prompt exactly as under `moderate`; only the T2-alone case widens. This is the literal reading of "findings that would sit just below today's high-impact bar" from the task's own framing — a purely structural signal with no corroborating uncertainty is no longer, by itself, enough to interrupt the user.
|
|
249
|
+
- **`strict` (no confirm prompt for escalating findings, ever)** — a finding tripping any of T1-T3 is **never presented to the user**. Instead:
|
|
250
|
+
1. Write the node directly with a hedged, low-confidence `description`, reusing the exact hedging convention the Human-Oracle-Availability Limitation section already specifies (e.g. "unconfirmed — traces did not fully corroborate this," adapted to name the specific gap).
|
|
251
|
+
2. Call `elicitation-state.sh converge` directly — **do not call `elicitation-state.sh turn` for this node.** No confirmation round is spent; the node goes straight from "proposed" to "converged," never "pending":
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
bash skills/j-uncharted/scripts/elicitation-state.sh converge --id <elicitation-id> --node <node-id> --note "auto-flagged under strict depth: <one-line reason, e.g. 'structurally central, traces disagree on scope'>"
|
|
255
|
+
```
|
|
256
|
+
3. **Log the auto-flag** in the elicitation state's checkpoint data, the same way `moderate`/`shallow` auto-accepts are logged — this is an automatic decision, not a silent one, and stays auditable exactly like every other gating outcome.
|
|
257
|
+
|
|
258
|
+
Low-risk findings under `strict` are unaffected — they auto-accept exactly as under `moderate`/`shallow`. `strict` only changes what happens to the escalating case.
|
|
259
|
+
|
|
260
|
+
The fixed internal/external question template used whenever `shallow`/`moderate` gating does decide to prompt is `skills/j-uncharted/assets/NODE_QUESTION_TEMPLATE.md` (Step 5, `E40_S06_T03`) — dormant under `strict`, since no prompt ever fires there.
|
|
261
|
+
5. **Confirm/correct, one round per call to `elicitation-state.sh turn`.** Never reached for a `strict`-depth candidate's escalating findings — those converge directly per Step 4 above. For a node requiring confirmation under `shallow`/`moderate`, do **not** present the draft with a fully open-ended "propose understanding, ask to confirm or correct" prompt. Instead use the fixed question set in `skills/j-uncharted/assets/NODE_QUESTION_TEMPLATE.md` (`E40_S06_T03`), selecting the variant by node kind:
|
|
262
|
+
|
|
263
|
+
- **Internal variant** — the node represents the candidate/service itself (the thing this investigation is about).
|
|
264
|
+
- **External variant** — the node represents a dependency or consumer the traces surfaced outside the candidate (something it calls, or something that calls it).
|
|
265
|
+
|
|
266
|
+
Present the drafted node/edge summary from Step 3 first, then ask the selected variant's fixed questions, then offer the same confirm / correct-with-detail / defer-as-unconfirmed / other choice as before (per the Interaction Pattern in `CLAUDE.md`) — the template file spells out both the questions and this response block verbatim, so read it rather than reconstructing either from memory. Each round, call:
|
|
220
267
|
|
|
221
268
|
```bash
|
|
222
269
|
bash skills/j-uncharted/scripts/elicitation-state.sh turn --id <elicitation-id> --node <node-id>
|
|
@@ -233,7 +280,7 @@ Runs once per surviving candidate (a subsystem, a named flow, a directory) after
|
|
|
233
280
|
```
|
|
234
281
|
|
|
235
282
|
Option 3 is the only way past the cap, and it is a per-node, explicit, one-time override — it does not raise the cap for the rest of the run.
|
|
236
|
-
|
|
283
|
+
6. **On convergence** (confirmed, corrected-and-accepted, or resolved via the cap choice above), call:
|
|
237
284
|
|
|
238
285
|
```bash
|
|
239
286
|
bash skills/j-uncharted/scripts/elicitation-state.sh converge --id <elicitation-id> --node <node-id> --note "<one-line summary of what was confirmed>"
|
|
@@ -252,9 +299,9 @@ A whole-codebase `onboard` conversation, or an investigation of a large director
|
|
|
252
299
|
```
|
|
253
300
|
|
|
254
301
|
Idempotent — safe to call again on a resumed `<elicitation-id>` without resetting progress. Choose `<elicitation-id>` so it is stable and re-derivable across sessions (e.g. `onboard-<root-slug>-<date>`, or `segment-investigate-<target-slug>`), since a resuming session must be able to reconstruct it to call `init` again.
|
|
255
|
-
- **`checkpoint` after every converged node
|
|
302
|
+
- **`checkpoint` after every converged node, after the Directory Triage confirmation gate, and after every Familiarity Check answer** — never only at the end. This is what makes a mid-run pause lossless: `checkpoint --id <id> --json <file>` merges arbitrary progress data (triage results, draft nodes not yet converged, per-candidate `verification_depth`, anything else worth surviving a pause) into the state file. `verification_depth` is stored as one object keyed by candidate id — `checkpoint.verification_depth.<candidate-id>` — and, per the script's own merge semantics (see its header), checking one candidate in never clobbers another candidate already recorded there.
|
|
256
303
|
- **`pause` when a session must end before the elicitation has converged.** Immediately after calling `elicitation-state.sh pause --id <elicitation-id>`, write the scrum-master's own `SessionEnd` handoff (per `$([ -f templates/SCRUM_BOARD_SCHEMA.md ] && echo templates/SCRUM_BOARD_SCHEMA.md || echo node_modules/@jenga-ai/agent/templates/SCRUM_BOARD_SCHEMA.md)`'s `handoffs/` convention) with `status: "elicitation_paused"` and both `elicitation_id` and `state_file` set — `hooks/on_session_end.sh` routes that into an `elicitation_resume` trigger on `scrum_triggers.jsonl`, which the next scrum-master session's Drain Scrum Triggers Queue procedure picks up (`agents/scrum-master.md`).
|
|
257
|
-
- **On resume**, read `state_file` directly — every converged node, every flagged node, and the checkpoint data (including the confirmed directory-triage lists) are already there. Do not re-run Directory Triage or re-ask about an already-converged node; resume the Convergence Loop only for nodes still `pending` or explicitly deferred.
|
|
304
|
+
- **On resume**, read `state_file` directly — every converged node, every flagged node, and the checkpoint data (including the confirmed directory-triage lists and any per-candidate `verification_depth` already recorded) are already there. Do not re-run Directory Triage, re-ask the Familiarity Check for a candidate already present under `checkpoint.verification_depth`, or re-ask about an already-converged node; resume the Convergence Loop only for nodes still `pending` or explicitly deferred, and only ask the Familiarity Check for a candidate that has neither.
|
|
258
305
|
- **`complete` when every candidate has converged, been deferred, or been explicitly accepted past the cap.** The state file is left on disk afterward as an audit trail — nothing currently prunes a completed elicitation's state file.
|
|
259
306
|
|
|
260
307
|
---
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
NODE QUESTION TEMPLATE — /uncharted Convergence Loop.
|
|
3
|
+
|
|
4
|
+
Added by E40_S06_T03. Consumed by the Convergence Loop's Step 5
|
|
5
|
+
("Confirm/correct", skills/j-uncharted/SKILL.md) whenever risk-weighted
|
|
6
|
+
gating (Step 4) decides a finding needs a confirm prompt under
|
|
7
|
+
`verification_depth: shallow` or `moderate`. Never reached under `strict`
|
|
8
|
+
— Step 4's strict branch converges the node directly, without ever
|
|
9
|
+
reaching Step 5, so this template is simply not invoked in that case.
|
|
10
|
+
|
|
11
|
+
Two fixed variants, selected by node kind:
|
|
12
|
+
|
|
13
|
+
INTERNAL — the node represents the candidate/service itself (the thing
|
|
14
|
+
`/uncharted` is investigating).
|
|
15
|
+
EXTERNAL — the node represents something outside the candidate that the
|
|
16
|
+
traces surfaced: a dependency it calls, or a consumer that calls it.
|
|
17
|
+
|
|
18
|
+
This replaces a fully open-ended "propose understanding, ask the user to
|
|
19
|
+
confirm or correct it" prompt for any node that fits one of these two
|
|
20
|
+
kinds — which, per the Convergence Loop, is every node this flow drafts.
|
|
21
|
+
Wording is fixed and matches the brainstorm's agreed phrasing verbatim
|
|
22
|
+
(project/documentation/examples/uncharted-conversational-elicitation-procedure.md);
|
|
23
|
+
do not paraphrase it when presenting the prompt.
|
|
24
|
+
|
|
25
|
+
Usage: present the drafted node/edge summary first (per Step 3's draft),
|
|
26
|
+
then ask the questions below for the selected variant, then offer the
|
|
27
|
+
same confirm / correct-with-detail / defer-as-unconfirmed / other choice
|
|
28
|
+
Step 5 already documents. This file supplies the fixed *questions*; the
|
|
29
|
+
response mechanics (turn cap, converge call) are unchanged and live in
|
|
30
|
+
SKILL.md, not here.
|
|
31
|
+
-->
|
|
32
|
+
|
|
33
|
+
# Node Question Template
|
|
34
|
+
|
|
35
|
+
## Internal Node
|
|
36
|
+
|
|
37
|
+
Use when the node represents the candidate/service itself — the thing this investigation is about,
|
|
38
|
+
not something external to it.
|
|
39
|
+
|
|
40
|
+
1. What is this?
|
|
41
|
+
2. What does it do?
|
|
42
|
+
3. Who consumes it?
|
|
43
|
+
4. Other (describe below)
|
|
44
|
+
|
|
45
|
+
## External Node
|
|
46
|
+
|
|
47
|
+
Use when the node represents a dependency or consumer the traces surfaced outside the candidate —
|
|
48
|
+
something the service calls, or something that calls the service.
|
|
49
|
+
|
|
50
|
+
1. What is this?
|
|
51
|
+
2. What does it do?
|
|
52
|
+
3. Is the service producing to it, or consuming from it?
|
|
53
|
+
4. Who is the producer, and who is the consumer?
|
|
54
|
+
5. Other (describe below)
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
After the selected question set, present the standard confirm/correct choice (per the Interaction
|
|
59
|
+
Pattern in `CLAUDE.md` and Convergence Loop Step 5):
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
1. Confirm the draft as accurate
|
|
63
|
+
2. Correct it — describe what's wrong
|
|
64
|
+
3. Defer — mark this node "unconfirmed" for now
|
|
65
|
+
4. Other (describe below)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Silence, a counter-question, or an ambiguous reply is not consent — re-ask, the same convention used
|
|
69
|
+
at every other confirmation gate in this skill.
|
|
@@ -53,7 +53,23 @@
|
|
|
53
53
|
# "nodes": {
|
|
54
54
|
# "<node-id>": { "turns": <int>, "status": "pending"|"converged"|"flagged", "note": "<text>" }
|
|
55
55
|
# },
|
|
56
|
-
# "checkpoint": {
|
|
56
|
+
# "checkpoint": {
|
|
57
|
+
# ...arbitrary, agent-defined fields, e.g. directory-triage results...
|
|
58
|
+
# "verification_depth": {
|
|
59
|
+
# // Recognized field (E40_S06_T01). Per-candidate Familiarity Check
|
|
60
|
+
# // answer from skills/j-uncharted/SKILL.md's Convergence Loop Step 1,
|
|
61
|
+
# // keyed by candidate/node id so a resumed elicitation can tell which
|
|
62
|
+
# // candidates already answered. Values are "shallow" | "moderate" |
|
|
63
|
+
# // "strict". Written and read by the agent driving /uncharted, same
|
|
64
|
+
# // as every other checkpoint field — this script assigns it no
|
|
65
|
+
# // special handling beyond the dict-merge behavior documented under
|
|
66
|
+
# // `checkpoint` below (which exists so that checking in one
|
|
67
|
+
# // candidate's depth never clobbers another's already recorded
|
|
68
|
+
# // here). Consumed by E40_S06_T02's risk-weighted gating; unread by
|
|
69
|
+
# // anything in this script or E40_S06_T01's own scope.
|
|
70
|
+
# "<candidate-id>": "shallow" | "moderate" | "strict"
|
|
71
|
+
# }
|
|
72
|
+
# }
|
|
57
73
|
# }
|
|
58
74
|
#
|
|
59
75
|
# ---------------------------------------------------------------------------
|
|
@@ -79,11 +95,22 @@
|
|
|
79
95
|
# the node's note (e.g. a one-line summary of what was confirmed).
|
|
80
96
|
#
|
|
81
97
|
# checkpoint --id ID --json FILE
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
#
|
|
98
|
+
# Merge the JSON object in FILE (or stdin when FILE is "-") into the
|
|
99
|
+
# state's top-level "checkpoint" field. New keys are added; existing
|
|
100
|
+
# keys are overwritten by the new value — EXCEPT when both the existing
|
|
101
|
+
# value and the new value for a given key are themselves JSON objects,
|
|
102
|
+
# in which case they are merged one level deep instead of one replacing
|
|
103
|
+
# the other (existing sub-keys are kept, new sub-keys are added,
|
|
104
|
+
# conflicting sub-keys take the new value). This one-level dict merge
|
|
105
|
+
# is what lets a map-shaped field addressed by its own sub-keys — e.g.
|
|
106
|
+
# "verification_depth", keyed per candidate id (E40_S06_T01) — accumulate
|
|
107
|
+
# entries across separate checkpoint calls instead of each call
|
|
108
|
+
# clobbering every entry a previous call wrote. Plain (non-dict)
|
|
109
|
+
# values — strings, numbers, lists, directory-triage's own arrays —
|
|
110
|
+
# still simply overwrite, exactly as before this addition. This is the
|
|
111
|
+
# generic "save progress" primitive — directory-triage results, draft
|
|
112
|
+
# node content, anything else the flow wants durable before it might
|
|
113
|
+
# pause.
|
|
87
114
|
#
|
|
88
115
|
# pause --id ID
|
|
89
116
|
# Set status "paused" and update "updated_at". The caller (the agent
|
|
@@ -422,7 +449,18 @@ elif subcommand == "checkpoint":
|
|
|
422
449
|
state = load()
|
|
423
450
|
payload = json.loads(checkpoint_json)
|
|
424
451
|
cp = state.setdefault("checkpoint", {})
|
|
425
|
-
|
|
452
|
+
# One-level-deep merge when both sides are dicts (E40_S06_T01) — lets a
|
|
453
|
+
# map-shaped field keyed by its own sub-keys (e.g. verification_depth,
|
|
454
|
+
# keyed per candidate id) accumulate entries across separate checkpoint
|
|
455
|
+
# calls instead of each call replacing the whole field. Anything else
|
|
456
|
+
# (strings, numbers, lists, or a dict landing on a non-dict/absent key)
|
|
457
|
+
# keeps the prior plain overwrite behavior.
|
|
458
|
+
for key, value in payload.items():
|
|
459
|
+
existing = cp.get(key)
|
|
460
|
+
if isinstance(existing, dict) and isinstance(value, dict):
|
|
461
|
+
existing.update(value)
|
|
462
|
+
else:
|
|
463
|
+
cp[key] = value
|
|
426
464
|
state["updated_at"] = now
|
|
427
465
|
atomic_write(state)
|
|
428
466
|
result = {"checkpoint_keys": list(payload.keys())}
|
|
@@ -461,18 +461,30 @@ if [ -n "${JENGA_PLAYBOOKS_TEST_ROOT:-}" ]; then
|
|
|
461
461
|
# E53_S05_T01 to also cover playbook-config.json resolution). Never set in a real invocation.
|
|
462
462
|
PKG_ROOT="$JENGA_PLAYBOOKS_TEST_ROOT"
|
|
463
463
|
PROJECT_DIR="$JENGA_PLAYBOOKS_TEST_ROOT"
|
|
464
|
-
# Resolve the jenga-agent PACKAGE root (where the canonical skills/ tree actually lives) — same
|
|
465
|
-
# monorepo-checkout vs. installed-npm-package detection used by
|
|
466
|
-
# skills/jenga/scripts/load-nl-catalog.sh's PKG_ROOT resolution and skills/init/scripts/init.sh.
|
|
467
|
-
elif [ -d "$SCRIPT_DIR/../../../templates" ]; then
|
|
468
|
-
PKG_ROOT="$SCRIPT_DIR/../../.."
|
|
469
|
-
PROJECT_DIR="${JENGA_PROJECT_DIR:-${CLAUDE_PROJECT_DIR:-$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || pwd)}}"
|
|
470
|
-
elif [ -n "${CLAUDE_PROJECT_DIR:-}" ] && [ -d "${CLAUDE_PROJECT_DIR}/node_modules/@jenga-ai/agent/templates" ]; then
|
|
471
|
-
PKG_ROOT="${CLAUDE_PROJECT_DIR}/node_modules/@jenga-ai/agent"
|
|
472
|
-
PROJECT_DIR="${JENGA_PROJECT_DIR:-$CLAUDE_PROJECT_DIR}"
|
|
473
464
|
else
|
|
474
|
-
|
|
475
|
-
|
|
465
|
+
# Resolve JENGA_PROJECT_DIR the same way every other script in skills/jenga/scripts/ does.
|
|
466
|
+
if [ -f "$SCRIPT_DIR/../../../lib/resolve-project-dir.sh" ]; then
|
|
467
|
+
# shellcheck source=/dev/null
|
|
468
|
+
source "$SCRIPT_DIR/../../../lib/resolve-project-dir.sh"
|
|
469
|
+
elif [ -n "${CLAUDE_PROJECT_DIR:-}" ]; then
|
|
470
|
+
JENGA_PROJECT_DIR="$CLAUDE_PROJECT_DIR"
|
|
471
|
+
else
|
|
472
|
+
JENGA_PROJECT_DIR="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
473
|
+
fi
|
|
474
|
+
|
|
475
|
+
# Resolve the jenga-agent PACKAGE root (where the canonical skills/ tree actually lives) — same
|
|
476
|
+
# monorepo-checkout vs. installed-npm-package detection used by
|
|
477
|
+
# skills/jenga/scripts/load-nl-catalog.sh's PKG_ROOT resolution and skills/init/scripts/init.sh.
|
|
478
|
+
if [ -d "$SCRIPT_DIR/../../../templates" ]; then
|
|
479
|
+
PKG_ROOT="$SCRIPT_DIR/../../.."
|
|
480
|
+
PROJECT_DIR="$JENGA_PROJECT_DIR"
|
|
481
|
+
elif [ -d "$JENGA_PROJECT_DIR/node_modules/@jenga-ai/agent/templates" ]; then
|
|
482
|
+
PKG_ROOT="$JENGA_PROJECT_DIR/node_modules/@jenga-ai/agent"
|
|
483
|
+
PROJECT_DIR="$JENGA_PROJECT_DIR"
|
|
484
|
+
else
|
|
485
|
+
echo "Error: could not locate the jenga-agent package root (templates/ not found via monorepo checkout or node_modules/@jenga-ai/agent)." >&2
|
|
486
|
+
exit 2
|
|
487
|
+
fi
|
|
476
488
|
fi
|
|
477
489
|
|
|
478
490
|
PLAYBOOKS_DIR="$PKG_ROOT/skills/jenga/playbooks"
|