@indigoai-us/hq-cli 5.345.160 → 5.345.162
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 +36 -0
- package/assets/scaffold/core/scripts/session-journal.sh +116 -24
- package/dist/command-catalog.generated.d.ts +262 -5
- package/dist/command-catalog.generated.js +322 -5
- package/dist/command-registration-plan.d.ts +6 -0
- package/dist/command-registration-plan.js +1 -0
- package/dist/commands/agent-inbox.js +6 -2
- package/dist/commands/auth.js +6 -5
- package/dist/commands/core-session-helper-runtime.d.ts +1 -0
- package/dist/commands/core-session-journal-native.d.ts +1 -0
- package/dist/commands/core-session-journal-native.js +158 -34
- package/dist/commands/feedback.d.ts +12 -0
- package/dist/commands/feedback.js +52 -0
- package/dist/commands/files-browse.d.ts +8 -0
- package/dist/commands/files-browse.js +83 -1
- package/dist/commands/install-global.d.ts +2 -0
- package/dist/commands/install-global.js +24 -1
- package/dist/commands/integrations-connect.js +1 -0
- package/dist/commands/integrations-manage.d.ts +2 -0
- package/dist/commands/integrations-manage.js +6 -4
- package/dist/commands/lanes-link.js +5 -3
- package/dist/commands/lanes-loop.js +7 -7
- package/dist/commands/lanes-questions.js +54 -4
- package/dist/commands/lanes-session-start.d.ts +12 -0
- package/dist/commands/lanes-session-start.js +93 -12
- package/dist/commands/lanes.js +2 -1
- package/dist/commands/meetings.d.ts +11 -0
- package/dist/commands/meetings.js +41 -11
- package/dist/commands/sync-held.d.ts +87 -0
- package/dist/commands/sync-held.js +191 -0
- package/dist/hq-cloud-sync-runner/bin/sync-runner.js +3830 -2812
- package/dist/hq-cloud-sync-runner/package.json +1 -1
- package/dist/index.js +21 -0
- package/dist/lanes-session-start-argv.d.ts +7 -0
- package/dist/lanes-session-start-argv.js +9 -0
- package/dist/lib/agent-kit/inbox-state.d.ts +5 -4
- package/dist/lib/agent-kit/inbox-state.js +24 -3
- package/dist/lib/bot/log.d.ts +3 -2
- package/dist/lib/bot/progress.d.ts +23 -1
- package/dist/lib/bot/progress.js +43 -5
- package/dist/lib/bot/run.js +2 -0
- package/dist/lib/bot/runtime/claude.d.ts +12 -0
- package/dist/lib/bot/runtime/claude.js +20 -0
- package/dist/lib/bot/runtime/index.d.ts +10 -1
- package/dist/lib/bot/runtime/index.js +14 -2
- package/dist/lib/bot/runtime/types.d.ts +8 -0
- package/dist/lib/doctor/checks/ps1-shims.d.ts +21 -0
- package/dist/lib/doctor/checks/ps1-shims.js +82 -0
- package/dist/lib/doctor/fix/apply.d.ts +13 -1
- package/dist/lib/doctor/fix/apply.js +38 -3
- package/dist/lib/doctor/fix/remediation.d.ts +9 -1
- package/dist/lib/doctor/fix/remediation.js +22 -0
- package/dist/lib/doctor/registry.js +2 -0
- package/dist/lib/flag-registry-worker-source.generated.d.ts +1 -1
- package/dist/lib/flag-registry-worker-source.generated.js +1 -1
- package/dist/lib/lanes/links.d.ts +2 -1
- package/dist/lib/lanes/links.js +235 -17
- package/dist/lib/lanes/loop.d.ts +17 -0
- package/dist/lib/lanes/loop.js +235 -5
- package/dist/lib/lanes/questions.d.ts +1 -0
- package/dist/lib/lanes/registry-flag.d.ts +24 -0
- package/dist/lib/lanes/registry-flag.js +72 -6
- package/dist/lib/lanes/store.d.ts +4 -2
- package/dist/lib/lanes/store.js +8 -8
- package/dist/lib/windows/ps1-shims.d.ts +60 -0
- package/dist/lib/windows/ps1-shims.js +152 -0
- package/dist/utils/self-update.d.ts +2 -0
- package/dist/utils/self-update.js +8 -0
- package/dist/utils/staged-npm-install.js +13 -2
- package/dist/utils/token-keychain.d.ts +11 -8
- package/dist/utils/token-keychain.js +36 -15
- package/package.json +8 -8
- package/scripts/install-hook-engine.mjs +12 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,42 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [5.345.162] — 2026-10-23
|
|
6
|
+
- `hq agent inbox` no longer reports malformed server responses as a verified empty inbox. Invalid JSON or a missing/non-array `messages` field keeps `source: "local-mirror"` and a privacy-safe warning. Mixed responses retain usable messages with `source: "server-partial"` and an incomplete-result warning; only `source: "server"` certifies completeness. Human output also says when an empty result is unverified. Reads still never send replies or acknowledgments.
|
|
7
|
+
- The bundled sync engine now uses hq-cloud 6.18.100, the current npm `latest`.
|
|
8
|
+
After an account switch, HQ Sync no longer pushes files left behind by the
|
|
9
|
+
previous person (hq-cloud #1040).
|
|
10
|
+
- Park a loop when its phase handoff remains malformed after repair, preserving
|
|
11
|
+
worker evidence and later queued work. The existing question flow can accept a
|
|
12
|
+
validated repaired handoff without rerunning the phase, explicitly retry with
|
|
13
|
+
an external-effects warning, or leave the phase held. Durable holds survive
|
|
14
|
+
controller restart, and explicit interruption and stop remain available.
|
|
15
|
+
- New `hq sync held` and `hq sync release-held`. After someone else signs in on the same computer, HQ sync holds every upload and cloud delete for the personal vault and each company until the signed-in person releases them. `hq sync held` lists what is held, with a count and sample paths. `hq sync release-held` shows the signed-in person's held scopes, asks "Are these files yours to upload?" and releases them (`--company <slug>`, `--personal`, `--yes`, `--json`). It identifies the person from the current session token, so a session without an email works, and it releases nothing if the signed-in account changes during the command. Both commands need an HQ sync engine with this hold; on an older one they say to update HQ. Feedback 3bf773c5-320e-433d-b84b-0bab13147ff5.
|
|
16
|
+
|
|
17
|
+
## [5.345.161] — 2026-10-23
|
|
18
|
+
- The bundled sync engine now uses hq-cloud 6.18.99, the current npm `latest`.
|
|
19
|
+
HQ Sync follows the server's telemetry decision for free-plan accounts,
|
|
20
|
+
failed company and personal sync legs report a short error summary with no
|
|
21
|
+
file names or paths, and the shell-script line-ending fix never rewrites a
|
|
22
|
+
file whose signature marks it as binary (hq-cloud #1039, #1043, #1044).
|
|
23
|
+
- Fence session-journal counter owners with atomically published PID and owner-token records. Reclaim dead or aged PID-less publisher claims and aged orphan temp directories; holders that lose ownership retry before their callback or counter write.
|
|
24
|
+
- `hq files cat` / `get` and the agent file tools now name the storage host when a signed vault download cannot connect (connection refused or reset, DNS failure, timeout, or a TLS failure from an HTTPS-inspecting proxy) and tell the operator to allow outbound HTTPS (TCP 443) to that host. Before this, the raw `fetch failed` error surfaced with no host.
|
|
25
|
+
- New `hq feedback assign <id> --to <email|prs_uid>` reassigns a feedback ticket with your own login, including a ticket another person claimed. Agent and operator tokens still get `TICKET_CLAIMED_BY_HUMAN` for those tickets, and the command says to rerun it from your own login.
|
|
26
|
+
- `hq integrations share`, `unshare`, `grant` and `ungrant` help now says the principal can be a vault group (`grp_…`), which the commands already accepted. Group membership is resolved when a tool is called, and `hq integrations access` shows the group's name once the server returns it.
|
|
27
|
+
- Bot turns on the Claude runtime now bound each Bash tool call to 10 minutes (`BASH_DEFAULT_TIMEOUT_MS` / `BASH_MAX_TIMEOUT_MS`, kept when already set), and the runtime process is started with stdin closed, so a bot-authored command that waits on stdin (`cat > /dev/null`) can no longer hold a turn "working" indefinitely.
|
|
28
|
+
- A bot no longer posts a short assistant aside (under 40 characters, no `hq-block`) that a tool call follows in the same assistant message ("Bind first, separately."); it is logged at debug level instead. Full-sentence progress notes still post.
|
|
29
|
+
- `hq integrations reconnect` now accepts `--scopes <list>` like `connect` (space- or comma-separated). Use it when a provider such as Meta refuses a sign-in request that names no scopes.
|
|
30
|
+
- Keep explicitly delivered conductor instructions replayable until the receiving
|
|
31
|
+
session acknowledges their stable receipt. Timing out or discarding hook output
|
|
32
|
+
no longer counts as instruction acceptance when the paired hook is installed.
|
|
33
|
+
|
|
34
|
+
- Malformed rows now retain a private audit without preventing valid later
|
|
35
|
+
instructions from being accepted. Active Stop retries do not block repeatedly.
|
|
36
|
+
- Keep temporary macOS Keychain read failures retryable instead of recording them as denied access, explain saved-sign-in fallback, and give explicit retries time to answer the prompt.
|
|
37
|
+
- `hq lanes session-start` (the SessionStart auto-conduct hook) no longer reads the lanes registry flags over the network on every new session. It reads them from the local flag cache and person flag snapshot, fails open when none is known, and refreshes old or missing values in the background. It also skips loading the full command graph. On a warm cache it now returns in about 0.3 s instead of about 3 s, so the hook stays under its 2 s cap and the auto-conduct context is no longer dropped. Feedback 4db60cce.
|
|
38
|
+
- `hq meetings list`, `get`, `transcript`, `search` and the other read subcommands now default to the bound company when the caller explicitly names its HQ session in the environment and omits `--company`. Before this they sent no company at all, so a bound session saw only the caller's personal recordings and missed the company's. Plain terminals and cron calls keep the server default; they never borrow the shared last-session pointer. `--company` still overrides, and `set-company` still requires an explicit target. Feedback 04771691-fcbc-4847-899a-6c966c561b52.
|
|
39
|
+
- On Windows, remove npm's `hq.ps1` and `hq-auth-refresh.ps1` launchers after install, update and `hq install --global`, so PowerShell runs `hq.cmd` instead of failing with UnauthorizedAccess under the default Restricted execution policy. `hq doctor` reports a blocked launcher that is still present and `hq doctor --fix` removes it. The execution policy is only read, never changed.
|
|
40
|
+
|
|
5
41
|
## [5.345.160] — 2026-10-22
|
|
6
42
|
- The bundled sync engine now uses hq-cloud 6.18.98. When HQ pauses an account because of usage, `hq sync` now shows the server's usage-pause message and a Billing link instead of a generic failure (hq-cloud #1036).
|
|
7
43
|
- `hq billing usage` now shows the amounts on HQ's usage statement, which is what the invoice bills. Before this it re-priced the meters itself, so it could show a different figure than the statement, for example charging the vault fee during the trial when the statement waived it.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# Spec: core/knowledge/public/hq-core/session-journal-spec.md
|
|
4
4
|
#
|
|
5
5
|
# Usage:
|
|
6
|
-
# session-journal.sh write "<title>" [--files f1,f2,...] [--body-file PATH] [--session KEY]
|
|
6
|
+
# session-journal.sh write "<title>" [--files f1,f2,...] [--body-file PATH] [--session KEY] [--company SLUG]
|
|
7
7
|
# session-journal.sh list [--date YYYY-MM-DD]
|
|
8
8
|
# session-journal.sh read <NNN> [--date YYYY-MM-DD]
|
|
9
9
|
# session-journal.sh index-path [--date YYYY-MM-DD] # prints the INDEX.md path
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
# "unscoped". A date-global counter let concurrent Claude and Codex tasks
|
|
19
19
|
# trigger and reset each other's journal reminders.
|
|
20
20
|
#
|
|
21
|
+
# HQ_JOURNAL_COUNTER_NOW overrides epoch seconds only in the counter-lock age check, for deterministic tests.
|
|
21
22
|
# All commands fail-soft: warn to stderr, exit 0 — never block the caller.
|
|
22
23
|
|
|
23
24
|
set -uo pipefail
|
|
@@ -131,7 +132,8 @@ resolve_session_key() {
|
|
|
131
132
|
counter_lock_is_aged() {
|
|
132
133
|
local lockdir="$1" lock_mtime now
|
|
133
134
|
lock_mtime="$(stat -c %Y "$lockdir" 2>/dev/null)" || lock_mtime="$(stat -f %m "$lockdir" 2>/dev/null)" || return 1
|
|
134
|
-
now="$(date -u +%s 2>/dev/null)"
|
|
135
|
+
now="${HQ_JOURNAL_COUNTER_NOW:-$(date -u +%s 2>/dev/null)}"
|
|
136
|
+
[ -n "$now" ] || return 1
|
|
135
137
|
case "$lock_mtime:$now" in *[!0-9:]*|:*|*:) return 1 ;; esac
|
|
136
138
|
[ "$now" -ge "$lock_mtime" ] && [ "$((now - lock_mtime))" -ge 60 ]
|
|
137
139
|
}
|
|
@@ -158,8 +160,9 @@ counter_lock_owner_is_alive() {
|
|
|
158
160
|
}
|
|
159
161
|
|
|
160
162
|
reclaim_stale_counter_lock() {
|
|
161
|
-
local lockdir="$1" owner_pid current_owner current_windows_pid windows_pid claim stale_dir suffix=0 pidless=0
|
|
163
|
+
local lockdir="$1" owner_pid current_owner current_windows_pid windows_pid owner_token current_token claim stale_dir suffix=0 pidless=0
|
|
162
164
|
owner_pid="$(cat "$lockdir/pid" 2>/dev/null || true)"
|
|
165
|
+
owner_token="$(cat "$lockdir/owner-token" 2>/dev/null || true)"
|
|
163
166
|
case "$owner_pid" in
|
|
164
167
|
'')
|
|
165
168
|
windows_pid="$(cat "$lockdir/winpid" 2>/dev/null || true)"
|
|
@@ -189,6 +192,7 @@ reclaim_stale_counter_lock() {
|
|
|
189
192
|
|
|
190
193
|
current_owner="$(cat "$lockdir/pid" 2>/dev/null || true)"
|
|
191
194
|
current_windows_pid="$(cat "$lockdir/winpid" 2>/dev/null || true)"
|
|
195
|
+
current_token="$(cat "$lockdir/owner-token" 2>/dev/null || true)"
|
|
192
196
|
if [ "$pidless" -eq 1 ]; then
|
|
193
197
|
# Recheck both identity and age after winning the claim, before renaming.
|
|
194
198
|
if [ -z "$current_owner" ] && [ "$current_windows_pid" = "$windows_pid" ] \
|
|
@@ -200,6 +204,7 @@ reclaim_stale_counter_lock() {
|
|
|
200
204
|
fi
|
|
201
205
|
fi
|
|
202
206
|
if [ "$current_owner" = "$owner_pid" ] && [ "$current_windows_pid" = "${windows_pid:-$(cat "$lockdir/winpid" 2>/dev/null || true)}" ] \
|
|
207
|
+
&& [ "$current_token" = "$owner_token" ] \
|
|
203
208
|
&& { [ "$pidless" -eq 1 ] || ! counter_lock_owner_is_alive "$lockdir" "$owner_pid"; }; then
|
|
204
209
|
stale_dir="${lockdir}.stale.$$.$RANDOM"
|
|
205
210
|
while [ -e "$stale_dir" ]; do
|
|
@@ -217,38 +222,111 @@ reclaim_stale_counter_lock() {
|
|
|
217
222
|
return 1
|
|
218
223
|
}
|
|
219
224
|
|
|
225
|
+
reclaim_stale_counter_tempdirs() {
|
|
226
|
+
local lockdir="$1" candidate owner_pid windows_pid owner_token current_pid current_windows current_token stale_dir suffix=0
|
|
227
|
+
# Publishers create <lock>.tmp.XXXXXX. Older native hq-cli builds used
|
|
228
|
+
# <lock>.tmp-XXXXXX, so reclaim aged orphans with either prefix.
|
|
229
|
+
for candidate in "${lockdir}.tmp."* "${lockdir}.tmp-"*; do
|
|
230
|
+
[ -d "$candidate" ] || continue
|
|
231
|
+
counter_lock_is_aged "$candidate" || continue
|
|
232
|
+
owner_pid="$(cat "$candidate/pid" 2>/dev/null || true)"
|
|
233
|
+
windows_pid="$(cat "$candidate/winpid" 2>/dev/null || true)"
|
|
234
|
+
owner_token="$(cat "$candidate/owner-token" 2>/dev/null || true)"
|
|
235
|
+
case "$owner_pid" in
|
|
236
|
+
'')
|
|
237
|
+
if [ -n "$windows_pid" ] && counter_windows_pid_is_alive "$windows_pid"; then continue; fi
|
|
238
|
+
;;
|
|
239
|
+
*[!0-9]*) continue ;;
|
|
240
|
+
*)
|
|
241
|
+
[ "$owner_pid" -gt 1 ] 2>/dev/null || continue
|
|
242
|
+
counter_lock_owner_is_alive "$candidate" "$owner_pid" && continue
|
|
243
|
+
;;
|
|
244
|
+
esac
|
|
245
|
+
current_pid="$(cat "$candidate/pid" 2>/dev/null || true)"
|
|
246
|
+
current_windows="$(cat "$candidate/winpid" 2>/dev/null || true)"
|
|
247
|
+
current_token="$(cat "$candidate/owner-token" 2>/dev/null || true)"
|
|
248
|
+
[ "$current_pid" = "$owner_pid" ] && [ "$current_windows" = "$windows_pid" ] \
|
|
249
|
+
&& [ "$current_token" = "$owner_token" ] && counter_lock_is_aged "$candidate" || continue
|
|
250
|
+
[ -z "$current_pid" ] || ! counter_lock_owner_is_alive "$candidate" "$current_pid" || continue
|
|
251
|
+
[ -z "$current_windows" ] || ! counter_windows_pid_is_alive "$current_windows" || continue
|
|
252
|
+
stale_dir="${candidate}.stale.$$.$RANDOM"
|
|
253
|
+
while [ -e "$stale_dir" ]; do suffix=$((suffix + 1)); stale_dir="${candidate}.stale.$$.$RANDOM.$suffix"; done
|
|
254
|
+
if mv "$candidate" "$stale_dir" 2>/dev/null; then rm -rf "$stale_dir" 2>/dev/null || true; fi
|
|
255
|
+
done
|
|
256
|
+
}
|
|
257
|
+
|
|
220
258
|
with_counter_lock() {
|
|
221
259
|
local lockdir="$1"; shift
|
|
222
|
-
local i=0 acquired=0 rc=0 tries="${HQ_JOURNAL_COUNTER_LOCK_TRIES:-250}"
|
|
260
|
+
local i=0 acquired=0 rc=0 tries="${HQ_JOURNAL_COUNTER_LOCK_TRIES:-250}" owner_token tempdir windows_pid token_file publish_claim
|
|
223
261
|
case "$tries" in ''|*[!0-9]*) tries=250 ;; esac
|
|
224
262
|
while [ "$i" -lt "$tries" ]; do
|
|
225
|
-
|
|
226
|
-
|
|
263
|
+
reclaim_stale_counter_tempdirs "$lockdir"
|
|
264
|
+
# Publish a complete owner record in one rename. Legacy clients may still
|
|
265
|
+
# leave PID-less lock directories, which the age-based reclaim handles.
|
|
266
|
+
tempdir="$(mktemp -d "${lockdir}.tmp.XXXXXX" 2>/dev/null)" || tempdir=""
|
|
267
|
+
if [ -n "$tempdir" ]; then
|
|
268
|
+
owner_token="$$.$RANDOM.$RANDOM.$(date -u +%s 2>/dev/null)"
|
|
227
269
|
if [[ "${OSTYPE:-}" == msys* ]] || [[ "${OSTYPE:-}" == cygwin* ]]; then
|
|
228
|
-
local windows_pid
|
|
229
270
|
windows_pid="$(cat "/proc/$$/winpid" 2>/dev/null || true)"
|
|
230
|
-
case "$windows_pid" in ''|*[!0-9]*)
|
|
271
|
+
case "$windows_pid" in ''|*[!0-9]*) windows_pid="" ;; esac
|
|
272
|
+
if [ -n "$windows_pid" ] && ! printf '%s\n' "$windows_pid" > "$tempdir/winpid"; then rm -rf "$tempdir"; tempdir=""; fi
|
|
231
273
|
fi
|
|
232
|
-
if
|
|
233
|
-
|
|
234
|
-
|
|
274
|
+
if [ -n "$tempdir" ] && printf '%s\n' "$$" > "$tempdir/pid" \
|
|
275
|
+
&& printf '%s\n' "$owner_token" > "$tempdir/owner-token"; then
|
|
276
|
+
# Serialize publishers so mv cannot interpret a concurrently-created
|
|
277
|
+
# lock directory as a destination directory and nest the temp folder.
|
|
278
|
+
publish_claim="${lockdir}.publish"
|
|
279
|
+
if mkdir "$publish_claim" 2>/dev/null; then
|
|
280
|
+
# Exclusive token creation fences a publisher resumed after a stale
|
|
281
|
+
# PID-less claim was reclaimed and reused by another process.
|
|
282
|
+
if (set -C; printf '%s\n' "$owner_token" > "$publish_claim/owner-token") 2>/dev/null \
|
|
283
|
+
&& [ "$(cat "$publish_claim/owner-token" 2>/dev/null || true)" = "$owner_token" ] \
|
|
284
|
+
&& (set -C; printf '%s\n' "$$" > "$publish_claim/pid") 2>/dev/null \
|
|
285
|
+
&& [ "$(cat "$publish_claim/owner-token" 2>/dev/null || true)" = "$owner_token" ] \
|
|
286
|
+
&& [ ! -e "$lockdir" ] && mv "$tempdir" "$lockdir" 2>/dev/null; then :; fi
|
|
287
|
+
if [ "$(cat "$publish_claim/owner-token" 2>/dev/null || true)" = "$owner_token" ]; then
|
|
288
|
+
rm -rf "$publish_claim" 2>/dev/null || true
|
|
289
|
+
fi
|
|
290
|
+
else
|
|
291
|
+
rm -rf "$tempdir" 2>/dev/null || true
|
|
292
|
+
reclaim_stale_counter_lock "$publish_claim" && continue
|
|
293
|
+
fi
|
|
294
|
+
if [ ! -e "$tempdir" ] && [ "$(cat "$lockdir/owner-token" 2>/dev/null || true)" = "$owner_token" ]; then
|
|
295
|
+
acquired=1
|
|
296
|
+
rmdir "$tempdir" 2>/dev/null || true
|
|
297
|
+
token_file="$lockdir/owner-token"
|
|
298
|
+
if [ "$(cat "$token_file" 2>/dev/null || true)" = "$owner_token" ]; then
|
|
299
|
+
"$@" "$owner_token"
|
|
300
|
+
rc=$?
|
|
301
|
+
if [ "$rc" -eq 75 ]; then
|
|
302
|
+
acquired=0
|
|
303
|
+
i=$((i + 1))
|
|
304
|
+
continue
|
|
305
|
+
fi
|
|
306
|
+
if [ "$(cat "$token_file" 2>/dev/null || true)" = "$owner_token" ]; then
|
|
307
|
+
rm -rf "$lockdir" 2>/dev/null || true
|
|
308
|
+
fi
|
|
309
|
+
return "$rc"
|
|
310
|
+
fi
|
|
311
|
+
acquired=0
|
|
312
|
+
i=$((i + 1))
|
|
313
|
+
continue
|
|
314
|
+
fi
|
|
315
|
+
if [ ! -e "$tempdir" ]; then rm -rf "$lockdir/$(basename "$tempdir")" 2>/dev/null || true; fi
|
|
235
316
|
fi
|
|
236
|
-
|
|
317
|
+
if [ -n "$tempdir" ]; then rm -rf "$tempdir" 2>/dev/null || true; fi
|
|
237
318
|
fi
|
|
238
319
|
reclaim_stale_counter_lock "$lockdir" && continue
|
|
239
320
|
i=$((i + 1))
|
|
240
321
|
[ "$i" -ge "$tries" ] || sleep 0.02 2>/dev/null || sleep 1
|
|
241
322
|
done
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
fi
|
|
323
|
+
warn "tool-counter: lock remained busy; skipped update"
|
|
324
|
+
return 0
|
|
325
|
+
}
|
|
246
326
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
fi
|
|
251
|
-
return "$rc"
|
|
327
|
+
counter_lock_token_is_current() {
|
|
328
|
+
local lockdir="$1" owner_token="$2"
|
|
329
|
+
[ -n "$owner_token" ] && [ "$(cat "$lockdir/owner-token" 2>/dev/null || true)" = "$owner_token" ]
|
|
252
330
|
}
|
|
253
331
|
|
|
254
332
|
counter_read_raw() {
|
|
@@ -303,8 +381,10 @@ case "$cmd" in
|
|
|
303
381
|
files_csv=""
|
|
304
382
|
body_file=""
|
|
305
383
|
session_arg=""
|
|
384
|
+
company_arg="${HQ_ACTIVE_COMPANY:-}"
|
|
306
385
|
while [ $# -gt 0 ]; do
|
|
307
386
|
case "$1" in
|
|
387
|
+
--company) company_arg="${2:-}"; shift 2 || break ;;
|
|
308
388
|
--files) files_csv="${2:-}"; shift 2 || break ;;
|
|
309
389
|
--body-file) body_file="${2:-}"; shift 2 || break ;;
|
|
310
390
|
--session) session_arg="${2:-}"; shift 2 || break ;;
|
|
@@ -313,6 +393,9 @@ case "$cmd" in
|
|
|
313
393
|
done
|
|
314
394
|
|
|
315
395
|
[ -z "$title" ] && { warn "write: title required"; exit 0; }
|
|
396
|
+
# The bound company tags the entry so the SessionStart index loader can
|
|
397
|
+
# surface only that company's entries. Anything not slug-shaped is dropped.
|
|
398
|
+
[[ "$company_arg" =~ ^[A-Za-z0-9_-]+$ ]] || company_arg=""
|
|
316
399
|
|
|
317
400
|
d="$(today)"
|
|
318
401
|
dir="$(journal_dir_for "$d")"
|
|
@@ -346,6 +429,7 @@ case "$cmd" in
|
|
|
346
429
|
printf 'ts: %s\n' "$(now_iso_z)"
|
|
347
430
|
printf 'title: %s\n' "$yaml_title"
|
|
348
431
|
printf 'slug: %s\n' "$yaml_slug"
|
|
432
|
+
[ -z "$company_arg" ] || printf 'company: %s\n' "$company_arg"
|
|
349
433
|
if [ -n "$files_csv" ]; then
|
|
350
434
|
printf 'files:\n'
|
|
351
435
|
old_ifs="$IFS"
|
|
@@ -384,7 +468,9 @@ case "$cmd" in
|
|
|
384
468
|
if [ ! -f "$idx" ]; then
|
|
385
469
|
printf '# Session journal — %s\n\n' "$d" > "$idx"
|
|
386
470
|
fi
|
|
387
|
-
|
|
471
|
+
company_tag=""
|
|
472
|
+
[ -z "$company_arg" ] || company_tag=" [company: $company_arg]"
|
|
473
|
+
printf -- '- `%s` %s — %s%s\n' "$seq" "$(now_hhmm_z)" "$title" "$company_tag" >> "$idx" \
|
|
388
474
|
|| warn "write: INDEX update failed"
|
|
389
475
|
|
|
390
476
|
# Reset the tool counter for THIS session only — journaling one task's
|
|
@@ -452,8 +538,10 @@ case "$cmd" in
|
|
|
452
538
|
case "$sub" in
|
|
453
539
|
increment)
|
|
454
540
|
do_increment() {
|
|
455
|
-
local n
|
|
541
|
+
local owner_token="${1:-}" n
|
|
542
|
+
counter_lock_token_is_current "$lockdir" "$owner_token" || return 75
|
|
456
543
|
n=$(counter_read_raw "$counter")
|
|
544
|
+
counter_lock_token_is_current "$lockdir" "$owner_token" || return 75
|
|
457
545
|
echo $((n + 1)) > "$counter" 2>/dev/null || true
|
|
458
546
|
}
|
|
459
547
|
with_counter_lock "$lockdir" do_increment
|
|
@@ -462,7 +550,11 @@ case "$cmd" in
|
|
|
462
550
|
printf '%d\n' "$(counter_read_raw "$counter")"
|
|
463
551
|
;;
|
|
464
552
|
reset)
|
|
465
|
-
do_reset() {
|
|
553
|
+
do_reset() {
|
|
554
|
+
local owner_token="${1:-}"
|
|
555
|
+
counter_lock_token_is_current "$lockdir" "$owner_token" || return 75
|
|
556
|
+
echo 0 > "$counter" 2>/dev/null || true
|
|
557
|
+
}
|
|
466
558
|
with_counter_lock "$lockdir" do_reset
|
|
467
559
|
;;
|
|
468
560
|
*) warn "tool-counter: subcommand required (increment|read|reset)" ;;
|