@jenga-ai/agent 2.0.0 → 3.1.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 +82 -243
- package/agents/developer.md +5 -5
- package/agents/scrum-master.md +23 -23
- package/agents/tester.md +5 -5
- package/bin/jenga.js +10 -0
- package/hooks/copilot_session_end.sh +7 -3
- package/hooks/prompt_router_helper.js +17 -5
- package/lib/commands/doctor.js +351 -0
- package/lib/commands/init.js +16 -0
- package/lib/generate-copilot-hooks.js +116 -0
- package/lib/generate-skill-allow-list.js +9 -3
- package/lib/legacy-shipped-paths.json +336 -0
- package/lib/postinstall-manifest.js +469 -0
- package/lib/skill-allow-list.json +2 -3
- package/package.json +16 -25
- package/scripts/apply-j-prefix.sh +25 -12
- package/scripts/generate-j-alias.sh +333 -0
- package/scripts/generate-legacy-shipped-paths.js +248 -0
- package/scripts/postinstall.js +205 -2
- package/scripts/verify-legacy-seed-reconcile.sh +254 -0
- package/scripts/verify-postinstall-reconcile.sh +392 -0
- package/skills/{brainstorm → j-brainstorm}/SKILL.md +9 -2
- package/skills/{btw → j-btw}/SKILL.md +9 -2
- package/skills/{clearify → j-clearify}/SKILL.md +9 -2
- package/skills/{close-story → j-close-story}/SKILL.md +17 -10
- package/skills/{close-story → j-close-story}/scripts/check-privatized.sh +2 -2
- package/skills/{close-story → j-close-story}/scripts/check-story-closeable.sh +1 -1
- package/skills/{close-story → j-close-story}/scripts/extract-task-diff-stats.sh +1 -1
- package/skills/{commit → j-commit}/SKILL.md +9 -2
- package/skills/j-continue/SKILL.md +36 -0
- package/skills/{deep-dive → j-deep-dive}/SKILL.md +9 -8
- package/skills/{dev-done → j-dev-done}/SKILL.md +11 -4
- package/skills/{dev-done → j-dev-done}/scripts/classify-commit-outcome.sh +4 -4
- package/skills/{distribute → j-distribute}/SKILL.md +17 -10
- package/skills/{distribute → j-distribute}/scripts/distribute-changes.sh +1 -1
- package/skills/{do → j-do}/SKILL.md +12 -5
- package/skills/{doc → j-doc}/README.md +5 -5
- package/skills/{doc → j-doc}/SKILL.md +15 -8
- package/skills/{doc → j-doc}/authoring-notes.md +1 -1
- package/skills/{doc-sync → j-doc-sync}/SKILL.md +9 -2
- package/skills/{dooo → j-dooo}/SKILL.md +9 -2
- package/skills/j-error/SKILL.md +36 -0
- package/skills/{evaluate → j-evaluate}/SKILL.md +9 -2
- package/skills/j-examplify/SKILL.md +49 -0
- package/skills/{help → j-help}/SKILL.md +9 -2
- package/skills/{idea → j-idea}/SKILL.md +10 -3
- package/skills/{idea → j-idea}/assets/idea_handoff_template.md +1 -1
- package/skills/{improve → j-improve}/SKILL.md +9 -2
- package/skills/j-init/SKILL.md +2 -2
- package/skills/j-jbp/SKILL.md +32 -0
- package/skills/j-lgtm/SKILL.md +28 -0
- package/skills/{pi-plan → j-pi-plan}/SKILL.md +10 -3
- package/skills/{proceed → j-proceed}/SKILL.md +9 -2
- package/skills/{publish → j-publish}/SKILL.md +47 -40
- package/skills/{publish → j-publish}/adapters/droplet.md +1 -1
- package/skills/{publish → j-publish}/adapters/mobile-ios.md +3 -3
- package/skills/{publish → j-publish}/adapters/npm-ci.md +3 -3
- package/skills/{publish → j-publish}/adapters/npm.md +8 -8
- package/skills/{publish → j-publish}/assets/ci-contract.md +2 -2
- package/skills/{publish → j-publish}/schemas/publish.schema.json +1 -1
- package/skills/{publish → j-publish}/scripts/npm_stage_inspect.sh +34 -1
- package/skills/{publish → j-publish}/scripts/npm_stage_pipeline.sh +9 -4
- package/skills/{publish → j-publish}/scripts/publish_deploy.sh +4 -4
- package/skills/{publish → j-publish}/scripts/validate_npm_stage_env.sh +1 -1
- package/skills/{publish → j-publish}/wizards/droplet.md +1 -1
- package/skills/{publish → j-publish}/wizards/mobile-ios.md +1 -1
- package/skills/{publish → j-publish}/wizards/npm-ci.md +1 -1
- package/skills/{publish → j-publish}/wizards/npm.md +1 -1
- package/skills/{reconcile → j-reconcile}/SKILL.md +12 -5
- package/skills/{reconcile → j-reconcile}/scripts/detect-unlinked-code.sh +2 -2
- package/skills/{reconcile → j-reconcile}/scripts/resolve-reconcile-scope.sh +3 -3
- package/skills/{reconcile-origin → j-reconcile-origin}/SKILL.md +13 -6
- package/skills/{redo → j-redo}/SKILL.md +9 -2
- package/skills/{skillify → j-skillify}/SKILL.md +10 -3
- package/skills/{spinoff → j-spinoff}/SKILL.md +9 -2
- package/skills/{status → j-status}/SKILL.md +9 -2
- package/skills/{todo → j-todo}/SKILL.md +10 -3
- package/skills/{todo → j-todo}/assets/todo_handoff_template.md +1 -1
- package/skills/{todo → j-todo}/scripts/add_trivial_task.sh +3 -3
- package/skills/{todo → j-todo}/scripts/update_story_tasks.py +2 -2
- package/skills/{uncharted → j-uncharted}/SKILL.md +35 -28
- package/skills/{uncharted → j-uncharted}/assets/UNDERSTANDING_DOC_TEMPLATE.md +2 -2
- package/skills/{uncharted → j-uncharted}/scripts/detect-dependencies.sh +1 -1
- package/skills/{uncharted → j-uncharted}/scripts/detect-tests.sh +1 -1
- package/skills/{uncharted → j-uncharted}/scripts/directory-triage.sh +3 -3
- package/skills/{uncharted → j-uncharted}/scripts/elicitation-state.sh +3 -3
- package/skills/{uncharted → j-uncharted}/scripts/enumerate-target.sh +1 -1
- package/skills/{uncharted → j-uncharted}/scripts/import-source.sh +1 -1
- package/skills/{uncharted → j-uncharted}/scripts/inspect-provenance.sh +1 -1
- package/skills/{uncharted → j-uncharted}/scripts/resolve-segment-target.sh +5 -5
- package/skills/{uncharted → j-uncharted}/scripts/run-engine.sh +1 -1
- package/skills/{uncharted → j-uncharted}/scripts/validate-proposed-items.sh +2 -2
- package/skills/{uncharted → j-uncharted}/scripts/write-backfilled-epics.sh +1 -1
- package/skills/j-wtf/SKILL.md +27 -0
- package/skills/jenga/SKILL.md +1 -1
- package/skills/jenga-permission-level/SKILL.md +1 -1
- package/templates/SCRUM_BOARD_SCHEMA.md +1 -1
- package/templates/agent-context.md.tpl +10 -10
- package/templates/copilot-instructions.md.tpl +89 -19
- package/skills/continue/SKILL.md +0 -29
- package/skills/error/SKILL.md +0 -29
- package/skills/examplify/SKILL.md +0 -42
- package/skills/init/SKILL.md +0 -155
- package/skills/init/assets/scope-thresholds_template.json +0 -7
- package/skills/init/assets/strategy_stub_template.md +0 -38
- package/skills/init/assets/workflow_template.json +0 -30
- package/skills/init/scripts/apply-project-visibility.sh +0 -176
- package/skills/init/scripts/detect-existing-codebase.sh +0 -166
- package/skills/init/scripts/init.sh +0 -116
- package/skills/jbp/SKILL.md +0 -25
- package/skills/lgtm/SKILL.md +0 -21
- package/skills/skillify/assets/init-new/assets/.gitignore_template +0 -15
- package/skills/skillify/assets/init-new/assets/PROJECT_SUMMARY_template.md +0 -13
- package/skills/skillify/assets/init-new/assets/directory_structure.txt +0 -14
- package/skills/skillify/assets/init-new/assets/test-config_template.json +0 -4
- package/skills/wtf/SKILL.md +0 -20
- /package/skills/{close-story → j-close-story}/scripts/compute-scope-divergence.sh +0 -0
- /package/skills/{close-story → j-close-story}/scripts/extract-diff-stats.sh +0 -0
- /package/skills/{close-story → j-close-story}/scripts/update-task-frontmatter.sh +0 -0
- /package/skills/{commit → j-commit}/assets/user_instructions_template.md +0 -0
- /package/skills/{distribute → j-distribute}/CONFIG_SCHEMA.md +0 -0
- /package/skills/{distribute → j-distribute}/scripts/check-version.sh +0 -0
- /package/skills/{distribute → j-distribute}/scripts/commit-version-bump.sh +0 -0
- /package/skills/{do → j-do}/assets/intent-vs-diff-prompt.md +0 -0
- /package/skills/{do → j-do}/assets/sender_template.json +0 -0
- /package/skills/{doc → j-doc}/assets/path-objectives.yaml +0 -0
- /package/skills/{doc → j-doc}/scripts/resolve_last_update.py +0 -0
- /package/skills/{doc-sync → j-doc-sync}/assets/default_excludes.txt +0 -0
- /package/skills/{doc-sync → j-doc-sync}/assets/doc_targets.md +0 -0
- /package/skills/{evaluate → j-evaluate}/assets/evaluation_invokation_template.yml +0 -0
- /package/skills/{evaluate → j-evaluate}/assets/evaluation_rapport_template.md +0 -0
- /package/skills/{idea → j-idea}/assets/idea_template.md +0 -0
- /package/skills/{pi-plan → j-pi-plan}/assets/epic.json +0 -0
- /package/skills/{pi-plan → j-pi-plan}/assets/story_template.md +0 -0
- /package/skills/{publish → j-publish}/assets/ExportOptions.plist.template +0 -0
- /package/skills/{publish → j-publish}/assets/ownership-matrix.md +0 -0
- /package/skills/{publish → j-publish}/assets/publish.example.json +0 -0
- /package/skills/{publish → j-publish}/assets/publish.example.npm-ci.json +0 -0
- /package/skills/{publish → j-publish}/assets/publish.example.npm.json +0 -0
- /package/skills/{publish → j-publish}/assets/secrets-guide.md +0 -0
- /package/skills/{publish → j-publish}/schemas/fixtures/npm-ci-minimal.json +0 -0
- /package/skills/{publish → j-publish}/schemas/fixtures/npm-ci-with-empty-secrets.json +0 -0
- /package/skills/{publish → j-publish}/schemas/fixtures/npm-ci-with-workflow-path.json +0 -0
- /package/skills/{publish → j-publish}/scripts/check_target_config.sh +0 -0
- /package/skills/{publish → j-publish}/scripts/droplet_pipeline.sh +0 -0
- /package/skills/{publish → j-publish}/scripts/finalize_changelog.sh +0 -0
- /package/skills/{publish → j-publish}/scripts/generate_release_notes.sh +0 -0
- /package/skills/{publish → j-publish}/scripts/ios_pipeline.sh +0 -0
- /package/skills/{publish → j-publish}/scripts/npm_ci_pipeline.sh +0 -0
- /package/skills/{publish → j-publish}/scripts/npm_pipeline.sh +0 -0
- /package/skills/{publish → j-publish}/scripts/publish_common.sh +0 -0
- /package/skills/{publish → j-publish}/scripts/reconcile_tags.sh +0 -0
- /package/skills/{publish → j-publish}/scripts/run_gates.sh +0 -0
- /package/skills/{publish → j-publish}/scripts/setup_wizard.sh +0 -0
- /package/skills/{publish → j-publish}/scripts/show_history.sh +0 -0
- /package/skills/{publish → j-publish}/scripts/suggest_semver_bump.sh +0 -0
- /package/skills/{publish → j-publish}/scripts/validate_config.sh +0 -0
- /package/skills/{publish → j-publish}/scripts/validate_droplet_env.sh +0 -0
- /package/skills/{publish → j-publish}/scripts/validate_ios_env.sh +0 -0
- /package/skills/{publish → j-publish}/scripts/validate_npm_ci_env.sh +0 -0
- /package/skills/{publish → j-publish}/scripts/validate_npm_env.sh +0 -0
- /package/skills/{publish → j-publish}/scripts/write_ledger_entry.sh +0 -0
- /package/skills/{reconcile → j-reconcile}/assets/report_format.md +0 -0
- /package/skills/{reconcile-origin → j-reconcile-origin}/scripts/reconcile-origin.sh +0 -0
- /package/skills/{skillify → j-skillify}/assets/init-new/SKILL.md +0 -0
- /package/skills/{init → j-skillify/assets/init-new}/assets/.gitignore_template +0 -0
- /package/skills/{init → j-skillify/assets/init-new}/assets/PROJECT_SUMMARY_template.md +0 -0
- /package/skills/{init → j-skillify/assets/init-new}/assets/directory_structure.txt +0 -0
- /package/skills/{init → j-skillify/assets/init-new}/assets/test-config_template.json +0 -0
- /package/skills/{skillify → j-skillify}/assets/init-new/assets/workflow_template.json +0 -0
- /package/skills/{skillify → j-skillify}/assets/init-new/scripts/init.sh +0 -0
- /package/skills/{skillify → j-skillify}/assets/init-old/SKILL.md +0 -0
- /package/skills/{status → j-status}/assets/output_format.md +0 -0
- /package/skills/{todo → j-todo}/assets/todo_template.md +0 -0
- /package/skills/{uncharted → j-uncharted}/assets/SEGMENT_PROPOSAL_TEMPLATE.md +0 -0
- /package/skills/{uncharted → j-uncharted}/scripts/apply-subsystem-cap.sh +0 -0
- /package/skills/{uncharted → j-uncharted}/scripts/discover-subsystems.sh +0 -0
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# verify-postinstall-reconcile.sh — fixture rehearsal for E26_S08_T01
|
|
4
|
+
#
|
|
5
|
+
# Rehearses the manifest-based delete reconciliation in scripts/postinstall.js
|
|
6
|
+
# against a THROWAWAY fixture consumer project, as required by E26_S08's
|
|
7
|
+
# `crucial_level: gated` note ("must be rehearsed against a throwaway fixture
|
|
8
|
+
# consumer directory before being considered done, not just unit-reasoned about").
|
|
9
|
+
#
|
|
10
|
+
# SAFETY: this script creates its own fixture root via `mktemp -d` and writes and
|
|
11
|
+
# deletes ONLY inside it. It takes no path argument and will never operate on an
|
|
12
|
+
# existing directory, so it cannot touch this repo or a real consumer project.
|
|
13
|
+
# Set KEEP_FIXTURE=1 to leave the fixture on disk for inspection.
|
|
14
|
+
#
|
|
15
|
+
# Scenarios covered
|
|
16
|
+
# A. First install with no prior manifest -> additive only, pre-existing consumer
|
|
17
|
+
# files survive, NO delete pass runs.
|
|
18
|
+
# B. Upgrade across a release that renames / removes / excludes skills -> stale
|
|
19
|
+
# package files removed from both mirror roots, consumer-authored files survive
|
|
20
|
+
# (including one planted INSIDE a package directory that is otherwise emptied),
|
|
21
|
+
# and files common to both versions are left byte- and mtime-identical.
|
|
22
|
+
#
|
|
23
|
+
# Usage: bash scripts/verify-postinstall-reconcile.sh
|
|
24
|
+
# Exit: 0 = all assertions passed, 1 = at least one failed.
|
|
25
|
+
|
|
26
|
+
set -uo pipefail
|
|
27
|
+
|
|
28
|
+
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
29
|
+
FIXTURE="$(mktemp -d "${TMPDIR:-/tmp}/jenga-postinstall-fixture.XXXXXX")"
|
|
30
|
+
|
|
31
|
+
PASS=0
|
|
32
|
+
FAIL=0
|
|
33
|
+
|
|
34
|
+
# When RESULTS_FILE is set, every verdict is also appended in a machine-readable
|
|
35
|
+
# `PASS<TAB><name>` / `FAIL<TAB><name>` form, so tests/postinstall-delete-reconciliation.bats
|
|
36
|
+
# can assert on individual named checks instead of on one opaque exit status.
|
|
37
|
+
record() { if [ -n "${RESULTS_FILE:-}" ]; then printf '%s\t%s\n' "$1" "$2" >> "$RESULTS_FILE"; fi; }
|
|
38
|
+
|
|
39
|
+
pass() { PASS=$((PASS + 1)); record PASS "$1"; printf ' \033[32mPASS\033[0m %s\n' "$1"; }
|
|
40
|
+
fail() { FAIL=$((FAIL + 1)); record FAIL "$1"; printf ' \033[31mFAIL\033[0m %s\n' "$1"; }
|
|
41
|
+
|
|
42
|
+
exists() { [ -e "$1" ]; }
|
|
43
|
+
assert_file() { if [ -f "$1" ]; then pass "$2"; else fail "$2 (missing: $1)"; fi; }
|
|
44
|
+
assert_absent() { if [ ! -e "$1" ]; then pass "$2"; else fail "$2 (still present: $1)"; fi; }
|
|
45
|
+
assert_grep() { if grep -q "$1" "$2" 2>/dev/null; then pass "$3"; else fail "$3"; fi; }
|
|
46
|
+
assert_nogrep() { if grep -q "$1" "$2" 2>/dev/null; then fail "$3"; else pass "$3"; fi; }
|
|
47
|
+
# ERE variant — needed where the pattern is a real regex rather than a literal.
|
|
48
|
+
assert_nogrep_re() { if grep -qE "$1" "$2" 2>/dev/null; then fail "$3"; else pass "$3"; fi; }
|
|
49
|
+
|
|
50
|
+
cleanup() {
|
|
51
|
+
if [ "${KEEP_FIXTURE:-0}" = "1" ]; then
|
|
52
|
+
printf '\n Fixture retained at: %s\n' "$FIXTURE"
|
|
53
|
+
else
|
|
54
|
+
# Confined to the mktemp -d created by this script itself.
|
|
55
|
+
rm -rf "$FIXTURE"
|
|
56
|
+
fi
|
|
57
|
+
}
|
|
58
|
+
trap cleanup EXIT
|
|
59
|
+
|
|
60
|
+
# ── build a fake package version ─────────────────────────────────────────────
|
|
61
|
+
# Copies the real lib/, scripts/ and templates/ from this repo (so the code under
|
|
62
|
+
# test is the real code), then lays down a small synthetic skills/ + agents/ tree.
|
|
63
|
+
make_pkg() {
|
|
64
|
+
local dir="$1" version="$2"
|
|
65
|
+
mkdir -p "$dir"
|
|
66
|
+
cp -R "$REPO_ROOT/lib" "$dir/lib"
|
|
67
|
+
cp -R "$REPO_ROOT/scripts" "$dir/scripts"
|
|
68
|
+
cp -R "$REPO_ROOT/templates" "$dir/templates" 2>/dev/null || true
|
|
69
|
+
cat > "$dir/package.json" <<JSON
|
|
70
|
+
{ "name": "@jenga-ai/agent", "version": "$version", "type": "module" }
|
|
71
|
+
JSON
|
|
72
|
+
mkdir -p "$dir/skills" "$dir/agents"
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
add_skill() {
|
|
76
|
+
local dir="$1" name="$2" body="$3"
|
|
77
|
+
mkdir -p "$dir/skills/$name"
|
|
78
|
+
printf '%s\n' "$body" > "$dir/skills/$name/SKILL.md"
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
run_install() {
|
|
82
|
+
local pkg="$1" consumer="$2" log="$3"
|
|
83
|
+
( cd "$pkg" && INIT_CWD="$consumer" node scripts/postinstall.js ) > "$log" 2>&1
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
echo
|
|
87
|
+
echo "══ Jenga postinstall delete-reconciliation rehearsal ══"
|
|
88
|
+
echo " fixture: $FIXTURE"
|
|
89
|
+
|
|
90
|
+
# ── package v1.0.0 ───────────────────────────────────────────────────────────
|
|
91
|
+
PKG1="$FIXTURE/pkg-v1"
|
|
92
|
+
make_pkg "$PKG1" "1.0.0"
|
|
93
|
+
add_skill "$PKG1" "do" "# do — stable across both versions"
|
|
94
|
+
add_skill "$PKG1" "renamed-old" "# renamed-old — becomes renamed-new in v2"
|
|
95
|
+
add_skill "$PKG1" "j-legacy-twin" "# j-legacy-twin — excluded in v2 (E50_S06 style)"
|
|
96
|
+
printf '# developer agent v1\n' > "$PKG1/agents/developer.md"
|
|
97
|
+
|
|
98
|
+
# ── package v2.0.0 ───────────────────────────────────────────────────────────
|
|
99
|
+
PKG2="$FIXTURE/pkg-v2"
|
|
100
|
+
make_pkg "$PKG2" "2.0.0"
|
|
101
|
+
add_skill "$PKG2" "do" "# do — stable across both versions" # byte-identical
|
|
102
|
+
add_skill "$PKG2" "renamed-new" "# renamed-new — replaces renamed-old"
|
|
103
|
+
# j-legacy-twin intentionally absent (excluded), renamed-old intentionally absent
|
|
104
|
+
printf '# developer agent v2 (changed)\n' > "$PKG2/agents/developer.md"
|
|
105
|
+
|
|
106
|
+
CONSUMER="$FIXTURE/consumer"
|
|
107
|
+
mkdir -p "$CONSUMER"
|
|
108
|
+
|
|
109
|
+
# ═══ Scenario A — first install, no prior manifest ═══════════════════════════
|
|
110
|
+
echo
|
|
111
|
+
echo "── Scenario A: first install (no prior manifest) ──"
|
|
112
|
+
|
|
113
|
+
# Plant a consumer file BEFORE the very first install. A first install must never
|
|
114
|
+
# delete it, because there is no manifest telling us what we wrote before.
|
|
115
|
+
mkdir -p "$CONSUMER/.agents/skills/preexisting" "$CONSUMER/.claude/skills/preexisting"
|
|
116
|
+
printf '# consumer file that predates any jenga install\n' > "$CONSUMER/.agents/skills/preexisting/JUNK.md"
|
|
117
|
+
printf '# consumer file that predates any jenga install\n' > "$CONSUMER/.claude/skills/preexisting/JUNK.md"
|
|
118
|
+
|
|
119
|
+
run_install "$PKG1" "$CONSUMER" "$FIXTURE/install-v1.log"
|
|
120
|
+
|
|
121
|
+
assert_grep "no previous install manifest" "$FIXTURE/install-v1.log" \
|
|
122
|
+
"first install reports no delete pass"
|
|
123
|
+
assert_nogrep_re "[1-9][0-9]* stale file" "$FIXTURE/install-v1.log" \
|
|
124
|
+
"first install deletes nothing (zero stale files reported)"
|
|
125
|
+
assert_file "$CONSUMER/.agents/skills/preexisting/JUNK.md" \
|
|
126
|
+
"pre-existing consumer file survives first install (.agents)"
|
|
127
|
+
assert_file "$CONSUMER/.claude/skills/preexisting/JUNK.md" \
|
|
128
|
+
"pre-existing consumer file survives first install (.claude)"
|
|
129
|
+
assert_file "$CONSUMER/.agents/skills/renamed-old/SKILL.md" \
|
|
130
|
+
"v1 skill mirrored to .agents"
|
|
131
|
+
assert_file "$CONSUMER/.claude/skills/renamed-old/SKILL.md" \
|
|
132
|
+
"v1 skill mirrored to .claude"
|
|
133
|
+
assert_file "$CONSUMER/.agents/.jenga-postinstall-manifest.json" \
|
|
134
|
+
"manifest written to .agents on first install"
|
|
135
|
+
assert_file "$CONSUMER/.claude/.jenga-postinstall-manifest.json" \
|
|
136
|
+
"manifest written to .claude on first install"
|
|
137
|
+
assert_nogrep "preexisting/JUNK.md" "$CONSUMER/.agents/.jenga-postinstall-manifest.json" \
|
|
138
|
+
"consumer file is NOT recorded in the manifest"
|
|
139
|
+
assert_grep "skills/do/SKILL.md" "$CONSUMER/.agents/.jenga-postinstall-manifest.json" \
|
|
140
|
+
"manifest records mirrored package paths"
|
|
141
|
+
|
|
142
|
+
# ═══ Scenario B — upgrade with renames / removals / exclusions ════════════════
|
|
143
|
+
echo
|
|
144
|
+
echo "── Scenario B: upgrade 1.0.0 -> 2.0.0 ──"
|
|
145
|
+
|
|
146
|
+
# Consumer authors their own custom skill alongside package-owned ones.
|
|
147
|
+
for root in .agents .claude; do
|
|
148
|
+
mkdir -p "$CONSUMER/$root/skills/my-custom-skill"
|
|
149
|
+
printf '# my hand-authored skill\n' > "$CONSUMER/$root/skills/my-custom-skill/SKILL.md"
|
|
150
|
+
# ...and drops a note INSIDE a package directory that v2 removes entirely.
|
|
151
|
+
printf '# my notes inside a package-owned dir\n' > "$CONSUMER/$root/skills/j-legacy-twin/MY-NOTES.md"
|
|
152
|
+
done
|
|
153
|
+
|
|
154
|
+
# Record identity of a file common to both versions, to prove it is not needlessly
|
|
155
|
+
# deleted and recopied (mirror() should classify it as `skipped`).
|
|
156
|
+
DO_BEFORE="$(ls -li "$CONSUMER/.agents/skills/do/SKILL.md" | awk '{print $1, $6, $7, $8}')"
|
|
157
|
+
|
|
158
|
+
run_install "$PKG2" "$CONSUMER" "$FIXTURE/install-v2.log"
|
|
159
|
+
|
|
160
|
+
echo
|
|
161
|
+
echo " [upgrade cleanup lines]"
|
|
162
|
+
grep -E "stale file|left in place|no previous" "$FIXTURE/install-v2.log" | sed 's/^/ /'
|
|
163
|
+
echo
|
|
164
|
+
|
|
165
|
+
# 1. Stale, fully-removed package skill is gone from BOTH roots, dir pruned.
|
|
166
|
+
assert_absent "$CONSUMER/.agents/skills/renamed-old" \
|
|
167
|
+
"renamed-away skill dir removed from .agents"
|
|
168
|
+
assert_absent "$CONSUMER/.claude/skills/renamed-old" \
|
|
169
|
+
"renamed-away skill dir removed from .claude"
|
|
170
|
+
|
|
171
|
+
# 2. Excluded twin's package file is gone, but the consumer's note in the same dir
|
|
172
|
+
# survives — so the directory itself must NOT be pruned.
|
|
173
|
+
assert_absent "$CONSUMER/.agents/skills/j-legacy-twin/SKILL.md" \
|
|
174
|
+
"excluded twin's package file removed (.agents)"
|
|
175
|
+
assert_absent "$CONSUMER/.claude/skills/j-legacy-twin/SKILL.md" \
|
|
176
|
+
"excluded twin's package file removed (.claude)"
|
|
177
|
+
assert_file "$CONSUMER/.agents/skills/j-legacy-twin/MY-NOTES.md" \
|
|
178
|
+
"consumer note INSIDE the emptied package dir survives (.agents)"
|
|
179
|
+
assert_file "$CONSUMER/.claude/skills/j-legacy-twin/MY-NOTES.md" \
|
|
180
|
+
"consumer note INSIDE the emptied package dir survives (.claude)"
|
|
181
|
+
|
|
182
|
+
# 3. Consumer's own custom skill is untouched.
|
|
183
|
+
assert_file "$CONSUMER/.agents/skills/my-custom-skill/SKILL.md" \
|
|
184
|
+
"consumer custom skill survives upgrade (.agents)"
|
|
185
|
+
assert_file "$CONSUMER/.claude/skills/my-custom-skill/SKILL.md" \
|
|
186
|
+
"consumer custom skill survives upgrade (.claude)"
|
|
187
|
+
assert_file "$CONSUMER/.agents/skills/preexisting/JUNK.md" \
|
|
188
|
+
"pre-manifest consumer file still survives upgrade (.agents)"
|
|
189
|
+
assert_file "$CONSUMER/.claude/skills/preexisting/JUNK.md" \
|
|
190
|
+
"pre-manifest consumer file still survives upgrade (.claude)"
|
|
191
|
+
|
|
192
|
+
# 4. New skill arrived.
|
|
193
|
+
assert_file "$CONSUMER/.agents/skills/renamed-new/SKILL.md" \
|
|
194
|
+
"renamed-to skill installed (.agents)"
|
|
195
|
+
assert_file "$CONSUMER/.claude/skills/renamed-new/SKILL.md" \
|
|
196
|
+
"renamed-to skill installed (.claude)"
|
|
197
|
+
|
|
198
|
+
# 5. Unchanged common file was neither deleted nor recopied.
|
|
199
|
+
DO_AFTER="$(ls -li "$CONSUMER/.agents/skills/do/SKILL.md" | awk '{print $1, $6, $7, $8}')"
|
|
200
|
+
if [ "$DO_BEFORE" = "$DO_AFTER" ]; then
|
|
201
|
+
pass "file common to both versions untouched (same inode+mtime)"
|
|
202
|
+
else
|
|
203
|
+
fail "file common to both versions was rewritten ($DO_BEFORE -> $DO_AFTER)"
|
|
204
|
+
fi
|
|
205
|
+
|
|
206
|
+
# 6. Changed common file was overwritten.
|
|
207
|
+
assert_grep "v2 (changed)" "$CONSUMER/.agents/agents/developer.md" \
|
|
208
|
+
"changed package file overwritten with v2 content"
|
|
209
|
+
|
|
210
|
+
# 7. Manifest refreshed.
|
|
211
|
+
assert_nogrep "renamed-old" "$CONSUMER/.agents/.jenga-postinstall-manifest.json" \
|
|
212
|
+
"refreshed manifest no longer lists the removed skill"
|
|
213
|
+
assert_grep "renamed-new" "$CONSUMER/.agents/.jenga-postinstall-manifest.json" \
|
|
214
|
+
"refreshed manifest lists the new skill"
|
|
215
|
+
assert_nogrep "my-custom-skill" "$CONSUMER/.agents/.jenga-postinstall-manifest.json" \
|
|
216
|
+
"refreshed manifest never records consumer-authored files"
|
|
217
|
+
|
|
218
|
+
# ═══ Scenario C — idempotent re-run of the same version ══════════════════════
|
|
219
|
+
echo
|
|
220
|
+
echo "── Scenario C: re-run same version (version gate) ──"
|
|
221
|
+
run_install "$PKG2" "$CONSUMER" "$FIXTURE/install-v2-again.log"
|
|
222
|
+
assert_grep "Nothing to do" "$FIXTURE/install-v2-again.log" \
|
|
223
|
+
"same-version re-run short-circuits before any delete pass"
|
|
224
|
+
assert_file "$CONSUMER/.agents/skills/my-custom-skill/SKILL.md" \
|
|
225
|
+
"consumer custom skill still present after re-run"
|
|
226
|
+
assert_file "$CONSUMER/.agents/skills/renamed-new/SKILL.md" \
|
|
227
|
+
"package skill still present after re-run"
|
|
228
|
+
|
|
229
|
+
# ═══ Scenario D — adversarial / corrupt manifests ════════════════════════════
|
|
230
|
+
# Exercises the guards directly: a manifest is data on the consumer's disk, so a
|
|
231
|
+
# tampered or corrupted one must never turn into an out-of-bounds or wrong-type
|
|
232
|
+
# delete. Uses a fresh consumer so it cannot disturb the scenarios above.
|
|
233
|
+
echo
|
|
234
|
+
echo "── Scenario D: adversarial + corrupt manifests ──"
|
|
235
|
+
|
|
236
|
+
CONSUMER_D="$FIXTURE/consumer-d"
|
|
237
|
+
mkdir -p "$CONSUMER_D"
|
|
238
|
+
run_install "$PKG1" "$CONSUMER_D" "$FIXTURE/d-install-v1.log"
|
|
239
|
+
|
|
240
|
+
# A file OUTSIDE the mirror roots that a traversal entry would try to reach.
|
|
241
|
+
printf 'precious\n' > "$CONSUMER_D/OUTSIDE-THE-MIRROR.txt"
|
|
242
|
+
# A symlink planted at a path the manifest will claim as ours.
|
|
243
|
+
mkdir -p "$CONSUMER_D/.agents/skills/trap"
|
|
244
|
+
ln -sf "$CONSUMER_D/OUTSIDE-THE-MIRROR.txt" "$CONSUMER_D/.agents/skills/trap/LINK.md"
|
|
245
|
+
# A directory planted where the manifest claims a file.
|
|
246
|
+
mkdir -p "$CONSUMER_D/.agents/skills/trap/DIR.md"
|
|
247
|
+
|
|
248
|
+
# Hand-craft a hostile manifest: traversal escape, symlink, directory, plus a real
|
|
249
|
+
# stale file that SHOULD still be cleaned up (proves the guards are selective, not
|
|
250
|
+
# a blanket bail-out).
|
|
251
|
+
python3 - "$CONSUMER_D" <<'PYEOF'
|
|
252
|
+
import json, sys, os
|
|
253
|
+
root = sys.argv[1]
|
|
254
|
+
m = os.path.join(root, ".agents", ".jenga-postinstall-manifest.json")
|
|
255
|
+
d = json.load(open(m))
|
|
256
|
+
d["paths"] = [
|
|
257
|
+
"../OUTSIDE-THE-MIRROR.txt", # traversal escape -> must be refused
|
|
258
|
+
"skills/trap/LINK.md", # symlink -> must be refused
|
|
259
|
+
"skills/trap/DIR.md", # directory -> must be refused
|
|
260
|
+
"skills/renamed-old/SKILL.md", # genuinely stale -> must be deleted
|
|
261
|
+
]
|
|
262
|
+
json.dump(d, open(m, "w"), indent=2)
|
|
263
|
+
PYEOF
|
|
264
|
+
|
|
265
|
+
run_install "$PKG2" "$CONSUMER_D" "$FIXTURE/d-install-v2.log"
|
|
266
|
+
|
|
267
|
+
echo
|
|
268
|
+
echo " [guard lines]"
|
|
269
|
+
grep -E "left in place|stale file" "$FIXTURE/d-install-v2.log" | sed 's/^/ /'
|
|
270
|
+
echo
|
|
271
|
+
|
|
272
|
+
assert_file "$CONSUMER_D/OUTSIDE-THE-MIRROR.txt" \
|
|
273
|
+
"traversal entry cannot delete a file outside the mirror root"
|
|
274
|
+
assert_grep "outside-dest-root" "$FIXTURE/d-install-v2.log" \
|
|
275
|
+
"traversal entry explicitly refused"
|
|
276
|
+
if [ -L "$CONSUMER_D/.agents/skills/trap/LINK.md" ]; then
|
|
277
|
+
pass "symlink entry refused, not followed or unlinked"
|
|
278
|
+
else
|
|
279
|
+
fail "symlink entry was removed"
|
|
280
|
+
fi
|
|
281
|
+
assert_grep "not-a-regular-file" "$FIXTURE/d-install-v2.log" \
|
|
282
|
+
"non-regular-file entries explicitly refused"
|
|
283
|
+
if [ -d "$CONSUMER_D/.agents/skills/trap/DIR.md" ]; then
|
|
284
|
+
pass "directory entry refused (manifests record files only)"
|
|
285
|
+
else
|
|
286
|
+
fail "directory entry was removed"
|
|
287
|
+
fi
|
|
288
|
+
assert_absent "$CONSUMER_D/.agents/skills/renamed-old/SKILL.md" \
|
|
289
|
+
"genuinely stale entry still cleaned up alongside refusals"
|
|
290
|
+
|
|
291
|
+
# Corrupt manifest must disable the delete pass entirely, not guess.
|
|
292
|
+
CONSUMER_E="$FIXTURE/consumer-e"
|
|
293
|
+
mkdir -p "$CONSUMER_E"
|
|
294
|
+
run_install "$PKG1" "$CONSUMER_E" "$FIXTURE/e-install-v1.log"
|
|
295
|
+
printf '{ this is not valid json' > "$CONSUMER_E/.agents/.jenga-postinstall-manifest.json"
|
|
296
|
+
printf '{"manifest_version": 99, "paths": ["skills/renamed-old/SKILL.md"]}' \
|
|
297
|
+
> "$CONSUMER_E/.claude/.jenga-postinstall-manifest.json"
|
|
298
|
+
run_install "$PKG2" "$CONSUMER_E" "$FIXTURE/e-install-v2.log"
|
|
299
|
+
|
|
300
|
+
assert_file "$CONSUMER_E/.agents/skills/renamed-old/SKILL.md" \
|
|
301
|
+
"corrupt manifest disables the delete pass (.agents)"
|
|
302
|
+
assert_file "$CONSUMER_E/.claude/skills/renamed-old/SKILL.md" \
|
|
303
|
+
"unknown manifest_version disables the delete pass (.claude)"
|
|
304
|
+
assert_grep "no previous install manifest" "$FIXTURE/e-install-v2.log" \
|
|
305
|
+
"unreadable manifest degrades to additive-only"
|
|
306
|
+
assert_grep "manifest_version" "$CONSUMER_E/.agents/.jenga-postinstall-manifest.json" \
|
|
307
|
+
"a fresh valid manifest is rewritten over the corrupt one"
|
|
308
|
+
|
|
309
|
+
# ═══ Scenario E — case-only rename on a case-insensitive filesystem ══════════
|
|
310
|
+
# Regression cover for tester finding 1 (E26_S08_T01 rapport). Staleness is decided
|
|
311
|
+
# by a case-SENSITIVE string set, but unlinks happen on a filesystem that may be
|
|
312
|
+
# case-INSENSITIVE (macOS APFS, Windows NTFS). After skill.md -> SKILL.md the old
|
|
313
|
+
# manifest string looks stale, yet it resolves to the file this run just wrote --
|
|
314
|
+
# so a string-only diff deletes the new file and the skill vanishes entirely.
|
|
315
|
+
echo
|
|
316
|
+
echo "── Scenario E: case-only rename (finding 1) ──"
|
|
317
|
+
|
|
318
|
+
PKG1C="$FIXTURE/pkg-v1-case"
|
|
319
|
+
PKG2C="$FIXTURE/pkg-v2-case"
|
|
320
|
+
make_pkg "$PKG1C" "1.0.0"
|
|
321
|
+
make_pkg "$PKG2C" "2.0.0"
|
|
322
|
+
mkdir -p "$PKG1C/skills/alpha" "$PKG2C/skills/alpha"
|
|
323
|
+
printf '# alpha\n' > "$PKG1C/skills/alpha/skill.md" # lowercase in v1
|
|
324
|
+
printf '# alpha\n' > "$PKG2C/skills/alpha/SKILL.md" # UPPERCASE in v2
|
|
325
|
+
|
|
326
|
+
CONSUMER_C="$FIXTURE/consumer-case"
|
|
327
|
+
mkdir -p "$CONSUMER_C"
|
|
328
|
+
run_install "$PKG1C" "$CONSUMER_C" "$FIXTURE/case-v1.log"
|
|
329
|
+
run_install "$PKG2C" "$CONSUMER_C" "$FIXTURE/case-v2.log"
|
|
330
|
+
|
|
331
|
+
# Detect whether this filesystem is even case-insensitive; on a case-SENSITIVE fs
|
|
332
|
+
# both names legitimately coexist and the old one is genuinely stale.
|
|
333
|
+
if [ -f "$CONSUMER_C/.agents/skills/alpha/skill.md" ] && \
|
|
334
|
+
[ -f "$CONSUMER_C/.agents/skills/alpha/SKILL.md" ] && \
|
|
335
|
+
[ "$(cat "$CONSUMER_C/.agents/skills/alpha/skill.md" 2>/dev/null)" != "$(cat "$CONSUMER_C/.agents/skills/alpha/SKILL.md" 2>/dev/null)" ]; then
|
|
336
|
+
CASE_INSENSITIVE=0
|
|
337
|
+
else
|
|
338
|
+
CASE_INSENSITIVE=1
|
|
339
|
+
fi
|
|
340
|
+
|
|
341
|
+
if [ "$CASE_INSENSITIVE" -eq 1 ]; then
|
|
342
|
+
# The whole point: the skill must still exist under SOME name after the upgrade.
|
|
343
|
+
if [ -f "$CONSUMER_C/.agents/skills/alpha/SKILL.md" ] || [ -f "$CONSUMER_C/.agents/skills/alpha/skill.md" ]; then
|
|
344
|
+
pass "case-only rename does not delete the just-written file (.agents)"
|
|
345
|
+
else
|
|
346
|
+
fail "case-only rename deleted the skill entirely (.agents)"
|
|
347
|
+
fi
|
|
348
|
+
if [ -f "$CONSUMER_C/.claude/skills/alpha/SKILL.md" ] || [ -f "$CONSUMER_C/.claude/skills/alpha/skill.md" ]; then
|
|
349
|
+
pass "case-only rename does not delete the just-written file (.claude)"
|
|
350
|
+
else
|
|
351
|
+
fail "case-only rename deleted the skill entirely (.claude)"
|
|
352
|
+
fi
|
|
353
|
+
assert_grep "written-this-run" "$FIXTURE/case-v2.log" \
|
|
354
|
+
"identity guard reports the spared entry as written-this-run"
|
|
355
|
+
else
|
|
356
|
+
pass "case-only rename (skipped: filesystem is case-sensitive)"
|
|
357
|
+
pass "case-only rename (skipped: filesystem is case-sensitive) (.claude)"
|
|
358
|
+
pass "identity guard reports the spared entry as written-this-run (n/a on case-sensitive fs)"
|
|
359
|
+
fi
|
|
360
|
+
|
|
361
|
+
# ═══ Scenario F — copySet entry missing from the package ═════════════════════
|
|
362
|
+
# Regression cover for tester finding 2. mirror() silently skips a missing source,
|
|
363
|
+
# so currentPaths under-reports and the delete pass would read the whole mirrored
|
|
364
|
+
# subtree as stale -- converting a bad publish into mass deletion on every consumer.
|
|
365
|
+
echo
|
|
366
|
+
echo "── Scenario F: packaging regression (finding 2) ──"
|
|
367
|
+
|
|
368
|
+
PKG2M="$FIXTURE/pkg-v2-missing"
|
|
369
|
+
make_pkg "$PKG2M" "2.0.0"
|
|
370
|
+
printf '# developer agent v2\n' > "$PKG2M/agents/developer.md"
|
|
371
|
+
rm -rf "$PKG2M/skills" # simulate skills/ omitted from the published package
|
|
372
|
+
|
|
373
|
+
CONSUMER_M="$FIXTURE/consumer-missing"
|
|
374
|
+
mkdir -p "$CONSUMER_M"
|
|
375
|
+
run_install "$PKG1" "$CONSUMER_M" "$FIXTURE/missing-v1.log"
|
|
376
|
+
run_install "$PKG2M" "$CONSUMER_M" "$FIXTURE/missing-v2.log"
|
|
377
|
+
|
|
378
|
+
assert_file "$CONSUMER_M/.agents/skills/do/SKILL.md" \
|
|
379
|
+
"missing copySet entry does not wipe the mirrored subtree (.agents)"
|
|
380
|
+
assert_file "$CONSUMER_M/.claude/skills/do/SKILL.md" \
|
|
381
|
+
"missing copySet entry does not wipe the mirrored subtree (.claude)"
|
|
382
|
+
assert_grep "Upgrade cleanup skipped" "$FIXTURE/missing-v2.log" \
|
|
383
|
+
"packaging regression reported, cleanup skipped"
|
|
384
|
+
assert_grep "skills/renamed-old/SKILL.md" "$CONSUMER_M/.agents/.jenga-postinstall-manifest.json" \
|
|
385
|
+
"previous manifest left intact (still describes what is on disk)"
|
|
386
|
+
|
|
387
|
+
echo
|
|
388
|
+
echo "══════════════════════════════════════════════════════"
|
|
389
|
+
printf ' Result: %d passed, %d failed\n' "$PASS" "$FAIL"
|
|
390
|
+
echo "══════════════════════════════════════════════════════"
|
|
391
|
+
echo
|
|
392
|
+
[ "$FAIL" -eq 0 ]
|
|
@@ -1,21 +1,28 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: j
|
|
3
|
-
description: Engage the scrum-master agent in a focused planning session to define, refine, or challenge features, improvements, tasks, stories, and epics. The agent asks probing questions, challenges assumptions, and helps shape ideas into actionable backlog items.
|
|
2
|
+
name: j.brainstorm
|
|
3
|
+
description: Polyfill alias of the brainstorm skill under a collision-safe directory name. Identical behavior to /brainstorm — Engage the scrum-master agent in a focused planning session to define, refine, or challenge features, improvements, tasks, stories, and epics. The agent asks probing questions, challenges assumptions, and helps shape ideas into actionable backlog items. Use when the bare /brainstorm form is shadowed by another tool's own built-in command of the same name.
|
|
4
4
|
keywords:
|
|
5
5
|
- brainstorm
|
|
6
6
|
- plan
|
|
7
7
|
- ideate
|
|
8
8
|
- feature planning
|
|
9
9
|
- requirements
|
|
10
|
+
- j-brainstorm
|
|
11
|
+
- polyfill
|
|
10
12
|
examples:
|
|
11
13
|
- "let's brainstorm ideas for X"
|
|
12
14
|
- "I need to plan a new feature"
|
|
15
|
+
- "j-brainstorm"
|
|
13
16
|
metadata:
|
|
14
17
|
prefered_agent: scrum-master
|
|
15
18
|
---
|
|
16
19
|
|
|
17
20
|
# Brainstorm — Collaborative Planning with the Scrum Master
|
|
18
21
|
|
|
22
|
+
This skill is a literal-directory-name duplicate of `skills/brainstorm/`. It exists so that `/j-brainstorm` (and `j.j-brainstorm`) give a guaranteed-unshadowed way to reach the same flow as `/brainstorm`, even if a host tool's own built-in command of the same name would otherwise shadow or override the bare `/brainstorm` alias (Claude Code's native skill resolution is a literal-string, directory-name-based match — see `docs/skill-authoring.md`'s "Invocation Convention").
|
|
23
|
+
|
|
24
|
+
This file is generated/synced by `scripts/generate-j-alias.sh brainstorm` from `skills/brainstorm/SKILL.md` — do not hand-edit it; re-run the generator instead to pick up source changes.
|
|
25
|
+
|
|
19
26
|
## Instructions
|
|
20
27
|
|
|
21
28
|
1. **Invoke the `scrum-master` agent** — Pass the user's input directly to it as the opening prompt for the brainstorm session.
|
|
@@ -1,21 +1,28 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: j
|
|
3
|
-
description: Capture a new mission (feature, change, or addition) and fit it into the project's Epic/Story structure, then choose to implement now or defer.
|
|
2
|
+
name: j.btw
|
|
3
|
+
description: Polyfill alias of the btw skill under a collision-safe directory name. Identical behavior to /btw — Capture a new mission (feature, change, or addition) and fit it into the project's Epic/Story structure, then choose to implement now or defer. Use when the bare /btw form is shadowed by another tool's own built-in command of the same name.
|
|
4
4
|
keywords:
|
|
5
5
|
- btw
|
|
6
6
|
- capture
|
|
7
7
|
- mission
|
|
8
8
|
- new idea
|
|
9
9
|
- side task
|
|
10
|
+
- j-btw
|
|
11
|
+
- polyfill
|
|
10
12
|
examples:
|
|
11
13
|
- "btw I also need to add X"
|
|
12
14
|
- "capture this as a new task"
|
|
15
|
+
- "j-btw"
|
|
13
16
|
metadata:
|
|
14
17
|
prefered_agent: scrum-master
|
|
15
18
|
---
|
|
16
19
|
|
|
17
20
|
# BTW — Capture a Mission
|
|
18
21
|
|
|
22
|
+
This skill is a literal-directory-name duplicate of `skills/btw/`. It exists so that `/j-btw` (and `j.j-btw`) give a guaranteed-unshadowed way to reach the same flow as `/btw`, even if a host tool's own built-in command of the same name would otherwise shadow or override the bare `/btw` alias (Claude Code's native skill resolution is a literal-string, directory-name-based match — see `docs/skill-authoring.md`'s "Invocation Convention").
|
|
23
|
+
|
|
24
|
+
This file is generated/synced by `scripts/generate-j-alias.sh btw` from `skills/btw/SKILL.md` — do not hand-edit it; re-run the generator instead to pick up source changes.
|
|
25
|
+
|
|
19
26
|
## Instructions
|
|
20
27
|
|
|
21
28
|
1. **Gather mission details** — Ask the user:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: j
|
|
3
|
-
description: Clarifies ambiguous, dense, or under-specified prompts and conversation on request — inspects an attached prompt or falls back to the current conversation and surfaces plain-language clarifications with examples.
|
|
2
|
+
name: j.clearify
|
|
3
|
+
description: Polyfill alias of the clearify skill under a collision-safe directory name. Identical behavior to /clearify — Clarifies ambiguous, dense, or under-specified prompts and conversation on request — inspects an attached prompt or falls back to the current conversation and surfaces plain-language clarifications with examples. Use when the bare /clearify form is shadowed by another tool's own built-in command of the same name.
|
|
4
4
|
keywords:
|
|
5
5
|
- clarify this
|
|
6
6
|
- clarify
|
|
@@ -9,16 +9,23 @@ keywords:
|
|
|
9
9
|
- wtf
|
|
10
10
|
- explain that again
|
|
11
11
|
- can you simplify
|
|
12
|
+
- j-clearify
|
|
13
|
+
- polyfill
|
|
12
14
|
examples:
|
|
13
15
|
- "clarify this"
|
|
14
16
|
- "clearify the last message"
|
|
15
17
|
- "wtf does this mean"
|
|
16
18
|
- "I don't understand what you're asking me to do here"
|
|
19
|
+
- "j-clearify"
|
|
17
20
|
alias: wtf
|
|
18
21
|
---
|
|
19
22
|
|
|
20
23
|
# Clearify — Ambiguity Clarification
|
|
21
24
|
|
|
25
|
+
This skill is a literal-directory-name duplicate of `skills/clearify/`. It exists so that `/j-clearify` (and `j.j-clearify`) give a guaranteed-unshadowed way to reach the same flow as `/clearify`, even if a host tool's own built-in command of the same name would otherwise shadow or override the bare `/clearify` alias (Claude Code's native skill resolution is a literal-string, directory-name-based match — see `docs/skill-authoring.md`'s "Invocation Convention").
|
|
26
|
+
|
|
27
|
+
This file is generated/synced by `scripts/generate-j-alias.sh clearify` from `skills/clearify/SKILL.md` — do not hand-edit it; re-run the generator instead to pick up source changes.
|
|
28
|
+
|
|
22
29
|
> **Note on the `alias: wtf` frontmatter field:** this repo has no runtime mechanism that reads an `alias` key to route slash commands — no existing `SKILL.md` implements one, and `project/configs/workflow.json` has no alias registry. The field here documents the intended relationship only. `/wtf` is made invocable as a working alias by the companion skill folder at `skills/wtf/SKILL.md`, which delegates to these same instructions.
|
|
23
30
|
|
|
24
31
|
## Instructions
|
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: j
|
|
3
|
-
description: Close a story by verifying all tasks are in terminal state, extracting actual diff stats per task, computing scope divergence flags, and writing closure metadata to task frontmatter.
|
|
2
|
+
name: j.close-story
|
|
3
|
+
description: Polyfill alias of the close-story skill under a collision-safe directory name. Identical behavior to /close-story — Close a story by verifying all tasks are in terminal state, extracting actual diff stats per task, computing scope divergence flags, and writing closure metadata to task frontmatter. Use when the bare /close-story form is shadowed by another tool's own built-in command of the same name.
|
|
4
4
|
keywords:
|
|
5
5
|
- close story
|
|
6
6
|
- close
|
|
7
7
|
- finish story
|
|
8
8
|
- complete story
|
|
9
9
|
- story done
|
|
10
|
+
- j-close-story
|
|
11
|
+
- polyfill
|
|
10
12
|
examples:
|
|
11
13
|
- "close story E17_S06"
|
|
12
14
|
- "/close-story E32_S06"
|
|
13
15
|
- "mark story E12_S03 as done"
|
|
16
|
+
- "j-close-story"
|
|
14
17
|
---
|
|
15
18
|
|
|
16
19
|
# close-story — Close a Story
|
|
17
20
|
|
|
21
|
+
This skill is a literal-directory-name duplicate of `skills/close-story/`. It exists so that `/j-close-story` (and `j.j-close-story`) give a guaranteed-unshadowed way to reach the same flow as `/close-story`, even if a host tool's own built-in command of the same name would otherwise shadow or override the bare `/close-story` alias (Claude Code's native skill resolution is a literal-string, directory-name-based match — see `docs/skill-authoring.md`'s "Invocation Convention").
|
|
22
|
+
|
|
23
|
+
This file is generated/synced by `scripts/generate-j-alias.sh close-story` from `skills/close-story/SKILL.md` — do not hand-edit it; re-run the generator instead to pick up source changes.
|
|
24
|
+
|
|
18
25
|
## Purpose
|
|
19
26
|
|
|
20
27
|
`/close-story <story-id>` performs the final closure steps for a story:
|
|
@@ -38,7 +45,7 @@ examples:
|
|
|
38
45
|
Run the guard script:
|
|
39
46
|
|
|
40
47
|
```bash
|
|
41
|
-
bash skills/close-story/scripts/check-story-closeable.sh <story-id>
|
|
48
|
+
bash skills/j-close-story/scripts/check-story-closeable.sh <story-id>
|
|
42
49
|
```
|
|
43
50
|
|
|
44
51
|
- If it exits with code 0 and prints `CLOSEABLE`, continue.
|
|
@@ -65,7 +72,7 @@ For **each task ID** listed in the story's `tasks:` frontmatter array:
|
|
|
65
72
|
|
|
66
73
|
3. **Run per-task diff stat extraction:**
|
|
67
74
|
```bash
|
|
68
|
-
bash skills/close-story/scripts/extract-task-diff-stats.sh <task-id>
|
|
75
|
+
bash skills/j-close-story/scripts/extract-task-diff-stats.sh <task-id>
|
|
69
76
|
```
|
|
70
77
|
The script outputs:
|
|
71
78
|
```
|
|
@@ -76,11 +83,11 @@ For **each task ID** listed in the story's `tasks:` frontmatter array:
|
|
|
76
83
|
|
|
77
84
|
4. **Write stats to task frontmatter:**
|
|
78
85
|
```bash
|
|
79
|
-
bash skills/close-story/scripts/update-task-frontmatter.sh \
|
|
86
|
+
bash skills/j-close-story/scripts/update-task-frontmatter.sh \
|
|
80
87
|
"project/board/tasks/<task-id>_*.md" \
|
|
81
88
|
actual_files_changed <N>
|
|
82
89
|
|
|
83
|
-
bash skills/close-story/scripts/update-task-frontmatter.sh \
|
|
90
|
+
bash skills/j-close-story/scripts/update-task-frontmatter.sh \
|
|
84
91
|
"project/board/tasks/<task-id>_*.md" \
|
|
85
92
|
actual_lines_delta <N>
|
|
86
93
|
```
|
|
@@ -97,13 +104,13 @@ For **each task ID** listed in the story's `tasks:` frontmatter array:
|
|
|
97
104
|
|
|
98
105
|
Run the divergence computation:
|
|
99
106
|
```bash
|
|
100
|
-
DIVERGENCE_FLAG=$(bash skills/close-story/scripts/compute-scope-divergence.sh \
|
|
107
|
+
DIVERGENCE_FLAG=$(bash skills/j-close-story/scripts/compute-scope-divergence.sh \
|
|
101
108
|
"<execution_scope>" <actual_files_changed> <actual_lines_delta>)
|
|
102
109
|
```
|
|
103
110
|
|
|
104
111
|
Write the result to task frontmatter:
|
|
105
112
|
```bash
|
|
106
|
-
bash skills/close-story/scripts/update-task-frontmatter.sh \
|
|
113
|
+
bash skills/j-close-story/scripts/update-task-frontmatter.sh \
|
|
107
114
|
"project/board/tasks/<task-id>_*.md" \
|
|
108
115
|
scope_divergence_flag "$DIVERGENCE_FLAG"
|
|
109
116
|
```
|
|
@@ -120,7 +127,7 @@ For **each task ID** listed in the story's `tasks:` frontmatter array:
|
|
|
120
127
|
frontmatter writes and divergence computation above, check whether this
|
|
121
128
|
task's own work is permanently excluded from the public mirror:
|
|
122
129
|
```bash
|
|
123
|
-
bash skills/close-story/scripts/check-privatized.sh <task-id> "project/board/tasks/<task-id>_*.md"
|
|
130
|
+
bash skills/j-close-story/scripts/check-privatized.sh <task-id> "project/board/tasks/<task-id>_*.md"
|
|
124
131
|
```
|
|
125
132
|
This is a **static** check (per `templates/SCRUM_BOARD_SCHEMA.md`'s "Static
|
|
126
133
|
vs. Reactive Status Setting" section) — it derives the task's touched-file
|
|
@@ -170,7 +177,7 @@ against the story's own direct commits (E51_S03_T03) **before** deciding the
|
|
|
170
177
|
story's terminal status:
|
|
171
178
|
|
|
172
179
|
```bash
|
|
173
|
-
bash skills/close-story/scripts/check-privatized.sh <story-id> "project/board/stories/<story-id>_*.md"
|
|
180
|
+
bash skills/j-close-story/scripts/check-privatized.sh <story-id> "project/board/stories/<story-id>_*.md"
|
|
174
181
|
```
|
|
175
182
|
|
|
176
183
|
Passing the story id (`E##_S##`) rather than a task id makes the script's
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# ---------------------------------------------------------------------------
|
|
3
|
-
# skills/close-story/scripts/check-privatized.sh
|
|
3
|
+
# skills/j-close-story/scripts/check-privatized.sh
|
|
4
4
|
#
|
|
5
5
|
# Static (run-independent) `.publicignore` membership check for a single
|
|
6
6
|
# board ticket, invoked by /close-story at both task granularity (Step 2's
|
|
@@ -142,7 +142,7 @@ PUBLICIGNORE="$REPO_ROOT/.publicignore"
|
|
|
142
142
|
[ -f "$PUBLICIGNORE" ] || die ".publicignore not found at $PUBLICIGNORE"
|
|
143
143
|
|
|
144
144
|
WITH_LOCK_SCRIPT="$REPO_ROOT/scripts/with-lock.sh"
|
|
145
|
-
UPDATE_FRONTMATTER_SCRIPT="$REPO_ROOT/skills/close-story/scripts/update-task-frontmatter.sh"
|
|
145
|
+
UPDATE_FRONTMATTER_SCRIPT="$REPO_ROOT/skills/j-close-story/scripts/update-task-frontmatter.sh"
|
|
146
146
|
EVENTS_FILE="$REPO_ROOT/project/logs/events.json"
|
|
147
147
|
|
|
148
148
|
[ -f "$WITH_LOCK_SCRIPT" ] || die "expected script not found: $WITH_LOCK_SCRIPT"
|
|
@@ -22,7 +22,7 @@ usage() {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
# Locate the project root relative to this script's location.
|
|
25
|
-
# Script lives at: skills/close-story/scripts/check-story-closeable.sh
|
|
25
|
+
# Script lives at: skills/j-close-story/scripts/check-story-closeable.sh
|
|
26
26
|
# Project root is three levels up (skills/ → repo root).
|
|
27
27
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
28
28
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
#
|
|
13
13
|
# For bundle tasks (a single commit covers multiple task IDs), each task that
|
|
14
14
|
# matches the commit receives the full bundle stats — this is the "full credit"
|
|
15
|
-
# attribution model. See skills/close-story/SKILL.md for the rationale.
|
|
15
|
+
# attribution model. See skills/j-close-story/SKILL.md for the rationale.
|
|
16
16
|
#
|
|
17
17
|
# Exit codes:
|
|
18
18
|
# 0 — success (even when no commits are found; outputs 0 values)
|
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: j
|
|
3
|
-
description: Commit implemented epic, story, or task work using the EST naming convention. Also handles user-action prerequisites and new-epic boundaries. Use after completing any EST work item.
|
|
2
|
+
name: j.commit
|
|
3
|
+
description: Polyfill alias of the commit skill under a collision-safe directory name. Identical behavior to /commit — Commit implemented epic, story, or task work using the EST naming convention. Also handles user-action prerequisites and new-epic boundaries. Use after completing any EST work item. Use when the bare /commit form is shadowed by another tool's own built-in command of the same name.
|
|
4
4
|
keywords:
|
|
5
5
|
- commit
|
|
6
6
|
- save
|
|
7
7
|
- git commit
|
|
8
8
|
- done
|
|
9
9
|
- push
|
|
10
|
+
- j-commit
|
|
11
|
+
- polyfill
|
|
10
12
|
examples:
|
|
11
13
|
- "commit this work"
|
|
12
14
|
- "save my changes"
|
|
15
|
+
- "j-commit"
|
|
13
16
|
---
|
|
14
17
|
|
|
15
18
|
# Commit — Commit Completed Work
|
|
16
19
|
|
|
20
|
+
This skill is a literal-directory-name duplicate of `skills/commit/`. It exists so that `/j-commit` (and `j.j-commit`) give a guaranteed-unshadowed way to reach the same flow as `/commit`, even if a host tool's own built-in command of the same name would otherwise shadow or override the bare `/commit` alias (Claude Code's native skill resolution is a literal-string, directory-name-based match — see `docs/skill-authoring.md`'s "Invocation Convention").
|
|
21
|
+
|
|
22
|
+
This file is generated/synced by `scripts/generate-j-alias.sh commit` from `skills/commit/SKILL.md` — do not hand-edit it; re-run the generator instead to pick up source changes.
|
|
23
|
+
|
|
17
24
|
## Inline Mode (called by /do for inline-scoped tasks)
|
|
18
25
|
|
|
19
26
|
When invoked with the `--inline` flag OR when the environment variable `JENGA_COMMIT_INLINE=1` is set, execute inline mode:
|