@sechroom/cli 2026.7.25 → 2026.7.27
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 +126 -37
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1031,7 +1031,7 @@ async function resolveInstruction(cfg, section, personalWorkspaceId) {
|
|
|
1031
1031
|
const { data } = await client.POST("/memories/search", {
|
|
1032
1032
|
body: { query: null, textQuery: null, semanticQuery: null, hybrid: false, limit: 1, includeArchived: false, includeSystem: false, tags }
|
|
1033
1033
|
});
|
|
1034
|
-
const hits = data ?? [];
|
|
1034
|
+
const hits = data?.items ?? [];
|
|
1035
1035
|
if (hits.length === 0) continue;
|
|
1036
1036
|
const templateId = hits[0].id;
|
|
1037
1037
|
const template = await fetchMemoryFields(cfg, templateId);
|
|
@@ -1041,7 +1041,7 @@ async function resolveInstruction(cfg, section, personalWorkspaceId) {
|
|
|
1041
1041
|
const { data: ovr } = await client.POST("/memories/search", {
|
|
1042
1042
|
body: { query: null, textQuery: null, semanticQuery: null, hybrid: false, limit: 1, includeArchived: false, includeSystem: false, tags: ["sechroom:role:override", `sechroom:template-ref:${templateId}`], owner: { type: "Workspace", id: personalWorkspaceId } }
|
|
1043
1043
|
});
|
|
1044
|
-
const ovrHits = ovr ?? [];
|
|
1044
|
+
const ovrHits = ovr?.items ?? [];
|
|
1045
1045
|
if (ovrHits.length > 0) {
|
|
1046
1046
|
const override = await fetchMemoryFields(cfg, ovrHits[0].id);
|
|
1047
1047
|
if (typeof override?.text === "string" && override.text.length > 0) {
|
|
@@ -3556,29 +3556,29 @@ Examples:
|
|
|
3556
3556
|
});
|
|
3557
3557
|
}
|
|
3558
3558
|
|
|
3559
|
-
// src/commands/
|
|
3559
|
+
// src/commands/work-plan.ts
|
|
3560
3560
|
import { readFile } from "fs/promises";
|
|
3561
|
-
function
|
|
3562
|
-
const
|
|
3563
|
-
"Drive a
|
|
3561
|
+
function registerWorkPlan(program2) {
|
|
3562
|
+
const workPlan = program2.command("work-plan").description(
|
|
3563
|
+
"Drive a work plan: create one from a brief, then execute / accept / reject"
|
|
3564
3564
|
);
|
|
3565
|
-
|
|
3565
|
+
workPlan.addHelpText(
|
|
3566
3566
|
"after",
|
|
3567
3567
|
`
|
|
3568
3568
|
Examples:
|
|
3569
|
-
$ sechroom
|
|
3570
|
-
$ sechroom
|
|
3571
|
-
$ sechroom
|
|
3572
|
-
$ sechroom
|
|
3573
|
-
$ sechroom
|
|
3574
|
-
$ sechroom
|
|
3575
|
-
$ sechroom
|
|
3569
|
+
$ sechroom work-plan create mem_XXXX
|
|
3570
|
+
$ sechroom work-plan create-from-tasks mem_XXXX --file plan.json
|
|
3571
|
+
$ sechroom work-plan get-plan wlp_XXXX
|
|
3572
|
+
$ sechroom work-plan execute wlp_XXXX
|
|
3573
|
+
$ sechroom work-plan publish-context-pack wlp_XXXX
|
|
3574
|
+
$ sechroom work-plan accept wlp_XXXX
|
|
3575
|
+
$ sechroom work-plan reject wlp_XXXX --reason "wrong shape"`
|
|
3576
3576
|
);
|
|
3577
|
-
|
|
3578
|
-
"
|
|
3577
|
+
workPlan.command("create <briefId>").description(
|
|
3578
|
+
"Create a work plan from a work brief \u2014 a candidate Task graph (POST /work-briefs/{id}/decompose)"
|
|
3579
3579
|
).action(async (briefId, _opts, cmd) => {
|
|
3580
3580
|
const cfg = resolveConfig(cmd.optsWithGlobals());
|
|
3581
|
-
const data = await runApi("
|
|
3581
|
+
const data = await runApi("Creating work plan", async () => {
|
|
3582
3582
|
const client = await makeClient(cfg);
|
|
3583
3583
|
return client.POST("/work-briefs/{id}/decompose", {
|
|
3584
3584
|
params: { path: { id: briefId } },
|
|
@@ -3586,13 +3586,13 @@ Examples:
|
|
|
3586
3586
|
});
|
|
3587
3587
|
});
|
|
3588
3588
|
emitAction(
|
|
3589
|
-
`
|
|
3589
|
+
`created work plan from ${style.bold(briefId)} \u2192 ${style.bold(data.suggestionId)}`,
|
|
3590
3590
|
data,
|
|
3591
3591
|
cmd.optsWithGlobals().json
|
|
3592
3592
|
);
|
|
3593
3593
|
});
|
|
3594
|
-
|
|
3595
|
-
"Create a
|
|
3594
|
+
workPlan.command("create-from-tasks <briefId>").description(
|
|
3595
|
+
"Create a work plan from a hand-authored JSON task list; tasks may carry Unix-millisecond wakeAtMs"
|
|
3596
3596
|
).requiredOption(
|
|
3597
3597
|
"--file <path>",
|
|
3598
3598
|
"JSON file containing { project, tasks, source? }; use - for stdin"
|
|
@@ -3601,7 +3601,7 @@ Examples:
|
|
|
3601
3601
|
const body = parsePlanInput(raw, opts.file);
|
|
3602
3602
|
const cfg = resolveConfig(cmd.optsWithGlobals());
|
|
3603
3603
|
const data = await runApi(
|
|
3604
|
-
"Creating
|
|
3604
|
+
"Creating work plan from tasks",
|
|
3605
3605
|
async () => {
|
|
3606
3606
|
const client = await makeClient(cfg);
|
|
3607
3607
|
return client.POST("/work-briefs/{id}/decompose-from-plan", {
|
|
@@ -3616,11 +3616,11 @@ Examples:
|
|
|
3616
3616
|
cmd.optsWithGlobals().json
|
|
3617
3617
|
);
|
|
3618
3618
|
});
|
|
3619
|
-
|
|
3619
|
+
workPlan.command("get-plan <decompositionId>").description(
|
|
3620
3620
|
"Inspect the compiled plan, including each scheduled step's Unix-millisecond wakeAtMs"
|
|
3621
3621
|
).action(async (decompositionId, _opts, cmd) => {
|
|
3622
3622
|
const cfg = resolveConfig(cmd.optsWithGlobals());
|
|
3623
|
-
const data = await runApi("Reading
|
|
3623
|
+
const data = await runApi("Reading work plan", async () => {
|
|
3624
3624
|
const client = await makeClient(cfg);
|
|
3625
3625
|
return client.GET("/decompositions/{id}/plan", {
|
|
3626
3626
|
params: { path: { id: decompositionId } }
|
|
@@ -3632,11 +3632,11 @@ Examples:
|
|
|
3632
3632
|
cmd.optsWithGlobals().json
|
|
3633
3633
|
);
|
|
3634
3634
|
});
|
|
3635
|
-
|
|
3636
|
-
"Execute a
|
|
3635
|
+
workPlan.command("execute <decompositionId>").description(
|
|
3636
|
+
"Execute a work plan's Task graph (POST /decompositions/{id}/execute)"
|
|
3637
3637
|
).action(async (decompositionId, _opts, cmd) => {
|
|
3638
3638
|
const cfg = resolveConfig(cmd.optsWithGlobals());
|
|
3639
|
-
const data = await runApi("Executing
|
|
3639
|
+
const data = await runApi("Executing work plan", async () => {
|
|
3640
3640
|
const client = await makeClient(cfg);
|
|
3641
3641
|
return client.POST("/decompositions/{id}/execute", {
|
|
3642
3642
|
params: { path: { id: decompositionId } },
|
|
@@ -3649,8 +3649,8 @@ Examples:
|
|
|
3649
3649
|
cmd.optsWithGlobals().json
|
|
3650
3650
|
);
|
|
3651
3651
|
});
|
|
3652
|
-
|
|
3653
|
-
"Publish an accepted
|
|
3652
|
+
workPlan.command("publish-context-pack <decompositionId>").description(
|
|
3653
|
+
"Publish an accepted work plan's context pack on demand (POST /decompositions/{id}/publish-run)"
|
|
3654
3654
|
).action(async (decompositionId, _opts, cmd) => {
|
|
3655
3655
|
const cfg = resolveConfig(cmd.optsWithGlobals());
|
|
3656
3656
|
const data = await runApi("Publishing context pack", async () => {
|
|
@@ -3666,11 +3666,11 @@ Examples:
|
|
|
3666
3666
|
cmd.optsWithGlobals().json
|
|
3667
3667
|
);
|
|
3668
3668
|
});
|
|
3669
|
-
|
|
3670
|
-
"Accept a Pending
|
|
3669
|
+
workPlan.command("accept <decompositionId>").description(
|
|
3670
|
+
"Accept a Pending work plan \u2014 promote + ratify its Tasks (POST /decompositions/{id}/accept)"
|
|
3671
3671
|
).action(async (decompositionId, _opts, cmd) => {
|
|
3672
3672
|
const cfg = resolveConfig(cmd.optsWithGlobals());
|
|
3673
|
-
const data = await runApi("Accepting
|
|
3673
|
+
const data = await runApi("Accepting work plan", async () => {
|
|
3674
3674
|
const client = await makeClient(cfg);
|
|
3675
3675
|
return client.POST("/decompositions/{id}/accept", {
|
|
3676
3676
|
params: { path: { id: decompositionId } },
|
|
@@ -3678,16 +3678,16 @@ Examples:
|
|
|
3678
3678
|
});
|
|
3679
3679
|
});
|
|
3680
3680
|
emitAction(
|
|
3681
|
-
`accepted
|
|
3681
|
+
`accepted work plan ${style.bold(decompositionId)}`,
|
|
3682
3682
|
data,
|
|
3683
3683
|
cmd.optsWithGlobals().json
|
|
3684
3684
|
);
|
|
3685
3685
|
});
|
|
3686
|
-
|
|
3687
|
-
"Reject a Pending
|
|
3686
|
+
workPlan.command("reject <decompositionId>").description(
|
|
3687
|
+
"Reject a Pending work plan \u2014 archive its Tasks, bounce the brief (POST /decompositions/{id}/reject)"
|
|
3688
3688
|
).option("--reason <reason>", "Optional free-text rejection reason").action(async (decompositionId, opts, cmd) => {
|
|
3689
3689
|
const cfg = resolveConfig(cmd.optsWithGlobals());
|
|
3690
|
-
const data = await runApi("Rejecting
|
|
3690
|
+
const data = await runApi("Rejecting work plan", async () => {
|
|
3691
3691
|
const client = await makeClient(cfg);
|
|
3692
3692
|
return client.POST("/decompositions/{id}/reject", {
|
|
3693
3693
|
params: { path: { id: decompositionId } },
|
|
@@ -3695,7 +3695,7 @@ Examples:
|
|
|
3695
3695
|
});
|
|
3696
3696
|
});
|
|
3697
3697
|
emitAction(
|
|
3698
|
-
`rejected
|
|
3698
|
+
`rejected work plan ${style.bold(decompositionId)}`,
|
|
3699
3699
|
data,
|
|
3700
3700
|
cmd.optsWithGlobals().json
|
|
3701
3701
|
);
|
|
@@ -6511,6 +6511,23 @@ function registerTelemetry(program2) {
|
|
|
6511
6511
|
);
|
|
6512
6512
|
}
|
|
6513
6513
|
});
|
|
6514
|
+
telemetry.command("show <decompositionId>").description(
|
|
6515
|
+
"Read a run's telemetry \u2014 per-task meters + the raw/parsed/approval/terminal timeline (GET /decompositions/{id}/run/telemetry). Returns hasTelemetry:false, not an error, before any event is ingested \u2014 so an unstarted run and a stalled one read differently. The read side of this group; `emit` is the source side. (FR-sechroom-442 slice 1 step 4; mirrors the work_plan_run_telemetry MCP tool.)"
|
|
6516
|
+
).action(async (decompositionId, _opts, cmd) => {
|
|
6517
|
+
const globals = cmd.optsWithGlobals();
|
|
6518
|
+
const cfg = resolveConfig(globals);
|
|
6519
|
+
const data = await runApi("Reading run telemetry", async () => {
|
|
6520
|
+
const client = await makeClient(cfg);
|
|
6521
|
+
return client.GET("/decompositions/{id}/run/telemetry", {
|
|
6522
|
+
params: { path: { id: decompositionId } }
|
|
6523
|
+
});
|
|
6524
|
+
});
|
|
6525
|
+
emitAction(
|
|
6526
|
+
data.hasTelemetry ? `read telemetry for ${style.bold(decompositionId)}` : `no telemetry yet for ${style.bold(decompositionId)} (run not started or not yet reporting)`,
|
|
6527
|
+
data,
|
|
6528
|
+
globals.json
|
|
6529
|
+
);
|
|
6530
|
+
});
|
|
6514
6531
|
telemetry.command("bind").description(
|
|
6515
6532
|
"Bind this checkout to a decomposition+task so the Stop hook auto-emits per-turn telemetry"
|
|
6516
6533
|
).requiredOption(
|
|
@@ -7025,6 +7042,77 @@ function capitalize(value) {
|
|
|
7025
7042
|
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
7026
7043
|
}
|
|
7027
7044
|
|
|
7045
|
+
// src/commands/work-task.ts
|
|
7046
|
+
function registerWorkTask(program2) {
|
|
7047
|
+
const workTask = program2.command("work-task").description("Read work tasks and close them out (list \xB7 card \xB7 mark-no-residue)");
|
|
7048
|
+
workTask.addHelpText(
|
|
7049
|
+
"after",
|
|
7050
|
+
`
|
|
7051
|
+
Examples:
|
|
7052
|
+
$ sechroom work-task list --status in-progress --lane claude-code-chris
|
|
7053
|
+
$ sechroom work-task card mem_XXXX
|
|
7054
|
+
$ sechroom work-task mark-no-residue mem_XXXX --decomposition wlp_XXXX`
|
|
7055
|
+
);
|
|
7056
|
+
workTask.command("list").description("List work tasks, newest-first (GET /work-tasks)").option("--shape <shape>", "Filter: bare | managed").option("--lane <lane>", "Filter by dispatch-lane value, e.g. claude-code-chris").option("--status <status>", "Filter by status value, e.g. in-progress").option("--page <n>", "1-based page number", (v) => Number.parseInt(v, 10)).option(
|
|
7057
|
+
"--page-size <n>",
|
|
7058
|
+
"Page size (default 50, capped 200)",
|
|
7059
|
+
(v) => Number.parseInt(v, 10)
|
|
7060
|
+
).action(async (opts, cmd) => {
|
|
7061
|
+
const globals = cmd.optsWithGlobals();
|
|
7062
|
+
const cfg = resolveConfig(globals);
|
|
7063
|
+
const data = await runApi("Listing work tasks", async () => {
|
|
7064
|
+
const client = await makeClient(cfg);
|
|
7065
|
+
return client.GET("/work-tasks", {
|
|
7066
|
+
params: {
|
|
7067
|
+
query: {
|
|
7068
|
+
shape: opts.shape,
|
|
7069
|
+
lane: opts.lane,
|
|
7070
|
+
status: opts.status,
|
|
7071
|
+
page: opts.page,
|
|
7072
|
+
pageSize: opts.pageSize
|
|
7073
|
+
}
|
|
7074
|
+
}
|
|
7075
|
+
});
|
|
7076
|
+
});
|
|
7077
|
+
emitAction(
|
|
7078
|
+
`listed ${style.bold(String(data.items.length))} of ${data.count} task(s)`,
|
|
7079
|
+
data,
|
|
7080
|
+
globals.json
|
|
7081
|
+
);
|
|
7082
|
+
});
|
|
7083
|
+
workTask.command("card <taskId>").description("Read one task's runnable card \u2014 its full working instructions (GET /tasks/{id}/card)").action(async (taskId, _opts, cmd) => {
|
|
7084
|
+
const globals = cmd.optsWithGlobals();
|
|
7085
|
+
const cfg = resolveConfig(globals);
|
|
7086
|
+
const data = await runApi("Reading task card", async () => {
|
|
7087
|
+
const client = await makeClient(cfg);
|
|
7088
|
+
return client.GET("/tasks/{id}/card", {
|
|
7089
|
+
params: { path: { id: taskId } }
|
|
7090
|
+
});
|
|
7091
|
+
});
|
|
7092
|
+
emitAction(`read card ${style.bold(taskId)}`, data, globals.json);
|
|
7093
|
+
});
|
|
7094
|
+
workTask.command("mark-no-residue <taskId>").description(
|
|
7095
|
+
"Mark a task as having produced no residue \u2014 the explicit no-residue marker that lets a lane finish a run it drove end-to-end (POST /work-tasks/mark-no-residue)"
|
|
7096
|
+
).requiredOption(
|
|
7097
|
+
"--decomposition <id>",
|
|
7098
|
+
"The work plan id (wlp_\u2026) the task belongs to \u2014 the marker is keyed (decompositionId, taskId)"
|
|
7099
|
+
).action(async (taskId, opts, cmd) => {
|
|
7100
|
+
const globals = cmd.optsWithGlobals();
|
|
7101
|
+
const cfg = resolveConfig(globals);
|
|
7102
|
+
const data = await runApi("Marking task no-residue", async () => {
|
|
7103
|
+
const client = await makeClient(cfg);
|
|
7104
|
+
return client.POST("/work-tasks/mark-no-residue", {
|
|
7105
|
+
body: { taskId, decompositionId: opts.decomposition }
|
|
7106
|
+
});
|
|
7107
|
+
});
|
|
7108
|
+
emitAction(
|
|
7109
|
+
`marked ${style.bold(taskId)} no-residue (minted: ${data.minted})`,
|
|
7110
|
+
data,
|
|
7111
|
+
globals.json
|
|
7112
|
+
);
|
|
7113
|
+
});
|
|
7114
|
+
}
|
|
7115
|
+
|
|
7028
7116
|
// src/index.ts
|
|
7029
7117
|
function resolveVersion() {
|
|
7030
7118
|
try {
|
|
@@ -7188,7 +7276,8 @@ registerRelationships(program);
|
|
|
7188
7276
|
registerWorkspace(program);
|
|
7189
7277
|
registerProject(program);
|
|
7190
7278
|
registerWorkBrief(program);
|
|
7191
|
-
|
|
7279
|
+
registerWorkTask(program);
|
|
7280
|
+
registerWorkPlan(program);
|
|
7192
7281
|
registerExecutor(program);
|
|
7193
7282
|
registerClose(program);
|
|
7194
7283
|
registerFiling(program);
|
package/package.json
CHANGED