@bli-cockpit/cli 0.2.261 → 0.2.262
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/commands/local-args.js +3 -1
- package/dist/commands/local-help-commands-tower.js +7 -1
- package/dist/commands/public-root.js +1 -1
- package/dist/commands/slack-privacy-args.js +28 -0
- package/dist/commands/slack-privacy.js +31 -0
- package/dist/commands/slack.js +3 -0
- package/package.json +2 -2
|
@@ -19,6 +19,7 @@ import { parseGlossaryArgs } from "./glossary.js";
|
|
|
19
19
|
import { parseSpendArgs } from "./spend.js";
|
|
20
20
|
import { parsePushArgs } from "./push.js";
|
|
21
21
|
import { parseRootsArgs } from "./roots.js";
|
|
22
|
+
import { parseSlackPrivacyArgs } from "./slack-privacy-args.js";
|
|
22
23
|
import { parseMilestoneArgs } from "./local-args-tower-milestone.js";
|
|
23
24
|
import { SURFACE_ALIASES } from "./local-help.js";
|
|
24
25
|
import { parseAgentRulesArgs, parseAnalyzeArgs, parseAutostartArgs, parseBackfillArgs, parseCleanArgs, parseDoctorArgs, parseInstallArgs, parseLoginArgs, parseMemoryArgs, parseLogoutArgs, parseOnboardArgs, parseReleaseArgs, parseServeArgs, parseSessionsArgs, parseSourcesArgs, parseStartArgs, parseStatusArgs, parseSyncArgs, parseUpdateArgs, } from "./local-args-collector.js";
|
|
@@ -67,7 +68,8 @@ const COMMAND_PARSERS = new Map([
|
|
|
67
68
|
["ci", (_command, rest) => parseCiArgs(rest)],
|
|
68
69
|
["delivery", (_command, rest) => parseDeliveryArgs(rest)],
|
|
69
70
|
["ops", (_command, rest) => parseOpsArgs(rest)],
|
|
70
|
-
|
|
71
|
+
// BLI-23244: `slack privacy` has its own flags and its own file.
|
|
72
|
+
["slack", (_command, rest) => (rest.includes("privacy") ? parseSlackPrivacyArgs(rest.filter((arg) => arg !== "privacy")) : parseSlackArgs(rest))],
|
|
71
73
|
["settings", (_command, rest) => parseSettingsArgs(rest)],
|
|
72
74
|
["team", (_command, rest) => parseTeamArgs(rest)],
|
|
73
75
|
["workbook", (_command, rest) => parseWorkbookArgs(rest)],
|
|
@@ -304,7 +304,13 @@ export const TOWER_COMMAND_HELP = [
|
|
|
304
304
|
[
|
|
305
305
|
"slack",
|
|
306
306
|
[
|
|
307
|
-
"Usage: cockpit slack [connect [--workspace bli|blue_pearl] | disconnect --workspace bli|blue_pearl | coverage [--workspace bli|blue_pearl] [--stale-only] [--list] | read [filters] [--format compact|full]] [--json]",
|
|
307
|
+
"Usage: cockpit slack [connect [--workspace bli|blue_pearl] | disconnect --workspace bli|blue_pearl | coverage [--workspace bli|blue_pearl] [--stale-only] [--list] | read [filters] [--format compact|full] | privacy] [--json]",
|
|
308
|
+
"",
|
|
309
|
+
" cockpit slack privacy (founders only)",
|
|
310
|
+
" Lists which Slack conversations Tower keeps out and lets in, and the founders' Slack ids.",
|
|
311
|
+
" A DM or group DM that includes a founder, and any channel a founder excludes, never enters",
|
|
312
|
+
" Tower unless a founder lets it in. Ids only (C…, D…, G…), never names. Changing a list needs",
|
|
313
|
+
" a signed-in browser session (ticket 23265), never this machine's token. Anyone else: owner_only.",
|
|
308
314
|
"",
|
|
309
315
|
" cockpit slack coverage",
|
|
310
316
|
" What Cockpit's Slack bot can see: how many channels it is in, what each",
|
|
@@ -21,7 +21,7 @@ export async function runCockpitCli(argv, io) {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
if (command === "--version" || command === "-V" || command === "version") {
|
|
24
|
-
writeLine(io?.stdout ?? process.stdout, "0.2.
|
|
24
|
+
writeLine(io?.stdout ?? process.stdout, "0.2.262");
|
|
25
25
|
return 0;
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cockpit slack privacy` arguments (BLI-23244): a founder LISTS their Slack privacy lists (which conversations Tower
|
|
3
|
+
* keeps out or lets in, and the founders' Slack identities). Ids only, never names.
|
|
4
|
+
*
|
|
5
|
+
* Read-only on purpose. Changing a list needs a signed-in browser session, so that an agent holding a founder's device
|
|
6
|
+
* token can never opt a founder's conversation in; the server refuses device-token writes. The browser card is
|
|
7
|
+
* ticket 23265. Split from `local-args-tower-admin.ts`, which is at this repo's readability band.
|
|
8
|
+
*/
|
|
9
|
+
import { optionalNonEmpty, optionalUrl, parseNamedArgs } from "./local-arg-values.js";
|
|
10
|
+
const VALUE_FLAGS = ["--home", "--dashboard-url"];
|
|
11
|
+
const WRITE_FLAGS = ["--exclude", "--optin", "--remove", "--identity", "--no-account"];
|
|
12
|
+
const ALLOWED_FLAGS = [...VALUE_FLAGS, "--json"];
|
|
13
|
+
export const SLACK_PRIVACY_WRITE_REFUSAL = "slack privacy only lists. Changing a founder privacy list needs a signed-in browser session, so an agent holding this machine's token can never opt a founder's conversation in (the Settings card is ticket 23265).";
|
|
14
|
+
export function parseSlackPrivacyArgs(args) {
|
|
15
|
+
if (args.some((arg) => WRITE_FLAGS.includes(arg)))
|
|
16
|
+
throw new Error(SLACK_PRIVACY_WRITE_REFUSAL);
|
|
17
|
+
const values = parseNamedArgs(args, { allowedFlags: ALLOWED_FLAGS, valueFlags: VALUE_FLAGS });
|
|
18
|
+
if (values.positionals.length > 0)
|
|
19
|
+
throw new Error("slack privacy takes no arguments; it lists the founder privacy lists.");
|
|
20
|
+
return {
|
|
21
|
+
kind: "slack",
|
|
22
|
+
action: "privacy",
|
|
23
|
+
privacy: { op: "list" },
|
|
24
|
+
homeDir: optionalNonEmpty(values.flags.get("--home")),
|
|
25
|
+
dashboardUrl: optionalUrl(values.flags.get("--dashboard-url")),
|
|
26
|
+
json: values.booleans.has("--json"),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { writeLine } from "./cli-io.js";
|
|
2
|
+
import { asRecord, callTower, openTower, writeCommandFailure } from "./tower-command.js";
|
|
3
|
+
export async function runSlackPrivacy(command, io) {
|
|
4
|
+
const tower = await openTower("slack", command, io);
|
|
5
|
+
const result = await callTower(tower, { path: "/api/slack/founder-privacy", label: "slack-privacy" });
|
|
6
|
+
if (!result.ok)
|
|
7
|
+
return writeCommandFailure(io, command.json, result);
|
|
8
|
+
writeLine(io.stderr, `[slack cli] privacy answered ${JSON.stringify({ op: "list", reason: "ok" })}`);
|
|
9
|
+
const body = asRecord(result.body);
|
|
10
|
+
if (command.json) {
|
|
11
|
+
writeLine(io.stdout, JSON.stringify(body));
|
|
12
|
+
return 0;
|
|
13
|
+
}
|
|
14
|
+
for (const line of describe(body))
|
|
15
|
+
writeLine(io.stdout, line);
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
18
|
+
/** Plain lines for a person. Exported for its test. */
|
|
19
|
+
export function describe(body) {
|
|
20
|
+
const rows = (key) => (Array.isArray(body[key]) ? body[key] : []);
|
|
21
|
+
const mark = (row) => ` ${String(row["conversationId"])} (${String(row["workspace"])}) since ${String(row["addedAt"]).slice(0, 10)}${row["addedByYou"] ? " — you" : " — the other founder"}`;
|
|
22
|
+
const identities = rows("identities");
|
|
23
|
+
return [
|
|
24
|
+
`Kept out (${rows("exclusions").length}):`, ...rows("exclusions").map(mark),
|
|
25
|
+
`Let in (${rows("optins").length}):`, ...rows("optins").map(mark),
|
|
26
|
+
`Founder Slack ids stated (${identities.length}):`,
|
|
27
|
+
...identities.map((row) => ` ${String(row["workspace"])}: ${row["slackUserId"] ? String(row["slackUserId"]) : "no account"}${row["yours"] ? " — you" : ""}`),
|
|
28
|
+
"Any DM or group DM that includes a founder is kept out unless it is on the let-in list.",
|
|
29
|
+
"To change a list, use Tower in the browser (ticket 23265); this command only lists.",
|
|
30
|
+
];
|
|
31
|
+
}
|
package/dist/commands/slack.js
CHANGED
|
@@ -22,7 +22,10 @@
|
|
|
22
22
|
*/
|
|
23
23
|
import { colorEnabled, dim, writeLine } from "./cli-io.js";
|
|
24
24
|
import { asRecord, callTower, openTower, writeCommandFailure } from "./tower-command.js";
|
|
25
|
+
import { runSlackPrivacy } from "./slack-privacy.js";
|
|
25
26
|
export async function runSlack(command, io) {
|
|
27
|
+
if (command.action === "privacy")
|
|
28
|
+
return runSlackPrivacy(command, io);
|
|
26
29
|
const tower = await openTower("slack", command, io);
|
|
27
30
|
if (command.action === "connect" || command.action === "disconnect") {
|
|
28
31
|
const result = await callTower(tower, { path: `/api/slack/connections${command.action === "disconnect" ? `?workspace=${command.workspace}` : ""}`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bli-cockpit/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.262",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@bli-cockpit/memory-mcp": "0.1.77",
|
|
31
|
-
"@bli-cockpit/mcp": "0.1.
|
|
31
|
+
"@bli-cockpit/mcp": "0.1.161",
|
|
32
32
|
"@bli-cockpit/telemetry-core": "0.1.84"
|
|
33
33
|
},
|
|
34
34
|
"repository": {
|