@indigoai-us/hq-cli 5.273.0-alpha.0 → 5.274.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 (91) hide show
  1. package/CHANGELOG.md +65 -2
  2. package/README.md +32 -1
  3. package/dist/command-catalog.generated.d.ts +83 -536
  4. package/dist/command-catalog.generated.js +129 -714
  5. package/dist/command-registration-plan.d.ts +12 -0
  6. package/dist/command-registration-plan.js +2 -0
  7. package/dist/commands/cloud.js +40 -0
  8. package/dist/commands/core-checkpoint.js +3 -1
  9. package/dist/commands/core-command-catalog.d.ts +32 -0
  10. package/dist/commands/core-command-catalog.js +58 -0
  11. package/dist/commands/core-ontology.js +9 -4
  12. package/dist/commands/core.d.ts +4 -0
  13. package/dist/commands/core.js +79 -75
  14. package/dist/commands/daemon.d.ts +0 -3
  15. package/dist/commands/daemon.js +1 -173
  16. package/dist/commands/deploy-comments.d.ts +3 -0
  17. package/dist/commands/deploy-comments.js +159 -0
  18. package/dist/commands/lanes-checks.d.ts +0 -1
  19. package/dist/commands/lanes-checks.js +217 -54
  20. package/dist/commands/lanes-hold.js +40 -2
  21. package/dist/commands/lanes-message.js +98 -14
  22. package/dist/commands/lanes-move.d.ts +12 -0
  23. package/dist/commands/lanes-move.js +342 -0
  24. package/dist/commands/lanes-resume.js +3 -1
  25. package/dist/commands/lanes-shared.d.ts +39 -3
  26. package/dist/commands/lanes-shared.js +59 -0
  27. package/dist/commands/lanes.d.ts +3 -5
  28. package/dist/commands/lanes.js +206 -478
  29. package/dist/commands/report.js +2 -14
  30. package/dist/commands/sync-mode.d.ts +0 -11
  31. package/dist/commands/sync-mode.js +0 -30
  32. package/dist/fast-core.js +1 -1
  33. package/dist/{commands/scaffold-fast.d.ts → fast-scaffold.d.ts} +1 -1
  34. package/dist/{commands/scaffold-fast.js → fast-scaffold.js} +1 -1
  35. package/dist/index.d.ts +1 -1
  36. package/dist/index.js +2 -2
  37. package/dist/lib/checkpoint-ontology/apply.d.ts +8 -0
  38. package/dist/lib/checkpoint-ontology/apply.js +33 -0
  39. package/dist/lib/checkpoint-ontology/plan.d.ts +15 -0
  40. package/dist/lib/checkpoint-ontology/plan.js +15 -0
  41. package/dist/lib/daemon/catalog.d.ts +2 -18
  42. package/dist/lib/daemon/catalog.js +2 -18
  43. package/dist/lib/daemon/config.d.ts +0 -6
  44. package/dist/lib/daemon/config.js +2 -15
  45. package/dist/lib/daemon/requests.d.ts +0 -4
  46. package/dist/lib/daemon/requests.js +0 -2
  47. package/dist/lib/daemon/run.js +19 -78
  48. package/dist/lib/daemon/supervisor.d.ts +0 -8
  49. package/dist/lib/daemon/supervisor.js +1 -101
  50. package/dist/lib/deploy-api.d.ts +6 -0
  51. package/dist/lib/deploy-api.js +21 -0
  52. package/dist/lib/doctor/checks/scaffold-cli-floor.d.ts +7 -0
  53. package/dist/lib/doctor/checks/scaffold-cli-floor.js +73 -0
  54. package/dist/lib/doctor/fix/apply.d.ts +17 -2
  55. package/dist/lib/doctor/fix/apply.js +111 -57
  56. package/dist/lib/doctor/fix/json-output.d.ts +9 -1
  57. package/dist/lib/doctor/fix/json-output.js +11 -0
  58. package/dist/lib/doctor/registry.js +2 -0
  59. package/dist/lib/first-sync-next-step.d.ts +37 -0
  60. package/dist/lib/first-sync-next-step.js +189 -0
  61. package/dist/lib/flag-registry-worker-source.generated.d.ts +1 -1
  62. package/dist/lib/flag-registry-worker-source.generated.js +1 -1
  63. package/dist/lib/lanes/hire-grant-dispatch.d.ts +6 -1
  64. package/dist/lib/lanes/hire-grant-dispatch.js +78 -3
  65. package/dist/lib/lanes/keep-alive.d.ts +3 -2
  66. package/dist/lib/lanes/keep-alive.js +2 -2
  67. package/dist/lib/lanes/merge-command.d.ts +1 -0
  68. package/dist/lib/lanes/merge-command.js +299 -33
  69. package/dist/lib/lanes/orphans.d.ts +7 -0
  70. package/dist/lib/lanes/orphans.js +39 -4
  71. package/dist/lib/lanes/tracker-store.d.ts +2 -18
  72. package/dist/lib/lanes/tracker-store.js +1 -172
  73. package/dist/lib/scaffold-cli-floor.d.ts +9 -0
  74. package/dist/lib/scaffold-cli-floor.js +50 -0
  75. package/dist/main.js +4 -1
  76. package/dist/utils/cli-telemetry.d.ts +7 -1
  77. package/dist/utils/cli-telemetry.js +84 -8
  78. package/dist/utils/contribution-table.d.ts +1 -1
  79. package/dist/utils/scaffold-fast-import-guard.d.ts +3 -0
  80. package/dist/utils/scaffold-fast-import-guard.js +28 -0
  81. package/dist/utils/scaffold-packlist-guard.d.ts +7 -0
  82. package/dist/utils/scaffold-packlist-guard.js +23 -0
  83. package/dist/utils/scaffold-sibling-references.d.ts +21 -0
  84. package/dist/utils/scaffold-sibling-references.js +156 -0
  85. package/package.json +2 -2
  86. package/dist/commands/lanes-import.d.ts +0 -14
  87. package/dist/commands/lanes-import.js +0 -1210
  88. package/dist/commands/lanes-tracker.d.ts +0 -18
  89. package/dist/commands/lanes-tracker.js +0 -452
  90. package/dist/lib/daemon/sync-runner.d.ts +0 -58
  91. package/dist/lib/daemon/sync-runner.js +0 -277
@@ -0,0 +1,189 @@
1
+ import { createHash } from "node:crypto";
2
+ import * as fs from "node:fs";
3
+ import * as os from "node:os";
4
+ import * as path from "node:path";
5
+ import { resolveProcessFlagGate } from "./flag-registry.js";
6
+ import { cognitoSubjectKey, isMachineIdentity, loadCachedTokens, } from "../utils/cognito-session.js";
7
+ export const CLI_FIRST_SYNC_NEXT_STEP_FLAG = "cli.first-sync-next-step";
8
+ export const FIRST_SYNC_NEXT_STEP_COPY = "Save a file in your HQ folder, then run `hq sync push`.";
9
+ export const FIRST_SYNC_CONFIRMATION_COPY = "Your first work sync is complete.";
10
+ const AUTOMATION_ENV_MARKERS = [
11
+ "CI",
12
+ "HQ_E2E",
13
+ "HQ_TEST",
14
+ "HQ_AUTOMATED",
15
+ "HQ_PROBE",
16
+ "HQ_AGENT_DIR",
17
+ ];
18
+ const pendingOutcomes = [];
19
+ export function shouldShowFirstSyncNextStep(input) {
20
+ return (input.flagEnabled &&
21
+ input.interactive &&
22
+ !input.alreadyShown &&
23
+ !input.alreadyCompleted);
24
+ }
25
+ export function shouldConfirmFirstWorkBearingSync(input) {
26
+ return (input.flagEnabled &&
27
+ input.interactive &&
28
+ !input.alreadyCompleted &&
29
+ input.workBearing);
30
+ }
31
+ export function isWorkBearingSyncResult(result) {
32
+ if (result.aborted === true)
33
+ return false;
34
+ return [
35
+ result.filesUploaded,
36
+ result.filesDownloaded,
37
+ result.sessionLogUploadedCount,
38
+ result.filesDeleted,
39
+ result.tombstonedCount,
40
+ ].some((count) => typeof count === "number" && Number.isFinite(count) && count > 0);
41
+ }
42
+ function isNonAutomatedHumanCliProcess(input) {
43
+ if (input.machineIdentity || input.env.NODE_ENV === "test")
44
+ return false;
45
+ return !AUTOMATION_ENV_MARKERS.some((name) => Boolean(input.env[name]?.trim()));
46
+ }
47
+ export function isHumanInteractiveCliSession(input) {
48
+ if (!input.stdoutIsTTY || !isNonAutomatedHumanCliProcess(input))
49
+ return false;
50
+ if (input.argv.some((arg) => ["--json", "--help", "-h", "--version", "-V"].includes(arg))) {
51
+ return false;
52
+ }
53
+ return true;
54
+ }
55
+ function markerDirectory(home) {
56
+ return path.join(home, ".hq", "first-sync-next-step");
57
+ }
58
+ export function firstSyncStepMarkerPaths(identity, home = process.env.HOME?.trim() || os.homedir()) {
59
+ const identityHash = createHash("sha256").update(identity).digest("hex");
60
+ const directory = markerDirectory(home);
61
+ return {
62
+ shown: path.join(directory, `${identityHash}.shown`),
63
+ completed: path.join(directory, `${identityHash}.completed`),
64
+ };
65
+ }
66
+ function reportMarkerError(action, err) {
67
+ const code = typeof err === "object" && err !== null && "code" in err
68
+ ? String(err.code)
69
+ : err instanceof Error
70
+ ? err.name
71
+ : "unknown error";
72
+ console.error(`hq: Could not ${action} first-sync state (${code}).`);
73
+ }
74
+ function firstSyncStepMarkerExists(kind, identity) {
75
+ try {
76
+ const paths = firstSyncStepMarkerPaths(identity);
77
+ return fs.existsSync(paths[kind]);
78
+ }
79
+ catch (err) {
80
+ reportMarkerError("read", err);
81
+ return false;
82
+ }
83
+ }
84
+ export function claimFirstSyncStepMarker(kind, identity, home = process.env.HOME?.trim() || os.homedir()) {
85
+ const paths = firstSyncStepMarkerPaths(identity, home);
86
+ const hqDirectory = path.join(home, ".hq");
87
+ try {
88
+ // Do not create ~/.hq on a signed-out machine. Authenticated CLI sessions
89
+ // already have it, and this state belongs only to the cached person.
90
+ if (!fs.existsSync(hqDirectory))
91
+ return false;
92
+ fs.mkdirSync(path.dirname(paths[kind]), { recursive: true, mode: 0o700 });
93
+ fs.writeFileSync(paths[kind], `${new Date().toISOString()}\n`, {
94
+ flag: "wx",
95
+ mode: 0o600,
96
+ });
97
+ return true;
98
+ }
99
+ catch (err) {
100
+ if (typeof err === "object" && err !== null && "code" in err && err.code === "EEXIST") {
101
+ return false;
102
+ }
103
+ reportMarkerError("write", err);
104
+ return false;
105
+ }
106
+ }
107
+ export function firstSyncStepTelemetryProperties(outcome) {
108
+ return {
109
+ step: "first_sync_next_step",
110
+ outcome,
111
+ flagKey: CLI_FIRST_SYNC_NEXT_STEP_FLAG,
112
+ };
113
+ }
114
+ export function isFirstSyncNextStepEnabled() {
115
+ return resolveProcessFlagGate(CLI_FIRST_SYNC_NEXT_STEP_FLAG, { fallback: false }, () => false);
116
+ }
117
+ function currentPersonIdentity() {
118
+ return cognitoSubjectKey(loadCachedTokens());
119
+ }
120
+ function isCurrentSessionEligible() {
121
+ return isHumanInteractiveCliSession({
122
+ stdoutIsTTY: Boolean(process.stdout.isTTY),
123
+ argv: process.argv,
124
+ env: process.env,
125
+ machineIdentity: isMachineIdentity(),
126
+ });
127
+ }
128
+ function queueOutcome(outcome) {
129
+ if (!pendingOutcomes.includes(outcome))
130
+ pendingOutcomes.push(outcome);
131
+ }
132
+ /** Called once after the first completed CLI action, before process finalization. */
133
+ export function maybeShowFirstSyncNextStep() {
134
+ // Keep the cheap eligibility/gate checks ahead of identity and filesystem
135
+ // reads; neither an automated invocation nor a flag-off session needs state.
136
+ if (!isCurrentSessionEligible() || !isFirstSyncNextStepEnabled())
137
+ return false;
138
+ const identity = currentPersonIdentity();
139
+ if (!identity)
140
+ return false;
141
+ const shouldShow = shouldShowFirstSyncNextStep({
142
+ flagEnabled: true,
143
+ interactive: true,
144
+ alreadyShown: firstSyncStepMarkerExists("shown", identity),
145
+ alreadyCompleted: firstSyncStepMarkerExists("completed", identity),
146
+ });
147
+ if (!shouldShow || !claimFirstSyncStepMarker("shown", identity))
148
+ return false;
149
+ console.log(FIRST_SYNC_NEXT_STEP_COPY);
150
+ queueOutcome("shown");
151
+ return true;
152
+ }
153
+ /** Capture the first positive CLI sync result without changing transfer logic. */
154
+ export function recordFirstWorkBearingSync(result) {
155
+ if (!isWorkBearingSyncResult(result))
156
+ return false;
157
+ if (!isNonAutomatedHumanCliProcess({
158
+ env: process.env,
159
+ machineIdentity: isMachineIdentity(),
160
+ }))
161
+ return false;
162
+ const identity = currentPersonIdentity();
163
+ if (!identity)
164
+ return false;
165
+ const alreadyCompleted = firstSyncStepMarkerExists("completed", identity);
166
+ if (alreadyCompleted || !claimFirstSyncStepMarker("completed", identity))
167
+ return false;
168
+ // Persist completion even while the rollout is off so enabling the flag later
169
+ // cannot prompt a person who already completed a work-bearing sync. JSON and
170
+ // other non-interactive human syncs count too; only the message is TTY-gated.
171
+ if (!isCurrentSessionEligible())
172
+ return false;
173
+ if (!shouldConfirmFirstWorkBearingSync({
174
+ flagEnabled: isFirstSyncNextStepEnabled(),
175
+ interactive: true,
176
+ alreadyCompleted: false,
177
+ workBearing: true,
178
+ }))
179
+ return false;
180
+ console.log(FIRST_SYNC_CONFIRMATION_COPY);
181
+ if (firstSyncStepMarkerExists("shown", identity))
182
+ queueOutcome("followed");
183
+ return true;
184
+ }
185
+ /** Drain outcomes once so each shown/followed event is sent at most once per run. */
186
+ export function takeFirstSyncStepOutcomes() {
187
+ return pendingOutcomes.splice(0, pendingOutcomes.length);
188
+ }
189
+ //# sourceMappingURL=first-sync-next-step.js.map