@indigoai-us/hq-cli 5.305.0 → 5.307.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/CHANGELOG.md +13 -0
- package/assets/scaffold/core/scripts/audit-log.sh +384 -0
- package/assets/scaffold/core/scripts/git-pack-extension-check.sh +164 -0
- package/assets/scaffold/core/scripts/hq-pin.sh +118 -0
- package/assets/scaffold/core/scripts/lib/portable.sh +211 -0
- package/assets/scaffold/core/scripts/refresh-vault-access.sh +188 -0
- package/dist/command-catalog.generated.d.ts +54 -2
- package/dist/command-catalog.generated.js +66 -2
- package/dist/commands/core-audit-log-native.d.ts +9 -0
- package/dist/commands/core-audit-log-native.js +257 -0
- package/dist/commands/core-git-pack-extension-check-native.d.ts +22 -0
- package/dist/commands/core-git-pack-extension-check-native.js +190 -0
- package/dist/commands/core-native-utilities-flag.d.ts +4 -0
- package/dist/commands/core-native-utilities-flag.js +7 -0
- package/dist/commands/core-native-utilities.d.ts +28 -0
- package/dist/commands/core-native-utilities.js +52 -0
- package/dist/commands/core-pin-native.d.ts +14 -0
- package/dist/commands/core-pin-native.js +236 -0
- package/dist/commands/core-refresh-vault-access-native.d.ts +20 -0
- package/dist/commands/core-refresh-vault-access-native.js +229 -0
- package/dist/commands/core.js +15 -0
- package/dist/commands/daemon.js +24 -23
- package/dist/commands/dm.js +6 -1
- package/dist/commands/lanes.js +43 -1
- package/dist/lib/agent-kit/fallback.d.ts +0 -7
- package/dist/lib/agent-kit/fallback.js +4 -4
- package/dist/lib/agent-kit/inbox-state.d.ts +0 -2
- package/dist/lib/agent-kit/inbox-state.js +2 -2
- package/dist/lib/agent-kit/kit-config.d.ts +0 -5
- package/dist/lib/agent-kit/kit-config.js +5 -5
- package/dist/lib/agent-kit/log.d.ts +0 -1
- package/dist/lib/agent-kit/log.js +1 -1
- package/dist/lib/agent-kit/mcp/jsonrpc.d.ts +3 -12
- package/dist/lib/agent-kit/mcp/jsonrpc.js +4 -4
- package/dist/lib/agent-kit/mcp/tools.d.ts +0 -2
- package/dist/lib/agent-kit/mcp/tools.js +2 -2
- package/dist/lib/agent-kit/services.d.ts +0 -1
- package/dist/lib/agent-kit/services.js +1 -1
- package/dist/lib/checkpoint-ontology/apply.d.ts +0 -49
- package/dist/lib/checkpoint-ontology/apply.js +5 -5
- package/dist/lib/checkpoint-ontology/identity.d.ts +2 -1
- package/dist/lib/checkpoint-ontology/identity.js +1 -1
- package/dist/lib/checkpoint-ontology/multi-writer.d.ts +4 -9
- package/dist/lib/checkpoint-ontology/multi-writer.js +6 -6
- package/dist/lib/checkpoint-ontology/plan.d.ts +4 -17
- package/dist/lib/checkpoint-ontology/plan.js +5 -5
- package/dist/lib/checkpoint-ontology/queued-touches.d.ts +0 -3
- package/dist/lib/checkpoint-ontology/queued-touches.js +3 -3
- package/dist/lib/daemon/catalog.js +6 -2
- package/dist/lib/daemon/remote-control.d.ts +19 -8
- package/dist/lib/daemon/remote-control.js +62 -12
- package/dist/lib/daemon/supervisor.d.ts +2 -0
- package/dist/lib/daemon/supervisor.js +11 -0
- package/dist/lib/db/control-plane.js +6 -0
- package/dist/lib/deploy-apps.js +5 -0
- package/dist/startup-registration.js +9 -3
- package/dist/utils/install-tree-torn.d.ts +13 -6
- package/dist/utils/install-tree-torn.js +42 -16
- package/dist/utils/sentry-fingerprint.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# shellcheck shell=bash
|
|
2
|
+
# portable.sh — shared OS-portability helpers for hq-core shell scripts.
|
|
3
|
+
#
|
|
4
|
+
# SOURCED, never executed: . "$ROOT/core/scripts/lib/portable.sh"
|
|
5
|
+
# bash 3.2 safe; works under Linux, macOS, and Windows Git Bash with set -u.
|
|
6
|
+
#
|
|
7
|
+
# Canonicalizes good in-repo dual-implementation patterns:
|
|
8
|
+
# - work-mesh-lib.sh wm_file_mtime (numeric-probe dual stat)
|
|
9
|
+
# - archive-old-threads.sh dual stat / date -d | date -v
|
|
10
|
+
# - compute-checksums.sh Git Bash awareness
|
|
11
|
+
#
|
|
12
|
+
# JSON engines are NOT here — source core/scripts/hook-lib.sh (hq_json_get /
|
|
13
|
+
# hq_json_encode: jq first, then node). This file owns OS primitives + hard-fail
|
|
14
|
+
# jq install messaging only.
|
|
15
|
+
|
|
16
|
+
# portable_stat_mtime <path>
|
|
17
|
+
# Print mtime as epoch seconds. Uses BSD-form stat -f first, accepts only a
|
|
18
|
+
# strictly numeric result (GNU stat -f is filesystem mode and may print text),
|
|
19
|
+
# then falls through to GNU stat -c. Mirrors work-mesh-lib.sh:215-230.
|
|
20
|
+
# Returns 1 when both forms fail.
|
|
21
|
+
portable_stat_mtime() {
|
|
22
|
+
local f="${1:-}" value
|
|
23
|
+
[ -n "$f" ] || return 1
|
|
24
|
+
value="$(stat -f %m "$f" 2>/dev/null)" || value=""
|
|
25
|
+
case "$value" in
|
|
26
|
+
''|*[!0-9]*) ;;
|
|
27
|
+
*) printf '%s' "$value"; return 0 ;;
|
|
28
|
+
esac
|
|
29
|
+
value="$(stat -c %Y "$f" 2>/dev/null)" || value=""
|
|
30
|
+
case "$value" in
|
|
31
|
+
''|*[!0-9]*) return 1 ;;
|
|
32
|
+
*) printf '%s' "$value"; return 0 ;;
|
|
33
|
+
esac
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# portable_sed_inplace <sed-script> <file> [extra sed args...]
|
|
37
|
+
# In-place sed that works on both GNU sed (sed -i) and BSD sed (sed -i '').
|
|
38
|
+
portable_sed_inplace() {
|
|
39
|
+
local script="${1:-}"
|
|
40
|
+
local file="${2:-}"
|
|
41
|
+
shift 2 2>/dev/null || true
|
|
42
|
+
[ -n "$script" ] && [ -n "$file" ] || return 1
|
|
43
|
+
[ -f "$file" ] || return 1
|
|
44
|
+
# Prefer GNU form; fall back to BSD empty-suffix form.
|
|
45
|
+
if sed --version >/dev/null 2>&1; then
|
|
46
|
+
sed -i "$@" -e "$script" "$file"
|
|
47
|
+
else
|
|
48
|
+
sed -i '' "$@" -e "$script" "$file"
|
|
49
|
+
fi
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# portable_tmpdir
|
|
53
|
+
# Print a writable temp directory (no trailing slash). Prefer TMPDIR, else /tmp.
|
|
54
|
+
portable_tmpdir() {
|
|
55
|
+
local d="${TMPDIR:-/tmp}"
|
|
56
|
+
# Strip trailing slash except for root.
|
|
57
|
+
case "$d" in
|
|
58
|
+
/) printf '%s' "$d" ;;
|
|
59
|
+
*/) printf '%s' "${d%/}" ;;
|
|
60
|
+
*) printf '%s' "$d" ;;
|
|
61
|
+
esac
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# portable_date_epoch_to_iso <epoch_seconds>
|
|
65
|
+
# Convert epoch seconds to UTC ISO-8601 (YYYY-MM-DDTHH:MM:SSZ).
|
|
66
|
+
# Dual: GNU date -d @N / BSD date -r N.
|
|
67
|
+
portable_date_epoch_to_iso() {
|
|
68
|
+
local epoch="${1:-}"
|
|
69
|
+
case "$epoch" in
|
|
70
|
+
''|*[!0-9]*) return 1 ;;
|
|
71
|
+
esac
|
|
72
|
+
date -u -d "@${epoch}" +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null \
|
|
73
|
+
|| date -u -r "$epoch" +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null \
|
|
74
|
+
|| return 1
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
# portable_user
|
|
78
|
+
# Print a filename-safe user key from USER or USERNAME (Git Bash often lacks USER).
|
|
79
|
+
portable_user() {
|
|
80
|
+
local u="${USER:-${USERNAME:-unknown}}"
|
|
81
|
+
# shellcheck disable=SC2001
|
|
82
|
+
u="$(printf '%s' "$u" | sed 's/[^[:alnum:]_.-]/_/g')"
|
|
83
|
+
[ -n "$u" ] || u="unknown"
|
|
84
|
+
printf '%s' "$u"
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# portable_jq_install_hint
|
|
88
|
+
# Print multi-line per-OS jq install guidance to stdout.
|
|
89
|
+
portable_jq_install_hint() {
|
|
90
|
+
# Single multi-OS line so portability lint does not flag brew-only messages.
|
|
91
|
+
printf '%s\n' "Install jq: Windows: winget install jqlang.jq | choco install jq | scoop install jq; Linux: sudo apt install jq | sudo dnf install jq; macOS: brew install jq"
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# require_jq
|
|
95
|
+
# Return 0 if jq is on PATH. Otherwise print install guidance to stderr and
|
|
96
|
+
# return 1. Caller decides whether to die. Does not implement JSON parse.
|
|
97
|
+
require_jq() {
|
|
98
|
+
if command -v jq >/dev/null 2>&1; then
|
|
99
|
+
return 0
|
|
100
|
+
fi
|
|
101
|
+
printf 'jq is required but not installed.\n' >&2
|
|
102
|
+
portable_jq_install_hint >&2
|
|
103
|
+
return 1
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
# portable_native_path <path>
|
|
107
|
+
# Print a path a native (non-MSYS) Windows binary can open. Git Bash mktemp
|
|
108
|
+
# and $TMPDIR often yield /tmp/... which Node's hq.exe cannot read, so
|
|
109
|
+
# --body-file looks empty. cygpath -m produces C:/... mixed paths. On
|
|
110
|
+
# POSIX hosts this is identity. Empty input returns 1.
|
|
111
|
+
portable_native_path() {
|
|
112
|
+
local p="${1:-}"
|
|
113
|
+
[ -n "$p" ] || return 1
|
|
114
|
+
if command -v cygpath >/dev/null 2>&1; then
|
|
115
|
+
cygpath -m "$p" 2>/dev/null || printf '%s' "$p"
|
|
116
|
+
return 0
|
|
117
|
+
fi
|
|
118
|
+
printf '%s' "$p"
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
# portable_qmd_models_dir
|
|
122
|
+
# Print qmd's GGUF cache directory (no trailing slash). Override with
|
|
123
|
+
# QMD_MODELS_DIR. Otherwise XDG_CACHE_HOME/qmd/models, then
|
|
124
|
+
# HOME/.cache/qmd/models, then USERPROFILE/.cache/qmd/models (Windows).
|
|
125
|
+
portable_qmd_models_dir() {
|
|
126
|
+
local d
|
|
127
|
+
if [ -n "${QMD_MODELS_DIR:-}" ]; then
|
|
128
|
+
d="$QMD_MODELS_DIR"
|
|
129
|
+
elif [ -n "${XDG_CACHE_HOME:-}" ]; then
|
|
130
|
+
d="$XDG_CACHE_HOME/qmd/models"
|
|
131
|
+
elif [ -n "${HOME:-}" ]; then
|
|
132
|
+
d="$HOME/.cache/qmd/models"
|
|
133
|
+
elif [ -n "${USERPROFILE:-}" ]; then
|
|
134
|
+
d="$USERPROFILE/.cache/qmd/models"
|
|
135
|
+
if command -v cygpath >/dev/null 2>&1; then
|
|
136
|
+
d="$(cygpath -u "$d" 2>/dev/null || printf '%s' "$d")"
|
|
137
|
+
fi
|
|
138
|
+
else
|
|
139
|
+
return 1
|
|
140
|
+
fi
|
|
141
|
+
case "$d" in
|
|
142
|
+
*/) d="${d%/}" ;;
|
|
143
|
+
esac
|
|
144
|
+
printf '%s' "$d"
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
# portable_qmd_embed_model_ready
|
|
148
|
+
# Return 0 when a usable GGUF already sits in the qmd models dir so
|
|
149
|
+
# vsearch/query/embed will not start a multi-hundred-MB download. A file
|
|
150
|
+
# named by QMD_EMBED_MODEL (basename after the last /) counts; otherwise
|
|
151
|
+
# any *.gguf of at least 1 MiB counts. Missing dir or tiny placeholders
|
|
152
|
+
# return 1.
|
|
153
|
+
portable_qmd_embed_model_ready() {
|
|
154
|
+
local dir want f sz
|
|
155
|
+
dir="$(portable_qmd_models_dir)" || return 1
|
|
156
|
+
[ -d "$dir" ] || return 1
|
|
157
|
+
if [ -n "${QMD_EMBED_MODEL:-}" ]; then
|
|
158
|
+
want="${QMD_EMBED_MODEL##*/}"
|
|
159
|
+
if [ -n "$want" ] && [ -f "$dir/$want" ]; then
|
|
160
|
+
sz="$(wc -c < "$dir/$want" | tr -d '[:space:]')"
|
|
161
|
+
case "$sz" in
|
|
162
|
+
''|*[!0-9]*) ;;
|
|
163
|
+
*) [ "$sz" -ge 1048576 ] && return 0 ;;
|
|
164
|
+
esac
|
|
165
|
+
fi
|
|
166
|
+
fi
|
|
167
|
+
for f in "$dir"/*.gguf; do
|
|
168
|
+
[ -f "$f" ] || continue
|
|
169
|
+
sz="$(wc -c < "$f" | tr -d '[:space:]')"
|
|
170
|
+
case "$sz" in
|
|
171
|
+
''|*[!0-9]*) continue ;;
|
|
172
|
+
esac
|
|
173
|
+
[ "$sz" -ge 1048576 ] && return 0
|
|
174
|
+
done
|
|
175
|
+
return 1
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
# portable_qmd_cmd_would_download_model <command>
|
|
179
|
+
# Return 0 when a shell command would invoke qmd vsearch, query, embed, or
|
|
180
|
+
# pull — the subcommands that auto-download GGUF models on first use.
|
|
181
|
+
# First non-flag argument after a qmd token is the subcommand, so
|
|
182
|
+
# `qmd search "how to vsearch"` is NOT a match.
|
|
183
|
+
portable_qmd_cmd_would_download_model() {
|
|
184
|
+
local cmd="${1:-}"
|
|
185
|
+
[ -n "$cmd" ] || return 1
|
|
186
|
+
case "$cmd" in
|
|
187
|
+
*qmd*) ;;
|
|
188
|
+
*) return 1 ;;
|
|
189
|
+
esac
|
|
190
|
+
printf '%s\n' "$cmd" | awk '
|
|
191
|
+
BEGIN { found = 0 }
|
|
192
|
+
{
|
|
193
|
+
n = split($0, raw, /[[:space:];|&]+/)
|
|
194
|
+
for (i = 1; i <= n; i++) {
|
|
195
|
+
tok = raw[i]
|
|
196
|
+
if (tok == "") continue
|
|
197
|
+
base = tok
|
|
198
|
+
sub(/^.*\//, "", base)
|
|
199
|
+
if (base == "qmd" || base == "qmd.exe") {
|
|
200
|
+
j = i + 1
|
|
201
|
+
while (j <= n && raw[j] ~ /^-/) j++
|
|
202
|
+
if (j <= n && raw[j] ~ /^(vsearch|query|embed|pull)$/) {
|
|
203
|
+
found = 1
|
|
204
|
+
exit
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
END { exit found ? 0 : 1 }
|
|
210
|
+
'
|
|
211
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# hq-core: public
|
|
3
|
+
# refresh-vault-access.sh — build/refresh the local vault-access manifest that
|
|
4
|
+
# enforce-vault-write-access.sh (PreToolUse hook) reads.
|
|
5
|
+
#
|
|
6
|
+
# Output: <hqRoot>/.hq/vault-access.json
|
|
7
|
+
#
|
|
8
|
+
# {
|
|
9
|
+
# "version": 1,
|
|
10
|
+
# "generatedAt": "2026-01-01T00:00:00Z",
|
|
11
|
+
# "companies": {
|
|
12
|
+
# "<slug>": {
|
|
13
|
+
# "role": "owner|admin|member|guest|unknown",
|
|
14
|
+
# "grants": [ { "path": "reports/*", "permission": "read|write" } ]
|
|
15
|
+
# }
|
|
16
|
+
# }
|
|
17
|
+
# }
|
|
18
|
+
#
|
|
19
|
+
# Sources (best-effort, all via the hq CLI):
|
|
20
|
+
# - grants: `hq files shared-with-me` (explicit per-prefix grants)
|
|
21
|
+
# - role: `hq members --company <slug> list` matched against the caller's
|
|
22
|
+
# email (from `hq whoami`, override with HQ_VAULT_ACCESS_EMAIL)
|
|
23
|
+
#
|
|
24
|
+
# Fail-open by design: anything this script cannot determine is recorded as
|
|
25
|
+
# role "unknown" (the hook does not enforce unknown roles), and a company it
|
|
26
|
+
# cannot query at all is left out of the manifest entirely (the hook allows
|
|
27
|
+
# companies absent from the manifest). The server-side STS/ACL layer remains
|
|
28
|
+
# the authoritative security boundary — this manifest only powers the local
|
|
29
|
+
# early-warning block for read-only shares.
|
|
30
|
+
#
|
|
31
|
+
# Usage:
|
|
32
|
+
# bash core/scripts/refresh-vault-access.sh [--company <slug>]... [--root <hqRoot>]
|
|
33
|
+
#
|
|
34
|
+
# With no --company, refreshes every company that appears in the
|
|
35
|
+
# `hq files shared-with-me` cross-company roll-up.
|
|
36
|
+
|
|
37
|
+
set -uo pipefail
|
|
38
|
+
|
|
39
|
+
log() { printf 'refresh-vault-access: %s\n' "$*" >&2; }
|
|
40
|
+
|
|
41
|
+
ROOT=""
|
|
42
|
+
SLUGS=()
|
|
43
|
+
while [ $# -gt 0 ]; do
|
|
44
|
+
case "$1" in
|
|
45
|
+
--root)
|
|
46
|
+
ROOT="${2:-}"
|
|
47
|
+
shift 2 || { log "--root requires a value"; exit 1; }
|
|
48
|
+
;;
|
|
49
|
+
--company)
|
|
50
|
+
SLUGS[${#SLUGS[@]}]="${2:-}"
|
|
51
|
+
shift 2 || { log "--company requires a value"; exit 1; }
|
|
52
|
+
;;
|
|
53
|
+
-h|--help)
|
|
54
|
+
sed -n '2,33p' "$0" | sed 's/^# \{0,1\}//'
|
|
55
|
+
exit 0
|
|
56
|
+
;;
|
|
57
|
+
*)
|
|
58
|
+
log "unknown argument: $1"
|
|
59
|
+
exit 1
|
|
60
|
+
;;
|
|
61
|
+
esac
|
|
62
|
+
done
|
|
63
|
+
|
|
64
|
+
is_hq_root() { [ -n "${1:-}" ] && [ -d "${1%/}/core" ] && [ -d "${1%/}/.claude" ]; }
|
|
65
|
+
|
|
66
|
+
if [ -z "$ROOT" ]; then
|
|
67
|
+
if is_hq_root "${CLAUDE_PROJECT_DIR:-}"; then
|
|
68
|
+
ROOT="$CLAUDE_PROJECT_DIR"
|
|
69
|
+
else
|
|
70
|
+
dir="$PWD"
|
|
71
|
+
while [ -n "$dir" ] && [ "$dir" != "/" ]; do
|
|
72
|
+
if is_hq_root "$dir"; then ROOT="$dir"; break; fi
|
|
73
|
+
dir="$(dirname "$dir")"
|
|
74
|
+
done
|
|
75
|
+
fi
|
|
76
|
+
fi
|
|
77
|
+
if ! is_hq_root "$ROOT"; then
|
|
78
|
+
log "could not resolve the HQ root (pass --root <hqRoot>)"
|
|
79
|
+
exit 1
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
command -v jq >/dev/null 2>&1 || { log "jq is required"; exit 1; }
|
|
83
|
+
if ! command -v hq >/dev/null 2>&1; then
|
|
84
|
+
log "hq CLI not found — nothing refreshed (the write-access hook stays fail-open without a manifest)"
|
|
85
|
+
exit 0
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
strip_ansi() { sed -e 's/\x1b\[[0-9;]*m//g'; }
|
|
89
|
+
|
|
90
|
+
# ── caller email (for role lookup) ─────────────────────────────────────────
|
|
91
|
+
EMAIL="${HQ_VAULT_ACCESS_EMAIL:-}"
|
|
92
|
+
if [ -z "$EMAIL" ]; then
|
|
93
|
+
EMAIL="$(hq whoami 2>/dev/null | strip_ansi \
|
|
94
|
+
| grep -Eo '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}' \
|
|
95
|
+
| grep -v '@outposts\.' | head -1 || true)"
|
|
96
|
+
fi
|
|
97
|
+
[ -n "$EMAIL" ] || log "could not determine caller email — roles will be 'unknown' (hook will not enforce)"
|
|
98
|
+
|
|
99
|
+
# ── explicit grants via shared-with-me ─────────────────────────────────────
|
|
100
|
+
# Table columns: COMPANY PATH PERMISSION SOURCE (header + ─── separator).
|
|
101
|
+
fetch_grants_tsv() {
|
|
102
|
+
# $1 = optional slug filter; prints "slug<TAB>path<TAB>permission" rows.
|
|
103
|
+
local slug="${1:-}" out
|
|
104
|
+
if [ -n "$slug" ]; then
|
|
105
|
+
out="$(hq files shared-with-me --company "$slug" 2>/dev/null | strip_ansi)" || return 1
|
|
106
|
+
else
|
|
107
|
+
out="$(hq files shared-with-me 2>/dev/null | strip_ansi)" || return 1
|
|
108
|
+
fi
|
|
109
|
+
# hq-cli >= 5.142 renders a private-folder row as "foo/ (private folder)";
|
|
110
|
+
# drop the label so the PATH column stays the verbatim `foo/` pattern.
|
|
111
|
+
printf '%s\n' "$out" | awk '
|
|
112
|
+
{ sub(/ \(private folder\)/, "") }
|
|
113
|
+
/^COMPANY[[:space:]]/ { next }
|
|
114
|
+
/^─/ { next }
|
|
115
|
+
/^[[:space:]]*$/ { next }
|
|
116
|
+
/^Nothing is explicitly shared/ { next }
|
|
117
|
+
NF >= 3 {
|
|
118
|
+
perm = ""
|
|
119
|
+
if ($3 == "read" || $3 == "write" || $3 == "admin") perm = $3
|
|
120
|
+
else if (NF >= 4 && ($4 == "read" || $4 == "write" || $4 == "admin")) perm = $4
|
|
121
|
+
if (perm != "") printf "%s\t%s\t%s\n", $1, $2, perm
|
|
122
|
+
}'
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
# ── role lookup ────────────────────────────────────────────────────────────
|
|
126
|
+
fetch_role() {
|
|
127
|
+
# $1 = slug; prints role or "unknown". Never fails.
|
|
128
|
+
local slug="$1" out role=""
|
|
129
|
+
if [ -n "$EMAIL" ]; then
|
|
130
|
+
# --company is declared on the parent `members` group, so it goes first.
|
|
131
|
+
out="$(hq members --company "$slug" list 2>/dev/null | strip_ansi)" || out=""
|
|
132
|
+
if [ -n "$out" ]; then
|
|
133
|
+
role="$(printf '%s\n' "$out" | awk -v email="$EMAIL" '$1 == email { print $2; exit }')"
|
|
134
|
+
fi
|
|
135
|
+
fi
|
|
136
|
+
case "$role" in
|
|
137
|
+
owner|admin|member|guest) printf '%s' "$role" ;;
|
|
138
|
+
*) printf 'unknown' ;;
|
|
139
|
+
esac
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
GRANTS_TSV=""
|
|
143
|
+
if [ "${#SLUGS[@]}" -gt 0 ]; then
|
|
144
|
+
for slug in "${SLUGS[@]}"; do
|
|
145
|
+
rows="$(fetch_grants_tsv "$slug")" || { log "skipping $slug — shared-with-me query failed"; continue; }
|
|
146
|
+
GRANTS_TSV="${GRANTS_TSV}${rows}
|
|
147
|
+
"
|
|
148
|
+
done
|
|
149
|
+
else
|
|
150
|
+
GRANTS_TSV="$(fetch_grants_tsv)" || { log "shared-with-me roll-up failed — nothing refreshed"; exit 0; }
|
|
151
|
+
fi
|
|
152
|
+
|
|
153
|
+
# Companies to include = every slug present in the grant rows (plus any
|
|
154
|
+
# explicitly requested slugs, so a company with zero explicit grants still
|
|
155
|
+
# gets a role entry when asked for by name).
|
|
156
|
+
ALL_SLUGS="$(printf '%s\n' "$GRANTS_TSV" | awk -F'\t' 'NF { print $1 }' | sort -u)"
|
|
157
|
+
if [ "${#SLUGS[@]}" -gt 0 ]; then
|
|
158
|
+
ALL_SLUGS="$(printf '%s\n%s\n' "$ALL_SLUGS" "$(printf '%s\n' "${SLUGS[@]}")" | awk 'NF' | sort -u)"
|
|
159
|
+
fi
|
|
160
|
+
|
|
161
|
+
if [ -z "$ALL_SLUGS" ]; then
|
|
162
|
+
log "no explicit grants found — writing an empty manifest (hook stays fail-open everywhere)"
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
COMPANIES_JSON="{}"
|
|
166
|
+
while IFS= read -r slug; do
|
|
167
|
+
[ -n "$slug" ] || continue
|
|
168
|
+
role="$(fetch_role "$slug")"
|
|
169
|
+
grants_json="$(printf '%s\n' "$GRANTS_TSV" \
|
|
170
|
+
| awk -F'\t' -v s="$slug" '$1 == s { printf "%s\t%s\n", $2, $3 }' \
|
|
171
|
+
| jq -Rn '[inputs | split("\t") | select(length == 2) | {path: .[0], permission: .[1]}]')"
|
|
172
|
+
COMPANIES_JSON="$(printf '%s' "$COMPANIES_JSON" \
|
|
173
|
+
| jq --arg slug "$slug" --arg role "$role" --argjson grants "$grants_json" \
|
|
174
|
+
'. + {($slug): {role: $role, grants: $grants}}')"
|
|
175
|
+
done <<EOF
|
|
176
|
+
$ALL_SLUGS
|
|
177
|
+
EOF
|
|
178
|
+
|
|
179
|
+
mkdir -p "$ROOT/.hq"
|
|
180
|
+
TMP_OUT="$(mktemp "$ROOT/.hq/vault-access.json.XXXXXX")"
|
|
181
|
+
jq -n --argjson companies "$COMPANIES_JSON" \
|
|
182
|
+
--arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
183
|
+
'{version: 1, generatedAt: $ts, companies: $companies}' > "$TMP_OUT"
|
|
184
|
+
mv "$TMP_OUT" "$ROOT/.hq/vault-access.json"
|
|
185
|
+
|
|
186
|
+
N_COMPANIES="$(printf '%s\n' "$ALL_SLUGS" | awk 'NF' | wc -l | tr -d ' ')"
|
|
187
|
+
log "wrote .hq/vault-access.json ($N_COMPANIES companies, identity: ${EMAIL:-unknown})"
|
|
188
|
+
exit 0
|
|
@@ -5730,6 +5730,58 @@ export declare const COMMAND_CATALOG: readonly [{
|
|
|
5730
5730
|
readonly options: readonly [];
|
|
5731
5731
|
readonly subcommands: readonly [];
|
|
5732
5732
|
}];
|
|
5733
|
+
}, {
|
|
5734
|
+
readonly name: "audit-log";
|
|
5735
|
+
readonly description: "Append, query, or summarize the HQ audit log";
|
|
5736
|
+
readonly aliases: readonly [];
|
|
5737
|
+
readonly hidden: false;
|
|
5738
|
+
readonly usage: "[args...]";
|
|
5739
|
+
readonly arguments: readonly [{
|
|
5740
|
+
readonly name: "args";
|
|
5741
|
+
readonly required: false;
|
|
5742
|
+
readonly variadic: true;
|
|
5743
|
+
}];
|
|
5744
|
+
readonly options: readonly [];
|
|
5745
|
+
readonly subcommands: readonly [];
|
|
5746
|
+
}, {
|
|
5747
|
+
readonly name: "git-pack-extension-check";
|
|
5748
|
+
readonly description: "Find or repair extensionless Git pack files";
|
|
5749
|
+
readonly aliases: readonly [];
|
|
5750
|
+
readonly hidden: false;
|
|
5751
|
+
readonly usage: "[args...]";
|
|
5752
|
+
readonly arguments: readonly [{
|
|
5753
|
+
readonly name: "args";
|
|
5754
|
+
readonly required: false;
|
|
5755
|
+
readonly variadic: true;
|
|
5756
|
+
}];
|
|
5757
|
+
readonly options: readonly [];
|
|
5758
|
+
readonly subcommands: readonly [];
|
|
5759
|
+
}, {
|
|
5760
|
+
readonly name: "pin";
|
|
5761
|
+
readonly description: "Pin the current session to one goal";
|
|
5762
|
+
readonly aliases: readonly [];
|
|
5763
|
+
readonly hidden: false;
|
|
5764
|
+
readonly usage: "[args...]";
|
|
5765
|
+
readonly arguments: readonly [{
|
|
5766
|
+
readonly name: "args";
|
|
5767
|
+
readonly required: false;
|
|
5768
|
+
readonly variadic: true;
|
|
5769
|
+
}];
|
|
5770
|
+
readonly options: readonly [];
|
|
5771
|
+
readonly subcommands: readonly [];
|
|
5772
|
+
}, {
|
|
5773
|
+
readonly name: "refresh-vault-access";
|
|
5774
|
+
readonly description: "Refresh the local vault access manifest";
|
|
5775
|
+
readonly aliases: readonly [];
|
|
5776
|
+
readonly hidden: false;
|
|
5777
|
+
readonly usage: "[args...]";
|
|
5778
|
+
readonly arguments: readonly [{
|
|
5779
|
+
readonly name: "args";
|
|
5780
|
+
readonly required: false;
|
|
5781
|
+
readonly variadic: true;
|
|
5782
|
+
}];
|
|
5783
|
+
readonly options: readonly [];
|
|
5784
|
+
readonly subcommands: readonly [];
|
|
5733
5785
|
}, {
|
|
5734
5786
|
readonly name: "worktree-gc";
|
|
5735
5787
|
readonly description: "Safely collect old, preserved HQ worktrees";
|
|
@@ -9664,7 +9716,7 @@ export declare const COMMAND_CATALOG: readonly [{
|
|
|
9664
9716
|
readonly arguments: readonly [];
|
|
9665
9717
|
readonly options: readonly [{
|
|
9666
9718
|
readonly flags: "--claude <path>";
|
|
9667
|
-
readonly description: "claude binary";
|
|
9719
|
+
readonly description: "claude binary (default: the one installed for this user)";
|
|
9668
9720
|
}, {
|
|
9669
9721
|
readonly flags: "--name <name>";
|
|
9670
9722
|
readonly description: "remote-control session name";
|
|
@@ -9685,7 +9737,7 @@ export declare const COMMAND_CATALOG: readonly [{
|
|
|
9685
9737
|
readonly description: "the box's Codex runner script";
|
|
9686
9738
|
}, {
|
|
9687
9739
|
readonly flags: "--codex <path>";
|
|
9688
|
-
readonly description: "codex binary, watched for updates";
|
|
9740
|
+
readonly description: "codex binary, watched for updates (default: the one installed for this user)";
|
|
9689
9741
|
}];
|
|
9690
9742
|
readonly subcommands: readonly [];
|
|
9691
9743
|
}];
|
|
@@ -7384,6 +7384,70 @@ export const COMMAND_CATALOG = [
|
|
|
7384
7384
|
}
|
|
7385
7385
|
]
|
|
7386
7386
|
},
|
|
7387
|
+
{
|
|
7388
|
+
"name": "audit-log",
|
|
7389
|
+
"description": "Append, query, or summarize the HQ audit log",
|
|
7390
|
+
"aliases": [],
|
|
7391
|
+
"hidden": false,
|
|
7392
|
+
"usage": "[args...]",
|
|
7393
|
+
"arguments": [
|
|
7394
|
+
{
|
|
7395
|
+
"name": "args",
|
|
7396
|
+
"required": false,
|
|
7397
|
+
"variadic": true
|
|
7398
|
+
}
|
|
7399
|
+
],
|
|
7400
|
+
"options": [],
|
|
7401
|
+
"subcommands": []
|
|
7402
|
+
},
|
|
7403
|
+
{
|
|
7404
|
+
"name": "git-pack-extension-check",
|
|
7405
|
+
"description": "Find or repair extensionless Git pack files",
|
|
7406
|
+
"aliases": [],
|
|
7407
|
+
"hidden": false,
|
|
7408
|
+
"usage": "[args...]",
|
|
7409
|
+
"arguments": [
|
|
7410
|
+
{
|
|
7411
|
+
"name": "args",
|
|
7412
|
+
"required": false,
|
|
7413
|
+
"variadic": true
|
|
7414
|
+
}
|
|
7415
|
+
],
|
|
7416
|
+
"options": [],
|
|
7417
|
+
"subcommands": []
|
|
7418
|
+
},
|
|
7419
|
+
{
|
|
7420
|
+
"name": "pin",
|
|
7421
|
+
"description": "Pin the current session to one goal",
|
|
7422
|
+
"aliases": [],
|
|
7423
|
+
"hidden": false,
|
|
7424
|
+
"usage": "[args...]",
|
|
7425
|
+
"arguments": [
|
|
7426
|
+
{
|
|
7427
|
+
"name": "args",
|
|
7428
|
+
"required": false,
|
|
7429
|
+
"variadic": true
|
|
7430
|
+
}
|
|
7431
|
+
],
|
|
7432
|
+
"options": [],
|
|
7433
|
+
"subcommands": []
|
|
7434
|
+
},
|
|
7435
|
+
{
|
|
7436
|
+
"name": "refresh-vault-access",
|
|
7437
|
+
"description": "Refresh the local vault access manifest",
|
|
7438
|
+
"aliases": [],
|
|
7439
|
+
"hidden": false,
|
|
7440
|
+
"usage": "[args...]",
|
|
7441
|
+
"arguments": [
|
|
7442
|
+
{
|
|
7443
|
+
"name": "args",
|
|
7444
|
+
"required": false,
|
|
7445
|
+
"variadic": true
|
|
7446
|
+
}
|
|
7447
|
+
],
|
|
7448
|
+
"options": [],
|
|
7449
|
+
"subcommands": []
|
|
7450
|
+
},
|
|
7387
7451
|
{
|
|
7388
7452
|
"name": "worktree-gc",
|
|
7389
7453
|
"description": "Safely collect old, preserved HQ worktrees",
|
|
@@ -12457,7 +12521,7 @@ export const COMMAND_CATALOG = [
|
|
|
12457
12521
|
"options": [
|
|
12458
12522
|
{
|
|
12459
12523
|
"flags": "--claude <path>",
|
|
12460
|
-
"description": "claude binary"
|
|
12524
|
+
"description": "claude binary (default: the one installed for this user)"
|
|
12461
12525
|
},
|
|
12462
12526
|
{
|
|
12463
12527
|
"flags": "--name <name>",
|
|
@@ -12484,7 +12548,7 @@ export const COMMAND_CATALOG = [
|
|
|
12484
12548
|
},
|
|
12485
12549
|
{
|
|
12486
12550
|
"flags": "--codex <path>",
|
|
12487
|
-
"description": "codex binary, watched for updates"
|
|
12551
|
+
"description": "codex binary, watched for updates (default: the one installed for this user)"
|
|
12488
12552
|
}
|
|
12489
12553
|
],
|
|
12490
12554
|
"subcommands": []
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type UtilityContext, type UtilityOutput } from "./core-native-utilities.js";
|
|
2
|
+
import type { Command } from "commander";
|
|
3
|
+
export declare const AUDIT_LOG_ASSET = "core/scripts/audit-log.sh";
|
|
4
|
+
export declare const AUDIT_LOG_HELP = "audit-log.sh \u2014 HQ audit log utility\n\nSUBCOMMANDS:\n append Write one JSONL record to the audit log\n query Filter and display records\n summary Show aggregated table (project | worker | status)\n\nAPPEND FLAGS (--event and --project are required):\n --timestamp ISO8601 (auto-filled if omitted)\n --event task_started | phase_completed | task_completed | task_failed |\n project_started | project_completed |\n story_dispatched | story_completed | story_failed |\n pipeline_started | pipeline_completed | pipeline_paused |\n pipeline_failed | project_pr_created | project_reviewed |\n project_merged | project_deployed | project_canary_pass |\n project_canary_fail | gate_requested | gate_resolved\n --company Company slug (e.g. {company})\n --project Project slug (e.g. hq-observability)\n --story-id Story ID (e.g. US-001)\n --worker Worker name (e.g. backend-dev)\n --model Model name (e.g. sonnet)\n --action Short description of what happened\n --files Comma-separated file paths touched\n --result success | fail | skipped\n --duration-ms Wall-clock time in milliseconds (integer)\n --error Error message if result=fail\n --session-id Claude session/thread ID\n\nQUERY FLAGS:\n --project Filter by project slug\n --company Filter by company slug\n --worker Filter by worker name\n --since Filter by timestamp >= YYYY-MM-DD (or full ISO8601)\n --event Filter by event type\n\nEXAMPLES:\n # Append a task_started event\n core/scripts/audit-log.sh append \\\n --event task_started \\\n --project hq-observability \\\n --company {company} \\\n --story-id US-001 \\\n --worker backend-dev \\\n --model sonnet\n\n # Query all failures for a project\n core/scripts/audit-log.sh query --project hq-observability --event task_failed\n\n # Query since a date\n core/scripts/audit-log.sh query --since 2026-03-01\n\n # Show summary table\n core/scripts/audit-log.sh summary\n\nLOG FILE:\n workspace/metrics/audit-log.jsonl\n";
|
|
5
|
+
type AuditDeps = Pick<UtilityContext, "root" | "now">;
|
|
6
|
+
export declare function runAuditLog(args: string[], deps: AuditDeps): UtilityOutput;
|
|
7
|
+
export declare function registerCoreAuditLogNative(core: Command): void;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=core-audit-log-native.d.ts.map
|