@indigoai-us/hq-cli 5.309.1 → 5.310.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env bash
2
+ # hq-core: public
3
+ # US-011 — write session meta + reconcile with observation.trustedContext.
4
+ # No --trusted CLI flag in hq-cli; trusted bind is the observation field.
5
+ set -euo pipefail
6
+
7
+ ROOT="${HQ_ROOT:-${CLAUDE_PROJECT_DIR:-}}"
8
+ if [ -z "$ROOT" ]; then
9
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
10
+ fi
11
+
12
+ COMPANY=""
13
+ PROJECT=""
14
+ TASK=""
15
+ SESSION_ID=""
16
+ NO_RECONCILE=0
17
+
18
+ while [ $# -gt 0 ]; do
19
+ case "$1" in
20
+ --company|--company-slug) COMPANY="${2:-}"; shift 2 ;;
21
+ --project) PROJECT="${2:-}"; shift 2 ;;
22
+ --task) TASK="${2:-}"; shift 2 ;;
23
+ --session|--session-id) SESSION_ID="${2:-}"; shift 2 ;;
24
+ --no-reconcile) NO_RECONCILE=1; shift ;;
25
+ --root) ROOT="${2:-}"; shift 2 ;;
26
+ -h|--help)
27
+ sed -n '2,8p' "$0" | sed 's/^# \{0,1\}//'
28
+ exit 0
29
+ ;;
30
+ *) shift ;;
31
+ esac
32
+ done
33
+
34
+ HQ_SESSION="$ROOT/core/scripts/hq-session.sh"
35
+
36
+ # Resolve session id before metadata writes so a known session is pinned even
37
+ # when the caller omitted --session-id. Empty `pin` must still be safe on
38
+ # macOS Bash 3.2 (`set -u` + `"${pin[@]}"` is an unbound-variable abort).
39
+ if [ -z "$SESSION_ID" ]; then
40
+ SESSION_ID="${HQ_SESSION_ID:-${CLAUDE_CODE_SESSION_ID:-${CLAUDE_SESSION_ID:-${CODEX_SESSION_ID:-${CODEX_THREAD_ID:-}}}}}"
41
+ SESSION_ID="$(printf '%s' "$SESSION_ID" | tr -d '[:space:]')"
42
+ if [ -z "$SESSION_ID" ] && [ -f "$ROOT/workspace/sessions/.current" ]; then
43
+ SESSION_ID="$(tr -d '[:space:]' <"$ROOT/workspace/sessions/.current")"
44
+ fi
45
+ fi
46
+
47
+ pin=()
48
+ if [ -n "$SESSION_ID" ]; then
49
+ pin=(--session-id "$SESSION_ID")
50
+ fi
51
+
52
+ if [ -n "$COMPANY" ]; then
53
+ bash "$HQ_SESSION" ${pin[@]+"${pin[@]}"} set company_slug "$COMPANY"
54
+ fi
55
+ if [ -n "$PROJECT" ]; then
56
+ bash "$HQ_SESSION" ${pin[@]+"${pin[@]}"} set project "$PROJECT"
57
+ fi
58
+ if [ -n "$TASK" ]; then
59
+ bash "$HQ_SESSION" ${pin[@]+"${pin[@]}"} set task "$TASK"
60
+ fi
61
+
62
+ if [ "$NO_RECONCILE" -eq 1 ]; then
63
+ exit 0
64
+ fi
65
+
66
+ [ -n "$SESSION_ID" ] || exit 0
67
+
68
+ # shellcheck source=lib/work-mesh-enqueue.sh
69
+ . "$ROOT/core/scripts/lib/work-mesh-enqueue.sh" 2>/dev/null || true
70
+
71
+ HARNESS="${HQ_HARNESS:-${HQ_WORK_MESH_HARNESS:-claude-code}}"
72
+ case "$HARNESS" in
73
+ claude|Claude|ClaudeCode) HARNESS=claude-code ;;
74
+ Codex) HARNESS=codex ;;
75
+ Grok) HARNESS=grok ;;
76
+ esac
77
+ ADAPTER="${HQ_ADAPTER_CONTRACT_VERSION:-1.0.0}"
78
+
79
+ if command -v work_mesh_ulid >/dev/null 2>&1; then
80
+ work_mesh_ulid >/dev/null; CLIENT_OP=$REPLY
81
+ else
82
+ CLIENT_OP="cop_$(date +%s)_$$"
83
+ fi
84
+
85
+ json_quote() {
86
+ if command -v work_mesh_json_quote >/dev/null 2>&1; then
87
+ work_mesh_json_quote "$1"; printf '%s' "$REPLY"
88
+ return 0
89
+ fi
90
+ if command -v jq >/dev/null 2>&1; then
91
+ jq -n --arg s "$1" '$s'
92
+ return 0
93
+ fi
94
+ # bash-only fallback (hooks-no-python)
95
+ local s=$1
96
+ s=${s//'\'/'\\'}
97
+ s=${s//'"'/'\"'}
98
+ s=${s//$'\n'/'\n'}
99
+ s=${s//$'\r'/'\r'}
100
+ s=${s//$'\t'/'\t'}
101
+ printf '"%s"' "$s"
102
+ }
103
+
104
+ _q_sid="$(json_quote "$SESSION_ID")"
105
+ _q_har="$(json_quote "$HARNESS")"
106
+ _q_ad="$(json_quote "$ADAPTER")"
107
+ _q_op="$(json_quote "$CLIENT_OP")"
108
+ _q_cwd="$(json_quote "${PWD:-}")"
109
+ _q_root="$(json_quote "$ROOT")"
110
+
111
+ OBS='{"contractVersion":1,"clientOperationId":'"$_q_op"',"identity":{"sessionId":'"$_q_sid"',"harness":'"$_q_har"',"adapterVersion":'"$_q_ad"'},"cwd":'"$_q_cwd"',"hqRoot":'"$_q_root"
112
+ if [ -n "$COMPANY" ] || [ -n "$PROJECT" ] || [ -n "$TASK" ]; then
113
+ OBS+=',"trustedContext":{'
114
+ _first=1
115
+ if [ -n "$COMPANY" ]; then
116
+ OBS+='"companySlug":'"$(json_quote "$COMPANY")"
117
+ _first=0
118
+ fi
119
+ if [ -n "$PROJECT" ]; then
120
+ [ "$_first" -eq 1 ] || OBS+=','
121
+ OBS+='"project":'"$(json_quote "$PROJECT")"
122
+ _first=0
123
+ fi
124
+ if [ -n "$TASK" ]; then
125
+ [ "$_first" -eq 1 ] || OBS+=','
126
+ OBS+='"task":'"$(json_quote "$TASK")"
127
+ fi
128
+ OBS+='}'
129
+ fi
130
+ OBS+='}'
131
+
132
+ OBS_DIR="${TMPDIR:-/tmp}/hq-work-mesh-obs"
133
+ mkdir -p -- "$OBS_DIR" 2>/dev/null || true
134
+ chmod 700 -- "$OBS_DIR" 2>/dev/null || true
135
+ OBS_FILE="$OBS_DIR/$SESSION_ID.bind.$$.json"
136
+ printf '%s\n' "$OBS" >"$OBS_FILE"
137
+
138
+ if [ -n "${HQ_WORK_MESH_RECONCILE_LOG:-}" ]; then
139
+ printf 'reconcile-trusted %s\n' "$OBS_FILE" >>"$HQ_WORK_MESH_RECONCILE_LOG" 2>/dev/null || true
140
+ fi
141
+
142
+ if [ "${HQ_WORK_MESH_RECONCILE_STUB:-}" = "1" ]; then
143
+ exit 0
144
+ fi
145
+
146
+ HQ_BIN="$(command -v hq 2>/dev/null || true)"
147
+ if [ -n "$HQ_BIN" ] && [ -f "$OBS_FILE" ]; then
148
+ nohup "$HQ_BIN" mesh context reconcile --observation-file "$OBS_FILE" --machine \
149
+ >/dev/null 2>&1 </dev/null &
150
+ disown 2>/dev/null || true
151
+ fi
152
+ exit 0
@@ -5798,6 +5798,32 @@ export declare const COMMAND_CATALOG: readonly [{
5798
5798
  }];
5799
5799
  readonly options: readonly [];
5800
5800
  readonly subcommands: readonly [];
5801
+ }, {
5802
+ readonly name: "dm-bind";
5803
+ readonly description: "Bind this session to one HQ DM channel";
5804
+ readonly aliases: readonly [];
5805
+ readonly hidden: false;
5806
+ readonly usage: "[args...]";
5807
+ readonly arguments: readonly [{
5808
+ readonly name: "args";
5809
+ readonly required: false;
5810
+ readonly variadic: true;
5811
+ }];
5812
+ readonly options: readonly [];
5813
+ readonly subcommands: readonly [];
5814
+ }, {
5815
+ readonly name: "work-mesh-bind-trusted";
5816
+ readonly description: "Bind trusted session context and reconcile it with Work Mesh";
5817
+ readonly aliases: readonly [];
5818
+ readonly hidden: false;
5819
+ readonly usage: "[args...]";
5820
+ readonly arguments: readonly [{
5821
+ readonly name: "args";
5822
+ readonly required: false;
5823
+ readonly variadic: true;
5824
+ }];
5825
+ readonly options: readonly [];
5826
+ readonly subcommands: readonly [];
5801
5827
  }, {
5802
5828
  readonly name: "worktree-gc";
5803
5829
  readonly description: "Safely collect old, preserved HQ worktrees";
@@ -7468,6 +7468,38 @@ export const COMMAND_CATALOG = [
7468
7468
  "options": [],
7469
7469
  "subcommands": []
7470
7470
  },
7471
+ {
7472
+ "name": "dm-bind",
7473
+ "description": "Bind this session to one HQ DM channel",
7474
+ "aliases": [],
7475
+ "hidden": false,
7476
+ "usage": "[args...]",
7477
+ "arguments": [
7478
+ {
7479
+ "name": "args",
7480
+ "required": false,
7481
+ "variadic": true
7482
+ }
7483
+ ],
7484
+ "options": [],
7485
+ "subcommands": []
7486
+ },
7487
+ {
7488
+ "name": "work-mesh-bind-trusted",
7489
+ "description": "Bind trusted session context and reconcile it with Work Mesh",
7490
+ "aliases": [],
7491
+ "hidden": false,
7492
+ "usage": "[args...]",
7493
+ "arguments": [
7494
+ {
7495
+ "name": "args",
7496
+ "required": false,
7497
+ "variadic": true
7498
+ }
7499
+ ],
7500
+ "options": [],
7501
+ "subcommands": []
7502
+ },
7471
7503
  {
7472
7504
  "name": "worktree-gc",
7473
7505
  "description": "Safely collect old, preserved HQ worktrees",
@@ -0,0 +1,32 @@
1
+ /** Native implementation of core/scripts/hq-dm-bind.sh. */
2
+ import * as fs from "node:fs";
3
+ import type { Command } from "commander";
4
+ import { type UtilityOutput } from "./core-native-utilities.js";
5
+ export declare const DM_BIND_ASSET = "core/scripts/hq-dm-bind.sh";
6
+ export declare const DM_BIND_HELP = "# hq-dm-bind.sh \u2014 bind the current session to one HQ DM channel, post\n# structured updates to it, and listen for replies (feedback / requests).\n#\n# Usage:\n# core/scripts/hq-dm-bind.sh bind <channel> # bind + set the read cursor to \"now\"\n# core/scripts/hq-dm-bind.sh status # show the binding and cursor\n# core/scripts/hq-dm-bind.sh post --title <t> [--state <s>] [--line <l>]... [--next <l>]... [--ask <l>]... [--to <name>]... [--topic <t>] [--under <id>] [--new-thread]\n# core/scripts/hq-dm-bind.sh post --title <t> - < body.md # body from stdin (already structured)\n# core/scripts/hq-dm-bind.sh threads # list the channel's recent top-level threads (id, replies, author, text)\n# core/scripts/hq-dm-bind.sh roster # print the channel members a post will @-mention\n# core/scripts/hq-dm-bind.sh poll # print new messages since the cursor, advance it\n# core/scripts/hq-dm-bind.sh listen [--interval 60] [--timeout 1800]\n# # block until a new message arrives (or timeout)\n# core/scripts/hq-dm-bind.sh unbind\n#\n# The binding lives in the session's meta.yaml (`dm_channel`) via hq-session.sh;\n# the cursor is `workspace/sessions/<sid>/dm-bind.cursor` (the last seen sort\n# key from `hq dm channel --json`). `listen` is meant to run detached\n# (Bash run_in_background): it exits 0 and prints the new messages the moment\n# one lands, exits 3 on timeout with nothing new.\n#\n# Every post opens with an @-mention of every other member of the channel, so\n# the update reaches people (HQ mentions are structured: the `hq` CLI resolves\n# the `@\"Display Name\"` tokens against the roster and sends the real mention\n";
7
+ export type DmBindDeps = {
8
+ root: string;
9
+ cwd: string;
10
+ env: NodeJS.ProcessEnv;
11
+ home: string;
12
+ now: () => Date;
13
+ fs: typeof fs;
14
+ runHq: (args: string[], env: NodeJS.ProcessEnv) => {
15
+ code: number;
16
+ stdout: string;
17
+ stderr: string;
18
+ };
19
+ runHqSession: (args: string[], env: NodeJS.ProcessEnv) => {
20
+ code: number;
21
+ stdout: string;
22
+ stderr: string;
23
+ };
24
+ fetch: typeof fetch;
25
+ readStdin: () => Promise<string>;
26
+ sleep: (milliseconds: number) => Promise<void>;
27
+ };
28
+ export declare const createDmBindDeps: (root: string, cwd: string, env: NodeJS.ProcessEnv, now: () => Date, home?: string) => DmBindDeps;
29
+ export declare function resolveDmBindSessionId(d: Pick<DmBindDeps, "root" | "env" | "fs">): string;
30
+ export declare function runDmBind(args: string[], deps: DmBindDeps): Promise<UtilityOutput>;
31
+ export declare function registerCoreDmBindNative(core: Command): void;
32
+ //# sourceMappingURL=core-dm-bind-native.d.ts.map