@indigoai-us/hq-cli 5.345.114 → 5.345.116
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 +13 -0
- package/assets/scaffold/core/scripts/hq-delegate-send.sh +5 -1
- package/dist/commands/bot-jobs.d.ts +1 -11
- package/dist/commands/bot-jobs.js +13 -34
- package/dist/commands/core-audit-log-native.js +1 -1
- package/dist/commands/core-checkpoint-native.d.ts +27 -0
- package/dist/commands/core-checkpoint-native.js +85 -2
- package/dist/commands/core-dm-bind-native.js +1 -1
- package/dist/commands/core-git-pack-extension-check-native.js +1 -1
- package/dist/commands/core-job-native-utils.d.ts +2 -2
- package/dist/commands/core-job-native-utils.js +3 -11
- package/dist/commands/core-job-notify-native.js +1 -2
- package/dist/commands/core-job-probe-native.d.ts +2 -3
- package/dist/commands/core-job-probe-native.js +14 -22
- package/dist/commands/core-job-remediate-native.js +1 -2
- package/dist/commands/core-job-run-native.js +58 -54
- package/dist/commands/core-jobs-native.d.ts +1 -3
- package/dist/commands/core-jobs-native.js +16 -271
- package/dist/commands/core-jobs-schedule.d.ts +7 -0
- package/dist/commands/core-jobs-schedule.js +243 -0
- package/dist/commands/core-native-utilities.d.ts +2 -3
- package/dist/commands/core-native-utilities.js +2 -19
- package/dist/commands/core-pin-native.js +1 -1
- package/dist/commands/core-refresh-vault-access-native.js +1 -1
- package/dist/commands/core-resolve-company-command.js +2 -17
- package/dist/commands/core-work-mesh-bind-trusted-native.js +1 -1
- package/dist/commands/core.js +1 -17
- package/dist/fast-scaffold.d.ts +1 -1
- package/dist/fast-scaffold.js +0 -38
- package/dist/lib/daemon/catalog.d.ts +0 -2
- package/dist/lib/daemon/catalog.js +3 -6
- package/dist/lib/daemon/run.js +0 -7
- package/dist/lib/scan-packages/index.js +6 -0
- package/dist/lib/workers-registry/index.d.ts +16 -0
- package/dist/lib/workers-registry/index.js +1 -1
- package/dist/utils/resident-package-preload.js +2 -7
- package/package.json +1 -1
- package/assets/scaffold/core/scripts/audit-log.sh +0 -384
- package/assets/scaffold/core/scripts/git-pack-extension-check.sh +0 -164
- package/assets/scaffold/core/scripts/hq-dm-bind.sh +0 -590
- package/assets/scaffold/core/scripts/hq-job-notify.sh +0 -389
- package/assets/scaffold/core/scripts/hq-job-probe.sh +0 -865
- package/assets/scaffold/core/scripts/hq-job-remediate.sh +0 -359
- package/assets/scaffold/core/scripts/hq-job-run.sh +0 -1025
- package/assets/scaffold/core/scripts/hq-pin.sh +0 -118
- package/assets/scaffold/core/scripts/jobs-schedule-parse.sh +0 -310
- package/assets/scaffold/core/scripts/jobs-validate.sh +0 -482
- package/assets/scaffold/core/scripts/outpost-jobs-reconcile.sh +0 -836
- package/assets/scaffold/core/scripts/refresh-vault-access.sh +0 -188
- package/assets/scaffold/core/scripts/resolve-company.sh +0 -331
- package/assets/scaffold/core/scripts/work-mesh-live-bind-trusted.sh +0 -184
- package/dist/commands/core-job-post-exit-assets.d.ts +0 -8
- package/dist/commands/core-job-post-exit-assets.js +0 -37
- package/dist/commands/core-native-jobs-flag.d.ts +0 -4
- package/dist/commands/core-native-jobs-flag.js +0 -7
- package/dist/commands/core-native-utilities-flag.d.ts +0 -4
- package/dist/commands/core-native-utilities-flag.js +0 -7
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/** Native schedule parsing shared by hq core and local bot jobs. */
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
const SCHEDULE_PARSE_USAGE = 'usage: jobs-schedule-parse.sh [--tz IANA] "<nl or cron schedule>"\n';
|
|
6
|
+
const CRON_RE = /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)$/;
|
|
7
|
+
const processScheduleParseWriters = {
|
|
8
|
+
stdout: (value) => { process.stdout.write(value); },
|
|
9
|
+
stderr: (value) => { process.stderr.write(value); },
|
|
10
|
+
};
|
|
11
|
+
const DAY_NAMES = {
|
|
12
|
+
sun: 0, sunday: 0, mon: 1, monday: 1, tue: 2, tues: 2, tuesday: 2,
|
|
13
|
+
wed: 3, wednesday: 3, thu: 4, thur: 4, thurs: 4, thursday: 4,
|
|
14
|
+
fri: 5, friday: 5, sat: 6, saturday: 6,
|
|
15
|
+
};
|
|
16
|
+
const DAY_LABELS = {
|
|
17
|
+
"0": "Sunday", "1": "Monday", "2": "Tuesday", "3": "Wednesday",
|
|
18
|
+
"4": "Thursday", "5": "Friday", "6": "Saturday", "1-5": "weekday",
|
|
19
|
+
"*": "day",
|
|
20
|
+
};
|
|
21
|
+
function parseClock(text) {
|
|
22
|
+
const match = /^(\d{1,2})(?::(\d{2}))?\s*(am|pm)?$/i.exec(text.trim().toLowerCase().replace(/ /g, ""));
|
|
23
|
+
if (!match)
|
|
24
|
+
return undefined;
|
|
25
|
+
let hour = Number.parseInt(match[1], 10);
|
|
26
|
+
const minute = Number.parseInt(match[2] || "0", 10);
|
|
27
|
+
const meridiem = match[3];
|
|
28
|
+
if (minute > 59)
|
|
29
|
+
return undefined;
|
|
30
|
+
if (meridiem) {
|
|
31
|
+
if (hour < 1 || hour > 12)
|
|
32
|
+
return undefined;
|
|
33
|
+
hour = meridiem === "am"
|
|
34
|
+
? (hour === 12 ? 0 : hour)
|
|
35
|
+
: (hour === 12 ? 12 : hour + 12);
|
|
36
|
+
}
|
|
37
|
+
else if (hour > 23) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
return [hour, minute];
|
|
41
|
+
}
|
|
42
|
+
function formatClock(hour, minute) {
|
|
43
|
+
const hour12 = hour % 12 || 12;
|
|
44
|
+
return `${hour12}:${String(minute).padStart(2, "0")} ${hour < 12 ? "AM" : "PM"}`;
|
|
45
|
+
}
|
|
46
|
+
function humanizeCron(cron, timezone) {
|
|
47
|
+
const fields = cron.split(/\s+/);
|
|
48
|
+
if (fields.length !== 5)
|
|
49
|
+
return `Cron \`${cron}\` (${timezone})`;
|
|
50
|
+
const [minute, hour, dayOfMonth, month, dayOfWeek] = fields;
|
|
51
|
+
if (/^\d+$/.test(minute) && /^\d+$/.test(hour) && dayOfMonth === "*"
|
|
52
|
+
&& month === "*" && (dayOfWeek === "*" || dayOfWeek === "1-5")) {
|
|
53
|
+
const day = dayOfWeek === "1-5" ? "Every weekday" : "Every day";
|
|
54
|
+
return `${day} at ${formatClock(+hour, +minute)} (${timezone})`;
|
|
55
|
+
}
|
|
56
|
+
if (/^\d+$/.test(minute) && /^\d+$/.test(hour) && dayOfMonth === "*"
|
|
57
|
+
&& month === "*" && /^\d+$/.test(dayOfWeek)) {
|
|
58
|
+
const day = DAY_LABELS[dayOfWeek] || `day ${dayOfWeek}`;
|
|
59
|
+
return `Every ${day} at ${formatClock(+hour, +minute)} (${timezone})`;
|
|
60
|
+
}
|
|
61
|
+
if (minute.startsWith("*/") && hour === "*" && dayOfMonth === "*"
|
|
62
|
+
&& month === "*" && dayOfWeek === "*") {
|
|
63
|
+
return `Every ${minute.slice(2)} minutes (${timezone})`;
|
|
64
|
+
}
|
|
65
|
+
if (minute === "0" && hour.startsWith("*/") && dayOfMonth === "*"
|
|
66
|
+
&& month === "*" && dayOfWeek === "*") {
|
|
67
|
+
return `Every ${hour.slice(2)} hours (${timezone})`;
|
|
68
|
+
}
|
|
69
|
+
if (minute === "0" && hour === "*" && dayOfMonth === "*"
|
|
70
|
+
&& month === "*" && dayOfWeek === "*") {
|
|
71
|
+
return `Every hour on the hour (${timezone})`;
|
|
72
|
+
}
|
|
73
|
+
return `Cron \`${cron}\` (${timezone})`;
|
|
74
|
+
}
|
|
75
|
+
function parseNaturalLanguage(text) {
|
|
76
|
+
const normalized = text.trim().toLowerCase();
|
|
77
|
+
let match = /^every\s+(\d+)\s+minutes?$/.exec(normalized);
|
|
78
|
+
if (match) {
|
|
79
|
+
const minutes = Number(match[1]);
|
|
80
|
+
if (minutes < 1 || minutes > 59)
|
|
81
|
+
return [null, "minute interval must be 1..59"];
|
|
82
|
+
return [`*/${minutes} * * * *`, `Every ${minutes} minutes`];
|
|
83
|
+
}
|
|
84
|
+
if (normalized === "every hour" || normalized === "hourly") {
|
|
85
|
+
return ["0 * * * *", "Every hour on the hour"];
|
|
86
|
+
}
|
|
87
|
+
match = /^every\s+(\d+)\s+hours?$/.exec(normalized);
|
|
88
|
+
if (match) {
|
|
89
|
+
const hours = Number(match[1]);
|
|
90
|
+
if (hours < 1 || hours > 23)
|
|
91
|
+
return [null, "hour interval must be 1..23"];
|
|
92
|
+
return [`0 */${hours} * * *`, `Every ${hours} hours`];
|
|
93
|
+
}
|
|
94
|
+
match = /^(?:every\s+)?(weekday|weekdays|day|daily)\s+(?:at\s+)?(.+)$/.exec(normalized);
|
|
95
|
+
if (match) {
|
|
96
|
+
const clock = parseClock(match[2]);
|
|
97
|
+
if (!clock)
|
|
98
|
+
return [null, `could not parse time: ${match[2]}`];
|
|
99
|
+
const [hour, minute] = clock;
|
|
100
|
+
const weekdays = match[1] === "weekday" || match[1] === "weekdays";
|
|
101
|
+
return [
|
|
102
|
+
`${minute} ${hour} * * ${weekdays ? "1-5" : "*"}`,
|
|
103
|
+
`${weekdays ? "Every weekday" : "Every day"} at ${formatClock(hour, minute)}`,
|
|
104
|
+
];
|
|
105
|
+
}
|
|
106
|
+
match = /^(?:every\s+)?(sun(?:day)?|mon(?:day)?|tue(?:s|sday)?|wed(?:nesday)?|thu(?:r|rs|rsday)?|fri(?:day)?|sat(?:urday)?)s?\s+(?:at\s+)?(.+)$/.exec(normalized);
|
|
107
|
+
if (match) {
|
|
108
|
+
const day = DAY_NAMES[match[1]];
|
|
109
|
+
const clock = parseClock(match[2]);
|
|
110
|
+
if (!clock)
|
|
111
|
+
return [null, `could not parse time: ${match[2]}`];
|
|
112
|
+
return [
|
|
113
|
+
`${clock[1]} ${clock[0]} * * ${day}`,
|
|
114
|
+
`Every ${DAY_LABELS[String(day)]} at ${formatClock(...clock)}`,
|
|
115
|
+
];
|
|
116
|
+
}
|
|
117
|
+
match = /^at\s+(.+?)\s+every\s+(weekday|weekdays|day|daily)$/.exec(normalized);
|
|
118
|
+
if (match) {
|
|
119
|
+
const clock = parseClock(match[1]);
|
|
120
|
+
if (!clock)
|
|
121
|
+
return [null, `could not parse time: ${match[1]}`];
|
|
122
|
+
const weekdays = match[2] === "weekday" || match[2] === "weekdays";
|
|
123
|
+
return [
|
|
124
|
+
`${clock[1]} ${clock[0]} * * ${weekdays ? "1-5" : "*"}`,
|
|
125
|
+
`${weekdays ? "Every weekday" : "Every day"} at ${formatClock(...clock)}`,
|
|
126
|
+
];
|
|
127
|
+
}
|
|
128
|
+
return [
|
|
129
|
+
null,
|
|
130
|
+
"unrecognized schedule — try 'every weekday at 9am', 'every day at 14:30', "
|
|
131
|
+
+ "'every monday at 9am', a 5-field cron, or 'every 15 minutes'",
|
|
132
|
+
];
|
|
133
|
+
}
|
|
134
|
+
function isValidTimezone(timezone) {
|
|
135
|
+
const wellFormed = /^(UTC|[A-Za-z0-9_+-]+(\/[A-Za-z0-9_+-]+)+)$/;
|
|
136
|
+
if (!wellFormed.test(timezone))
|
|
137
|
+
return false;
|
|
138
|
+
try {
|
|
139
|
+
new Intl.DateTimeFormat(undefined, { timeZone: timezone });
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// Hosts without tzdata accept the same well-formed names as the shell.
|
|
144
|
+
return wellFormed.test(timezone);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
export function detectHostTimezone(override, resolveLocaltime = fs.realpathSync, readTimedatectl = () => {
|
|
148
|
+
const result = spawnSync("timedatectl", ["show", "-p", "Timezone", "--value"], { encoding: "utf8", timeout: 2000, stdio: ["ignore", "pipe", "ignore"] });
|
|
149
|
+
if (result.error || result.status !== 0)
|
|
150
|
+
return "";
|
|
151
|
+
return result.stdout || "";
|
|
152
|
+
}) {
|
|
153
|
+
if (override)
|
|
154
|
+
return override;
|
|
155
|
+
const environmentTimezone = (process.env.TZ || "").trim();
|
|
156
|
+
if (environmentTimezone && environmentTimezone.includes("/"))
|
|
157
|
+
return environmentTimezone;
|
|
158
|
+
try {
|
|
159
|
+
const realpath = resolveLocaltime("/etc/localtime");
|
|
160
|
+
const parts = realpath.split(path.sep).filter(Boolean);
|
|
161
|
+
const zoneinfo = parts.indexOf("zoneinfo");
|
|
162
|
+
if (zoneinfo >= 0 && parts.slice(zoneinfo + 1).length) {
|
|
163
|
+
return parts.slice(zoneinfo + 1).join("/");
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
// Ignore an unavailable local timezone link.
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
const timezone = readTimedatectl().trim();
|
|
171
|
+
if (timezone && timezone.includes("/"))
|
|
172
|
+
return timezone;
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
// Ignore unavailable timedatectl.
|
|
176
|
+
}
|
|
177
|
+
return "UTC";
|
|
178
|
+
}
|
|
179
|
+
export function runScheduleParse(argv, writers = processScheduleParseWriters) {
|
|
180
|
+
let timezoneOverride = "";
|
|
181
|
+
const args = [...argv];
|
|
182
|
+
while (args.length) {
|
|
183
|
+
const argument = args[0];
|
|
184
|
+
if (argument === "--tz") {
|
|
185
|
+
if (args.length < 2) {
|
|
186
|
+
writers.stderr(SCHEDULE_PARSE_USAGE);
|
|
187
|
+
return 2;
|
|
188
|
+
}
|
|
189
|
+
timezoneOverride = args[1];
|
|
190
|
+
args.splice(0, 2);
|
|
191
|
+
}
|
|
192
|
+
else if (argument === "--json") {
|
|
193
|
+
args.shift();
|
|
194
|
+
}
|
|
195
|
+
else if (argument === "-h" || argument === "--help") {
|
|
196
|
+
writers.stderr(SCHEDULE_PARSE_USAGE);
|
|
197
|
+
return 2;
|
|
198
|
+
}
|
|
199
|
+
else if (argument === "--") {
|
|
200
|
+
args.shift();
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
else if (argument.startsWith("-")) {
|
|
204
|
+
writers.stderr(`jobs-schedule-parse: unknown flag: ${argument}\n${SCHEDULE_PARSE_USAGE}`);
|
|
205
|
+
return 2;
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (!args.length) {
|
|
212
|
+
writers.stderr(SCHEDULE_PARSE_USAGE);
|
|
213
|
+
return 2;
|
|
214
|
+
}
|
|
215
|
+
const input = args.join(" ").trim();
|
|
216
|
+
if (!input) {
|
|
217
|
+
writers.stdout('{"ok":false,"error":"empty schedule"}\n');
|
|
218
|
+
return 1;
|
|
219
|
+
}
|
|
220
|
+
const timezone = detectHostTimezone(timezoneOverride);
|
|
221
|
+
if (!isValidTimezone(timezone)) {
|
|
222
|
+
writers.stdout(`${JSON.stringify({ ok: false, error: `invalid IANA timezone: ${timezone}` })}\n`);
|
|
223
|
+
return 1;
|
|
224
|
+
}
|
|
225
|
+
if (CRON_RE.test(input) && !/[A-Za-z]/.test(input)) {
|
|
226
|
+
writers.stdout(`${JSON.stringify({ ok: true, cron: input, timezone, human: humanizeCron(input, timezone), source: "cron" })}\n`);
|
|
227
|
+
return 0;
|
|
228
|
+
}
|
|
229
|
+
const namedCron = /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(mon-fri|monday-friday)$/i.exec(input);
|
|
230
|
+
if (namedCron) {
|
|
231
|
+
const cron = `${namedCron[1]} ${namedCron[2]} ${namedCron[3]} ${namedCron[4]} 1-5`;
|
|
232
|
+
writers.stdout(`${JSON.stringify({ ok: true, cron, timezone, human: humanizeCron(cron, timezone), source: "cron" })}\n`);
|
|
233
|
+
return 0;
|
|
234
|
+
}
|
|
235
|
+
const [cron, message] = parseNaturalLanguage(input);
|
|
236
|
+
if (cron === null) {
|
|
237
|
+
writers.stdout(`${JSON.stringify({ ok: false, error: message })}\n`);
|
|
238
|
+
return 1;
|
|
239
|
+
}
|
|
240
|
+
writers.stdout(`${JSON.stringify({ ok: true, cron, timezone, human: `${message} (${timezone})`, source: "nl" })}\n`);
|
|
241
|
+
return 0;
|
|
242
|
+
}
|
|
243
|
+
//# sourceMappingURL=core-jobs-schedule.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Shared
|
|
1
|
+
/** Shared registration for native operator utility commands. */
|
|
2
2
|
import type { Command } from "commander";
|
|
3
3
|
import { type CoreCommandRoot } from "./core-command-catalog.js";
|
|
4
4
|
export type UtilityOutput = {
|
|
@@ -15,13 +15,12 @@ export type UtilityContext = {
|
|
|
15
15
|
};
|
|
16
16
|
export type NativeUtilityDefinition = {
|
|
17
17
|
name: string;
|
|
18
|
-
asset: string;
|
|
19
18
|
root: CoreCommandRoot;
|
|
20
19
|
summary: string;
|
|
21
20
|
resolveRoot: (cwd: string, hqRoot?: string) => string;
|
|
22
21
|
run: (args: string[], context: UtilityContext) => UtilityOutput | Promise<UtilityOutput>;
|
|
23
22
|
};
|
|
24
|
-
/** Register one raw-argv command
|
|
23
|
+
/** Register one raw-argv native command. */
|
|
25
24
|
export declare function registerNativeUtility(core: Command, definition: NativeUtilityDefinition): void;
|
|
26
25
|
export declare function utilityError(message: string, code?: number): UtilityOutput;
|
|
27
26
|
/** Preserve Bash's set -u diagnostic for a missing positional option value. */
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
|
-
import { coreNativeUtilitiesEnabled } from "./core-native-utilities-flag.js";
|
|
3
2
|
import { describeCoreCommand } from "./core-command-catalog.js";
|
|
4
|
-
import { runBundledScript } from "../utils/run-bundled-script.js";
|
|
5
3
|
import { packageRoot } from "../utils/hq-roots.js";
|
|
6
|
-
/** Register one raw-argv command
|
|
4
|
+
/** Register one raw-argv native command. */
|
|
7
5
|
export function registerNativeUtility(core, definition) {
|
|
8
6
|
const command = core.command(definition.name)
|
|
9
7
|
.description(definition.summary)
|
|
@@ -16,21 +14,6 @@ export function registerNativeUtility(core, definition) {
|
|
|
16
14
|
const groupRoot = core.opts().hqRoot;
|
|
17
15
|
const operands = cmd.args.length > 0 ? cmd.args : args;
|
|
18
16
|
const root = definition.resolveRoot(cwd, groupRoot);
|
|
19
|
-
const nativeEnabled = await coreNativeUtilitiesEnabled();
|
|
20
|
-
if (process.env.HQ_CM_W5_EXPECT_NATIVE === "1" && !nativeEnabled) {
|
|
21
|
-
throw new Error(`core-native-utilities dispatch gate is disabled for ${definition.name}`);
|
|
22
|
-
}
|
|
23
|
-
if (!nativeEnabled) {
|
|
24
|
-
const result = runBundledScript({
|
|
25
|
-
asset: definition.asset,
|
|
26
|
-
args: operands,
|
|
27
|
-
cwd: definition.root === "live" ? root : cwd,
|
|
28
|
-
hqRoot: root,
|
|
29
|
-
});
|
|
30
|
-
if (result.code !== 0)
|
|
31
|
-
process.exitCode = result.code;
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
17
|
const result = await definition.run(operands, { root, cwd, env: process.env, now: () => new Date() });
|
|
35
18
|
if (result.stdout)
|
|
36
19
|
process.stdout.write(result.stdout);
|
|
@@ -41,7 +24,7 @@ export function registerNativeUtility(core, definition) {
|
|
|
41
24
|
if (result.code !== 0)
|
|
42
25
|
process.exitCode = result.code;
|
|
43
26
|
});
|
|
44
|
-
describeCoreCommand(command, { execution: "native",
|
|
27
|
+
describeCoreCommand(command, { execution: "native", root: definition.root });
|
|
45
28
|
}
|
|
46
29
|
export function utilityError(message, code = 1) {
|
|
47
30
|
return { code, stdout: "", stderr: `${message}\n` };
|
|
@@ -228,7 +228,7 @@ export function runPin(args, deps) {
|
|
|
228
228
|
}
|
|
229
229
|
export function registerCorePinNative(core) {
|
|
230
230
|
registerNativeUtility(core, {
|
|
231
|
-
name: "pin",
|
|
231
|
+
name: "pin", root: "live", summary: "Pin the current session to one goal",
|
|
232
232
|
resolveRoot: (_cwd, hqRoot) => resolveLiveRoot({ hqRoot }),
|
|
233
233
|
run: (args, context) => runPin(args, context),
|
|
234
234
|
});
|
|
@@ -239,7 +239,7 @@ export function runRefreshVaultAccess(args, deps) {
|
|
|
239
239
|
}
|
|
240
240
|
export function registerCoreRefreshVaultAccessNative(core) {
|
|
241
241
|
registerNativeUtility(core, {
|
|
242
|
-
name: "refresh-vault-access",
|
|
242
|
+
name: "refresh-vault-access", root: "cwd", summary: "Refresh the local vault access manifest",
|
|
243
243
|
resolveRoot: (cwd) => cwd,
|
|
244
244
|
run: (args, context) => runRefreshVaultAccess(args, createRefreshVaultAccessDependencies(context.cwd, context.env, context.now)),
|
|
245
245
|
});
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { resolveLiveRoot } from "../utils/hq-roots.js";
|
|
2
|
-
import { runBundledScript } from "../utils/run-bundled-script.js";
|
|
3
2
|
import { describeCoreCommand } from "./core-command-catalog.js";
|
|
4
|
-
import {
|
|
5
|
-
import { RESOLVE_COMPANY_ASSET, resolveCompany } from "./core-resolve-company-native.js";
|
|
3
|
+
import { resolveCompany } from "./core-resolve-company-native.js";
|
|
6
4
|
/** Commander registration stays in the full graph; the native resolver is fast-path safe. */
|
|
7
5
|
export function registerCoreResolveCompanyNativeCommand(core) {
|
|
8
6
|
const command = core.command("resolve-company")
|
|
@@ -13,19 +11,6 @@ export function registerCoreResolveCompanyNativeCommand(core) {
|
|
|
13
11
|
.argument("[args...]")
|
|
14
12
|
.action(async (args = [], _options, cmd) => {
|
|
15
13
|
const operands = cmd.args.length > 0 ? cmd.args : args;
|
|
16
|
-
if (!await coreNativeUtilitiesEnabled()) {
|
|
17
|
-
const root = resolveLiveRoot({ hqRoot: core.opts().hqRoot });
|
|
18
|
-
const { code } = runBundledScript({
|
|
19
|
-
asset: RESOLVE_COMPANY_ASSET,
|
|
20
|
-
args: operands,
|
|
21
|
-
cwd: root,
|
|
22
|
-
hqRoot: root,
|
|
23
|
-
env: { HQ_CALLER_CWD: process.cwd() },
|
|
24
|
-
});
|
|
25
|
-
if (code !== 0)
|
|
26
|
-
process.exit(code);
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
14
|
const root = resolveLiveRoot({ hqRoot: core.opts().hqRoot });
|
|
30
15
|
const result = await resolveCompany(operands, {
|
|
31
16
|
cwd: process.cwd(),
|
|
@@ -38,6 +23,6 @@ export function registerCoreResolveCompanyNativeCommand(core) {
|
|
|
38
23
|
if (result.code !== 0)
|
|
39
24
|
process.exit(result.code);
|
|
40
25
|
});
|
|
41
|
-
describeCoreCommand(command, { execution: "native",
|
|
26
|
+
describeCoreCommand(command, { execution: "native", root: "live" });
|
|
42
27
|
}
|
|
43
28
|
//# sourceMappingURL=core-resolve-company-command.js.map
|
|
@@ -250,7 +250,7 @@ export function runWorkMeshBindTrusted(args, deps) {
|
|
|
250
250
|
}
|
|
251
251
|
export function registerCoreWorkMeshBindTrustedNative(core) {
|
|
252
252
|
registerNativeUtility(core, {
|
|
253
|
-
name: "work-mesh-bind-trusted",
|
|
253
|
+
name: "work-mesh-bind-trusted", root: "live", summary: "Bind trusted session context and reconcile it with Work Mesh",
|
|
254
254
|
resolveRoot: (_cwd, hqRoot) => resolveLiveRoot({ hqRoot }),
|
|
255
255
|
run: async (args, context) => {
|
|
256
256
|
const { fastFlagEnabled } = await import("../native-fast-route.js");
|
package/dist/commands/core.js
CHANGED
|
@@ -255,17 +255,7 @@ export const SCAFFOLD_ONLY_ASSETS = [
|
|
|
255
255
|
{ asset: "core/scripts/session-project.sh", root: "live", summary: "Rollback companion for native session project" },
|
|
256
256
|
{ asset: "core/scripts/session-title.sh", root: "live", summary: "Rollback companion for native session title" },
|
|
257
257
|
{ asset: "core/scripts/session-title-config.sh", root: "live", summary: "Rollback companion for native session-title settings" },
|
|
258
|
-
{ asset: "core/scripts/resolve-company.sh", root: "live", summary: "Rollback companion for native resolve-company" },
|
|
259
|
-
{ asset: "core/scripts/jobs-schedule-parse.sh", root: "live", summary: "Rollback companion for native jobs schedule-parse" },
|
|
260
|
-
{ asset: "core/scripts/jobs-validate.sh", root: "live", summary: "Rollback companion for native jobs validate" },
|
|
261
|
-
{ asset: "core/scripts/outpost-jobs-reconcile.sh", root: "live", summary: "Rollback companion for native jobs reconcile" },
|
|
262
|
-
{ asset: "core/scripts/hq-job-probe.sh", root: "live", summary: "Scheduled jobs readiness probe used by the reconcile rollback path" },
|
|
263
|
-
{ asset: "core/scripts/hq-job-run.sh", root: "live", summary: "Scheduled jobs runner used by generated systemd units" },
|
|
264
|
-
{ asset: "core/scripts/hq-job-notify.sh", root: "live", summary: "Scheduled jobs failure notification helper" },
|
|
265
|
-
{ asset: "core/scripts/hq-job-remediate.sh", root: "live", summary: "Scheduled jobs bounded remediation helper" },
|
|
266
258
|
{ asset: "core/scripts/pipeline-worker-table.sh", root: "live", summary: "Rollback companion for native pipeline worker-table" },
|
|
267
|
-
{ asset: "core/scripts/hq-dm-bind.sh", root: "live", summary: "Rollback shell for native dm-bind" },
|
|
268
|
-
{ asset: "core/scripts/work-mesh-live-bind-trusted.sh", root: "live", summary: "Rollback shell for native work-mesh-bind-trusted" },
|
|
269
259
|
{ asset: "core/scripts/share-suggestion-state.sh", root: "live", summary: "Rollback shell for native share-suggestion-state" },
|
|
270
260
|
{ asset: "core/scripts/repo-run-registry.sh", root: "live", summary: "Rollback shell for native repo-run-registry" },
|
|
271
261
|
{ asset: "core/scripts/detect-stale-review-base.sh", root: "live", summary: "Rollback shell for native detect-stale-review-base" },
|
|
@@ -317,13 +307,7 @@ export const SCAFFOLD_ONLY_ASSETS = [
|
|
|
317
307
|
{ asset: "core/scripts/handoff-post.sh", root: "live", summary: "Rollback shell for native handoff post" },
|
|
318
308
|
{ asset: "core/scripts/handoff-open-steps.sh", root: "live", summary: "Rollback shell for native handoff open-steps" },
|
|
319
309
|
{ asset: "core/scripts/qmd-reindex-bg.sh", root: "live", summary: "Rollback handoff reindex forwarder" },
|
|
320
|
-
|
|
321
|
-
// because these assets were not present in the hq-cli bundle at launch.
|
|
322
|
-
{ asset: "core/scripts/audit-log.sh", root: "live", summary: "Rollback shell for native audit-log" },
|
|
323
|
-
{ asset: "core/scripts/git-pack-extension-check.sh", root: "cwd", summary: "Rollback shell for native git-pack-extension-check" },
|
|
324
|
-
{ asset: "core/scripts/hq-pin.sh", root: "live", summary: "Rollback shell for native pin" },
|
|
325
|
-
{ asset: "core/scripts/refresh-vault-access.sh", root: "cwd", summary: "Rollback shell for native refresh-vault-access" },
|
|
326
|
-
{ asset: "core/scripts/lib/portable.sh", root: "live", summary: "Shared portable helpers sourced by the audit-log rollback shell" },
|
|
310
|
+
{ asset: "core/scripts/lib/portable.sh", root: "live", summary: "Shared portable helpers sourced by bundled scripts" },
|
|
327
311
|
...NATIVE_UTILITY_COMMANDS.map(({ asset, root, summary }) => ({
|
|
328
312
|
asset,
|
|
329
313
|
root,
|
package/dist/fast-scaffold.d.ts
CHANGED
|
@@ -63,7 +63,7 @@ export declare function coreCommandHasPathOperands(argv: readonly string[]): boo
|
|
|
63
63
|
/** Apply the manifest's operand rule to a copied process.argv vector. */
|
|
64
64
|
export declare function normalizeCorePathOperands(argv: readonly string[], platform?: NodeJS.Platform, convertPath?: (value: string) => string): string[];
|
|
65
65
|
/** Family kill switches whose owner-approved default is enabled. */
|
|
66
|
-
export declare const CORE_NATIVE_DEFAULT_ON_FAMILY_FLAGS: readonly ["core-native-session", "core-native-hook-helpers", "core-native-policy", "core-native-
|
|
66
|
+
export declare const CORE_NATIVE_DEFAULT_ON_FAMILY_FLAGS: readonly ["core-native-session", "core-native-hook-helpers", "core-native-policy", "core-native-handoff", "core-native-bucket-c", "core-native-delegate"];
|
|
67
67
|
export declare function isDefaultOnFastFamily(flagKey: string): boolean;
|
|
68
68
|
/** The relocated scripts that qualify for the entrypoint fast path. */
|
|
69
69
|
export declare const FAST_SCAFFOLD_SCRIPTS: readonly FastScaffoldScript[];
|
package/dist/fast-scaffold.js
CHANGED
|
@@ -150,8 +150,6 @@ export const CORE_NATIVE_DEFAULT_ON_FAMILY_FLAGS = [
|
|
|
150
150
|
"core-native-session",
|
|
151
151
|
"core-native-hook-helpers",
|
|
152
152
|
"core-native-policy",
|
|
153
|
-
"core-native-utilities",
|
|
154
|
-
"core-native-jobs",
|
|
155
153
|
"core-native-handoff",
|
|
156
154
|
"core-native-bucket-c",
|
|
157
155
|
"core-native-delegate",
|
|
@@ -263,11 +261,7 @@ export const FAST_SCAFFOLD_SCRIPTS = [
|
|
|
263
261
|
: name === "remediate" ? "runJobRemediateFast"
|
|
264
262
|
: "runJobFast",
|
|
265
263
|
flagKey: "hq-core-native-fast-route",
|
|
266
|
-
familyFlagKey: "core-native-jobs",
|
|
267
|
-
asset: `core/scripts/hq-job-${name}.sh`,
|
|
268
264
|
root: "live",
|
|
269
|
-
shellCwd: "live",
|
|
270
|
-
shellHqRoot: "live",
|
|
271
265
|
requiresNodeNetworkCompatibility: name === "probe" || name === "run",
|
|
272
266
|
})),
|
|
273
267
|
{
|
|
@@ -276,11 +270,7 @@ export const FAST_SCAFFOLD_SCRIPTS = [
|
|
|
276
270
|
modulePath: "./commands/core-pin-fast.js",
|
|
277
271
|
exportName: "runPinFast",
|
|
278
272
|
flagKey: "hq-core-native-fast-route",
|
|
279
|
-
familyFlagKey: "core-native-utilities",
|
|
280
|
-
asset: "core/scripts/hq-pin.sh",
|
|
281
273
|
root: "live",
|
|
282
|
-
shellCwd: "live",
|
|
283
|
-
shellHqRoot: "live",
|
|
284
274
|
},
|
|
285
275
|
{
|
|
286
276
|
name: "worker lint",
|
|
@@ -474,12 +464,8 @@ export const FAST_SCAFFOLD_SCRIPTS = [
|
|
|
474
464
|
modulePath: "./commands/core-jobs-native.js",
|
|
475
465
|
exportName: "runJobsFast",
|
|
476
466
|
flagKey: "hq-core-native-fast-route",
|
|
477
|
-
familyFlagKey: "core-native-jobs",
|
|
478
|
-
asset: `core/scripts/${name === "reconcile" ? "outpost-jobs-reconcile" : `jobs-${name}`}.sh`,
|
|
479
467
|
requiresNodeNetworkCompatibility: true,
|
|
480
468
|
root: name === "reconcile" ? "passthrough" : "cwd",
|
|
481
|
-
shellCwd: "caller",
|
|
482
|
-
shellHqRoot: name === "reconcile" ? "reconcile-default" : "none",
|
|
483
469
|
})),
|
|
484
470
|
...["share-suggestion-state", "repo-run-registry", "detect-stale-review-base"].map((name) => ({
|
|
485
471
|
name,
|
|
@@ -508,11 +494,7 @@ export const FAST_SCAFFOLD_SCRIPTS = [
|
|
|
508
494
|
modulePath: "./commands/core-resolve-company-native.js",
|
|
509
495
|
exportName: "runResolveCompanyFast",
|
|
510
496
|
flagKey: "hq-core-native-fast-route",
|
|
511
|
-
familyFlagKey: "core-native-utilities",
|
|
512
|
-
asset: "core/scripts/resolve-company.sh",
|
|
513
497
|
root: "live",
|
|
514
|
-
shellCwd: "live",
|
|
515
|
-
shellHqRoot: "live",
|
|
516
498
|
},
|
|
517
499
|
...["session-journal", "session-project", "session-title", "session-title-config"].map((name) => ({
|
|
518
500
|
name,
|
|
@@ -602,11 +584,7 @@ export const FAST_SCAFFOLD_SCRIPTS = [
|
|
|
602
584
|
modulePath: "./commands/core-audit-log-fast.js",
|
|
603
585
|
exportName: "runAuditLogFast",
|
|
604
586
|
flagKey: "hq-core-native-fast-route",
|
|
605
|
-
familyFlagKey: "core-native-utilities",
|
|
606
|
-
asset: "core/scripts/audit-log.sh",
|
|
607
587
|
root: "live",
|
|
608
|
-
shellCwd: "live",
|
|
609
|
-
shellHqRoot: "live",
|
|
610
588
|
},
|
|
611
589
|
{
|
|
612
590
|
name: "refresh-vault-access",
|
|
@@ -614,11 +592,7 @@ export const FAST_SCAFFOLD_SCRIPTS = [
|
|
|
614
592
|
modulePath: "./commands/core-refresh-vault-access-fast.js",
|
|
615
593
|
exportName: "runRefreshVaultAccessFast",
|
|
616
594
|
flagKey: "hq-core-native-fast-route",
|
|
617
|
-
familyFlagKey: "core-native-utilities",
|
|
618
|
-
asset: "core/scripts/refresh-vault-access.sh",
|
|
619
595
|
root: "cwd",
|
|
620
|
-
shellCwd: "caller",
|
|
621
|
-
shellHqRoot: "cwd",
|
|
622
596
|
},
|
|
623
597
|
{
|
|
624
598
|
name: "generate-workers-registry",
|
|
@@ -635,11 +609,7 @@ export const FAST_SCAFFOLD_SCRIPTS = [
|
|
|
635
609
|
modulePath: "./commands/core-dm-bind-fast.js",
|
|
636
610
|
exportName: "runDmBindFast",
|
|
637
611
|
flagKey: "hq-core-native-fast-route",
|
|
638
|
-
familyFlagKey: "core-native-utilities",
|
|
639
|
-
asset: "core/scripts/hq-dm-bind.sh",
|
|
640
612
|
root: "live",
|
|
641
|
-
shellCwd: "live",
|
|
642
|
-
shellHqRoot: "live",
|
|
643
613
|
readsStdinFor: (args) => {
|
|
644
614
|
if (args[0] !== "post")
|
|
645
615
|
return false;
|
|
@@ -660,11 +630,7 @@ export const FAST_SCAFFOLD_SCRIPTS = [
|
|
|
660
630
|
modulePath: "./commands/core-git-pack-extension-check-fast.js",
|
|
661
631
|
exportName: "runGitPackExtensionCheckFast",
|
|
662
632
|
flagKey: "hq-core-native-fast-route",
|
|
663
|
-
familyFlagKey: "core-native-utilities",
|
|
664
|
-
asset: "core/scripts/git-pack-extension-check.sh",
|
|
665
633
|
root: "cwd",
|
|
666
|
-
shellCwd: "caller",
|
|
667
|
-
shellHqRoot: "cwd",
|
|
668
634
|
},
|
|
669
635
|
{
|
|
670
636
|
name: "scan-packages",
|
|
@@ -690,11 +656,7 @@ export const FAST_SCAFFOLD_SCRIPTS = [
|
|
|
690
656
|
modulePath: "./commands/core-work-mesh-bind-trusted-fast.js",
|
|
691
657
|
exportName: "runWorkMeshBindTrustedFast",
|
|
692
658
|
flagKey: "hq-core-native-fast-route",
|
|
693
|
-
familyFlagKey: "core-native-utilities",
|
|
694
|
-
asset: "core/scripts/work-mesh-live-bind-trusted.sh",
|
|
695
659
|
root: "live",
|
|
696
|
-
shellCwd: "live",
|
|
697
|
-
shellHqRoot: "live",
|
|
698
660
|
requiresNodeNetworkCompatibility: true,
|
|
699
661
|
},
|
|
700
662
|
{
|
|
@@ -121,8 +121,6 @@ export interface PlanContext {
|
|
|
121
121
|
legacyOwner: (unitId: string) => string | null;
|
|
122
122
|
/** This CLI is a global install the updater can replace (not a project dependency). */
|
|
123
123
|
cliSelfUpdatable: boolean;
|
|
124
|
-
/** `<hqRoot>/core/scripts/outpost-jobs-reconcile.sh` when it exists. */
|
|
125
|
-
jobsReconcileScript: string | null;
|
|
126
124
|
/** Absolute paths of the claude and tmux binaries, or null when not installed. */
|
|
127
125
|
claudePath: string | null;
|
|
128
126
|
tmuxPath: string | null;
|
|
@@ -279,21 +279,18 @@ function planService(service, ctx) {
|
|
|
279
279
|
case "jobs-reconcile": {
|
|
280
280
|
if (ctx.platform === "win32")
|
|
281
281
|
return [unavailable(service, "needs bash; not supported on Windows")];
|
|
282
|
-
const script = ctx.jobsReconcileScript;
|
|
283
282
|
return [
|
|
284
283
|
base(service, {
|
|
285
284
|
kind: "scheduled",
|
|
286
285
|
intervalSec: 600,
|
|
287
286
|
initialDelaySec: 600,
|
|
288
287
|
command: {
|
|
289
|
-
type: "
|
|
290
|
-
|
|
291
|
-
args: [script ?? "", "--hq-root", ctx.hqRoot ?? "", "--ensure-hook", "--after-sync"],
|
|
288
|
+
type: "hq",
|
|
289
|
+
args: ["core", "--hq-root", ctx.hqRoot ?? "", "jobs", "reconcile", "--ensure-hook", "--after-sync"],
|
|
292
290
|
},
|
|
293
|
-
env: ctx.hqRoot ? { HQ_ROOT: ctx.hqRoot } : {},
|
|
291
|
+
env: ctx.hqRoot ? { HQ_ROOT: ctx.hqRoot, HQ_NO_UPDATE_CHECK: "1" } : { HQ_NO_UPDATE_CHECK: "1" },
|
|
294
292
|
blocked: firstBlock([
|
|
295
293
|
[!ctx.hqRoot, NO_HQ_ROOT],
|
|
296
|
-
[!script, "this HQ folder has no core/scripts/outpost-jobs-reconcile.sh"],
|
|
297
294
|
]),
|
|
298
295
|
}),
|
|
299
296
|
];
|
package/dist/lib/daemon/run.js
CHANGED
|
@@ -350,12 +350,6 @@ export function desktopAppManagesSync(opts) {
|
|
|
350
350
|
return false;
|
|
351
351
|
return opts.legacy.some((u) => u.service === "sync" && !u.migratable) || opts.appRunning();
|
|
352
352
|
}
|
|
353
|
-
function jobsReconcileScript(hqRoot) {
|
|
354
|
-
if (!hqRoot)
|
|
355
|
-
return null;
|
|
356
|
-
const script = path.join(hqRoot, "core", "scripts", "outpost-jobs-reconcile.sh");
|
|
357
|
-
return fs.existsSync(script) ? script : null;
|
|
358
|
-
}
|
|
359
353
|
function signedIn(env, home, log) {
|
|
360
354
|
if (fs.existsSync(agentKitPaths(home, env).machineCredsPath))
|
|
361
355
|
return true;
|
|
@@ -859,7 +853,6 @@ export async function runDaemon(opts) {
|
|
|
859
853
|
bots: listLocalBots(),
|
|
860
854
|
legacyOwner: legacyOwnerLookup(legacy),
|
|
861
855
|
cliSelfUpdatable: updatable,
|
|
862
|
-
jobsReconcileScript: jobsReconcileScript(hqRoot),
|
|
863
856
|
claudePath: findUserBinary("claude", env, home),
|
|
864
857
|
codexPath: findUserBinary("codex", env, home),
|
|
865
858
|
codexRunnerScript: platform === "linux" && fs.existsSync(CODEX_RUNNER_SCRIPT) ? CODEX_RUNNER_SCRIPT : null,
|
|
@@ -4,6 +4,7 @@ import * as path from 'node:path';
|
|
|
4
4
|
import * as yaml from 'js-yaml';
|
|
5
5
|
import { contributionLinks } from '../../utils/pack-contribution-links.js';
|
|
6
6
|
import { CONTRIBUTION_TABLE } from '../../utils/contribution-table.js';
|
|
7
|
+
import { isExcludedWorkerDirectory } from '../workers-registry/index.js';
|
|
7
8
|
function isDirectory(target) { try {
|
|
8
9
|
return fs.statSync(target).isDirectory();
|
|
9
10
|
}
|
|
@@ -75,6 +76,11 @@ function workerId(file) {
|
|
|
75
76
|
function allWorkerYamlFiles(root, relative) {
|
|
76
77
|
const output = [];
|
|
77
78
|
const walk = (next, seen) => {
|
|
79
|
+
// Prune exactly what the worker registry prunes (tenant repos/ checkouts,
|
|
80
|
+
// _template, _overrides). A worker.yaml the registry never indexes cannot
|
|
81
|
+
// collide with a pack worker, and walking source checkouts is slow.
|
|
82
|
+
if (isExcludedWorkerDirectory(next))
|
|
83
|
+
return;
|
|
78
84
|
const absolute = path.join(root, next);
|
|
79
85
|
if (!isDirectory(absolute))
|
|
80
86
|
return;
|
|
@@ -9,6 +9,22 @@ export interface GenerateWorkersRegistryResult {
|
|
|
9
9
|
written: boolean;
|
|
10
10
|
quarantined: number;
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Worker roots hold two kinds of `worker.yaml` that must never reach the
|
|
14
|
+
* registry.
|
|
15
|
+
*
|
|
16
|
+
* The `_template` company and any `_overrides` directory are scaffolding —
|
|
17
|
+
* copies kept so a new tenant or a pack override can be stamped out from them.
|
|
18
|
+
*
|
|
19
|
+
* A checkout nested under a tenant's `repos/` is a source repository that tenant
|
|
20
|
+
* happens to keep inside HQ, and when that repository is HQ itself, its own
|
|
21
|
+
* `core/workers` and template trees are full of worker.yaml files. Indexing them
|
|
22
|
+
* treats product source as deployed workers: they claim ids real workers already
|
|
23
|
+
* own, and because duplicates resolve by path order — a tenant path sorts before
|
|
24
|
+
* both `core` and `personal` — the checkout wins. The operator's actual worker
|
|
25
|
+
* then silently vanishes from the registry every skill reads.
|
|
26
|
+
*/
|
|
27
|
+
export declare function isExcludedWorkerDirectory(relativeDirectory: string): boolean;
|
|
12
28
|
/**
|
|
13
29
|
* Generate core/workers/registry.yaml from worker.yaml files. Invalid workers
|
|
14
30
|
* are quarantined but do not prevent all valid workers from being registered.
|
|
@@ -158,7 +158,7 @@ function withoutTimestamp(content) {
|
|
|
158
158
|
* both `core` and `personal` — the checkout wins. The operator's actual worker
|
|
159
159
|
* then silently vanishes from the registry every skill reads.
|
|
160
160
|
*/
|
|
161
|
-
function isExcludedWorkerDirectory(relativeDirectory) {
|
|
161
|
+
export function isExcludedWorkerDirectory(relativeDirectory) {
|
|
162
162
|
const normalized = relativeDirectory.replaceAll('\\', '/');
|
|
163
163
|
const [root, tenant, nested] = normalized.split('/');
|
|
164
164
|
if (root !== 'companies')
|