@indigoai-us/hq-cli 5.289.0 → 5.290.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.
@@ -33,6 +33,8 @@ export interface MergeCopiesCommandOptions {
33
33
  variants?: boolean;
34
34
  limit?: number;
35
35
  only?: string;
36
+ /** Also re-point refs and links held today (flag merge-rewrite-refs). */
37
+ rewriteRefs?: boolean;
36
38
  json?: boolean;
37
39
  }
38
40
  /** Reads a `--only` file: a JSON array of `{ copy, original }` company-relative paths. */
@@ -44,7 +46,10 @@ export declare function readListedPairs(file: string): ListedPair[];
44
46
  * `checkpoint.ontology.merge-copies` and `checkpoint.ontology.multi-writer`.
45
47
  * With `--variants`, merges two-file duplicate groups whose names differ only
46
48
  * in case, spacing or punctuation instead, gated by
47
- * `checkpoint.ontology.merge-variants`.
49
+ * `checkpoint.ontology.merge-variants`. `--rewrite-refs` (flag
50
+ * `checkpoint.ontology.merge-rewrite-refs`) also re-points signal refs,
51
+ * invoice and bill links, source and knowledge links, and carries external
52
+ * ids and web domains.
48
53
  */
49
54
  export declare function runOntologyMergeCopies(hqRoot: string, slug: string | undefined, options: MergeCopiesCommandOptions, deps?: OntologyCommandDeps): Promise<string>;
50
55
  export declare function registerCoreOntologyCommand(core: Command): void;
@@ -17,7 +17,7 @@ import { applyOntologyRun, ApplyError } from "../lib/checkpoint-ontology/apply.j
17
17
  import { resolveOntologyCompany, WriteBoundsError } from "../lib/checkpoint-ontology/company.js";
18
18
  import { findDuplicateGroups, summarizeMergeBack, } from "../lib/checkpoint-ontology/multi-writer.js";
19
19
  import { buildEntityIndex } from "../lib/checkpoint-ontology/tree.js";
20
- import { MERGE_COPIES_FLAG, MERGE_VARIANTS_FLAG, mergeCopies, } from "../lib/checkpoint-ontology/merge-copies.js";
20
+ import { MERGE_COPIES_FLAG, MERGE_REWRITE_REFS_FLAG, MERGE_VARIANTS_FLAG, mergeCopies, } from "../lib/checkpoint-ontology/merge-copies.js";
21
21
  import { callDeleteEndpoint } from "./files.js";
22
22
  import { resolveVaultCredential } from "../utils/resolve-vault-credential.js";
23
23
  import { registerCoreOntologyNativeCommands } from "./core-ontology-native.js";
@@ -146,11 +146,12 @@ function mergeCopiesSummary(report) {
146
146
  const held = report.plans.filter((plan) => plan.held).length;
147
147
  const lines = [
148
148
  `ontology merge-copies (${report.mode.replace("_", " ")}) in ${report.company} (${report.pair_kind}): ${report.plans.length} of ${report.copies_found} copies, ${held} held, ${report.skipped.length} skipped`,
149
- ` merged ${report.merged.length}, relinked ${report.relinked.length}, deleted ${report.deleted.length}, not ready ${report.not_ready.length}, errors ${report.errors.length}`,
149
+ ` merged ${report.merged.length}, relinked ${report.relinked.length}${report.rewritten !== undefined ? `, rewritten ${report.rewritten.length}` : ""}, deleted ${report.deleted.length}, not ready ${report.not_ready.length}, errors ${report.errors.length}`,
150
150
  ` duplicate groups ${report.duplicate_groups_before} -> ${report.duplicate_groups_after}; broken entity links ${report.broken_links_before} -> ${report.broken_links_after}`,
151
151
  ];
152
- for (const plan of report.plans.filter((entry) => entry.held))
153
- lines.push(` held ${plan.copy}: ${plan.held}`);
152
+ for (const plan of report.plans.filter((entry) => entry.held)) {
153
+ lines.push(` held ${plan.copy}: ${plan.held}${plan.held === "external_id_conflict" ? ` (${plan.detail})` : ""}`);
154
+ }
154
155
  for (const error of report.errors)
155
156
  lines.push(` error ${error.path}: ${error.error}`);
156
157
  for (const entry of report.only_unmatched ?? [])
@@ -176,7 +177,36 @@ export function readListedPairs(file) {
176
177
  })) {
177
178
  throw new OntologyUsageError("ontology: --only must be a non-empty JSON array of { copy, original } paths");
178
179
  }
179
- return parsed.map((entry) => ({ copy: entry.copy, original: entry.original }));
180
+ return parsed.map((entry) => {
181
+ if (entry.resolve_external_ids === undefined)
182
+ return { copy: entry.copy, original: entry.original };
183
+ return { copy: entry.copy, original: entry.original, resolve_external_ids: readResolution(entry.copy, entry.resolve_external_ids) };
184
+ });
185
+ }
186
+ /** `{ provider: { primary, namespace, object_type? } }`, every value a non-empty string. */
187
+ function readResolution(copy, raw) {
188
+ const usage = `ontology: --only entry ${copy}: resolve_external_ids must map each provider to { primary, namespace, object_type? } strings`;
189
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw) || Object.keys(raw).length === 0)
190
+ throw new OntologyUsageError(usage);
191
+ const out = {};
192
+ for (const [provider, value] of Object.entries(raw)) {
193
+ if (value === null || typeof value !== "object" || Array.isArray(value))
194
+ throw new OntologyUsageError(usage);
195
+ const record = value;
196
+ const nonEmpty = (field) => typeof field === "string" && field.length > 0;
197
+ if (!Object.keys(record).every((key) => key === "primary" || key === "namespace" || key === "object_type") ||
198
+ !nonEmpty(record.primary) ||
199
+ !nonEmpty(record.namespace) ||
200
+ (record.object_type !== undefined && !nonEmpty(record.object_type))) {
201
+ throw new OntologyUsageError(usage);
202
+ }
203
+ out[provider] = {
204
+ primary: record.primary,
205
+ namespace: record.namespace,
206
+ ...(record.object_type !== undefined ? { object_type: record.object_type } : {}),
207
+ };
208
+ }
209
+ return out;
180
210
  }
181
211
  /**
182
212
  * `hq core ontology merge-copies`: merge `<slug> <n>.md` copies into their
@@ -185,7 +215,10 @@ export function readListedPairs(file) {
185
215
  * `checkpoint.ontology.merge-copies` and `checkpoint.ontology.multi-writer`.
186
216
  * With `--variants`, merges two-file duplicate groups whose names differ only
187
217
  * in case, spacing or punctuation instead, gated by
188
- * `checkpoint.ontology.merge-variants`.
218
+ * `checkpoint.ontology.merge-variants`. `--rewrite-refs` (flag
219
+ * `checkpoint.ontology.merge-rewrite-refs`) also re-points signal refs,
220
+ * invoice and bill links, source and knowledge links, and carries external
221
+ * ids and web domains.
189
222
  */
190
223
  export async function runOntologyMergeCopies(hqRoot, slug, options, deps = {}) {
191
224
  if (options.apply && options.delete) {
@@ -200,7 +233,7 @@ export async function runOntologyMergeCopies(hqRoot, slug, options, deps = {}) {
200
233
  throw new OntologyUsageError(`ontology: company rejected: ${resolution.reason}`);
201
234
  const company = resolution.company;
202
235
  const readFlag = deps.readFlag ?? registryFlagReader;
203
- for (const flag of [options.variants ? MERGE_VARIANTS_FLAG : MERGE_COPIES_FLAG, MULTI_WRITER_FLAG]) {
236
+ for (const flag of [options.variants ? MERGE_VARIANTS_FLAG : MERGE_COPIES_FLAG, MULTI_WRITER_FLAG, ...(options.rewriteRefs ? [MERGE_REWRITE_REFS_FLAG] : [])]) {
204
237
  if (!(await readFlag(flag, company))) {
205
238
  return options.json ? JSON.stringify({ company: company.slug, skipped: `${flag} off` }) : `ontology merge-copies: skipped (${flag} is off)`;
206
239
  }
@@ -220,6 +253,7 @@ export async function runOntologyMergeCopies(hqRoot, slug, options, deps = {}) {
220
253
  ...(options.variants ? { pairKind: "variants" } : {}),
221
254
  ...(options.limit !== undefined ? { limit: options.limit } : {}),
222
255
  ...(only ? { only } : {}),
256
+ ...(options.rewriteRefs ? { rewriteRefs: true } : {}),
223
257
  ...(deleteVaultKey ? { deleteVaultKey } : {}),
224
258
  });
225
259
  return options.json ? JSON.stringify(report, null, 2) : mergeCopiesSummary(report);
@@ -274,6 +308,7 @@ export function registerCoreOntologyCommand(core) {
274
308
  .option("--variants", "merge two-file duplicate groups whose names differ only in case, spacing or punctuation (checkpoint.ontology.merge-variants)")
275
309
  .option("--limit <n>", "handle at most this many copies", (value) => Number(value))
276
310
  .option("--only <file>", "handle only the copy -> original pairs listed in this JSON file")
311
+ .option("--rewrite-refs", "also re-point signal refs, invoice, source and knowledge links to the survivor and carry external ids and web domains (checkpoint.ontology.merge-rewrite-refs)")
277
312
  .option("--json", "print JSON")
278
313
  .option("--hq-root <path>", "HQ installation to operate on")
279
314
  .action(async (options) => {
@@ -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 { registerCoreHandoffCommand } from "./core-handoff.js";
34
35
  import { registerCoreOntologyCommand } from "./core-ontology.js";
35
36
  import { registerCoreKnowledgePrefsCommand } from "./core-knowledge-prefs.js";
36
37
  import { registerCorePolicyCommand } from "./core-policy.js";
@@ -241,7 +242,7 @@ export const SCAFFOLD_ONLY_ASSETS = [
241
242
  { asset: "core/scripts/ontology-source-worklist.sh", root: "live", summary: "Rollback companion for native ontology source worklist" },
242
243
  { asset: "core/scripts/source-yaml-validate.sh", root: "cwd", summary: "Rollback companion for native source YAML validation" },
243
244
  // Shared by native knowledge-prefs and the ontology candidate shell fallback.
244
- { asset: "core/scripts/knowledge-prefs.sh", root: "live", summary: "Rollback companion for native knowledge-prefs and ontology candidate" },
245
+ { asset: "core/scripts/knowledge-prefs.sh", root: "live", summary: "Sibling dependency for ontology candidate rollback companion" },
245
246
  // Rollback companions for the default-off native knowledge and policy routes.
246
247
  // policy-retire also runs the scaffold validator in-process when native, but
247
248
  // its bundled shell fallback needs both helper assets at these exact paths.
@@ -250,6 +251,11 @@ export const SCAFFOLD_ONLY_ASSETS = [
250
251
  { asset: "core/scripts/read-policy-frontmatter.sh", root: "cwd", summary: "Rollback companion for native policy frontmatter" },
251
252
  { asset: "core/scripts/eval-trigger.sh", root: "live", summary: "Trigger grammar helper used by the policy validator companion" },
252
253
  { asset: ".claude/hooks/validate-policy-frontmatter.sh", root: "live", summary: "Policy validator companion used by policy-retire rollback" },
254
+ // Wave 2a handoff shells remain bundled as the default-off rollback path.
255
+ { asset: "core/scripts/handoff-finalize.sh", root: "live", summary: "Rollback shell for native handoff finalize" },
256
+ { asset: "core/scripts/handoff-post.sh", root: "live", summary: "Rollback shell for native handoff post" },
257
+ { asset: "core/scripts/handoff-open-steps.sh", root: "live", summary: "Rollback shell for native handoff open-steps" },
258
+ { asset: "core/scripts/qmd-reindex-bg.sh", root: "live", summary: "Rollback handoff reindex forwarder" },
253
259
  ...NATIVE_UTILITY_COMMANDS.map(({ asset, root, summary }) => ({
254
260
  asset,
255
261
  root,
@@ -326,6 +332,7 @@ export function registerCoreCommands(program) {
326
332
  registerCoreOntologyCommand(core);
327
333
  registerCoreCheckpointGateSettingCommand(core);
328
334
  registerCoreDelegateCommand(core);
335
+ registerCoreHandoffCommand(core);
329
336
  registerCoreKnowledgePrefsCommand(core);
330
337
  registerCorePolicyCommand(core);
331
338
  // Wave 2 handoff/worktree commands retain their byte-identical shell assets
@@ -66,6 +66,27 @@ export type PatchResult = {
66
66
  * change, the file is returned unchanged so a rerun writes nothing.
67
67
  */
68
68
  export declare function patchEntityFile(content: string, patch: EntityPatch): PatchResult;
69
+ /** A namespaced record in a source system, as the cloud schema's `external_refs` holds it. */
70
+ export interface ExternalRef {
71
+ system: string;
72
+ namespace: string;
73
+ objectType?: string;
74
+ recordId: string;
75
+ }
76
+ export interface IdentityPatch {
77
+ externalIds: Record<string, string>;
78
+ webDomains: string[];
79
+ /** When set, the whole `external_refs` list; when absent, the key is left alone. */
80
+ externalRefs?: ExternalRef[];
81
+ lastUpdated: string;
82
+ }
83
+ /**
84
+ * Set `external_ids` and `web_domains` on an existing, valid entity file.
85
+ * A key whose value is already equal is left as it is; an absent key is
86
+ * appended at the end of the front matter. Nothing else changes except
87
+ * `last_updated`. When neither key changes the file is returned unchanged.
88
+ */
89
+ export declare function setIdentityKeys(content: string, patch: IdentityPatch): PatchResult;
69
90
  export interface SignalBackRef {
70
91
  signalType: string;
71
92
  preview: string;
@@ -206,6 +206,106 @@ function checkPatched(original, next, aliases, signalCount, lastUpdated) {
206
206
  return "patch_last_updated";
207
207
  return null;
208
208
  }
209
+ function renderExternalIds(ids) {
210
+ const entries = Object.entries(ids);
211
+ if (entries.length === 0)
212
+ return "external_ids: {}";
213
+ return ["external_ids:", ...entries.map(([key, value]) => ` ${key}: ${quote(value)}`)].join("\n");
214
+ }
215
+ function renderExternalRefs(refs) {
216
+ if (refs.length === 0)
217
+ return "external_refs: []";
218
+ const lines = ["external_refs:"];
219
+ for (const ref of refs) {
220
+ lines.push(` - system: ${quote(ref.system)}`, ` namespace: ${quote(ref.namespace)}`);
221
+ if (ref.objectType !== undefined)
222
+ lines.push(` objectType: ${quote(ref.objectType)}`);
223
+ lines.push(` recordId: ${quote(ref.recordId)}`);
224
+ }
225
+ return lines.join("\n");
226
+ }
227
+ function renderWebDomains(domains) {
228
+ if (domains.length === 0)
229
+ return "web_domains: []";
230
+ return ["web_domains:", ...domains.map((domain) => ` - ${quote(domain)}`)].join("\n");
231
+ }
232
+ /**
233
+ * Set `external_ids` and `web_domains` on an existing, valid entity file.
234
+ * A key whose value is already equal is left as it is; an absent key is
235
+ * appended at the end of the front matter. Nothing else changes except
236
+ * `last_updated`. When neither key changes the file is returned unchanged.
237
+ */
238
+ export function setIdentityKeys(content, patch) {
239
+ const match = FRONTMATTER_RE.exec(content);
240
+ const parsed = parseEntityFile(content);
241
+ if (!match || !parsed)
242
+ return { ok: false, reason: "unparseable" };
243
+ const before = validateEntityFrontmatter(parsed.frontmatter);
244
+ if (typeof before === "string")
245
+ return { ok: false, reason: `invalid_existing:${before}` };
246
+ for (const key of Object.keys(patch.externalIds)) {
247
+ if (!/^[A-Za-z0-9_-]+$/.test(key))
248
+ return { ok: false, reason: "external_ids_key" };
249
+ }
250
+ const currentIds = (parsed.frontmatter.external_ids ?? {});
251
+ const currentDomains = (parsed.frontmatter.web_domains ?? []);
252
+ const currentRefs = parsed.frontmatter.external_refs ?? [];
253
+ const idsChanged = !isDeepStrictEqual(currentIds, patch.externalIds);
254
+ const domainsChanged = !isDeepStrictEqual(currentDomains, patch.webDomains);
255
+ const refsChanged = patch.externalRefs !== undefined && !isDeepStrictEqual(currentRefs, patch.externalRefs);
256
+ if (!idsChanged && !domainsChanged && !refsChanged)
257
+ return { ok: true, content, changed: false };
258
+ const newline = content.includes("\r\n") ? "\r\n" : "\n";
259
+ let lines = match[1].split(/\r?\n/);
260
+ if (idsChanged) {
261
+ const rendered = renderExternalIds(patch.externalIds);
262
+ lines = replaceTopLevelKey(lines, "external_ids", rendered) ?? [...lines, ...rendered.split("\n")];
263
+ }
264
+ if (domainsChanged) {
265
+ const rendered = renderWebDomains(patch.webDomains);
266
+ lines = replaceTopLevelKey(lines, "web_domains", rendered) ?? [...lines, ...rendered.split("\n")];
267
+ }
268
+ if (refsChanged) {
269
+ const rendered = renderExternalRefs(patch.externalRefs);
270
+ lines = replaceTopLevelKey(lines, "external_refs", rendered) ?? [...lines, ...rendered.split("\n")];
271
+ }
272
+ const stamped = replaceTopLevelKey(lines, "last_updated", `last_updated: ${patch.lastUpdated}`);
273
+ if (!stamped)
274
+ return { ok: false, reason: "missing_owned_key" };
275
+ lines = stamped;
276
+ const head = content.slice(0, content.indexOf(match[1]));
277
+ const tail = content.slice(content.indexOf(match[1]) + match[1].length);
278
+ const next = `${head}${lines.join(newline)}${tail}`;
279
+ const reparsed = parseEntityFile(next);
280
+ if (!reparsed)
281
+ return { ok: false, reason: "patch_unparseable" };
282
+ if (typeof validateEntityFrontmatter(reparsed.frontmatter) === "string")
283
+ return { ok: false, reason: "patch_invalid" };
284
+ const keys = new Set([...Object.keys(parsed.frontmatter), ...Object.keys(reparsed.frontmatter)]);
285
+ for (const key of keys) {
286
+ if (key === "external_ids" || key === "web_domains" || key === "last_updated")
287
+ continue;
288
+ if (key === "external_refs" && patch.externalRefs !== undefined)
289
+ continue;
290
+ if (!isDeepStrictEqual(parsed.frontmatter[key], reparsed.frontmatter[key])) {
291
+ return { ok: false, reason: `patch_changed_key:${key}` };
292
+ }
293
+ }
294
+ if (!isDeepStrictEqual(reparsed.frontmatter.external_ids ?? {}, patch.externalIds)) {
295
+ return { ok: false, reason: "patch_external_ids" };
296
+ }
297
+ if (!isDeepStrictEqual(reparsed.frontmatter.web_domains ?? [], patch.webDomains)) {
298
+ return { ok: false, reason: "patch_web_domains" };
299
+ }
300
+ if (refsChanged && !isDeepStrictEqual(reparsed.frontmatter.external_refs ?? [], patch.externalRefs)) {
301
+ return { ok: false, reason: "patch_external_refs" };
302
+ }
303
+ if (reparsed.frontmatter.last_updated !== patch.lastUpdated)
304
+ return { ok: false, reason: "patch_last_updated" };
305
+ if (reparsed.body !== parsed.body)
306
+ return { ok: false, reason: "patch_body" };
307
+ return { ok: true, content: next, changed: true };
308
+ }
209
309
  /** hq-pro `previewSignalContent`: first 80 characters, one line. */
210
310
  export function previewSignalContent(canonicalContent) {
211
311
  const collapsed = canonicalContent.replace(/\s+/g, " ").trim();
@@ -26,7 +26,11 @@
26
26
  * merge cannot rewrite (a copy, a knowledge file, a signal) is held.
27
27
  *
28
28
  * A signal whose `entity_refs` names a copy holds that copy: signals are
29
- * server-owned, so the ref cannot be re-pointed from here.
29
+ * server-owned, so the ref cannot be re-pointed from here. With `rewriteRefs`
30
+ * (flag `checkpoint.ontology.merge-rewrite-refs`) signal refs, invoice and
31
+ * bill links, source and knowledge links are re-pointed at the survivor, the
32
+ * survivor receives the copy's `external_ids` and `web_domains`, and only a
33
+ * link from another copy or an external id conflict holds a pair.
30
34
  *
31
35
  * With `pairKind: "variants"` (flag `checkpoint.ontology.merge-variants`) the
32
36
  * pairs are two-file duplicate groups whose canonical names differ only in
@@ -42,6 +46,12 @@ export declare const MERGE_COPIES_FLAG = "checkpoint.ontology.merge-copies";
42
46
  * names differ only in spacing, case or punctuation (CO-65).
43
47
  */
44
48
  export declare const MERGE_VARIANTS_FLAG = "checkpoint.ontology.merge-variants";
49
+ /**
50
+ * `merge-copies --rewrite-refs`: re-point signal `entity_refs`, invoice and
51
+ * bill links, source and knowledge links from a copy to its survivor, and
52
+ * carry the copy's `external_ids` and `web_domains` to the survivor.
53
+ */
54
+ export declare const MERGE_REWRITE_REFS_FLAG = "checkpoint.ontology.merge-rewrite-refs";
45
55
  export type CopySkipReason = "no_original" | "original_invalid" | "identity_differs" | "not_in_duplicate_group" | "group_size" | "type_differs" | "names_differ" | "numbered_copy" | "not_listed";
46
56
  export type PairKind = "numbered" | "variants";
47
57
  export interface CopySkip {
@@ -55,10 +65,22 @@ export interface CopyPair {
55
65
  /** Company-relative path of the original it merges into. */
56
66
  original: string;
57
67
  }
68
+ /**
69
+ * How to settle one provider's `external_ids` conflict: `primary` stays in
70
+ * `external_ids`, and the pair's other id moves to `external_refs` under
71
+ * `namespace` (the provider account or workspace) and `object_type`.
72
+ */
73
+ export interface ExternalIdResolution {
74
+ primary: string;
75
+ namespace: string;
76
+ object_type?: string;
77
+ }
58
78
  /** One entry of a `--only` list: an exact copy -> original pair. */
59
79
  export interface ListedPair {
60
80
  copy: string;
61
81
  original: string;
82
+ /** Provider -> resolution, applied only when `rewriteRefs` is on and the ids conflict. */
83
+ resolve_external_ids?: Record<string, ExternalIdResolution>;
62
84
  }
63
85
  export interface CopyPlan extends CopyPair {
64
86
  add_aliases: string[];
@@ -75,8 +97,14 @@ export interface CopyPlan extends CopyPair {
75
97
  /** Signal files whose `entity_refs` name the copy. */
76
98
  signal_refs: string[];
77
99
  /** Why the copy cannot be merged or deleted from here. */
78
- held?: "signal_refs" | "linked_from_unwritable" | "merge_invalid";
100
+ held?: "signal_refs" | "linked_from_unwritable" | "merge_invalid" | "external_id_conflict";
79
101
  detail?: string;
102
+ /** Keys added to the survivor. Set only when `rewriteRefs` is on. */
103
+ add_external_ids?: string[];
104
+ /** Domains added to the survivor. Set only when `rewriteRefs` is on. */
105
+ add_web_domains?: string[];
106
+ /** `system:namespace:recordId` refs added to the survivor's `external_refs`. Set only when `rewriteRefs` is on. */
107
+ add_external_refs?: string[];
80
108
  /** Body lines of the copy the merged original lacks; a copy with any is never deleted. */
81
109
  unmerged_body_lines: number;
82
110
  }
@@ -105,6 +133,8 @@ export interface MergeCopiesReport {
105
133
  }[];
106
134
  /** Listed entries the finder did not produce. Absent unless `--only` was set. */
107
135
  only_unmatched?: ListedPair[];
136
+ /** Signal, source and knowledge files re-pointed at a survivor. Absent unless `rewriteRefs` was set. */
137
+ rewritten?: string[];
108
138
  /** Entity-file links whose target file does not exist. */
109
139
  broken_links_before: number;
110
140
  broken_links_after: number;
@@ -123,6 +153,8 @@ export interface MergeCopiesOptions {
123
153
  limit?: number;
124
154
  /** Handle only these exact pairs; every other found pair is skipped as `not_listed`. */
125
155
  only?: ListedPair[];
156
+ /** Re-point refs and links held today, and carry ids and domains (flag merge-rewrite-refs). */
157
+ rewriteRefs?: boolean;
126
158
  now: Date;
127
159
  deleteVaultKey?: DeleteVaultKey;
128
160
  }