@jenga-ai/agent 3.1.0 → 3.2.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 +3 -3
- package/agents/developer.md +15 -15
- package/agents/scrum-master.md +17 -17
- package/agents/tester.md +25 -15
- package/lib/skill-allow-list.json +3 -2
- package/package.json +1 -1
- package/scripts/audit-twin-divergence.sh +625 -0
- package/scripts/build-pages-site.sh +268 -0
- package/scripts/check-public-playbook-steps.sh +136 -0
- package/skills/j-close-story/SKILL.md +1 -1
- package/skills/j-do/SKILL.md +19 -19
- package/skills/j-doc-sync/SKILL.md +12 -1
- package/skills/j-idea/SKILL.md +1 -1
- package/skills/j-init/SKILL.md +5 -4
- package/skills/j-init/assets/directory_structure.txt +1 -0
- package/skills/j-init/scripts/detect-existing-codebase.sh +2 -2
- package/skills/j-init/scripts/init.sh +13 -2
- package/skills/j-playbook/SKILL.md +81 -0
- package/skills/j-proceed/SKILL.md +1 -1
- package/skills/j-publish/SKILL.md +1 -1
- package/skills/j-publish/adapters/npm-ci.md +29 -0
- package/skills/j-publish/scripts/npm_ci_pipeline.sh +3 -0
- package/skills/j-publish/scripts/npm_pipeline.sh +18 -0
- package/skills/j-publish/scripts/npm_stage_pipeline.sh +81 -41
- package/skills/j-reconcile/SKILL.md +1 -0
- package/skills/j-redo/SKILL.md +1 -1
- package/skills/j-status/SKILL.md +12 -0
- package/skills/j-todo/SKILL.md +2 -2
- package/skills/j-uncharted/SKILL.md +8 -7
- package/skills/j-uncharted/scripts/elicitation-state.sh +15 -1
- package/skills/j-uncharted/scripts/validate-proposed-items.sh +18 -2
- package/skills/jenga/SKILL.md +80 -9
- package/skills/jenga/playbooks/idea-to-committed.json +20 -0
- package/skills/jenga/playbooks/schema.json +42 -0
- package/skills/jenga/scripts/detect-nl-intent.sh +179 -0
- package/skills/jenga/scripts/load-nl-catalog.js +206 -0
- package/skills/jenga/scripts/load-nl-catalog.sh +65 -0
- package/skills/jenga/scripts/load-playbooks.sh +1022 -0
- package/skills/jenga/scripts/match-playbook.sh +262 -0
- package/skills/jenga/scripts/render-playbook-confirmation.sh +517 -0
- package/skills/jenga/scripts/run-playbook-step.sh +766 -0
- package/skills/jenga-permission-level/SKILL.md +4 -4
- package/templates/KNOWLEDGE_GRAPH_STUB_SCHEMA_TEMPLATE.md +128 -0
- package/templates/playbook-types.json +8 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: j.playbook
|
|
3
|
+
description: Invoke a specific /jenga playbook directly by ID, skipping natural-language matching entirely and going straight to chain confirmation and execution.
|
|
4
|
+
keywords:
|
|
5
|
+
- run playbook
|
|
6
|
+
- invoke playbook by id
|
|
7
|
+
- playbook direct
|
|
8
|
+
- execute playbook
|
|
9
|
+
examples:
|
|
10
|
+
- "j.playbook brainstorm-to-mirror"
|
|
11
|
+
- "run the understand-then-ship playbook"
|
|
12
|
+
- "invoke playbook by id"
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Playbook — Direct Playbook Invocation by ID
|
|
16
|
+
|
|
17
|
+
## Purpose
|
|
18
|
+
|
|
19
|
+
`/jenga`'s natural-language branch (`skills/jenga/SKILL.md`) proposes a playbook only when
|
|
20
|
+
free-text intent doesn't cleanly resolve to a single skill and `skills/jenga/scripts/match-playbook.sh`
|
|
21
|
+
finds a confident match. That's the right default when the user doesn't know a playbook exists or
|
|
22
|
+
doesn't know its exact id. `j.playbook <id>` is the other case: the user already knows exactly
|
|
23
|
+
which playbook they want and names it directly — this skill skips `detect-nl-intent.sh` and
|
|
24
|
+
`match-playbook.sh` entirely and goes straight to the same confirmation-and-execution machinery
|
|
25
|
+
`/jenga`'s natural-language branch already uses (`E53_S06_T03`, per story `E53_S06`'s fourth and
|
|
26
|
+
fifth Acceptance Criteria).
|
|
27
|
+
|
|
28
|
+
This skill never re-implements chain confirmation, sequential execution, `forward_from`/`resolve`
|
|
29
|
+
resolution, or composition/conditional handling — all of that is `skills/jenga/SKILL.md`'s
|
|
30
|
+
Natural-language branch steps 5a-5e, reused here by reference. The only genuinely new logic in
|
|
31
|
+
this skill is id resolution (step 1 below).
|
|
32
|
+
|
|
33
|
+
## Instructions
|
|
34
|
+
|
|
35
|
+
1. **Resolve the id** — invoke `skills/jenga/scripts/load-playbooks.sh lookup "<id>"`
|
|
36
|
+
(`E53_S06_T02`), where `<id>` is this skill's argument. Branch on the returned `status` field:
|
|
37
|
+
|
|
38
|
+
- **`"not_found"`** — no playbook with that id exists. Tell the user plainly that no such
|
|
39
|
+
playbook was found. As a "did you mean" nudge, you may additionally invoke
|
|
40
|
+
`skills/jenga/scripts/load-playbooks.sh` (no arguments, full-catalog mode) and list the
|
|
41
|
+
available `id`s from its output — use your judgment on whether this is helpful given the
|
|
42
|
+
specific id the user typed. Halt this invocation; do not proceed to step 2.
|
|
43
|
+
- **`"invalid"`** — a file for that id exists but failed load-time validation. Report the
|
|
44
|
+
`reason` field to the user **verbatim** — never a generic "not found" message, since this is
|
|
45
|
+
a materially different situation from `not_found` (the story's explicit distinguishing
|
|
46
|
+
requirement, `E53_S06_T02`). Halt this invocation; do not proceed to step 2.
|
|
47
|
+
- **`"valid"`** — continue to step 2, using the returned `playbook` object's `id`, `name`, and
|
|
48
|
+
`steps` fields. This object has the exact same field shape as one entry from
|
|
49
|
+
`load-playbooks.sh`'s full-catalog output — the same shape `match-playbook.sh`'s
|
|
50
|
+
`playbook_match` result carries `id`/`name`/`steps` in, for `/jenga`'s Natural-language
|
|
51
|
+
branch step 5.
|
|
52
|
+
|
|
53
|
+
2. **Confirm and execute the chain** — follow `skills/jenga/SKILL.md`'s Natural-language branch
|
|
54
|
+
**step 5, sub-steps a through e, verbatim** (conditional/origin metadata resolution; render and
|
|
55
|
+
confirm the chain via `render-playbook-confirmation.sh`; the reply loop; sequential-runner
|
|
56
|
+
`init`; the execute-in-a-loop procedure covering skip evaluation, `forward_from`/`resolve`
|
|
57
|
+
resolution (`E53_S06_T01`), invocation, `advance`, and halt handling) exactly as written there
|
|
58
|
+
— do not duplicate that prose here. Use the `id`/`name`/`steps` resolved in step 1 above
|
|
59
|
+
wherever that section refers to `match-playbook.sh`'s `playbook_id`/`name`/`steps` output; every
|
|
60
|
+
other detail (including how `forward_from`, `resolve`, conditionals, and composed/nested steps
|
|
61
|
+
are handled) is identical, with no special-casing for this direct-invocation entry point.
|
|
62
|
+
|
|
63
|
+
The one framing difference: step 5b's confirmation prompt need not (and should not) present
|
|
64
|
+
this as a *proposal* the user might not have expected — they named this playbook explicitly by
|
|
65
|
+
id. Otherwise render, confirm, and execute exactly as that section already does.
|
|
66
|
+
|
|
67
|
+
3. **On a `complete` or `halted` result** (per step 5e-v/5e-vi), report exactly as that section
|
|
68
|
+
already specifies. This skill does not continue into any further phase — there is no `/jenga`
|
|
69
|
+
Phase 1-4 to fall into here, since this is a direct entry point, not `/jenga` itself.
|
|
70
|
+
|
|
71
|
+
## Edge Cases
|
|
72
|
+
|
|
73
|
+
- **The looked-up playbook contains a `resolve` step or composed/nested steps** — handled
|
|
74
|
+
identically to the natural-language path; no special-casing exists or is ever needed here (per
|
|
75
|
+
story `E53_S06`'s fifth Acceptance Criterion).
|
|
76
|
+
- **The user cancels at the chain confirmation step (step 5c)** — identical posture to
|
|
77
|
+
`/jenga`'s own playbook-confirmation cancellation: halt immediately after relaying the
|
|
78
|
+
cancellation acknowledgement, with no step of the chain executed.
|
|
79
|
+
- **`load-playbooks.sh lookup` itself fails unexpectedly (exit code 2, usage/setup error)** — this
|
|
80
|
+
is an environment/setup problem, not a normal `not_found`/`invalid` result; surface the script's
|
|
81
|
+
stderr output to the user rather than treating it as either playbook-lookup outcome.
|
|
@@ -30,7 +30,7 @@ This file is generated/synced by `scripts/generate-j-alias.sh proceed` from `ski
|
|
|
30
30
|
|
|
31
31
|
3. **Determine the next action**:
|
|
32
32
|
- If there are tasks in `Pending` or `In Progress` status that have not yet been assigned to the developer, identify them.
|
|
33
|
-
- If outstanding tasks are ready for implementation, write a session handoff to `project/queue/handoffs/scrum-master-<session_id>-<task_id>.json` (per-session path — see
|
|
33
|
+
- If outstanding tasks are ready for implementation, write a session handoff to `project/queue/handoffs/scrum-master-<session_id>-<task_id>.json` (per-session path — see `$([ -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/` section; use the first task ID, or `batch` if several) with `"status": "planning_complete"` so that `on_session_end.sh` routes them to the developer queue.
|
|
34
34
|
- If all tasks are complete, check for epic/story rollup and update board statuses accordingly.
|
|
35
35
|
|
|
36
36
|
4. **Report** a clear summary to the user: what is done, what is in progress, what is next — and which agent will handle it.
|
|
@@ -261,7 +261,7 @@ Implementation: `bash skills/j-publish/scripts/generate_release_notes.sh [--targ
|
|
|
261
261
|
|
|
262
262
|
Release-note rules:
|
|
263
263
|
- The last publish tag is the highest semver tag on the current branch that also has a matching ledger entry in `project/logs/publish-history.json`.
|
|
264
|
-
- **Default target (no `--output`):** the repo-root `CHANGELOG.md` — created from
|
|
264
|
+
- **Default target (no `--output`):** the repo-root `CHANGELOG.md` — created from `$([ -f templates/CHANGELOG_TEMPLATE.md ] && echo templates/CHANGELOG_TEMPLATE.md || echo node_modules/@jenga-ai/agent/templates/CHANGELOG_TEMPLATE.md)` first if it doesn't exist yet (backward-compat for projects scaffolded before this convention). New Features/Bug Fixes/Other/Completed-task entries since the last publish tag are appended under the existing `## [Unreleased]` heading's subsections; everything else in the file (prior versioned entries, manual edits) is preserved. Entries already present are deduped (matched by commit short-sha or task id), so re-running with no new commits produces zero diff.
|
|
265
265
|
- **`--output <path>`:** writes a standalone, disposable draft to that path instead (the pre-E36 behavior) — `CHANGELOG.md` is not touched in this mode.
|
|
266
266
|
- If no prior ledger-backed tag exists, a `--output` draft includes `> First release — full history included`; the standing `CHANGELOG.md` merge mode has no equivalent banner (it just merges full history into `[Unreleased]` like any other run).
|
|
267
267
|
- Scrum-board enrichment is best-effort only; missing or unreadable board data never fails the command.
|
|
@@ -240,6 +240,35 @@ automated and human halves of the flow:
|
|
|
240
240
|
`bash skills/j-publish/scripts/npm_stage_inspect.sh approve <stage-id> --otp <otp>`
|
|
241
241
|
from their own machine. `reject` (same script) is available to either
|
|
242
242
|
side to discard a staged candidate.
|
|
243
|
+
- **Stage-id capture reads the CI run's own log, not a local `npm stage
|
|
244
|
+
list` call.** Because the actual `npm stage publish --provenance` call
|
|
245
|
+
runs inside the dispatched Actions run, the local `npm_stage_pipeline.sh`
|
|
246
|
+
process never sees npm's real stage-publish output — `STAGE_OUTPUT` for
|
|
247
|
+
an `npm-ci` target is only ever the fixed dispatch-summary string ("staged
|
|
248
|
+
via GitHub Actions workflow run: `<url>`"). Once `gh run watch` reports
|
|
249
|
+
the run finished successfully, phase 5 instead fetches the full run log
|
|
250
|
+
via `gh run view <run-id> --repo <github_repo> --log` and parses that
|
|
251
|
+
text for a `stage id: ...` line (or a JSON payload), using the same
|
|
252
|
+
parsing logic the `npm` target applies to its local output. **`npm stage
|
|
253
|
+
list ... --json` (the `npm` target's third fallback attempt) is never
|
|
254
|
+
invoked for `npm-ci`** — there is no local npm credential for this target
|
|
255
|
+
type, so a local `npm stage list` call would only ever fail with an
|
|
256
|
+
unrelated auth error.
|
|
257
|
+
- **Manual recovery when the log can't be parsed.** If no stage id can be
|
|
258
|
+
parsed from the run log, `npm_stage_pipeline.sh` exits `3`
|
|
259
|
+
(`EXIT_STAGE_FAILURE`) with a message stating that staging on the
|
|
260
|
+
registry likely **succeeded** — the workflow run itself exited 0, so the
|
|
261
|
+
`npm stage publish --provenance` step almost certainly ran — pointing at
|
|
262
|
+
`gh run view <run-id> --repo <github_repo> --log` (or the printed run
|
|
263
|
+
URL) to find the id by hand in the `npm stage publish` step output, and
|
|
264
|
+
printing an already-filled-in recovery command:
|
|
265
|
+
```
|
|
266
|
+
bash skills/j-publish/scripts/write_ledger_entry.sh <target> npm-ci staged "" \
|
|
267
|
+
--version <version> --config <config> --stage-id <recovered-id> --dist-tag <tag>
|
|
268
|
+
```
|
|
269
|
+
`<target>`, `<version>`, `<config>`, and `<tag>` are the real, already-known
|
|
270
|
+
values for the run that just happened — only `--stage-id` is left for the
|
|
271
|
+
operator to fill in by hand after reading it out of the run log.
|
|
243
272
|
|
|
244
273
|
Same registry-existence precondition as a normal `npm-ci` deploy: staged
|
|
245
274
|
publishing only applies to a package that has already had at least one
|
|
@@ -191,6 +191,9 @@ jobs:
|
|
|
191
191
|
- name: Install dependencies
|
|
192
192
|
run: npm ci
|
|
193
193
|
|
|
194
|
+
- name: Regenerate lib/legacy-shipped-paths.json (E26_S08_T03)
|
|
195
|
+
run: node scripts/generate-legacy-shipped-paths.js || echo "::warning::legacy-shipped-paths generation failed; publishing without an updated list"
|
|
196
|
+
|
|
194
197
|
- name: Publish to npm
|
|
195
198
|
run: npm publish --provenance --access ${NPM_ACCESS} --tag ${DIST_TAG}
|
|
196
199
|
|
|
@@ -207,6 +207,24 @@ if (( DRY_RUN )); then
|
|
|
207
207
|
MODE_LABEL="dry-run"
|
|
208
208
|
fi
|
|
209
209
|
|
|
210
|
+
# Regenerate lib/legacy-shipped-paths.json (E26_S08_T03) — incremental, no-network mode:
|
|
211
|
+
# folds this release's own skills/+agents/ tree into the running cumulative record so the
|
|
212
|
+
# artifact this version SHIPS already reflects what it is about to publish, ready to seed
|
|
213
|
+
# a pre-manifest consumer's first manifest on their NEXT upgrade. Runs on both dry-run and
|
|
214
|
+
# live publish (it only writes a local file, never touches the registry) so a dry-run
|
|
215
|
+
# rehearsal surfaces a generation failure too. Best-effort: a failure here must not block
|
|
216
|
+
# a publish, matching this repo's existing fail-toward-doing-nothing posture for generated
|
|
217
|
+
# artifacts (see lib/generate-skill-allow-list.js's equivalent best-effort call sites).
|
|
218
|
+
GENERATE_LEGACY_PATHS_SCRIPT="$REPO_ROOT/scripts/generate-legacy-shipped-paths.js"
|
|
219
|
+
if [[ -f "$GENERATE_LEGACY_PATHS_SCRIPT" ]]; then
|
|
220
|
+
log_info "Regenerating lib/legacy-shipped-paths.json (incremental, no network)…"
|
|
221
|
+
if ! node "$GENERATE_LEGACY_PATHS_SCRIPT"; then
|
|
222
|
+
log_warn "legacy-shipped-paths generation failed; publishing without an updated list"
|
|
223
|
+
fi
|
|
224
|
+
else
|
|
225
|
+
log_warn "scripts/generate-legacy-shipped-paths.js not found; skipping legacy-paths regeneration"
|
|
226
|
+
fi
|
|
227
|
+
|
|
210
228
|
echo "========== NPM PUBLISH PIPELINE =========="
|
|
211
229
|
printf 'Package: %s\n' "$PACKAGE_NAME"
|
|
212
230
|
printf 'Version: %s\n' "$PACKAGE_VERSION"
|
|
@@ -359,6 +359,32 @@ if (( DRY_RUN )); then
|
|
|
359
359
|
exit 0
|
|
360
360
|
fi
|
|
361
361
|
|
|
362
|
+
# ---------------------------------------------------------------------------
|
|
363
|
+
# Stage-id parsing helper — shared between the `npm` target's locally
|
|
364
|
+
# captured STAGE_OUTPUT and the `npm-ci` target's fetched CI run log. Tries
|
|
365
|
+
# direct-output regex parsing first, then treats the text as JSON. Echoes
|
|
366
|
+
# the recovered id, or nothing if neither matches.
|
|
367
|
+
# ---------------------------------------------------------------------------
|
|
368
|
+
parse_stage_id_from_text() {
|
|
369
|
+
local text="$1"
|
|
370
|
+
local id=""
|
|
371
|
+
|
|
372
|
+
# Direct-output parsing. Tolerant of label variants npm may use
|
|
373
|
+
# ("stage id:", "stageId:", "stage_id="), case-insensitive.
|
|
374
|
+
id="$(printf '%s\n' "${text}" \
|
|
375
|
+
| grep -Eio '\bstage[ _-]?id["'"'"']?[[:space:]]*[:=][[:space:]]*["'"'"']?[A-Za-z0-9._-]+' \
|
|
376
|
+
| head -n 1 \
|
|
377
|
+
| grep -Eo '[A-Za-z0-9._-]+$' || true)"
|
|
378
|
+
|
|
379
|
+
# The text is itself JSON (e.g. if npm's stage publish supports --json the
|
|
380
|
+
# way `npm publish --json` does, or a fenced JSON blob in a CI log).
|
|
381
|
+
if [[ -z "${id}" ]] && printf '%s' "${text}" | jq -e . >/dev/null 2>&1; then
|
|
382
|
+
id="$(printf '%s' "${text}" | jq -r '.id // .stageId // .stage_id // empty' 2>/dev/null || true)"
|
|
383
|
+
fi
|
|
384
|
+
|
|
385
|
+
printf '%s' "${id}"
|
|
386
|
+
}
|
|
387
|
+
|
|
362
388
|
# ---------------------------------------------------------------------------
|
|
363
389
|
# Phase 5: capture — parse the stage id
|
|
364
390
|
# ---------------------------------------------------------------------------
|
|
@@ -366,52 +392,66 @@ log_info "[capture] parsing stage id from stage output..."
|
|
|
366
392
|
|
|
367
393
|
STAGE_ID=""
|
|
368
394
|
|
|
369
|
-
|
|
370
|
-
#
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
#
|
|
377
|
-
#
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
if [[ -z "${STAGE_ID}" ]]; then
|
|
390
|
-
log_warn "could not parse a stage id directly from stage output; falling back to 'npm stage list --json'..."
|
|
391
|
-
|
|
392
|
-
LIST_STATUS=0
|
|
393
|
-
LIST_OUTPUT="$(npm stage list "${PACKAGE_NAME}" --json 2>&1)" || LIST_STATUS=$?
|
|
394
|
-
|
|
395
|
-
if [[ ${LIST_STATUS} -ne 0 ]]; then
|
|
396
|
-
printf '%s\n' "${LIST_OUTPUT}" >&2
|
|
397
|
-
printf 'npm stage pipeline: staged successfully but stage id capture failed (npm stage list also exited %s).\n' "${LIST_STATUS}" >&2
|
|
395
|
+
if [[ "${TARGET_TYPE}" == "npm-ci" ]]; then
|
|
396
|
+
# STAGE_OUTPUT for npm-ci is the fixed one-line dispatch-summary string set
|
|
397
|
+
# in Phase 4 above ("staged via GitHub Actions workflow run: <url>") —
|
|
398
|
+
# never npm's real output — so Attempt 1/2 can never match against it. The
|
|
399
|
+
# actual `npm stage publish --provenance` output (including whatever
|
|
400
|
+
# "stage id: ..." line npm prints) lands in the workflow run's own log
|
|
401
|
+
# instead. Fetch it and apply the same parsing logic used for the `npm`
|
|
402
|
+
# target's local STAGE_OUTPUT. `npm stage list --json` (Attempt 3) is
|
|
403
|
+
# never invoked for npm-ci — there is no local npm auth for this target
|
|
404
|
+
# type, so it would only ever produce a misleading secondary failure.
|
|
405
|
+
log_info "[capture] fetching CI run log for run ${RUN_ID}..."
|
|
406
|
+
CI_LOG_OUTPUT="$(gh run view "${RUN_ID}" --repo "${GITHUB_REPO}" --log 2>&1)" || true
|
|
407
|
+
STAGE_ID="$(parse_stage_id_from_text "${CI_LOG_OUTPUT}")"
|
|
408
|
+
|
|
409
|
+
if [[ -z "${STAGE_ID}" ]]; then
|
|
410
|
+
{
|
|
411
|
+
printf 'npm stage pipeline: the GitHub Actions workflow run completed successfully, so staging on the registry likely SUCCEEDED — but the stage id could not be parsed from the run log.\n'
|
|
412
|
+
printf 'Run "gh run view %s --repo %s --log" (or open %s) to find the "stage id: ..." line by hand in the "npm stage publish" step output, then record it manually:\n' "${RUN_ID}" "${GITHUB_REPO}" "${RUN_URL}"
|
|
413
|
+
printf ' bash skills/j-publish/scripts/write_ledger_entry.sh %s %s staged "" --version %s --config %s --stage-id <recovered-id> --dist-tag %s\n' "${TARGET_NAME}" "${TARGET_TYPE}" "${PACKAGE_VERSION}" "${CONFIG_PATH}" "${DIST_TAG}"
|
|
414
|
+
} >&2
|
|
398
415
|
exit "${EXIT_STAGE_FAILURE}"
|
|
399
416
|
fi
|
|
417
|
+
else
|
|
418
|
+
STAGE_ID="$(parse_stage_id_from_text "${STAGE_OUTPUT}")"
|
|
419
|
+
|
|
420
|
+
# Attempt 3: fall back to `npm stage list <package> --json` and extract the
|
|
421
|
+
# most recent matching entry's id. `npm stage list` rejects a version-
|
|
422
|
+
# qualified spec ("Version specifiers are not supported for listing staged
|
|
423
|
+
# packages") — it only accepts a bare package name — so this must pass
|
|
424
|
+
# PACKAGE_NAME, never PACKAGE_SPEC; the version match happens client-side
|
|
425
|
+
# via jq below instead (confirmed live on jenga-npm during v1.3.0 staging
|
|
426
|
+
# on 2026-09-01, project/todo.md). `npm` target only — npm-ci never
|
|
427
|
+
# reaches here (see the branch above).
|
|
428
|
+
if [[ -z "${STAGE_ID}" ]]; then
|
|
429
|
+
log_warn "could not parse a stage id directly from stage output; falling back to 'npm stage list --json'..."
|
|
430
|
+
|
|
431
|
+
LIST_STATUS=0
|
|
432
|
+
LIST_OUTPUT="$(npm stage list "${PACKAGE_NAME}" --json 2>&1)" || LIST_STATUS=$?
|
|
433
|
+
|
|
434
|
+
if [[ ${LIST_STATUS} -ne 0 ]]; then
|
|
435
|
+
printf '%s\n' "${LIST_OUTPUT}" >&2
|
|
436
|
+
printf 'npm stage pipeline: staged successfully but stage id capture failed (npm stage list also exited %s).\n' "${LIST_STATUS}" >&2
|
|
437
|
+
exit "${EXIT_STAGE_FAILURE}"
|
|
438
|
+
fi
|
|
400
439
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
440
|
+
if printf '%s' "${LIST_OUTPUT}" | jq -e . >/dev/null 2>&1; then
|
|
441
|
+
STAGE_ID="$(printf '%s' "${LIST_OUTPUT}" | jq -r --arg pkg "${PACKAGE_NAME}" --arg ver "${PACKAGE_VERSION}" '
|
|
442
|
+
( if (type == "array") then . else (.stages? // .items? // []) end ) as $entries
|
|
443
|
+
| [ $entries[]? | select(((.name // .package // "") == $pkg) and ((.version // "") == $ver)) ]
|
|
444
|
+
| sort_by(.stagedAt // .staged_at // .created // .createdAt // "")
|
|
445
|
+
| last
|
|
446
|
+
| (.id // .stageId // .stage_id // empty)
|
|
447
|
+
' 2>/dev/null || true)"
|
|
448
|
+
fi
|
|
409
449
|
fi
|
|
410
|
-
fi
|
|
411
450
|
|
|
412
|
-
if [[ -z "${STAGE_ID}" ]]; then
|
|
413
|
-
|
|
414
|
-
|
|
451
|
+
if [[ -z "${STAGE_ID}" ]]; then
|
|
452
|
+
printf 'npm stage pipeline: staged successfully but the stage id could not be captured from either the direct output or "npm stage list --json". Run "npm stage list %s --json" manually to recover it (bare package name — a version-qualified spec is rejected by npm).\n' "${PACKAGE_NAME}" >&2
|
|
453
|
+
exit "${EXIT_STAGE_FAILURE}"
|
|
454
|
+
fi
|
|
415
455
|
fi
|
|
416
456
|
|
|
417
457
|
echo ""
|
|
@@ -3,6 +3,7 @@ name: j.reconcile
|
|
|
3
3
|
description: Polyfill alias of the reconcile skill under a collision-safe directory name. Identical behavior to /reconcile — Reconcile the scrum board with actual implementation state. Cross-checks every task's board status against git history and worktrees, merges orphaned worktree branches, demotes unimplemented "Done" items, promotes secretly-implemented items, flags code with no board provenance and offers /uncharted segment for it, and cleans stale entries from todo.md. Use when the board feels out of sync, after a big merge session, when tasks were completed outside the normal workflow, or when todo.md has grown stale. Trigger on phrases like "sync the board", "clean up the board", "reconcile", "board is out of date", "todo is stale", or "check what's really done". Use when the bare /reconcile form is shadowed by another tool's own built-in command of the same name.
|
|
4
4
|
metadata:
|
|
5
5
|
prefered_agent: scrum-master
|
|
6
|
+
output_types: text
|
|
6
7
|
keywords:
|
|
7
8
|
- j-reconcile
|
|
8
9
|
- polyfill
|
package/skills/j-redo/SKILL.md
CHANGED
|
@@ -45,7 +45,7 @@ If either part is missing, ask the user to provide it before proceeding.
|
|
|
45
45
|
- Run `git --no-pager show <SHA>` to inspect the full diff.
|
|
46
46
|
|
|
47
47
|
**Epic / Story number:**
|
|
48
|
-
- Read the matching file under `$(bash scripts/board_resolver.sh)epics/` or `$(bash scripts/board_resolver.sh)stories/` to understand the scope.
|
|
48
|
+
- Read the matching file under `$(bash "$([ -f scripts/board_resolver.sh ] && echo scripts/board_resolver.sh || echo node_modules/@jenga-ai/agent/scripts/board_resolver.sh)")epics/` or `$(bash "$([ -f scripts/board_resolver.sh ] && echo scripts/board_resolver.sh || echo node_modules/@jenga-ai/agent/scripts/board_resolver.sh)")stories/` to understand the scope.
|
|
49
49
|
- Use `git --no-pager log --all --oneline --grep="<epic or story title>"` to locate related commits and their diffs.
|
|
50
50
|
|
|
51
51
|
Collect the list of **files originally changed** and the **original intent** of the implementation.
|
package/skills/j-status/SKILL.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: j.status
|
|
3
3
|
description: Polyfill alias of the status skill under a collision-safe directory name. Identical behavior to /status — Print a human-readable summary of the entire scrum board — all epics, stories, and tasks with their statuses — plus any open rapports and unprocessed queue triggers. Use when you want a quick overview of project state without reading raw files. Use when the bare /status form is shadowed by another tool's own built-in command of the same name.
|
|
4
|
+
output_types: text
|
|
4
5
|
keywords:
|
|
5
6
|
- status
|
|
6
7
|
- board summary
|
|
@@ -38,3 +39,14 @@ This file is generated/synced by `scripts/generate-j-alias.sh status` from `skil
|
|
|
38
39
|
7. **Print the summary** following the layout and icon conventions in `assets/output_format.md`.
|
|
39
40
|
|
|
40
41
|
8. If no epics exist, print: `No board items found. Run /pi-plan to define epics or /todo to add items.`
|
|
42
|
+
|
|
43
|
+
## Scope note: playbook step status (E53_S04_T03 audit)
|
|
44
|
+
|
|
45
|
+
This skill reports board-level status only (steps 2-4 above: epic/story/task `status` from
|
|
46
|
+
`project/board/`). It never reads or reports `/jenga` playbook run state
|
|
47
|
+
(`skills/jenga/scripts/run-playbook-step.sh`'s temp state file, its `step_ready`/`complete`/
|
|
48
|
+
`halted` reports, or per-step `passed`/`failed`/`skipped` outcomes) — a playbook run is ephemeral,
|
|
49
|
+
session-local execution state, not a board item, and has no representation in
|
|
50
|
+
`project/board/`. This is confirmed as intentional, not a gap: `skipped` is scoped strictly to
|
|
51
|
+
playbook-step context and is never written to a task/story's board-level `status` field (see
|
|
52
|
+
`templates/SCRUM_BOARD_SCHEMA.md`'s Status Values table, unmodified by `E53_S04`).
|
package/skills/j-todo/SKILL.md
CHANGED
|
@@ -53,7 +53,7 @@ When `--trivial` is present, the mission is written as a **fully-formed task boa
|
|
|
53
53
|
|
|
54
54
|
4. **Update project documentation** — Add the mission to the appropriate files under `project/board/epics/` and `project/board/stories/` if applicable.
|
|
55
55
|
- If the mission involves implementing or modifying a skill, apply the **Skill Implementation Principle — Scripts Over Inline Logic** (see `CLAUDE.md` / `AGENTS.md`): note in the story/task's acceptance criteria that deterministic, repeatable steps must be offloaded to scripts under `skills/<name>/scripts/` (or `scripts/`) rather than encoded as inline agent instructions in `SKILL.md`.
|
|
56
|
-
- If the user indicates the mission is high-risk, or explicitly asks to flag it, set an elevated caution tier directly on the story or task frontmatter: `crucial_level` (one of `advisory`, `gated`, `locked` — see
|
|
56
|
+
- If the user indicates the mission is high-risk, or explicitly asks to flag it, set an elevated caution tier directly on the story or task frontmatter: `crucial_level` (one of `advisory`, `gated`, `locked` — see `$([ -f templates/SCRUM_BOARD_SCHEMA.md ] && echo templates/SCRUM_BOARD_SCHEMA.md || echo node_modules/@jenga-ai/agent/templates/SCRUM_BOARD_SCHEMA.md)` for valid values and their meaning), `crucial_set_by: user`, and `crucial_note` capturing the user's stated reason. This user-initiated flag is written immediately — it does not require the confirm-before-write gate, which applies only to scrum-master-*proposed* caution tiers (a separate, heuristic-driven path).
|
|
57
57
|
|
|
58
58
|
4.5. **If `--trivial` was passed, create the task now** (skip step 5 — this step writes the todo.md entry itself):
|
|
59
59
|
|
|
@@ -81,7 +81,7 @@ When `--trivial` is present, the mission is written as a **fully-formed task boa
|
|
|
81
81
|
|
|
82
82
|
5. **Add to `project/todo.md`** by running (skip this step if step 4.5 already ran):
|
|
83
83
|
```
|
|
84
|
-
bash scripts/todo_manager.sh add '<mission title>: <Epic no.>_<Story no.>'
|
|
84
|
+
bash "$([ -f scripts/todo_manager.sh ] && echo scripts/todo_manager.sh || echo node_modules/@jenga-ai/agent/scripts/todo_manager.sh)" add '<mission title>: <Epic no.>_<Story no.>'
|
|
85
85
|
```
|
|
86
86
|
The epic and story reference is only required if the mission is assigned to one.
|
|
87
87
|
|
|
@@ -3,6 +3,7 @@ name: j.uncharted
|
|
|
3
3
|
description: Polyfill alias of the uncharted skill under a collision-safe directory name. Identical behavior to /uncharted — Investigate code that has no Jenga board provenance — a foreign file, an external source being pulled in, or an entire pre-existing codebase — and give it a consistent understanding document plus proper board representation. Use when the bare /uncharted form is shadowed by another tool's own built-in command of the same name.
|
|
4
4
|
metadata:
|
|
5
5
|
prefered_agent: scrum-master
|
|
6
|
+
output_types: text
|
|
6
7
|
keywords:
|
|
7
8
|
- "uncharted"
|
|
8
9
|
- "foreign code"
|
|
@@ -117,7 +118,7 @@ Every mode produces exactly one document per target, rendered from `skills/j-unc
|
|
|
117
118
|
|
|
118
119
|
**Where it goes:** `project/rapports/analysis/`, named `uncharted-<mode>-<slug>-<YYYYMMDDTHHMMSSZ>.md`. Nothing is ever overwritten — a name collision gets a `-2`, `-3`… suffix, so repeated runs against one target leave a diffable history.
|
|
119
120
|
|
|
120
|
-
This reuses the **existing `analysis` rapport type** already defined in
|
|
121
|
+
This reuses the **existing `analysis` rapport type** already defined in `$([ -f templates/SCRUM_BOARD_SCHEMA.md ] && echo templates/SCRUM_BOARD_SCHEMA.md || echo node_modules/@jenga-ai/agent/templates/SCRUM_BOARD_SCHEMA.md)`. `/uncharted` introduces **no new rapport type** — if a change to the rapport taxonomy ever seems necessary, that is a schema change to be raised with the scrum-master, not something this skill invents.
|
|
121
122
|
|
|
122
123
|
**Fixed structure** — seven headings, never added to, removed, reordered, or renamed, because downstream steps read the document by heading:
|
|
123
124
|
|
|
@@ -157,7 +158,7 @@ A document whose judgement sections are generic enough to apply to any codebase
|
|
|
157
158
|
|
|
158
159
|
Since **E20_S08_T03**, `onboard`'s default behavior and `segment --mode investigate` both run a human-in-the-loop **conversational elicitation** instead of (or, for `onboard`, in addition to keeping available) a one-shot deterministic pass. This section defines the mechanics shared by both; each mode's own subsection below only describes what is specific to it.
|
|
159
160
|
|
|
160
|
-
**What conversational elicitation produces, and how that differs from the Understanding Document above:** the **primary** output is coarse-tier graph nodes/edges — written directly to `project/knowledge-graph/graph.json`, conforming to the stub schema at `project/knowledge-graph/STUB_SCHEMA.md` (E20_S08_T01; this is a throwaway pilot schema, swapped wholesale once E20_S01's real schema lands — do not extend it expecting stability). Every node this flow writes carries `source: "human"`, since it comes from a person confirming or correcting a proposed understanding, not from mechanical extraction. Board representation is a `[ARCH]`-tagged epic, story, or task at whichever level fits the investigated scope (see
|
|
161
|
+
**What conversational elicitation produces, and how that differs from the Understanding Document above:** the **primary** output is coarse-tier graph nodes/edges — written directly to `project/knowledge-graph/graph.json`, conforming to the stub schema at `project/knowledge-graph/STUB_SCHEMA.md` (E20_S08_T01; this is a throwaway pilot schema, swapped wholesale once E20_S01's real schema lands — do not extend it expecting stability). Every node this flow writes carries `source: "human"`, since it comes from a person confirming or correcting a proposed understanding, not from mechanical extraction. Board representation is a `[ARCH]`-tagged epic, story, or task at whichever level fits the investigated scope (see `$([ -f templates/SCRUM_BOARD_SCHEMA.md ] && echo templates/SCRUM_BOARD_SCHEMA.md || echo node_modules/@jenga-ai/agent/templates/SCRUM_BOARD_SCHEMA.md)`'s `[ARCH]` — Durable Architectural Inventory convention) — **not** the delivery-shaped epic/story/task proposal `segment --mode delivery` and legacy `onboard` produce, and not the fixed 7-heading Understanding Document either. A written summary is produced only when warranted, filed as the resulting board item's ordinary `-summary.md` — there is no new artifact type or separate "Understanding Document" for conversational output.
|
|
161
162
|
|
|
162
163
|
### Human-Oracle-Availability Limitation
|
|
163
164
|
|
|
@@ -252,7 +253,7 @@ A whole-codebase `onboard` conversation, or an investigation of a large director
|
|
|
252
253
|
|
|
253
254
|
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.
|
|
254
255
|
- **`checkpoint` after every converged node and after the Directory Triage confirmation gate** — 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, anything else worth surviving a pause) into the state file.
|
|
255
|
-
- **`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
|
|
256
|
+
- **`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`).
|
|
256
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.
|
|
257
258
|
- **`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.
|
|
258
259
|
|
|
@@ -341,7 +342,7 @@ A new epic is the last option, not the default, and needs a stated reason. Recor
|
|
|
341
342
|
|
|
342
343
|
**Step 5 — Draft the proposal** using `skills/j-uncharted/assets/SEGMENT_PROPOSAL_TEMPLATE.md`. Its six headings are fixed; fill every one of them. Two things it will not let you skip:
|
|
343
344
|
|
|
344
|
-
- **Every proposed task carries `execution_scope` and a non-empty `scope_rationale`** containing a file-count or line-count claim, assigned against `project/configs/scope-thresholds.json` rather than by feel — `inline` at or under 1 file / 20 lines, `story` when tasks share files across the story (up to 5 files), `task` otherwise. Never self-assign `execution_scope: epic`: it requires `epic_scope_approval: true`, which only a human sets. Propose `story` and say the task looks bigger instead. Field semantics live in
|
|
345
|
+
- **Every proposed task carries `execution_scope` and a non-empty `scope_rationale`** containing a file-count or line-count claim, assigned against `project/configs/scope-thresholds.json` rather than by feel — `inline` at or under 1 file / 20 lines, `story` when tasks share files across the story (up to 5 files), `task` otherwise. Never self-assign `execution_scope: epic`: it requires `epic_scope_approval: true`, which only a human sets. Propose `story` and say the task looks bigger instead. Field semantics live in `$([ -f templates/SCRUM_BOARD_SCHEMA.md ] && echo templates/SCRUM_BOARD_SCHEMA.md || echo node_modules/@jenga-ai/agent/templates/SCRUM_BOARD_SCHEMA.md)` — read them there, do not paraphrase them here.
|
|
345
346
|
- **The document's `Open Questions` carry over verbatim**, not re-derived, each with who can answer it and whether it blocks confirmation. A blocking question is resolved *before* the proposal is accepted, because the breakdown depends on its answer.
|
|
346
347
|
- **Propose everything the board file will contain**, not just titles. Each story's Acceptance Criteria and Definition of Done are proposed at the gate, and a new epic's Purpose and Definition of Done with it — `scripts/validate-story-format.sh` requires those sections, so anything missing here is text `E40_S02_T03` would have to invent after the user has already said yes.
|
|
347
348
|
|
|
@@ -367,7 +368,7 @@ Options 2 and 3 loop back to Step 5 (or to Step 4 for a re-parent) and re-presen
|
|
|
367
368
|
|
|
368
369
|
The proposal is the input and the **only** source of content. Everything the board files contain — the epic's Purpose and Definition of Done, each story's `As a …, I want …, so that …` line, Acceptance Criteria, and Definition of Done, each task's `execution_scope` and `scope_rationale` — was proposed at the gate and is transcribed **verbatim**. Nothing is composed, expanded, or improved at write time. If a field looks wrong now, that is a revision (option 2), not an edit in passing: text the user did not read has no business on the board, which is the whole point of the gate.
|
|
369
370
|
|
|
370
|
-
Shape, field names, and file naming come from
|
|
371
|
+
Shape, field names, and file naming come from `$([ -f templates/SCRUM_BOARD_SCHEMA.md ] && echo templates/SCRUM_BOARD_SCHEMA.md || echo node_modules/@jenga-ai/agent/templates/SCRUM_BOARD_SCHEMA.md)`. Read them there — do not paraphrase them here. Five things it will not let you skip:
|
|
371
372
|
|
|
372
373
|
- **Parent before child.** Epic (if new), then stories, then tasks. The schema's Linking Convention makes the epic's `stories[]` and each story's `tasks[]` the authoritative index, so a child written before its parent leaves an index nobody has updated.
|
|
373
374
|
- **IDs continue the sequence they belong to.** `E##` is the next free epic number board-wide, but `S##` is the next free story number **within its parent epic** and `T##` the next free task number **within its parent story** — that is what the `E##_S##_T##` shape means. Story numbers restarting per epic is normal and expected, not a collision. Nothing catches an error here: `validate-board.sh` checks an ID's *shape*, never its uniqueness or its sequence, so a well-formed wrong number passes every gate in Step 7 and quietly reuses an ID that already meant something else.
|
|
@@ -387,7 +388,7 @@ It runs `scripts/validate-board.sh` over every file and `scripts/validate-story-
|
|
|
387
388
|
|
|
388
389
|
On success, tell the user exactly which files were created, with their IDs.
|
|
389
390
|
|
|
390
|
-
**Step 8 — Hand off to the standard path.** Queue each new task with the canonical todo owner —
|
|
391
|
+
**Step 8 — Hand off to the standard path.** Queue each new task with the canonical todo owner — `` bash "$([ -f scripts/todo_manager.sh ] && echo scripts/todo_manager.sh || echo node_modules/@jenga-ai/agent/scripts/todo_manager.sh)" add "<entry>" ``, one call per task, referencing the task ID — and the work then proceeds through the ordinary `/todo` → `/do` → developer → tester path, with no special casing anywhere along it. Point the tasks' Description at the understanding document from Step 2; it is the context the developer picking one up would otherwise lack.
|
|
391
392
|
|
|
392
393
|
**`/uncharted` writes board files and stops there.** It does not adapt the segment to project conventions, edit or move the code it just analysed, open a worktree, or write an execution plan. That is ordinary developer work, driven by ordinary task files, and it is the developer agent's job — the same as for a task that came from `/brainstorm` or `/pi-plan`. A segment that has reached the board is no longer a special case, and this skill growing its own integration path would be a second, divergent execution route for work the existing one already handles.
|
|
393
394
|
|
|
@@ -712,7 +713,7 @@ re-running `onboard` with a higher `--cap`.
|
|
|
712
713
|
Live as of `E40_S04_T04`. `skills/j-uncharted/scripts/write-backfilled-epics.sh` is the only thing
|
|
713
714
|
that actually writes backfilled epics to the board — it consumes `apply-subsystem-cap.sh`'s
|
|
714
715
|
`kept` array and renders one epic file per entry, following the Epic format in
|
|
715
|
-
|
|
716
|
+
`$([ -f templates/SCRUM_BOARD_SCHEMA.md ] && echo templates/SCRUM_BOARD_SCHEMA.md || echo node_modules/@jenga-ai/agent/templates/SCRUM_BOARD_SCHEMA.md)` exactly (`provenance: backfilled`, `status: Pending`, an empty
|
|
716
717
|
`stories` array, a Purpose section built from the discovery evidence, and a Definition of Done
|
|
717
718
|
framed around understanding and integration, never original construction):
|
|
718
719
|
|
|
@@ -151,7 +151,21 @@ if [ -z "$REPO_ROOT" ]; then
|
|
|
151
151
|
exit 2
|
|
152
152
|
fi
|
|
153
153
|
|
|
154
|
-
|
|
154
|
+
# ─── Resolve with-lock.sh's package root ──────────────────────────────────
|
|
155
|
+
# postinstall.js mirrors only skills/ and agents/ into a consumer's .claude/
|
|
156
|
+
# and .agents/ — scripts/ (which owns with-lock.sh) is never copied there, so
|
|
157
|
+
# this script — itself shipped under skills/j-uncharted/scripts/ and mirrored
|
|
158
|
+
# alongside it — cannot assume "$REPO_ROOT/scripts/with-lock.sh" exists.
|
|
159
|
+
# Mirrors skills/init/scripts/init.sh's PKG_ROOT fallback: prefer a monorepo
|
|
160
|
+
# checkout's sibling scripts/ dir, else fall back to the installed npm
|
|
161
|
+
# package under node_modules/@jenga-ai/agent.
|
|
162
|
+
if [ -f "$SCRIPT_DIR/../../../scripts/with-lock.sh" ]; then
|
|
163
|
+
WITH_LOCK="$SCRIPT_DIR/../../../scripts/with-lock.sh"
|
|
164
|
+
elif [ -f "$REPO_ROOT/node_modules/@jenga-ai/agent/scripts/with-lock.sh" ]; then
|
|
165
|
+
WITH_LOCK="$REPO_ROOT/node_modules/@jenga-ai/agent/scripts/with-lock.sh"
|
|
166
|
+
else
|
|
167
|
+
WITH_LOCK="$REPO_ROOT/scripts/with-lock.sh"
|
|
168
|
+
fi
|
|
155
169
|
STATE_DIR="$REPO_ROOT/project/queue/elicitation-state"
|
|
156
170
|
DEFAULT_CAP=5
|
|
157
171
|
|
|
@@ -48,8 +48,24 @@ SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)
|
|
|
48
48
|
REPO_ROOT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || true)
|
|
49
49
|
[ -n "$REPO_ROOT" ] || REPO_ROOT=$(cd -- "$SCRIPT_DIR/../../.." && pwd -P)
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
# ─── Resolve the validators' package root ─────────────────────────────────
|
|
52
|
+
# postinstall.js mirrors only skills/ and agents/ into a consumer's .claude/
|
|
53
|
+
# and .agents/ — scripts/ (which owns both validators) is never copied there,
|
|
54
|
+
# so this script — itself shipped under skills/j-uncharted/scripts/ and mirrored
|
|
55
|
+
# alongside it — cannot assume "$REPO_ROOT/scripts/..." exists. Mirrors
|
|
56
|
+
# skills/init/scripts/init.sh's PKG_ROOT fallback (same pattern already
|
|
57
|
+
# applied to this skill's elicitation-state.sh WITH_LOCK resolution): prefer
|
|
58
|
+
# a monorepo checkout's sibling scripts/ dir, else fall back to the installed
|
|
59
|
+
# npm package under node_modules/@jenga-ai/agent.
|
|
60
|
+
if [ -f "$SCRIPT_DIR/../../../scripts/validate-board.sh" ]; then
|
|
61
|
+
VALIDATOR_ROOT="$SCRIPT_DIR/../../../scripts"
|
|
62
|
+
elif [ -f "$REPO_ROOT/node_modules/@jenga-ai/agent/scripts/validate-board.sh" ]; then
|
|
63
|
+
VALIDATOR_ROOT="$REPO_ROOT/node_modules/@jenga-ai/agent/scripts"
|
|
64
|
+
else
|
|
65
|
+
VALIDATOR_ROOT="$REPO_ROOT/scripts"
|
|
66
|
+
fi
|
|
67
|
+
BOARD_VALIDATOR="$VALIDATOR_ROOT/validate-board.sh"
|
|
68
|
+
STORY_VALIDATOR="$VALIDATOR_ROOT/validate-story-format.sh"
|
|
53
69
|
|
|
54
70
|
usage() {
|
|
55
71
|
echo "Usage: $(basename "$0") <board-file> [more-files...]" >&2
|