@jenga-ai/agent 1.0.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/LICENSE +201 -0
- package/README.md +340 -0
- package/agents/ai_engineer.md +113 -0
- package/agents/developer.md +236 -0
- package/agents/scrum-master.md +349 -0
- package/agents/scrutiny-agent.md +137 -0
- package/agents/solution-assessor.md +185 -0
- package/agents/tester.md +339 -0
- package/bin/jenga.js +70 -0
- package/hooks/copilot_session_end.sh +29 -0
- package/hooks/on_session_end.sh +238 -0
- package/hooks/prompt_router.sh +11 -0
- package/hooks/prompt_router_helper.js +52 -0
- package/hooks/session_end_helper.js +29 -0
- package/hooks/session_end_watcher.sh +24 -0
- package/lib/commands/attach.js +47 -0
- package/lib/commands/init.js +207 -0
- package/lib/commands/start.js +16 -0
- package/lib/commands/status.js +53 -0
- package/lib/config-schema.js +72 -0
- package/lib/inject-settings.js +61 -0
- package/lib/mirror.js +244 -0
- package/lib/resolve-project-dir.sh +47 -0
- package/mcp/execute-ticket/index.js +10 -0
- package/mcp/execute-ticket/package.json +5 -0
- package/mcp/help/index.js +79 -0
- package/mcp/help/package.json +14 -0
- package/mcp/router/README.md +19 -0
- package/mcp/router/embedder.js +23 -0
- package/mcp/router/index.js +204 -0
- package/mcp/router/matcher.js +87 -0
- package/mcp/router/package-lock.json +1048 -0
- package/mcp/router/package.json +11 -0
- package/mcp/router/skill-index.js +104 -0
- package/package.json +47 -0
- package/scripts/board_resolver.sh +46 -0
- package/scripts/e25_s01_extract_board_graph.py +292 -0
- package/scripts/e25_s01_generate_synthetic_board.py +90 -0
- package/scripts/measurement-10x.json +50 -0
- package/scripts/measurement-10x.txt +4 -0
- package/scripts/measurement-real.json +50 -0
- package/scripts/measurement-real.txt +4 -0
- package/scripts/postinstall.js +165 -0
- package/scripts/todo_cleanup.sh +22 -0
- package/scripts/todo_manager.sh +86 -0
- package/scripts/validate-board.sh +190 -0
- package/scripts/validate-story-format.sh +53 -0
- package/skills/brainstorm/SKILL.md +47 -0
- package/skills/btw/SKILL.md +42 -0
- package/skills/commit/SKILL.md +29 -0
- package/skills/commit/assets/user_instructions_template.md +22 -0
- package/skills/continue/SKILL.md +29 -0
- package/skills/convert/SKILL.md +124 -0
- package/skills/convert/convert_cli.py +235 -0
- package/skills/convert/tests/sample.csv +4 -0
- package/skills/convert/tests/sample.json +5 -0
- package/skills/convert/tests/sample.jsonl +3 -0
- package/skills/convert/tests/sample.yaml +18 -0
- package/skills/convert/tests/sample_obj.csv +2 -0
- package/skills/convert/tests/sample_obj.json +9 -0
- package/skills/deep-dive/SKILL.md +167 -0
- package/skills/do/SKILL.md +88 -0
- package/skills/do/assets/sender_template.json +12 -0
- package/skills/doc/SKILL.md +314 -0
- package/skills/doc/assets/path-objectives.yaml +38 -0
- package/skills/doc-sync/SKILL.md +167 -0
- package/skills/doc-sync/assets/default_excludes.txt +21 -0
- package/skills/doc-sync/assets/doc_targets.md +14 -0
- package/skills/dooo/SKILL.md +60 -0
- package/skills/error/SKILL.md +29 -0
- package/skills/evaluate/SKILL.md +45 -0
- package/skills/evaluate/assets/evaluation_invokation_template.yml +3 -0
- package/skills/evaluate/assets/evaluation_rapport_template.md +24 -0
- package/skills/examplify/SKILL.md +42 -0
- package/skills/help/SKILL.md +36 -0
- package/skills/improve/SKILL.md +55 -0
- package/skills/index/scripts/board-index +4 -0
- package/skills/index/scripts/board_index.py +615 -0
- package/skills/index/scripts/smoke_test.sh +86 -0
- package/skills/init/SKILL.md +44 -0
- package/skills/init/assets/.gitignore_template +15 -0
- package/skills/init/assets/PROJECT_SUMMARY_template.md +13 -0
- package/skills/init/assets/directory_structure.txt +13 -0
- package/skills/init/assets/test-config_template.json +4 -0
- package/skills/init/assets/workflow_template.json +30 -0
- package/skills/init/scripts/init.sh +48 -0
- package/skills/jbp/SKILL.md +25 -0
- package/skills/jenga/SKILL.md +68 -0
- package/skills/lgtm/SKILL.md +21 -0
- package/skills/mirror-public/SKILL.md +237 -0
- package/skills/mirror-public/assets/config.json +5 -0
- package/skills/mirror-public/scripts/mirror.sh +374 -0
- package/skills/pi-plan/SKILL.md +62 -0
- package/skills/pi-plan/assets/epic.json +7 -0
- package/skills/pi-plan/assets/story_template.md +18 -0
- package/skills/proceed/SKILL.md +29 -0
- package/skills/publish/SKILL.md +351 -0
- package/skills/publish/adapters/droplet.md +200 -0
- package/skills/publish/adapters/mobile-ios.md +114 -0
- package/skills/publish/adapters/npm-ci.md +223 -0
- package/skills/publish/adapters/npm.md +121 -0
- package/skills/publish/assets/ExportOptions.plist.template +19 -0
- package/skills/publish/assets/ci-contract.md +111 -0
- package/skills/publish/assets/ownership-matrix.md +17 -0
- package/skills/publish/assets/publish.example.json +85 -0
- package/skills/publish/assets/publish.example.npm-ci.json +40 -0
- package/skills/publish/assets/publish.example.npm.json +41 -0
- package/skills/publish/assets/secrets-guide.md +104 -0
- package/skills/publish/schemas/fixtures/npm-ci-minimal.json +17 -0
- package/skills/publish/schemas/fixtures/npm-ci-with-empty-secrets.json +18 -0
- package/skills/publish/schemas/fixtures/npm-ci-with-workflow-path.json +18 -0
- package/skills/publish/schemas/publish.schema.json +428 -0
- package/skills/publish/scripts/check_target_config.sh +96 -0
- package/skills/publish/scripts/droplet_pipeline.sh +208 -0
- package/skills/publish/scripts/generate_release_notes.sh +200 -0
- package/skills/publish/scripts/ios_pipeline.sh +486 -0
- package/skills/publish/scripts/npm_ci_pipeline.sh +225 -0
- package/skills/publish/scripts/npm_pipeline.sh +249 -0
- package/skills/publish/scripts/publish_common.sh +253 -0
- package/skills/publish/scripts/publish_deploy.sh +538 -0
- package/skills/publish/scripts/reconcile_tags.sh +135 -0
- package/skills/publish/scripts/run_gates.sh +616 -0
- package/skills/publish/scripts/setup_wizard.sh +394 -0
- package/skills/publish/scripts/show_history.sh +95 -0
- package/skills/publish/scripts/suggest_semver_bump.sh +105 -0
- package/skills/publish/scripts/validate_config.sh +163 -0
- package/skills/publish/scripts/validate_droplet_env.sh +45 -0
- package/skills/publish/scripts/validate_ios_env.sh +68 -0
- package/skills/publish/scripts/validate_npm_ci_env.sh +71 -0
- package/skills/publish/scripts/validate_npm_env.sh +22 -0
- package/skills/publish/scripts/write_ledger_entry.sh +126 -0
- package/skills/publish/wizards/droplet.md +275 -0
- package/skills/publish/wizards/mobile-ios.md +157 -0
- package/skills/publish/wizards/npm-ci.md +240 -0
- package/skills/publish/wizards/npm.md +224 -0
- package/skills/reconcile/SKILL.md +93 -0
- package/skills/reconcile/assets/report_format.md +44 -0
- package/skills/reconcile-origin/SKILL.md +75 -0
- package/skills/reconcile-origin/scripts/reconcile-origin.sh +372 -0
- package/skills/redo/SKILL.md +70 -0
- package/skills/route/SKILL.md +180 -0
- package/skills/self-sync/SKILL.md +73 -0
- package/skills/self-sync/scripts/run.js +136 -0
- package/skills/skillify/SKILL.md +68 -0
- package/skills/skillify/assets/init-new/SKILL.md +35 -0
- package/skills/skillify/assets/init-new/assets/.gitignore_template +15 -0
- package/skills/skillify/assets/init-new/assets/PROJECT_SUMMARY_template.md +13 -0
- package/skills/skillify/assets/init-new/assets/directory_structure.txt +10 -0
- package/skills/skillify/assets/init-new/assets/test-config_template.json +4 -0
- package/skills/skillify/assets/init-new/assets/workflow_template.json +17 -0
- package/skills/skillify/assets/init-new/scripts/init.sh +48 -0
- package/skills/skillify/assets/init-old/SKILL.md +124 -0
- package/skills/spinoff/SKILL.md +48 -0
- package/skills/status/SKILL.md +33 -0
- package/skills/status/assets/output_format.md +41 -0
- package/skills/todo/SKILL.md +46 -0
- package/skills/todo/assets/todo_handoff_template.md +22 -0
- package/skills/todo/assets/todo_template.md +3 -0
- package/skills/train/SKILL.md +116 -0
- package/skills/train/assets/dashboard-templates/classifiers.html +106 -0
- package/skills/train/assets/dashboard-templates/nlp.html +102 -0
- package/skills/train/assets/dashboard-templates/transformers.html +98 -0
- package/skills/train/assets/results-parsers/__init__.py +9 -0
- package/skills/train/assets/results-parsers/classifiers.py +84 -0
- package/skills/train/assets/results-parsers/nlp.py +88 -0
- package/skills/train/assets/results-parsers/reporter.py +154 -0
- package/skills/train/assets/results-parsers/transformers.py +120 -0
- package/skills/train/train_cli.py +786 -0
- package/templates/EXECUTION_PLAN_TEMPLATE.md +43 -0
- package/templates/EXECUTION_SUMMARY_TEMPLATE.md +50 -0
- package/templates/JENGA_CONFIG_TEMPLATE.json +23 -0
- package/templates/PROBLEM_RAPPORT_TEMPLATE.md +88 -0
- package/templates/SCRUM_BOARD_SCHEMA.md +311 -0
- package/templates/SKILL.md +16 -0
- package/templates/SKILL_TEMPLATE.md +28 -0
- package/templates/USER_INSTRUCTIONS_TEMPLATE.md +22 -0
- package/templates/copilot-instructions.md.tpl +55 -0
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ---------------------------------------------------------------------------
|
|
3
|
+
# skills/mirror-public/scripts/mirror.sh
|
|
4
|
+
#
|
|
5
|
+
# One-way sync engine for /mirror-public.
|
|
6
|
+
#
|
|
7
|
+
# Reads: skills/mirror-public/assets/config.json
|
|
8
|
+
# - publicRepoUrl : URL of the public downstream repo
|
|
9
|
+
# - defaultBranch : branch to sync (typically "main")
|
|
10
|
+
# - worktreePath : scratch worktree path (relative to repo root)
|
|
11
|
+
# .publicignore : rsync blocklist (single source of truth for
|
|
12
|
+
# private-only paths — see T01)
|
|
13
|
+
#
|
|
14
|
+
# Flow:
|
|
15
|
+
# 1. Prepare a scratch clone of <publicRepoUrl> at <worktreePath>, checked
|
|
16
|
+
# out to <defaultBranch> at the tip of origin/<defaultBranch>.
|
|
17
|
+
# 2. Safety-check origin/<defaultBranch> against the local `last-mirror-sync`
|
|
18
|
+
# tag in the scratch clone. Abort if the public branch has diverged
|
|
19
|
+
# unless --force is passed.
|
|
20
|
+
# 3. rsync the private repo root into the worktree, respecting
|
|
21
|
+
# .publicignore and explicitly excluding .git/.
|
|
22
|
+
# 4. If nothing changed, exit 0 idempotently.
|
|
23
|
+
# 5. Otherwise squash everything into a single "chore(mirror): sync from
|
|
24
|
+
# private at <short-sha> <UTC-timestamp>" commit with a
|
|
25
|
+
# `Source-Commit: <full-sha>` trailer, advance the local marker tag,
|
|
26
|
+
# and push origin/<defaultBranch>.
|
|
27
|
+
# 6. Print a summary (files-changed count, new commit SHA, remote branch,
|
|
28
|
+
# public URL).
|
|
29
|
+
#
|
|
30
|
+
# Flags:
|
|
31
|
+
# --dry-run Read-only preview mode. Prepares the scratch worktree
|
|
32
|
+
# (fetch+reset only — no rsync writes, no commit, no push),
|
|
33
|
+
# then prints two labeled sections:
|
|
34
|
+
# - "Files that would ship" (from rsync --dry-run)
|
|
35
|
+
# - "Files that would be blocked" (candidates \ shipped)
|
|
36
|
+
# Followed by totals and an explicit "dry run — no push" notice.
|
|
37
|
+
# --force Override the safety-abort when the public branch is ahead
|
|
38
|
+
# of the recorded last mirror.
|
|
39
|
+
# -h|--help Print usage and exit.
|
|
40
|
+
#
|
|
41
|
+
# Env overrides:
|
|
42
|
+
# MIRROR_PUBLIC_URL_OVERRIDE Swap the configured publicRepoUrl at
|
|
43
|
+
# runtime (used for local-remote testing).
|
|
44
|
+
#
|
|
45
|
+
# The script NEVER modifies the private repo's .git/ or working tree.
|
|
46
|
+
# ---------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
set -euo pipefail
|
|
49
|
+
IFS=$'\n\t'
|
|
50
|
+
|
|
51
|
+
# -----------------------------------------------------------------------------
|
|
52
|
+
# Helpers
|
|
53
|
+
# -----------------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
die() {
|
|
56
|
+
printf 'mirror.sh: error: %s\n' "$*" >&2
|
|
57
|
+
exit 1
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
log() {
|
|
61
|
+
printf 'mirror.sh: %s\n' "$*"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
usage() {
|
|
65
|
+
cat <<'EOF'
|
|
66
|
+
Usage: mirror.sh [--dry-run] [--force] [-h|--help]
|
|
67
|
+
|
|
68
|
+
Options:
|
|
69
|
+
--dry-run Read-only preview. Prints the exact list of files that would
|
|
70
|
+
ship and the list of files blocked by .publicignore, then
|
|
71
|
+
exits with no commit and no push.
|
|
72
|
+
--force Override the safety abort when the public branch has moved
|
|
73
|
+
since the last mirror.
|
|
74
|
+
-h, --help Show this message and exit.
|
|
75
|
+
|
|
76
|
+
Env:
|
|
77
|
+
MIRROR_PUBLIC_URL_OVERRIDE Override the configured publicRepoUrl.
|
|
78
|
+
EOF
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
# -----------------------------------------------------------------------------
|
|
82
|
+
# Locate script + repo root
|
|
83
|
+
# -----------------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
SCRIPT_PATH="${BASH_SOURCE[0]}"
|
|
86
|
+
# Resolve symlinks to a real path so SCRIPT_DIR points at the on-disk file.
|
|
87
|
+
while [ -h "$SCRIPT_PATH" ]; do
|
|
88
|
+
LINK_TARGET="$(readlink "$SCRIPT_PATH")"
|
|
89
|
+
case "$LINK_TARGET" in
|
|
90
|
+
/*) SCRIPT_PATH="$LINK_TARGET" ;;
|
|
91
|
+
*) SCRIPT_PATH="$(cd "$(dirname "$SCRIPT_PATH")" && pwd)/$LINK_TARGET" ;;
|
|
92
|
+
esac
|
|
93
|
+
done
|
|
94
|
+
SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_PATH")" && pwd)"
|
|
95
|
+
SKILL_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
96
|
+
|
|
97
|
+
REPO_ROOT="$(git -C "$SKILL_DIR" rev-parse --show-toplevel 2>/dev/null || true)"
|
|
98
|
+
[ -n "$REPO_ROOT" ] || die "could not locate private repo root (git rev-parse failed from $SKILL_DIR)"
|
|
99
|
+
|
|
100
|
+
CONFIG_FILE="$SKILL_DIR/assets/config.json"
|
|
101
|
+
[ -f "$CONFIG_FILE" ] || die "config not found: $CONFIG_FILE"
|
|
102
|
+
|
|
103
|
+
PUBLICIGNORE="$REPO_ROOT/.publicignore"
|
|
104
|
+
[ -f "$PUBLICIGNORE" ] || die ".publicignore not found at $PUBLICIGNORE (should have been created in T01)"
|
|
105
|
+
|
|
106
|
+
# -----------------------------------------------------------------------------
|
|
107
|
+
# Parse flags
|
|
108
|
+
# -----------------------------------------------------------------------------
|
|
109
|
+
|
|
110
|
+
DRY_RUN=0
|
|
111
|
+
FORCE=0
|
|
112
|
+
|
|
113
|
+
while [ $# -gt 0 ]; do
|
|
114
|
+
case "$1" in
|
|
115
|
+
--dry-run) DRY_RUN=1 ;;
|
|
116
|
+
--force) FORCE=1 ;;
|
|
117
|
+
-h|--help) usage; exit 0 ;;
|
|
118
|
+
*) usage >&2; die "unknown argument: $1" ;;
|
|
119
|
+
esac
|
|
120
|
+
shift
|
|
121
|
+
done
|
|
122
|
+
|
|
123
|
+
# -----------------------------------------------------------------------------
|
|
124
|
+
# Load config (jq preferred, python3 fallback)
|
|
125
|
+
# -----------------------------------------------------------------------------
|
|
126
|
+
|
|
127
|
+
read_config_field() {
|
|
128
|
+
local field="$1"
|
|
129
|
+
if command -v jq >/dev/null 2>&1; then
|
|
130
|
+
jq -er --arg f "$field" '.[$f]' "$CONFIG_FILE" 2>/dev/null || return 1
|
|
131
|
+
elif command -v python3 >/dev/null 2>&1; then
|
|
132
|
+
python3 - "$CONFIG_FILE" "$field" <<'PY' || return 1
|
|
133
|
+
import json, sys
|
|
134
|
+
path, field = sys.argv[1], sys.argv[2]
|
|
135
|
+
with open(path) as fh:
|
|
136
|
+
data = json.load(fh)
|
|
137
|
+
if field not in data:
|
|
138
|
+
sys.exit(1)
|
|
139
|
+
sys.stdout.write(str(data[field]))
|
|
140
|
+
PY
|
|
141
|
+
else
|
|
142
|
+
die "neither jq nor python3 available to parse $CONFIG_FILE"
|
|
143
|
+
fi
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
PUBLIC_URL="$(read_config_field publicRepoUrl)" || die "config missing publicRepoUrl"
|
|
147
|
+
DEFAULT_BRANCH="$(read_config_field defaultBranch)" || die "config missing defaultBranch"
|
|
148
|
+
WORKTREE_REL="$(read_config_field worktreePath)" || die "config missing worktreePath"
|
|
149
|
+
|
|
150
|
+
# Env override for local-remote testing.
|
|
151
|
+
if [ -n "${MIRROR_PUBLIC_URL_OVERRIDE:-}" ]; then
|
|
152
|
+
log "using MIRROR_PUBLIC_URL_OVERRIDE=$MIRROR_PUBLIC_URL_OVERRIDE (config value ignored)"
|
|
153
|
+
PUBLIC_URL="$MIRROR_PUBLIC_URL_OVERRIDE"
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
# Resolve worktree path against repo root if it's relative.
|
|
157
|
+
case "$WORKTREE_REL" in
|
|
158
|
+
/*) WORKTREE_PATH="$WORKTREE_REL" ;;
|
|
159
|
+
*) WORKTREE_PATH="$REPO_ROOT/$WORKTREE_REL" ;;
|
|
160
|
+
esac
|
|
161
|
+
|
|
162
|
+
log "repo root: $REPO_ROOT"
|
|
163
|
+
log "public URL: $PUBLIC_URL"
|
|
164
|
+
log "default branch: $DEFAULT_BRANCH"
|
|
165
|
+
log "worktree path: $WORKTREE_PATH"
|
|
166
|
+
|
|
167
|
+
# -----------------------------------------------------------------------------
|
|
168
|
+
# Prepare scratch worktree (clone if missing, fetch+reset if present)
|
|
169
|
+
# -----------------------------------------------------------------------------
|
|
170
|
+
|
|
171
|
+
mkdir -p "$(dirname "$WORKTREE_PATH")"
|
|
172
|
+
|
|
173
|
+
if [ ! -d "$WORKTREE_PATH/.git" ]; then
|
|
174
|
+
log "cloning $PUBLIC_URL -> $WORKTREE_PATH (branch: $DEFAULT_BRANCH)"
|
|
175
|
+
git clone --branch "$DEFAULT_BRANCH" --single-branch "$PUBLIC_URL" "$WORKTREE_PATH"
|
|
176
|
+
else
|
|
177
|
+
log "refreshing existing scratch worktree at $WORKTREE_PATH"
|
|
178
|
+
git -C "$WORKTREE_PATH" remote set-url origin "$PUBLIC_URL"
|
|
179
|
+
git -C "$WORKTREE_PATH" fetch origin "$DEFAULT_BRANCH"
|
|
180
|
+
git -C "$WORKTREE_PATH" checkout -B "$DEFAULT_BRANCH" "origin/$DEFAULT_BRANCH"
|
|
181
|
+
git -C "$WORKTREE_PATH" reset --hard "origin/$DEFAULT_BRANCH"
|
|
182
|
+
# Preserve the marker tag if it exists; -x would leave untracked scratch,
|
|
183
|
+
# but -fd is enough because we hard-reset above.
|
|
184
|
+
git -C "$WORKTREE_PATH" clean -fd
|
|
185
|
+
fi
|
|
186
|
+
|
|
187
|
+
# -----------------------------------------------------------------------------
|
|
188
|
+
# Safety check: last-mirror-sync tag vs origin/<branch>
|
|
189
|
+
# -----------------------------------------------------------------------------
|
|
190
|
+
|
|
191
|
+
MARKER_SHA="$(git -C "$WORKTREE_PATH" rev-parse -q --verify refs/tags/last-mirror-sync 2>/dev/null || true)"
|
|
192
|
+
REMOTE_HEAD="$(git -C "$WORKTREE_PATH" rev-parse "origin/$DEFAULT_BRANCH")"
|
|
193
|
+
|
|
194
|
+
if [ -z "$MARKER_SHA" ]; then
|
|
195
|
+
log "no last-mirror-sync tag found (first mirror or wiped scratch) — proceeding"
|
|
196
|
+
elif [ "$MARKER_SHA" = "$REMOTE_HEAD" ]; then
|
|
197
|
+
log "last-mirror-sync matches origin/$DEFAULT_BRANCH — safe to proceed"
|
|
198
|
+
else
|
|
199
|
+
if [ "$FORCE" -eq 1 ]; then
|
|
200
|
+
log "WARNING: origin/$DEFAULT_BRANCH ($REMOTE_HEAD) has moved past last-mirror-sync ($MARKER_SHA); proceeding due to --force"
|
|
201
|
+
else
|
|
202
|
+
die "origin/$DEFAULT_BRANCH ($REMOTE_HEAD) has moved past last-mirror-sync ($MARKER_SHA). The public repo has commits the mirror did not create. Re-run with --force to overwrite."
|
|
203
|
+
fi
|
|
204
|
+
fi
|
|
205
|
+
|
|
206
|
+
command -v rsync >/dev/null 2>&1 || die "rsync not installed"
|
|
207
|
+
|
|
208
|
+
# -----------------------------------------------------------------------------
|
|
209
|
+
# --dry-run: full read-only preview
|
|
210
|
+
#
|
|
211
|
+
# Compute + print the exact "would ship" set (from rsync --dry-run --itemize)
|
|
212
|
+
# and the "would be blocked" set (git-tracked/untracked candidates minus the
|
|
213
|
+
# ship set). Zero rsync writes, zero commits, zero pushes.
|
|
214
|
+
# -----------------------------------------------------------------------------
|
|
215
|
+
|
|
216
|
+
if [ "$DRY_RUN" -eq 1 ]; then
|
|
217
|
+
log "dry-run: computing ship + blocked sets (no rsync write, no commit, no push)"
|
|
218
|
+
|
|
219
|
+
SHIP_LIST_FILE="$(mktemp -t mirror-ship.XXXXXX)"
|
|
220
|
+
CANDIDATE_LIST_FILE="$(mktemp -t mirror-candidates.XXXXXX)"
|
|
221
|
+
BLOCKED_LIST_FILE="$(mktemp -t mirror-blocked.XXXXXX)"
|
|
222
|
+
# shellcheck disable=SC2064
|
|
223
|
+
trap "rm -f '$SHIP_LIST_FILE' '$CANDIDATE_LIST_FILE' '$BLOCKED_LIST_FILE'" EXIT
|
|
224
|
+
|
|
225
|
+
# 1. Ship list — rsync --dry-run --itemize-changes uses the SAME flag set as
|
|
226
|
+
# the real run below, so the emitted transfer list is exactly what the real
|
|
227
|
+
# run would transfer. Itemize flag format is 11 chars: YXcstpoguax
|
|
228
|
+
# Y (update type): >=receive, <=send, c=create local, h=hard link,
|
|
229
|
+
# .=no update, *=message (e.g. deleting)
|
|
230
|
+
# X (file type): f=file, d=directory, L=symlink, D=device, S=special
|
|
231
|
+
# We keep any entry that transfers/creates a file OR a symlink OR a hardlink,
|
|
232
|
+
# and drop directory-only entries (rsync recreates dirs implicitly) and any
|
|
233
|
+
# attribute-only / deletion / message lines. This matches exactly what the
|
|
234
|
+
# real rsync would push into the scratch worktree and therefore into the
|
|
235
|
+
# public remote.
|
|
236
|
+
rsync -a --delete \
|
|
237
|
+
--exclude-from="$PUBLICIGNORE" \
|
|
238
|
+
--exclude=".git" \
|
|
239
|
+
--dry-run --itemize-changes --out-format='%i %n' \
|
|
240
|
+
"$REPO_ROOT/" \
|
|
241
|
+
"$WORKTREE_PATH/" \
|
|
242
|
+
| awk '{
|
|
243
|
+
flag = $1;
|
|
244
|
+
first = substr(flag, 1, 1);
|
|
245
|
+
second = substr(flag, 2, 1);
|
|
246
|
+
# Skip directories — public tree recreates them implicitly.
|
|
247
|
+
if (second == "d") next;
|
|
248
|
+
# Keep only entries that transfer or create a file/symlink/hardlink.
|
|
249
|
+
keep = 0;
|
|
250
|
+
if (first == ">" || first == "<") keep = 1; # file transfer
|
|
251
|
+
else if (first == "c" && second == "L") keep = 1; # create symlink
|
|
252
|
+
else if (first == "h") keep = 1; # hard link
|
|
253
|
+
if (!keep) next;
|
|
254
|
+
# Rebuild path (everything after the flag token).
|
|
255
|
+
$1 = "";
|
|
256
|
+
sub(/^ /, "");
|
|
257
|
+
# Strip trailing slash just in case (should only appear on dirs, which
|
|
258
|
+
# we already skipped, but be defensive).
|
|
259
|
+
sub(/\/$/, "");
|
|
260
|
+
if (length($0) > 0) print $0;
|
|
261
|
+
}' \
|
|
262
|
+
| LC_ALL=C sort -u > "$SHIP_LIST_FILE"
|
|
263
|
+
|
|
264
|
+
# 2. Candidate list — every tracked file plus every untracked-not-gitignored
|
|
265
|
+
# file under the private repo root. This is the honest "what the maintainer
|
|
266
|
+
# thinks of as the repo" set.
|
|
267
|
+
git -C "$REPO_ROOT" ls-files -co --exclude-standard \
|
|
268
|
+
| LC_ALL=C sort -u > "$CANDIDATE_LIST_FILE"
|
|
269
|
+
|
|
270
|
+
# 3. Blocked = candidates \ shipped.
|
|
271
|
+
LC_ALL=C comm -23 "$CANDIDATE_LIST_FILE" "$SHIP_LIST_FILE" > "$BLOCKED_LIST_FILE"
|
|
272
|
+
|
|
273
|
+
SHIP_COUNT="$(wc -l < "$SHIP_LIST_FILE" | tr -d ' ')"
|
|
274
|
+
BLOCKED_COUNT="$(wc -l < "$BLOCKED_LIST_FILE" | tr -d ' ')"
|
|
275
|
+
|
|
276
|
+
printf '\n'
|
|
277
|
+
printf '=== Files that would ship (%s) ===\n' "$SHIP_COUNT"
|
|
278
|
+
if [ "$SHIP_COUNT" -eq 0 ]; then
|
|
279
|
+
printf ' (none — public tree already matches private, post-blocklist)\n'
|
|
280
|
+
else
|
|
281
|
+
cat "$SHIP_LIST_FILE"
|
|
282
|
+
fi
|
|
283
|
+
|
|
284
|
+
printf '\n'
|
|
285
|
+
printf '=== Files that would be blocked (%s) ===\n' "$BLOCKED_COUNT"
|
|
286
|
+
if [ "$BLOCKED_COUNT" -eq 0 ]; then
|
|
287
|
+
printf ' (none — .publicignore matched nothing under this repo)\n'
|
|
288
|
+
else
|
|
289
|
+
cat "$BLOCKED_LIST_FILE"
|
|
290
|
+
fi
|
|
291
|
+
|
|
292
|
+
printf '\n'
|
|
293
|
+
printf '================ mirror-public dry-run summary ================\n'
|
|
294
|
+
printf 'would ship : %s files\n' "$SHIP_COUNT"
|
|
295
|
+
printf 'would block : %s files\n' "$BLOCKED_COUNT"
|
|
296
|
+
printf 'public URL : %s\n' "$PUBLIC_URL"
|
|
297
|
+
printf 'remote branch : %s\n' "$DEFAULT_BRANCH"
|
|
298
|
+
printf 'dry run — no push, no commit, no remote mutation\n'
|
|
299
|
+
printf '===============================================================\n'
|
|
300
|
+
|
|
301
|
+
exit 0
|
|
302
|
+
fi
|
|
303
|
+
|
|
304
|
+
# -----------------------------------------------------------------------------
|
|
305
|
+
# rsync private root -> scratch worktree
|
|
306
|
+
# -----------------------------------------------------------------------------
|
|
307
|
+
|
|
308
|
+
log "rsync $REPO_ROOT/ -> $WORKTREE_PATH/ (excludes: .publicignore + .git)"
|
|
309
|
+
rsync -a --delete \
|
|
310
|
+
--exclude-from="$PUBLICIGNORE" \
|
|
311
|
+
--exclude=".git" \
|
|
312
|
+
"$REPO_ROOT/" \
|
|
313
|
+
"$WORKTREE_PATH/"
|
|
314
|
+
|
|
315
|
+
# -----------------------------------------------------------------------------
|
|
316
|
+
# Stage + detect changes (idempotency)
|
|
317
|
+
# -----------------------------------------------------------------------------
|
|
318
|
+
|
|
319
|
+
git -C "$WORKTREE_PATH" add -A
|
|
320
|
+
|
|
321
|
+
if git -C "$WORKTREE_PATH" diff --cached --quiet; then
|
|
322
|
+
log "nothing to mirror — public tree already matches private (post-blocklist)"
|
|
323
|
+
exit 0
|
|
324
|
+
fi
|
|
325
|
+
|
|
326
|
+
# -----------------------------------------------------------------------------
|
|
327
|
+
# Squash commit
|
|
328
|
+
# -----------------------------------------------------------------------------
|
|
329
|
+
|
|
330
|
+
PRIVATE_SHORT_SHA="$(git -C "$REPO_ROOT" rev-parse --short HEAD)"
|
|
331
|
+
PRIVATE_FULL_SHA="$(git -C "$REPO_ROOT" rev-parse HEAD)"
|
|
332
|
+
UTC_TS="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
333
|
+
|
|
334
|
+
COMMIT_SUBJECT="chore(mirror): sync from private at $PRIVATE_SHORT_SHA $UTC_TS"
|
|
335
|
+
COMMIT_TRAILER="Source-Commit: $PRIVATE_FULL_SHA"
|
|
336
|
+
|
|
337
|
+
# Ensure the scratch clone has a committer identity even in ephemeral CI/test.
|
|
338
|
+
if ! git -C "$WORKTREE_PATH" config user.email >/dev/null 2>&1; then
|
|
339
|
+
git -C "$WORKTREE_PATH" config user.email "mirror-public@jenga.local"
|
|
340
|
+
fi
|
|
341
|
+
if ! git -C "$WORKTREE_PATH" config user.name >/dev/null 2>&1; then
|
|
342
|
+
git -C "$WORKTREE_PATH" config user.name "jenga mirror-public"
|
|
343
|
+
fi
|
|
344
|
+
|
|
345
|
+
git -C "$WORKTREE_PATH" commit -m "$COMMIT_SUBJECT" -m "$COMMIT_TRAILER" >/dev/null
|
|
346
|
+
|
|
347
|
+
NEW_SHA="$(git -C "$WORKTREE_PATH" rev-parse HEAD)"
|
|
348
|
+
|
|
349
|
+
# -----------------------------------------------------------------------------
|
|
350
|
+
# Advance marker tag (LOCAL to scratch clone — never pushed)
|
|
351
|
+
# -----------------------------------------------------------------------------
|
|
352
|
+
|
|
353
|
+
git -C "$WORKTREE_PATH" tag -f last-mirror-sync HEAD >/dev/null
|
|
354
|
+
|
|
355
|
+
# -----------------------------------------------------------------------------
|
|
356
|
+
# Push
|
|
357
|
+
# -----------------------------------------------------------------------------
|
|
358
|
+
|
|
359
|
+
log "pushing $NEW_SHA -> origin/$DEFAULT_BRANCH"
|
|
360
|
+
git -C "$WORKTREE_PATH" push origin "$DEFAULT_BRANCH"
|
|
361
|
+
|
|
362
|
+
# -----------------------------------------------------------------------------
|
|
363
|
+
# Summary
|
|
364
|
+
# -----------------------------------------------------------------------------
|
|
365
|
+
|
|
366
|
+
FILES_CHANGED="$(git -C "$WORKTREE_PATH" diff-tree --no-commit-id --name-only -r HEAD | wc -l | tr -d ' ')"
|
|
367
|
+
|
|
368
|
+
printf '\n'
|
|
369
|
+
printf '================ mirror-public summary ================\n'
|
|
370
|
+
printf 'files changed : %s\n' "$FILES_CHANGED"
|
|
371
|
+
printf 'new commit : %s\n' "$NEW_SHA"
|
|
372
|
+
printf 'remote branch : %s\n' "$DEFAULT_BRANCH"
|
|
373
|
+
printf 'public URL : %s\n' "$PUBLIC_URL"
|
|
374
|
+
printf '=======================================================\n'
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pi-plan
|
|
3
|
+
description: Define or expand project Epics in PROJECT_SUMMARY.md. Use this at the start of a project to establish its foundation, AND whenever the user wants to add major new features, plan a significant new area of work, or make epic-level changes to an existing project. Trigger whenever you hear things like "new feature area", "big change", "new epic", "expand the project", "add a major capability", or "plan a new phase" — even mid-project.
|
|
4
|
+
keywords:
|
|
5
|
+
- epic
|
|
6
|
+
- template
|
|
7
|
+
- expand
|
|
8
|
+
- new feature area
|
|
9
|
+
- project structure
|
|
10
|
+
examples:
|
|
11
|
+
- "add a new epic for X"
|
|
12
|
+
- "expand the project with a new feature area"
|
|
13
|
+
metadata:
|
|
14
|
+
prefered_agent: scrum-master
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Pi-plan — Define and Expand Project Epics
|
|
18
|
+
|
|
19
|
+
## When to use this skill
|
|
20
|
+
|
|
21
|
+
- **New project**: Gather project description and goals, then define the initial set of Epics.
|
|
22
|
+
- **Existing project**: Add one or more new Epics to an existing `PROJECT_SUMMARY.md` when the user wants to plan a major new area of work.
|
|
23
|
+
|
|
24
|
+
Detect which mode you're in by checking whether `project/PROJECT_SUMMARY.md` already exists and has Epics defined.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Mode 1: New Project
|
|
29
|
+
|
|
30
|
+
1. **Gather project info** — Ask the user for:
|
|
31
|
+
- **Description**: A high-level explanation of what the app or service does (an "elevator pitch").
|
|
32
|
+
- **Goals**: What specific problem(s) the project is intended to solve. Be clear about the desired outcome.
|
|
33
|
+
|
|
34
|
+
2. **Clarify scope** — If the responses are unclear or lack sufficient detail, ask clarifying questions. The goal is a broad understanding — avoid delving into granular details unless they directly impact the core idea.
|
|
35
|
+
|
|
36
|
+
3. **Define Epics** — Using the description and goals, define the Epics section of `project/PROJECT_SUMMARY.md`. Each Epic is a JSON object:
|
|
37
|
+
|
|
38
|
+
- **title**: Concise title for the Epic.
|
|
39
|
+
- **short_description**: Brief explanation of what this Epic aims to achieve.
|
|
40
|
+
- **date_added**: Today's date (YYYY-MM-DD).
|
|
41
|
+
- **date_started**: Set to `null` initially.
|
|
42
|
+
- **related_stories**: Empty array `[]` initially.
|
|
43
|
+
|
|
44
|
+
Example: `./assets/epic.json`.
|
|
45
|
+
|
|
46
|
+
Story files created under `project/board/stories/` should follow `./assets/story_template.md`.
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Mode 2: Existing Project — Adding New Epics
|
|
50
|
+
|
|
51
|
+
1. **Read the existing file** — Load `project/PROJECT_SUMMARY.md` to understand the current project context and existing Epics. This prevents duplication and ensures new Epics are coherent with what's already there.
|
|
52
|
+
|
|
53
|
+
2. **Understand the new scope** — Ask the user:
|
|
54
|
+
- What is the new capability, feature area, or phase they want to add?
|
|
55
|
+
- What problem does it solve, or what goal does it serve?
|
|
56
|
+
- Are there any dependencies on existing Epics?
|
|
57
|
+
|
|
58
|
+
3. **Clarify if needed** — Same as Mode 1: ask follow-up questions if the scope is vague, but stay high-level.
|
|
59
|
+
|
|
60
|
+
4. **Define new Epics** — Draft one or more new Epic objects using the same schema as above, then append them to the existing Epics list in `project/PROJECT_SUMMARY.md`. Do not modify existing Epics unless the user explicitly asks.
|
|
61
|
+
|
|
62
|
+
5. **Confirm before writing** — Show the user the proposed new Epic(s) and get confirmation before updating the file.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Story: <title>
|
|
2
|
+
|
|
3
|
+
**ID**: E##_S##
|
|
4
|
+
**Epic**: E## — <epic title>
|
|
5
|
+
**Status**: Pending
|
|
6
|
+
**Date Added**: YYYY-MM-DD
|
|
7
|
+
|
|
8
|
+
## Description
|
|
9
|
+
|
|
10
|
+
<what this story aims to achieve>
|
|
11
|
+
|
|
12
|
+
## Acceptance Criteria
|
|
13
|
+
|
|
14
|
+
- [ ] <criterion>
|
|
15
|
+
|
|
16
|
+
## Tasks
|
|
17
|
+
|
|
18
|
+
<!-- Tasks will be added during implementation -->
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: proceed
|
|
3
|
+
description: Review project progress by checking epics and stories, optionally consulting PROJECT_SUMMARY.md and WARP.md, then continue executing the project plan.
|
|
4
|
+
keywords:
|
|
5
|
+
- proceed
|
|
6
|
+
- review progress
|
|
7
|
+
- check epics
|
|
8
|
+
- continue executing
|
|
9
|
+
examples:
|
|
10
|
+
- "proceed with the plan"
|
|
11
|
+
- "review progress and continue"
|
|
12
|
+
metadata:
|
|
13
|
+
prefered_agent: scrum-master
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Proceed — Resume Project Execution
|
|
17
|
+
|
|
18
|
+
## Instructions
|
|
19
|
+
|
|
20
|
+
1. **Assess progress** — Read `project/PROJECT_SUMMARY.md`, then check `project/board/epics/`, `project/board/stories/`, and `project/board/tasks/` to determine how far the project has come and what is outstanding.
|
|
21
|
+
|
|
22
|
+
2. **Check queues** — Review `project/queue/scrum_triggers.jsonl` for any pending triggers (rollup reviews, rapport reviews, status reviews). Process them first before deciding on next steps.
|
|
23
|
+
|
|
24
|
+
3. **Determine the next action**:
|
|
25
|
+
- If there are tasks in `Pending` or `In Progress` status that have not yet been assigned to the developer, identify them.
|
|
26
|
+
- If outstanding tasks are ready for implementation, write a session handoff to `project/queue/.session_handoff.json` with `"status": "planning_complete"` so that `on_session_end.sh` routes them to the developer queue.
|
|
27
|
+
- If all tasks are complete, check for epic/story rollup and update board statuses accordingly.
|
|
28
|
+
|
|
29
|
+
4. **Report** a clear summary to the user: what is done, what is in progress, what is next — and which agent will handle it.
|