@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,163 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -u
|
|
3
|
+
|
|
4
|
+
CONFIG_PATH="${1:-}"
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
SCHEMA_PATH="${SCRIPT_DIR}/../schemas/publish.schema.json"
|
|
7
|
+
EXIT_CONFIG_INVALID=4
|
|
8
|
+
|
|
9
|
+
fail() {
|
|
10
|
+
printf 'publish config validation failed: %s\n' "$1" >&2
|
|
11
|
+
exit "$EXIT_CONFIG_INVALID"
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
[[ -n "$CONFIG_PATH" ]] || fail "missing config path argument"
|
|
15
|
+
[[ -f "$CONFIG_PATH" ]] || fail "config file not found at '$CONFIG_PATH'"
|
|
16
|
+
[[ -f "$SCHEMA_PATH" ]] || fail "schema file not found at '$SCHEMA_PATH'"
|
|
17
|
+
command -v jq >/dev/null 2>&1 || fail "jq is required"
|
|
18
|
+
|
|
19
|
+
jq -e . "$SCHEMA_PATH" >/dev/null 2>&1 || fail "schema file is not valid JSON"
|
|
20
|
+
jq -e . "$CONFIG_PATH" >/dev/null 2>&1 || fail "config file is not valid JSON"
|
|
21
|
+
|
|
22
|
+
# shellcheck disable=SC2154 # $t, $cfg, $schema are jq variables inside the single-quoted program below, not shell variables.
|
|
23
|
+
ERRORS="$(
|
|
24
|
+
jq -rn \
|
|
25
|
+
--slurpfile cfg "$CONFIG_PATH" \
|
|
26
|
+
--slurpfile schema "$SCHEMA_PATH" '
|
|
27
|
+
($cfg[0]) as $cfg
|
|
28
|
+
| ($schema[0]) as $schema
|
|
29
|
+
| def env_ref: type == "string" and test("^\\$\\{?[A-Z][A-Z0-9_]*\\}?$");
|
|
30
|
+
def non_empty_string: type == "string" and length > 0;
|
|
31
|
+
def string_gate_name: type == "string" and test("^[a-z0-9][a-z0-9-]*$");
|
|
32
|
+
def gate_entry_valid:
|
|
33
|
+
(string_gate_name)
|
|
34
|
+
or (
|
|
35
|
+
type == "object"
|
|
36
|
+
and (
|
|
37
|
+
(.name? | string_gate_name)
|
|
38
|
+
or (.gate? | string_gate_name)
|
|
39
|
+
or (.type? | string_gate_name)
|
|
40
|
+
)
|
|
41
|
+
);
|
|
42
|
+
def gate_list_valid:
|
|
43
|
+
type == "array" and all(.[]?; gate_entry_valid);
|
|
44
|
+
def checks_valid:
|
|
45
|
+
type == "object"
|
|
46
|
+
and ((.pre? == null) or (.pre | gate_list_valid))
|
|
47
|
+
and ((.post? == null) or (.post | gate_list_valid));
|
|
48
|
+
def secrets_valid:
|
|
49
|
+
type == "object"
|
|
50
|
+
and (.app_store_connect_api_key_id? | env_ref)
|
|
51
|
+
and (.app_store_connect_issuer_id? | env_ref)
|
|
52
|
+
and (.app_store_connect_private_key_path? | env_ref)
|
|
53
|
+
and (.code_sign_identity? | env_ref)
|
|
54
|
+
and (.provisioning_profile_uuid? | env_ref);
|
|
55
|
+
def ios_valid:
|
|
56
|
+
type == "object"
|
|
57
|
+
and (.scheme? | non_empty_string)
|
|
58
|
+
and (.configuration? | non_empty_string)
|
|
59
|
+
and (.archive_path? | non_empty_string)
|
|
60
|
+
and (.export_path? | non_empty_string)
|
|
61
|
+
and (((.export_method? // "") == "ad-hoc") or ((.export_method? // "") == "app-store"))
|
|
62
|
+
and (.bundle_id? | non_empty_string)
|
|
63
|
+
and (.team_id? | type == "string" and test("^[A-Z0-9]{6,}$"))
|
|
64
|
+
and (.app_store_app_id? | type == "string" and test("^[0-9]+$"))
|
|
65
|
+
and (((.project_path? // empty) | non_empty_string) or ((.workspace_path? // empty) | non_empty_string));
|
|
66
|
+
def npm_secrets_valid:
|
|
67
|
+
type == "object"
|
|
68
|
+
and (
|
|
69
|
+
(((.NPM_TOKEN? // null) != null) and (.NPM_TOKEN | env_ref))
|
|
70
|
+
or (((.NODE_AUTH_TOKEN? // null) != null) and (.NODE_AUTH_TOKEN | env_ref))
|
|
71
|
+
);
|
|
72
|
+
def npm_valid:
|
|
73
|
+
type == "object"
|
|
74
|
+
and (.package_name? | non_empty_string)
|
|
75
|
+
and (.package_name | test("^(?:@[a-z0-9][a-z0-9._-]*\\/)?[a-z0-9][a-z0-9._-]*$"))
|
|
76
|
+
and ((.package_name | length) <= 214)
|
|
77
|
+
and (((.access? // "") == "public") or ((.access? // "") == "restricted"))
|
|
78
|
+
and (((.registry? // null) == null) or (.registry | non_empty_string))
|
|
79
|
+
and (((.dist_tag? // null) == null) or (((.dist_tag | type) == "string") and (.dist_tag | test("^[a-z0-9][a-z0-9._-]*$"))));
|
|
80
|
+
def npm_ci_valid:
|
|
81
|
+
type == "object"
|
|
82
|
+
and (.package_name? | non_empty_string)
|
|
83
|
+
and (.package_name | test("^(?:@[a-z0-9][a-z0-9._-]*\\/)?[a-z0-9][a-z0-9._-]*$"))
|
|
84
|
+
and ((.package_name | length) <= 214)
|
|
85
|
+
and (((.access? // "") == "public") or ((.access? // "") == "restricted"))
|
|
86
|
+
and (((.registry? // null) == null) or (.registry | non_empty_string))
|
|
87
|
+
and (((.dist_tag? // null) == null) or (((.dist_tag | type) == "string") and (.dist_tag | test("^[a-z0-9][a-z0-9._-]*$"))));
|
|
88
|
+
def ios_target_valid:
|
|
89
|
+
type == "object"
|
|
90
|
+
and (.name? | type == "string" and test("^[a-z0-9][a-z0-9-]*$"))
|
|
91
|
+
and (.type? == "mobile-ios")
|
|
92
|
+
and (.platform? == "ios-app-store")
|
|
93
|
+
and (.checks? | checks_valid)
|
|
94
|
+
and (.secrets? | secrets_valid)
|
|
95
|
+
and (.ios? | ios_valid);
|
|
96
|
+
def npm_target_valid:
|
|
97
|
+
type == "object"
|
|
98
|
+
and (.name? | type == "string" and test("^[a-z0-9][a-z0-9-]*$"))
|
|
99
|
+
and (.type? == "npm")
|
|
100
|
+
and (((.platform? // "") == "npm-registry") or ((.platform? // "") == "github-packages"))
|
|
101
|
+
and (.checks? | checks_valid)
|
|
102
|
+
and (.secrets? | npm_secrets_valid)
|
|
103
|
+
and (.npm? | npm_valid)
|
|
104
|
+
and ((.ios? // null) == null);
|
|
105
|
+
def npm_ci_target_valid:
|
|
106
|
+
type == "object"
|
|
107
|
+
and (.name? | type == "string" and test("^[a-z0-9][a-z0-9-]*$"))
|
|
108
|
+
and (.type? == "npm-ci")
|
|
109
|
+
and ((.github_repo? // "") | non_empty_string)
|
|
110
|
+
and (.npm? | npm_ci_valid)
|
|
111
|
+
and ((.ios? // null) == null);
|
|
112
|
+
def target_valid: ios_target_valid or npm_target_valid or npm_ci_target_valid;
|
|
113
|
+
def target_label: (.name? // "<unnamed>");
|
|
114
|
+
def npm_diagnostics:
|
|
115
|
+
. as $t
|
|
116
|
+
| [
|
|
117
|
+
(if (($t.npm? | type) != "object") then ("target \"" + ($t | target_label) + "\": npm block is required for npm targets") else empty end),
|
|
118
|
+
(if ((($t.npm?.package_name? // "") | non_empty_string) | not) then ("target \"" + ($t | target_label) + "\": npm.package_name is required and must be a non-empty string") else empty end),
|
|
119
|
+
(if ((($t.npm?.package_name? // "") | type) == "string" and (($t.npm.package_name | length) > 0) and ((($t.npm.package_name | test("^(?:@[a-z0-9][a-z0-9._-]*\\/)?[a-z0-9][a-z0-9._-]*$"))) | not)) then ("target \"" + ($t | target_label) + "\": npm.package_name must match npm naming rules") else empty end),
|
|
120
|
+
(if (((($t.npm?.access? // "") == "public") or (($t.npm?.access? // "") == "restricted")) | not) then ("target \"" + ($t | target_label) + "\": npm.access must be \"public\" or \"restricted\"") else empty end),
|
|
121
|
+
(if (($t.ios? // null) != null) then ("target \"" + ($t | target_label) + "\": ios block is not allowed on npm targets") else empty end),
|
|
122
|
+
(if (((($t.platform? // "") == "npm-registry") or (($t.platform? // "") == "github-packages")) | not) then ("target \"" + ($t | target_label) + "\": platform must be \"npm-registry\" or \"github-packages\" for npm targets") else empty end),
|
|
123
|
+
(if (($t.secrets? | npm_secrets_valid) | not) then ("target \"" + ($t | target_label) + "\": secrets must contain NPM_TOKEN or NODE_AUTH_TOKEN as an environment reference") else empty end)
|
|
124
|
+
] | .[];
|
|
125
|
+
def npm_ci_diagnostics:
|
|
126
|
+
. as $t
|
|
127
|
+
| [
|
|
128
|
+
(if (($t.github_repo? // "") | non_empty_string) then empty else ("target \"" + ($t | target_label) + "\": github_repo is required and must be a non-empty string") end),
|
|
129
|
+
(if (($t.npm? | type) != "object") then ("target \"" + ($t | target_label) + "\": npm block is required for npm-ci targets") else empty end),
|
|
130
|
+
(if ((($t.npm?.package_name? // "") | non_empty_string) | not) then ("target \"" + ($t | target_label) + "\": npm.package_name is required and must be a non-empty string") else empty end),
|
|
131
|
+
(if ((($t.npm?.package_name? // "") | type) == "string" and (($t.npm.package_name | length) > 0) and ((($t.npm.package_name | test("^(?:@[a-z0-9][a-z0-9._-]*\\/)?[a-z0-9][a-z0-9._-]*$"))) | not)) then ("target \"" + ($t | target_label) + "\": npm.package_name must match npm naming rules") else empty end),
|
|
132
|
+
(if (((($t.npm?.access? // "") == "public") or (($t.npm?.access? // "") == "restricted")) | not) then ("target \"" + ($t | target_label) + "\": npm.access must be \"public\" or \"restricted\"") else empty end),
|
|
133
|
+
(if (($t.ios? // null) != null) then ("target \"" + ($t | target_label) + "\": ios block is not allowed on npm-ci targets") else empty end)
|
|
134
|
+
] | .[];
|
|
135
|
+
def per_target_errors:
|
|
136
|
+
. as $t
|
|
137
|
+
| if target_valid then empty
|
|
138
|
+
elif ($t.type? == "npm") then ($t | npm_diagnostics)
|
|
139
|
+
elif ($t.type? == "npm-ci") then ($t | npm_ci_diagnostics)
|
|
140
|
+
elif ($t.type? == "mobile-ios") then ("invalid target: " + ($t | target_label))
|
|
141
|
+
else ("target \"" + ($t | target_label) + "\": type must be \"mobile-ios\", \"npm\", or \"npm-ci\"") end;
|
|
142
|
+
[
|
|
143
|
+
(if (($schema["$schema"] // "") | contains("draft-07")) then empty else "schema must declare draft-07" end),
|
|
144
|
+
(if (($cfg | type) == "object") then empty else "root config must be an object" end),
|
|
145
|
+
(if (($cfg.version? // null) == 1) then empty else "version must be 1" end),
|
|
146
|
+
(if (($cfg.defaults? | type) == "object") then empty else "defaults must be an object" end),
|
|
147
|
+
(if (($cfg.defaults.history_file? // "") | non_empty_string) then empty else "defaults.history_file must be a non-empty string" end),
|
|
148
|
+
(if (($cfg.defaults.mandatory_checks? | type) == "array" and (($cfg.defaults.mandatory_checks | length) > 0) and all($cfg.defaults.mandatory_checks[]; string_gate_name)) then empty else "defaults.mandatory_checks must be a non-empty array of gate names" end),
|
|
149
|
+
(if (($cfg.defaults.optional_checks? == null) or (($cfg.defaults.optional_checks | type) == "array" and all($cfg.defaults.optional_checks[]; string_gate_name))) then empty else "defaults.optional_checks must be an array of gate names when provided" end),
|
|
150
|
+
(if (($cfg.targets? | type) == "array" and (($cfg.targets | length) > 0)) then empty else "targets must be a non-empty array" end),
|
|
151
|
+
(if (($cfg.targets? | type) == "array") then ([$cfg.targets[] | per_target_errors] | .[]) else empty end)
|
|
152
|
+
] | map(select(. != null and . != "")) | .[]
|
|
153
|
+
' 2>/dev/null || true
|
|
154
|
+
)"
|
|
155
|
+
|
|
156
|
+
if [[ -n "$ERRORS" ]]; then
|
|
157
|
+
while IFS= read -r line; do
|
|
158
|
+
[[ -n "$line" ]] && printf 'publish config validation failed: %s\n' "$line" >&2
|
|
159
|
+
done <<< "$ERRORS"
|
|
160
|
+
exit "$EXIT_CONFIG_INVALID"
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
exit 0
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -u
|
|
3
|
+
|
|
4
|
+
EXIT_ENV_INVALID=4
|
|
5
|
+
|
|
6
|
+
# Usage: validate_droplet_env.sh <publish_json_path> <target_name>
|
|
7
|
+
|
|
8
|
+
CONFIG_PATH="${1:-}"
|
|
9
|
+
TARGET_NAME="${2:-}"
|
|
10
|
+
|
|
11
|
+
fail() {
|
|
12
|
+
printf 'droplet env validation failed: %s\n' "$1" >&2
|
|
13
|
+
exit "$EXIT_ENV_INVALID"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
[[ -n "$CONFIG_PATH" ]] || fail "missing publish.json path argument"
|
|
17
|
+
[[ -f "$CONFIG_PATH" ]] || fail "publish config not found at '$CONFIG_PATH'"
|
|
18
|
+
command -v jq >/dev/null 2>&1 || fail "jq is required but not found on PATH"
|
|
19
|
+
[[ -n "$TARGET_NAME" ]] || fail "missing target name argument"
|
|
20
|
+
|
|
21
|
+
# Extract the droplet target block
|
|
22
|
+
TARGET_JSON="$(jq -c --arg t "$TARGET_NAME" \
|
|
23
|
+
'.targets[]? | select(.name == $t and .type == "droplet")' \
|
|
24
|
+
"$CONFIG_PATH")"
|
|
25
|
+
[[ -n "$TARGET_JSON" ]] || fail "target '$TARGET_NAME' was not found or is not type 'droplet' in '$CONFIG_PATH'"
|
|
26
|
+
|
|
27
|
+
check_field() {
|
|
28
|
+
local label="$1"
|
|
29
|
+
local value
|
|
30
|
+
value="$(printf '%s' "$TARGET_JSON" | jq -r "$2 // empty" 2>/dev/null || true)"
|
|
31
|
+
if [[ -z "$value" ]]; then
|
|
32
|
+
fail "missing required field '$label'"
|
|
33
|
+
fi
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
check_field "host" '.droplet.host'
|
|
37
|
+
check_field "ssh_user" '.droplet.ssh_user'
|
|
38
|
+
check_field "deploy_path" '.droplet.deploy_path'
|
|
39
|
+
check_field "github_repo" '.droplet.github_repo'
|
|
40
|
+
check_field "deploy_branch" '.droplet.deploy_branch'
|
|
41
|
+
check_field "start_cmd" '.droplet.start_cmd'
|
|
42
|
+
check_field "ssh_key_secret" '.secrets.ssh_key_secret'
|
|
43
|
+
check_field "known_hosts_secret" '.secrets.known_hosts_secret'
|
|
44
|
+
|
|
45
|
+
exit 0
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -u
|
|
3
|
+
|
|
4
|
+
CONFIG_PATH="${1:-}"
|
|
5
|
+
TARGET_NAME="${2:-}"
|
|
6
|
+
EXIT_ENV_INVALID=4
|
|
7
|
+
|
|
8
|
+
fail() {
|
|
9
|
+
printf 'iOS env validation failed: %s\n' "$1" >&2
|
|
10
|
+
exit "$EXIT_ENV_INVALID"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
[[ -n "$CONFIG_PATH" ]] || fail "missing publish.json path argument"
|
|
14
|
+
[[ -f "$CONFIG_PATH" ]] || fail "publish config not found at '$CONFIG_PATH'"
|
|
15
|
+
command -v jq >/dev/null 2>&1 || fail "jq is required"
|
|
16
|
+
|
|
17
|
+
if [[ -n "$TARGET_NAME" ]]; then
|
|
18
|
+
jq -e --arg target "$TARGET_NAME" '.targets[]? | select(.name == $target and .type == "mobile-ios")' "$CONFIG_PATH" >/dev/null 2>&1 || \
|
|
19
|
+
fail "target '$TARGET_NAME' was not found or is not mobile-ios"
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
REQUIRED_VARS=()
|
|
23
|
+
while IFS= read -r var_name; do
|
|
24
|
+
[[ -n "$var_name" ]] && REQUIRED_VARS+=("$var_name")
|
|
25
|
+
done < <(
|
|
26
|
+
jq -r --arg target "$TARGET_NAME" '
|
|
27
|
+
[
|
|
28
|
+
.targets[]?
|
|
29
|
+
| select(.type == "mobile-ios")
|
|
30
|
+
| if $target == "" then . else select(.name == $target) end
|
|
31
|
+
| [
|
|
32
|
+
.secrets.app_store_connect_api_key_id?,
|
|
33
|
+
.secrets.app_store_connect_issuer_id?,
|
|
34
|
+
.secrets.app_store_connect_private_key_path?,
|
|
35
|
+
.secrets.code_sign_identity?,
|
|
36
|
+
.secrets.provisioning_profile_uuid?
|
|
37
|
+
][]
|
|
38
|
+
| select(type == "string" and length > 0)
|
|
39
|
+
| sub("^\\$\\{"; "")
|
|
40
|
+
| sub("^\\$"; "")
|
|
41
|
+
| sub("\\}$"; "")
|
|
42
|
+
]
|
|
43
|
+
| unique
|
|
44
|
+
| .[]
|
|
45
|
+
' "$CONFIG_PATH"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
if [[ ${#REQUIRED_VARS[@]} -eq 0 ]]; then
|
|
49
|
+
if [[ -n "$TARGET_NAME" ]]; then
|
|
50
|
+
fail "no mobile-ios env-var references were found for target '$TARGET_NAME'"
|
|
51
|
+
fi
|
|
52
|
+
fail "no mobile-ios env-var references were found in '$CONFIG_PATH'"
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
MISSING_VARS=()
|
|
56
|
+
for var_name in "${REQUIRED_VARS[@]}"; do
|
|
57
|
+
value="$(printenv "$var_name" 2>/dev/null || true)"
|
|
58
|
+
if [[ -z "$value" ]]; then
|
|
59
|
+
MISSING_VARS+=("$var_name")
|
|
60
|
+
fi
|
|
61
|
+
done
|
|
62
|
+
|
|
63
|
+
if [[ ${#MISSING_VARS[@]} -gt 0 ]]; then
|
|
64
|
+
printf 'Missing required iOS environment variables: %s\n' "${MISSING_VARS[*]}" >&2
|
|
65
|
+
exit "$EXIT_ENV_INVALID"
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
exit 0
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -u
|
|
3
|
+
|
|
4
|
+
EXIT_ENV_INVALID=4
|
|
5
|
+
|
|
6
|
+
# Usage: validate_npm_ci_env.sh <publish_json_path> <target_name>
|
|
7
|
+
|
|
8
|
+
CONFIG_PATH="${1:-}"
|
|
9
|
+
TARGET_NAME="${2:-}"
|
|
10
|
+
|
|
11
|
+
fail() {
|
|
12
|
+
printf '[validate] ERROR: %s\n' "$1" >&2
|
|
13
|
+
exit "$EXIT_ENV_INVALID"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
# ── runtime dependency checks ──────────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
command -v gh >/dev/null 2>&1 || fail "gh CLI is required but not found on PATH. Install it from https://cli.github.com/ and re-run."
|
|
19
|
+
|
|
20
|
+
gh auth status >/dev/null 2>&1 || fail "gh CLI is not authenticated. Run 'gh auth login' and re-run."
|
|
21
|
+
|
|
22
|
+
command -v jq >/dev/null 2>&1 || fail "jq is required but not found on PATH. Install it from https://stedolan.github.io/jq/ and re-run."
|
|
23
|
+
|
|
24
|
+
# ── config argument checks ─────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
[[ -n "$CONFIG_PATH" ]] || fail "missing publish.json path argument"
|
|
27
|
+
[[ -f "$CONFIG_PATH" ]] || fail "publish config not found at '$CONFIG_PATH'"
|
|
28
|
+
[[ -n "$TARGET_NAME" ]] || fail "missing target name argument"
|
|
29
|
+
|
|
30
|
+
# ── extract the npm-ci target block ───────────────────────────────────────────
|
|
31
|
+
|
|
32
|
+
TARGET_JSON="$(jq -c --arg t "$TARGET_NAME" \
|
|
33
|
+
'.targets[]? | select(.name == $t and .type == "npm-ci")' \
|
|
34
|
+
"$CONFIG_PATH")"
|
|
35
|
+
[[ -n "$TARGET_JSON" ]] || fail "target '$TARGET_NAME' was not found or is not type 'npm-ci' in '$CONFIG_PATH'"
|
|
36
|
+
|
|
37
|
+
# ── field validators ───────────────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
check_field() {
|
|
40
|
+
local label="$1"
|
|
41
|
+
local value
|
|
42
|
+
value="$(printf '%s' "$TARGET_JSON" | jq -r "$2 // empty" 2>/dev/null || true)"
|
|
43
|
+
if [[ -z "$value" ]]; then
|
|
44
|
+
fail "missing required field '$label'"
|
|
45
|
+
fi
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# github_repo — required at the target level (not nested under .npm)
|
|
49
|
+
check_field "github_repo" '.github_repo'
|
|
50
|
+
|
|
51
|
+
# Verify github_repo contains exactly one '/'
|
|
52
|
+
GITHUB_REPO="$(printf '%s' "$TARGET_JSON" | jq -r '.github_repo // empty' 2>/dev/null || true)"
|
|
53
|
+
SLASH_COUNT="${GITHUB_REPO//[!\/]}"
|
|
54
|
+
if [[ ${#SLASH_COUNT} -ne 1 ]]; then
|
|
55
|
+
fail "field 'github_repo' must be in 'owner/name' format (contains exactly one '/'), got: '$GITHUB_REPO'"
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
# npm.package_name — required
|
|
59
|
+
check_field "npm.package_name" '.npm.package_name'
|
|
60
|
+
|
|
61
|
+
# npm.access — required; must be 'public' or 'restricted'
|
|
62
|
+
check_field "npm.access" '.npm.access'
|
|
63
|
+
NPM_ACCESS="$(printf '%s' "$TARGET_JSON" | jq -r '.npm.access // empty' 2>/dev/null || true)"
|
|
64
|
+
if [[ "$NPM_ACCESS" != "public" && "$NPM_ACCESS" != "restricted" ]]; then
|
|
65
|
+
fail "field 'npm.access' must be 'public' or 'restricted', got: '$NPM_ACCESS'"
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# ── all checks passed ──────────────────────────────────────────────────────────
|
|
69
|
+
|
|
70
|
+
printf '[validate] environment OK\n'
|
|
71
|
+
exit 0
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -u
|
|
3
|
+
|
|
4
|
+
EXIT_ENV_INVALID=4
|
|
5
|
+
|
|
6
|
+
fail() {
|
|
7
|
+
printf 'npm env validation failed: %s\n' "$1" >&2
|
|
8
|
+
exit "$EXIT_ENV_INVALID"
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if ! command -v npm >/dev/null 2>&1; then
|
|
12
|
+
fail "'npm' was not found on PATH. Install Node.js (which provides npm) from https://nodejs.org/ or via your package manager, then re-run."
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
NPM_TOKEN_VALUE="$(printenv NPM_TOKEN 2>/dev/null || true)"
|
|
16
|
+
NODE_AUTH_TOKEN_VALUE="$(printenv NODE_AUTH_TOKEN 2>/dev/null || true)"
|
|
17
|
+
|
|
18
|
+
if [[ -z "$NPM_TOKEN_VALUE" && -z "$NODE_AUTH_TOKEN_VALUE" ]]; then
|
|
19
|
+
fail "no npm auth token found. Set NPM_TOKEN (or NODE_AUTH_TOKEN) in the environment before publishing, e.g. 'export NPM_TOKEN=<your-npm-automation-token>'. Generate a token at https://www.npmjs.com/settings/<user>/tokens."
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
exit 0
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
source "$SCRIPT_DIR/publish_common.sh"
|
|
6
|
+
|
|
7
|
+
usage() {
|
|
8
|
+
cat <<'USAGE'
|
|
9
|
+
Usage: write_ledger_entry.sh <target> <adapter> <platform_state> <notes_path> [--yes] [--dry-run] [--version <vX.Y.Z>] [--config <path>]
|
|
10
|
+
USAGE
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
[[ $# -ge 4 ]] || { usage >&2; exit 1; }
|
|
14
|
+
TARGET_NAME="$1"
|
|
15
|
+
ADAPTER_NAME="$2"
|
|
16
|
+
PLATFORM_STATE="$3"
|
|
17
|
+
NOTES_PATH_RAW="$4"
|
|
18
|
+
shift 4
|
|
19
|
+
|
|
20
|
+
AUTO_ACCEPT=0
|
|
21
|
+
DRY_RUN=0
|
|
22
|
+
SELECTED_VERSION=''
|
|
23
|
+
CONFIG_PATH="${PUBLISH_CONFIG:-}"
|
|
24
|
+
|
|
25
|
+
while [[ $# -gt 0 ]]; do
|
|
26
|
+
case "$1" in
|
|
27
|
+
--yes)
|
|
28
|
+
AUTO_ACCEPT=1
|
|
29
|
+
shift
|
|
30
|
+
;;
|
|
31
|
+
--dry-run)
|
|
32
|
+
DRY_RUN=1
|
|
33
|
+
shift
|
|
34
|
+
;;
|
|
35
|
+
--version)
|
|
36
|
+
[[ $# -ge 2 ]] || { usage >&2; exit 1; }
|
|
37
|
+
SELECTED_VERSION="$2"
|
|
38
|
+
shift 2
|
|
39
|
+
;;
|
|
40
|
+
--config)
|
|
41
|
+
[[ $# -ge 2 ]] || { usage >&2; exit 1; }
|
|
42
|
+
CONFIG_PATH="$2"
|
|
43
|
+
shift 2
|
|
44
|
+
;;
|
|
45
|
+
--help|-h)
|
|
46
|
+
usage
|
|
47
|
+
exit 0
|
|
48
|
+
;;
|
|
49
|
+
*)
|
|
50
|
+
usage >&2
|
|
51
|
+
exit 1
|
|
52
|
+
;;
|
|
53
|
+
esac
|
|
54
|
+
done
|
|
55
|
+
|
|
56
|
+
[[ -n "$TARGET_NAME" && -n "$ADAPTER_NAME" && -n "$PLATFORM_STATE" ]] || { usage >&2; exit 1; }
|
|
57
|
+
command -v jq >/dev/null 2>&1 || { echo 'jq is required.' >&2; exit 1; }
|
|
58
|
+
|
|
59
|
+
HISTORY_FILE="$(publish_resolve_history_file "$CONFIG_PATH")"
|
|
60
|
+
publish_ensure_history_file "$HISTORY_FILE"
|
|
61
|
+
|
|
62
|
+
if [[ -n "$SELECTED_VERSION" ]]; then
|
|
63
|
+
VERSION="$SELECTED_VERSION"
|
|
64
|
+
else
|
|
65
|
+
SUGGEST_CMD=(bash "$SCRIPT_DIR/suggest_semver_bump.sh")
|
|
66
|
+
if (( AUTO_ACCEPT )); then
|
|
67
|
+
SUGGEST_CMD+=(--yes)
|
|
68
|
+
fi
|
|
69
|
+
if [[ -n "$CONFIG_PATH" ]]; then
|
|
70
|
+
SUGGEST_CMD+=("$CONFIG_PATH")
|
|
71
|
+
fi
|
|
72
|
+
VERSION_OUTPUT="$("${SUGGEST_CMD[@]}")"
|
|
73
|
+
printf '%s\n' "$VERSION_OUTPUT"
|
|
74
|
+
VERSION="$(printf '%s\n' "$VERSION_OUTPUT" | tail -n 1 | tr -d '\r')"
|
|
75
|
+
fi
|
|
76
|
+
VERSION="$(publish_normalize_version "$VERSION")" || {
|
|
77
|
+
echo "Unable to resolve a valid version from suggest_semver_bump.sh output." >&2
|
|
78
|
+
exit 1
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
GIT_TAG="$VERSION"
|
|
82
|
+
if (( DRY_RUN )); then
|
|
83
|
+
printf '[DRY RUN] Would create tag %s\n' "$GIT_TAG"
|
|
84
|
+
elif git rev-parse "$GIT_TAG" >/dev/null 2>&1; then
|
|
85
|
+
printf '⚠️ Git tag %s already exists — skipping tag creation\n' "$GIT_TAG" >&2
|
|
86
|
+
else
|
|
87
|
+
git tag -a "$GIT_TAG" -m "Release $GIT_TAG — deployed to $TARGET_NAME"
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
TIMESTAMP="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
|
91
|
+
RELEASED_BY="$(publish_current_actor)"
|
|
92
|
+
COMMIT_SHA="$(git rev-parse HEAD)"
|
|
93
|
+
ENTRY_ID="$(uuidgen | tr '[:upper:]' '[:lower:]')"
|
|
94
|
+
|
|
95
|
+
if [[ -z "$NOTES_PATH_RAW" || "$NOTES_PATH_RAW" == 'null' ]]; then
|
|
96
|
+
NOTES_JSON='null'
|
|
97
|
+
else
|
|
98
|
+
NOTES_JSON="$(jq -Rn --arg path "$NOTES_PATH_RAW" '$path')"
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
ENTRY_JSON="$(jq -cn \
|
|
102
|
+
--arg id "$ENTRY_ID" \
|
|
103
|
+
--arg version "$VERSION" \
|
|
104
|
+
--arg target "$TARGET_NAME" \
|
|
105
|
+
--arg adapter "$ADAPTER_NAME" \
|
|
106
|
+
--arg timestamp "$TIMESTAMP" \
|
|
107
|
+
--arg released_by "$RELEASED_BY" \
|
|
108
|
+
--arg platform_state "$PLATFORM_STATE" \
|
|
109
|
+
--arg git_tag "$GIT_TAG" \
|
|
110
|
+
--arg commit_sha "$COMMIT_SHA" \
|
|
111
|
+
--argjson release_notes_path "$NOTES_JSON" \
|
|
112
|
+
'{
|
|
113
|
+
id: $id,
|
|
114
|
+
version: $version,
|
|
115
|
+
target: $target,
|
|
116
|
+
adapter: $adapter,
|
|
117
|
+
timestamp: $timestamp,
|
|
118
|
+
released_by: $released_by,
|
|
119
|
+
release_notes_path: $release_notes_path,
|
|
120
|
+
platform_state: $platform_state,
|
|
121
|
+
git_tag: $git_tag,
|
|
122
|
+
commit_sha: $commit_sha
|
|
123
|
+
}')"
|
|
124
|
+
|
|
125
|
+
publish_append_history_entry "$HISTORY_FILE" "$ENTRY_JSON"
|
|
126
|
+
printf '🧾 Publish ledger entry appended for %s\n' "$VERSION"
|