@indigoai-us/hq-cli 5.89.0 → 5.89.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/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [5.89.1]
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- `hq core worker lint` now partitions its duplicate check by ownership domain
|
|
10
|
+
(`core/workers`, each `core/packages/<pack>`, each `companies/<co>`) and
|
|
11
|
+
excludes dot-directories (`.archive/`) and `._*` AppleDouble files. A
|
|
12
|
+
whole-tree scan of a real install previously reported false positives for
|
|
13
|
+
packs that intentionally vendor a byte-identical copy of a core worker skill,
|
|
14
|
+
for archived pack snapshots, and for macOS metadata files. Within-domain
|
|
15
|
+
duplicates are still flagged. (policy
|
|
16
|
+
hq-lint-comparison-domains-must-match-ownership)
|
|
17
|
+
|
|
5
18
|
## [5.89.0]
|
|
6
19
|
|
|
7
20
|
### Added
|
|
@@ -12,22 +12,37 @@
|
|
|
12
12
|
#
|
|
13
13
|
# This linter makes that convention enforceable. It flags two failure shapes:
|
|
14
14
|
#
|
|
15
|
-
# DUPLICATE — two or more NON-symlink skill files,
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
# moment someone edits one, they drift. (Symlinks that
|
|
19
|
-
# a shared canonical are single-sourced and are NOT
|
|
20
|
-
# though their resolved content matches
|
|
15
|
+
# DUPLICATE — two or more NON-symlink skill files, WITHIN A SINGLE OWNERSHIP
|
|
16
|
+
# DOMAIN, whose byte content is identical. Identical bytes across
|
|
17
|
+
# two real files in the same domain is exactly an un-single-sourced
|
|
18
|
+
# copy: the moment someone edits one, they drift. (Symlinks that
|
|
19
|
+
# resolve to a shared canonical are single-sourced and are NOT
|
|
20
|
+
# flagged, even though their resolved content matches.)
|
|
21
21
|
# BROKEN — a skill entry that is a symlink whose target does not resolve.
|
|
22
22
|
#
|
|
23
23
|
# It deliberately does NOT flag two same-NAMED skills whose content differs
|
|
24
24
|
# (e.g. an API-level vs a browser-level e2e skill): distinct content means they
|
|
25
25
|
# are distinct skills that merely share a filename, not a drifted share.
|
|
26
26
|
#
|
|
27
|
+
# OWNERSHIP DOMAINS — filesystem adjacency does NOT establish duplicate
|
|
28
|
+
# ownership, so comparison is partitioned by the tree that OWNS a skill (policy
|
|
29
|
+
# hq-lint-comparison-domains-must-match-ownership):
|
|
30
|
+
#
|
|
31
|
+
# - `core/workers` — the curated first-party worker library
|
|
32
|
+
# - `core/packages/<pack>` — one installed pack (self-contained; may legally
|
|
33
|
+
# vendor a byte-identical copy of a core worker)
|
|
34
|
+
# - `companies/<co>` — one tenant's workers
|
|
35
|
+
#
|
|
36
|
+
# A byte-identical file in TWO DIFFERENT domains (a pack vendoring a core skill,
|
|
37
|
+
# or two packs shipping the same skill) is intentional distribution, NOT drift,
|
|
38
|
+
# and is never flagged. Excluded from the scan entirely: dot-directories
|
|
39
|
+
# (`.archive/`, `.git/`, …) and `._*` AppleDouble OS-metadata files — byte-
|
|
40
|
+
# identical by design, and not skills.
|
|
41
|
+
#
|
|
27
42
|
# Usage: lint-shared-worker-skills.sh [root ...]
|
|
28
43
|
# Default roots: core/workers core/packages (the SHIPPED hq-core scope —
|
|
29
|
-
# company
|
|
30
|
-
#
|
|
44
|
+
# company workers live under companies/<co>/ and are linted per-tenant; pass
|
|
45
|
+
# them explicitly to include them).
|
|
31
46
|
#
|
|
32
47
|
# Exit 0 + "OK:" line when clean; exit 1 + a report naming every offending group
|
|
33
48
|
# when not. Matches the loud-and-specific style of lint-skill-script-refs.sh.
|
|
@@ -54,11 +69,29 @@ content_hash() {
|
|
|
54
69
|
fi
|
|
55
70
|
}
|
|
56
71
|
|
|
72
|
+
# The ownership domain that OWNS a skill path — the boundary within which two
|
|
73
|
+
# byte-identical files are a real duplicate. Across domains, identical content
|
|
74
|
+
# is intentional (a pack vendoring a core skill, two packs shipping the same
|
|
75
|
+
# skill), so it must never be compared. See policy header above.
|
|
76
|
+
domain_of() {
|
|
77
|
+
local p="${1#./}" rest
|
|
78
|
+
case "$p" in
|
|
79
|
+
core/packages/*) rest="${p#core/packages/}"; printf 'core/packages/%s' "${rest%%/*}" ;;
|
|
80
|
+
companies/*) rest="${p#companies/}"; printf 'companies/%s' "${rest%%/*}" ;;
|
|
81
|
+
core/workers/*|core/workers) printf 'core/workers' ;;
|
|
82
|
+
# Arbitrary root (custom scans, tests): the top path segment is the domain.
|
|
83
|
+
*) printf '%s' "${p%%/*}" ;;
|
|
84
|
+
esac
|
|
85
|
+
}
|
|
86
|
+
|
|
57
87
|
# Collect skill entries: regular files AND symlinks named *.md under any
|
|
58
88
|
# .../skills/... path. -type l must be matched explicitly — a symlink is not a
|
|
59
89
|
# -type f, so a skills symlink would otherwise be invisible to the scan.
|
|
90
|
+
# EXCLUDED: any dot-directory component (`*/.*/*` — covers `.archive/`, `.git/`)
|
|
91
|
+
# and `._*` AppleDouble files; both are byte-identical by design and not skills.
|
|
60
92
|
mapfile -t entries < <(
|
|
61
|
-
find "${roots[@]}" \( -type f -o -type l \) -path '*/skills/*.md'
|
|
93
|
+
find "${roots[@]}" \( -type f -o -type l \) -path '*/skills/*.md' \
|
|
94
|
+
-not -path '*/.*/*' -not -name '._*' 2>/dev/null | sort
|
|
62
95
|
)
|
|
63
96
|
|
|
64
97
|
# Empty is clean — and guards `"${entries[@]}"` under `set -u` on bash 3.2
|
|
@@ -69,10 +102,13 @@ if [[ ${#entries[@]} -eq 0 ]]; then
|
|
|
69
102
|
fi
|
|
70
103
|
|
|
71
104
|
broken=()
|
|
72
|
-
# Parallel arrays keyed by content
|
|
73
|
-
# hash_regfiles[i]
|
|
74
|
-
#
|
|
75
|
-
#
|
|
105
|
+
# Parallel arrays keyed by "<domain>|<content-hash>": hash_keys[i] is that
|
|
106
|
+
# composite key, hash_regfiles[i] a newline-joined list of the NON-symlink files
|
|
107
|
+
# carrying it. Keying on domain AS WELL AS hash is what confines a duplicate
|
|
108
|
+
# finding to a single ownership tree — two identical files in different domains
|
|
109
|
+
# land in different buckets and are never flagged. Bash 3.2 (macOS) has no
|
|
110
|
+
# portable associative arrays, so a linear scan over parallel arrays keeps this
|
|
111
|
+
# runnable everywhere HQ runs.
|
|
76
112
|
hash_keys=()
|
|
77
113
|
hash_regfiles=()
|
|
78
114
|
|
|
@@ -94,12 +130,13 @@ for entry in "${entries[@]}"; do
|
|
|
94
130
|
fi
|
|
95
131
|
continue
|
|
96
132
|
fi
|
|
97
|
-
# Regular file:
|
|
98
|
-
# bucket are two copies of the same skill
|
|
99
|
-
|
|
100
|
-
|
|
133
|
+
# Regular file: bucket it by (ownership domain, byte content). Two regular
|
|
134
|
+
# files sharing a bucket are two copies of the same skill in the same tree —
|
|
135
|
+
# the drift hazard.
|
|
136
|
+
key="$(domain_of "$entry")|$(content_hash "$entry")"
|
|
137
|
+
idx="$(hash_index "$key")"
|
|
101
138
|
if [[ "$idx" == "-1" ]]; then
|
|
102
|
-
hash_keys+=("$
|
|
139
|
+
hash_keys+=("$key")
|
|
103
140
|
hash_regfiles+=("$entry")
|
|
104
141
|
else
|
|
105
142
|
hash_regfiles[$idx]="${hash_regfiles[$idx]}"$'\n'"$entry"
|
|
@@ -116,7 +153,8 @@ for i in "${!hash_keys[@]}"; do
|
|
|
116
153
|
echo "lint-shared-worker-skills: FAIL — duplicated worker skills (single-source these via _shared-skills/ + relative symlinks):" >&2
|
|
117
154
|
fi
|
|
118
155
|
findings=$((findings + 1))
|
|
119
|
-
|
|
156
|
+
domain="${hash_keys[$i]%%|*}"
|
|
157
|
+
echo " DUPLICATE in domain '${domain}' (identical content, ${count} copies — pick one canonical and symlink the rest):" >&2
|
|
120
158
|
printf ' %s\n' "$group" >&2
|
|
121
159
|
fi
|
|
122
160
|
done
|