@indigoai-us/hq-cloud 6.15.0 → 6.15.2
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/bin/sync-mutation.d.ts +16 -0
- package/dist/bin/sync-mutation.d.ts.map +1 -0
- package/dist/bin/sync-mutation.js +60 -0
- package/dist/bin/sync-mutation.js.map +1 -0
- package/dist/bin/sync-mutation.test.d.ts +2 -0
- package/dist/bin/sync-mutation.test.d.ts.map +1 -0
- package/dist/bin/sync-mutation.test.js +165 -0
- package/dist/bin/sync-mutation.test.js.map +1 -0
- package/dist/bin/sync-runner-company.d.ts +8 -0
- package/dist/bin/sync-runner-company.d.ts.map +1 -1
- package/dist/bin/sync-runner-company.js +16 -0
- package/dist/bin/sync-runner-company.js.map +1 -1
- package/dist/bin/sync-runner-company.test.d.ts +2 -0
- package/dist/bin/sync-runner-company.test.d.ts.map +1 -0
- package/dist/bin/sync-runner-company.test.js +36 -0
- package/dist/bin/sync-runner-company.test.js.map +1 -0
- package/dist/bin/sync-runner-watch-loop.d.ts.map +1 -1
- package/dist/bin/sync-runner-watch-loop.js +98 -8
- package/dist/bin/sync-runner-watch-loop.js.map +1 -1
- package/dist/bin/sync-runner.d.ts +17 -0
- package/dist/bin/sync-runner.d.ts.map +1 -1
- package/dist/bin/sync-runner.js.map +1 -1
- package/dist/bin/sync-runner.test.js +109 -0
- package/dist/bin/sync-runner.test.js.map +1 -1
- package/dist/cli/conflict-recovery.test.d.ts +2 -0
- package/dist/cli/conflict-recovery.test.d.ts.map +1 -0
- package/dist/cli/conflict-recovery.test.js +201 -0
- package/dist/cli/conflict-recovery.test.js.map +1 -0
- package/dist/cli/conflict.d.ts +60 -0
- package/dist/cli/conflict.d.ts.map +1 -1
- package/dist/cli/conflict.js +333 -0
- package/dist/cli/conflict.js.map +1 -1
- package/dist/cli/sync.d.ts +35 -0
- package/dist/cli/sync.d.ts.map +1 -1
- package/dist/cli/sync.js +100 -0
- package/dist/cli/sync.js.map +1 -1
- package/dist/cli/sync.test.js +85 -1
- package/dist/cli/sync.test.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/skill-telemetry.d.ts +6 -0
- package/dist/skill-telemetry.d.ts.map +1 -1
- package/dist/skill-telemetry.js +14 -2
- package/dist/skill-telemetry.js.map +1 -1
- package/dist/skill-telemetry.test.js +79 -0
- package/dist/skill-telemetry.test.js.map +1 -1
- package/dist/sync/candidate-uploader.d.ts +88 -0
- package/dist/sync/candidate-uploader.d.ts.map +1 -0
- package/dist/sync/candidate-uploader.js +212 -0
- package/dist/sync/candidate-uploader.js.map +1 -0
- package/dist/sync/candidate-uploader.test.d.ts +2 -0
- package/dist/sync/candidate-uploader.test.d.ts.map +1 -0
- package/dist/sync/candidate-uploader.test.js +132 -0
- package/dist/sync/candidate-uploader.test.js.map +1 -0
- package/dist/sync/delta-client.d.ts +73 -0
- package/dist/sync/delta-client.d.ts.map +1 -0
- package/dist/sync/delta-client.js +201 -0
- package/dist/sync/delta-client.js.map +1 -0
- package/dist/sync/delta-client.test.d.ts +2 -0
- package/dist/sync/delta-client.test.d.ts.map +1 -0
- package/dist/sync/delta-client.test.js +97 -0
- package/dist/sync/delta-client.test.js.map +1 -0
- package/dist/sync/durable-apply.d.ts +76 -0
- package/dist/sync/durable-apply.d.ts.map +1 -0
- package/dist/sync/durable-apply.js +530 -0
- package/dist/sync/durable-apply.js.map +1 -0
- package/dist/sync/durable-apply.test.d.ts +2 -0
- package/dist/sync/durable-apply.test.d.ts.map +1 -0
- package/dist/sync/durable-apply.test.js +180 -0
- package/dist/sync/durable-apply.test.js.map +1 -0
- package/dist/sync/event-sync.d.ts +33 -1
- package/dist/sync/event-sync.d.ts.map +1 -1
- package/dist/sync/event-sync.js +149 -1
- package/dist/sync/event-sync.js.map +1 -1
- package/dist/sync/event-sync.test.js +142 -1
- package/dist/sync/event-sync.test.js.map +1 -1
- package/dist/sync/index.d.ts +2 -0
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +1 -0
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/multipart-uploader.d.ts +99 -0
- package/dist/sync/multipart-uploader.d.ts.map +1 -0
- package/dist/sync/multipart-uploader.js +447 -0
- package/dist/sync/multipart-uploader.js.map +1 -0
- package/dist/sync/multipart-uploader.test.d.ts +2 -0
- package/dist/sync/multipart-uploader.test.d.ts.map +1 -0
- package/dist/sync/multipart-uploader.test.js +119 -0
- package/dist/sync/multipart-uploader.test.js.map +1 -0
- package/dist/sync/mutation-client.d.ts +85 -0
- package/dist/sync/mutation-client.d.ts.map +1 -0
- package/dist/sync/mutation-client.js +245 -0
- package/dist/sync/mutation-client.js.map +1 -0
- package/dist/sync/mutation-client.test.d.ts +2 -0
- package/dist/sync/mutation-client.test.d.ts.map +1 -0
- package/dist/sync/mutation-client.test.js +51 -0
- package/dist/sync/mutation-client.test.js.map +1 -0
- package/dist/sync/push-receiver.d.ts +45 -0
- package/dist/sync/push-receiver.d.ts.map +1 -1
- package/dist/sync/push-receiver.js +101 -0
- package/dist/sync/push-receiver.js.map +1 -1
- package/dist/sync/push-receiver.test.js +54 -2
- package/dist/sync/push-receiver.test.js.map +1 -1
- package/dist/sync/scope-inventory-client.d.ts +69 -0
- package/dist/sync/scope-inventory-client.d.ts.map +1 -0
- package/dist/sync/scope-inventory-client.js +210 -0
- package/dist/sync/scope-inventory-client.js.map +1 -0
- package/dist/sync/scope-inventory-client.test.d.ts +2 -0
- package/dist/sync/scope-inventory-client.test.d.ts.map +1 -0
- package/dist/sync/scope-inventory-client.test.js +94 -0
- package/dist/sync/scope-inventory-client.test.js.map +1 -0
- package/dist/sync/snapshot-client.d.ts +98 -0
- package/dist/sync/snapshot-client.d.ts.map +1 -0
- package/dist/sync/snapshot-client.js +402 -0
- package/dist/sync/snapshot-client.js.map +1 -0
- package/dist/sync/snapshot-client.test.d.ts +2 -0
- package/dist/sync/snapshot-client.test.d.ts.map +1 -0
- package/dist/sync/snapshot-client.test.js +169 -0
- package/dist/sync/snapshot-client.test.js.map +1 -0
- package/dist/sync/uploader-finalization.d.ts +97 -0
- package/dist/sync/uploader-finalization.d.ts.map +1 -0
- package/dist/sync/uploader-finalization.js +273 -0
- package/dist/sync/uploader-finalization.js.map +1 -0
- package/dist/sync/uploader-finalization.test.d.ts +2 -0
- package/dist/sync/uploader-finalization.test.d.ts.map +1 -0
- package/dist/sync/uploader-finalization.test.js +92 -0
- package/dist/sync/uploader-finalization.test.js.map +1 -0
- package/dist/telemetry.d.ts +11 -1
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +21 -2
- package/dist/telemetry.js.map +1 -1
- package/dist/telemetry.test.js +80 -0
- package/dist/telemetry.test.js.map +1 -1
- package/package.json +6 -1
- package/.claude/policies/hq-cloud-esm-cannot-spy-fs-builtins.md +0 -30
- package/.claude/policies/hq-cloud-strip-types-no-parameter-properties.md +0 -22
- package/.github/workflows/ci.yml +0 -84
- package/.github/workflows/publish.yml +0 -56
- package/.github/workflows/unreleased-commits-nag.yml +0 -256
- package/eslint.config.js +0 -67
- package/pnpm-workspace.yaml +0 -2
- package/scripts/presign-transport-e2e.mjs +0 -250
- package/scripts/vault-rebaseline.sh +0 -323
- package/scripts/vault-rescue.sh +0 -332
- package/src/active-company.test.ts +0 -188
- package/src/active-company.ts +0 -168
- package/src/agent-codex-instructions.test.ts +0 -332
- package/src/agent-codex-instructions.ts +0 -309
- package/src/auth.ts +0 -146
- package/src/backup-prune.test.ts +0 -98
- package/src/backup-prune.ts +0 -182
- package/src/bin/backup-prune-runner.ts +0 -33
- package/src/bin/rescue-runner.ts +0 -25
- package/src/bin/sync-runner-company.ts +0 -695
- package/src/bin/sync-runner-events.test.ts +0 -143
- package/src/bin/sync-runner-events.ts +0 -55
- package/src/bin/sync-runner-planning.test.ts +0 -311
- package/src/bin/sync-runner-planning.ts +0 -258
- package/src/bin/sync-runner-rollup.test.ts +0 -37
- package/src/bin/sync-runner-rollup.ts +0 -97
- package/src/bin/sync-runner-telemetry.ts +0 -15
- package/src/bin/sync-runner-watch-loop.ts +0 -1235
- package/src/bin/sync-runner-watch-routes.test.ts +0 -71
- package/src/bin/sync-runner-watch-routes.ts +0 -184
- package/src/bin/sync-runner.test.ts +0 -8767
- package/src/bin/sync-runner.ts +0 -2190
- package/src/cli/accept.ts +0 -124
- package/src/cli/conflict.ts +0 -119
- package/src/cli/doctor.test.ts +0 -581
- package/src/cli/doctor.ts +0 -642
- package/src/cli/index.ts +0 -49
- package/src/cli/invite.test.ts +0 -250
- package/src/cli/invite.ts +0 -214
- package/src/cli/promote.ts +0 -157
- package/src/cli/reindex-knowledge.test.ts +0 -307
- package/src/cli/reindex-knowledge.ts +0 -450
- package/src/cli/reindex.test.ts +0 -957
- package/src/cli/reindex.ts +0 -979
- package/src/cli/rescue-classify-ordering.test.ts +0 -548
- package/src/cli/rescue-clone-diagnostics.test.ts +0 -120
- package/src/cli/rescue-core.ts +0 -3011
- package/src/cli/rescue-drift-reconcile.test.ts +0 -179
- package/src/cli/rescue-drop-dir-symlink.test.ts +0 -224
- package/src/cli/rescue-exec-bit-preserve.test.ts +0 -187
- package/src/cli/rescue-hq-root-guard.test.ts +0 -232
- package/src/cli/rescue-journal-reconcile.test.ts +0 -215
- package/src/cli/rescue-mtime-preserve.test.ts +0 -203
- package/src/cli/rescue-settings-reconcile.test.ts +0 -637
- package/src/cli/rescue-snapshot.test.ts +0 -57
- package/src/cli/rescue-snapshot.ts +0 -51
- package/src/cli/rescue.reindex.test.ts +0 -63
- package/src/cli/rescue.test.ts +0 -131
- package/src/cli/rescue.ts +0 -182
- package/src/cli/share.test.ts +0 -7843
- package/src/cli/share.ts +0 -3663
- package/src/cli/sync-scope.test.ts +0 -652
- package/src/cli/sync.test.ts +0 -5207
- package/src/cli/sync.ts +0 -3470
- package/src/cli/tombstones.ts +0 -106
- package/src/cli/watch-event-push-conflict.test.ts +0 -234
- package/src/client-info.test.ts +0 -214
- package/src/client-info.ts +0 -121
- package/src/cognito-auth.test.ts +0 -712
- package/src/cognito-auth.ts +0 -1422
- package/src/company-resolver.test.ts +0 -618
- package/src/company-resolver.ts +0 -521
- package/src/context.test.ts +0 -583
- package/src/context.ts +0 -378
- package/src/daemon-worker.ts +0 -26
- package/src/daemon.ts +0 -99
- package/src/entity-resolver.test.ts +0 -315
- package/src/entity-resolver.ts +0 -180
- package/src/ignore.test.ts +0 -466
- package/src/ignore.ts +0 -469
- package/src/index.ts +0 -439
- package/src/journal.test.ts +0 -968
- package/src/journal.ts +0 -765
- package/src/lib/cloud-authoritative.test.ts +0 -45
- package/src/lib/cloud-authoritative.ts +0 -59
- package/src/lib/conflict-file.ts +0 -86
- package/src/lib/conflict-index.ts +0 -289
- package/src/lib/conflict.test.ts +0 -348
- package/src/lib/describe-error.test.ts +0 -100
- package/src/lib/describe-error.ts +0 -58
- package/src/lib/exit-codes.ts +0 -24
- package/src/lib/machine-id.test.ts +0 -231
- package/src/lib/machine-id.ts +0 -175
- package/src/lib/net-errors.test.ts +0 -65
- package/src/lib/net-errors.ts +0 -86
- package/src/lib/readlink-safe.test.ts +0 -43
- package/src/lib/readlink-safe.ts +0 -29
- package/src/local-path-codec.test.ts +0 -138
- package/src/local-path-codec.ts +0 -161
- package/src/machine-auth.test.ts +0 -1323
- package/src/manifest-reconcile.test.ts +0 -1123
- package/src/manifest-reconcile.ts +0 -518
- package/src/object-io.test.ts +0 -1221
- package/src/object-io.ts +0 -1306
- package/src/operation-lock.test.ts +0 -484
- package/src/operation-lock.ts +0 -680
- package/src/outcome-telemetry.test.ts +0 -498
- package/src/outcome-telemetry.ts +0 -639
- package/src/personal-vault-exclusions.test.ts +0 -308
- package/src/personal-vault-exclusions.ts +0 -354
- package/src/personal-vault.test.ts +0 -756
- package/src/personal-vault.ts +0 -496
- package/src/prefix-coalesce.test.ts +0 -240
- package/src/prefix-coalesce.ts +0 -273
- package/src/public-surface.test.ts +0 -117
- package/src/qmd-reindex.test.ts +0 -877
- package/src/qmd-reindex.ts +0 -842
- package/src/read-only-state-dir.test.ts +0 -188
- package/src/remote-pull.test.ts +0 -1130
- package/src/remote-pull.ts +0 -618
- package/src/s3.symlink-materialize.test.ts +0 -492
- package/src/s3.test.ts +0 -1789
- package/src/s3.ts +0 -1532
- package/src/schemas/signal-types.test.ts +0 -82
- package/src/schemas/signal-types.ts +0 -38
- package/src/schemas/source-channels.test.ts +0 -82
- package/src/schemas/source-channels.ts +0 -53
- package/src/scope-shrink.test.ts +0 -633
- package/src/scope-shrink.ts +0 -481
- package/src/signals/get.test.ts +0 -310
- package/src/signals/get.ts +0 -75
- package/src/signals/internals.ts +0 -195
- package/src/signals/list.test.ts +0 -420
- package/src/signals/list.ts +0 -79
- package/src/signals/parse.ts +0 -8
- package/src/signals/types.ts +0 -91
- package/src/skill-telemetry.test.ts +0 -1825
- package/src/skill-telemetry.ts +0 -1439
- package/src/sources/get.test.ts +0 -293
- package/src/sources/get.ts +0 -66
- package/src/sources/internals.ts +0 -198
- package/src/sources/list.test.ts +0 -402
- package/src/sources/list.ts +0 -84
- package/src/sources/parse.ts +0 -43
- package/src/sources/types.ts +0 -84
- package/src/sync/event-sync.test.ts +0 -594
- package/src/sync/event-sync.ts +0 -545
- package/src/sync/feature-flags.test.ts +0 -378
- package/src/sync/feature-flags.ts +0 -62
- package/src/sync/index.ts +0 -76
- package/src/sync/lease-client.test.ts +0 -128
- package/src/sync/lease-client.ts +0 -207
- package/src/sync/logger.test.ts +0 -242
- package/src/sync/logger.ts +0 -79
- package/src/sync/metrics.test.ts +0 -462
- package/src/sync/metrics.ts +0 -213
- package/src/sync/pull-scope.ts +0 -265
- package/src/sync/push-event.test.ts +0 -266
- package/src/sync/push-event.ts +0 -224
- package/src/sync/push-receiver.test.ts +0 -566
- package/src/sync/push-receiver.ts +0 -1048
- package/src/sync/push-transport.ts +0 -231
- package/src/sync/realtime-rollout.test.ts +0 -86
- package/src/sync/realtime-rollout.ts +0 -262
- package/src/sync/state-store.test.ts +0 -194
- package/src/sync/state-store.ts +0 -727
- package/src/sync-core.ts +0 -58
- package/src/sync-progress.test.ts +0 -94
- package/src/sync-progress.ts +0 -140
- package/src/telemetry-events.test.ts +0 -88
- package/src/telemetry-events.ts +0 -205
- package/src/telemetry.test.ts +0 -1280
- package/src/telemetry.ts +0 -1109
- package/src/types.ts +0 -314
- package/src/vault-client.test.ts +0 -1380
- package/src/vault-client.ts +0 -1694
- package/src/version.ts +0 -24
- package/src/watch-roots.test.ts +0 -278
- package/src/watch-roots.ts +0 -162
- package/src/watcher-event-gate.test.ts +0 -212
- package/src/watcher.test.ts +0 -1079
- package/src/watcher.ts +0 -1741
- package/test/e2e/sync/cross-tenant-isolation.test.ts +0 -630
- package/test/e2e/sync/skill-telemetry-oversized-transcript.test.ts +0 -124
- package/test/e2e/sync/transient-company-leg.test.ts +0 -384
- package/test/e2e/sync/windows-unreadable-link-leg.test.ts +0 -191
- package/test/e2e/watcher-real-chokidar.test.ts +0 -165
- package/test/e2e/watcher-recursive-backend.test.ts +0 -181
- package/test/e2e/watcher-scoped-coverage.test.ts +0 -381
- package/test/invite-flow.integration.test.ts +0 -244
- package/test/joiner-manifest-reconcile.integration.test.ts +0 -322
- package/test/share-sync.integration.test.ts +0 -213
- package/tsconfig.json +0 -19
- package/vitest.config.ts +0 -22
|
@@ -1,323 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# vault-rebaseline.sh — overlay hq-core@vX.Y.Z baseline content onto a vault.
|
|
3
|
-
#
|
|
4
|
-
# For vaults that pre-date core/core.yaml (pre-v15 partial cloud snapshots
|
|
5
|
-
# missing the companies/ + personal/ structure). `replace-rescue.sh` refuses
|
|
6
|
-
# to operate on those vaults because its safety gate requires HQ-root layout;
|
|
7
|
-
# this script provides a narrower, additive alternative: push the v15
|
|
8
|
-
# baseline tree (.claude/, .agents/, .codex/, core/, companies/_template/,
|
|
9
|
-
# personal/, etc.) into the vault, preserving everything the user already
|
|
10
|
-
# has there. Symlinks are serialized to `hq-symlink:<target>` markers so
|
|
11
|
-
# they round-trip cleanly through hq-sync's protocol.
|
|
12
|
-
#
|
|
13
|
-
# Purely additive by default — no `--delete`. Their v14-era root files
|
|
14
|
-
# (CHANGELOG.md, RELEASE-NOTES-v14.0.0.md, etc.) remain in S3 until they
|
|
15
|
-
# either upgrade locally (menubar Update HQ) or we run a follow-up cleanup.
|
|
16
|
-
# Pass `--delete-v14-cruft` to remove a hardcoded set of known v14-only
|
|
17
|
-
# root files in the same run.
|
|
18
|
-
#
|
|
19
|
-
# Usage:
|
|
20
|
-
#
|
|
21
|
-
# vault-rebaseline.sh --prs <prs_*> [--version X.Y.Z] [opts...]
|
|
22
|
-
#
|
|
23
|
-
# Required:
|
|
24
|
-
# --prs <prs_*> Entity UID. Bucket = hq-vault-<lower-uid-w/-dashes>.
|
|
25
|
-
#
|
|
26
|
-
# Optional:
|
|
27
|
-
# --version <X.Y.Z> Default 15.0.4 (current latest release).
|
|
28
|
-
# --source <owner/repo> Default indigoai-us/hq-core. Override e.g. with
|
|
29
|
-
# indigoai-us/hq-core-staging (would use --ref main
|
|
30
|
-
# when version is not a tag).
|
|
31
|
-
# --dry-run Show plan, don't push.
|
|
32
|
-
# --keep-tmp Preserve the baseline clone + staging dirs.
|
|
33
|
-
# --delete-v14-cruft Also delete a known set of v14 root files
|
|
34
|
-
# (CHANGELOG.md, README.md, LICENSE, setup.sh,
|
|
35
|
-
# RELEASE-NOTES-v14.0.0.md, MIGRATION-v11.md,
|
|
36
|
-
# USER-GUIDE.md, CONTRIBUTING.md) so their
|
|
37
|
-
# local install drops them on next sync.
|
|
38
|
-
# --profile/--region AWS config. Default $HQ_VAULT_AWS_PROFILE /
|
|
39
|
-
# us-east-1.
|
|
40
|
-
#
|
|
41
|
-
# Auth: uses the operator's standing AWS S3 perms directly. Operator/admin
|
|
42
|
-
# only — vault-service STS vending is bypassed.
|
|
43
|
-
|
|
44
|
-
set -euo pipefail
|
|
45
|
-
|
|
46
|
-
PRS=""
|
|
47
|
-
VERSION="15.0.4"
|
|
48
|
-
SOURCE_REPO="indigoai-us/hq-core"
|
|
49
|
-
DRY_RUN=0
|
|
50
|
-
KEEP_TMP=0
|
|
51
|
-
DELETE_CRUFT=0
|
|
52
|
-
AWS_PROFILE_OVERRIDE="${HQ_VAULT_AWS_PROFILE:-}"
|
|
53
|
-
AWS_REGION_OVERRIDE="${HQ_VAULT_AWS_REGION:-us-east-1}"
|
|
54
|
-
|
|
55
|
-
usage() {
|
|
56
|
-
sed -n '2,40p' "$0"
|
|
57
|
-
exit 2
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
while [ $# -gt 0 ]; do
|
|
61
|
-
case "$1" in
|
|
62
|
-
--prs) PRS="$2"; shift 2 ;;
|
|
63
|
-
--version) VERSION="$2"; shift 2 ;;
|
|
64
|
-
--source) SOURCE_REPO="$2"; shift 2 ;;
|
|
65
|
-
--dry-run) DRY_RUN=1; shift ;;
|
|
66
|
-
--keep-tmp) KEEP_TMP=1; shift ;;
|
|
67
|
-
--delete-v14-cruft) DELETE_CRUFT=1; shift ;;
|
|
68
|
-
--profile) AWS_PROFILE_OVERRIDE="$2"; shift 2 ;;
|
|
69
|
-
--region) AWS_REGION_OVERRIDE="$2"; shift 2 ;;
|
|
70
|
-
-h|--help) usage ;;
|
|
71
|
-
*) echo "unknown arg: $1" >&2; usage ;;
|
|
72
|
-
esac
|
|
73
|
-
done
|
|
74
|
-
|
|
75
|
-
[ -n "$PRS" ] || { echo "error: --prs is required" >&2; usage; }
|
|
76
|
-
case "$PRS" in
|
|
77
|
-
prs_*) ;;
|
|
78
|
-
*) echo "error: --prs must look like prs_*; got '$PRS'" >&2; exit 2 ;;
|
|
79
|
-
esac
|
|
80
|
-
|
|
81
|
-
BUCKET="hq-vault-$(printf '%s' "$PRS" | tr '[:upper:]' '[:lower:]' | tr '_' '-')"
|
|
82
|
-
|
|
83
|
-
# Construct git ref. Tagged releases live in hq-core as v<version>; staging
|
|
84
|
-
# uses main and treats --version as informational.
|
|
85
|
-
case "$SOURCE_REPO" in
|
|
86
|
-
*hq-core-staging) REF="main" ;;
|
|
87
|
-
*) REF="v$VERSION" ;;
|
|
88
|
-
esac
|
|
89
|
-
|
|
90
|
-
AWS_ARGS=()
|
|
91
|
-
[ -n "$AWS_PROFILE_OVERRIDE" ] && AWS_ARGS+=(--profile "$AWS_PROFILE_OVERRIDE")
|
|
92
|
-
AWS_ARGS+=(--region "$AWS_REGION_OVERRIDE")
|
|
93
|
-
|
|
94
|
-
command -v jq >/dev/null || {
|
|
95
|
-
echo "error: jq is required to preserve existing S3 metadata during hq-mode repair" >&2
|
|
96
|
-
exit 2
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
# Tmp dirs.
|
|
100
|
-
BASELINE="$(mktemp -d -t hq-rebaseline-baseline-XXXXXX)"
|
|
101
|
-
STAGING="$(mktemp -d -t hq-rebaseline-stage-XXXXXX)"
|
|
102
|
-
|
|
103
|
-
cleanup() {
|
|
104
|
-
local rc="${1:-$?}"
|
|
105
|
-
if [ "$KEEP_TMP" = "1" ]; then
|
|
106
|
-
echo "==> --keep-tmp set; preserving $BASELINE and $STAGING" >&2
|
|
107
|
-
else
|
|
108
|
-
rm -rf "${BASELINE:-}" "${STAGING:-}"
|
|
109
|
-
fi
|
|
110
|
-
return $rc
|
|
111
|
-
}
|
|
112
|
-
trap cleanup EXIT
|
|
113
|
-
|
|
114
|
-
cat <<EOF
|
|
115
|
-
==> vault-rebaseline
|
|
116
|
-
prs: $PRS
|
|
117
|
-
bucket: s3://$BUCKET
|
|
118
|
-
baseline: $SOURCE_REPO @ $REF (version $VERSION)
|
|
119
|
-
baseline tmp: $BASELINE
|
|
120
|
-
staging tmp: $STAGING
|
|
121
|
-
dry-run: $([ "$DRY_RUN" = "1" ] && echo "ON" || echo "off")
|
|
122
|
-
delete v14: $([ "$DELETE_CRUFT" = "1" ] && echo "ON" || echo "off")
|
|
123
|
-
keep-tmp: $([ "$KEEP_TMP" = "1" ] && echo "yes" || echo "no")
|
|
124
|
-
EOF
|
|
125
|
-
|
|
126
|
-
# ---------- phase 1: clone baseline ----------
|
|
127
|
-
echo "" >&2
|
|
128
|
-
echo "==> [1/3] clone $SOURCE_REPO@$REF (depth=1)" >&2
|
|
129
|
-
git clone --quiet --depth 1 --branch "$REF" "https://github.com/$SOURCE_REPO.git" "$BASELINE" 2>&1 | tail -3 || {
|
|
130
|
-
echo "error: clone failed. Is $SOURCE_REPO@$REF a valid ref?" >&2
|
|
131
|
-
exit 1
|
|
132
|
-
}
|
|
133
|
-
echo "==> clone done. baseline files: $(find "$BASELINE" -type f | wc -l | tr -d ' ') (excl .git)" >&2
|
|
134
|
-
|
|
135
|
-
# ---------- phase 2: stage with symlink serialization ----------
|
|
136
|
-
echo "" >&2
|
|
137
|
-
echo "==> [2/3] stage baseline tree (serialize symlinks → hq-symlink: markers)" >&2
|
|
138
|
-
|
|
139
|
-
n_files=0; n_syms=0
|
|
140
|
-
SYMLIST="$STAGING.symlinks.txt"
|
|
141
|
-
: > "$SYMLIST"
|
|
142
|
-
|
|
143
|
-
while IFS= read -r -d '' src; do
|
|
144
|
-
rel="${src#"$BASELINE/"}"
|
|
145
|
-
[ "$rel" = "$src" ] && continue
|
|
146
|
-
[ -z "$rel" ] && continue
|
|
147
|
-
|
|
148
|
-
# Skip the clone's .git directory (we're shipping just the tree, not the repo).
|
|
149
|
-
case "$rel" in
|
|
150
|
-
.git|.git/*) continue ;;
|
|
151
|
-
esac
|
|
152
|
-
|
|
153
|
-
dest="$STAGING/$rel"
|
|
154
|
-
mkdir -p "$(dirname "$dest")"
|
|
155
|
-
|
|
156
|
-
if [ -L "$src" ]; then
|
|
157
|
-
# Read the symlink's literal target string (apps/hq-cloud/src/s3.ts:417).
|
|
158
|
-
target="$(readlink "$src")"
|
|
159
|
-
printf 'hq-symlink:%s' "$target" > "$dest"
|
|
160
|
-
printf '%s\n' "$rel" >> "$SYMLIST"
|
|
161
|
-
n_syms=$((n_syms + 1))
|
|
162
|
-
elif [ -f "$src" ]; then
|
|
163
|
-
cp -p "$src" "$dest"
|
|
164
|
-
n_files=$((n_files + 1))
|
|
165
|
-
fi
|
|
166
|
-
done < <(find "$BASELINE" \( -type d -name .git -prune \) -o \( \( -type f -o -type l \) -print0 \))
|
|
167
|
-
|
|
168
|
-
echo " staged: $n_files files, $n_syms symlinks" >&2
|
|
169
|
-
|
|
170
|
-
# Strip files from staging that are KNOWN user-state — baseline ships
|
|
171
|
-
# default values for these but the vault almost certainly has the user's
|
|
172
|
-
# own customizations. Overwriting them would clobber config that lives
|
|
173
|
-
# nowhere else (the menubar's hq-cloud/ignore.ts excludes some of these
|
|
174
|
-
# from cloud sync, but earlier vault versions uploaded them).
|
|
175
|
-
#
|
|
176
|
-
# Each entry is a relative path inside the staging tree. Removed BEFORE
|
|
177
|
-
# `aws s3 sync` runs so the file is not even a candidate for upload.
|
|
178
|
-
PRESERVE_USER_STATE=(
|
|
179
|
-
# Company registry — user-owned, registers their connected companies'
|
|
180
|
-
# cloud_uid + bucket_name. v15 baseline ships an empty stub.
|
|
181
|
-
"companies/manifest.yaml"
|
|
182
|
-
# Claude Code prefs — user-customized model, env vars, hooks. v15 ships
|
|
183
|
-
# opinionated defaults that would overwrite e.g. MAX_THINKING_TOKENS,
|
|
184
|
-
# CLAUDE_CODE_SUBAGENT_MODEL, hook routing.
|
|
185
|
-
".claude/settings.json"
|
|
186
|
-
# Obsidian UI state — pane layout, bookmarks, graph view. v15 ships
|
|
187
|
-
# defaults; users with active Obsidian have their own.
|
|
188
|
-
".obsidian/workspace.json"
|
|
189
|
-
".obsidian/graph.json"
|
|
190
|
-
".obsidian/bookmarks.json"
|
|
191
|
-
".obsidian/app.json"
|
|
192
|
-
".obsidian/appearance.json"
|
|
193
|
-
".obsidian/core-plugins.json"
|
|
194
|
-
)
|
|
195
|
-
n_preserved=0
|
|
196
|
-
for rel in "${PRESERVE_USER_STATE[@]}"; do
|
|
197
|
-
if [ -f "$STAGING/$rel" ]; then
|
|
198
|
-
rm -f "$STAGING/$rel"
|
|
199
|
-
n_preserved=$((n_preserved + 1))
|
|
200
|
-
echo " preserving user state (skipped from upload): $rel" >&2
|
|
201
|
-
fi
|
|
202
|
-
done
|
|
203
|
-
|
|
204
|
-
# ---------- phase 3: push ----------
|
|
205
|
-
echo "" >&2
|
|
206
|
-
echo "==> [3/3] aws s3 sync $STAGING/ → s3://$BUCKET/" >&2
|
|
207
|
-
|
|
208
|
-
# `--size-only` because staging mtime is fresh and S3 LastModified reflects
|
|
209
|
-
# original upload time. Default mtime-based comparison would re-upload every
|
|
210
|
-
# content-stable file (same problem as vault-rescue.sh's push phase).
|
|
211
|
-
#
|
|
212
|
-
# No `--delete` by default. v14 baseline files coexist with v15 in S3 until
|
|
213
|
-
# either the user upgrades locally (menubar Update HQ) or --delete-v14-cruft
|
|
214
|
-
# is passed (handled below as a separate rm pass for a narrow allowlist).
|
|
215
|
-
SYNC_ARGS=("s3" "sync" "$STAGING/" "s3://$BUCKET/" "--size-only")
|
|
216
|
-
[ "$DRY_RUN" = "1" ] && SYNC_ARGS+=("--dryrun")
|
|
217
|
-
|
|
218
|
-
aws "${AWS_ARGS[@]}" "${SYNC_ARGS[@]}"
|
|
219
|
-
|
|
220
|
-
# `aws s3 sync` carries bytes but does not derive hq-cloud's per-file hq-mode
|
|
221
|
-
# metadata. Re-upload ONLY regular objects that lack a valid mode, taking the
|
|
222
|
-
# permission bits from this freshly cloned release tree (the canonical git
|
|
223
|
-
# manifest). This is the one-time repair for legacy objects: a fresh pull can
|
|
224
|
-
# now restore shipped hooks/scripts from metadata rather than guessing from
|
|
225
|
-
# content. Existing user metadata is retained, including created-by fields.
|
|
226
|
-
n_mode_backfilled=0
|
|
227
|
-
MODE_META_DIR="$(mktemp -d -t hq-rebaseline-mode-meta-XXXXXX)"
|
|
228
|
-
cleanup_mode_meta() { rm -rf "${MODE_META_DIR:-}"; }
|
|
229
|
-
trap 'rc=$?; cleanup_mode_meta; cleanup "$rc"' EXIT
|
|
230
|
-
mode_index=0
|
|
231
|
-
while IFS= read -r -d '' src; do
|
|
232
|
-
rel="${src#"$STAGING/"}"
|
|
233
|
-
# Symlink records intentionally have no hq-mode (their mode is OS-owned).
|
|
234
|
-
grep -Fqx -- "$rel" "$SYMLIST" && continue
|
|
235
|
-
|
|
236
|
-
mode="$(stat -c '%a' "$src")"
|
|
237
|
-
head_json="$MODE_META_DIR/$mode_index.head.json"
|
|
238
|
-
metadata_json="$MODE_META_DIR/$mode_index.metadata.json"
|
|
239
|
-
mode_index=$((mode_index + 1))
|
|
240
|
-
aws "${AWS_ARGS[@]}" s3api head-object \
|
|
241
|
-
--bucket "$BUCKET" --key "$rel" --output json > "$head_json"
|
|
242
|
-
existing_mode="$(jq -r '.Metadata["hq-mode"] // empty' "$head_json")"
|
|
243
|
-
if [[ "$existing_mode" =~ ^[0-7]{1,4}$ ]]; then
|
|
244
|
-
continue
|
|
245
|
-
fi
|
|
246
|
-
|
|
247
|
-
jq -c --arg mode "$mode" \
|
|
248
|
-
'(.Metadata // {}) + {"hq-mode": $mode}' \
|
|
249
|
-
"$head_json" > "$metadata_json"
|
|
250
|
-
content_type="$(jq -r '.ContentType // empty' "$head_json")"
|
|
251
|
-
if [ "$DRY_RUN" = "1" ]; then
|
|
252
|
-
echo " would backfill hq-mode=$mode: $rel" >&2
|
|
253
|
-
else
|
|
254
|
-
PUT_ARGS=(s3api put-object --bucket "$BUCKET" --key "$rel" --body "$src" --metadata "file://$metadata_json")
|
|
255
|
-
[ -n "$content_type" ] && PUT_ARGS+=(--content-type "$content_type")
|
|
256
|
-
aws "${AWS_ARGS[@]}" "${PUT_ARGS[@]}" >/dev/null
|
|
257
|
-
echo " backfilled hq-mode=$mode: $rel" >&2
|
|
258
|
-
fi
|
|
259
|
-
n_mode_backfilled=$((n_mode_backfilled + 1))
|
|
260
|
-
done < <(find "$STAGING" -type f -print0)
|
|
261
|
-
|
|
262
|
-
# Stamp the hq-symlink-target metadata header on every marker so the menubar
|
|
263
|
-
# pull materializes them as real symlinks (apps/hq-cloud/src/s3.ts:466-468
|
|
264
|
-
# prefers header detection; body sniff is fallback).
|
|
265
|
-
n_stamped=0
|
|
266
|
-
if [ "$DRY_RUN" = "0" ] && [ -s "$SYMLIST" ]; then
|
|
267
|
-
echo "" >&2
|
|
268
|
-
echo " stamping hq-symlink-target metadata on $(wc -l < "$SYMLIST" | tr -d ' ') markers" >&2
|
|
269
|
-
while IFS= read -r rel; do
|
|
270
|
-
[ -z "$rel" ] && continue
|
|
271
|
-
aws "${AWS_ARGS[@]}" s3api put-object \
|
|
272
|
-
--bucket "$BUCKET" \
|
|
273
|
-
--key "$rel" \
|
|
274
|
-
--body "$STAGING/$rel" \
|
|
275
|
-
--metadata "hq-symlink-target=1" \
|
|
276
|
-
--content-type "text/plain" \
|
|
277
|
-
>/dev/null
|
|
278
|
-
n_stamped=$((n_stamped + 1))
|
|
279
|
-
done < "$SYMLIST"
|
|
280
|
-
echo " stamped: $n_stamped" >&2
|
|
281
|
-
fi
|
|
282
|
-
|
|
283
|
-
# Optional: delete v14-era root files that don't exist in v15. Narrow
|
|
284
|
-
# allowlist — files we can confidently say were always release-shipped and
|
|
285
|
-
# would never be user-customized. Everything else stays.
|
|
286
|
-
n_deleted=0
|
|
287
|
-
if [ "$DELETE_CRUFT" = "1" ]; then
|
|
288
|
-
echo "" >&2
|
|
289
|
-
echo " deleting v14 root-file cruft" >&2
|
|
290
|
-
V14_CRUFT=(
|
|
291
|
-
"CHANGELOG.md"
|
|
292
|
-
"README.md"
|
|
293
|
-
"LICENSE"
|
|
294
|
-
"setup.sh"
|
|
295
|
-
"RELEASE-NOTES-v14.0.0.md"
|
|
296
|
-
"MIGRATION-v11.md"
|
|
297
|
-
"USER-GUIDE.md"
|
|
298
|
-
"CONTRIBUTING.md"
|
|
299
|
-
)
|
|
300
|
-
for key in "${V14_CRUFT[@]}"; do
|
|
301
|
-
# Probe first — only delete if it actually exists.
|
|
302
|
-
if aws "${AWS_ARGS[@]}" s3api head-object --bucket "$BUCKET" --key "$key" >/dev/null 2>&1; then
|
|
303
|
-
if [ "$DRY_RUN" = "1" ]; then
|
|
304
|
-
echo " would delete: $key" >&2
|
|
305
|
-
else
|
|
306
|
-
aws "${AWS_ARGS[@]}" s3api delete-object --bucket "$BUCKET" --key "$key" >/dev/null
|
|
307
|
-
echo " deleted: $key" >&2
|
|
308
|
-
fi
|
|
309
|
-
n_deleted=$((n_deleted + 1))
|
|
310
|
-
fi
|
|
311
|
-
done
|
|
312
|
-
fi
|
|
313
|
-
|
|
314
|
-
echo "" >&2
|
|
315
|
-
echo "==> vault-rebaseline complete." >&2
|
|
316
|
-
echo " bucket: s3://$BUCKET" >&2
|
|
317
|
-
echo " version: $VERSION ($SOURCE_REPO@$REF)" >&2
|
|
318
|
-
echo " pushed: $n_files files, $n_syms symlinks (gross — preserved excluded)" >&2
|
|
319
|
-
echo " user-state preserved: $n_preserved files" >&2
|
|
320
|
-
echo " stamped: $n_stamped" >&2
|
|
321
|
-
echo " hq-mode backfilled: $n_mode_backfilled" >&2
|
|
322
|
-
echo " deleted: $n_deleted (v14 cruft)" >&2
|
|
323
|
-
exit 0
|
package/scripts/vault-rescue.sh
DELETED
|
@@ -1,332 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# vault-rescue.sh — end-to-end vault rescue for a single HQ user.
|
|
3
|
-
#
|
|
4
|
-
# Pulls the user's S3 vault to a tmp dir, runs the hq-sync rescue script
|
|
5
|
-
# against it at a target hq-core version, and pushes the result back to
|
|
6
|
-
# S3 with the hq-symlink:<target> wire protocol intact. The whole flow
|
|
7
|
-
# replicates what the menubar app would do if the user clicked "Update HQ"
|
|
8
|
-
# locally — except the operator runs it remotely against any vault they
|
|
9
|
-
# have AWS S3 access to.
|
|
10
|
-
#
|
|
11
|
-
# Usage:
|
|
12
|
-
#
|
|
13
|
-
# vault-rescue.sh --prs <prs_*> --version <hq-version> [opts...]
|
|
14
|
-
#
|
|
15
|
-
# Required:
|
|
16
|
-
# --prs <prs_*> Entity UID (e.g. prs_01KQ7NTBRY8X2QAA4S8AAF26W6).
|
|
17
|
-
# Bucket name resolves to hq-vault-<lower-uid-w/-dashes>.
|
|
18
|
-
# --version <X.Y.Z> Target hq-core version. Becomes --ref v<X.Y.Z>.
|
|
19
|
-
#
|
|
20
|
-
# Optional:
|
|
21
|
-
# --source <owner/repo> Default: indigoai-us/hq-core (release repo, tagged).
|
|
22
|
-
# Override with indigoai-us/hq-core-staging for staging
|
|
23
|
-
# builds (no v-prefix; passes --ref main with the
|
|
24
|
-
# version used only for logging / future floor lookup).
|
|
25
|
-
# --dry-run Don't actually mutate S3. Pull still happens (so you
|
|
26
|
-
# can inspect the tmp dir), rescue runs --dry-run, push
|
|
27
|
-
# runs --dryrun. Combine with --keep-tmp to inspect
|
|
28
|
-
# what the rescue would have produced.
|
|
29
|
-
# --keep-tmp Don't delete the tmp dir on exit (useful for diffing).
|
|
30
|
-
# --rescue-script <path> Override path to hq-sync's replace-rescue.sh.
|
|
31
|
-
# Default resolves via $HQ_RESCUE_SCRIPT, then
|
|
32
|
-
# <this-script>/../../hq-sync/scripts/replace-rescue.sh.
|
|
33
|
-
# --profile <name> AWS profile. Default: $HQ_VAULT_AWS_PROFILE.
|
|
34
|
-
# --region <name> AWS region. Default: us-east-1.
|
|
35
|
-
# --tmp-dir <dir> Override the tmp dir path. Default: mktemp under /tmp.
|
|
36
|
-
# --floor-sha <40-hex> Forwarded to replace-rescue.sh; bypasses the
|
|
37
|
-
# vault's stamped last_sync_sha.
|
|
38
|
-
#
|
|
39
|
-
# Auth: uses the caller's AWS profile directly. The menubar app vends
|
|
40
|
-
# short-lived STS creds via vault-service; this script does not — it
|
|
41
|
-
# requires standing S3 perms on the target bucket. Operator/admin only.
|
|
42
|
-
#
|
|
43
|
-
# Output: live logs from each phase, plus a final summary. The pre-update
|
|
44
|
-
# safety snapshot from replace-rescue.sh lands at
|
|
45
|
-
# ~/.hq/backups/pre-update-<ts>/ on the OPERATOR's machine, not the user's.
|
|
46
|
-
|
|
47
|
-
set -euo pipefail
|
|
48
|
-
|
|
49
|
-
PRS=""
|
|
50
|
-
VERSION=""
|
|
51
|
-
SOURCE_REPO="indigoai-us/hq-core"
|
|
52
|
-
DRY_RUN=0
|
|
53
|
-
KEEP_TMP=0
|
|
54
|
-
RESCUE_SCRIPT="${HQ_RESCUE_SCRIPT:-}"
|
|
55
|
-
AWS_PROFILE_OVERRIDE="${HQ_VAULT_AWS_PROFILE:-}"
|
|
56
|
-
AWS_REGION_OVERRIDE="${HQ_VAULT_AWS_REGION:-us-east-1}"
|
|
57
|
-
TMP_DIR_OVERRIDE=""
|
|
58
|
-
FLOOR_SHA=""
|
|
59
|
-
|
|
60
|
-
# Default rescue script: discover relative to this file's location. Works
|
|
61
|
-
# when hq-cloud and hq-sync are sibling apps under hq-workspace; falls back
|
|
62
|
-
# to the env var when checked out elsewhere.
|
|
63
|
-
if [ -z "$RESCUE_SCRIPT" ]; then
|
|
64
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
65
|
-
CANDIDATE="$SCRIPT_DIR/../../hq-sync/scripts/replace-rescue.sh"
|
|
66
|
-
[ -f "$CANDIDATE" ] && RESCUE_SCRIPT="$CANDIDATE"
|
|
67
|
-
fi
|
|
68
|
-
|
|
69
|
-
usage() {
|
|
70
|
-
sed -n '2,45p' "$0"
|
|
71
|
-
exit 2
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
while [ $# -gt 0 ]; do
|
|
75
|
-
case "$1" in
|
|
76
|
-
--prs) PRS="$2"; shift 2 ;;
|
|
77
|
-
--version) VERSION="$2"; shift 2 ;;
|
|
78
|
-
--source) SOURCE_REPO="$2"; shift 2 ;;
|
|
79
|
-
--dry-run) DRY_RUN=1; shift ;;
|
|
80
|
-
--keep-tmp) KEEP_TMP=1; shift ;;
|
|
81
|
-
--rescue-script) RESCUE_SCRIPT="$2"; shift 2 ;;
|
|
82
|
-
--profile) AWS_PROFILE_OVERRIDE="$2"; shift 2 ;;
|
|
83
|
-
--region) AWS_REGION_OVERRIDE="$2"; shift 2 ;;
|
|
84
|
-
--tmp-dir) TMP_DIR_OVERRIDE="$2"; shift 2 ;;
|
|
85
|
-
--floor-sha) FLOOR_SHA="$2"; shift 2 ;;
|
|
86
|
-
-h|--help) usage ;;
|
|
87
|
-
*) echo "unknown arg: $1" >&2; usage ;;
|
|
88
|
-
esac
|
|
89
|
-
done
|
|
90
|
-
|
|
91
|
-
[ -n "$PRS" ] || { echo "error: --prs is required" >&2; usage; }
|
|
92
|
-
[ -n "$VERSION" ] || { echo "error: --version is required" >&2; usage; }
|
|
93
|
-
[ -n "$RESCUE_SCRIPT" ] || {
|
|
94
|
-
echo "error: replace-rescue.sh not found. Pass --rescue-script <path> or set HQ_RESCUE_SCRIPT." >&2
|
|
95
|
-
exit 2
|
|
96
|
-
}
|
|
97
|
-
[ -f "$RESCUE_SCRIPT" ] || {
|
|
98
|
-
echo "error: --rescue-script '$RESCUE_SCRIPT' is not a file" >&2
|
|
99
|
-
exit 2
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
case "$PRS" in
|
|
103
|
-
prs_*) ;;
|
|
104
|
-
*) echo "error: --prs must look like prs_*; got '$PRS'" >&2; exit 2 ;;
|
|
105
|
-
esac
|
|
106
|
-
|
|
107
|
-
# Bucket name convention (matches s3.ts entity → bucket mapping):
|
|
108
|
-
# prs_01ABC... → hq-vault-prs-01abc...
|
|
109
|
-
BUCKET="hq-vault-$(printf '%s' "$PRS" | tr '[:upper:]' '[:lower:]' | tr '_' '-')"
|
|
110
|
-
|
|
111
|
-
# Construct rescue --ref. Tagged releases live in hq-core as v<version>;
|
|
112
|
-
# rolling staging uses main and treats --version as informational.
|
|
113
|
-
case "$SOURCE_REPO" in
|
|
114
|
-
*hq-core-staging) REF="main" ;;
|
|
115
|
-
*) REF="v$VERSION" ;;
|
|
116
|
-
esac
|
|
117
|
-
|
|
118
|
-
# AWS CLI prefix.
|
|
119
|
-
AWS_ARGS=()
|
|
120
|
-
[ -n "$AWS_PROFILE_OVERRIDE" ] && AWS_ARGS+=(--profile "$AWS_PROFILE_OVERRIDE")
|
|
121
|
-
AWS_ARGS+=(--region "$AWS_REGION_OVERRIDE")
|
|
122
|
-
|
|
123
|
-
command -v jq >/dev/null || {
|
|
124
|
-
echo "error: jq is required to preserve existing S3 metadata during hq-mode repair" >&2
|
|
125
|
-
exit 2
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
# Tmp dir setup.
|
|
129
|
-
if [ -n "$TMP_DIR_OVERRIDE" ]; then
|
|
130
|
-
TMP_DIR="$TMP_DIR_OVERRIDE"
|
|
131
|
-
mkdir -p "$TMP_DIR"
|
|
132
|
-
else
|
|
133
|
-
TMP_DIR="$(mktemp -d -t hq-vault-rescue-XXXXXX)"
|
|
134
|
-
fi
|
|
135
|
-
|
|
136
|
-
# Trap MUST reference an unconditional global with default-empty fallback
|
|
137
|
-
# (set -u trips on undef refs in the trap body otherwise).
|
|
138
|
-
cleanup() {
|
|
139
|
-
local rc=$?
|
|
140
|
-
if [ "$KEEP_TMP" = "1" ]; then
|
|
141
|
-
echo "==> --keep-tmp set; preserving $TMP_DIR" >&2
|
|
142
|
-
elif [ -n "${TMP_DIR:-}" ] && [ -d "$TMP_DIR" ]; then
|
|
143
|
-
rm -rf "$TMP_DIR"
|
|
144
|
-
fi
|
|
145
|
-
return $rc
|
|
146
|
-
}
|
|
147
|
-
trap cleanup EXIT
|
|
148
|
-
|
|
149
|
-
cat <<EOF
|
|
150
|
-
==> vault-rescue
|
|
151
|
-
prs: $PRS
|
|
152
|
-
bucket: s3://$BUCKET
|
|
153
|
-
target: $SOURCE_REPO @ $REF (version $VERSION)
|
|
154
|
-
rescue script: $RESCUE_SCRIPT
|
|
155
|
-
tmp dir: $TMP_DIR
|
|
156
|
-
dry-run: $([ "$DRY_RUN" = "1" ] && echo "ON (no S3 mutation, no tmp mutation past pull)" || echo "off")
|
|
157
|
-
keep-tmp: $([ "$KEEP_TMP" = "1" ] && echo "yes" || echo "no")
|
|
158
|
-
EOF
|
|
159
|
-
|
|
160
|
-
# ---------- phase 1: pull ----------
|
|
161
|
-
echo "" >&2
|
|
162
|
-
echo "==> [1/3] pull s3://$BUCKET/ -> $TMP_DIR/" >&2
|
|
163
|
-
aws "${AWS_ARGS[@]}" s3 sync "s3://$BUCKET/" "$TMP_DIR/" --quiet
|
|
164
|
-
echo "==> pull done. files: $(find "$TMP_DIR" -type f | wc -l | tr -d ' ')" >&2
|
|
165
|
-
|
|
166
|
-
# ---------- phase 2: rescue ----------
|
|
167
|
-
echo "" >&2
|
|
168
|
-
echo "==> [2/3] rescue: $RESCUE_SCRIPT --source $SOURCE_REPO --ref $REF --cloud-update" >&2
|
|
169
|
-
|
|
170
|
-
RESCUE_ARGS=(
|
|
171
|
-
--hq-root "$TMP_DIR"
|
|
172
|
-
--source "$SOURCE_REPO"
|
|
173
|
-
--ref "$REF"
|
|
174
|
-
--cloud-update
|
|
175
|
-
--no-backup
|
|
176
|
-
--yes
|
|
177
|
-
)
|
|
178
|
-
# --no-backup is intentional: replace-rescue.sh's own pre-update snapshot
|
|
179
|
-
# would land at ~/.hq/backups/ on the OPERATOR's machine, not the vault
|
|
180
|
-
# owner's — so it doesn't help the user we're rescuing. Phase 1 already
|
|
181
|
-
# leaves the pulled tmp tree on disk (preserved with --keep-tmp), which IS
|
|
182
|
-
# the meaningful pre-rescue snapshot. Operators who want a hardened
|
|
183
|
-
# backup tarball it themselves before invoking this script.
|
|
184
|
-
# Requires hq-sync ≥0.6.4 (indigoai-us/hq-sync#170 — earlier versions
|
|
185
|
-
# return exit 1 on the --no-backup branch and kill us mid-flight).
|
|
186
|
-
[ "$DRY_RUN" = "1" ] && RESCUE_ARGS+=(--dry-run)
|
|
187
|
-
[ -n "$FLOOR_SHA" ] && RESCUE_ARGS+=(--floor-sha "$FLOOR_SHA")
|
|
188
|
-
|
|
189
|
-
bash "$RESCUE_SCRIPT" "${RESCUE_ARGS[@]}"
|
|
190
|
-
echo "==> rescue done." >&2
|
|
191
|
-
|
|
192
|
-
if [ "$DRY_RUN" = "1" ]; then
|
|
193
|
-
echo "" >&2
|
|
194
|
-
echo "==> [3/3] push: SKIPPED (--dry-run; rescue ran --dry-run too, no tmp mutation to push)" >&2
|
|
195
|
-
echo "==> vault-rescue complete (dry-run). Inspect $TMP_DIR." >&2
|
|
196
|
-
KEEP_TMP=1
|
|
197
|
-
exit 0
|
|
198
|
-
fi
|
|
199
|
-
|
|
200
|
-
# ---------- phase 3: push ----------
|
|
201
|
-
echo "" >&2
|
|
202
|
-
echo "==> [3/3] push $TMP_DIR/ -> s3://$BUCKET/" >&2
|
|
203
|
-
|
|
204
|
-
# Build a staging tree: regular files copied verbatim; local symlinks
|
|
205
|
-
# serialized as hq-symlink:<target> marker files (no trailing newline,
|
|
206
|
-
# per apps/hq-cloud/src/s3.ts:417). Skip a minimal denylist that should
|
|
207
|
-
# never round-trip through S3.
|
|
208
|
-
STAGING="$(mktemp -d -t hq-vault-rescue-stage-XXXXXX)"
|
|
209
|
-
MODE_META_DIR="$(mktemp -d -t hq-vault-rescue-mode-meta-XXXXXX)"
|
|
210
|
-
add_staging_cleanup() {
|
|
211
|
-
rm -rf "${STAGING:-}" "${MODE_META_DIR:-}"
|
|
212
|
-
}
|
|
213
|
-
# Chain cleanup: existing trap removes TMP_DIR; we also need STAGING gone.
|
|
214
|
-
trap '{ add_staging_cleanup; cleanup; }' EXIT
|
|
215
|
-
|
|
216
|
-
echo " staging at $STAGING" >&2
|
|
217
|
-
|
|
218
|
-
# Denylist (path prefixes that should never push back). This is INTENTIONALLY
|
|
219
|
-
# smaller than apps/hq-cloud/src/ignore.ts — the vault we just pulled IS the
|
|
220
|
-
# source of truth, so over-filtering would cause spurious deletes.
|
|
221
|
-
deny_path() {
|
|
222
|
-
case "$1" in
|
|
223
|
-
.git|.git/*) return 0 ;;
|
|
224
|
-
node_modules|node_modules/*) return 0 ;;
|
|
225
|
-
target|target/*) return 0 ;;
|
|
226
|
-
dist|dist/*) return 0 ;;
|
|
227
|
-
build|build/*) return 0 ;;
|
|
228
|
-
__pycache__|__pycache__/*) return 0 ;;
|
|
229
|
-
.venv|.venv/*|venv|venv/*) return 0 ;;
|
|
230
|
-
.DS_Store|*/.DS_Store) return 0 ;;
|
|
231
|
-
.env|.env.*) return 0 ;;
|
|
232
|
-
*.pyc|*.class) return 0 ;;
|
|
233
|
-
esac
|
|
234
|
-
return 1
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
n_files=0; n_symlinks=0; n_skipped=0
|
|
238
|
-
SYMLINK_LIST="$STAGING.symlinks.txt"
|
|
239
|
-
: > "$SYMLINK_LIST"
|
|
240
|
-
|
|
241
|
-
while IFS= read -r -d '' src; do
|
|
242
|
-
rel="${src#"$TMP_DIR/"}"
|
|
243
|
-
[ "$rel" = "$src" ] && continue
|
|
244
|
-
[ -z "$rel" ] && continue
|
|
245
|
-
if deny_path "$rel"; then
|
|
246
|
-
n_skipped=$((n_skipped + 1))
|
|
247
|
-
continue
|
|
248
|
-
fi
|
|
249
|
-
dest="$STAGING/$rel"
|
|
250
|
-
mkdir -p "$(dirname "$dest")"
|
|
251
|
-
if [ -L "$src" ]; then
|
|
252
|
-
target="$(readlink "$src")"
|
|
253
|
-
printf 'hq-symlink:%s' "$target" > "$dest"
|
|
254
|
-
printf '%s\n' "$rel" >> "$SYMLINK_LIST"
|
|
255
|
-
n_symlinks=$((n_symlinks + 1))
|
|
256
|
-
elif [ -f "$src" ]; then
|
|
257
|
-
cp -p "$src" "$dest"
|
|
258
|
-
n_files=$((n_files + 1))
|
|
259
|
-
fi
|
|
260
|
-
done < <(find "$TMP_DIR" \( -type d \( -name node_modules -o -name .git -o -name target -o -name dist -o -name build \) -prune \) -o \( \( -type f -o -type l \) -print0 \))
|
|
261
|
-
|
|
262
|
-
echo " staged files=$n_files symlinks=$n_symlinks skipped=$n_skipped" >&2
|
|
263
|
-
|
|
264
|
-
# Sync to S3 — `--size-only` because staging mtime=now (fresh write) and
|
|
265
|
-
# S3 LastModified reflects original upload, so the default mtime-based
|
|
266
|
-
# comparator would treat every staging file as newer and re-upload it.
|
|
267
|
-
echo " aws s3 sync $STAGING/ -> s3://$BUCKET/ --size-only --delete" >&2
|
|
268
|
-
aws "${AWS_ARGS[@]}" s3 sync "$STAGING/" "s3://$BUCKET/" --size-only --delete
|
|
269
|
-
|
|
270
|
-
# The AWS CLI moves bytes without hq-cloud's hq-mode metadata. Re-upload only
|
|
271
|
-
# regular objects that need the one-time repair, preserving existing S3 user
|
|
272
|
-
# metadata. For release-shipped files the rescue overlay supplied these modes
|
|
273
|
-
# from the trusted hq-core git tree, so a fresh pull restores hooks/scripts
|
|
274
|
-
# from canonical metadata instead of trying to infer executability from bytes.
|
|
275
|
-
n_mode_backfilled=0
|
|
276
|
-
mode_index=0
|
|
277
|
-
while IFS= read -r -d '' src; do
|
|
278
|
-
rel="${src#"$STAGING/"}"
|
|
279
|
-
# Symlink records intentionally have no hq-mode (their mode is OS-owned).
|
|
280
|
-
grep -Fqx -- "$rel" "$SYMLINK_LIST" && continue
|
|
281
|
-
|
|
282
|
-
mode="$(stat -c '%a' "$src")"
|
|
283
|
-
head_json="$MODE_META_DIR/$mode_index.head.json"
|
|
284
|
-
metadata_json="$MODE_META_DIR/$mode_index.metadata.json"
|
|
285
|
-
mode_index=$((mode_index + 1))
|
|
286
|
-
aws "${AWS_ARGS[@]}" s3api head-object \
|
|
287
|
-
--bucket "$BUCKET" --key "$rel" --output json > "$head_json"
|
|
288
|
-
existing_mode="$(jq -r '.Metadata["hq-mode"] // empty' "$head_json")"
|
|
289
|
-
if [[ "$existing_mode" =~ ^[0-7]{1,4}$ ]]; then
|
|
290
|
-
continue
|
|
291
|
-
fi
|
|
292
|
-
|
|
293
|
-
jq -c --arg mode "$mode" \
|
|
294
|
-
'(.Metadata // {}) + {"hq-mode": $mode}' \
|
|
295
|
-
"$head_json" > "$metadata_json"
|
|
296
|
-
content_type="$(jq -r '.ContentType // empty' "$head_json")"
|
|
297
|
-
PUT_ARGS=(s3api put-object --bucket "$BUCKET" --key "$rel" --body "$src" --metadata "file://$metadata_json")
|
|
298
|
-
[ -n "$content_type" ] && PUT_ARGS+=(--content-type "$content_type")
|
|
299
|
-
aws "${AWS_ARGS[@]}" "${PUT_ARGS[@]}" >/dev/null
|
|
300
|
-
echo " backfilled hq-mode=$mode: $rel" >&2
|
|
301
|
-
n_mode_backfilled=$((n_mode_backfilled + 1))
|
|
302
|
-
done < <(find "$STAGING" -type f -print0)
|
|
303
|
-
|
|
304
|
-
# Stamp the hq-symlink metadata header on every symlink-marker object so
|
|
305
|
-
# the menubar pull materializes them as real symlinks (apps/hq-cloud/src/
|
|
306
|
-
# s3.ts:466-468 prefers header detection; body-sniff is fallback).
|
|
307
|
-
n_stamped=0
|
|
308
|
-
if [ -s "$SYMLINK_LIST" ]; then
|
|
309
|
-
echo " stamping hq-symlink-target metadata on $(wc -l < "$SYMLINK_LIST" | tr -d ' ') objects" >&2
|
|
310
|
-
while IFS= read -r rel; do
|
|
311
|
-
[ -z "$rel" ] && continue
|
|
312
|
-
aws "${AWS_ARGS[@]}" s3api put-object \
|
|
313
|
-
--bucket "$BUCKET" \
|
|
314
|
-
--key "$rel" \
|
|
315
|
-
--body "$STAGING/$rel" \
|
|
316
|
-
--metadata "hq-symlink-target=1" \
|
|
317
|
-
--content-type "text/plain" \
|
|
318
|
-
>/dev/null
|
|
319
|
-
n_stamped=$((n_stamped + 1))
|
|
320
|
-
done < "$SYMLINK_LIST"
|
|
321
|
-
fi
|
|
322
|
-
echo " stamped: $n_stamped" >&2
|
|
323
|
-
|
|
324
|
-
echo "" >&2
|
|
325
|
-
echo "==> vault-rescue complete." >&2
|
|
326
|
-
echo " bucket: s3://$BUCKET" >&2
|
|
327
|
-
echo " version: $VERSION ($SOURCE_REPO@$REF)" >&2
|
|
328
|
-
echo " files: $n_files" >&2
|
|
329
|
-
echo " symlinks: $n_symlinks" >&2
|
|
330
|
-
echo " stamped: $n_stamped" >&2
|
|
331
|
-
echo " hq-mode backfilled: $n_mode_backfilled" >&2
|
|
332
|
-
echo " skipped: $n_skipped" >&2
|