@indigoai-us/hq-cli 5.345.114 → 5.345.116
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/hq-delegate-send.sh +5 -1
- package/dist/commands/bot-jobs.d.ts +1 -11
- package/dist/commands/bot-jobs.js +13 -34
- package/dist/commands/core-audit-log-native.js +1 -1
- package/dist/commands/core-checkpoint-native.d.ts +27 -0
- package/dist/commands/core-checkpoint-native.js +85 -2
- package/dist/commands/core-dm-bind-native.js +1 -1
- package/dist/commands/core-git-pack-extension-check-native.js +1 -1
- package/dist/commands/core-job-native-utils.d.ts +2 -2
- package/dist/commands/core-job-native-utils.js +3 -11
- package/dist/commands/core-job-notify-native.js +1 -2
- package/dist/commands/core-job-probe-native.d.ts +2 -3
- package/dist/commands/core-job-probe-native.js +14 -22
- package/dist/commands/core-job-remediate-native.js +1 -2
- package/dist/commands/core-job-run-native.js +58 -54
- package/dist/commands/core-jobs-native.d.ts +1 -3
- package/dist/commands/core-jobs-native.js +16 -271
- package/dist/commands/core-jobs-schedule.d.ts +7 -0
- package/dist/commands/core-jobs-schedule.js +243 -0
- package/dist/commands/core-native-utilities.d.ts +2 -3
- package/dist/commands/core-native-utilities.js +2 -19
- package/dist/commands/core-pin-native.js +1 -1
- package/dist/commands/core-refresh-vault-access-native.js +1 -1
- package/dist/commands/core-resolve-company-command.js +2 -17
- package/dist/commands/core-work-mesh-bind-trusted-native.js +1 -1
- package/dist/commands/core.js +1 -17
- package/dist/fast-scaffold.d.ts +1 -1
- package/dist/fast-scaffold.js +0 -38
- package/dist/lib/daemon/catalog.d.ts +0 -2
- package/dist/lib/daemon/catalog.js +3 -6
- package/dist/lib/daemon/run.js +0 -7
- package/dist/lib/scan-packages/index.js +6 -0
- package/dist/lib/workers-registry/index.d.ts +16 -0
- package/dist/lib/workers-registry/index.js +1 -1
- package/dist/utils/resident-package-preload.js +2 -7
- package/package.json +1 -1
- package/assets/scaffold/core/scripts/audit-log.sh +0 -384
- package/assets/scaffold/core/scripts/git-pack-extension-check.sh +0 -164
- package/assets/scaffold/core/scripts/hq-dm-bind.sh +0 -590
- package/assets/scaffold/core/scripts/hq-job-notify.sh +0 -389
- package/assets/scaffold/core/scripts/hq-job-probe.sh +0 -865
- package/assets/scaffold/core/scripts/hq-job-remediate.sh +0 -359
- package/assets/scaffold/core/scripts/hq-job-run.sh +0 -1025
- package/assets/scaffold/core/scripts/hq-pin.sh +0 -118
- package/assets/scaffold/core/scripts/jobs-schedule-parse.sh +0 -310
- package/assets/scaffold/core/scripts/jobs-validate.sh +0 -482
- package/assets/scaffold/core/scripts/outpost-jobs-reconcile.sh +0 -836
- package/assets/scaffold/core/scripts/refresh-vault-access.sh +0 -188
- package/assets/scaffold/core/scripts/resolve-company.sh +0 -331
- package/assets/scaffold/core/scripts/work-mesh-live-bind-trusted.sh +0 -184
- package/dist/commands/core-job-post-exit-assets.d.ts +0 -8
- package/dist/commands/core-job-post-exit-assets.js +0 -37
- package/dist/commands/core-native-jobs-flag.d.ts +0 -4
- package/dist/commands/core-native-jobs-flag.js +0 -7
- package/dist/commands/core-native-utilities-flag.d.ts +0 -4
- package/dist/commands/core-native-utilities-flag.js +0 -7
|
@@ -42,7 +42,7 @@ export const RESIDENT_PACKAGE_MODULES = {
|
|
|
42
42
|
"bot-logs-follow": [],
|
|
43
43
|
mcp: ["../lib/mcp/tools.js", "../lib/mcp/prompts.js", "../lib/anywhere-person-setting.js", "../utils/cognito-session.js", "@indigoai-us/hq-cloud", "../sentry.js", "../lib/doctor/client-health-reason-codes-flag.js", "@indigoai-us/hq-flags-client"],
|
|
44
44
|
childWrapper: ["../main.js", "../lib/service-manager/startup-migration.js", "../commands/storage-gate.js", "../lib/storage-feature-flag.js"],
|
|
45
|
-
coreJobRun: [
|
|
45
|
+
coreJobRun: [],
|
|
46
46
|
"daemon-call": ["../lib/daemon/protocol.js"],
|
|
47
47
|
daemon: [
|
|
48
48
|
"../sentry.js",
|
|
@@ -204,12 +204,7 @@ const LOADERS = {
|
|
|
204
204
|
() => import("../commands/storage-gate.js"),
|
|
205
205
|
() => import("../lib/storage-feature-flag.js"),
|
|
206
206
|
],
|
|
207
|
-
coreJobRun: [
|
|
208
|
-
() => import("../commands/core-native-jobs-flag.js"),
|
|
209
|
-
() => import("../commands/core-native-family-flag.js"),
|
|
210
|
-
() => import("../lib/flag-registry.js"),
|
|
211
|
-
() => import("../lib/flag-snapshot-file.js"),
|
|
212
|
-
],
|
|
207
|
+
coreJobRun: [],
|
|
213
208
|
"daemon-call": [
|
|
214
209
|
() => import("../lib/daemon/protocol.js"),
|
|
215
210
|
],
|
package/package.json
CHANGED
|
@@ -1,384 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# =============================================================================
|
|
3
|
-
# audit-log.sh — Structured audit log utility for HQ
|
|
4
|
-
#
|
|
5
|
-
# Schema fields: timestamp, event, company, project, story_id, worker, model,
|
|
6
|
-
# action, files_touched, result, duration_ms, error, session_id
|
|
7
|
-
#
|
|
8
|
-
# Usage:
|
|
9
|
-
# core/scripts/audit-log.sh append --event task_started --project my-project [fields...]
|
|
10
|
-
# core/scripts/audit-log.sh query [--project X] [--company X] [--worker X] [--since X] [--event X]
|
|
11
|
-
# core/scripts/audit-log.sh summary
|
|
12
|
-
#
|
|
13
|
-
# Events: task_started | phase_completed | task_completed | task_failed |
|
|
14
|
-
# project_started | project_completed |
|
|
15
|
-
# story_dispatched | story_completed | story_failed |
|
|
16
|
-
# pipeline_started | pipeline_completed | pipeline_paused | pipeline_failed |
|
|
17
|
-
# project_pr_created | project_reviewed | project_merged | project_deployed |
|
|
18
|
-
# project_canary_pass | project_canary_fail |
|
|
19
|
-
# gate_requested | gate_resolved
|
|
20
|
-
# Results: success | fail | skipped
|
|
21
|
-
# =============================================================================
|
|
22
|
-
|
|
23
|
-
set -euo pipefail
|
|
24
|
-
|
|
25
|
-
HQ_ROOT="${HQ_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
|
|
26
|
-
# shellcheck source=core/scripts/lib/portable.sh
|
|
27
|
-
. "$HQ_ROOT/core/scripts/lib/portable.sh"
|
|
28
|
-
AUDIT_LOG="$HQ_ROOT/workspace/metrics/audit-log.jsonl"
|
|
29
|
-
|
|
30
|
-
VALID_EVENTS="task_started phase_completed task_completed task_failed project_started project_completed story_dispatched story_completed story_failed pipeline_started pipeline_completed pipeline_paused pipeline_failed project_pr_created project_reviewed project_merged project_deployed project_canary_pass project_canary_fail gate_requested gate_resolved"
|
|
31
|
-
VALID_RESULTS="success fail skipped"
|
|
32
|
-
|
|
33
|
-
# ---------------------------------------------------------------------------
|
|
34
|
-
# helpers
|
|
35
|
-
# ---------------------------------------------------------------------------
|
|
36
|
-
|
|
37
|
-
die() { echo "ERROR: $*" >&2; exit 1; }
|
|
38
|
-
|
|
39
|
-
# require_jq comes from portable.sh (multi-OS install guidance).
|
|
40
|
-
|
|
41
|
-
iso_now() {
|
|
42
|
-
date -u +"%Y-%m-%dT%H:%M:%SZ"
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
contains() {
|
|
46
|
-
local needle="$1" haystack="$2"
|
|
47
|
-
[[ " $haystack " == *" $needle "* ]]
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
# ---------------------------------------------------------------------------
|
|
51
|
-
# append subcommand
|
|
52
|
-
# ---------------------------------------------------------------------------
|
|
53
|
-
# Usage:
|
|
54
|
-
# audit-log.sh append \
|
|
55
|
-
# --event task_started \
|
|
56
|
-
# --project hq-observability \
|
|
57
|
-
# [--company {company}] \
|
|
58
|
-
# [--story-id US-001] \
|
|
59
|
-
# [--worker backend-dev] \
|
|
60
|
-
# [--model sonnet] \
|
|
61
|
-
# [--action "Scaffold schema"] \
|
|
62
|
-
# [--files "core/scripts/audit-log.sh,workspace/metrics/audit-log.jsonl"] \
|
|
63
|
-
# [--result success] \
|
|
64
|
-
# [--duration-ms 1234] \
|
|
65
|
-
# [--error "message"] \
|
|
66
|
-
# [--session-id abc123]
|
|
67
|
-
# ---------------------------------------------------------------------------
|
|
68
|
-
cmd_append() {
|
|
69
|
-
require_jq
|
|
70
|
-
|
|
71
|
-
local timestamp="" event="" company="" project="" story_id="" worker=""
|
|
72
|
-
local model="" action="" files_touched="" result="" duration_ms="" error="" session_id=""
|
|
73
|
-
|
|
74
|
-
while [[ $# -gt 0 ]]; do
|
|
75
|
-
case "$1" in
|
|
76
|
-
--timestamp) timestamp="$2"; shift 2 ;;
|
|
77
|
-
--event) event="$2"; shift 2 ;;
|
|
78
|
-
--company) company="$2"; shift 2 ;;
|
|
79
|
-
--project) project="$2"; shift 2 ;;
|
|
80
|
-
--story-id) story_id="$2"; shift 2 ;;
|
|
81
|
-
--worker) worker="$2"; shift 2 ;;
|
|
82
|
-
--model) model="$2"; shift 2 ;;
|
|
83
|
-
--action) action="$2"; shift 2 ;;
|
|
84
|
-
--files) files_touched="$2"; shift 2 ;;
|
|
85
|
-
--result) result="$2"; shift 2 ;;
|
|
86
|
-
--duration-ms) duration_ms="$2"; shift 2 ;;
|
|
87
|
-
--error) error="$2"; shift 2 ;;
|
|
88
|
-
--session-id) session_id="$2"; shift 2 ;;
|
|
89
|
-
*) die "Unknown flag: $1" ;;
|
|
90
|
-
esac
|
|
91
|
-
done
|
|
92
|
-
|
|
93
|
-
# --- required field validation ---
|
|
94
|
-
[[ -n "$event" ]] || die "Missing required field: --event"
|
|
95
|
-
[[ -n "$project" ]] || die "Missing required field: --project"
|
|
96
|
-
|
|
97
|
-
# validate event value
|
|
98
|
-
contains "$event" "$VALID_EVENTS" || die "Invalid event '$event'. Must be one of: $VALID_EVENTS"
|
|
99
|
-
|
|
100
|
-
# validate result if provided
|
|
101
|
-
if [[ -n "$result" ]]; then
|
|
102
|
-
contains "$result" "$VALID_RESULTS" || die "Invalid result '$result'. Must be one of: $VALID_RESULTS"
|
|
103
|
-
fi
|
|
104
|
-
|
|
105
|
-
# validate duration_ms is numeric if provided
|
|
106
|
-
if [[ -n "$duration_ms" ]]; then
|
|
107
|
-
[[ "$duration_ms" =~ ^[0-9]+$ ]] || die "--duration-ms must be a non-negative integer"
|
|
108
|
-
fi
|
|
109
|
-
|
|
110
|
-
# auto-fill timestamp
|
|
111
|
-
[[ -n "$timestamp" ]] || timestamp="$(iso_now)"
|
|
112
|
-
|
|
113
|
-
# --- build files_touched array ---
|
|
114
|
-
# Input: comma-separated string → JSON array
|
|
115
|
-
local files_json="[]"
|
|
116
|
-
if [[ -n "$files_touched" ]]; then
|
|
117
|
-
files_json="$(echo "$files_touched" | jq -Rc 'split(",")')"
|
|
118
|
-
fi
|
|
119
|
-
|
|
120
|
-
# --- build JSON line ---
|
|
121
|
-
local entry
|
|
122
|
-
entry="$(jq -cn \
|
|
123
|
-
--arg ts "$timestamp" \
|
|
124
|
-
--arg event "$event" \
|
|
125
|
-
--arg company "$company" \
|
|
126
|
-
--arg project "$project" \
|
|
127
|
-
--arg story_id "$story_id" \
|
|
128
|
-
--arg worker "$worker" \
|
|
129
|
-
--arg model "$model" \
|
|
130
|
-
--arg action "$action" \
|
|
131
|
-
--argjson files "$files_json" \
|
|
132
|
-
--arg result "$result" \
|
|
133
|
-
--arg dur "$duration_ms" \
|
|
134
|
-
--arg error "$error" \
|
|
135
|
-
--arg session "$session_id" \
|
|
136
|
-
'{
|
|
137
|
-
timestamp: $ts,
|
|
138
|
-
event: $event,
|
|
139
|
-
company: (if $company != "" then $company else null end),
|
|
140
|
-
project: $project,
|
|
141
|
-
story_id: (if $story_id != "" then $story_id else null end),
|
|
142
|
-
worker: (if $worker != "" then $worker else null end),
|
|
143
|
-
model: (if $model != "" then $model else null end),
|
|
144
|
-
action: (if $action != "" then $action else null end),
|
|
145
|
-
files_touched: $files,
|
|
146
|
-
result: (if $result != "" then $result else null end),
|
|
147
|
-
duration_ms: (if $dur != "" then ($dur | tonumber) else null end),
|
|
148
|
-
error: (if $error != "" then $error else null end),
|
|
149
|
-
session_id: (if $session != "" then $session else null end)
|
|
150
|
-
} | with_entries(select(.value != null and .value != []))'
|
|
151
|
-
)"
|
|
152
|
-
|
|
153
|
-
mkdir -p "$(dirname "$AUDIT_LOG")"
|
|
154
|
-
echo "$entry" >> "$AUDIT_LOG"
|
|
155
|
-
echo "Appended to $AUDIT_LOG"
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
# ---------------------------------------------------------------------------
|
|
159
|
-
# query subcommand
|
|
160
|
-
# ---------------------------------------------------------------------------
|
|
161
|
-
# Usage:
|
|
162
|
-
# audit-log.sh query [--project X] [--company X] [--worker X] [--since YYYY-MM-DD] [--event X]
|
|
163
|
-
# ---------------------------------------------------------------------------
|
|
164
|
-
cmd_query() {
|
|
165
|
-
require_jq
|
|
166
|
-
|
|
167
|
-
local filter_project="" filter_company="" filter_worker="" filter_since="" filter_event=""
|
|
168
|
-
|
|
169
|
-
while [[ $# -gt 0 ]]; do
|
|
170
|
-
case "$1" in
|
|
171
|
-
--project) filter_project="$2"; shift 2 ;;
|
|
172
|
-
--company) filter_company="$2"; shift 2 ;;
|
|
173
|
-
--worker) filter_worker="$2"; shift 2 ;;
|
|
174
|
-
--since) filter_since="$2"; shift 2 ;;
|
|
175
|
-
--event) filter_event="$2"; shift 2 ;;
|
|
176
|
-
*) die "Unknown flag: $1" ;;
|
|
177
|
-
esac
|
|
178
|
-
done
|
|
179
|
-
|
|
180
|
-
if [[ ! -f "$AUDIT_LOG" ]]; then
|
|
181
|
-
echo "No audit log found at $AUDIT_LOG" >&2
|
|
182
|
-
exit 0
|
|
183
|
-
fi
|
|
184
|
-
|
|
185
|
-
# Build jq args + filter chain (parameterized to prevent filter injection)
|
|
186
|
-
local jq_args=()
|
|
187
|
-
local jq_filter="."
|
|
188
|
-
|
|
189
|
-
if [[ -n "$filter_project" ]]; then
|
|
190
|
-
jq_args+=(--arg fp "$filter_project")
|
|
191
|
-
jq_filter+=' | select(.project == $fp)'
|
|
192
|
-
fi
|
|
193
|
-
if [[ -n "$filter_company" ]]; then
|
|
194
|
-
jq_args+=(--arg fc "$filter_company")
|
|
195
|
-
jq_filter+=' | select(.company == $fc)'
|
|
196
|
-
fi
|
|
197
|
-
if [[ -n "$filter_worker" ]]; then
|
|
198
|
-
jq_args+=(--arg fw "$filter_worker")
|
|
199
|
-
jq_filter+=' | select(.worker == $fw)'
|
|
200
|
-
fi
|
|
201
|
-
if [[ -n "$filter_event" ]]; then
|
|
202
|
-
jq_args+=(--arg fe "$filter_event")
|
|
203
|
-
jq_filter+=' | select(.event == $fe)'
|
|
204
|
-
fi
|
|
205
|
-
if [[ -n "$filter_since" ]]; then
|
|
206
|
-
jq_args+=(--arg fs "$filter_since")
|
|
207
|
-
jq_filter+=' | select(.timestamp >= $fs)'
|
|
208
|
-
fi
|
|
209
|
-
|
|
210
|
-
local count
|
|
211
|
-
count=$(jq -r "${jq_args[@]}" "$jq_filter" "$AUDIT_LOG" 2>/dev/null | jq -s 'length')
|
|
212
|
-
|
|
213
|
-
jq -r "${jq_args[@]}" "$jq_filter" "$AUDIT_LOG" 2>/dev/null | jq -s '.'
|
|
214
|
-
echo "--- $count record(s) matched ---" >&2
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
# ---------------------------------------------------------------------------
|
|
218
|
-
# summary subcommand
|
|
219
|
-
# ---------------------------------------------------------------------------
|
|
220
|
-
# Outputs table: project | stories | phases | failures | last_activity
|
|
221
|
-
# ---------------------------------------------------------------------------
|
|
222
|
-
cmd_summary() {
|
|
223
|
-
require_jq
|
|
224
|
-
|
|
225
|
-
if [[ ! -f "$AUDIT_LOG" ]]; then
|
|
226
|
-
echo "No audit log found at $AUDIT_LOG" >&2
|
|
227
|
-
exit 0
|
|
228
|
-
fi
|
|
229
|
-
|
|
230
|
-
local line_count
|
|
231
|
-
line_count=$(wc -l < "$AUDIT_LOG" | tr -d ' ')
|
|
232
|
-
|
|
233
|
-
if [[ "$line_count" -eq 0 ]]; then
|
|
234
|
-
echo "Audit log is empty — no records to summarize."
|
|
235
|
-
exit 0
|
|
236
|
-
fi
|
|
237
|
-
|
|
238
|
-
echo ""
|
|
239
|
-
echo "=== Audit Log Summary ==="
|
|
240
|
-
echo ""
|
|
241
|
-
|
|
242
|
-
# Per-project breakdown
|
|
243
|
-
echo "--- By Project ---"
|
|
244
|
-
printf "%-40s %8s %8s %8s %8s %-26s\n" \
|
|
245
|
-
"PROJECT" "STORIES" "PHASES" "FAILURES" "SKIPPED" "LAST_ACTIVITY"
|
|
246
|
-
printf "%-40s %8s %8s %8s %8s %-26s\n" \
|
|
247
|
-
"$(printf '%0.s-' {1..40})" "--------" "--------" "--------" "--------" "$(printf '%0.s-' {1..26})"
|
|
248
|
-
|
|
249
|
-
jq -rs '
|
|
250
|
-
group_by(.project) |
|
|
251
|
-
.[] |
|
|
252
|
-
{
|
|
253
|
-
project: .[0].project,
|
|
254
|
-
stories: (map(select(.event == "task_completed" or .event == "task_failed")) | length),
|
|
255
|
-
phases: (map(select(.event == "phase_completed")) | length),
|
|
256
|
-
failures: (map(select(.result == "fail" or .event == "task_failed")) | length),
|
|
257
|
-
skipped: (map(select(.result == "skipped")) | length),
|
|
258
|
-
last_activity: (sort_by(.timestamp) | last | .timestamp)
|
|
259
|
-
}
|
|
260
|
-
' "$AUDIT_LOG" | jq -r '
|
|
261
|
-
"\(.project // "unknown")\t\(.stories)\t\(.phases)\t\(.failures)\t\(.skipped)\t\(.last_activity // "-")"
|
|
262
|
-
' | while IFS=$'\t' read -r proj stories phases failures skipped last; do
|
|
263
|
-
printf "%-40s %8s %8s %8s %8s %-26s\n" \
|
|
264
|
-
"$proj" "$stories" "$phases" "$failures" "$skipped" "$last"
|
|
265
|
-
done
|
|
266
|
-
|
|
267
|
-
echo ""
|
|
268
|
-
|
|
269
|
-
# Per-worker breakdown
|
|
270
|
-
echo "--- By Worker ---"
|
|
271
|
-
printf "%-30s %8s %8s %-10s\n" "WORKER" "TASKS" "FAILURES" "SUCCESS_RATE"
|
|
272
|
-
printf "%-30s %8s %8s %-10s\n" \
|
|
273
|
-
"$(printf '%0.s-' {1..30})" "--------" "--------" "----------"
|
|
274
|
-
|
|
275
|
-
jq -rs '
|
|
276
|
-
map(select(.worker != null)) |
|
|
277
|
-
group_by(.worker) |
|
|
278
|
-
.[] |
|
|
279
|
-
{
|
|
280
|
-
worker: .[0].worker,
|
|
281
|
-
tasks: (map(select(.event == "task_completed" or .event == "task_failed")) | length),
|
|
282
|
-
failures: (map(select(.result == "fail" or .event == "task_failed")) | length)
|
|
283
|
-
} |
|
|
284
|
-
. + {
|
|
285
|
-
rate: (if .tasks > 0 then (((.tasks - .failures) / .tasks * 100) | round | tostring) + "%" else "n/a" end)
|
|
286
|
-
}
|
|
287
|
-
' "$AUDIT_LOG" | jq -r '
|
|
288
|
-
"\(.worker)\t\(.tasks)\t\(.failures)\t\(.rate)"
|
|
289
|
-
' | while IFS=$'\t' read -r worker tasks failures rate; do
|
|
290
|
-
printf "%-30s %8s %8s %-10s\n" "$worker" "$tasks" "$failures" "$rate"
|
|
291
|
-
done
|
|
292
|
-
|
|
293
|
-
echo ""
|
|
294
|
-
|
|
295
|
-
# Overall stats
|
|
296
|
-
local total_events total_tasks total_failures
|
|
297
|
-
total_events=$(wc -l < "$AUDIT_LOG" | tr -d ' ')
|
|
298
|
-
total_tasks=$(jq -rs 'map(select(.event == "task_completed" or .event == "task_failed")) | length' "$AUDIT_LOG")
|
|
299
|
-
total_failures=$(jq -rs 'map(select(.result == "fail" or .event == "task_failed")) | length' "$AUDIT_LOG")
|
|
300
|
-
|
|
301
|
-
echo "--- Totals ---"
|
|
302
|
-
echo " Total events: $total_events"
|
|
303
|
-
echo " Total tasks: $total_tasks"
|
|
304
|
-
echo " Total failures: $total_failures"
|
|
305
|
-
echo ""
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
# ---------------------------------------------------------------------------
|
|
309
|
-
# help
|
|
310
|
-
# ---------------------------------------------------------------------------
|
|
311
|
-
cmd_help() {
|
|
312
|
-
cat <<'EOF'
|
|
313
|
-
audit-log.sh — HQ audit log utility
|
|
314
|
-
|
|
315
|
-
SUBCOMMANDS:
|
|
316
|
-
append Write one JSONL record to the audit log
|
|
317
|
-
query Filter and display records
|
|
318
|
-
summary Show aggregated table (project | worker | status)
|
|
319
|
-
|
|
320
|
-
APPEND FLAGS (--event and --project are required):
|
|
321
|
-
--timestamp ISO8601 (auto-filled if omitted)
|
|
322
|
-
--event task_started | phase_completed | task_completed | task_failed |
|
|
323
|
-
project_started | project_completed |
|
|
324
|
-
story_dispatched | story_completed | story_failed |
|
|
325
|
-
pipeline_started | pipeline_completed | pipeline_paused |
|
|
326
|
-
pipeline_failed | project_pr_created | project_reviewed |
|
|
327
|
-
project_merged | project_deployed | project_canary_pass |
|
|
328
|
-
project_canary_fail | gate_requested | gate_resolved
|
|
329
|
-
--company Company slug (e.g. {company})
|
|
330
|
-
--project Project slug (e.g. hq-observability)
|
|
331
|
-
--story-id Story ID (e.g. US-001)
|
|
332
|
-
--worker Worker name (e.g. backend-dev)
|
|
333
|
-
--model Model name (e.g. sonnet)
|
|
334
|
-
--action Short description of what happened
|
|
335
|
-
--files Comma-separated file paths touched
|
|
336
|
-
--result success | fail | skipped
|
|
337
|
-
--duration-ms Wall-clock time in milliseconds (integer)
|
|
338
|
-
--error Error message if result=fail
|
|
339
|
-
--session-id Claude session/thread ID
|
|
340
|
-
|
|
341
|
-
QUERY FLAGS:
|
|
342
|
-
--project Filter by project slug
|
|
343
|
-
--company Filter by company slug
|
|
344
|
-
--worker Filter by worker name
|
|
345
|
-
--since Filter by timestamp >= YYYY-MM-DD (or full ISO8601)
|
|
346
|
-
--event Filter by event type
|
|
347
|
-
|
|
348
|
-
EXAMPLES:
|
|
349
|
-
# Append a task_started event
|
|
350
|
-
core/scripts/audit-log.sh append \
|
|
351
|
-
--event task_started \
|
|
352
|
-
--project hq-observability \
|
|
353
|
-
--company {company} \
|
|
354
|
-
--story-id US-001 \
|
|
355
|
-
--worker backend-dev \
|
|
356
|
-
--model sonnet
|
|
357
|
-
|
|
358
|
-
# Query all failures for a project
|
|
359
|
-
core/scripts/audit-log.sh query --project hq-observability --event task_failed
|
|
360
|
-
|
|
361
|
-
# Query since a date
|
|
362
|
-
core/scripts/audit-log.sh query --since 2026-03-01
|
|
363
|
-
|
|
364
|
-
# Show summary table
|
|
365
|
-
core/scripts/audit-log.sh summary
|
|
366
|
-
|
|
367
|
-
LOG FILE:
|
|
368
|
-
workspace/metrics/audit-log.jsonl
|
|
369
|
-
EOF
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
# ---------------------------------------------------------------------------
|
|
373
|
-
# dispatch
|
|
374
|
-
# ---------------------------------------------------------------------------
|
|
375
|
-
SUBCOMMAND="${1:-help}"
|
|
376
|
-
shift || true
|
|
377
|
-
|
|
378
|
-
case "$SUBCOMMAND" in
|
|
379
|
-
append) cmd_append "$@" ;;
|
|
380
|
-
query) cmd_query "$@" ;;
|
|
381
|
-
summary) cmd_summary "$@" ;;
|
|
382
|
-
help|--help|-h) cmd_help ;;
|
|
383
|
-
*) die "Unknown subcommand '$SUBCOMMAND'. Use: append | query | summary | help" ;;
|
|
384
|
-
esac
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# hq-core: public
|
|
3
|
-
# git-pack-extension-check.sh — find pack files that have lost their extension.
|
|
4
|
-
#
|
|
5
|
-
# A git packfile set is three files sharing one basename:
|
|
6
|
-
#
|
|
7
|
-
# pack-<sha>.pack the objects (magic "PACK")
|
|
8
|
-
# pack-<sha>.idx the index into them (magic "\377tOc")
|
|
9
|
-
# pack-<sha>.rev reverse index (magic "RIDX")
|
|
10
|
-
#
|
|
11
|
-
# Git pairs them BY EXTENSION. Strip the extension off any one of them and git
|
|
12
|
-
# stops seeing the set entirely: the objects are still on disk, byte for byte,
|
|
13
|
-
# but they become unreachable. The repo then fails in a way that reads like
|
|
14
|
-
# catastrophic history loss rather than a filename problem:
|
|
15
|
-
#
|
|
16
|
-
# fatal: unable to read tree (<sha>)
|
|
17
|
-
# error: bad tree object HEAD
|
|
18
|
-
# error: refs/heads/<branch>: invalid sha1 pointer <sha>
|
|
19
|
-
#
|
|
20
|
-
# `git fsck` reports the objects as missing and `git gc` cannot help, because
|
|
21
|
-
# nothing is actually corrupt — the bytes are intact and the repair is a
|
|
22
|
-
# rename. That mismatch between how it presents and what it is makes this
|
|
23
|
-
# failure expensive to diagnose from the error text alone, which is why this
|
|
24
|
-
# check exists as a deterministic probe.
|
|
25
|
-
#
|
|
26
|
-
# Git never writes an extensionless `pack-*` file, so finding one is
|
|
27
|
-
# unambiguous. Observed in the wild on a macOS HQ root where a folder-level
|
|
28
|
-
# sync/backup agent had been walking the tree; the mechanism that drops the
|
|
29
|
-
# extension is not established.
|
|
30
|
-
#
|
|
31
|
-
# Usage:
|
|
32
|
-
# git-pack-extension-check.sh [--root <path>] [--fix] [--quiet]
|
|
33
|
-
#
|
|
34
|
-
# --root <path> Repository to check (default: current directory).
|
|
35
|
-
# --fix Rename each orphan back to the extension its magic bytes
|
|
36
|
-
# prove it should carry. Without this the script only
|
|
37
|
-
# reports.
|
|
38
|
-
# --quiet Suppress the healthy-case line; findings still print.
|
|
39
|
-
#
|
|
40
|
-
# Exit codes:
|
|
41
|
-
# 0 healthy, or every orphan was repaired under --fix
|
|
42
|
-
# 1 usage error, or the root is not a git repository
|
|
43
|
-
# 2 orphans found and left in place (report-only, or unrepairable)
|
|
44
|
-
#
|
|
45
|
-
# The repair is a rename and nothing else. It never deletes, never rewrites
|
|
46
|
-
# file contents, never touches refs or the index, and refuses to overwrite an
|
|
47
|
-
# existing target. A file whose magic bytes are not a known pack signature is
|
|
48
|
-
# reported and left alone — this script will not guess.
|
|
49
|
-
|
|
50
|
-
set -uo pipefail
|
|
51
|
-
|
|
52
|
-
ROOT="."
|
|
53
|
-
FIX=0
|
|
54
|
-
QUIET=0
|
|
55
|
-
|
|
56
|
-
while [[ $# -gt 0 ]]; do
|
|
57
|
-
case "$1" in
|
|
58
|
-
--root)
|
|
59
|
-
[[ $# -ge 2 ]] || { echo "git-pack-extension-check: --root needs a path" >&2; exit 1; }
|
|
60
|
-
ROOT="$2"; shift 2 ;;
|
|
61
|
-
--fix) FIX=1; shift ;;
|
|
62
|
-
--quiet) QUIET=1; shift ;;
|
|
63
|
-
-h|--help)
|
|
64
|
-
sed -n '2,50p' "$0" | sed 's/^# \{0,1\}//'
|
|
65
|
-
exit 0 ;;
|
|
66
|
-
*)
|
|
67
|
-
echo "git-pack-extension-check: unknown argument '$1'" >&2
|
|
68
|
-
exit 1 ;;
|
|
69
|
-
esac
|
|
70
|
-
done
|
|
71
|
-
|
|
72
|
-
if [[ ! -d "$ROOT" ]]; then
|
|
73
|
-
echo "git-pack-extension-check: not a directory: $ROOT" >&2
|
|
74
|
-
exit 1
|
|
75
|
-
fi
|
|
76
|
-
|
|
77
|
-
# Packs live in the COMMON git dir, not the per-worktree one — a linked
|
|
78
|
-
# worktree shares the main object store, so checking either resolves to the
|
|
79
|
-
# same place. `--path-format=absolute` needs git 2.31+; the fallback keeps
|
|
80
|
-
# this working on older hosts by resolving the (possibly relative) path
|
|
81
|
-
# against the repo root itself.
|
|
82
|
-
GIT_COMMON="$(git -C "$ROOT" rev-parse --path-format=absolute --git-common-dir 2>/dev/null || true)"
|
|
83
|
-
if [[ -z "$GIT_COMMON" ]]; then
|
|
84
|
-
GIT_COMMON="$(git -C "$ROOT" rev-parse --git-common-dir 2>/dev/null || true)"
|
|
85
|
-
if [[ -z "$GIT_COMMON" ]]; then
|
|
86
|
-
echo "git-pack-extension-check: not a git repository: $ROOT" >&2
|
|
87
|
-
exit 1
|
|
88
|
-
fi
|
|
89
|
-
if [[ "$GIT_COMMON" != /* ]]; then
|
|
90
|
-
GIT_COMMON="$(cd "$ROOT" && cd "$GIT_COMMON" 2>/dev/null && pwd || true)"
|
|
91
|
-
fi
|
|
92
|
-
fi
|
|
93
|
-
|
|
94
|
-
PACK_DIR="$GIT_COMMON/objects/pack"
|
|
95
|
-
if [[ ! -d "$PACK_DIR" ]]; then
|
|
96
|
-
[[ "$QUIET" == "1" ]] || echo "git-pack-extension-check: no pack directory, nothing to check"
|
|
97
|
-
exit 0
|
|
98
|
-
fi
|
|
99
|
-
|
|
100
|
-
# The magic bytes are read with `od` rather than compared as shell strings:
|
|
101
|
-
# a packfile is binary and its first bytes can include NUL, which a shell
|
|
102
|
-
# variable cannot hold.
|
|
103
|
-
magic_of() {
|
|
104
|
-
od -A n -t x1 -N 4 "$1" 2>/dev/null | tr -d ' \n'
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
FOUND=0
|
|
108
|
-
REPAIRED=0
|
|
109
|
-
UNREPAIRED=0
|
|
110
|
-
|
|
111
|
-
# NUL-delimited: a mangled filename is exactly the case where a newline in a
|
|
112
|
-
# name would split the list and corrupt the scan.
|
|
113
|
-
while IFS= read -r -d '' orphan; do
|
|
114
|
-
base="$(basename "$orphan")"
|
|
115
|
-
hex="$(magic_of "$orphan")"
|
|
116
|
-
case "$hex" in
|
|
117
|
-
5041434b) ext="pack" ;; # "PACK"
|
|
118
|
-
ff744f63) ext="idx" ;; # "\377tOc"
|
|
119
|
-
52494458) ext="rev" ;; # "RIDX"
|
|
120
|
-
*) ext="" ;;
|
|
121
|
-
esac
|
|
122
|
-
|
|
123
|
-
FOUND=$((FOUND + 1))
|
|
124
|
-
|
|
125
|
-
if [[ -z "$ext" ]]; then
|
|
126
|
-
echo "git-pack-extension-check: FOUND $base — extensionless, but its magic bytes (${hex:-empty}) are not a pack/idx/rev signature; leaving it alone" >&2
|
|
127
|
-
UNREPAIRED=$((UNREPAIRED + 1))
|
|
128
|
-
continue
|
|
129
|
-
fi
|
|
130
|
-
|
|
131
|
-
target="$orphan.$ext"
|
|
132
|
-
if [[ -e "$target" ]]; then
|
|
133
|
-
echo "git-pack-extension-check: FOUND $base — should be $base.$ext, but that file already exists; resolve by hand" >&2
|
|
134
|
-
UNREPAIRED=$((UNREPAIRED + 1))
|
|
135
|
-
continue
|
|
136
|
-
fi
|
|
137
|
-
|
|
138
|
-
if [[ "$FIX" != "1" ]]; then
|
|
139
|
-
echo "git-pack-extension-check: FOUND $base — lost its .$ext extension; git cannot see this pack set. Re-run with --fix to rename it." >&2
|
|
140
|
-
UNREPAIRED=$((UNREPAIRED + 1))
|
|
141
|
-
continue
|
|
142
|
-
fi
|
|
143
|
-
|
|
144
|
-
if mv -n "$orphan" "$target" 2>/dev/null && [[ -e "$target" && ! -e "$orphan" ]]; then
|
|
145
|
-
echo "git-pack-extension-check: REPAIRED $base -> $base.$ext"
|
|
146
|
-
REPAIRED=$((REPAIRED + 1))
|
|
147
|
-
else
|
|
148
|
-
echo "git-pack-extension-check: FAILED to rename $base -> $base.$ext" >&2
|
|
149
|
-
UNREPAIRED=$((UNREPAIRED + 1))
|
|
150
|
-
fi
|
|
151
|
-
done < <(find "$PACK_DIR" -maxdepth 1 -type f -name 'pack-*' ! -name '*.*' -print0 2>/dev/null)
|
|
152
|
-
|
|
153
|
-
if [[ "$FOUND" -eq 0 ]]; then
|
|
154
|
-
[[ "$QUIET" == "1" ]] || echo "git-pack-extension-check: ok — no extensionless pack files in $PACK_DIR"
|
|
155
|
-
exit 0
|
|
156
|
-
fi
|
|
157
|
-
|
|
158
|
-
if [[ "$UNREPAIRED" -gt 0 ]]; then
|
|
159
|
-
echo "git-pack-extension-check: ${FOUND} orphan(s), ${REPAIRED} repaired, ${UNREPAIRED} still broken" >&2
|
|
160
|
-
exit 2
|
|
161
|
-
fi
|
|
162
|
-
|
|
163
|
-
echo "git-pack-extension-check: ${REPAIRED} pack file(s) repaired — re-run 'git fsck' to confirm"
|
|
164
|
-
exit 0
|