@sechroom/cli 2026.6.9 → 2026.6.10
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/README.md +1 -2
- package/dist/index.js +52 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -146,12 +146,11 @@ The CLI mirrors the sechroom MCP tool surface — every command is a thin wrappe
|
|
|
146
146
|
| `continuity` | snapshot-create / -get · snapshots · resume-me / resume-lane · changed-since · load-set · grant / revoke-grant |
|
|
147
147
|
| `id` | next / peek (FR-_/D-_ sequence allocation) |
|
|
148
148
|
| `account` | profile / set-profile · feed · reviews / review-get / review-accept · lookup-batch |
|
|
149
|
-
| `chat` | messages · replies · stop-tracking (Slack / Discord, via `--surface`) |
|
|
149
|
+
| `chat` | send · messages · replies · stop-tracking (Slack / Discord, via `--surface`) |
|
|
150
150
|
| `worklog` · `lookup` | append · resolve any id |
|
|
151
151
|
|
|
152
152
|
Notes on deliberate gaps (API-rooted, not CLI):
|
|
153
153
|
- **No `memory delete`** — the API exposes no hard DELETE; `memory archive` is the soft-delete path.
|
|
154
|
-
- **No `chat send`** — the unified `/chat/*` surface has no POST send endpoint yet, so the Slack/Discord *send* tools can't be wrapped. Reading works today; `send` lands once the route is added to the spec.
|
|
155
154
|
- **`memory revert`** needs `--text` + `--content` — the revert endpoint doesn't reconstruct a version's body from its number; pull them from `memory versions` / `memory get` first.
|
|
156
155
|
|
|
157
156
|
## Onboarding (`init` / `setup`)
|
package/dist/index.js
CHANGED
|
@@ -468,6 +468,12 @@ function emit(data, json) {
|
|
|
468
468
|
function publicUrl(url) {
|
|
469
469
|
return url.replace(/^https?:\/\/localhost:5012/, "https://sechroom.yi.ocd.codes");
|
|
470
470
|
}
|
|
471
|
+
function resolveViewUrl(baseUrl, url) {
|
|
472
|
+
if (!url) return void 0;
|
|
473
|
+
if (/^https?:\/\//i.test(url)) return publicUrl(url);
|
|
474
|
+
const origin = baseUrl.replace(/\/api\/?$/i, "").replace(/\/+$/, "");
|
|
475
|
+
return publicUrl(`${origin}${url.startsWith("/") ? url : `/${url}`}`);
|
|
476
|
+
}
|
|
471
477
|
function emitAction(summary, data, json) {
|
|
472
478
|
if (json) {
|
|
473
479
|
process.stdout.write(JSON.stringify(data) + "\n");
|
|
@@ -538,7 +544,8 @@ Examples:
|
|
|
538
544
|
});
|
|
539
545
|
});
|
|
540
546
|
const titlePart = opts.title ? ` ${style.dim(`"${opts.title}"`)}` : "";
|
|
541
|
-
const
|
|
547
|
+
const view = resolveViewUrl(cfg.baseUrl, data.url);
|
|
548
|
+
const urlPart = view ? ` ${style.dim("\u2192")} ${view}` : "";
|
|
542
549
|
emitAction(`created memory ${style.bold(data.id)}${titlePart}${urlPart}`, data, cmd.optsWithGlobals().json);
|
|
543
550
|
});
|
|
544
551
|
memory.command("get <memoryId>").description("Fetch a memory by id (GET /memories/{memoryId})").action(async (memoryId, _opts, cmd) => {
|
|
@@ -847,7 +854,8 @@ Examples:
|
|
|
847
854
|
});
|
|
848
855
|
});
|
|
849
856
|
const inversePart = data.inverseId ? ` ${style.dim(`(inverse ${data.inverseId})`)}` : "";
|
|
850
|
-
const
|
|
857
|
+
const view = resolveViewUrl(cfg.baseUrl, data.url);
|
|
858
|
+
const urlPart = view ? ` ${style.dim("\u2192")} ${view}` : "";
|
|
851
859
|
emitAction(
|
|
852
860
|
`created relationship ${style.bold(data.id)} ${style.dim(`${fromMemoryId} \u2192 ${toMemoryId}`)}${inversePart}${urlPart}`,
|
|
853
861
|
data,
|
|
@@ -997,7 +1005,8 @@ Examples:
|
|
|
997
1005
|
}
|
|
998
1006
|
});
|
|
999
1007
|
});
|
|
1000
|
-
const
|
|
1008
|
+
const view = resolveViewUrl(cfg.baseUrl, data.url);
|
|
1009
|
+
const urlPart = view ? ` ${style.dim("\u2192")} ${view}` : "";
|
|
1001
1010
|
emitAction(
|
|
1002
1011
|
`created workspace ${style.bold(data.id)} ${style.dim(`"${opts.name}"`)}${urlPart}`,
|
|
1003
1012
|
data,
|
|
@@ -1140,7 +1149,8 @@ Examples:
|
|
|
1140
1149
|
}
|
|
1141
1150
|
});
|
|
1142
1151
|
});
|
|
1143
|
-
const
|
|
1152
|
+
const view = resolveViewUrl(cfg.baseUrl, data.url);
|
|
1153
|
+
const urlPart = view ? ` ${style.dim("\u2192")} ${view}` : "";
|
|
1144
1154
|
emitAction(`created project ${style.bold(data.id)}${urlPart}`, data, cmd.optsWithGlobals().json);
|
|
1145
1155
|
});
|
|
1146
1156
|
project.command("list").description("List projects (GET /projects)").option("--workspace <workspaceId>", "Scope to a workspace").option("--status <status>", "Draft | Active | OnHold | Completed | Cancelled").option("--include-archived", "Include archived projects", false).action(async (opts, cmd) => {
|
|
@@ -1658,17 +1668,52 @@ Examples:
|
|
|
1658
1668
|
|
|
1659
1669
|
// src/commands/chat.ts
|
|
1660
1670
|
function registerChat(program2) {
|
|
1661
|
-
const chat = program2.command("chat").description("
|
|
1671
|
+
const chat = program2.command("chat").description("Send and read Slack / Discord channel messages").option("--surface <surface>", "slack | discord", "slack");
|
|
1662
1672
|
chat.addHelpText(
|
|
1663
1673
|
"after",
|
|
1664
1674
|
`
|
|
1665
1675
|
Examples:
|
|
1676
|
+
$ sechroom chat send C0123456789 "deploy is green" --surface slack
|
|
1677
|
+
$ sechroom chat send 987654321098765432 "deploy is green" --surface discord --guild 123456789012345678
|
|
1678
|
+
$ sechroom chat send C0123456789 "lgtm" --surface slack --as user --parent 1718049600.123456
|
|
1666
1679
|
$ sechroom chat messages --surface slack
|
|
1667
|
-
$ sechroom chat messages --surface discord --json
|
|
1668
1680
|
$ sechroom chat replies 1718049600.123456 --surface slack
|
|
1669
|
-
$ sechroom chat replies 1234567890123456789 --surface discord --json
|
|
1670
1681
|
$ sechroom chat stop-tracking 1718049600.123456 --surface slack`
|
|
1671
1682
|
);
|
|
1683
|
+
chat.command("send <channelId> <text>").description("Send a message to a channel (POST /chat/channel-messages/{surface})").option("--guild <guildId>", "Discord guild snowflake \u2014 required for --surface discord").option("--memory <memoryId>", "Attach a sechroom memory id").option("--no-track", "Don't capture replies to this message").option("--parent <parentMessage>", "Thread under a parent (Slack thread_ts / Discord message id)").option("--source <source>", "Source / lane stamp (renders an attribution footer)", "cli").option("--as <as>", "Slack only: 'bot' (default) or 'user' (your linked Slack identity)", "bot").action(async (channelId, text, opts, cmd) => {
|
|
1684
|
+
const { surface, ...globals } = cmd.optsWithGlobals();
|
|
1685
|
+
const json = Boolean(cmd.optsWithGlobals().json);
|
|
1686
|
+
const cfg = resolveConfig(globals);
|
|
1687
|
+
const data = await runApi("Sending message", async () => {
|
|
1688
|
+
const client = await makeClient(cfg);
|
|
1689
|
+
return client.POST("/chat/channel-messages/{surface}", {
|
|
1690
|
+
params: { path: { surface: String(surface) } },
|
|
1691
|
+
body: {
|
|
1692
|
+
channelId,
|
|
1693
|
+
text,
|
|
1694
|
+
guildId: opts.guild ?? null,
|
|
1695
|
+
attachedMemoryId: opts.memory ?? null,
|
|
1696
|
+
trackReplies: opts.track,
|
|
1697
|
+
parentMessage: opts.parent ?? null,
|
|
1698
|
+
source: opts.source,
|
|
1699
|
+
as: opts.as
|
|
1700
|
+
}
|
|
1701
|
+
});
|
|
1702
|
+
});
|
|
1703
|
+
if (!data.ok) {
|
|
1704
|
+
if (json) {
|
|
1705
|
+
emit(data, true);
|
|
1706
|
+
} else {
|
|
1707
|
+
process.stderr.write(
|
|
1708
|
+
`${err("\u2717")} send failed: ${data.upstreamError ?? "error"}${data.errorDescription ? ` \u2014 ${data.errorDescription}` : ""}
|
|
1709
|
+
`
|
|
1710
|
+
);
|
|
1711
|
+
}
|
|
1712
|
+
process.exit(1);
|
|
1713
|
+
}
|
|
1714
|
+
const idPart = data.persistedId ? ` ${style.dim(`(${data.persistedId})`)}` : "";
|
|
1715
|
+
emitAction(`sent to ${surface} ${style.bold(channelId)}${idPart}`, data, json);
|
|
1716
|
+
});
|
|
1672
1717
|
chat.command("messages").description("List recent channel messages (GET /chat/channel-messages/{surface})").action(async (_opts, cmd) => {
|
|
1673
1718
|
const { surface, ...globals } = cmd.optsWithGlobals();
|
|
1674
1719
|
const cfg = resolveConfig(globals);
|
package/package.json
CHANGED