@indigoai-us/hq-cli 5.270.0 → 5.272.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 +21 -0
- package/dist/command-catalog.generated.d.ts +30 -0
- package/dist/command-catalog.generated.js +39 -0
- package/dist/commands/core-ontology.d.ts +16 -0
- package/dist/commands/core-ontology.js +86 -0
- package/dist/commands/files.d.ts +16 -0
- package/dist/commands/files.js +1 -1
- package/dist/commands/lanes-message.js +6 -3
- package/dist/commands/lanes-resume.js +6 -3
- package/dist/commands/lanes-shared.d.ts +20 -4
- package/dist/commands/lanes.d.ts +1 -1
- package/dist/commands/lanes.js +212 -33
- package/dist/lib/checkpoint-ontology/merge-copies.d.ts +116 -0
- package/dist/lib/checkpoint-ontology/merge-copies.js +521 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [5.272.0] — 2026-09-28
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Add `hq core ontology merge-copies`, gated by
|
|
10
|
+
`checkpoint.ontology.merge-copies`. It merges each `<name> N.md` entity copy
|
|
11
|
+
into its own original (aliases, back-references, relationship links and
|
|
12
|
+
signal count), repoints links to the copy, and with `--delete` removes merged
|
|
13
|
+
copies from the vault. Dry run by default.
|
|
14
|
+
|
|
15
|
+
## [5.271.0] — 2026-09-28
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- `hq lanes create --outpost` reads `lanes.outpost-load-balancing` for the
|
|
20
|
+
resolved company, so enabled personal worker profiles can run on an Outpost.
|
|
21
|
+
- Resolve host-suffixed lanes created on a registered Outpost for grant,
|
|
22
|
+
message, and resume commands while keeping senior authorization on the primary.
|
|
23
|
+
- `hq lanes move-target` keeps the company placement gate, and unfiltered
|
|
24
|
+
`hq lanes list` resolves the active company for host capacity.
|
|
25
|
+
|
|
5
26
|
## [5.270.0] — 2026-09-28
|
|
6
27
|
|
|
7
28
|
### Fixed
|
|
@@ -5148,6 +5148,33 @@ export declare const COMMAND_CATALOG: readonly [{
|
|
|
5148
5148
|
readonly description: "HQ installation to operate on";
|
|
5149
5149
|
}];
|
|
5150
5150
|
readonly subcommands: readonly [];
|
|
5151
|
+
}, {
|
|
5152
|
+
readonly name: "merge-copies";
|
|
5153
|
+
readonly description: "Merge '<name> N.md' entity copies into their original, then delete them from the vault (dry run by default)";
|
|
5154
|
+
readonly aliases: readonly [];
|
|
5155
|
+
readonly hidden: false;
|
|
5156
|
+
readonly usage: "[options]";
|
|
5157
|
+
readonly arguments: readonly [];
|
|
5158
|
+
readonly options: readonly [{
|
|
5159
|
+
readonly flags: "--company <slug>";
|
|
5160
|
+
readonly description: "company to change";
|
|
5161
|
+
}, {
|
|
5162
|
+
readonly flags: "--apply";
|
|
5163
|
+
readonly description: "merge each copy into its original and re-point links (writes entity files)";
|
|
5164
|
+
}, {
|
|
5165
|
+
readonly flags: "--delete";
|
|
5166
|
+
readonly description: "delete fully merged copies from the vault by exact key (after sync pushed the merge)";
|
|
5167
|
+
}, {
|
|
5168
|
+
readonly flags: "--limit <n>";
|
|
5169
|
+
readonly description: "handle at most this many copies";
|
|
5170
|
+
}, {
|
|
5171
|
+
readonly flags: "--json";
|
|
5172
|
+
readonly description: "print JSON";
|
|
5173
|
+
}, {
|
|
5174
|
+
readonly flags: "--hq-root <path>";
|
|
5175
|
+
readonly description: "HQ installation to operate on";
|
|
5176
|
+
}];
|
|
5177
|
+
readonly subcommands: readonly [];
|
|
5151
5178
|
}, {
|
|
5152
5179
|
readonly name: "apply";
|
|
5153
5180
|
readonly description: "Validate the run's entity candidates and write them to the payload company";
|
|
@@ -7800,6 +7827,9 @@ export declare const COMMAND_CATALOG: readonly [{
|
|
|
7800
7827
|
readonly options: readonly [{
|
|
7801
7828
|
readonly flags: "--hire <n>";
|
|
7802
7829
|
readonly description: "Non-negative safe integer hire grant";
|
|
7830
|
+
}, {
|
|
7831
|
+
readonly flags: "--outpost <id>";
|
|
7832
|
+
readonly description: "Confirm the registered Outpost hosting a native lane";
|
|
7803
7833
|
}, {
|
|
7804
7834
|
readonly flags: "--json";
|
|
7805
7835
|
readonly description: "JSON on stdout (always)";
|
|
@@ -6657,6 +6657,41 @@ export const COMMAND_CATALOG = [
|
|
|
6657
6657
|
],
|
|
6658
6658
|
"subcommands": []
|
|
6659
6659
|
},
|
|
6660
|
+
{
|
|
6661
|
+
"name": "merge-copies",
|
|
6662
|
+
"description": "Merge '<name> N.md' entity copies into their original, then delete them from the vault (dry run by default)",
|
|
6663
|
+
"aliases": [],
|
|
6664
|
+
"hidden": false,
|
|
6665
|
+
"usage": "[options]",
|
|
6666
|
+
"arguments": [],
|
|
6667
|
+
"options": [
|
|
6668
|
+
{
|
|
6669
|
+
"flags": "--company <slug>",
|
|
6670
|
+
"description": "company to change"
|
|
6671
|
+
},
|
|
6672
|
+
{
|
|
6673
|
+
"flags": "--apply",
|
|
6674
|
+
"description": "merge each copy into its original and re-point links (writes entity files)"
|
|
6675
|
+
},
|
|
6676
|
+
{
|
|
6677
|
+
"flags": "--delete",
|
|
6678
|
+
"description": "delete fully merged copies from the vault by exact key (after sync pushed the merge)"
|
|
6679
|
+
},
|
|
6680
|
+
{
|
|
6681
|
+
"flags": "--limit <n>",
|
|
6682
|
+
"description": "handle at most this many copies"
|
|
6683
|
+
},
|
|
6684
|
+
{
|
|
6685
|
+
"flags": "--json",
|
|
6686
|
+
"description": "print JSON"
|
|
6687
|
+
},
|
|
6688
|
+
{
|
|
6689
|
+
"flags": "--hq-root <path>",
|
|
6690
|
+
"description": "HQ installation to operate on"
|
|
6691
|
+
}
|
|
6692
|
+
],
|
|
6693
|
+
"subcommands": []
|
|
6694
|
+
},
|
|
6660
6695
|
{
|
|
6661
6696
|
"name": "apply",
|
|
6662
6697
|
"description": "Validate the run's entity candidates and write them to the payload company",
|
|
@@ -10086,6 +10121,10 @@ export const COMMAND_CATALOG = [
|
|
|
10086
10121
|
"flags": "--hire <n>",
|
|
10087
10122
|
"description": "Non-negative safe integer hire grant"
|
|
10088
10123
|
},
|
|
10124
|
+
{
|
|
10125
|
+
"flags": "--outpost <id>",
|
|
10126
|
+
"description": "Confirm the registered Outpost hosting a native lane"
|
|
10127
|
+
},
|
|
10089
10128
|
{
|
|
10090
10129
|
"flags": "--json",
|
|
10091
10130
|
"description": "JSON on stdout (always)"
|
|
@@ -9,12 +9,15 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { Command } from "commander";
|
|
11
11
|
import { type FlagReader } from "../lib/checkpoint-ontology/plan.js";
|
|
12
|
+
import { type DeleteVaultKey } from "../lib/checkpoint-ontology/merge-copies.js";
|
|
12
13
|
export declare const ONTOLOGY_PAYLOAD_FILE = "payload.json";
|
|
13
14
|
/** The hq-flags read, scoped to the payload company. */
|
|
14
15
|
export declare const registryFlagReader: FlagReader;
|
|
15
16
|
export interface OntologyCommandDeps {
|
|
16
17
|
readFlag?: FlagReader;
|
|
17
18
|
now?: () => Date;
|
|
19
|
+
/** Builds the exact-key vault delete for a company uid. */
|
|
20
|
+
vaultDeleter?: (companyUid: string) => Promise<DeleteVaultKey>;
|
|
18
21
|
}
|
|
19
22
|
export declare function runOntologyPlan(hqRoot: string, runDirOption: string | undefined, deps?: OntologyCommandDeps): Promise<string>;
|
|
20
23
|
export declare function runOntologyApply(hqRoot: string, runDirOption: string | undefined, deps?: OntologyCommandDeps): string;
|
|
@@ -24,5 +27,18 @@ export declare function runOntologyApply(hqRoot: string, runDirOption: string |
|
|
|
24
27
|
* `checkpoint.ontology.multi-writer`.
|
|
25
28
|
*/
|
|
26
29
|
export declare function runOntologyDuplicates(hqRoot: string, slug: string | undefined, json: boolean, deps?: OntologyCommandDeps): Promise<string>;
|
|
30
|
+
export interface MergeCopiesCommandOptions {
|
|
31
|
+
apply?: boolean;
|
|
32
|
+
delete?: boolean;
|
|
33
|
+
limit?: number;
|
|
34
|
+
json?: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* `hq core ontology merge-copies`: merge `<slug> <n>.md` copies into their
|
|
38
|
+
* original (`--apply`), then delete merged copies from the vault
|
|
39
|
+
* (`--delete`). Without either it only reports. Gated by
|
|
40
|
+
* `checkpoint.ontology.merge-copies` and `checkpoint.ontology.multi-writer`.
|
|
41
|
+
*/
|
|
42
|
+
export declare function runOntologyMergeCopies(hqRoot: string, slug: string | undefined, options: MergeCopiesCommandOptions, deps?: OntologyCommandDeps): Promise<string>;
|
|
27
43
|
export declare function registerCoreOntologyCommand(core: Command): void;
|
|
28
44
|
//# sourceMappingURL=core-ontology.d.ts.map
|
|
@@ -16,6 +16,9 @@ import { applyOntologyRun, ApplyError } from "../lib/checkpoint-ontology/apply.j
|
|
|
16
16
|
import { resolveOntologyCompany, WriteBoundsError } from "../lib/checkpoint-ontology/company.js";
|
|
17
17
|
import { findDuplicateGroups, summarizeMergeBack, } from "../lib/checkpoint-ontology/multi-writer.js";
|
|
18
18
|
import { buildEntityIndex } from "../lib/checkpoint-ontology/tree.js";
|
|
19
|
+
import { MERGE_COPIES_FLAG, mergeCopies, } from "../lib/checkpoint-ontology/merge-copies.js";
|
|
20
|
+
import { callDeleteEndpoint } from "./files.js";
|
|
21
|
+
import { resolveVaultCredential } from "../utils/resolve-vault-credential.js";
|
|
19
22
|
export const ONTOLOGY_PAYLOAD_FILE = "payload.json";
|
|
20
23
|
class OntologyUsageError extends Error {
|
|
21
24
|
}
|
|
@@ -124,6 +127,72 @@ export async function runOntologyDuplicates(hqRoot, slug, json, deps = {}) {
|
|
|
124
127
|
}
|
|
125
128
|
return lines.join("\n");
|
|
126
129
|
}
|
|
130
|
+
/** Delete one exact company vault key, refusing when the server would match anything else. */
|
|
131
|
+
async function companyVaultDeleter(companyUid) {
|
|
132
|
+
const token = (await resolveVaultCredential()).token;
|
|
133
|
+
return async (key) => {
|
|
134
|
+
const preview = await callDeleteEndpoint({ token, companyUid, prefix: key, dryRun: true });
|
|
135
|
+
if (preview.matched === 0)
|
|
136
|
+
return 0;
|
|
137
|
+
if (preview.matched !== 1 || preview.keys.length !== 1 || preview.keys[0] !== key) {
|
|
138
|
+
throw new Error(`vault preview matched ${preview.matched} object(s), not exactly ${key}`);
|
|
139
|
+
}
|
|
140
|
+
return (await callDeleteEndpoint({ token, companyUid, prefix: key, dryRun: false })).deleted;
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function mergeCopiesSummary(report) {
|
|
144
|
+
const held = report.plans.filter((plan) => plan.held).length;
|
|
145
|
+
const lines = [
|
|
146
|
+
`ontology merge-copies (${report.mode.replace("_", " ")}) in ${report.company}: ${report.plans.length} of ${report.copies_found} copies, ${held} held, ${report.skipped.length} skipped`,
|
|
147
|
+
` merged ${report.merged.length}, relinked ${report.relinked.length}, deleted ${report.deleted.length}, not ready ${report.not_ready.length}, errors ${report.errors.length}`,
|
|
148
|
+
` duplicate groups ${report.duplicate_groups_before} -> ${report.duplicate_groups_after}; broken entity links ${report.broken_links_before} -> ${report.broken_links_after}`,
|
|
149
|
+
];
|
|
150
|
+
for (const plan of report.plans.filter((entry) => entry.held))
|
|
151
|
+
lines.push(` held ${plan.copy}: ${plan.held}`);
|
|
152
|
+
for (const error of report.errors)
|
|
153
|
+
lines.push(` error ${error.path}: ${error.error}`);
|
|
154
|
+
return lines.join("\n");
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* `hq core ontology merge-copies`: merge `<slug> <n>.md` copies into their
|
|
158
|
+
* original (`--apply`), then delete merged copies from the vault
|
|
159
|
+
* (`--delete`). Without either it only reports. Gated by
|
|
160
|
+
* `checkpoint.ontology.merge-copies` and `checkpoint.ontology.multi-writer`.
|
|
161
|
+
*/
|
|
162
|
+
export async function runOntologyMergeCopies(hqRoot, slug, options, deps = {}) {
|
|
163
|
+
if (options.apply && options.delete) {
|
|
164
|
+
throw new OntologyUsageError("ontology: run --apply first, let sync push the merged files, then run --delete");
|
|
165
|
+
}
|
|
166
|
+
if (options.limit !== undefined && (!Number.isInteger(options.limit) || options.limit < 1)) {
|
|
167
|
+
throw new OntologyUsageError("ontology: --limit must be a positive whole number");
|
|
168
|
+
}
|
|
169
|
+
const resolution = resolveOntologyCompany(hqRoot, slug);
|
|
170
|
+
if (!resolution.ok)
|
|
171
|
+
throw new OntologyUsageError(`ontology: company rejected: ${resolution.reason}`);
|
|
172
|
+
const company = resolution.company;
|
|
173
|
+
const readFlag = deps.readFlag ?? registryFlagReader;
|
|
174
|
+
for (const flag of [MERGE_COPIES_FLAG, MULTI_WRITER_FLAG]) {
|
|
175
|
+
if (!(await readFlag(flag, company))) {
|
|
176
|
+
return options.json ? JSON.stringify({ company: company.slug, skipped: `${flag} off` }) : `ontology merge-copies: skipped (${flag} is off)`;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const mode = options.apply ? "merge" : options.delete ? "delete" : "dry_run";
|
|
180
|
+
let deleteVaultKey;
|
|
181
|
+
if (mode === "delete") {
|
|
182
|
+
if (!company.cloudUid)
|
|
183
|
+
throw new OntologyUsageError("ontology: the company has no cloud_uid in the manifest");
|
|
184
|
+
deleteVaultKey = await (deps.vaultDeleter ?? companyVaultDeleter)(company.cloudUid);
|
|
185
|
+
}
|
|
186
|
+
const report = await mergeCopies({
|
|
187
|
+
hqRoot,
|
|
188
|
+
company,
|
|
189
|
+
mode,
|
|
190
|
+
now: deps.now?.() ?? new Date(),
|
|
191
|
+
...(options.limit !== undefined ? { limit: options.limit } : {}),
|
|
192
|
+
...(deleteVaultKey ? { deleteVaultKey } : {}),
|
|
193
|
+
});
|
|
194
|
+
return options.json ? JSON.stringify(report, null, 2) : mergeCopiesSummary(report);
|
|
195
|
+
}
|
|
127
196
|
function fail(error) {
|
|
128
197
|
if (error instanceof OntologyUsageError || error instanceof ApplyError || error instanceof WriteBoundsError) {
|
|
129
198
|
process.stderr.write(`${error.message}\n`);
|
|
@@ -163,6 +232,23 @@ export function registerCoreOntologyCommand(core) {
|
|
|
163
232
|
fail(error);
|
|
164
233
|
}
|
|
165
234
|
});
|
|
235
|
+
ontology
|
|
236
|
+
.command("merge-copies")
|
|
237
|
+
.description("Merge '<name> N.md' entity copies into their original, then delete them from the vault (dry run by default)")
|
|
238
|
+
.requiredOption("--company <slug>", "company to change")
|
|
239
|
+
.option("--apply", "merge each copy into its original and re-point links (writes entity files)")
|
|
240
|
+
.option("--delete", "delete fully merged copies from the vault by exact key (after sync pushed the merge)")
|
|
241
|
+
.option("--limit <n>", "handle at most this many copies", (value) => Number(value))
|
|
242
|
+
.option("--json", "print JSON")
|
|
243
|
+
.option("--hq-root <path>", "HQ installation to operate on")
|
|
244
|
+
.action(async (options) => {
|
|
245
|
+
try {
|
|
246
|
+
process.stdout.write(`${await runOntologyMergeCopies(rootFor(options), options.company, options)}\n`);
|
|
247
|
+
}
|
|
248
|
+
catch (error) {
|
|
249
|
+
fail(error);
|
|
250
|
+
}
|
|
251
|
+
});
|
|
166
252
|
ontology
|
|
167
253
|
.command("apply")
|
|
168
254
|
.description("Validate the run's entity candidates and write them to the payload company")
|
package/dist/commands/files.d.ts
CHANGED
|
@@ -62,6 +62,22 @@ export declare class FilesDeleteHttpError extends Error {
|
|
|
62
62
|
export declare function formatFilesDeleteError(err: FilesDeleteHttpError, prefix: string): string;
|
|
63
63
|
/** Injectable yes/no confirmation seam (stubbed in tests). */
|
|
64
64
|
export type ConfirmFn = (message: string) => Promise<boolean>;
|
|
65
|
+
/**
|
|
66
|
+
* POST /v1/files/delete. Throws FilesDeleteHttpError on any non-2xx so the one
|
|
67
|
+
* caller renders a single consistent error path.
|
|
68
|
+
*
|
|
69
|
+
* Scope is EITHER a company vault (`companyUid` set) OR the caller's personal
|
|
70
|
+
* vault (`personal: true`). For the personal case the server resolves the target
|
|
71
|
+
* person + bucket from the authenticated caller — we send NO uid, just the
|
|
72
|
+
* `personal` flag — so there is nothing for the client to get wrong or spoof.
|
|
73
|
+
*/
|
|
74
|
+
export declare function callDeleteEndpoint(params: {
|
|
75
|
+
token: string;
|
|
76
|
+
companyUid?: string;
|
|
77
|
+
personal?: boolean;
|
|
78
|
+
prefix: string;
|
|
79
|
+
dryRun: boolean;
|
|
80
|
+
}): Promise<FilesDeleteResponse>;
|
|
65
81
|
interface RunFilesDeleteParams {
|
|
66
82
|
prefix: string;
|
|
67
83
|
dryRun: boolean;
|
package/dist/commands/files.js
CHANGED
|
@@ -879,7 +879,7 @@ function realConfirm(message) {
|
|
|
879
879
|
* person + bucket from the authenticated caller — we send NO uid, just the
|
|
880
880
|
* `personal` flag — so there is nothing for the client to get wrong or spoof.
|
|
881
881
|
*/
|
|
882
|
-
async function callDeleteEndpoint(params) {
|
|
882
|
+
export async function callDeleteEndpoint(params) {
|
|
883
883
|
const res = await vaultApiFetch({
|
|
884
884
|
token: params.token,
|
|
885
885
|
path: "/v1/files/delete",
|
|
@@ -65,9 +65,12 @@ export function createLaneMessageHandlers(deps) {
|
|
|
65
65
|
if (!text) {
|
|
66
66
|
throw new LanesError("missing_text", "--text is required", {});
|
|
67
67
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
const resolution = await deps.resolveCommandLane(ctx, laneId);
|
|
69
|
+
let lane = resolution.lane;
|
|
70
|
+
if (resolution.remoteOnly || (lane.host.kind === "outpost" && !laneIsHostedHere(ctx, lane))) {
|
|
71
|
+
await dispatchOutpostLaneCommand(ctx, lane, "message", opts, resolution.remoteOnly
|
|
72
|
+
? { syncPrimary: false, expectedOwnerHost: resolution.ownerHost }
|
|
73
|
+
: undefined);
|
|
71
74
|
return;
|
|
72
75
|
}
|
|
73
76
|
assertLaneRunsHereForOperatorMutation(ctx, lane, "message");
|
|
@@ -86,7 +86,8 @@ export function createLaneResumeHandlers(deps) {
|
|
|
86
86
|
*/
|
|
87
87
|
async function runResume(ctx, laneId, opts) {
|
|
88
88
|
const hqRoot = ctx.hqRoot();
|
|
89
|
-
|
|
89
|
+
const resolution = await deps.resolveCommandLane(ctx, laneId);
|
|
90
|
+
let lane = resolution.lane;
|
|
90
91
|
const failedResumeReason = opts.reason?.trim();
|
|
91
92
|
if (opts.reason !== undefined && opts.fromFailed !== true) {
|
|
92
93
|
throw new LanesError("failed_resume_reason_requires_flag", "--reason on hq lanes resume requires --from-failed", { lane_id: laneId });
|
|
@@ -122,9 +123,11 @@ export function createLaneResumeHandlers(deps) {
|
|
|
122
123
|
if (opts.profileRepinContext !== undefined && !ctx.isSsmOwnerDispatch()) {
|
|
123
124
|
throw new LanesError("worker_profile_hash_mismatch", "Profile re-pin context is only valid on an Outpost owner dispatch", { lane_id: laneId });
|
|
124
125
|
}
|
|
125
|
-
if (lane.host.kind === "outpost" && !laneIsHostedHere(ctx, lane)) {
|
|
126
|
+
if (resolution.remoteOnly || (lane.host.kind === "outpost" && !laneIsHostedHere(ctx, lane))) {
|
|
126
127
|
await withResumeHireAdmission(ctx, lane, () => undefined);
|
|
127
|
-
await dispatchOutpostLaneCommand(ctx, lane, "resume", opts
|
|
128
|
+
await dispatchOutpostLaneCommand(ctx, lane, "resume", opts, resolution.remoteOnly
|
|
129
|
+
? { syncPrimary: false, expectedOwnerHost: resolution.ownerHost }
|
|
130
|
+
: undefined);
|
|
128
131
|
return;
|
|
129
132
|
}
|
|
130
133
|
// Fail before provider/session work if a terminal child would consume a
|
|
@@ -115,6 +115,21 @@ export declare function resolveResumeEffort(ctx: Ctx, lane: LaneRecord, input: {
|
|
|
115
115
|
model?: string;
|
|
116
116
|
}): ResolvedEffort | undefined;
|
|
117
117
|
export declare function recordedResumeEffort(lane: LaneRecord): ResolvedEffort;
|
|
118
|
+
export type CommandLaneResolution = {
|
|
119
|
+
lane: LaneRecord;
|
|
120
|
+
remoteOnly: false;
|
|
121
|
+
} | {
|
|
122
|
+
lane: LaneRecord;
|
|
123
|
+
remoteOnly: true;
|
|
124
|
+
outpostId: string;
|
|
125
|
+
ownerHost: LaneRecord["host"];
|
|
126
|
+
};
|
|
127
|
+
export interface OutpostLaneDispatchBehavior {
|
|
128
|
+
/** Keep remote-only lanes out of the primary lane store. */
|
|
129
|
+
syncPrimary?: boolean;
|
|
130
|
+
/** Host identity returned by the remote record lookup for a remote-only lane. */
|
|
131
|
+
expectedOwnerHost?: LaneRecord["host"];
|
|
132
|
+
}
|
|
118
133
|
export interface LaneMessageHandlerDeps {
|
|
119
134
|
archiveResumeMessage(hqRoot: string, laneId: string, message: {
|
|
120
135
|
message_id: string;
|
|
@@ -128,7 +143,7 @@ export interface LaneMessageHandlerDeps {
|
|
|
128
143
|
alreadyQueued?: boolean;
|
|
129
144
|
}): Promise<AdmissionResult>;
|
|
130
145
|
casUpdateLane(hqRoot: string, laneId: string, updater: (current: LaneRecord) => LaneRecord): LaneRecord;
|
|
131
|
-
dispatchOutpostLaneCommand(ctx: Ctx, lane: LaneRecord, action: "message" | "resume", options: LaneMessageOptions | LaneResumeOptions): Promise<void>;
|
|
146
|
+
dispatchOutpostLaneCommand(ctx: Ctx, lane: LaneRecord, action: "message" | "resume", options: LaneMessageOptions | LaneResumeOptions, behavior?: OutpostLaneDispatchBehavior): Promise<void>;
|
|
132
147
|
drainHookStatusFor(ctx: Ctx, lane: LaneRecord): {
|
|
133
148
|
registered: boolean;
|
|
134
149
|
kind: string;
|
|
@@ -142,6 +157,7 @@ export interface LaneMessageHandlerDeps {
|
|
|
142
157
|
persistClaudeAccountSelection(hqRoot: string, lane: LaneRecord, selection: LaneAccountSelection): LaneRecord;
|
|
143
158
|
printJson(value: unknown): void;
|
|
144
159
|
recordResumeSetup(ctx: Ctx, lane: LaneRecord, input: RecordResumeSetupInput): LaneRecord;
|
|
160
|
+
resolveCommandLane(ctx: Ctx, laneId: string): Promise<CommandLaneResolution>;
|
|
145
161
|
resolveActiveQuestionCompany(ctx: Ctx, message?: string): Promise<LaneCompanyRef>;
|
|
146
162
|
resolveResumeProfile(ctx: Ctx, lane: LaneRecord, workerId: string): ResolvedResumeProfile;
|
|
147
163
|
selectAutomaticClaudeResumeAccount(ctx: Ctx, lane: LaneRecord, workerProfile?: ResolvedResumeProfile, options?: {
|
|
@@ -154,8 +170,8 @@ export interface LaneMessageHandlerDeps {
|
|
|
154
170
|
validateResumeProfileModel(ctx: Ctx, lane: LaneRecord, profile: WorkerProfile): void;
|
|
155
171
|
withResumeHireAdmission<T>(ctx: Ctx, lane: LaneRecord, fn: () => T, grantContext?: OutpostHireGrantContext): Promise<T>;
|
|
156
172
|
}
|
|
157
|
-
export interface LaneResumeHandlerDeps extends Pick<LaneMessageHandlerDeps, "archiveResumeMessage" | "assertLaneRunsHereForAdmission" | "assertLaneRunsHereForOperatorMutation" | "assessLaneAdmission" | "casUpdateLane" | "laneIsHostedHere" | "laneWithRecoveredProviderSession" | "mintMessageId" | "prepareAccountMove" | "persistClaudeAccountSelection" | "printJson" | "recordResumeSetup" | "resolveResumeProfile" | "selectAutomaticClaudeResumeAccount" | "validateResumeProfileModel" | "withResumeHireAdmission"> {
|
|
158
|
-
dispatchOutpostLaneCommand(ctx: Ctx, lane: LaneRecord, action: "resume", options: LaneResumeOptions): Promise<void>;
|
|
173
|
+
export interface LaneResumeHandlerDeps extends Pick<LaneMessageHandlerDeps, "archiveResumeMessage" | "assertLaneRunsHereForAdmission" | "assertLaneRunsHereForOperatorMutation" | "assessLaneAdmission" | "casUpdateLane" | "laneIsHostedHere" | "laneWithRecoveredProviderSession" | "mintMessageId" | "prepareAccountMove" | "persistClaudeAccountSelection" | "printJson" | "recordResumeSetup" | "resolveCommandLane" | "resolveResumeProfile" | "selectAutomaticClaudeResumeAccount" | "validateResumeProfileModel" | "withResumeHireAdmission"> {
|
|
174
|
+
dispatchOutpostLaneCommand(ctx: Ctx, lane: LaneRecord, action: "resume", options: LaneResumeOptions, behavior?: OutpostLaneDispatchBehavior): Promise<void>;
|
|
159
175
|
authorizeFailedResume(ctx: Ctx, lane: LaneRecord, encodedContext?: string): string;
|
|
160
176
|
authorizeResumeProfileRepin(ctx: Ctx, lane: LaneRecord, profile: ResolvedResumeProfile | undefined, encodedContext: string | undefined): ResumeProfileRepinAuthorization | undefined;
|
|
161
177
|
automaticBalanceMoveHistoryReason(ctx: Ctx, lane: LaneRecord): AccountHistoryEntry["reason"];
|
|
@@ -217,7 +233,7 @@ export interface Ctx {
|
|
|
217
233
|
}) => Promise<OutpostDispatchResult>;
|
|
218
234
|
backfillOutpostIdentity: (expectedId: string) => "created" | "unchanged";
|
|
219
235
|
fetchText: (url: string) => Promise<string>;
|
|
220
|
-
lanePlacementEnabled: () => boolean
|
|
236
|
+
lanePlacementEnabled: (company: LaneCompanyRef | undefined) => Promise<boolean>;
|
|
221
237
|
storyLedgerEnabled: () => boolean;
|
|
222
238
|
isSsmOwnerDispatch: () => boolean;
|
|
223
239
|
withGrantHireLocks: typeof withLaneHireLocks;
|
package/dist/commands/lanes.d.ts
CHANGED
|
@@ -83,7 +83,7 @@ export interface LanesCommandDeps {
|
|
|
83
83
|
locateTranscript?: (home: string, sessionId: string) => string | null;
|
|
84
84
|
monitorEvidence?: MonitorEvidenceReader;
|
|
85
85
|
/** Test seam for the default-off outpost placement rollout flag. */
|
|
86
|
-
lanePlacementEnabled?: () => boolean
|
|
86
|
+
lanePlacementEnabled?: (company: LaneCompanyRef | undefined) => Promise<boolean>;
|
|
87
87
|
/** Test seam for the default-off story ledger flag. */
|
|
88
88
|
storyLedgerEnabled?: () => boolean;
|
|
89
89
|
/** Test seam for the SSM-only Outpost owner grant path. */
|