@indigoai-us/hq-cli 5.345.105 → 5.345.107

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.
Files changed (60) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/assets/scaffold/core/scripts/hq-task.mjs +259 -0
  3. package/assets/scaffold/core/scripts/hq-task.sh +31 -0
  4. package/assets/scaffold/core/scripts/pipeline-worker-table.sh +285 -0
  5. package/dist/command-catalog.generated.d.ts +135 -5
  6. package/dist/command-catalog.generated.js +161 -5
  7. package/dist/commands/auth.js +42 -0
  8. package/dist/commands/core-hq-task-fast.d.ts +4 -0
  9. package/dist/commands/core-hq-task-fast.js +11 -0
  10. package/dist/commands/core-hq-task-native.d.ts +20 -0
  11. package/dist/commands/core-hq-task-native.js +275 -0
  12. package/dist/commands/core-native-bucket-c-flag.d.ts +3 -0
  13. package/dist/commands/core-native-bucket-c-flag.js +6 -0
  14. package/dist/commands/core-native-family-flag.d.ts +0 -2
  15. package/dist/commands/core-native-family-flag.js +0 -4
  16. package/dist/commands/core-native-pipeline-flag.d.ts +3 -0
  17. package/dist/commands/core-native-pipeline-flag.js +6 -0
  18. package/dist/commands/core-ontology-native.js +24 -30
  19. package/dist/commands/core-pipeline-workers-command.d.ts +3 -0
  20. package/dist/commands/core-pipeline-workers-command.js +37 -0
  21. package/dist/commands/core-pipeline-workers-native.d.ts +13 -0
  22. package/dist/commands/core-pipeline-workers-native.js +361 -0
  23. package/dist/commands/core.js +12 -10
  24. package/dist/commands/lanes.js +32 -7
  25. package/dist/commands/logout.d.ts +6 -1
  26. package/dist/commands/logout.js +18 -2
  27. package/dist/commands/outposts.d.ts +5 -0
  28. package/dist/commands/outposts.js +5 -0
  29. package/dist/fast-scaffold.d.ts +14 -1
  30. package/dist/fast-scaffold.js +149 -5
  31. package/dist/hq-cloud-sync-runner/bin/sync-runner.js +56937 -64550
  32. package/dist/hq-cloud-sync-runner/package.json +1 -1
  33. package/dist/index.js +15 -1
  34. package/dist/lib/daemon/remote-control-pools.d.ts +2 -2
  35. package/dist/lib/flag-registry-worker-source.generated.d.ts +1 -1
  36. package/dist/lib/flag-registry-worker-source.generated.js +1 -1
  37. package/dist/lib/lanes/reconcile.js +4 -0
  38. package/dist/lib/lanes/remote-control-lane.d.ts +33 -0
  39. package/dist/lib/lanes/remote-control-lane.js +276 -0
  40. package/dist/lib/lanes/spawn.d.ts +5 -0
  41. package/dist/lib/lanes/spawn.js +65 -14
  42. package/dist/lib/lanes/store.js +7 -0
  43. package/dist/lib/lanes/types.d.ts +2 -0
  44. package/dist/lib/lanes/types.js +1 -1
  45. package/dist/lib/lanes/watcher.js +8 -1
  46. package/dist/utils/cognito-config.d.ts +5 -0
  47. package/dist/utils/cognito-config.js +14 -0
  48. package/dist/utils/cognito-revoke.d.ts +33 -0
  49. package/dist/utils/cognito-revoke.js +42 -0
  50. package/dist/utils/cognito-session.d.ts +12 -4
  51. package/dist/utils/cognito-session.js +42 -9
  52. package/dist/utils/token-keychain.d.ts +96 -0
  53. package/dist/utils/token-keychain.js +218 -0
  54. package/package.json +2 -2
  55. package/assets/scaffold/core/scripts/ontology-audience-grant.sh +0 -81
  56. package/assets/scaffold/core/scripts/ontology-brief.mjs +0 -93
  57. package/assets/scaffold/core/scripts/ontology-candidate.sh +0 -100
  58. package/assets/scaffold/core/scripts/ontology-garden.mjs +0 -327
  59. package/assets/scaffold/core/scripts/ontology-source-worklist.sh +0 -226
  60. package/assets/scaffold/core/scripts/source-yaml-validate.sh +0 -36
@@ -1,226 +0,0 @@
1
- #!/usr/bin/env bash
2
- # ontology-source-worklist.sh — list a declared source's unprocessed items with
3
- # each item's resolved audience. The ontology worker's process-source skill
4
- # reads this list, extracts candidates from each item, and marks it done.
5
- # Specs: source-yaml-spec.md, ontology-local-spec.md (core/knowledge/public/hq-core/)
6
- #
7
- # Usage:
8
- # ontology-source-worklist.sh --company <co> --channel <ch> [--limit N] [--force]
9
- # ontology-source-worklist.sh --company <co> --channel <ch> --mark-done <item-file>
10
- #
11
- # Output: one JSON object per line:
12
- # {"file":"sources/meetings/x.md","audience_key":"…","audience":["prs_…","a@x.com"]}
13
- # {"file":"sources/meetings/y.md","skip":"no-audience"}
14
- # Audience by audience_rule:
15
- # attendees / thread / channel — the item's `audience:` or `attendees:` list if
16
- # it has one, else the direct read grants on the item's vault key
17
- # (hq files acl), which is how cloud ingestion records who was privy.
18
- # explicit — the item's own `audience:` frontmatter only.
19
- # company — "company".
20
- # An item with no resolvable audience is emitted as a skip, never as company.
21
- # Exit 0; 2 bad usage / invalid source.yaml; 4 run: cloud source without --force.
22
- set -uo pipefail
23
- HQ="${HQ_BIN:-hq}"
24
- root="${HQ_ROOT:-$(cd "$(dirname "$0")/../.." && pwd)}"
25
- here="$(cd "$(dirname "$0")" && pwd)"
26
- co="" ch="" limit=50 force=0 done_item=""
27
- while [ $# -gt 0 ]; do
28
- case "$1" in
29
- --company) co="$2"; shift 2 ;; --channel) ch="$2"; shift 2 ;; --limit) limit="$2"; shift 2 ;;
30
- --force) force=1; shift ;; --mark-done) done_item="$2"; shift 2 ;;
31
- *) echo "unknown flag $1" >&2; exit 2 ;;
32
- esac
33
- done
34
- [ -n "$co" ] && [ -n "$ch" ] || { echo "usage: ontology-source-worklist.sh --company <co> --channel <ch> [--limit N] [--force] [--mark-done <file>]" >&2; exit 2; }
35
- D="$root/companies/$co/sources/$ch"; Y="$D/source.yaml"; ledger="$D/.processed"; skip_ledger="$D/.skipped"
36
- # Bumped when the audience parser gains new recognisable frontmatter fields; items
37
- # previously skipped as no-audience under an older PARSER_VERSION get re-evaluated
38
- # on the next run instead of staying stuck forever (see feedback_b8d61e28).
39
- PARSER_VERSION=2
40
- bash "$here/source-yaml-validate.sh" "$Y" >/dev/null || { bash "$here/source-yaml-validate.sh" "$Y" >&2; exit 2; }
41
-
42
- if [ -n "$done_item" ]; then printf '%s\t%s\n' "$(basename "$done_item")" "$PARSER_VERSION" >> "$ledger"; exit 0; fi
43
-
44
- # Migrate `.processed` to parser-version stamps so a successfully processed item
45
- # stays processed across runs. Entries are `basename\tversion`; new mark-done
46
- # writes always include the stamp. Convergence rule for legacy UNSTAMPED
47
- # entries from the pre-fix slack-dm bug (254 DMs recorded in `.processed` as
48
- # plain basenames while no candidates were ever written): drop ones whose file
49
- # carries `resolved_participants:` (the exact bug signature) so the main loop
50
- # re-evaluates them exactly once; the next mark-done writes them back stamped
51
- # at the current version. Any other unstamped entry is upgraded in place to a
52
- # stamp — never re-stripped again. Stamped entries at a version below current
53
- # PARSER_VERSION are also dropped so a parser upgrade re-evaluates them.
54
- # ontology-candidate ids are content-addressed, so a true reprocess is idempotent.
55
- if [ -f "$ledger" ]; then
56
- tmp="$ledger.heal.$$"
57
- : > "$tmp"
58
- changed=0
59
- while IFS=$'\t' read -r b ver || [ -n "$b" ]; do
60
- b="${b%$'\r'}"; ver="${ver%$'\r'}"
61
- [ -n "$b" ] || continue
62
- if [ -n "${ver:-}" ]; then
63
- if [ "$ver" -lt "$PARSER_VERSION" ] 2>/dev/null; then changed=1; continue; fi
64
- printf '%s\t%s\n' "$b" "$ver" >> "$tmp"
65
- continue
66
- fi
67
- item="$D/$b"
68
- if [ -f "$item" ] && awk '/^---$/{fm++; if(fm==2) exit} fm==1 && /^resolved_participants:/{found=1; exit} END{exit !found}' "$item" 2>/dev/null; then
69
- changed=1; continue
70
- fi
71
- printf '%s\t%s\n' "$b" "$PARSER_VERSION" >> "$tmp"
72
- changed=1
73
- done < "$ledger"
74
- if [ "$changed" = 1 ]; then mv "$tmp" "$ledger"; else rm -f "$tmp"; fi
75
- fi
76
- is_processed() { # 0 if $1 is recorded in .processed at >= current parser version (or unstamped — treated as current after migration)
77
- [ -f "$ledger" ] || return 1
78
- awk -F '\t' -v b="$1" -v v="$PARSER_VERSION" '
79
- { sub(/\r$/, "") }
80
- $1==b { if (NF < 2 || $2=="") { found=1; exit } if (($2+0) >= v) { found=1; exit } }
81
- END { exit !found }
82
- ' "$ledger"
83
- }
84
-
85
- # Walk `.skipped`: entries whose recorded version is < current PARSER_VERSION
86
- # are dropped so the main loop re-evaluates them. Entries at the current
87
- # version stay as the ignore set for this run.
88
- declare_skipped=""
89
- if [ -f "$skip_ledger" ]; then
90
- tmp="$skip_ledger.rev.$$"
91
- : > "$tmp"
92
- changed=0
93
- while IFS=$'\t' read -r b reason ver || [ -n "$b" ]; do
94
- [ -n "$b" ] || continue
95
- if [ -z "${ver:-}" ] || [ "$ver" -lt "$PARSER_VERSION" ] 2>/dev/null; then
96
- changed=1; continue
97
- fi
98
- printf '%s\t%s\t%s\n' "$b" "$reason" "$ver" >> "$tmp"
99
- done < "$skip_ledger"
100
- if [ "$changed" = 1 ]; then mv "$tmp" "$skip_ledger"; else rm -f "$tmp"; fi
101
- fi
102
- skipped_at_current() { # 0 if $1 is recorded as skipped at the current parser version
103
- [ -f "$skip_ledger" ] || return 1
104
- awk -F '\t' -v b="$1" -v v="$PARSER_VERSION" '$1==b && $3==v { found=1; exit } END { exit !found }' "$skip_ledger"
105
- }
106
-
107
- get() { awk -v k="$1" '$0 ~ "^"k":" { sub("^"k":[[:space:]]*", ""); gsub(/^["\x27]|["\x27]$/, ""); print; exit }' "$Y"; }
108
- run="$(get run)"; rule="$(get audience_rule)"
109
- if [ "$run" = cloud ] && [ "$force" = 0 ]; then echo "assigned to cloud agent (run: cloud); pass --force to run locally" >&2; exit 4; fi
110
-
111
- item_list() { # frontmatter list field: inline [a, b] or block "- a"
112
- awk -v k="$2" '
113
- BEGIN{fm=0}
114
- /^---$/ { fm++; if (fm==2) exit; next }
115
- fm==1 && $0 ~ "^"k":" { v=$0; sub("^"k":[[:space:]]*", "", v)
116
- if (v ~ /^\[/) { gsub(/[\[\]"\x27]/, "", v); n=split(v, a, ","); for(i=1;i<=n;i++){gsub(/^[ \t]+|[ \t]+$/, "", a[i]); if(a[i]!="") print a[i]}; exit }
117
- inlist=1; next }
118
- fm==1 && inlist && /^[[:space:]]*-[[:space:]]/ { v=$0; sub(/^[[:space:]]*-[[:space:]]*/, "", v); gsub(/["\x27]/, "", v); print v; next }
119
- fm==1 && inlist { exit }
120
- ' "$1"
121
- }
122
-
123
- # participant_ids: for a frontmatter block list of mappings under key $2 (e.g.
124
- # resolved_participants:), emit one id per entry: the entry's `person_uid:` if
125
- # present, otherwise its `email:`. Entries with only `slack_user_id:` (no
126
- # person_uid, no email) are skipped — the audience must stay exactly the
127
- # resolvable DM participants, never widened. Scope: ONLY the mapping list
128
- # directly under $2 in frontmatter.
129
- participant_ids() {
130
- awk -v k="$2" '
131
- { sub(/\r$/, "") }
132
- BEGIN{fm=0; inlist=0; have_pid=0; have_email=0; pid=""; em=""}
133
- function flush() {
134
- if (have_pid && pid != "") { print pid }
135
- else if (have_email && em != "") { print em }
136
- have_pid=0; have_email=0; pid=""; em=""
137
- }
138
- /^---$/ { fm++; if (fm==2) { if (inlist) flush(); exit } next }
139
- fm==1 && $0 ~ "^"k":" { inlist=1; next }
140
- fm==1 && inlist {
141
- # end of list = a line that is not indented beyond col 0 and not a bare "-"
142
- if ($0 ~ /^[^ \t-]/) { flush(); inlist=0; next }
143
- is_dash = ($0 ~ /^[[:space:]]*-[[:space:]]/)
144
- if (is_dash) {
145
- flush()
146
- s=$0; sub(/^[[:space:]]*-[[:space:]]*/, "", s)
147
- # inline mapping (JSON-style) on same line as the dash
148
- if (s ~ /^\{/) {
149
- gsub(/[{}"\x27]/, "", s); n=split(s, kv, ",")
150
- for (i=1;i<=n;i++) {
151
- gsub(/^[ \t]+|[ \t]+$/, "", kv[i])
152
- if (match(kv[i], /^person_uid[[:space:]]*:[[:space:]]*/)) { pid=substr(kv[i], RLENGTH+1); have_pid=1 }
153
- else if (match(kv[i], /^email[[:space:]]*:[[:space:]]*/)) { em=substr(kv[i], RLENGTH+1); have_email=1 }
154
- }
155
- flush()
156
- next
157
- }
158
- # First mapping key on same line as the dash, e.g.
159
- # - person_uid: prs_01ALICE
160
- # Fall through to the key/value handlers below with the de-dashed line.
161
- line = s
162
- } else {
163
- line = $0; sub(/^[[:space:]]+/, "", line)
164
- }
165
- if (line ~ /^person_uid:/) {
166
- v=line; sub(/^person_uid:[[:space:]]*/, "", v); gsub(/["\x27]/, "", v); gsub(/^[ \t]+|[ \t]+$/, "", v)
167
- if (v != "") { pid=v; have_pid=1 }
168
- next
169
- }
170
- if (line ~ /^email:/) {
171
- v=line; sub(/^email:[[:space:]]*/, "", v); gsub(/["\x27]/, "", v); gsub(/^[ \t]+|[ \t]+$/, "", v)
172
- if (v != "") { em=v; have_email=1 }
173
- next
174
- }
175
- }
176
- END { if (inlist) flush() }
177
- ' "$1"
178
- }
179
-
180
- n=0
181
- for f in "$D"/*.md; do
182
- [ -f "$f" ] || continue
183
- b="$(basename "$f")"
184
- is_processed "$b" && continue
185
- skipped_at_current "$b" && continue
186
- [ "$n" -ge "$limit" ] && break
187
- n=$((n+1))
188
- rel="sources/$ch/$b"
189
- aud=""
190
- case "$rule" in
191
- company) aud="company" ;;
192
- explicit) aud="$(item_list "$f" audience | paste -sd, -)" ;;
193
- *)
194
- aud="$(item_list "$f" audience | paste -sd, -)"
195
- [ -n "$aud" ] || aud="$(item_list "$f" attendees | grep -E '@|^(prs|agt)_' | paste -sd, -)"
196
- # Slack DM items (hq-pro inbound slack-personal-dm.ts) only carry
197
- # resolved_participants: a block list of mappings with person_uid /
198
- # slack_user_id / email. Derive audience from those, scoped exactly to
199
- # the DM's own participants (never widened to company). Only entries
200
- # whose person_uid or email resolves become audience ids; a slack_user_id
201
- # alone is not a usable audience key, so that entry is dropped — matching
202
- # the frontmatter contract exercised in hq-pro
203
- # test/sources/inbound/slack-personal-dm.test.ts.
204
- [ -n "$aud" ] || aud="$(participant_ids "$f" resolved_participants | grep -E '@|^(prs|agt)_' | paste -sd, -)"
205
- if [ -z "$aud" ]; then
206
- # A transient ACL or jq failure must not turn a source into a durable
207
- # no-audience skip. Retry once, while treating valid empty ACL output as
208
- # a completed lookup that needs no retry.
209
- for attempt in 1 2; do
210
- acl_output=""
211
- if acl_output="$("$HQ" files --company "$co" acl "$rel" --json 2>/dev/null \
212
- | jq -r '[.direct[]? | select(.granteeType=="person" or .granteeType=="email" or .granteeType=="agent") | select(.permission=="read" or .permission=="write" or .permission=="admin") | .granteeId] | unique | join(",")' 2>/dev/null)"; then
213
- aud="$acl_output"
214
- break
215
- fi
216
- aud=""
217
- done
218
- fi ;;
219
- esac
220
- if [ -z "$aud" ]; then
221
- printf '%s\t%s\t%s\n' "$b" "no-audience" "$PARSER_VERSION" >> "$skip_ledger"
222
- jq -cn --arg f "$rel" '{file:$f, skip:"no-audience"}'; continue
223
- fi
224
- key="$(HQ_ROOT="$root" bash "$here/ontology-candidate.sh" key "$aud")"
225
- jq -cn --arg f "$rel" --arg k "$key" --arg a "$aud" '{file:$f, audience_key:$k, audience:($a|split(","))}'
226
- done
@@ -1,36 +0,0 @@
1
- #!/usr/bin/env bash
2
- # source-yaml-validate.sh — validate a sources/{channel}/source.yaml.
3
- # Spec: core/knowledge/public/hq-core/source-yaml-spec.md
4
- # Usage: source-yaml-validate.sh <path/to/source.yaml>
5
- # Exit 0 valid; 1 invalid (each violation printed); 2 bad usage / missing file.
6
- set -uo pipefail
7
- f="${1:-}"
8
- [ -n "$f" ] || { echo "usage: source-yaml-validate.sh <source.yaml>" >&2; exit 2; }
9
- [ -f "$f" ] || { echo "source-yaml-validate: no such file $f" >&2; exit 2; }
10
-
11
- get() {
12
- awk -v k="$1" '$0 ~ "^"k":" { sub("^"k":[[:space:]]*", ""); sub("[[:space:]]+#.*$", ""); gsub(/^["\x27]|["\x27]$/, ""); print; exit }' "$f"
13
- }
14
- v=0
15
- bad() { echo "$f: $*"; v=$((v+1)); }
16
- oneof() { case " $3 " in *" $2 "*) ;; *) bad "$1 must be one of: $3 (got '${2:-<missing>}')" ;; esac; }
17
-
18
- channel="$(get channel)"; kind="$(get kind)"; arrives="$(get arrives)"; pull="$(get pull_command)"
19
- aud="$(get audience_rule)"; proc="$(get processor)"; run="$(get run)"; sched="$(get schedule)"
20
-
21
- [ -n "$channel" ] || bad "channel is required"
22
- folder="$(basename "$(dirname "$f")")"
23
- [ -z "$channel" ] || [ "$channel" = "$folder" ] || bad "channel '$channel' must equal its folder name '$folder'"
24
- oneof kind "$kind" "meeting email slack doc custom"
25
- oneof arrives "$arrives" "drop pull cloud"
26
- [ "$arrives" != pull ] || [ -n "$pull" ] || bad "pull_command is required when arrives: pull"
27
- [ -n "$aud" ] || bad "audience_rule is required (attendees|thread|channel|company|explicit); it is never defaulted"
28
- [ -z "$aud" ] || oneof audience_rule "$aud" "attendees thread channel company explicit"
29
- [ -n "$proc" ] || bad "processor is required (<worker>/<skill>)"
30
- [ -z "$proc" ] || printf '%s' "$proc" | grep -Eq '^[a-z0-9-]+/[a-z0-9-]+$' || bad "processor must look like <worker>/<skill> (got '$proc')"
31
- oneof run "$run" "local cloud"
32
- if [ -z "$sched" ]; then bad "schedule is required (cron or on-close)"
33
- elif [ "$sched" != on-close ] && [ "$(printf '%s' "$sched" | awk '{print NF}')" -ne 5 ]; then bad "schedule must be a 5-field cron or on-close (got '$sched')"; fi
34
-
35
- [ "$v" -eq 0 ] && { echo "$f: ok"; exit 0; }
36
- exit 1