@indigoai-us/hq-cli 5.293.0 → 5.295.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.
Files changed (97) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/assets/scaffold/core/scripts/outpost-jobs-reconcile.sh +5 -1
  3. package/dist/command-catalog.generated.d.ts +54 -33
  4. package/dist/command-catalog.generated.js +68 -42
  5. package/dist/commands/auth.d.ts +1 -0
  6. package/dist/commands/auth.js +76 -1
  7. package/dist/commands/core-command-catalog.js +3 -2
  8. package/dist/commands/core-delegate-w1b.d.ts +2 -0
  9. package/dist/commands/core-delegate-w1b.js +28 -2
  10. package/dist/commands/core-delegate.d.ts +3 -1
  11. package/dist/commands/core-delegate.js +35 -5
  12. package/dist/commands/core-handoff-fast.d.ts +18 -0
  13. package/dist/commands/core-handoff-fast.js +103 -0
  14. package/dist/commands/core-handoff-open-steps.d.ts +21 -0
  15. package/dist/commands/core-handoff-open-steps.js +264 -0
  16. package/dist/commands/core-handoff.d.ts +4 -2
  17. package/dist/commands/core-handoff.js +22 -249
  18. package/dist/commands/core-jobs-native.d.ts +2 -0
  19. package/dist/commands/core-jobs-native.js +22 -11
  20. package/dist/commands/core-knowledge-prefs.d.ts +2 -0
  21. package/dist/commands/core-knowledge-prefs.js +13 -1
  22. package/dist/commands/core-ontology-native.d.ts +2 -0
  23. package/dist/commands/core-ontology-native.js +22 -2
  24. package/dist/commands/core-policy.d.ts +2 -0
  25. package/dist/commands/core-policy.js +18 -1
  26. package/dist/commands/core.js +2 -1
  27. package/dist/commands/daemon.d.ts +2 -1
  28. package/dist/commands/daemon.js +22 -7
  29. package/dist/commands/doctor.js +0 -74
  30. package/dist/commands/lanes-autopilot.d.ts +11 -0
  31. package/dist/commands/lanes-autopilot.js +336 -0
  32. package/dist/commands/lanes-message.js +23 -5
  33. package/dist/commands/lanes-questions.js +8 -5
  34. package/dist/commands/lanes-resume.js +0 -3
  35. package/dist/commands/lanes-shared.d.ts +18 -2
  36. package/dist/commands/lanes-stories.d.ts +14 -0
  37. package/dist/commands/lanes-stories.js +308 -0
  38. package/dist/commands/lanes.d.ts +1 -9
  39. package/dist/commands/lanes.js +216 -481
  40. package/dist/fast-core.js +53 -25
  41. package/dist/fast-scaffold.d.ts +15 -7
  42. package/dist/fast-scaffold.js +167 -17
  43. package/dist/index.js +1 -10
  44. package/dist/lib/core-utils/sentry-report.d.ts +0 -19
  45. package/dist/lib/core-utils/sentry-report.js +8 -61
  46. package/dist/lib/core-utils/worktree-resume.d.ts +2 -0
  47. package/dist/lib/core-utils/worktree-resume.js +16 -0
  48. package/dist/lib/daemon/migrate.d.ts +8 -1
  49. package/dist/lib/daemon/migrate.js +19 -7
  50. package/dist/lib/doctor/checks/claude-wiring.js +9 -0
  51. package/dist/lib/lanes/autopilot-metrics.d.ts +99 -0
  52. package/dist/lib/lanes/autopilot-metrics.js +301 -0
  53. package/dist/lib/lanes/flag-keys.d.ts +2 -0
  54. package/dist/lib/lanes/flag-keys.js +2 -0
  55. package/dist/lib/lanes/manager-status-gate.d.ts +0 -17
  56. package/dist/lib/lanes/manager-status-gate.js +2 -43
  57. package/dist/lib/lanes/outpost-dispatch.d.ts +2 -0
  58. package/dist/lib/lanes/outpost-dispatch.js +7 -1
  59. package/dist/lib/lanes/outpost-hire-cache.d.ts +0 -1
  60. package/dist/lib/lanes/outpost-hire-cache.js +0 -1
  61. package/dist/lib/lanes/outpost-snapshot-memo.d.ts +6 -0
  62. package/dist/lib/lanes/outpost-snapshot-memo.js +14 -0
  63. package/dist/lib/lanes/reconcile.d.ts +2 -3
  64. package/dist/lib/lanes/reconcile.js +44 -38
  65. package/dist/lib/lanes/spawn.d.ts +0 -2
  66. package/dist/lib/lanes/spawn.js +18 -5
  67. package/dist/lib/lanes/store.d.ts +2 -0
  68. package/dist/lib/lanes/store.js +54 -3
  69. package/dist/lib/lanes/types.d.ts +18 -1
  70. package/dist/lib/lanes/types.js +1 -1
  71. package/dist/lib/lanes/watcher.d.ts +4 -3
  72. package/dist/lib/lanes/watcher.js +102 -34
  73. package/dist/lib/mesh/live/daemon/run.js +18 -1
  74. package/dist/native-fast-route.d.ts +3 -1
  75. package/dist/native-fast-route.js +10 -8
  76. package/dist/utils/cognito-session.d.ts +6 -0
  77. package/dist/utils/cognito-session.js +9 -0
  78. package/dist/utils/contribution-table.d.ts +1 -1
  79. package/dist/utils/fast-stream-errors.d.ts +12 -0
  80. package/dist/utils/fast-stream-errors.js +18 -0
  81. package/dist/utils/scaffold-fast-import-guard.d.ts +2 -2
  82. package/dist/utils/scaffold-fast-import-guard.js +6 -3
  83. package/dist/utils/self-update.js +31 -0
  84. package/dist/utils/version-gate.js +22 -3
  85. package/package.json +1 -1
  86. package/dist/fast-lanes-list-route.d.ts +0 -8
  87. package/dist/fast-lanes-list-route.js +0 -32
  88. package/dist/fast-lanes-list.d.ts +0 -3
  89. package/dist/fast-lanes-list.js +0 -224
  90. package/dist/lib/doctor/client-health-sentry-flag.d.ts +0 -23
  91. package/dist/lib/doctor/client-health-sentry-flag.js +0 -99
  92. package/dist/lib/doctor/client-health-sentry.d.ts +0 -71
  93. package/dist/lib/doctor/client-health-sentry.js +0 -286
  94. package/dist/lib/lanes/outpost-snapshot-cache.d.ts +0 -26
  95. package/dist/lib/lanes/outpost-snapshot-cache.js +0 -215
  96. package/dist/lib/lanes/outpost-snapshot-refresh.d.ts +0 -21
  97. package/dist/lib/lanes/outpost-snapshot-refresh.js +0 -329
package/CHANGELOG.md CHANGED
@@ -2,9 +2,40 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.295.0] — 2026-09-30
6
+ - Remove the unused direct client-health Sentry route; the existing server-side reporting path remains unchanged.
7
+
8
+ - Self-update supervisor copy and cleanup failures now log their error class.
9
+ - Report failed and ineffective self-updates to Sentry with bounded context.
10
+
11
+ - hq-cli release notes now use per-branch fragments that are folded into the next version section, reducing conflicts between parallel pull requests.
12
+ - Claude keep-alive resume events now retain a compact account-load selection snapshot, including when the lane stays on its current account.
13
+ - After a successful missing-envelope repair reports unfinished work, the watcher can queue one automatic continue behind the default-off `lanes.envelope-repair-continue` flag. The repair prompt now gives the required unfinished-story envelope fields.
14
+ - Add a private machine-session token-file command for supported machine-auth handoffs.
15
+ - Apply the 5x fast-route speedup gate only when the base p95 is at or above the 200 ms target; retain the p95 latency and base/PR regression gates.
16
+ - The changelog fragment check runs only on pull requests again, so pushes to main no longer fail it.
17
+ - Refresh terminal Outpost lane mirrors before applying `hq lanes list` state filters, so a lane whose owner is still running is listed as running.
18
+ - Remove the unused Outpost snapshot cache flag and its cache-first lane-list path.
19
+ - The mesh daemon logs spool watcher failures and continues flushing on its polling interval instead of exiting on an unhandled watcher error.
20
+ - Make the manager status gate always active and remove its rollout flag lookup.
21
+ - Compare fast-route latency with a PR-build full-graph baseline so the 5x gate remains valid after the base build gains fast routing.
22
+
23
+ ## [5.294.0] — 2026-09-30
24
+ - Record automatic keep-alive resumes in each lane's durable, bounded history and expose it in `hq lanes show --json` and `hq lanes list --json`.
25
+
26
+ ### Fixed
27
+
28
+ - Outpost `hq lanes message` now reaches primary-hosted lanes through the
29
+ primary owner command, which checks sender rights and includes the
30
+ destination in JSON output.
31
+ - Split the lane story command handlers into a dedicated module without changing behavior.
32
+ - On a box, `sudo hq daemon migrate --apply` now finds the login user's own systemd user units (hq-mesh-daemon, hq-lanes-reconcile and the rest) and stops them through that user's systemd manager. `sudo hq daemon uninstall --restore-legacy` restarts them the same way. Before, root looked only in its own home and could not reach the login user's manager.
33
+
5
34
  ## [5.293.0] — 2026-09-30
6
35
  - [HQ-CLI-HOOK-TIMEOUT-KIND] Group hook timeout events by normalized kind (`warning` or `exceeded`) across scripts; keep script and platform tags for triage. Existing per-script issues will stop receiving new events, and the lead handles their status.
36
+ - [HQ-CLI-2C] Label unmeasured SessionStart delay as entry Bash startup when BASH_ENV is set; doctor follows the env-prefixed hook command.
7
37
  - `hq lanes move` now reports an already-on-target no-op without dispatching or changing the queued lane.
38
+ - Keep bundled scheduled-job reconciliation units on the live scaffold runner, and preserve caller spelling in job-validation paths.
8
39
  - On Linux, `hq daemon run` sets XDG_RUNTIME_DIR for its services when the system unit left it unset, so `systemctl --user` from jobs-reconcile no longer fails with "Failed to connect to bus: No medium found".
9
40
 
10
41
  - With the default-off lanes.keep-alive-resume-blocked gate enabled, reconcile
@@ -18,13 +49,21 @@
18
49
  - Preserve empty directory paths and modes in recorded corpus cases. The recorder rejects tree entries the case format cannot replay, and CI checks committed snapshots after a clean Git archive extraction.
19
50
  - Cross-Outpost resume and hire-grant dispatch verify the senior from the
20
51
  senior's owning Outpost before signing the caller's grant context.
52
+ - Run the no-Hermes source guard with the required Changelog gate in one runner job.
21
53
 
22
54
  ### Added
23
55
 
56
+ - Add the read-only `hq lanes autopilot report` metrics command for operator nudges, review latency, idle capacity with ready work, and nudge defects.
57
+
24
58
  - Add `hq lanes ask --priority P0|P1|P2` and show question urgency in the queue; warn when omitted during the compatibility release.
59
+ - Route ported native hq core commands through the fast-startup gate while preserving each family's bundled shell fallback.
25
60
 
26
61
  ### Fixed
27
62
 
63
+ - Skip malformed remote lane mirrors with a lane and field warning while
64
+ keeping local lane validation strict. Refresh mirror queue reason and details
65
+ from one owner snapshot.
66
+ - Primary-side Outpost question show and answer skip the current Outpost during owner lookup. Remote answers require the lane senior; when the owner is reachable, an unrelated unavailable Outpost is returned as `lookup_errors` without blocking the answer.
28
67
  - CI-only: keep the same-binary Node control case measured without applying performance regression thresholds.
29
68
  - Fix npm global self-updates, which have failed with MODULE_NOT_FOUND since 5.290.0. The update moved the hq-cli package aside and then started its installer through a supervisor script inside that package. It now runs the installer through a copy of the supervisor outside the package.
30
69
 
@@ -39,7 +39,6 @@ set -euo pipefail
39
39
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
40
40
  HQ_ROOT="${HQ_ROOT:-$(cd "$SCRIPT_DIR/../.." && pwd)}"
41
41
  VALIDATE="$SCRIPT_DIR/jobs-validate.sh"
42
- RUNNER="$SCRIPT_DIR/hq-job-run.sh"
43
42
  PROBE="$SCRIPT_DIR/hq-job-probe.sh"
44
43
 
45
44
  DRY_RUN=0
@@ -99,6 +98,11 @@ while [ $# -gt 0 ]; do
99
98
  esac
100
99
  done
101
100
 
101
+ # The shell script is also bundled inside hq-cli. Its own SCRIPT_DIR then
102
+ # points into the npm package, while job units must always target the live
103
+ # scaffold forwarder so they survive CLI upgrades and Node switches.
104
+ RUNNER="$HQ_ROOT/core/scripts/hq-job-run.sh"
105
+
102
106
  command -v yq >/dev/null 2>&1 || die "yq is required (mikefarah/yq)"
103
107
  command -v jq >/dev/null 2>&1 || die "jq is required"
104
108
  [ -x "$VALIDATE" ] || [ -f "$VALIDATE" ] || die "missing jobs-validate.sh"
@@ -860,6 +860,18 @@ export declare const COMMAND_CATALOG: readonly [{
860
860
  readonly arguments: readonly [];
861
861
  readonly options: readonly [];
862
862
  readonly subcommands: readonly [{
863
+ readonly name: "machine-session";
864
+ readonly description: "Write the existing machine identity session to a private file";
865
+ readonly aliases: readonly [];
866
+ readonly hidden: false;
867
+ readonly usage: "[options]";
868
+ readonly arguments: readonly [];
869
+ readonly options: readonly [{
870
+ readonly flags: "--output <path>";
871
+ readonly description: "path for the private machine session JSON";
872
+ }];
873
+ readonly subcommands: readonly [];
874
+ }, {
863
875
  readonly name: "login";
864
876
  readonly description: "Sign in to HQ — opens the Cognito Hosted UI and caches tokens locally";
865
877
  readonly aliases: readonly [];
@@ -6130,15 +6142,6 @@ export declare const COMMAND_CATALOG: readonly [{
6130
6142
  }, {
6131
6143
  readonly flags: "--client-health-report";
6132
6144
  readonly description: "Resolve the opt-in hq-flags gate used by the client-health report hook.";
6133
- }, {
6134
- readonly flags: "--client-health-sentry";
6135
- readonly description: "Send the opt-in client-health Sentry report from a doctor JSON document.";
6136
- }, {
6137
- readonly flags: "--json-input <file>";
6138
- readonly description: "Doctor JSON input for the client-health report.";
6139
- }, {
6140
- readonly flags: "--client-health-fix-outcome <outcome>";
6141
- readonly description: "Safe fix outcome label for the client-health report.";
6142
6145
  }, {
6143
6146
  readonly flags: "--yes";
6144
6147
  readonly description: "Skip the interactive --fix confirmation (non-interactive use).";
@@ -7769,6 +7772,48 @@ export declare const COMMAND_CATALOG: readonly [{
7769
7772
  readonly description: "Print the KR freshness report as JSON";
7770
7773
  }];
7771
7774
  readonly subcommands: readonly [];
7775
+ }, {
7776
+ readonly name: "autopilot";
7777
+ readonly description: "Run lead autopilot checks and report follow-through metrics";
7778
+ readonly aliases: readonly [];
7779
+ readonly hidden: false;
7780
+ readonly usage: "[options] [command]";
7781
+ readonly arguments: readonly [];
7782
+ readonly options: readonly [];
7783
+ readonly subcommands: readonly [{
7784
+ readonly name: "report";
7785
+ readonly description: "Report operator nudges, review latency, and idle slots with ready work";
7786
+ readonly aliases: readonly [];
7787
+ readonly hidden: false;
7788
+ readonly usage: "[options]";
7789
+ readonly arguments: readonly [];
7790
+ readonly options: readonly [{
7791
+ readonly flags: "--since <iso>";
7792
+ readonly description: "Include activity since this ISO timestamp";
7793
+ }, {
7794
+ readonly flags: "--days <n>";
7795
+ readonly description: "Include the most recent number of days";
7796
+ }, {
7797
+ readonly flags: "--json";
7798
+ readonly description: "Print JSON";
7799
+ }];
7800
+ readonly subcommands: readonly [];
7801
+ }, {
7802
+ readonly name: "run";
7803
+ readonly description: "Run one lead autopilot check pass";
7804
+ readonly aliases: readonly [];
7805
+ readonly hidden: false;
7806
+ readonly usage: "[options]";
7807
+ readonly arguments: readonly [];
7808
+ readonly options: readonly [{
7809
+ readonly flags: "--dry-run";
7810
+ readonly description: "Report proposed wakes without writing them";
7811
+ }, {
7812
+ readonly flags: "--json";
7813
+ readonly description: "Emit JSON on stdout (default)";
7814
+ }];
7815
+ readonly subcommands: readonly [];
7816
+ }];
7772
7817
  }, {
7773
7818
  readonly name: "create";
7774
7819
  readonly description: "Register a lane, run admission, and return immediately";
@@ -8992,30 +9037,6 @@ export declare const COMMAND_CATALOG: readonly [{
8992
9037
  readonly description: "JSON on stdout (always)";
8993
9038
  }];
8994
9039
  readonly subcommands: readonly [];
8995
- }, {
8996
- readonly name: "autopilot";
8997
- readonly description: "Check registered team leads and wake them for ready work";
8998
- readonly aliases: readonly [];
8999
- readonly hidden: false;
9000
- readonly usage: "[options] [command]";
9001
- readonly arguments: readonly [];
9002
- readonly options: readonly [];
9003
- readonly subcommands: readonly [{
9004
- readonly name: "run";
9005
- readonly description: "Run one lead autopilot check pass";
9006
- readonly aliases: readonly [];
9007
- readonly hidden: false;
9008
- readonly usage: "[options]";
9009
- readonly arguments: readonly [];
9010
- readonly options: readonly [{
9011
- readonly flags: "--dry-run";
9012
- readonly description: "Report proposed wakes without writing them";
9013
- }, {
9014
- readonly flags: "--json";
9015
- readonly description: "Emit JSON on stdout (default)";
9016
- }];
9017
- readonly subcommands: readonly [];
9018
- }];
9019
9040
  }, {
9020
9041
  readonly name: "reconcile";
9021
9042
  readonly description: "Run one machine-owned reconcile pass and exit";
@@ -1097,6 +1097,21 @@ export const COMMAND_CATALOG = [
1097
1097
  "arguments": [],
1098
1098
  "options": [],
1099
1099
  "subcommands": [
1100
+ {
1101
+ "name": "machine-session",
1102
+ "description": "Write the existing machine identity session to a private file",
1103
+ "aliases": [],
1104
+ "hidden": false,
1105
+ "usage": "[options]",
1106
+ "arguments": [],
1107
+ "options": [
1108
+ {
1109
+ "flags": "--output <path>",
1110
+ "description": "path for the private machine session JSON"
1111
+ }
1112
+ ],
1113
+ "subcommands": []
1114
+ },
1100
1115
  {
1101
1116
  "name": "login",
1102
1117
  "description": "Sign in to HQ — opens the Cognito Hosted UI and caches tokens locally",
@@ -7883,18 +7898,6 @@ export const COMMAND_CATALOG = [
7883
7898
  "flags": "--client-health-report",
7884
7899
  "description": "Resolve the opt-in hq-flags gate used by the client-health report hook."
7885
7900
  },
7886
- {
7887
- "flags": "--client-health-sentry",
7888
- "description": "Send the opt-in client-health Sentry report from a doctor JSON document."
7889
- },
7890
- {
7891
- "flags": "--json-input <file>",
7892
- "description": "Doctor JSON input for the client-health report."
7893
- },
7894
- {
7895
- "flags": "--client-health-fix-outcome <outcome>",
7896
- "description": "Safe fix outcome label for the client-health report."
7897
- },
7898
7901
  {
7899
7902
  "flags": "--yes",
7900
7903
  "description": "Skip the interactive --fix confirmation (non-interactive use)."
@@ -10013,6 +10016,59 @@ export const COMMAND_CATALOG = [
10013
10016
  ],
10014
10017
  "subcommands": []
10015
10018
  },
10019
+ {
10020
+ "name": "autopilot",
10021
+ "description": "Run lead autopilot checks and report follow-through metrics",
10022
+ "aliases": [],
10023
+ "hidden": false,
10024
+ "usage": "[options] [command]",
10025
+ "arguments": [],
10026
+ "options": [],
10027
+ "subcommands": [
10028
+ {
10029
+ "name": "report",
10030
+ "description": "Report operator nudges, review latency, and idle slots with ready work",
10031
+ "aliases": [],
10032
+ "hidden": false,
10033
+ "usage": "[options]",
10034
+ "arguments": [],
10035
+ "options": [
10036
+ {
10037
+ "flags": "--since <iso>",
10038
+ "description": "Include activity since this ISO timestamp"
10039
+ },
10040
+ {
10041
+ "flags": "--days <n>",
10042
+ "description": "Include the most recent number of days"
10043
+ },
10044
+ {
10045
+ "flags": "--json",
10046
+ "description": "Print JSON"
10047
+ }
10048
+ ],
10049
+ "subcommands": []
10050
+ },
10051
+ {
10052
+ "name": "run",
10053
+ "description": "Run one lead autopilot check pass",
10054
+ "aliases": [],
10055
+ "hidden": false,
10056
+ "usage": "[options]",
10057
+ "arguments": [],
10058
+ "options": [
10059
+ {
10060
+ "flags": "--dry-run",
10061
+ "description": "Report proposed wakes without writing them"
10062
+ },
10063
+ {
10064
+ "flags": "--json",
10065
+ "description": "Emit JSON on stdout (default)"
10066
+ }
10067
+ ],
10068
+ "subcommands": []
10069
+ }
10070
+ ]
10071
+ },
10016
10072
  {
10017
10073
  "name": "create",
10018
10074
  "description": "Register a lane, run admission, and return immediately",
@@ -11608,36 +11664,6 @@ export const COMMAND_CATALOG = [
11608
11664
  ],
11609
11665
  "subcommands": []
11610
11666
  },
11611
- {
11612
- "name": "autopilot",
11613
- "description": "Check registered team leads and wake them for ready work",
11614
- "aliases": [],
11615
- "hidden": false,
11616
- "usage": "[options] [command]",
11617
- "arguments": [],
11618
- "options": [],
11619
- "subcommands": [
11620
- {
11621
- "name": "run",
11622
- "description": "Run one lead autopilot check pass",
11623
- "aliases": [],
11624
- "hidden": false,
11625
- "usage": "[options]",
11626
- "arguments": [],
11627
- "options": [
11628
- {
11629
- "flags": "--dry-run",
11630
- "description": "Report proposed wakes without writing them"
11631
- },
11632
- {
11633
- "flags": "--json",
11634
- "description": "Emit JSON on stdout (default)"
11635
- }
11636
- ],
11637
- "subcommands": []
11638
- }
11639
- ]
11640
- },
11641
11667
  {
11642
11668
  "name": "reconcile",
11643
11669
  "description": "Run one machine-owned reconcile pass and exit",
@@ -6,6 +6,7 @@
6
6
  * hq auth logout — clear the cached HQ session
7
7
  * hq auth refresh — ensure a valid cached Cognito session (non-interactive)
8
8
  * hq auth status — show whether a valid session is cached + expiry
9
+ * hq auth machine-session --output <path> — write machine tokens to a private file
9
10
  *
10
11
  * Sign-up is owned by the onboarding web app at
11
12
  * https://onboarding.hq.computer. `hq auth login` signs an existing account
@@ -6,6 +6,7 @@
6
6
  * hq auth logout — clear the cached HQ session
7
7
  * hq auth refresh — ensure a valid cached Cognito session (non-interactive)
8
8
  * hq auth status — show whether a valid session is cached + expiry
9
+ * hq auth machine-session --output <path> — write machine tokens to a private file
9
10
  *
10
11
  * Sign-up is owned by the onboarding web app at
11
12
  * https://onboarding.hq.computer. `hq auth login` signs an existing account
@@ -13,9 +14,12 @@
13
14
  * session is kept valid by `hq auth refresh` / `hq-auth-refresh` and consumed
14
15
  * by the deploy + sync skills.
15
16
  */
17
+ import * as fs from "node:fs";
18
+ import { open, realpath } from "node:fs/promises";
19
+ import path from "node:path";
16
20
  import chalk from "chalk";
17
21
  import { browserLogin, clearCachedTokens, loadCachedTokens, isExpiring, loadMachineCreds, CognitoAuthError, } from "@indigoai-us/hq-cloud";
18
- import { DEFAULT_COGNITO, refreshCachedSession, resolveCognitoTokenSource, } from "../utils/cognito-session.js";
22
+ import { DEFAULT_COGNITO, refreshCachedSession, resolveCognitoTokenSource, ensureMachineSessionTokens, personTokenCacheFile, machineTokenCacheFile, } from "../utils/cognito-session.js";
19
23
  import { resolveLoginProviderSelection, } from "../utils/login-provider.js";
20
24
  import { getLastLoginProviderStatePath, loadLastLoginProvider, storeLastLoginProvider, } from "../lib/auth-login-provider-state.js";
21
25
  import { callbackPortBusyGuidance, DEFAULT_CALLBACK_PORT, isCallbackPortBusy, } from "../utils/callback-port-busy.js";
@@ -128,6 +132,77 @@ export function registerAuthCommands(program) {
128
132
  const authCmd = program
129
133
  .command("auth")
130
134
  .description("Manage the local HQ Cognito session");
135
+ authCmd
136
+ .command("machine-session")
137
+ .description("Write the existing machine identity session to a private file")
138
+ .requiredOption("--output <path>", "path for the private machine session JSON")
139
+ .action(async (options) => {
140
+ const requestedPath = path.resolve(options.output);
141
+ let handle;
142
+ try {
143
+ if (!loadMachineCreds()) {
144
+ throw new Error("Machine credentials are unavailable.");
145
+ }
146
+ const outputDirectory = await realpath(path.dirname(requestedPath));
147
+ const outputPath = path.join(outputDirectory, path.basename(requestedPath));
148
+ const protectedPaths = await Promise.all([personTokenCacheFile(), machineTokenCacheFile()].map(async (protectedPath) => {
149
+ const resolved = path.resolve(protectedPath);
150
+ try {
151
+ return path.join(await realpath(path.dirname(resolved)), path.basename(resolved));
152
+ }
153
+ catch (error) {
154
+ if (error.code === "ENOENT")
155
+ return resolved;
156
+ throw error;
157
+ }
158
+ }));
159
+ if (protectedPaths.includes(outputPath)) {
160
+ throw new Error("Refusing to overwrite a cached Cognito session.");
161
+ }
162
+ const tokens = await ensureMachineSessionTokens();
163
+ const contents = JSON.stringify({
164
+ accessToken: tokens.accessToken,
165
+ idToken: tokens.idToken,
166
+ expiresAt: tokens.expiresAt,
167
+ }) + "\n";
168
+ try {
169
+ handle = await open(outputPath, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL |
170
+ (fs.constants.O_NOFOLLOW ?? 0), 0o600);
171
+ }
172
+ catch (error) {
173
+ if (error.code !== "EEXIST")
174
+ throw error;
175
+ handle = await open(outputPath, fs.constants.O_WRONLY | (fs.constants.O_NOFOLLOW ?? 0));
176
+ const metadata = await handle.stat();
177
+ if (!metadata.isFile() ||
178
+ metadata.uid !== process.getuid?.() ||
179
+ (metadata.mode & 0o077) !== 0) {
180
+ throw new Error("Existing output file is not a private file owned by this user.");
181
+ }
182
+ await handle.truncate(0);
183
+ }
184
+ await handle.writeFile(contents, { encoding: "utf8" });
185
+ await handle.close();
186
+ handle = undefined;
187
+ }
188
+ catch (error) {
189
+ if (handle)
190
+ await handle.close().catch(() => undefined);
191
+ const code = error && typeof error === "object" && "code" in error &&
192
+ typeof error.code === "string" && /^[A-Z0-9_]+$/.test(error.code)
193
+ ? error.code
194
+ : undefined;
195
+ console.error(code === "EACCES" || code === "ELOOP" || code === "EEXIST"
196
+ ? "Could not write machine session file (unsafe or inaccessible path)."
197
+ : error instanceof Error && error.message === "Machine credentials are unavailable."
198
+ ? "Machine credentials are unavailable."
199
+ : error instanceof Error && (error.message === "Existing output file is not a private file owned by this user." ||
200
+ error.message === "Refusing to overwrite a cached Cognito session.")
201
+ ? error.message
202
+ : "Could not obtain or write machine session.");
203
+ process.exitCode = 1;
204
+ }
205
+ });
131
206
  authCmd
132
207
  .command("login")
133
208
  .description("Sign in to HQ — opens the Cognito Hosted UI and caches tokens locally")
@@ -46,8 +46,9 @@ export function fastScaffoldListingMismatches(listing, fastScripts) {
46
46
  else if (fast.kind === "shell" && listed.asset !== fast.asset) {
47
47
  mismatches.push(`${fast.name} lists ${listed.asset ?? "no asset"}, fast path uses ${fast.asset ?? "no asset"}`);
48
48
  }
49
- else if (fast.kind === "native" && (listed.execution !== "native" || listed.asset)) {
50
- mismatches.push(`${fast.name} is native in the fast path but not in the command catalog`);
49
+ else if (fast.kind === "native" && (listed.execution !== "native" ||
50
+ (fast.asset === undefined ? listed.asset !== undefined : listed.asset !== fast.asset))) {
51
+ mismatches.push(`${fast.name} has fast-route metadata that differs from the native command catalog`);
51
52
  }
52
53
  }
53
54
  return mismatches;
@@ -3,6 +3,8 @@ import { Command } from "commander";
3
3
  import { type DelegateContext } from "./core-delegate.js";
4
4
  type W1bName = "bundle" | "grant" | "publish" | "send" | "verify";
5
5
  export declare function runNativeDelegateW1b(name: W1bName, args: string[], context: DelegateContext): number;
6
+ /** Fast-entry adapter; the shared family flag is resolved before this module loads. */
7
+ export declare function runDelegateW1bFast(args: readonly string[], _stdin: string, _cwd: string, hqRoot: string | undefined, commandName: string): number;
6
8
  export declare function registerCoreDelegateW1b(delegate: Command, core: Command): void;
7
9
  export {};
8
10
  //# sourceMappingURL=core-delegate-w1b.d.ts.map
@@ -5,7 +5,6 @@ import * as os from "node:os";
5
5
  import * as path from "node:path";
6
6
  import { serializeJqJson } from "../lib/core-utils/jq-json-serializer.js";
7
7
  import { matchingSecretPatterns } from "../lib/core-utils/secret-patterns.js";
8
- import { resolveProcessFlagGate } from "../lib/flag-registry.js";
9
8
  import { describeCoreCommand } from "./core-command-catalog.js";
10
9
  import { isRecord, jsonAt, jqFallback, jqRawPath, jqRawPaths, moveFile, readJsonFile, subprocess, writeJsonAtomically, } from "./core-delegate.js";
11
10
  import { resolveLiveRoot } from "../utils/hq-roots.js";
@@ -1004,6 +1003,32 @@ export function runNativeDelegateW1b(name, args, context) {
1004
1003
  case "verify": return runVerify(args, context);
1005
1004
  }
1006
1005
  }
1006
+ /** Fast-entry adapter; the shared family flag is resolved before this module loads. */
1007
+ export function runDelegateW1bFast(args, _stdin, _cwd, hqRoot, commandName) {
1008
+ const root = hqRoot ?? resolveLiveRoot();
1009
+ const context = { cwd: root, root };
1010
+ const saved = new Map();
1011
+ for (const key of ["HQ_ROOT", "CLAUDE_PROJECT_DIR", "PWD"])
1012
+ saved.set(key, process.env[key]);
1013
+ process.env.HQ_ROOT = root;
1014
+ process.env.CLAUDE_PROJECT_DIR = root;
1015
+ process.env.PWD = root;
1016
+ let code;
1017
+ try {
1018
+ code = runNativeDelegateW1b(commandName, [...args], context);
1019
+ }
1020
+ finally {
1021
+ for (const [key, value] of saved) {
1022
+ if (value === undefined)
1023
+ delete process.env[key];
1024
+ else
1025
+ process.env[key] = value;
1026
+ }
1027
+ }
1028
+ if (code !== 0)
1029
+ process.exitCode = code;
1030
+ return code;
1031
+ }
1007
1032
  export function registerCoreDelegateW1b(delegate, core) {
1008
1033
  for (const name of ["bundle", "grant", "publish", "send", "verify"]) {
1009
1034
  const command = delegate.command(name)
@@ -1012,10 +1037,11 @@ export function registerCoreDelegateW1b(delegate, core) {
1012
1037
  .allowExcessArguments()
1013
1038
  .helpOption(false)
1014
1039
  .argument("[args...]", "arguments accepted for shell ABI compatibility")
1015
- .action((args = []) => {
1040
+ .action(async (args = []) => {
1016
1041
  const options = core.opts();
1017
1042
  const root = resolveLiveRoot({ hqRoot: options.hqRoot });
1018
1043
  const context = { cwd: root, root };
1044
+ const { resolveProcessFlagGate } = await import("../lib/flag-registry.js");
1019
1045
  if (!resolveProcessFlagGate(FLAG, { fallback: false }, () => false)) {
1020
1046
  const result = runBundledScript({ asset: ASSETS[name], args, cwd: root, hqRoot: root });
1021
1047
  if (result.code !== 0)
@@ -28,7 +28,9 @@ export declare function jqRawPaths(value: unknown, dottedPaths: string[], fallba
28
28
  export declare function requireRecord(value: unknown, property: string): JsonRecord;
29
29
  export declare function moveFile(source: string, target: string): void;
30
30
  export declare function writeJsonAtomically(target: string, value: unknown, siblingTemp?: boolean): void;
31
+ /** Fast-entry adapter; family gating and shell fallback happen before import. */
32
+ export declare function runDelegateFast(args: readonly string[], _stdin: string, cwd: string, hqRoot: string | undefined, commandName: string): number;
31
33
  /** Register the Wave 1a delegate commands and preserve the shell rollback path. */
32
- export declare function registerCoreDelegateCommand(core: Command): void;
34
+ export declare function registerCoreDelegateCommand(core: Command, registerWave1b?: (delegate: Command, core: Command) => void): void;
33
35
  export {};
34
36
  //# sourceMappingURL=core-delegate.d.ts.map
@@ -4,11 +4,9 @@ import * as fs from "node:fs";
4
4
  import * as os from "node:os";
5
5
  import * as path from "node:path";
6
6
  import { serializeJqJson } from "../lib/core-utils/jq-json-serializer.js";
7
- import { resolveProcessFlagGate } from "../lib/flag-registry.js";
8
7
  import { describeCoreCommand } from "./core-command-catalog.js";
9
8
  import { resolveLiveRoot } from "../utils/hq-roots.js";
10
9
  import { runBundledScript } from "../utils/run-bundled-script.js";
11
- import { registerCoreDelegateW1b } from "./core-delegate-w1b.js";
12
10
  export const CORE_NATIVE_DELEGATE_FLAG = "core-native-delegate";
13
11
  const SCRIPT_ASSETS = {
14
12
  resolve: "core/scripts/hq-delegate-resolve.sh",
@@ -936,8 +934,39 @@ function runNative(name, args, context) {
936
934
  case "transfer": return runTransfer(args, context);
937
935
  }
938
936
  }
937
+ /** Fast-entry adapter; family gating and shell fallback happen before import. */
938
+ export function runDelegateFast(args, _stdin, cwd, hqRoot, commandName) {
939
+ const name = commandName;
940
+ const context = name === "pickup"
941
+ ? { cwd }
942
+ : (() => { const root = hqRoot ?? resolveLiveRoot(); return { cwd: root, root }; })();
943
+ const savedEnvironment = new Map();
944
+ if (context.root) {
945
+ for (const key of ["HQ_ROOT", "CLAUDE_PROJECT_DIR", "PWD"]) {
946
+ savedEnvironment.set(key, process.env[key]);
947
+ }
948
+ process.env.HQ_ROOT = context.root;
949
+ process.env.CLAUDE_PROJECT_DIR = context.root;
950
+ process.env.PWD = context.cwd;
951
+ }
952
+ let code;
953
+ try {
954
+ code = runNative(name, [...args], context);
955
+ }
956
+ finally {
957
+ for (const [key, value] of savedEnvironment) {
958
+ if (value === undefined)
959
+ delete process.env[key];
960
+ else
961
+ process.env[key] = value;
962
+ }
963
+ }
964
+ if (code !== 0)
965
+ process.exitCode = code;
966
+ return code;
967
+ }
939
968
  /** Register the Wave 1a delegate commands and preserve the shell rollback path. */
940
- export function registerCoreDelegateCommand(core) {
969
+ export function registerCoreDelegateCommand(core, registerWave1b) {
941
970
  const delegate = core.command("delegate").description("Delegation handover helpers");
942
971
  for (const name of ["resolve", "pickup", "repo", "secrets", "transfer"]) {
943
972
  const rootMode = name === "pickup" ? "cwd" : "live";
@@ -947,11 +976,12 @@ export function registerCoreDelegateCommand(core) {
947
976
  .allowExcessArguments()
948
977
  .helpOption(false)
949
978
  .argument("[args...]", "arguments accepted for shell ABI compatibility")
950
- .action((args = []) => {
979
+ .action(async (args = []) => {
951
980
  const scope = core.opts();
952
981
  const context = rootMode === "cwd"
953
982
  ? { cwd: process.cwd() }
954
983
  : (() => { const root = resolveLiveRoot({ hqRoot: scope.hqRoot }); return { cwd: root, root }; })();
984
+ const { resolveProcessFlagGate } = await import("../lib/flag-registry.js");
955
985
  if (!resolveProcessFlagGate(CORE_NATIVE_DELEGATE_FLAG, { fallback: false }, () => false)) {
956
986
  const result = runBundledScript({ asset: SCRIPT_ASSETS[name], args, cwd: context.cwd, hqRoot: context.root });
957
987
  if (result.code !== 0)
@@ -984,6 +1014,6 @@ export function registerCoreDelegateCommand(core) {
984
1014
  });
985
1015
  describeCoreCommand(command, { execution: "native", asset: SCRIPT_ASSETS[name], root: rootMode });
986
1016
  }
987
- registerCoreDelegateW1b(delegate, core);
1017
+ registerWave1b?.(delegate, core);
988
1018
  }
989
1019
  //# sourceMappingURL=core-delegate.js.map
@@ -0,0 +1,18 @@
1
+ /** Lightweight entry adapters for the fast handoff routes. */
2
+ type RunResult = {
3
+ code: number;
4
+ stdout: string;
5
+ stderr: string;
6
+ };
7
+ /**
8
+ * `handoff finalize --help` is historically an unknown-argument error. Keep
9
+ * that fast error path out of the large handoff implementation module.
10
+ */
11
+ export declare function handoffFinalizeHelpResult(args: readonly string[], root: string, tmpRoot?: string): RunResult | undefined;
12
+ /**
13
+ * Keep cheap help/launch paths in this small module. Commands that do the
14
+ * actual handoff work load the existing implementation only when invoked.
15
+ */
16
+ export declare function runHandoffFastEntry(args: readonly string[], stdin: string, cwd: string, hqRoot: string | undefined, commandName: string): Promise<number>;
17
+ export {};
18
+ //# sourceMappingURL=core-handoff-fast.d.ts.map