@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,249 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# npm_pipeline.sh — Execute the npm publish pipeline for the JengaAgent repo.
|
|
3
|
+
#
|
|
4
|
+
# Runs from the JengaAgent repo root (where package.json lives) and invokes
|
|
5
|
+
# `npm publish --tag <dist_tag>` (or `--dry-run` when requested).
|
|
6
|
+
#
|
|
7
|
+
# Exit codes:
|
|
8
|
+
# 0 success (live publish or dry-run completed)
|
|
9
|
+
# 2 pre-publish gate failure (missing package.json, missing npm/node, bad args)
|
|
10
|
+
# 3 publish error (`npm publish` returned non-zero)
|
|
11
|
+
#
|
|
12
|
+
# Style and conventions mirror `ios_pipeline.sh`.
|
|
13
|
+
|
|
14
|
+
set -euo pipefail
|
|
15
|
+
|
|
16
|
+
EXIT_PRE_PUBLISH_FAILURE=2
|
|
17
|
+
EXIT_PUBLISH_FAILURE=3
|
|
18
|
+
|
|
19
|
+
usage() {
|
|
20
|
+
cat <<'USAGE'
|
|
21
|
+
Usage: npm_pipeline.sh [<target> <publish_json_path>] [--dry-run] [--dist-tag <tag>] [--non-interactive]
|
|
22
|
+
|
|
23
|
+
Options:
|
|
24
|
+
<target> Optional target name from publish.json (npm target).
|
|
25
|
+
<publish_json_path> Optional path to publish.json for reading defaults.
|
|
26
|
+
--dry-run Run `npm publish --dry-run`; do not touch the registry.
|
|
27
|
+
--dist-tag <tag> Override dist-tag. Falls back to $NPM_DIST_TAG, then
|
|
28
|
+
to the target's `npm.dist_tag`, then to "latest".
|
|
29
|
+
--non-interactive Reserved flag for CI; no interactive prompts today.
|
|
30
|
+
-h, --help Show this message.
|
|
31
|
+
USAGE
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
log_info() {
|
|
35
|
+
printf '→ %s\n' "$1"
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
log_warn() {
|
|
39
|
+
printf '⚠ %s\n' "$1" >&2
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
fail_pre_publish() {
|
|
43
|
+
printf 'npm pipeline pre-publish failure: %s\n' "$1" >&2
|
|
44
|
+
exit "$EXIT_PRE_PUBLISH_FAILURE"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
fail_publish() {
|
|
48
|
+
printf 'npm pipeline publish failure: %s\n' "$1" >&2
|
|
49
|
+
exit "$EXIT_PUBLISH_FAILURE"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
TARGET_NAME=""
|
|
53
|
+
PUBLISH_JSON=""
|
|
54
|
+
DRY_RUN=0
|
|
55
|
+
NON_INTERACTIVE=0
|
|
56
|
+
DIST_TAG_ARG=""
|
|
57
|
+
|
|
58
|
+
# Peel off optional positional args before flag parsing so callers may pass
|
|
59
|
+
# `<target> <publish_json_path>` in either order relative to flags.
|
|
60
|
+
POSITIONAL=()
|
|
61
|
+
while (($#)); do
|
|
62
|
+
case "$1" in
|
|
63
|
+
-h|--help)
|
|
64
|
+
usage
|
|
65
|
+
exit 0
|
|
66
|
+
;;
|
|
67
|
+
--dry-run)
|
|
68
|
+
DRY_RUN=1
|
|
69
|
+
shift
|
|
70
|
+
;;
|
|
71
|
+
--non-interactive)
|
|
72
|
+
NON_INTERACTIVE=1
|
|
73
|
+
shift
|
|
74
|
+
;;
|
|
75
|
+
--dist-tag)
|
|
76
|
+
[[ $# -ge 2 ]] || fail_pre_publish "--dist-tag requires a value"
|
|
77
|
+
DIST_TAG_ARG="$2"
|
|
78
|
+
shift 2
|
|
79
|
+
;;
|
|
80
|
+
--dist-tag=*)
|
|
81
|
+
DIST_TAG_ARG="${1#*=}"
|
|
82
|
+
shift
|
|
83
|
+
;;
|
|
84
|
+
--)
|
|
85
|
+
shift
|
|
86
|
+
while (($#)); do
|
|
87
|
+
POSITIONAL+=("$1")
|
|
88
|
+
shift
|
|
89
|
+
done
|
|
90
|
+
;;
|
|
91
|
+
-*)
|
|
92
|
+
usage >&2
|
|
93
|
+
fail_pre_publish "unknown option: $1"
|
|
94
|
+
;;
|
|
95
|
+
*)
|
|
96
|
+
POSITIONAL+=("$1")
|
|
97
|
+
shift
|
|
98
|
+
;;
|
|
99
|
+
esac
|
|
100
|
+
done
|
|
101
|
+
|
|
102
|
+
if [[ ${#POSITIONAL[@]} -ge 1 ]]; then
|
|
103
|
+
TARGET_NAME="${POSITIONAL[0]}"
|
|
104
|
+
fi
|
|
105
|
+
if [[ ${#POSITIONAL[@]} -ge 2 ]]; then
|
|
106
|
+
PUBLISH_JSON="${POSITIONAL[1]}"
|
|
107
|
+
fi
|
|
108
|
+
if [[ ${#POSITIONAL[@]} -gt 2 ]]; then
|
|
109
|
+
usage >&2
|
|
110
|
+
fail_pre_publish "unexpected extra positional arguments"
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
# Silence unused warnings; these are contract flags for the adapter layer.
|
|
114
|
+
: "${TARGET_NAME:=}"
|
|
115
|
+
: "${NON_INTERACTIVE:=0}"
|
|
116
|
+
|
|
117
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
118
|
+
if REPO_ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null)"; then
|
|
119
|
+
:
|
|
120
|
+
else
|
|
121
|
+
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
VALIDATE_ENV_SCRIPT="$SCRIPT_DIR/validate_npm_env.sh"
|
|
125
|
+
|
|
126
|
+
command -v npm >/dev/null 2>&1 || fail_pre_publish "npm is required on PATH"
|
|
127
|
+
|
|
128
|
+
PACKAGE_JSON="$REPO_ROOT/package.json"
|
|
129
|
+
[[ -f "$PACKAGE_JSON" ]] || fail_pre_publish "package.json not found at '$PACKAGE_JSON'"
|
|
130
|
+
|
|
131
|
+
# Read a JSON string field. Prefers jq, falls back to node.
|
|
132
|
+
read_json_string() {
|
|
133
|
+
local file="$1"
|
|
134
|
+
local path="$2"
|
|
135
|
+
local value=""
|
|
136
|
+
if command -v jq >/dev/null 2>&1; then
|
|
137
|
+
value="$(jq -r "$path // \"\"" "$file" 2>/dev/null || true)"
|
|
138
|
+
elif command -v node >/dev/null 2>&1; then
|
|
139
|
+
# Convert a jq-style dot path (e.g. ".npm.dist_tag") to a JS accessor.
|
|
140
|
+
local js_path="${path#.}"
|
|
141
|
+
value="$(node -e "
|
|
142
|
+
try {
|
|
143
|
+
const data = require('$file');
|
|
144
|
+
const parts = '$js_path'.split('.').filter(Boolean);
|
|
145
|
+
let v = data;
|
|
146
|
+
for (const p of parts) { v = v == null ? undefined : v[p]; }
|
|
147
|
+
process.stdout.write(v == null ? '' : String(v));
|
|
148
|
+
} catch (e) { process.stdout.write(''); }
|
|
149
|
+
" 2>/dev/null || true)"
|
|
150
|
+
fi
|
|
151
|
+
printf '%s' "$value"
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
PACKAGE_NAME="$(read_json_string "$PACKAGE_JSON" '.name')"
|
|
155
|
+
PACKAGE_VERSION="$(read_json_string "$PACKAGE_JSON" '.version')"
|
|
156
|
+
[[ -n "$PACKAGE_NAME" ]] || fail_pre_publish "package.json is missing a 'name' field"
|
|
157
|
+
[[ -n "$PACKAGE_VERSION" ]] || fail_pre_publish "package.json is missing a 'version' field"
|
|
158
|
+
|
|
159
|
+
# Pull defaults from publish.json when both target + config are supplied.
|
|
160
|
+
CONFIG_DIST_TAG=""
|
|
161
|
+
CONFIG_REGISTRY=""
|
|
162
|
+
CONFIG_ACCESS=""
|
|
163
|
+
if [[ -n "$TARGET_NAME" && -n "$PUBLISH_JSON" ]]; then
|
|
164
|
+
[[ -f "$PUBLISH_JSON" ]] || fail_pre_publish "publish config not found at '$PUBLISH_JSON'"
|
|
165
|
+
command -v jq >/dev/null 2>&1 || fail_pre_publish "jq is required when passing a publish.json path"
|
|
166
|
+
|
|
167
|
+
TARGET_JSON="$(jq -c --arg target "$TARGET_NAME" \
|
|
168
|
+
'.targets[]? | select(.name == $target and .type == "npm")' \
|
|
169
|
+
"$PUBLISH_JSON")"
|
|
170
|
+
[[ -n "$TARGET_JSON" ]] \
|
|
171
|
+
|| fail_pre_publish "npm target '$TARGET_NAME' was not found in '$PUBLISH_JSON'"
|
|
172
|
+
|
|
173
|
+
CONFIG_DIST_TAG="$(printf '%s' "$TARGET_JSON" | jq -r '.npm.dist_tag // ""')"
|
|
174
|
+
CONFIG_REGISTRY="$(printf '%s' "$TARGET_JSON" | jq -r '.npm.registry // ""')"
|
|
175
|
+
CONFIG_ACCESS="$(printf '%s' "$TARGET_JSON" | jq -r '.npm.access // ""')"
|
|
176
|
+
|
|
177
|
+
if [[ -f "$VALIDATE_ENV_SCRIPT" ]]; then
|
|
178
|
+
if ! bash "$VALIDATE_ENV_SCRIPT" "$PUBLISH_JSON" "$TARGET_NAME"; then
|
|
179
|
+
fail_pre_publish "environment validation via validate_npm_env.sh failed"
|
|
180
|
+
fi
|
|
181
|
+
else
|
|
182
|
+
log_warn "validate_npm_env.sh not found; skipping env pre-check"
|
|
183
|
+
fi
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
# Resolve dist-tag with precedence: flag > env > config > default.
|
|
187
|
+
DIST_TAG=""
|
|
188
|
+
if [[ -n "$DIST_TAG_ARG" ]]; then
|
|
189
|
+
DIST_TAG="$DIST_TAG_ARG"
|
|
190
|
+
elif [[ -n "${NPM_DIST_TAG:-}" ]]; then
|
|
191
|
+
DIST_TAG="$NPM_DIST_TAG"
|
|
192
|
+
elif [[ -n "$CONFIG_DIST_TAG" ]]; then
|
|
193
|
+
DIST_TAG="$CONFIG_DIST_TAG"
|
|
194
|
+
else
|
|
195
|
+
DIST_TAG="latest"
|
|
196
|
+
fi
|
|
197
|
+
|
|
198
|
+
# Resolve registry: config value wins; otherwise npm's default.
|
|
199
|
+
if [[ -n "$CONFIG_REGISTRY" ]]; then
|
|
200
|
+
REGISTRY="$CONFIG_REGISTRY"
|
|
201
|
+
else
|
|
202
|
+
REGISTRY="https://registry.npmjs.org/"
|
|
203
|
+
fi
|
|
204
|
+
|
|
205
|
+
MODE_LABEL="live publish"
|
|
206
|
+
if (( DRY_RUN )); then
|
|
207
|
+
MODE_LABEL="dry-run"
|
|
208
|
+
fi
|
|
209
|
+
|
|
210
|
+
echo "========== NPM PUBLISH PIPELINE =========="
|
|
211
|
+
printf 'Package: %s\n' "$PACKAGE_NAME"
|
|
212
|
+
printf 'Version: %s\n' "$PACKAGE_VERSION"
|
|
213
|
+
printf 'Dist tag: %s\n' "$DIST_TAG"
|
|
214
|
+
printf 'Registry: %s\n' "$REGISTRY"
|
|
215
|
+
if [[ -n "$CONFIG_ACCESS" ]]; then
|
|
216
|
+
printf 'Access: %s\n' "$CONFIG_ACCESS"
|
|
217
|
+
fi
|
|
218
|
+
printf 'Mode: %s\n' "$MODE_LABEL"
|
|
219
|
+
printf 'Repo: %s\n' "$REPO_ROOT"
|
|
220
|
+
echo "=========================================="
|
|
221
|
+
|
|
222
|
+
PUBLISH_CMD=(npm publish --tag "$DIST_TAG")
|
|
223
|
+
if [[ -n "$CONFIG_ACCESS" ]]; then
|
|
224
|
+
PUBLISH_CMD+=(--access "$CONFIG_ACCESS")
|
|
225
|
+
fi
|
|
226
|
+
if [[ -n "$CONFIG_REGISTRY" ]]; then
|
|
227
|
+
PUBLISH_CMD+=(--registry "$CONFIG_REGISTRY")
|
|
228
|
+
fi
|
|
229
|
+
|
|
230
|
+
cd "$REPO_ROOT"
|
|
231
|
+
|
|
232
|
+
if (( DRY_RUN )); then
|
|
233
|
+
echo "DRY RUN — nothing was published"
|
|
234
|
+
PUBLISH_CMD+=(--dry-run)
|
|
235
|
+
log_info "Running: ${PUBLISH_CMD[*]}"
|
|
236
|
+
if "${PUBLISH_CMD[@]}"; then
|
|
237
|
+
log_info "Dry-run completed successfully."
|
|
238
|
+
exit 0
|
|
239
|
+
fi
|
|
240
|
+
fail_publish "npm publish --dry-run exited non-zero"
|
|
241
|
+
fi
|
|
242
|
+
|
|
243
|
+
log_info "Running: ${PUBLISH_CMD[*]}"
|
|
244
|
+
if "${PUBLISH_CMD[@]}"; then
|
|
245
|
+
log_info "Published $PACKAGE_NAME@$PACKAGE_VERSION to $REGISTRY (dist-tag: $DIST_TAG)"
|
|
246
|
+
exit 0
|
|
247
|
+
fi
|
|
248
|
+
|
|
249
|
+
fail_publish "npm publish exited non-zero"
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
if [[ -n "${PUBLISH_COMMON_SH_LOADED:-}" ]]; then
|
|
4
|
+
return 0
|
|
5
|
+
fi
|
|
6
|
+
PUBLISH_COMMON_SH_LOADED=1
|
|
7
|
+
|
|
8
|
+
PUBLISH_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
|
+
if PUBLISH_REPO_ROOT="$(git -C "$PUBLISH_SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null)"; then
|
|
10
|
+
:
|
|
11
|
+
else
|
|
12
|
+
PUBLISH_REPO_ROOT="$(cd "$PUBLISH_SCRIPT_DIR/../../.." && pwd)"
|
|
13
|
+
fi
|
|
14
|
+
PUBLISH_DEFAULT_HISTORY_FILE="$PUBLISH_REPO_ROOT/project/logs/publish-history.json"
|
|
15
|
+
PUBLISH_DEFAULT_CONFIG_FILE="$PUBLISH_REPO_ROOT/project/configs/publish.json"
|
|
16
|
+
|
|
17
|
+
publish_stat_mtime() {
|
|
18
|
+
if [[ -e "$1" ]]; then
|
|
19
|
+
stat -f %m "$1" 2>/dev/null || echo 0
|
|
20
|
+
else
|
|
21
|
+
echo 0
|
|
22
|
+
fi
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
publish_acquire_lock() {
|
|
26
|
+
local lock_path="$1"
|
|
27
|
+
local attempt=0
|
|
28
|
+
local now mtime
|
|
29
|
+
|
|
30
|
+
while :; do
|
|
31
|
+
if [[ -e "$lock_path" ]]; then
|
|
32
|
+
now="$(date +%s)"
|
|
33
|
+
mtime="$(publish_stat_mtime "$lock_path")"
|
|
34
|
+
if (( now - mtime < 60 )); then
|
|
35
|
+
if (( attempt >= 1 )); then
|
|
36
|
+
return 1
|
|
37
|
+
fi
|
|
38
|
+
sleep 10
|
|
39
|
+
attempt=$((attempt + 1))
|
|
40
|
+
continue
|
|
41
|
+
fi
|
|
42
|
+
rm -f "$lock_path"
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
if ( set -o noclobber; : > "$lock_path" ) 2>/dev/null; then
|
|
46
|
+
return 0
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
if (( attempt >= 1 )); then
|
|
50
|
+
return 1
|
|
51
|
+
fi
|
|
52
|
+
sleep 10
|
|
53
|
+
attempt=$((attempt + 1))
|
|
54
|
+
done
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
publish_release_lock() {
|
|
58
|
+
rm -f "$1"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
publish_normalize_path() {
|
|
62
|
+
local path="$1"
|
|
63
|
+
if [[ -z "$path" ]]; then
|
|
64
|
+
return 1
|
|
65
|
+
fi
|
|
66
|
+
if [[ "$path" = /* ]]; then
|
|
67
|
+
printf '%s\n' "$path"
|
|
68
|
+
else
|
|
69
|
+
printf '%s/%s\n' "$PUBLISH_REPO_ROOT" "$path"
|
|
70
|
+
fi
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
publish_resolve_history_file() {
|
|
74
|
+
local config_path="${1:-}"
|
|
75
|
+
local history_path="${PUBLISH_HISTORY_FILE:-}"
|
|
76
|
+
|
|
77
|
+
if [[ -z "$history_path" && -n "$config_path" && -f "$config_path" ]] && command -v jq >/dev/null 2>&1; then
|
|
78
|
+
history_path="$(jq -r '.defaults.history_file // empty' "$config_path" 2>/dev/null || true)"
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
if [[ -z "$history_path" ]]; then
|
|
82
|
+
history_path="$PUBLISH_DEFAULT_HISTORY_FILE"
|
|
83
|
+
printf '%s\n' "$history_path"
|
|
84
|
+
return 0
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
publish_normalize_path "$history_path"
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
publish_ensure_history_file() {
|
|
91
|
+
local history_file="$1"
|
|
92
|
+
local lock_file="${history_file}.lock"
|
|
93
|
+
local tmp_file="${history_file}.tmp.$$"
|
|
94
|
+
|
|
95
|
+
mkdir -p "$(dirname "$history_file")"
|
|
96
|
+
if ! publish_acquire_lock "$lock_file"; then
|
|
97
|
+
echo "Could not acquire lock for $history_file" >&2
|
|
98
|
+
return 1
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
if [[ ! -f "$history_file" ]]; then
|
|
102
|
+
printf '[]\n' > "$history_file"
|
|
103
|
+
elif ! jq -e 'type == "array"' "$history_file" >/dev/null 2>&1; then
|
|
104
|
+
publish_release_lock "$lock_file"
|
|
105
|
+
rm -f "$tmp_file"
|
|
106
|
+
echo "Publish history file must contain a JSON array: $history_file" >&2
|
|
107
|
+
return 1
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
publish_release_lock "$lock_file"
|
|
111
|
+
return 0
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
publish_append_history_entry() {
|
|
115
|
+
local history_file="$1"
|
|
116
|
+
local entry_json="$2"
|
|
117
|
+
local lock_file="${history_file}.lock"
|
|
118
|
+
local tmp_file="${history_file}.tmp.$$"
|
|
119
|
+
|
|
120
|
+
mkdir -p "$(dirname "$history_file")"
|
|
121
|
+
if ! publish_acquire_lock "$lock_file"; then
|
|
122
|
+
echo "Could not acquire lock for $history_file" >&2
|
|
123
|
+
return 1
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
if [[ ! -f "$history_file" ]]; then
|
|
127
|
+
printf '[]\n' > "$history_file"
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
if ! jq -e 'type == "array"' "$history_file" >/dev/null 2>&1; then
|
|
131
|
+
publish_release_lock "$lock_file"
|
|
132
|
+
rm -f "$tmp_file"
|
|
133
|
+
echo "Publish history file must contain a JSON array: $history_file" >&2
|
|
134
|
+
return 1
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
if ! jq --argjson entry "$entry_json" '. + [$entry]' "$history_file" > "$tmp_file"; then
|
|
138
|
+
publish_release_lock "$lock_file"
|
|
139
|
+
rm -f "$tmp_file"
|
|
140
|
+
echo "Failed to append publish history entry." >&2
|
|
141
|
+
return 1
|
|
142
|
+
fi
|
|
143
|
+
|
|
144
|
+
mv "$tmp_file" "$history_file"
|
|
145
|
+
publish_release_lock "$lock_file"
|
|
146
|
+
return 0
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
publish_is_semver_tag() {
|
|
150
|
+
[[ "$1" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
publish_list_semver_tags() {
|
|
154
|
+
local ref="${1:-HEAD}"
|
|
155
|
+
git tag --merged "$ref" --list 'v*.*.*' --sort=-v:refname 2>/dev/null | while IFS= read -r tag; do
|
|
156
|
+
[[ -z "$tag" ]] && continue
|
|
157
|
+
if publish_is_semver_tag "$tag"; then
|
|
158
|
+
printf '%s\n' "$tag"
|
|
159
|
+
fi
|
|
160
|
+
done
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
publish_history_has_version() {
|
|
164
|
+
local history_file="$1"
|
|
165
|
+
local version="$2"
|
|
166
|
+
[[ -f "$history_file" ]] || return 1
|
|
167
|
+
jq -e --arg version "$version" 'type == "array" and any(.[]?; (.version? // "") == $version)' "$history_file" >/dev/null 2>&1
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
publish_resolve_last_publish_tag() {
|
|
171
|
+
local history_file="$1"
|
|
172
|
+
local ref="${2:-HEAD}"
|
|
173
|
+
local tag
|
|
174
|
+
|
|
175
|
+
[[ -f "$history_file" ]] || return 1
|
|
176
|
+
|
|
177
|
+
while IFS= read -r tag; do
|
|
178
|
+
[[ -z "$tag" ]] && continue
|
|
179
|
+
if publish_history_has_version "$history_file" "$tag"; then
|
|
180
|
+
printf '%s\n' "$tag"
|
|
181
|
+
return 0
|
|
182
|
+
fi
|
|
183
|
+
done < <(publish_list_semver_tags "$ref")
|
|
184
|
+
|
|
185
|
+
return 1
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
publish_latest_ledger_version() {
|
|
189
|
+
local history_file="$1"
|
|
190
|
+
[[ -f "$history_file" ]] || return 1
|
|
191
|
+
jq -r '[.[]? | .version? | strings | select(test("^v[0-9]+\\.[0-9]+\\.[0-9]+$"))] | last // empty' "$history_file"
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
publish_normalize_version() {
|
|
195
|
+
local version="$1"
|
|
196
|
+
if [[ "$version" != v* ]]; then
|
|
197
|
+
version="v$version"
|
|
198
|
+
fi
|
|
199
|
+
publish_is_semver_tag "$version" || return 1
|
|
200
|
+
printf '%s\n' "$version"
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
publish_bump_version() {
|
|
204
|
+
local current_version="$1"
|
|
205
|
+
local bump_level="$2"
|
|
206
|
+
local major minor patch
|
|
207
|
+
|
|
208
|
+
current_version="$(publish_normalize_version "$current_version")" || return 1
|
|
209
|
+
IFS=. read -r major minor patch <<< "${current_version#v}"
|
|
210
|
+
|
|
211
|
+
case "$bump_level" in
|
|
212
|
+
major)
|
|
213
|
+
major=$((major + 1))
|
|
214
|
+
minor=0
|
|
215
|
+
patch=0
|
|
216
|
+
;;
|
|
217
|
+
minor)
|
|
218
|
+
minor=$((minor + 1))
|
|
219
|
+
patch=0
|
|
220
|
+
;;
|
|
221
|
+
patch)
|
|
222
|
+
patch=$((patch + 1))
|
|
223
|
+
;;
|
|
224
|
+
*)
|
|
225
|
+
return 1
|
|
226
|
+
;;
|
|
227
|
+
esac
|
|
228
|
+
|
|
229
|
+
printf 'v%s.%s.%s\n' "$major" "$minor" "$patch"
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
publish_current_actor() {
|
|
233
|
+
local actor
|
|
234
|
+
actor="$(git config user.name 2>/dev/null || true)"
|
|
235
|
+
if [[ -n "$actor" ]]; then
|
|
236
|
+
printf '%s\n' "$actor"
|
|
237
|
+
return 0
|
|
238
|
+
fi
|
|
239
|
+
|
|
240
|
+
actor="${GITHUB_ACTOR:-${USER:-}}"
|
|
241
|
+
if [[ -n "$actor" ]]; then
|
|
242
|
+
printf '%s\n' "$actor"
|
|
243
|
+
return 0
|
|
244
|
+
fi
|
|
245
|
+
|
|
246
|
+
printf 'CI\n'
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
publish_temp_release_notes_path() {
|
|
250
|
+
local dir="$PUBLISH_REPO_ROOT/.claude/publish-tmp"
|
|
251
|
+
mkdir -p "$dir"
|
|
252
|
+
printf '%s/release-notes-%s.md\n' "$dir" "$(date -u +"%Y%m%dT%H%M%SZ")"
|
|
253
|
+
}
|