@indigoai-us/hq-cli 5.345.171 → 5.345.173

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 (48) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/command-catalog.generated.d.ts +74 -2
  3. package/dist/command-catalog.generated.js +88 -2
  4. package/dist/command-registration-plan.d.ts +7 -0
  5. package/dist/command-registration-plan.js +1 -0
  6. package/dist/commands/bot.js +46 -8
  7. package/dist/commands/cloud.js +9 -5
  8. package/dist/commands/daemon.js +16 -1
  9. package/dist/commands/files.d.ts +1 -0
  10. package/dist/commands/files.js +22 -4
  11. package/dist/commands/sync-core.d.ts +22 -0
  12. package/dist/commands/sync-core.js +126 -0
  13. package/dist/hq-cloud-sync-runner/bin/sync-runner.js +278 -224
  14. package/dist/hq-cloud-sync-runner/package.json +1 -1
  15. package/dist/lib/bot/fleet-local.d.ts +16 -1
  16. package/dist/lib/bot/fleet-local.js +99 -48
  17. package/dist/lib/bot/fleet-python.d.ts +47 -0
  18. package/dist/lib/bot/fleet-python.js +218 -0
  19. package/dist/lib/bot/index.d.ts +1 -0
  20. package/dist/lib/bot/index.js +1 -0
  21. package/dist/lib/bot/prompt.d.ts +6 -1
  22. package/dist/lib/bot/prompt.js +8 -3
  23. package/dist/lib/daemon/catalog.d.ts +12 -4
  24. package/dist/lib/daemon/catalog.js +70 -27
  25. package/dist/lib/daemon/config.d.ts +0 -7
  26. package/dist/lib/daemon/config.js +0 -32
  27. package/dist/lib/daemon/run.d.ts +5 -1
  28. package/dist/lib/daemon/run.js +48 -11
  29. package/dist/lib/daemon/supervisor.js +3 -1
  30. package/dist/lib/sync-core/engine-home.d.ts +45 -0
  31. package/dist/lib/sync-core/engine-home.js +194 -0
  32. package/dist/lib/sync-core/flag.d.ts +17 -0
  33. package/dist/lib/sync-core/flag.js +47 -0
  34. package/dist/lib/sync-core/reconcile.d.ts +31 -0
  35. package/dist/lib/sync-core/reconcile.js +217 -0
  36. package/dist/lib/sync-core/release.d.ts +32 -0
  37. package/dist/lib/sync-core/release.js +142 -0
  38. package/dist/lib/sync-core/rollout-state.d.ts +28 -0
  39. package/dist/lib/sync-core/rollout-state.js +115 -0
  40. package/dist/lib/sync-core/skip.d.ts +7 -0
  41. package/dist/lib/sync-core/skip.js +30 -0
  42. package/dist/lib/vault-sync-switches.d.ts +5 -0
  43. package/dist/lib/vault-sync-switches.js +43 -0
  44. package/dist/utils/remote-list-not-converging.d.ts +21 -0
  45. package/dist/utils/remote-list-not-converging.js +40 -0
  46. package/package.json +8 -8
  47. package/dist/lib/daemon/sync-core-canary.d.ts +0 -12
  48. package/dist/lib/daemon/sync-core-canary.js +0 -61
@@ -0,0 +1,126 @@
1
+ import * as fs from "node:fs";
2
+ import * as os from "node:os";
3
+ import * as path from "node:path";
4
+ import { ensureSyncCoreBinary } from "../lib/sync-core/release.js";
5
+ import { readCompanyRolloutFlag } from "../lib/sync-core/flag.js";
6
+ import { reconcileSyncCore } from "../lib/sync-core/reconcile.js";
7
+ import { readSyncCoreRolloutState, syncCoreRolloutStatePath } from "../lib/sync-core/rollout-state.js";
8
+ import { readVaultSyncSwitches } from "../lib/vault-sync-switches.js";
9
+ function defaultDeps() {
10
+ return {
11
+ home: os.homedir(),
12
+ env: process.env,
13
+ platform: process.platform,
14
+ arch: process.arch,
15
+ out: (line) => console.log(line),
16
+ err: (line) => console.error(line),
17
+ };
18
+ }
19
+ async function resolveHqRoot(flag, env) {
20
+ const configured = flag?.trim() || env.HQ_ROOT?.trim();
21
+ if (configured) {
22
+ const root = path.resolve(configured);
23
+ if (!fs.existsSync(path.join(root, "companies")))
24
+ throw new Error(`${root} is not an HQ folder (no companies/ inside it)`);
25
+ return root;
26
+ }
27
+ const { readDaemonConfig } = await import("../lib/daemon/config.js");
28
+ const { daemonPaths } = await import("../lib/daemon/paths.js");
29
+ const fromDaemon = readDaemonConfig(daemonPaths(os.homedir(), env).configPath).hqRoot;
30
+ if (fromDaemon && fs.existsSync(path.join(fromDaemon, "companies")))
31
+ return fromDaemon;
32
+ const { resolveDefaultHqRoot } = await import("../utils/cognito-session.js");
33
+ const fallback = resolveDefaultHqRoot();
34
+ if (fallback && fs.existsSync(path.join(fallback, "companies")))
35
+ return fallback;
36
+ throw new Error("no HQ folder found; pass --hq-root <path>");
37
+ }
38
+ export async function runSyncCoreReconcile(opts, d = defaultDeps()) {
39
+ const hqRoot = await resolveHqRoot(opts.hqRoot, d.env);
40
+ const [{ VaultClient }, { buildVaultConfig, ensureCognitoIdToken, machineTokenCacheFile, wantsMachineCognitoTokens }] = await Promise.all([import("@indigoai-us/hq-cloud"), import("../utils/cognito-session.js")]);
41
+ const token = await ensureCognitoIdToken({ interactive: false });
42
+ const machine = wantsMachineCognitoTokens({});
43
+ const tokenFile = path.resolve(opts.tokenFile?.trim() || (machine ? machineTokenCacheFile(d.home, d.env) : path.join(d.home, ".hq", "cognito-tokens.json")));
44
+ if (!fs.existsSync(tokenFile))
45
+ throw new Error(`the token file ${tokenFile} does not exist`);
46
+ const client = new VaultClient(buildVaultConfig(token));
47
+ const { resolveCanonicalPersonUid } = await import("./cloud.js");
48
+ const result = await reconcileSyncCore({
49
+ home: d.home,
50
+ hqRoot,
51
+ tokenFile,
52
+ companiesOnly: opts.companiesOnly === true || machine,
53
+ listMemberships: async () => (await client.listMyMemberships()).map((m) => ({ companyUid: m.companyUid })),
54
+ resolvePersonUid: () => resolveCanonicalPersonUid({
55
+ listMyMemberships: () => client.listMyMemberships(),
56
+ listPersonEntities: () => client.entity.listByType("person"),
57
+ getEntity: async () => null,
58
+ }),
59
+ readRolloutFlag: (companyUid) => readCompanyRolloutFlag(companyUid, token, { env: d.env }),
60
+ ensureBinary: (release) => ensureSyncCoreBinary({ home: d.home, platform: d.platform, arch: d.arch, release, env: d.env }),
61
+ log: opts.json ? () => { } : d.out,
62
+ });
63
+ if (opts.json)
64
+ d.out(JSON.stringify(result.state, null, 2));
65
+ else if (result.state.vaults.length === 0)
66
+ d.out("no vault on this machine is switched to the new sync engine");
67
+ return result;
68
+ }
69
+ export function runSyncCoreStatus(opts, d = defaultDeps()) {
70
+ const state = readSyncCoreRolloutState(d.home);
71
+ if (opts.json) {
72
+ d.out(JSON.stringify(state, null, 2));
73
+ return;
74
+ }
75
+ if (!state) {
76
+ d.out(`no rollout state yet (${syncCoreRolloutStatePath(d.home)})`);
77
+ return;
78
+ }
79
+ const switches = readVaultSyncSwitches(d.home);
80
+ d.out(`engine ${state.release} at ${state.binaryPath}, last read ${state.readAt}`);
81
+ if (state.error)
82
+ d.out(`warning: ${state.error}`);
83
+ for (const vault of state.vaults) {
84
+ const legacyOff = vault.kind === "personal" ? switches.personalOff : switches.offCompanies.has(vault.slug ?? "");
85
+ d.out(` ${vault.uid} ${vault.kind}${vault.slug ? ` ${vault.slug}` : ""} ${vault.phase === "full" ? "full" : "read-only"} legacy sync ${legacyOff ? "off" : "still on"} home ${vault.engineHome}`);
86
+ if (vault.plan) {
87
+ const p = vault.plan;
88
+ d.out(` plan ${p.at}: ${p.remoteRows} server rows, ${p.localFiles} local files; would upload ${p.uploads}, download ${p.downloads}, delete ${p.deletes}, write ${p.conflicts} conflict or merge copies`);
89
+ }
90
+ if (vault.hold)
91
+ d.out(` held read-only: ${vault.hold}`);
92
+ }
93
+ for (const skip of state.skipped ?? [])
94
+ d.out(` ${skip.uid} skipped on this machine: ${skip.reason}`);
95
+ if (state.vaults.length === 0)
96
+ d.out(" no vault is switched to the new sync engine");
97
+ }
98
+ export function registerSyncCoreCommand(program, over = {}) {
99
+ const deps = () => ({ ...defaultDeps(), ...over });
100
+ const syncCore = program
101
+ .command("sync-core", { hidden: true })
102
+ .description("Move this machine's vaults between the current sync and the new sync engine, following each company's switch");
103
+ syncCore
104
+ .command("reconcile")
105
+ .description("Read each company's switch, install the engine when needed, and write the engine homes and legacy off-switches")
106
+ .option("--hq-root <path>", "HQ folder (default: the daemon's)")
107
+ .option("--companies-only", "Never move the personal vault (agent boxes)")
108
+ .option("--token-file <path>", "Token file the engine reads (default: this user's hq sign-in)")
109
+ .option("--json", "Print the written rollout state as JSON")
110
+ .action(async (opts) => {
111
+ const d = deps();
112
+ try {
113
+ await runSyncCoreReconcile(opts, d);
114
+ }
115
+ catch (error) {
116
+ d.err(error instanceof Error ? error.message : String(error));
117
+ process.exitCode = 1;
118
+ }
119
+ });
120
+ syncCore
121
+ .command("status")
122
+ .description("Show which vaults are on the new sync engine on this machine")
123
+ .option("--json", "Print JSON")
124
+ .action((opts) => runSyncCoreStatus(opts, deps()));
125
+ }
126
+ //# sourceMappingURL=sync-core.js.map