@sechroom/cli 2026.7.10 → 2026.7.12
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/dist/index.js +78 -13
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -633,7 +633,22 @@ async function runApi(label, fn) {
|
|
|
633
633
|
return res.data;
|
|
634
634
|
}
|
|
635
635
|
function fail(error) {
|
|
636
|
-
|
|
636
|
+
let msg;
|
|
637
|
+
if (typeof error === "object" && error !== null && "title" in error) {
|
|
638
|
+
const problem = error;
|
|
639
|
+
msg = String(problem.title);
|
|
640
|
+
if (problem.errors && typeof problem.errors === "object") {
|
|
641
|
+
const detail = Object.entries(problem.errors).flatMap(
|
|
642
|
+
([field, msgs]) => (Array.isArray(msgs) ? msgs : [msgs]).map((m) => ` ${field}: ${String(m)}`)
|
|
643
|
+
);
|
|
644
|
+
if (detail.length > 0) msg += `
|
|
645
|
+
${detail.join("\n")}`;
|
|
646
|
+
}
|
|
647
|
+
} else if (typeof error === "object" && error !== null) {
|
|
648
|
+
msg = JSON.stringify(error);
|
|
649
|
+
} else {
|
|
650
|
+
msg = String(error);
|
|
651
|
+
}
|
|
637
652
|
process.stderr.write(`error: ${msg}
|
|
638
653
|
`);
|
|
639
654
|
process.exit(1);
|
|
@@ -2551,6 +2566,9 @@ function registerClose(program2) {
|
|
|
2551
2566
|
).option(
|
|
2552
2567
|
"--no-status-flip",
|
|
2553
2568
|
"Skip the status flip on a BARE task. (Managed runs never flip here \u2014 the run engine reflects the verdict onto the task on resume.)"
|
|
2569
|
+
).option(
|
|
2570
|
+
"--to-version <n>",
|
|
2571
|
+
"Pin the Reference edge at this task version \u2014 the DISPATCHED version the executor worked against (D-continuity-2). Default: the task's current version (status flips are metadata edits that don't bump the version, so current == dispatched in the normal case; pass this when the task's content changed between dispatch and close)."
|
|
2554
2572
|
).option("--source <source>", "Source / lane stamp", "cli").addHelpText(
|
|
2555
2573
|
"after",
|
|
2556
2574
|
`
|
|
@@ -2584,6 +2602,7 @@ Examples:
|
|
|
2584
2602
|
);
|
|
2585
2603
|
const client = await makeClient(cfg);
|
|
2586
2604
|
let matchTags;
|
|
2605
|
+
let dispatchedVersion;
|
|
2587
2606
|
if (opts.decomposition) {
|
|
2588
2607
|
const run = await runApi(
|
|
2589
2608
|
"Reading run contract",
|
|
@@ -2601,6 +2620,8 @@ Examples:
|
|
|
2601
2620
|
`run ${opts.decomposition} is awaiting task ${run.awaitingTaskId}, not ${opts.task} \u2014 refusing to mis-key the resume.`
|
|
2602
2621
|
);
|
|
2603
2622
|
matchTags = await_.matchTags;
|
|
2623
|
+
if (typeof await_.dispatchedTaskVersion === "number")
|
|
2624
|
+
dispatchedVersion = await_.dispatchedTaskVersion;
|
|
2604
2625
|
} else {
|
|
2605
2626
|
matchTags = [`wlp-task:${opts.task}`];
|
|
2606
2627
|
}
|
|
@@ -2627,11 +2648,34 @@ Examples:
|
|
|
2627
2648
|
}
|
|
2628
2649
|
})
|
|
2629
2650
|
);
|
|
2651
|
+
let toVersion;
|
|
2652
|
+
if (opts.toVersion !== void 0) {
|
|
2653
|
+
toVersion = Number(opts.toVersion);
|
|
2654
|
+
if (!Number.isInteger(toVersion) || toVersion < 1)
|
|
2655
|
+
fail(
|
|
2656
|
+
`--to-version must be an integer >= 1 \u2014 got '${opts.toVersion}'`
|
|
2657
|
+
);
|
|
2658
|
+
} else if (dispatchedVersion !== void 0) {
|
|
2659
|
+
toVersion = dispatchedVersion;
|
|
2660
|
+
} else {
|
|
2661
|
+
const task = await runApi(
|
|
2662
|
+
"Reading task version",
|
|
2663
|
+
async () => client.GET("/memories/{memoryId}", {
|
|
2664
|
+
params: { path: { memoryId: opts.task } }
|
|
2665
|
+
})
|
|
2666
|
+
);
|
|
2667
|
+
const v = task?.item?.currentVersion ?? task?.currentVersion;
|
|
2668
|
+
if (typeof v !== "number" || v < 1)
|
|
2669
|
+
fail(
|
|
2670
|
+
`could not read task ${opts.task} version to pin the Reference edge \u2014 pass --to-version <n>`
|
|
2671
|
+
);
|
|
2672
|
+
toVersion = v;
|
|
2673
|
+
}
|
|
2630
2674
|
const edge = await runApi(
|
|
2631
2675
|
"Wiring Reference edge",
|
|
2632
2676
|
async () => client.POST("/memories/{memoryId}/relationships", {
|
|
2633
2677
|
params: { path: { memoryId: closeout.id } },
|
|
2634
|
-
body: { toMemoryId: opts.task, type: "Reference" }
|
|
2678
|
+
body: { toMemoryId: opts.task, type: "Reference", toVersion }
|
|
2635
2679
|
})
|
|
2636
2680
|
);
|
|
2637
2681
|
let taskStatus;
|
|
@@ -2851,12 +2895,12 @@ Examples:
|
|
|
2851
2895
|
$ sechroom decomposition reject sug_XXXX --reason "wrong shape"`
|
|
2852
2896
|
);
|
|
2853
2897
|
decomposition.command("decompose <briefId>").description(
|
|
2854
|
-
"Decompose a
|
|
2898
|
+
"Decompose a work brief into a candidate Task graph (POST /work-briefs/{id}/decompose)"
|
|
2855
2899
|
).action(async (briefId, _opts, cmd) => {
|
|
2856
2900
|
const cfg = resolveConfig(cmd.optsWithGlobals());
|
|
2857
2901
|
const data = await runApi("Queueing decomposition", async () => {
|
|
2858
2902
|
const client = await makeClient(cfg);
|
|
2859
|
-
return client.POST("/
|
|
2903
|
+
return client.POST("/work-briefs/{id}/decompose", {
|
|
2860
2904
|
params: { path: { id: briefId } },
|
|
2861
2905
|
body: { id: briefId }
|
|
2862
2906
|
});
|
|
@@ -5065,24 +5109,45 @@ Examples:
|
|
|
5065
5109
|
$ sechroom relationship suggestions --status Pending --memory mem_XXXX
|
|
5066
5110
|
$ sechroom relationship suggestion accept rsg_XXXX`
|
|
5067
5111
|
);
|
|
5068
|
-
relationship.command("create <fromMemoryId> <toMemoryId>").description("Create a relationship (POST /memories/{memoryId}/relationships)").option("--type <type>", "Relationship type (Reference, Related, Parent, Child, Follows, \u2026)", "Reference").
|
|
5112
|
+
relationship.command("create <fromMemoryId> <toMemoryId>").description("Create a relationship (POST /memories/{memoryId}/relationships)").option("--type <type>", "Relationship type (Reference, Related, Parent, Child, Follows, \u2026)", "Reference").option(
|
|
5113
|
+
"--to-version <number>",
|
|
5114
|
+
"Version of the target memory to pin the edge to (defaults to the target's current version)"
|
|
5115
|
+
).action(async (fromMemoryId, toMemoryId, opts, cmd) => {
|
|
5069
5116
|
const cfg = resolveConfig(cmd.optsWithGlobals());
|
|
5070
|
-
const
|
|
5071
|
-
|
|
5072
|
-
|
|
5117
|
+
const client = await makeClient(cfg);
|
|
5118
|
+
let toVersion;
|
|
5119
|
+
if (opts.toVersion !== void 0) {
|
|
5120
|
+
toVersion = Number(opts.toVersion);
|
|
5121
|
+
if (!Number.isInteger(toVersion) || toVersion < 1) {
|
|
5122
|
+
fail(`--to-version must be a positive integer (got '${opts.toVersion}').`);
|
|
5123
|
+
}
|
|
5124
|
+
} else {
|
|
5125
|
+
const target = await runApi(
|
|
5126
|
+
"Resolving target version",
|
|
5127
|
+
async () => client.GET("/memories/{memoryId}", { params: { path: { memoryId: toMemoryId } } })
|
|
5128
|
+
);
|
|
5129
|
+
if (typeof target.item?.currentVersion !== "number") {
|
|
5130
|
+
fail(`Could not resolve the current version of ${toMemoryId}; pass --to-version explicitly.`);
|
|
5131
|
+
}
|
|
5132
|
+
toVersion = target.item.currentVersion;
|
|
5133
|
+
}
|
|
5134
|
+
const data = await runApi(
|
|
5135
|
+
"Creating relationship",
|
|
5136
|
+
async () => client.POST("/memories/{memoryId}/relationships", {
|
|
5073
5137
|
params: { path: { memoryId: fromMemoryId } },
|
|
5074
5138
|
body: {
|
|
5075
5139
|
toMemoryId,
|
|
5076
|
-
type: opts.type
|
|
5140
|
+
type: opts.type,
|
|
5141
|
+
toVersion
|
|
5077
5142
|
}
|
|
5078
|
-
})
|
|
5079
|
-
|
|
5143
|
+
})
|
|
5144
|
+
);
|
|
5080
5145
|
const inversePart = data.inverseId ? ` ${style.dim(`(inverse ${data.inverseId})`)}` : "";
|
|
5081
5146
|
const view = resolveViewUrl(cfg.baseUrl, data.url);
|
|
5082
5147
|
const urlPart = view ? ` ${style.dim("\u2192")} ${view}` : "";
|
|
5083
5148
|
emitAction(
|
|
5084
|
-
`created relationship ${style.bold(data.id)} ${style.dim(`${fromMemoryId} \u2192 ${toMemoryId}`)}${inversePart}${urlPart}`,
|
|
5085
|
-
data,
|
|
5149
|
+
`created relationship ${style.bold(data.id)} ${style.dim(`${fromMemoryId} \u2192 ${toMemoryId} @v${toVersion}`)}${inversePart}${urlPart}`,
|
|
5150
|
+
{ ...data, toVersion },
|
|
5086
5151
|
cmd.optsWithGlobals().json
|
|
5087
5152
|
);
|
|
5088
5153
|
});
|
package/package.json
CHANGED