@indigoai-us/hq-cli 5.292.0 → 5.294.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 +40 -0
- package/assets/scaffold/core/scripts/outpost-jobs-reconcile.sh +5 -1
- package/dist/command-catalog.generated.d.ts +45 -24
- package/dist/command-catalog.generated.js +57 -30
- package/dist/commands/core-command-catalog.js +3 -2
- package/dist/commands/core-delegate-w1b.d.ts +2 -0
- package/dist/commands/core-delegate-w1b.js +28 -2
- package/dist/commands/core-delegate.d.ts +3 -1
- package/dist/commands/core-delegate.js +35 -5
- package/dist/commands/core-handoff-fast.d.ts +18 -0
- package/dist/commands/core-handoff-fast.js +103 -0
- package/dist/commands/core-handoff-open-steps.d.ts +21 -0
- package/dist/commands/core-handoff-open-steps.js +264 -0
- package/dist/commands/core-handoff.d.ts +4 -2
- package/dist/commands/core-handoff.js +22 -249
- package/dist/commands/core-jobs-native.d.ts +2 -0
- package/dist/commands/core-jobs-native.js +22 -11
- package/dist/commands/core-knowledge-prefs.d.ts +2 -0
- package/dist/commands/core-knowledge-prefs.js +13 -1
- package/dist/commands/core-ontology-native.d.ts +2 -0
- package/dist/commands/core-ontology-native.js +22 -2
- package/dist/commands/core-policy.d.ts +2 -0
- package/dist/commands/core-policy.js +18 -1
- package/dist/commands/core.js +2 -1
- package/dist/commands/daemon.d.ts +2 -1
- package/dist/commands/daemon.js +22 -7
- package/dist/commands/lanes-autopilot.d.ts +11 -0
- package/dist/commands/lanes-autopilot.js +336 -0
- package/dist/commands/lanes-move.js +54 -1
- package/dist/commands/lanes-questions.js +12 -5
- package/dist/commands/lanes-shared.d.ts +17 -0
- package/dist/commands/lanes-stories.d.ts +14 -0
- package/dist/commands/lanes-stories.js +308 -0
- package/dist/commands/lanes.d.ts +2 -0
- package/dist/commands/lanes.js +158 -314
- package/dist/fast-core.js +53 -25
- package/dist/fast-scaffold.d.ts +15 -2
- package/dist/fast-scaffold.js +167 -7
- package/dist/lib/core-utils/sentry-report.js +2 -2
- package/dist/lib/core-utils/worktree-resume.d.ts +2 -0
- package/dist/lib/core-utils/worktree-resume.js +16 -0
- package/dist/lib/daemon/migrate.d.ts +8 -1
- package/dist/lib/daemon/migrate.js +19 -7
- package/dist/lib/daemon/run.d.ts +11 -0
- package/dist/lib/daemon/run.js +17 -1
- package/dist/lib/lanes/autopilot-metrics.d.ts +99 -0
- package/dist/lib/lanes/autopilot-metrics.js +301 -0
- package/dist/lib/lanes/autopilot.d.ts +13 -1
- package/dist/lib/lanes/autopilot.js +271 -28
- package/dist/lib/lanes/grants.d.ts +1 -1
- package/dist/lib/lanes/grants.js +7 -5
- package/dist/lib/lanes/index.d.ts +1 -1
- package/dist/lib/lanes/keep-alive.d.ts +5 -0
- package/dist/lib/lanes/keep-alive.js +9 -4
- package/dist/lib/lanes/questions.d.ts +2 -1
- package/dist/lib/lanes/questions.js +2 -0
- package/dist/lib/lanes/reconcile.js +186 -9
- package/dist/lib/lanes/spawn.js +4 -0
- package/dist/lib/lanes/store.d.ts +2 -0
- package/dist/lib/lanes/store.js +53 -4
- package/dist/lib/lanes/types.d.ts +13 -1
- package/dist/lib/lanes/types.js +2 -2
- package/dist/lib/lanes/watcher.js +3 -1
- package/dist/native-fast-route.d.ts +3 -1
- package/dist/native-fast-route.js +10 -8
- package/dist/utils/contribution-table.d.ts +1 -1
- package/dist/utils/fast-stream-errors.d.ts +12 -0
- package/dist/utils/fast-stream-errors.js +18 -0
- package/dist/utils/scaffold-fast-import-guard.d.ts +2 -2
- package/dist/utils/scaffold-fast-import-guard.js +6 -3
- package/dist/utils/self-update.d.ts +7 -0
- package/dist/utils/self-update.js +5 -1
- package/dist/utils/version-gate.d.ts +15 -0
- package/dist/utils/version-gate.js +46 -2
- package/package.json +1 -1
|
@@ -7,7 +7,6 @@ import { serializeJqJson } from "../lib/core-utils/jq-json-serializer.js";
|
|
|
7
7
|
import { resolveLiveRoot } from "../utils/hq-roots.js";
|
|
8
8
|
import { runBundledScript } from "../utils/run-bundled-script.js";
|
|
9
9
|
import { describeCoreCommand } from "./core-command-catalog.js";
|
|
10
|
-
import { coreNativeJobsEnabled } from "./core-native-jobs-flag.js";
|
|
11
10
|
const SCHEDULE_PARSE_ASSET = "core/scripts/jobs-schedule-parse.sh";
|
|
12
11
|
const VALIDATE_ASSET = "core/scripts/jobs-validate.sh";
|
|
13
12
|
const RECONCILE_ASSET = "core/scripts/outpost-jobs-reconcile.sh";
|
|
@@ -518,23 +517,26 @@ function collectJobFiles(args, emit) {
|
|
|
518
517
|
const stat = fs.statSync(argument);
|
|
519
518
|
if (stat.isFile()) {
|
|
520
519
|
if (/\.(yaml|yml)$/.test(argument))
|
|
521
|
-
files.push(argument);
|
|
520
|
+
files.push({ diskPath: argument, displayPath: argument });
|
|
522
521
|
else
|
|
523
522
|
emit(argument, "path", "not a .yaml/.yml job file");
|
|
524
523
|
return;
|
|
525
524
|
}
|
|
526
525
|
if (stat.isDirectory()) {
|
|
527
|
-
const
|
|
526
|
+
const strippedArgument = argument.replace(/\/+$/, "") || path.parse(argument).root;
|
|
527
|
+
const walk = (directory, displayDirectory) => {
|
|
528
528
|
const entries = fs.readdirSync(directory, { withFileTypes: true });
|
|
529
529
|
for (const entry of entries) {
|
|
530
530
|
const file = path.join(directory, entry.name);
|
|
531
|
+
const displayFile = `${displayDirectory.replace(/\/$/, "")}/${entry.name}`;
|
|
531
532
|
if (entry.isDirectory())
|
|
532
|
-
walk(file);
|
|
533
|
-
else if (entry.isFile() && /\.(yaml|yml)$/.test(entry.name))
|
|
534
|
-
files.push(file);
|
|
533
|
+
walk(file, displayFile);
|
|
534
|
+
else if (entry.isFile() && /\.(yaml|yml)$/.test(entry.name)) {
|
|
535
|
+
files.push({ diskPath: file, displayPath: displayFile });
|
|
536
|
+
}
|
|
535
537
|
}
|
|
536
538
|
};
|
|
537
|
-
walk(argument);
|
|
539
|
+
walk(argument, strippedArgument);
|
|
538
540
|
return;
|
|
539
541
|
}
|
|
540
542
|
emit(argument, "path", "file or directory not found");
|
|
@@ -559,19 +561,19 @@ export function validateJobs(args) {
|
|
|
559
561
|
errors.push(`jobs-validate: ${file}: ${field}: ${message}`);
|
|
560
562
|
};
|
|
561
563
|
const seenIds = [];
|
|
562
|
-
const files = collectJobFiles(args, emit).sort(comparePathsLikeSort);
|
|
564
|
+
const files = collectJobFiles(args, emit).sort((left, right) => comparePathsLikeSort(left.diskPath, right.diskPath));
|
|
563
565
|
if (!files.length) {
|
|
564
566
|
for (const error of errors)
|
|
565
567
|
process.stderr.write(`${error}\n`);
|
|
566
568
|
process.stderr.write("jobs-validate: no job YAML files found\n");
|
|
567
569
|
return 1;
|
|
568
570
|
}
|
|
569
|
-
for (const
|
|
571
|
+
for (const { diskPath, displayPath } of files) {
|
|
570
572
|
try {
|
|
571
|
-
validateJob(
|
|
573
|
+
validateJob(displayPath, parseJobFile(fs.readFileSync(diskPath, "utf8")), seenIds, emit);
|
|
572
574
|
}
|
|
573
575
|
catch {
|
|
574
|
-
emit(
|
|
576
|
+
emit(displayPath, "yaml", "failed to parse YAML");
|
|
575
577
|
}
|
|
576
578
|
}
|
|
577
579
|
for (const error of errors)
|
|
@@ -1292,6 +1294,7 @@ export function registerCoreJobsNativeCommand(core) {
|
|
|
1292
1294
|
.action(async (args, _options, current) => {
|
|
1293
1295
|
const argv = rawArgumentsForCommand(current, args);
|
|
1294
1296
|
const groupHqRoot = core.opts().hqRoot;
|
|
1297
|
+
const { coreNativeJobsEnabled } = await import("./core-native-jobs-flag.js");
|
|
1295
1298
|
if (!await coreNativeJobsEnabled()) {
|
|
1296
1299
|
const hqRoot = asset === RECONCILE_ASSET && !argv.includes("--hq-root")
|
|
1297
1300
|
&& !argv.includes("--help") && !argv.includes("-h")
|
|
@@ -1328,4 +1331,12 @@ export function rawArgumentsForCommand(command, fallback, raw = process.argv) {
|
|
|
1328
1331
|
}
|
|
1329
1332
|
return start >= 0 ? raw.slice(start) : (command.args.length ? command.args : fallback);
|
|
1330
1333
|
}
|
|
1334
|
+
/** Fast-entry adapter; the shared family flag is resolved before this module loads. */
|
|
1335
|
+
export async function runJobsFast(args, _stdin, _cwd, _liveRoot, commandName, hqRootArg) {
|
|
1336
|
+
if (commandName === "schedule-parse")
|
|
1337
|
+
return runScheduleParse([...args]);
|
|
1338
|
+
if (commandName === "validate")
|
|
1339
|
+
return validateJobs([...args]);
|
|
1340
|
+
return runReconcile([...args], hqRootArg ?? process.env.HQ_ROOT);
|
|
1341
|
+
}
|
|
1331
1342
|
//# sourceMappingURL=core-jobs-native.js.map
|
|
@@ -6,5 +6,7 @@ export type CoreCommandResult = {
|
|
|
6
6
|
stderr: string;
|
|
7
7
|
};
|
|
8
8
|
export declare function runKnowledgePrefs(args: readonly string[], root: string): CoreCommandResult;
|
|
9
|
+
/** Fast-entry adapter; family gating and shell fallback happen before import. */
|
|
10
|
+
export declare function runKnowledgePrefsFast(args: readonly string[], _stdin: string, _cwd: string, hqRoot: string | undefined): number;
|
|
9
11
|
export declare function registerCoreKnowledgePrefsCommand(core: Command): void;
|
|
10
12
|
//# sourceMappingURL=core-knowledge-prefs.d.ts.map
|
|
@@ -9,7 +9,6 @@ import * as path from 'node:path';
|
|
|
9
9
|
import { resolveLiveRoot } from '../utils/hq-roots.js';
|
|
10
10
|
import { runBundledScript } from '../utils/run-bundled-script.js';
|
|
11
11
|
import { describeCoreCommand } from './core-command-catalog.js';
|
|
12
|
-
import { coreNativePolicyEnabled } from './core-native-policy-flag.js';
|
|
13
12
|
export const KNOWLEDGE_PREFS_ASSET = 'core/scripts/knowledge-prefs.sh';
|
|
14
13
|
const DEFAULTS = {
|
|
15
14
|
signals_enabled: 'true',
|
|
@@ -84,6 +83,18 @@ export function runKnowledgePrefs(args, root) {
|
|
|
84
83
|
stderr: '',
|
|
85
84
|
};
|
|
86
85
|
}
|
|
86
|
+
/** Fast-entry adapter; family gating and shell fallback happen before import. */
|
|
87
|
+
export function runKnowledgePrefsFast(args, _stdin, _cwd, hqRoot) {
|
|
88
|
+
const root = hqRoot ?? resolveLiveRoot();
|
|
89
|
+
const result = runKnowledgePrefs(args, root);
|
|
90
|
+
if (result.stdout)
|
|
91
|
+
process.stdout.write(result.stdout);
|
|
92
|
+
if (result.stderr)
|
|
93
|
+
process.stderr.write(result.stderr);
|
|
94
|
+
if (result.code !== 0)
|
|
95
|
+
process.exitCode = result.code;
|
|
96
|
+
return result.code;
|
|
97
|
+
}
|
|
87
98
|
export function registerCoreKnowledgePrefsCommand(core) {
|
|
88
99
|
const command = core
|
|
89
100
|
.command('knowledge-prefs')
|
|
@@ -97,6 +108,7 @@ export function registerCoreKnowledgePrefsCommand(core) {
|
|
|
97
108
|
const hqRoot = resolveLiveRoot({
|
|
98
109
|
hqRoot: core.opts().hqRoot,
|
|
99
110
|
});
|
|
111
|
+
const { coreNativePolicyEnabled } = await import('./core-native-policy-flag.js');
|
|
100
112
|
if (!await coreNativePolicyEnabled()) {
|
|
101
113
|
const result = runBundledScript({
|
|
102
114
|
asset: KNOWLEDGE_PREFS_ASSET,
|
|
@@ -5,6 +5,8 @@ export interface ScriptResult {
|
|
|
5
5
|
stdout: string;
|
|
6
6
|
stderr: string;
|
|
7
7
|
}
|
|
8
|
+
/** Fast-entry adapter; family gating and shell fallback happen before import. */
|
|
9
|
+
export declare function runOntologyNativeFast(args: readonly string[], _stdin: string, cwd: string, hqRoot: string | undefined, commandName: string): number;
|
|
8
10
|
export declare function sourceYamlValidate(file: string | undefined): ScriptResult;
|
|
9
11
|
export declare function candidateCommand(args: string[], root: string): ScriptResult;
|
|
10
12
|
export declare function briefCommand(args: string[], defaultRoot: string): ScriptResult;
|
|
@@ -3,7 +3,6 @@ import { createHash } from "node:crypto";
|
|
|
3
3
|
import { spawnSync } from "node:child_process";
|
|
4
4
|
import * as fs from "node:fs";
|
|
5
5
|
import * as path from "node:path";
|
|
6
|
-
import { resolveProcessFlagGate } from "../lib/flag-registry.js";
|
|
7
6
|
import { runBundledScript } from "../utils/run-bundled-script.js";
|
|
8
7
|
import { resolveBundledAsset } from "../utils/hq-roots.js";
|
|
9
8
|
import { describeCoreCommand } from "./core-command-catalog.js";
|
|
@@ -34,6 +33,26 @@ function writeResult(result) {
|
|
|
34
33
|
process.stderr.write(result.stderr);
|
|
35
34
|
process.exitCode = result.code;
|
|
36
35
|
}
|
|
36
|
+
/** Fast-entry adapter; family gating and shell fallback happen before import. */
|
|
37
|
+
export function runOntologyNativeFast(args, _stdin, cwd, hqRoot, commandName) {
|
|
38
|
+
const operands = [...args];
|
|
39
|
+
const root = commandName === "source-yaml-validate" ? cwd : hqRoot ?? cwd;
|
|
40
|
+
let result;
|
|
41
|
+
if (commandName === "audience-grant")
|
|
42
|
+
result = audienceGrant(operands, root);
|
|
43
|
+
else if (commandName === "brief")
|
|
44
|
+
result = briefCommand(operands, root);
|
|
45
|
+
else if (commandName === "candidate")
|
|
46
|
+
result = candidateCommand(operands, root);
|
|
47
|
+
else if (commandName === "garden")
|
|
48
|
+
result = gardenCommand(operands, root);
|
|
49
|
+
else if (commandName === "source-worklist")
|
|
50
|
+
result = worklistCommand(operands, root);
|
|
51
|
+
else
|
|
52
|
+
result = sourceYamlValidate(operands[0]);
|
|
53
|
+
writeResult(result);
|
|
54
|
+
return result.code;
|
|
55
|
+
}
|
|
37
56
|
function runHq(args, output = "capture") {
|
|
38
57
|
const executable = process.env.HQ_BIN || "hq";
|
|
39
58
|
const result = spawnSync(executable, args, {
|
|
@@ -869,7 +888,7 @@ export function registerCoreOntologyNativeCommands(ontology, rootFor) {
|
|
|
869
888
|
.allowExcessArguments()
|
|
870
889
|
.helpOption(false)
|
|
871
890
|
.argument("[args...]", "arguments accepted for shell ABI compatibility")
|
|
872
|
-
.action((args = [], _options, commandContext) => {
|
|
891
|
+
.action(async (args = [], _options, commandContext) => {
|
|
873
892
|
const argv = process.argv.slice(2);
|
|
874
893
|
const coreIndex = argv.indexOf("core");
|
|
875
894
|
const ontologyIndex = argv.indexOf("ontology", coreIndex + 1);
|
|
@@ -877,6 +896,7 @@ export function registerCoreOntologyNativeCommands(ontology, rootFor) {
|
|
|
877
896
|
const forwarded = commandIndex >= 0 ? argv.slice(commandIndex + 1)
|
|
878
897
|
: commandContext.args.length > 0 ? commandContext.args : args;
|
|
879
898
|
const liveRoot = entry.root === "live" ? rootFor() : process.cwd();
|
|
899
|
+
const { resolveProcessFlagGate } = await import("../lib/flag-registry.js");
|
|
880
900
|
if (!resolveProcessFlagGate(FLAG, { fallback: false }, () => false)) {
|
|
881
901
|
const result = runBundledScript({
|
|
882
902
|
asset: `${ASSET}${entry.asset}`,
|
|
@@ -11,5 +11,7 @@ export type CorePolicyResult = {
|
|
|
11
11
|
export declare function runPolicyAgeReport(args: readonly string[], root: string, env?: NodeJS.ProcessEnv, nowEpoch?: number): CorePolicyResult;
|
|
12
12
|
export declare function runPolicyFrontmatter(args: readonly string[], cwd: string): FrontmatterResult;
|
|
13
13
|
export declare function runPolicyRetire(args: readonly string[], root: string, cwd: string, env?: NodeJS.ProcessEnv, now?: Date): CorePolicyResult;
|
|
14
|
+
/** Fast-entry adapter; family gating and shell fallback happen before import. */
|
|
15
|
+
export declare function runPolicyFast(args: readonly string[], _stdin: string, cwd: string, hqRoot: string | undefined, commandName: string): number;
|
|
14
16
|
export declare function registerCorePolicyCommand(core: Command): void;
|
|
15
17
|
//# sourceMappingURL=core-policy.d.ts.map
|
|
@@ -7,7 +7,6 @@ import { policyValidatorDiagnostic } from '../lib/policy-validator.js';
|
|
|
7
7
|
import { resolveLiveRoot, resolveBundledAsset } from '../utils/hq-roots.js';
|
|
8
8
|
import { runBundledScript } from '../utils/run-bundled-script.js';
|
|
9
9
|
import { describeCoreCommand } from './core-command-catalog.js';
|
|
10
|
-
import { coreNativePolicyEnabled } from './core-native-policy-flag.js';
|
|
11
10
|
import { runPolicyFrontmatter as runPolicyFrontmatterImpl } from './core-policy-frontmatter.js';
|
|
12
11
|
export const POLICY_AGE_REPORT_ASSET = 'core/scripts/policy-age-report.sh';
|
|
13
12
|
export const POLICY_RETIRE_ASSET = 'core/scripts/policy-retire.sh';
|
|
@@ -947,6 +946,21 @@ function writeResult(result) {
|
|
|
947
946
|
if (result.code !== 0)
|
|
948
947
|
process.exitCode = result.code;
|
|
949
948
|
}
|
|
949
|
+
/** Fast-entry adapter; family gating and shell fallback happen before import. */
|
|
950
|
+
export function runPolicyFast(args, _stdin, cwd, hqRoot, commandName) {
|
|
951
|
+
let result;
|
|
952
|
+
if (commandName === "frontmatter") {
|
|
953
|
+
result = runPolicyFrontmatter(args, cwd);
|
|
954
|
+
}
|
|
955
|
+
else {
|
|
956
|
+
const root = hqRoot ?? resolveLiveRoot();
|
|
957
|
+
result = commandName === "age-report"
|
|
958
|
+
? runPolicyAgeReport(args, root)
|
|
959
|
+
: runPolicyRetire(args, root, cwd);
|
|
960
|
+
}
|
|
961
|
+
writeResult(result);
|
|
962
|
+
return result.code;
|
|
963
|
+
}
|
|
950
964
|
export function registerCorePolicyCommand(core) {
|
|
951
965
|
const group = core.command('policy').description('Policy maintenance commands');
|
|
952
966
|
const register = (name, asset, summary, rootKind) => {
|
|
@@ -963,6 +977,7 @@ export function registerCorePolicyCommand(core) {
|
|
|
963
977
|
const ageReport = register('age-report', POLICY_AGE_REPORT_ASSET, 'Report policy usage and retirement candidates', 'live');
|
|
964
978
|
ageReport.action(async (args = [], _options, command) => {
|
|
965
979
|
const operands = command.args.length > 0 ? command.args : args;
|
|
980
|
+
const { coreNativePolicyEnabled } = await import('./core-native-policy-flag.js');
|
|
966
981
|
if (!await coreNativePolicyEnabled()) {
|
|
967
982
|
const root = resolveLiveRoot({ hqRoot: core.opts().hqRoot });
|
|
968
983
|
const result = runBundledScript({ asset: POLICY_AGE_REPORT_ASSET, args: operands, cwd: process.cwd(), hqRoot: root });
|
|
@@ -976,6 +991,7 @@ export function registerCorePolicyCommand(core) {
|
|
|
976
991
|
const retire = register('retire', POLICY_RETIRE_ASSET, 'Retire or restore a policy', 'live');
|
|
977
992
|
retire.action(async (args = [], _options, command) => {
|
|
978
993
|
const operands = command.args.length > 0 ? command.args : args;
|
|
994
|
+
const { coreNativePolicyEnabled } = await import('./core-native-policy-flag.js');
|
|
979
995
|
if (!await coreNativePolicyEnabled()) {
|
|
980
996
|
const root = resolveLiveRoot({ hqRoot: core.opts().hqRoot });
|
|
981
997
|
const result = runBundledScript({ asset: POLICY_RETIRE_ASSET, args: operands, cwd: process.cwd(), hqRoot: root });
|
|
@@ -989,6 +1005,7 @@ export function registerCorePolicyCommand(core) {
|
|
|
989
1005
|
const frontmatter = register('frontmatter', POLICY_FRONTMATTER_ASSET, 'Extract policy frontmatter', 'cwd');
|
|
990
1006
|
frontmatter.action(async (args = [], _options, command) => {
|
|
991
1007
|
const operands = command.args.length > 0 ? command.args : args;
|
|
1008
|
+
const { coreNativePolicyEnabled } = await import('./core-native-policy-flag.js');
|
|
992
1009
|
if (!await coreNativePolicyEnabled()) {
|
|
993
1010
|
const result = runBundledScript({ asset: POLICY_FRONTMATTER_ASSET, args: operands, cwd: process.cwd() });
|
|
994
1011
|
if (result.code !== 0)
|
package/dist/commands/core.js
CHANGED
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
import { Option } from "commander";
|
|
32
32
|
import { registerCoreCheckpointCommand } from "./core-checkpoint.js";
|
|
33
33
|
import { registerCoreDelegateCommand } from "./core-delegate.js";
|
|
34
|
+
import { registerCoreDelegateW1b } from "./core-delegate-w1b.js";
|
|
34
35
|
import { registerCoreHandoffCommand } from "./core-handoff.js";
|
|
35
36
|
import { registerCoreOntologyCommand } from "./core-ontology.js";
|
|
36
37
|
import { registerCoreKnowledgePrefsCommand } from "./core-knowledge-prefs.js";
|
|
@@ -347,7 +348,7 @@ export function registerCoreCommands(program) {
|
|
|
347
348
|
registerCoreCheckpointCommand(core);
|
|
348
349
|
registerCoreOntologyCommand(core);
|
|
349
350
|
registerCoreCheckpointGateSettingCommand(core);
|
|
350
|
-
registerCoreDelegateCommand(core);
|
|
351
|
+
registerCoreDelegateCommand(core, registerCoreDelegateW1b);
|
|
351
352
|
registerCoreHandoffCommand(core);
|
|
352
353
|
registerCoreKnowledgePrefsCommand(core);
|
|
353
354
|
registerCorePolicyCommand(core);
|
|
@@ -33,7 +33,8 @@ export interface DaemonCommandDeps {
|
|
|
33
33
|
readFile: (p: string) => string;
|
|
34
34
|
/** Writes a root-owned file such as /etc/hq/machine-type, creating its folder. */
|
|
35
35
|
writeFile: (p: string, text: string) => void;
|
|
36
|
-
|
|
36
|
+
/** Older units in `home` (default: this user's home). */
|
|
37
|
+
legacyUnits: (home?: string) => LegacyUnit[];
|
|
37
38
|
resolveHqRoot: (flag: string | undefined) => string | undefined;
|
|
38
39
|
/** Home folder of the login user a box's system unit runs as. */
|
|
39
40
|
userHome: (user: string) => string;
|
package/dist/commands/daemon.js
CHANGED
|
@@ -86,9 +86,9 @@ async function loadDefaults(over) {
|
|
|
86
86
|
fs.writeFileSync(p, text, { mode: 0o644 });
|
|
87
87
|
}),
|
|
88
88
|
legacyUnits: over.legacyUnits ??
|
|
89
|
-
(() => findLegacyUnits({
|
|
89
|
+
((dir) => findLegacyUnits({
|
|
90
90
|
platform,
|
|
91
|
-
home,
|
|
91
|
+
home: dir ?? home,
|
|
92
92
|
existsSync: fs.existsSync,
|
|
93
93
|
listDir: (dir) => fs.readdirSync(dir),
|
|
94
94
|
windowsTaskExists: (task) => run("schtasks.exe", ["/Query", "/TN", task]).status === 0,
|
|
@@ -246,11 +246,25 @@ async function runInstall(d, opts) {
|
|
|
246
246
|
}
|
|
247
247
|
d.out(`Installed and started: ${result.unitPath}`);
|
|
248
248
|
}
|
|
249
|
-
|
|
249
|
+
/** Root acting for a box's login user needs that user's uid to reach their systemd manager. */
|
|
250
|
+
function loginUid(d, user) {
|
|
251
|
+
const r = d.run("id", ["-u", user]);
|
|
252
|
+
const uid = Number(r.stdout.trim());
|
|
253
|
+
if (r.status !== 0 || !Number.isInteger(uid) || uid < 0 || r.stdout.trim() === "") {
|
|
254
|
+
throw new DaemonCommandError(`Could not look up the uid of ${user}.`);
|
|
255
|
+
}
|
|
256
|
+
return uid;
|
|
257
|
+
}
|
|
258
|
+
/** Where the older units are: a box's login user's home when root runs this for them. */
|
|
259
|
+
function legacyUnitsFor(d, host) {
|
|
260
|
+
return d.isRoot && host.runAsUser ? d.legacyUnits(d.userHome(host.runAsUser)) : d.legacyUnits();
|
|
261
|
+
}
|
|
262
|
+
function migrateDeps(d, paths, runAsUser) {
|
|
250
263
|
return {
|
|
251
264
|
run: d.run,
|
|
252
265
|
uid: d.uid,
|
|
253
266
|
isRoot: d.isRoot,
|
|
267
|
+
userUnitsOwner: d.isRoot && runAsUser ? { user: runAsUser, uid: loginUid(d, runAsUser) } : undefined,
|
|
254
268
|
adoptedDir: path.join(paths.root, "adopted"),
|
|
255
269
|
recordPath: path.join(paths.root, "adopted.json"),
|
|
256
270
|
// Box system units: root-owned, outside the login user's daemon folder (which handOver chowns to that user).
|
|
@@ -268,7 +282,8 @@ function unrestoredUnits(d, migrate) {
|
|
|
268
282
|
async function runUninstall(d, opts) {
|
|
269
283
|
const host = currentHost(d);
|
|
270
284
|
const { paths, detected } = host;
|
|
271
|
-
|
|
285
|
+
// Only a restore acts on the login user's units.
|
|
286
|
+
const migrate = migrateDeps(d, paths, opts.restoreLegacy ? host.runAsUser : undefined);
|
|
272
287
|
const adopted = unrestoredUnits(d, migrate);
|
|
273
288
|
if (opts.purge && !opts.restoreLegacy && adopted.length > 0) {
|
|
274
289
|
throw new DaemonCommandError(`hq daemon took over ${adopted.map((u) => u.unitId).join(", ")}, and their original units are kept in ${migrate.adoptedDir}. ` +
|
|
@@ -547,13 +562,13 @@ async function runPinHqCloud(d, version, opts) {
|
|
|
547
562
|
d.out("Run `hq daemon trigger updater`; wait for the hq-cloud update or current-version message in `hq daemon logs updater`, then restart `hq daemon restart sync`, `hq daemon restart heartbeat`, and `hq daemon restart session-host`.");
|
|
548
563
|
}
|
|
549
564
|
async function runMigrate(d, opts) {
|
|
550
|
-
const
|
|
565
|
+
const host = currentHost(d);
|
|
566
|
+
const units = legacyUnitsFor(d, host);
|
|
551
567
|
if (units.length === 0) {
|
|
552
568
|
d.out("No older HQ background units found. Nothing to migrate.");
|
|
553
569
|
return;
|
|
554
570
|
}
|
|
555
571
|
if (opts.apply) {
|
|
556
|
-
const host = currentHost(d);
|
|
557
572
|
// Stopping the older units with nothing installed to replace them would
|
|
558
573
|
// leave their services off.
|
|
559
574
|
const installed = daemonUnitInstalled({
|
|
@@ -565,7 +580,7 @@ async function runMigrate(d, opts) {
|
|
|
565
580
|
if (!installed) {
|
|
566
581
|
throw new DaemonCommandError("hq daemon is not installed here yet. Run `hq daemon install` first, then `hq daemon migrate --apply`.");
|
|
567
582
|
}
|
|
568
|
-
const result = adoptLegacyUnits(units, migrateDeps(d, host.paths));
|
|
583
|
+
const result = adoptLegacyUnits(units, migrateDeps(d, host.paths, host.runAsUser));
|
|
569
584
|
handOver(d, host);
|
|
570
585
|
for (const a of result.adopted)
|
|
571
586
|
d.out(`Took over ${a.unitId} from ${describeLegacyUnit(a)}`);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import { type ReconcileHost } from "../lib/lanes/reconcile.js";
|
|
3
|
+
type WrapHandler = <Args extends unknown[]>(action: (...args: Args) => Promise<void>) => (...args: Args) => Promise<void>;
|
|
4
|
+
export interface LaneAutopilotReportDeps {
|
|
5
|
+
hqRoot: () => string;
|
|
6
|
+
now: () => Date;
|
|
7
|
+
currentHost: () => ReconcileHost;
|
|
8
|
+
}
|
|
9
|
+
export declare function registerLaneAutopilotReportCommand(parent: Command, deps: LaneAutopilotReportDeps, wrap: WrapHandler): void;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=lanes-autopilot.d.ts.map
|