skillwiki 0.9.63 → 0.10.1
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/dist/chunk-C5OLZRRM.js +357 -0
- package/dist/chunk-IZABIE44.js +647 -0
- package/dist/chunk-R6BKJWVC.js +890 -0
- package/dist/chunk-SCGC7YNM.js +213 -0
- package/dist/{chunk-TUFQZ5K4.js → chunk-XSTXPA34.js} +834 -1981
- package/dist/cli.js +1780 -697
- package/dist/index-projection-ERFX76U5.js +10 -0
- package/dist/managed-write-preflight-PW4OOOMV.js +11 -0
- package/dist/skillwiki-mcp.js +4 -1
- package/dist/vault-sync/scripts/lib/conflict-markers.sh +69 -0
- package/dist/vault-sync/scripts/lib/delete-intent.sh +74 -0
- package/dist/vault-sync/scripts/lib/fleet.sh +103 -0
- package/dist/vault-sync/scripts/lib/git-case.sh +71 -0
- package/dist/vault-sync/scripts/lib/git-materialization.sh +264 -0
- package/dist/vault-sync/scripts/lib/git-operation-journal.sh +469 -0
- package/dist/vault-sync/scripts/lib/git-rebase-state.sh +180 -0
- package/dist/vault-sync/scripts/lib/lockfile.sh +70 -0
- package/dist/vault-sync/scripts/lib/managed-write-lock.sh +80 -0
- package/dist/vault-sync/scripts/lib/platform.sh +184 -0
- package/dist/vault-sync/scripts/lib/runtime-manifest.sh +223 -0
- package/dist/vault-sync/scripts/wiki-fetch-notify.sh +207 -0
- package/dist/vault-sync/scripts/wiki-fuse-refresh.sh +405 -0
- package/dist/vault-sync/scripts/wiki-pull-with-auto-resolve.sh +631 -0
- package/dist/vault-sync/scripts/wiki-push.sh +364 -0
- package/dist/vault-sync/scripts/wiki-snapshot.sh +587 -0
- package/package.json +2 -2
- package/skills/.claude-plugin/plugin.json +1 -1
- package/skills/.codex-plugin/plugin.json +1 -1
- package/skills/README.md +13 -0
- package/skills/package.json +1 -1
- package/skills/proj-work/SKILL.md +3 -0
- package/skills/skills/proj-work/SKILL.md +3 -0
- package/skills/skills/using-skillwiki/SKILL.md +24 -0
- package/skills/skills/wiki-crystallize/SKILL.md +3 -0
- package/skills/using-skillwiki/SKILL.md +24 -0
- package/skills/wiki-crystallize/SKILL.md +3 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# lockfile.sh — Advisory locking for vault-sync scripts.
|
|
3
|
+
#
|
|
4
|
+
# Uses flock when available (Linux primary); falls back to mkdir mutex (macOS).
|
|
5
|
+
# Reclaims locks older than max_age seconds (default 600 = 10 min).
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# lockfile_acquire <path> [max_age_seconds] → returns 0 on success, 1 on contention, 2 on stale-reclaim
|
|
9
|
+
# lockfile_release <path>
|
|
10
|
+
|
|
11
|
+
# Acquire advisory lock.
|
|
12
|
+
# Returns: 0 = acquired, 1 = contended, 2 = stale-reclaim
|
|
13
|
+
lockfile_acquire() {
|
|
14
|
+
_lock_path="$1"
|
|
15
|
+
_max_age="${2:-600}"
|
|
16
|
+
|
|
17
|
+
# Try flock first (Linux primary, macOS opportunistic)
|
|
18
|
+
# shellcheck disable=SC2034
|
|
19
|
+
if command -v flock >/dev/null 2>&1; then
|
|
20
|
+
# Use fd 9 for the lock
|
|
21
|
+
eval "exec 9>\"$_lock_path\""
|
|
22
|
+
if flock -n 9 2>/dev/null; then
|
|
23
|
+
return 0
|
|
24
|
+
fi
|
|
25
|
+
# flock failed — fall through to mkdir mutex
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# mkdir mutex fallback
|
|
29
|
+
_lock_dir="${_lock_path}.d"
|
|
30
|
+
if mkdir "$_lock_dir" 2>/dev/null; then
|
|
31
|
+
_VS_LOCK_DIR="$_lock_dir"
|
|
32
|
+
export _VS_LOCK_DIR
|
|
33
|
+
trap 'lockfile_release "$_lock_path"' EXIT
|
|
34
|
+
return 0
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# Directory exists — check if stale
|
|
38
|
+
if [ -d "$_lock_dir" ]; then
|
|
39
|
+
_now=$(date +%s)
|
|
40
|
+
_ctime=$(platform_stat_ctime "$_lock_dir")
|
|
41
|
+
_age=$(( _now - _ctime ))
|
|
42
|
+
if [ "$_age" -gt "$_max_age" ]; then
|
|
43
|
+
# Stale lock — reclaim
|
|
44
|
+
rmdir "$_lock_dir" 2>/dev/null || true
|
|
45
|
+
if mkdir "$_lock_dir" 2>/dev/null; then
|
|
46
|
+
_VS_LOCK_DIR="$_lock_dir"
|
|
47
|
+
export _VS_LOCK_DIR
|
|
48
|
+
trap 'lockfile_release "$_lock_path"' EXIT
|
|
49
|
+
return 2
|
|
50
|
+
fi
|
|
51
|
+
fi
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
return 1
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# Release advisory lock.
|
|
58
|
+
lockfile_release() {
|
|
59
|
+
_lock_path="$1"
|
|
60
|
+
_lock_dir="${_lock_path}.d"
|
|
61
|
+
|
|
62
|
+
# Release mkdir mutex if we hold it
|
|
63
|
+
if [ -n "${_VS_LOCK_DIR:-}" ] && [ "$_VS_LOCK_DIR" = "$_lock_dir" ]; then
|
|
64
|
+
rmdir "$_lock_dir" 2>/dev/null || true
|
|
65
|
+
unset _VS_LOCK_DIR
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# flock is released when fd 9 closes (process exit)
|
|
69
|
+
return 0
|
|
70
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# managed-write-lock.sh — shared CLI/shell managed-write lock (Bash 3.2).
|
|
3
|
+
# Source from vault-sync scripts. Lock path: git --git-path vault-sync/managed-write.lock
|
|
4
|
+
|
|
5
|
+
VAULT_SYNC_MANAGED_LOCK_PATH=""
|
|
6
|
+
VAULT_SYNC_MANAGED_LOCK_TOKEN_OWNED=""
|
|
7
|
+
VAULT_SYNC_MANAGED_LOCK_ACQUIRED=""
|
|
8
|
+
VAULT_SYNC_MANAGED_LOCK_OWNS_RELEASE=0
|
|
9
|
+
|
|
10
|
+
vault_sync_managed_lock_path() {
|
|
11
|
+
local repo="${1:-.}"
|
|
12
|
+
local path
|
|
13
|
+
path="$(git -C "$repo" rev-parse --git-path vault-sync/managed-write.lock 2>/dev/null)" || return 1
|
|
14
|
+
case "$path" in
|
|
15
|
+
/*) printf '%s\n' "$path" ;;
|
|
16
|
+
*) printf '%s\n' "$repo/$path" ;;
|
|
17
|
+
esac
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
vault_sync_managed_lock_read_token() {
|
|
21
|
+
local path="$1"
|
|
22
|
+
[ -f "$path" ] || return 1
|
|
23
|
+
sed -n 's/.*"owner_token"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$path" | head -1
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# Acquire or adopt managed-write lock. Returns 0 on success, 1 on contention/mismatch.
|
|
27
|
+
vault_sync_managed_lock_acquire() {
|
|
28
|
+
local repo="${1:-.}"
|
|
29
|
+
local command="${2:-wiki-pull}"
|
|
30
|
+
local path token now inherited
|
|
31
|
+
path="$(vault_sync_managed_lock_path "$repo")" || return 1
|
|
32
|
+
VAULT_SYNC_MANAGED_LOCK_PATH="$path"
|
|
33
|
+
mkdir -p "$(dirname "$path")" || return 1
|
|
34
|
+
|
|
35
|
+
inherited="${VAULT_SYNC_MANAGED_LOCK_TOKEN:-}"
|
|
36
|
+
if [ -n "$inherited" ]; then
|
|
37
|
+
if [ -f "$path" ]; then
|
|
38
|
+
token="$(vault_sync_managed_lock_read_token "$path" || true)"
|
|
39
|
+
if [ "$token" = "$inherited" ]; then
|
|
40
|
+
VAULT_SYNC_MANAGED_LOCK_TOKEN_OWNED="$inherited"
|
|
41
|
+
VAULT_SYNC_MANAGED_LOCK_OWNS_RELEASE=0
|
|
42
|
+
return 0
|
|
43
|
+
fi
|
|
44
|
+
return 1
|
|
45
|
+
fi
|
|
46
|
+
return 1
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
token="$(od -An -N16 -tx1 /dev/urandom 2>/dev/null | tr -d ' \n')"
|
|
50
|
+
[ -n "$token" ] || token="$$-$(date +%s)"
|
|
51
|
+
now="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
52
|
+
if ( set -o noclobber; printf '{"pid":%s,"owner_token":"%s","acquired":"%s","command":"%s"}\n' \
|
|
53
|
+
"$$" "$token" "$now" "$command" >"$path" ) 2>/dev/null; then
|
|
54
|
+
VAULT_SYNC_MANAGED_LOCK_TOKEN_OWNED="$token"
|
|
55
|
+
VAULT_SYNC_MANAGED_LOCK_ACQUIRED="$now"
|
|
56
|
+
VAULT_SYNC_MANAGED_LOCK_OWNS_RELEASE=1
|
|
57
|
+
return 0
|
|
58
|
+
fi
|
|
59
|
+
return 1
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
vault_sync_managed_lock_release() {
|
|
63
|
+
local path token
|
|
64
|
+
path="${VAULT_SYNC_MANAGED_LOCK_PATH:-}"
|
|
65
|
+
[ -n "$path" ] || return 0
|
|
66
|
+
if [ "${VAULT_SYNC_MANAGED_LOCK_OWNS_RELEASE:-0}" != "1" ]; then
|
|
67
|
+
return 0
|
|
68
|
+
fi
|
|
69
|
+
if [ ! -f "$path" ]; then
|
|
70
|
+
VAULT_SYNC_MANAGED_LOCK_OWNS_RELEASE=0
|
|
71
|
+
return 0
|
|
72
|
+
fi
|
|
73
|
+
token="$(vault_sync_managed_lock_read_token "$path" || true)"
|
|
74
|
+
if [ "$token" != "${VAULT_SYNC_MANAGED_LOCK_TOKEN_OWNED:-}" ]; then
|
|
75
|
+
return 1
|
|
76
|
+
fi
|
|
77
|
+
rm -f -- "$path"
|
|
78
|
+
VAULT_SYNC_MANAGED_LOCK_OWNS_RELEASE=0
|
|
79
|
+
return 0
|
|
80
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# platform.sh — Cross-platform abstraction for vault-sync scripts.
|
|
3
|
+
#
|
|
4
|
+
# Sourced by all vault-sync scripts. Provides OS detection, normalized
|
|
5
|
+
# paths, stat wrappers, notification shim, scheduler abstraction, and
|
|
6
|
+
# feature prerequisites.
|
|
7
|
+
#
|
|
8
|
+
# Works in bash and /bin/sh (dash on Debian). No external deps beyond
|
|
9
|
+
# what vault-sync itself requires (rclone, git).
|
|
10
|
+
|
|
11
|
+
# Detect OS. Sets VS_OS to "macos" | "linux" | "unsupported".
|
|
12
|
+
platform_detect_os() {
|
|
13
|
+
case "$(uname -s)" in
|
|
14
|
+
Darwin) VS_OS=macos ;;
|
|
15
|
+
Linux) VS_OS=linux ;;
|
|
16
|
+
*) VS_OS=unsupported ;;
|
|
17
|
+
esac
|
|
18
|
+
export VS_OS
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# Normalized paths (XDG on Linux, ~/Library on macOS):
|
|
22
|
+
|
|
23
|
+
platform_log_dir() {
|
|
24
|
+
case "${VS_OS:-}" in
|
|
25
|
+
macos) echo "$HOME/Library/Logs" ;;
|
|
26
|
+
linux) echo "$HOME/.local/state/vault-sync/log" ;;
|
|
27
|
+
*) echo "$HOME/.local/state/vault-sync/log" ;;
|
|
28
|
+
esac
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
platform_cache_dir() {
|
|
32
|
+
case "${VS_OS:-}" in
|
|
33
|
+
macos) echo "$HOME/Library/Caches/vault-sync" ;;
|
|
34
|
+
linux) echo "$HOME/.cache/vault-sync" ;;
|
|
35
|
+
*) echo "$HOME/.cache/vault-sync" ;;
|
|
36
|
+
esac
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
platform_share_dir() {
|
|
40
|
+
case "${VS_OS:-}" in
|
|
41
|
+
macos) echo "$HOME/Library/Application Support/vault-sync" ;;
|
|
42
|
+
linux) echo "$HOME/.local/share/vault-sync" ;;
|
|
43
|
+
*) echo "$HOME/.local/share/vault-sync" ;;
|
|
44
|
+
esac
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
platform_rclone_config_dir() {
|
|
48
|
+
echo "$HOME/.config/rclone"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# Stat wrappers (BSD -f vs GNU -c):
|
|
52
|
+
|
|
53
|
+
platform_stat_size() {
|
|
54
|
+
# echo bytes
|
|
55
|
+
case "${VS_OS:-}" in
|
|
56
|
+
macos) stat -f%z "$1" 2>/dev/null || echo 0 ;;
|
|
57
|
+
linux) stat -c%s "$1" 2>/dev/null || echo 0 ;;
|
|
58
|
+
*) stat -c%s "$1" 2>/dev/null || stat -f%z "$1" 2>/dev/null || echo 0 ;;
|
|
59
|
+
esac
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
platform_stat_ctime() {
|
|
63
|
+
# echo unix epoch
|
|
64
|
+
case "${VS_OS:-}" in
|
|
65
|
+
macos) stat -f%c "$1" 2>/dev/null || echo 0 ;;
|
|
66
|
+
linux) stat -c%Z "$1" 2>/dev/null || echo 0 ;;
|
|
67
|
+
*) stat -c%Z "$1" 2>/dev/null || stat -f%c "$1" 2>/dev/null || echo 0 ;;
|
|
68
|
+
esac
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
# Notification (graceful degrade):
|
|
72
|
+
# macos: osascript display notification
|
|
73
|
+
# linux: notify-send if available, else log only
|
|
74
|
+
# headless: no-op (return 0)
|
|
75
|
+
platform_notify() {
|
|
76
|
+
_title="$1"
|
|
77
|
+
_msg="$2"
|
|
78
|
+
case "${VS_OS:-}" in
|
|
79
|
+
macos)
|
|
80
|
+
osascript -e "display notification \"$_msg\" with title \"$_title\"" 2>/dev/null || true
|
|
81
|
+
;;
|
|
82
|
+
linux)
|
|
83
|
+
if command -v notify-send >/dev/null 2>&1; then
|
|
84
|
+
notify-send "$_title" "$_msg" 2>/dev/null || true
|
|
85
|
+
fi
|
|
86
|
+
# Headless Linux: no-op, return 0
|
|
87
|
+
;;
|
|
88
|
+
*) ;;
|
|
89
|
+
esac
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
# Scheduler abstraction:
|
|
93
|
+
|
|
94
|
+
platform_scheduler() {
|
|
95
|
+
# echo: launchd | systemd | none
|
|
96
|
+
case "${VS_OS:-}" in
|
|
97
|
+
macos)
|
|
98
|
+
if command -v launchctl >/dev/null 2>&1; then
|
|
99
|
+
echo "launchd"
|
|
100
|
+
else
|
|
101
|
+
echo "none"
|
|
102
|
+
fi
|
|
103
|
+
;;
|
|
104
|
+
linux)
|
|
105
|
+
if command -v systemctl >/dev/null 2>&1 && systemctl --user >/dev/null 2>&1; then
|
|
106
|
+
echo "systemd"
|
|
107
|
+
else
|
|
108
|
+
echo "none"
|
|
109
|
+
fi
|
|
110
|
+
;;
|
|
111
|
+
*) echo "none" ;;
|
|
112
|
+
esac
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
platform_job_status() {
|
|
116
|
+
# Returns JSON: {"enabled": bool, "running": bool, "last_exit": int}
|
|
117
|
+
_name="$1"
|
|
118
|
+
_enabled=false
|
|
119
|
+
_running=false
|
|
120
|
+
_last_exit=-1
|
|
121
|
+
|
|
122
|
+
case "${VS_OS:-}" in
|
|
123
|
+
macos)
|
|
124
|
+
# launchd: check via launchctl print
|
|
125
|
+
if launchctl print "gui/$(id -u)/${_name}" >/dev/null 2>&1; then
|
|
126
|
+
_enabled=true
|
|
127
|
+
_running=true # launchd prints exit status if job ran
|
|
128
|
+
_last_exit=0 # simplified; full parsing is complex
|
|
129
|
+
fi
|
|
130
|
+
;;
|
|
131
|
+
linux)
|
|
132
|
+
# systemd --user
|
|
133
|
+
if _is_enabled="$(systemctl --user is-enabled "${_name}.timer" 2>/dev/null)"; then
|
|
134
|
+
if [ "$_is_enabled" = "enabled" ]; then
|
|
135
|
+
_enabled=true
|
|
136
|
+
fi
|
|
137
|
+
fi
|
|
138
|
+
if _is_active="$(systemctl --user is-active "${_name}.timer" 2>/dev/null)"; then
|
|
139
|
+
if [ "$_is_active" = "active" ]; then
|
|
140
|
+
_running=true
|
|
141
|
+
fi
|
|
142
|
+
fi
|
|
143
|
+
_last_exit=0 # simplified
|
|
144
|
+
;;
|
|
145
|
+
esac
|
|
146
|
+
|
|
147
|
+
printf '{"enabled": %s, "running": %s, "last_exit": %d}\n' "$_enabled" "$_running" "$_last_exit"
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
# Feature prerequisite check:
|
|
151
|
+
# exit 1 with message if not available
|
|
152
|
+
platform_require() {
|
|
153
|
+
_feature="$1"
|
|
154
|
+
case "$_feature" in
|
|
155
|
+
rclone)
|
|
156
|
+
if ! command -v rclone >/dev/null 2>&1; then
|
|
157
|
+
echo "FATAL: rclone not found in PATH" >&2
|
|
158
|
+
return 1
|
|
159
|
+
fi
|
|
160
|
+
;;
|
|
161
|
+
git)
|
|
162
|
+
if ! command -v git >/dev/null 2>&1; then
|
|
163
|
+
echo "FATAL: git not found in PATH" >&2
|
|
164
|
+
return 1
|
|
165
|
+
fi
|
|
166
|
+
;;
|
|
167
|
+
linux)
|
|
168
|
+
if [ "${VS_OS:-}" != "linux" ]; then
|
|
169
|
+
echo "FATAL: this operation requires Linux" >&2
|
|
170
|
+
return 1
|
|
171
|
+
fi
|
|
172
|
+
;;
|
|
173
|
+
macos)
|
|
174
|
+
if [ "${VS_OS:-}" != "macos" ]; then
|
|
175
|
+
echo "FATAL: this operation requires macOS" >&2
|
|
176
|
+
return 1
|
|
177
|
+
fi
|
|
178
|
+
;;
|
|
179
|
+
*)
|
|
180
|
+
echo "FATAL: unknown prerequisite: $_feature" >&2
|
|
181
|
+
return 1
|
|
182
|
+
;;
|
|
183
|
+
esac
|
|
184
|
+
}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# runtime-manifest.sh — SHA-256 inventory of installed vault-sync artifacts.
|
|
3
|
+
#
|
|
4
|
+
# Sourced by vault-sync-install (and later vault-sync-status). Works in bash
|
|
5
|
+
# and /bin/sh. Prefers python3 for JSON emission; falls back to a minimal
|
|
6
|
+
# hand-built JSON object when python3 is unavailable.
|
|
7
|
+
#
|
|
8
|
+
# Public API:
|
|
9
|
+
# vault_sync_sha256 <file> → hex digest or empty
|
|
10
|
+
# vault_sync_package_version <root> → version string
|
|
11
|
+
# vault_sync_package_commit <root> → git HEAD or empty
|
|
12
|
+
# vault_sync_write_runtime_manifest \
|
|
13
|
+
# <out_path> <share_dir> <launch_agents_dir> \
|
|
14
|
+
# <package_version> <package_commit> <installer_version> \
|
|
15
|
+
# <installed_at> <role> <host_id>
|
|
16
|
+
|
|
17
|
+
# Resolve once per process when possible.
|
|
18
|
+
_vault_sync_sha256_resolved=0
|
|
19
|
+
_vault_sync_sha256_tool=""
|
|
20
|
+
|
|
21
|
+
_vault_sync_sha256_resolve() {
|
|
22
|
+
if [ "$_vault_sync_sha256_resolved" = "1" ]; then
|
|
23
|
+
return 0
|
|
24
|
+
fi
|
|
25
|
+
_vault_sync_sha256_resolved=1
|
|
26
|
+
if command -v shasum >/dev/null 2>&1; then
|
|
27
|
+
_vault_sync_sha256_tool=shasum
|
|
28
|
+
elif command -v sha256sum >/dev/null 2>&1; then
|
|
29
|
+
_vault_sync_sha256_tool=sha256sum
|
|
30
|
+
elif command -v openssl >/dev/null 2>&1; then
|
|
31
|
+
_vault_sync_sha256_tool=openssl
|
|
32
|
+
elif command -v python3 >/dev/null 2>&1; then
|
|
33
|
+
_vault_sync_sha256_tool=python3
|
|
34
|
+
else
|
|
35
|
+
_vault_sync_sha256_tool=""
|
|
36
|
+
fi
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
vault_sync_sha256() {
|
|
40
|
+
_f="$1"
|
|
41
|
+
if [ ! -f "$_f" ]; then
|
|
42
|
+
echo ""
|
|
43
|
+
return 0
|
|
44
|
+
fi
|
|
45
|
+
_vault_sync_sha256_resolve
|
|
46
|
+
case "$_vault_sync_sha256_tool" in
|
|
47
|
+
shasum)
|
|
48
|
+
shasum -a 256 "$_f" 2>/dev/null | awk '{print $1}'
|
|
49
|
+
;;
|
|
50
|
+
sha256sum)
|
|
51
|
+
sha256sum "$_f" 2>/dev/null | awk '{print $1}'
|
|
52
|
+
;;
|
|
53
|
+
openssl)
|
|
54
|
+
openssl dgst -sha256 "$_f" 2>/dev/null | awk '{print $NF}'
|
|
55
|
+
;;
|
|
56
|
+
python3)
|
|
57
|
+
python3 -c 'import hashlib,sys; print(hashlib.sha256(open(sys.argv[1],"rb").read()).hexdigest())' "$_f" 2>/dev/null
|
|
58
|
+
;;
|
|
59
|
+
*)
|
|
60
|
+
echo ""
|
|
61
|
+
;;
|
|
62
|
+
esac
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# Trim leading/trailing whitespace (portable; no bashisms required).
|
|
66
|
+
_vault_sync_trim() {
|
|
67
|
+
printf '%s' "$1" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
vault_sync_package_version() {
|
|
71
|
+
_root="$1"
|
|
72
|
+
# Deploy provenance override (rsync/staged install). Metadata only.
|
|
73
|
+
_override="$(_vault_sync_trim "${VS_PACKAGE_VERSION:-}")"
|
|
74
|
+
if [ -n "$_override" ]; then
|
|
75
|
+
printf '%s\n' "$_override"
|
|
76
|
+
return 0
|
|
77
|
+
fi
|
|
78
|
+
# Prefer monorepo package.json two levels up from packages/vault-sync, else root.
|
|
79
|
+
if [ -f "$_root/../../package.json" ]; then
|
|
80
|
+
if command -v python3 >/dev/null 2>&1; then
|
|
81
|
+
python3 -c 'import json,sys; print(json.load(open(sys.argv[1])).get("version",""))' "$_root/../../package.json" 2>/dev/null && return 0
|
|
82
|
+
fi
|
|
83
|
+
sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$_root/../../package.json" 2>/dev/null | head -n 1
|
|
84
|
+
return 0
|
|
85
|
+
fi
|
|
86
|
+
if [ -f "$_root/package.json" ]; then
|
|
87
|
+
if command -v python3 >/dev/null 2>&1; then
|
|
88
|
+
python3 -c 'import json,sys; print(json.load(open(sys.argv[1])).get("version",""))' "$_root/package.json" 2>/dev/null && return 0
|
|
89
|
+
fi
|
|
90
|
+
fi
|
|
91
|
+
echo "0.0.0"
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
vault_sync_package_commit() {
|
|
95
|
+
_root="$1"
|
|
96
|
+
# Deploy provenance override (rsync/staged install). Metadata only.
|
|
97
|
+
_override="$(_vault_sync_trim "${VS_PACKAGE_COMMIT:-}")"
|
|
98
|
+
if [ -n "$_override" ]; then
|
|
99
|
+
printf '%s\n' "$_override"
|
|
100
|
+
return 0
|
|
101
|
+
fi
|
|
102
|
+
if command -v git >/dev/null 2>&1 && [ -d "$_root/../../.git" -o -f "$_root/../../.git" ] 2>/dev/null; then
|
|
103
|
+
git -C "$_root/../.." rev-parse HEAD 2>/dev/null || echo ""
|
|
104
|
+
return 0
|
|
105
|
+
fi
|
|
106
|
+
if command -v git >/dev/null 2>&1; then
|
|
107
|
+
git -C "$_root" rev-parse HEAD 2>/dev/null || echo ""
|
|
108
|
+
return 0
|
|
109
|
+
fi
|
|
110
|
+
echo ""
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
# Collect relative_path=sha256 pairs for files under share_dir/bin and
|
|
114
|
+
# LaunchAgents plists. Writes newline-separated "relpath\thash" to stdout.
|
|
115
|
+
vault_sync_collect_file_hashes() {
|
|
116
|
+
_share="$1"
|
|
117
|
+
_agents="$2"
|
|
118
|
+
_bin="$_share/bin"
|
|
119
|
+
|
|
120
|
+
if [ -d "$_bin" ]; then
|
|
121
|
+
# shell scripts at bin root
|
|
122
|
+
for _f in "$_bin"/*; do
|
|
123
|
+
[ -f "$_f" ] || continue
|
|
124
|
+
_base="$(basename "$_f")"
|
|
125
|
+
_h="$(vault_sync_sha256 "$_f")"
|
|
126
|
+
[ -n "$_h" ] && printf 'bin/%s\t%s\n' "$_base" "$_h"
|
|
127
|
+
done
|
|
128
|
+
# lib/*.sh
|
|
129
|
+
if [ -d "$_bin/lib" ]; then
|
|
130
|
+
for _f in "$_bin/lib"/*; do
|
|
131
|
+
[ -f "$_f" ] || continue
|
|
132
|
+
_base="$(basename "$_f")"
|
|
133
|
+
_h="$(vault_sync_sha256 "$_f")"
|
|
134
|
+
[ -n "$_h" ] && printf 'bin/lib/%s\t%s\n' "$_base" "$_h"
|
|
135
|
+
done
|
|
136
|
+
fi
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
if [ -d "$_agents" ]; then
|
|
140
|
+
for _f in "$_agents"/com.karlchow.wiki-*.plist; do
|
|
141
|
+
[ -f "$_f" ] || continue
|
|
142
|
+
_base="$(basename "$_f")"
|
|
143
|
+
_h="$(vault_sync_sha256 "$_f")"
|
|
144
|
+
[ -n "$_h" ] && printf 'LaunchAgents/%s\t%s\n' "$_base" "$_h"
|
|
145
|
+
done
|
|
146
|
+
fi
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
vault_sync_write_runtime_manifest() {
|
|
150
|
+
_out="$1"
|
|
151
|
+
_share="$2"
|
|
152
|
+
_agents="$3"
|
|
153
|
+
_pkg_ver="$4"
|
|
154
|
+
_pkg_commit="$5"
|
|
155
|
+
_installer_ver="$6"
|
|
156
|
+
_installed_at="$7"
|
|
157
|
+
_role="$8"
|
|
158
|
+
_host_id="$9"
|
|
159
|
+
|
|
160
|
+
_pairs="$(mktemp)"
|
|
161
|
+
vault_sync_collect_file_hashes "$_share" "$_agents" >"$_pairs"
|
|
162
|
+
|
|
163
|
+
mkdir -p "$(dirname "$_out")"
|
|
164
|
+
|
|
165
|
+
if command -v python3 >/dev/null 2>&1; then
|
|
166
|
+
python3 - "$_out" "$_pkg_ver" "$_pkg_commit" "$_installer_ver" "$_installed_at" "$_role" "$_host_id" "$_pairs" <<'PY'
|
|
167
|
+
import json, sys
|
|
168
|
+
out, pkg_ver, pkg_commit, installer_ver, installed_at, role, host_id, pairs_path = sys.argv[1:9]
|
|
169
|
+
files = {}
|
|
170
|
+
with open(pairs_path, "r", encoding="utf-8") as fh:
|
|
171
|
+
for line in fh:
|
|
172
|
+
line = line.rstrip("\n")
|
|
173
|
+
if not line:
|
|
174
|
+
continue
|
|
175
|
+
if "\t" not in line:
|
|
176
|
+
continue
|
|
177
|
+
rel, digest = line.split("\t", 1)
|
|
178
|
+
files[rel] = digest
|
|
179
|
+
manifest = {
|
|
180
|
+
"schema_version": 1,
|
|
181
|
+
"package_commit": pkg_commit,
|
|
182
|
+
"package_version": pkg_ver,
|
|
183
|
+
"installer_version": installer_ver,
|
|
184
|
+
"installed_at": installed_at,
|
|
185
|
+
"role": role,
|
|
186
|
+
"host_id": host_id,
|
|
187
|
+
"files": files,
|
|
188
|
+
}
|
|
189
|
+
with open(out, "w", encoding="utf-8") as fh:
|
|
190
|
+
json.dump(manifest, fh, indent=2, sort_keys=False)
|
|
191
|
+
fh.write("\n")
|
|
192
|
+
PY
|
|
193
|
+
_rc=$?
|
|
194
|
+
rm -f "$_pairs"
|
|
195
|
+
return $_rc
|
|
196
|
+
fi
|
|
197
|
+
|
|
198
|
+
# Minimal fallback without python3
|
|
199
|
+
{
|
|
200
|
+
printf '{\n'
|
|
201
|
+
printf ' "schema_version": 1,\n'
|
|
202
|
+
printf ' "package_commit": "%s",\n' "$_pkg_commit"
|
|
203
|
+
printf ' "package_version": "%s",\n' "$_pkg_ver"
|
|
204
|
+
printf ' "installer_version": "%s",\n' "$_installer_ver"
|
|
205
|
+
printf ' "installed_at": "%s",\n' "$_installed_at"
|
|
206
|
+
printf ' "role": "%s",\n' "$_role"
|
|
207
|
+
printf ' "host_id": "%s",\n' "$_host_id"
|
|
208
|
+
printf ' "files": {\n'
|
|
209
|
+
_first=1
|
|
210
|
+
while IFS="$(printf '\t')" read -r _rel _hash; do
|
|
211
|
+
[ -n "$_rel" ] || continue
|
|
212
|
+
if [ "$_first" -eq 1 ]; then
|
|
213
|
+
_first=0
|
|
214
|
+
else
|
|
215
|
+
printf ',\n'
|
|
216
|
+
fi
|
|
217
|
+
printf ' "%s": "%s"' "$_rel" "$_hash"
|
|
218
|
+
done <"$_pairs"
|
|
219
|
+
printf '\n }\n}\n'
|
|
220
|
+
} >"$_out"
|
|
221
|
+
rm -f "$_pairs"
|
|
222
|
+
return 0
|
|
223
|
+
}
|