@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.
- package/CHANGELOG.md +65 -2
- package/README.md +32 -1
- package/dist/command-catalog.generated.d.ts +83 -536
- package/dist/command-catalog.generated.js +129 -714
- package/dist/command-registration-plan.d.ts +12 -0
- package/dist/command-registration-plan.js +2 -0
- package/dist/commands/cloud.js +40 -0
- package/dist/commands/core-checkpoint.js +3 -1
- package/dist/commands/core-command-catalog.d.ts +32 -0
- package/dist/commands/core-command-catalog.js +58 -0
- package/dist/commands/core-ontology.js +9 -4
- package/dist/commands/core.d.ts +4 -0
- package/dist/commands/core.js +79 -75
- package/dist/commands/daemon.d.ts +0 -3
- package/dist/commands/daemon.js +1 -173
- package/dist/commands/deploy-comments.d.ts +3 -0
- package/dist/commands/deploy-comments.js +159 -0
- package/dist/commands/lanes-checks.d.ts +0 -1
- package/dist/commands/lanes-checks.js +217 -54
- package/dist/commands/lanes-hold.js +40 -2
- package/dist/commands/lanes-message.js +98 -14
- package/dist/commands/lanes-move.d.ts +12 -0
- package/dist/commands/lanes-move.js +342 -0
- package/dist/commands/lanes-resume.js +3 -1
- package/dist/commands/lanes-shared.d.ts +39 -3
- package/dist/commands/lanes-shared.js +59 -0
- package/dist/commands/lanes.d.ts +3 -5
- package/dist/commands/lanes.js +206 -478
- package/dist/commands/report.js +2 -14
- package/dist/commands/sync-mode.d.ts +0 -11
- package/dist/commands/sync-mode.js +0 -30
- package/dist/fast-core.js +1 -1
- package/dist/{commands/scaffold-fast.d.ts → fast-scaffold.d.ts} +1 -1
- package/dist/{commands/scaffold-fast.js → fast-scaffold.js} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/lib/checkpoint-ontology/apply.d.ts +8 -0
- package/dist/lib/checkpoint-ontology/apply.js +33 -0
- package/dist/lib/checkpoint-ontology/plan.d.ts +15 -0
- package/dist/lib/checkpoint-ontology/plan.js +15 -0
- package/dist/lib/daemon/catalog.d.ts +2 -18
- package/dist/lib/daemon/catalog.js +2 -18
- package/dist/lib/daemon/config.d.ts +0 -6
- package/dist/lib/daemon/config.js +2 -15
- package/dist/lib/daemon/requests.d.ts +0 -4
- package/dist/lib/daemon/requests.js +0 -2
- package/dist/lib/daemon/run.js +19 -78
- package/dist/lib/daemon/supervisor.d.ts +0 -8
- package/dist/lib/daemon/supervisor.js +1 -101
- package/dist/lib/deploy-api.d.ts +6 -0
- package/dist/lib/deploy-api.js +21 -0
- package/dist/lib/doctor/checks/scaffold-cli-floor.d.ts +7 -0
- package/dist/lib/doctor/checks/scaffold-cli-floor.js +73 -0
- package/dist/lib/doctor/fix/apply.d.ts +17 -2
- package/dist/lib/doctor/fix/apply.js +111 -57
- package/dist/lib/doctor/fix/json-output.d.ts +9 -1
- package/dist/lib/doctor/fix/json-output.js +11 -0
- package/dist/lib/doctor/registry.js +2 -0
- package/dist/lib/first-sync-next-step.d.ts +37 -0
- package/dist/lib/first-sync-next-step.js +189 -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/hire-grant-dispatch.d.ts +6 -1
- package/dist/lib/lanes/hire-grant-dispatch.js +78 -3
- package/dist/lib/lanes/keep-alive.d.ts +3 -2
- package/dist/lib/lanes/keep-alive.js +2 -2
- package/dist/lib/lanes/merge-command.d.ts +1 -0
- package/dist/lib/lanes/merge-command.js +299 -33
- package/dist/lib/lanes/orphans.d.ts +7 -0
- package/dist/lib/lanes/orphans.js +39 -4
- package/dist/lib/lanes/tracker-store.d.ts +2 -18
- package/dist/lib/lanes/tracker-store.js +1 -172
- package/dist/lib/scaffold-cli-floor.d.ts +9 -0
- package/dist/lib/scaffold-cli-floor.js +50 -0
- package/dist/main.js +4 -1
- package/dist/utils/cli-telemetry.d.ts +7 -1
- package/dist/utils/cli-telemetry.js +84 -8
- package/dist/utils/contribution-table.d.ts +1 -1
- package/dist/utils/scaffold-fast-import-guard.d.ts +3 -0
- package/dist/utils/scaffold-fast-import-guard.js +28 -0
- package/dist/utils/scaffold-packlist-guard.d.ts +7 -0
- package/dist/utils/scaffold-packlist-guard.js +23 -0
- package/dist/utils/scaffold-sibling-references.d.ts +21 -0
- package/dist/utils/scaffold-sibling-references.js +156 -0
- package/package.json +2 -2
- package/dist/commands/lanes-import.d.ts +0 -14
- package/dist/commands/lanes-import.js +0 -1210
- package/dist/commands/lanes-tracker.d.ts +0 -18
- package/dist/commands/lanes-tracker.js +0 -452
- package/dist/lib/daemon/sync-runner.d.ts +0 -58
- 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
|