@sechroom/cli 2026.6.29-rc.692f8a8f → 2026.6.30-rc.3b1b16ff
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 +194 -32
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -16,6 +16,8 @@ import { mkdirSync, readFileSync, writeFileSync, existsSync, rmSync } from "fs";
|
|
|
16
16
|
var CONFIG_DIR = join(homedir(), ".config", "sechroom");
|
|
17
17
|
var CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
18
18
|
var TOKEN_FILE = join(CONFIG_DIR, "token.json");
|
|
19
|
+
var ACCOUNTS_FILE = join(CONFIG_DIR, "accounts.json");
|
|
20
|
+
var DEFAULT_ACCOUNT = "default";
|
|
19
21
|
var STATE_DIR_NAME = ".sechroom";
|
|
20
22
|
var BASELINE_CONFIG_NAME = ".sechroom.json";
|
|
21
23
|
var OVERRIDE_CONFIG_NAME = join(STATE_DIR_NAME, "config.json");
|
|
@@ -44,23 +46,87 @@ function writeDcrClientId(baseUrl, clientId) {
|
|
|
44
46
|
const p = readPersisted();
|
|
45
47
|
writePersisted({ clientIds: { ...p.clientIds ?? {}, [baseUrl]: clientId } });
|
|
46
48
|
}
|
|
47
|
-
function
|
|
48
|
-
const envTok = process.env.SECHROOM_TOKEN;
|
|
49
|
-
if (envTok) return { accessToken: envTok };
|
|
49
|
+
function readAccountsFile() {
|
|
50
50
|
try {
|
|
51
|
-
|
|
51
|
+
const parsed = JSON.parse(readFileSync(ACCOUNTS_FILE, "utf8"));
|
|
52
|
+
if (parsed && typeof parsed === "object" && parsed.accounts) return parsed;
|
|
53
|
+
} catch {
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
const legacy = JSON.parse(readFileSync(TOKEN_FILE, "utf8"));
|
|
57
|
+
if (legacy?.accessToken) {
|
|
58
|
+
const migrated = {
|
|
59
|
+
accounts: {
|
|
60
|
+
[DEFAULT_ACCOUNT]: { ...legacy, baseUrl: readPersisted().baseUrl ?? DEFAULT_BASE_URL }
|
|
61
|
+
},
|
|
62
|
+
default: DEFAULT_ACCOUNT
|
|
63
|
+
};
|
|
64
|
+
writeAccountsFile(migrated);
|
|
65
|
+
rmSync(TOKEN_FILE, { force: true });
|
|
66
|
+
return migrated;
|
|
67
|
+
}
|
|
52
68
|
} catch {
|
|
53
|
-
return null;
|
|
54
69
|
}
|
|
70
|
+
return { accounts: {} };
|
|
55
71
|
}
|
|
56
|
-
function
|
|
72
|
+
function writeAccountsFile(file) {
|
|
57
73
|
ensureDir();
|
|
58
|
-
writeFileSync(
|
|
74
|
+
writeFileSync(ACCOUNTS_FILE, JSON.stringify(file, null, 2), { mode: 384 });
|
|
75
|
+
}
|
|
76
|
+
function readAccount(alias) {
|
|
77
|
+
return readAccountsFile().accounts[alias] ?? null;
|
|
78
|
+
}
|
|
79
|
+
function writeAccount(alias, entry) {
|
|
80
|
+
const file = readAccountsFile();
|
|
81
|
+
file.accounts[alias] = entry;
|
|
82
|
+
if (!file.default) file.default = alias;
|
|
83
|
+
writeAccountsFile(file);
|
|
84
|
+
}
|
|
85
|
+
function removeAccount(alias) {
|
|
86
|
+
const file = readAccountsFile();
|
|
87
|
+
if (!(alias in file.accounts)) return false;
|
|
88
|
+
delete file.accounts[alias];
|
|
89
|
+
if (file.default === alias) file.default = Object.keys(file.accounts)[0];
|
|
90
|
+
writeAccountsFile(file);
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
function listAccounts() {
|
|
94
|
+
const file = readAccountsFile();
|
|
95
|
+
return Object.entries(file.accounts).map(([alias, entry]) => ({
|
|
96
|
+
alias,
|
|
97
|
+
entry,
|
|
98
|
+
isDefault: file.default === alias
|
|
99
|
+
}));
|
|
100
|
+
}
|
|
101
|
+
function setDefaultAccount(alias) {
|
|
102
|
+
const file = readAccountsFile();
|
|
103
|
+
if (!(alias in file.accounts)) throw new Error(`No account "${alias}". Run \`sechroom login --account ${alias}\` first.`);
|
|
104
|
+
file.default = alias;
|
|
105
|
+
writeAccountsFile(file);
|
|
106
|
+
}
|
|
107
|
+
function resolveAccountAlias(flagAccount) {
|
|
108
|
+
return flagAccount ?? process.env.SECHROOM_ACCOUNT ?? readLocalConfig().account ?? readAccountsFile().default ?? DEFAULT_ACCOUNT;
|
|
109
|
+
}
|
|
110
|
+
function writeLocalAccount(alias) {
|
|
111
|
+
const home = findConfigHome() ?? process.cwd();
|
|
112
|
+
const overridePath = join(home, OVERRIDE_CONFIG_NAME);
|
|
113
|
+
mkdirSync(dirname(overridePath), { recursive: true });
|
|
114
|
+
const current = readJsonConfig(overridePath) ?? {};
|
|
115
|
+
writeFileSync(
|
|
116
|
+
overridePath,
|
|
117
|
+
JSON.stringify({ ...current, account: alias }, null, 2),
|
|
118
|
+
{ mode: 384 }
|
|
119
|
+
);
|
|
120
|
+
return overridePath;
|
|
121
|
+
}
|
|
122
|
+
function readToken() {
|
|
123
|
+
const envTok = process.env.SECHROOM_TOKEN;
|
|
124
|
+
if (envTok) return { accessToken: envTok };
|
|
125
|
+
return readAccount(resolveAccountAlias());
|
|
59
126
|
}
|
|
60
127
|
function clearToken() {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return TOKEN_FILE;
|
|
128
|
+
const alias = resolveAccountAlias();
|
|
129
|
+
return removeAccount(alias) ? `${ACCOUNTS_FILE} (account "${alias}")` : void 0;
|
|
64
130
|
}
|
|
65
131
|
function clearPersisted() {
|
|
66
132
|
if (!existsSync(CONFIG_FILE)) return void 0;
|
|
@@ -95,6 +161,7 @@ function readLocalConfig() {
|
|
|
95
161
|
tenant: merged.tenant,
|
|
96
162
|
workspaceId: merged.workspaceId,
|
|
97
163
|
defaultProjectId: merged.defaultProjectId,
|
|
164
|
+
account: merged.account,
|
|
98
165
|
path: existsSync(baselinePath) ? baselinePath : overridePath
|
|
99
166
|
};
|
|
100
167
|
}
|
|
@@ -129,7 +196,8 @@ function resolveConfig(flags) {
|
|
|
129
196
|
}
|
|
130
197
|
const workspaceId = process.env.SECHROOM_WORKSPACE ?? local.workspaceId ?? persisted.workspaceId ?? void 0;
|
|
131
198
|
const defaultProjectId = local.defaultProjectId ?? persisted.defaultProjectId ?? void 0;
|
|
132
|
-
|
|
199
|
+
const account = resolveAccountAlias(flags.account);
|
|
200
|
+
return { baseUrl: baseUrl.replace(/\/$/, ""), tenant, account, workspaceId, defaultProjectId, clientId: persisted.clientId };
|
|
133
201
|
}
|
|
134
202
|
function describeConfig(flags) {
|
|
135
203
|
const local = readLocalConfig();
|
|
@@ -245,14 +313,25 @@ async function exchange(meta, clientId, code, verifier, redirectUri) {
|
|
|
245
313
|
})
|
|
246
314
|
});
|
|
247
315
|
if (!res.ok) throw new Error(`Token exchange failed (${res.status}): ${await res.text()}`);
|
|
248
|
-
|
|
316
|
+
return await res.json();
|
|
317
|
+
}
|
|
318
|
+
function decodeEmail(accessToken) {
|
|
319
|
+
try {
|
|
320
|
+
const payload = accessToken.split(".")[1];
|
|
321
|
+
if (!payload) return void 0;
|
|
322
|
+
const claims = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
|
|
323
|
+
return typeof claims.email === "string" ? claims.email : void 0;
|
|
324
|
+
} catch {
|
|
325
|
+
return void 0;
|
|
326
|
+
}
|
|
249
327
|
}
|
|
250
|
-
function persistTokenResponse(
|
|
251
|
-
|
|
252
|
-
|
|
328
|
+
function persistTokenResponse(account, baseUrl, tok) {
|
|
329
|
+
writeAccount(account, {
|
|
330
|
+
baseUrl,
|
|
253
331
|
accessToken: tok.access_token,
|
|
254
332
|
refreshToken: tok.refresh_token,
|
|
255
|
-
expiresAt: tok.expires_in ? Date.now() + tok.expires_in * 1e3 : void 0
|
|
333
|
+
expiresAt: tok.expires_in ? Date.now() + tok.expires_in * 1e3 : void 0,
|
|
334
|
+
email: decodeEmail(tok.access_token)
|
|
256
335
|
});
|
|
257
336
|
}
|
|
258
337
|
async function login(cfg) {
|
|
@@ -276,14 +355,25 @@ ${authUrl}
|
|
|
276
355
|
`);
|
|
277
356
|
await open(authUrl.toString());
|
|
278
357
|
const code = await loopback.code;
|
|
279
|
-
await exchange(meta, clientId, code, verifier, loopback.redirectUri);
|
|
280
|
-
|
|
358
|
+
const tok = await exchange(meta, clientId, code, verifier, loopback.redirectUri);
|
|
359
|
+
persistTokenResponse(cfg.account, cfg.baseUrl, tok);
|
|
360
|
+
const email = decodeEmail(tok.access_token);
|
|
361
|
+
process.stderr.write(`Signed in${email ? ` as ${email}` : ""} (account "${cfg.account}"). Token cached.
|
|
362
|
+
`);
|
|
281
363
|
}
|
|
282
364
|
async function requireToken(cfg) {
|
|
283
365
|
if (process.env.SECHROOM_TOKEN) return process.env.SECHROOM_TOKEN;
|
|
284
|
-
const cached =
|
|
366
|
+
const cached = readAccount(cfg.account);
|
|
285
367
|
if (!cached?.accessToken) {
|
|
286
|
-
throw new Error(
|
|
368
|
+
throw new Error(
|
|
369
|
+
`Not signed in (account "${cfg.account}"). Run \`sechroom login --account ${cfg.account}\` (or set SECHROOM_TOKEN for headless use).`
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
if (cached.baseUrl !== cfg.baseUrl) {
|
|
373
|
+
const matching = listAccounts().filter((a) => a.entry.baseUrl === cfg.baseUrl).map((a) => a.alias);
|
|
374
|
+
throw new Error(
|
|
375
|
+
`Account "${cfg.account}" is signed in to ${cached.baseUrl}, but this call targets ${cfg.baseUrl}. ` + (matching.length > 0 ? `Use --account ${matching[0]} (signed in there)` + (matching.length > 1 ? ` \u2014 or one of: ${matching.join(", ")}` : "") + ", or " : "") + `run \`sechroom login --account ${cfg.account}\` against it.`
|
|
376
|
+
);
|
|
287
377
|
}
|
|
288
378
|
const nearExpiry = cached.expiresAt !== void 0 && Date.now() > cached.expiresAt - 6e4;
|
|
289
379
|
if (nearExpiry && cached.refreshToken) {
|
|
@@ -297,10 +387,10 @@ async function requireToken(cfg) {
|
|
|
297
387
|
})
|
|
298
388
|
});
|
|
299
389
|
if (res.ok) {
|
|
300
|
-
persistTokenResponse(await res.json());
|
|
301
|
-
return
|
|
390
|
+
persistTokenResponse(cfg.account, cfg.baseUrl, await res.json());
|
|
391
|
+
return readAccount(cfg.account).accessToken;
|
|
302
392
|
}
|
|
303
|
-
throw new Error(
|
|
393
|
+
throw new Error(`Session expired and refresh failed. Run \`sechroom login --account ${cfg.account}\` again.`);
|
|
304
394
|
}
|
|
305
395
|
return cached.accessToken;
|
|
306
396
|
}
|
|
@@ -545,6 +635,62 @@ function fail(error) {
|
|
|
545
635
|
process.exit(1);
|
|
546
636
|
}
|
|
547
637
|
|
|
638
|
+
// src/commands/accounts.ts
|
|
639
|
+
function registerAccounts(program2) {
|
|
640
|
+
const accounts = program2.command("accounts").description("Manage signed-in identities (multi-account)");
|
|
641
|
+
accounts.addHelpText(
|
|
642
|
+
"after",
|
|
643
|
+
`
|
|
644
|
+
Examples:
|
|
645
|
+
$ sechroom login --account work sign in a second identity under the "work" alias
|
|
646
|
+
$ sechroom accounts list see every signed-in identity + which is active here
|
|
647
|
+
$ sechroom accounts use work make "work" the machine default
|
|
648
|
+
$ sechroom accounts use work --local pin "work" for THIS directory only (gitignored)
|
|
649
|
+
$ sechroom logout --account work sign the "work" identity out`
|
|
650
|
+
);
|
|
651
|
+
accounts.command("list").description("List signed-in accounts (alias, email, server, expiry)").action((_opts, cmd) => {
|
|
652
|
+
const active2 = resolveAccountAlias(cmd.optsWithGlobals().account);
|
|
653
|
+
const rows = listAccounts().map(({ alias, entry, isDefault }) => ({
|
|
654
|
+
alias,
|
|
655
|
+
email: entry.email,
|
|
656
|
+
baseUrl: entry.baseUrl,
|
|
657
|
+
expiresAt: entry.expiresAt ? new Date(entry.expiresAt).toISOString() : void 0,
|
|
658
|
+
isDefault,
|
|
659
|
+
isActiveHere: alias === active2
|
|
660
|
+
}));
|
|
661
|
+
if (cmd.optsWithGlobals().json) return emit({ accounts: rows, active: active2 }, true);
|
|
662
|
+
if (rows.length === 0) {
|
|
663
|
+
console.log(style.dim("No accounts signed in. Run `sechroom login` (optionally --account <alias>)."));
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
for (const r of rows) {
|
|
667
|
+
const markers = [r.isActiveHere ? style.green("active") : "", r.isDefault ? style.dim("default") : ""].filter(Boolean).join(" ");
|
|
668
|
+
console.log(
|
|
669
|
+
`${r.alias.padEnd(16)} ${(r.email ?? "\u2014").padEnd(28)} ${r.baseUrl} ${markers}`
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
accounts.command("use <alias>").description("Select the account used for calls (machine default, or --local for this directory)").option("--local", "pin for this directory only (gitignored .sechroom/config.json)").action((alias, opts, cmd) => {
|
|
674
|
+
const json = cmd.optsWithGlobals().json;
|
|
675
|
+
if (opts.local) {
|
|
676
|
+
const path = writeLocalAccount(alias);
|
|
677
|
+
if (json) return emit({ account: alias, scope: "local", path }, true);
|
|
678
|
+
console.log(style.green(`Account "${alias}" pinned for this directory (${path}).`));
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
setDefaultAccount(alias);
|
|
682
|
+
if (json) return emit({ account: alias, scope: "global" }, true);
|
|
683
|
+
console.log(style.green(`Account "${alias}" is now the machine default.`));
|
|
684
|
+
});
|
|
685
|
+
accounts.command("remove <alias>").description("Forget an account's cached token (local removal \u2014 does not revoke at the server)").action((alias, _opts, cmd) => {
|
|
686
|
+
const removed = removeAccount(alias);
|
|
687
|
+
if (cmd.optsWithGlobals().json) return emit({ removed: removed ? [alias] : [] }, true);
|
|
688
|
+
console.log(
|
|
689
|
+
removed ? style.green(`Account "${alias}" removed.`) : style.dim(`No account "${alias}".`)
|
|
690
|
+
);
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
|
|
548
694
|
// src/commands/memory.ts
|
|
549
695
|
function registerMemory(program2) {
|
|
550
696
|
const memory = program2.command("memory").description("Create, read, and search memories");
|
|
@@ -3179,7 +3325,7 @@ async function ensureTenant(baseUrl, g, opts) {
|
|
|
3179
3325
|
const local = readLocalConfig();
|
|
3180
3326
|
let tenant = g.tenant ?? process.env.SECHROOM_TENANT ?? local.tenant ?? persisted.tenant ?? "";
|
|
3181
3327
|
if (!tenant) {
|
|
3182
|
-
const client = await makeClient({ baseUrl, tenant: "", clientId: persisted.clientId });
|
|
3328
|
+
const client = await makeClient({ baseUrl, tenant: "", account: resolveAccountAlias(), clientId: persisted.clientId });
|
|
3183
3329
|
const { data, error } = await client.GET("/auth/me/tenants", {});
|
|
3184
3330
|
if (error) {
|
|
3185
3331
|
fail(`Couldn't list your tenants: ${JSON.stringify(error)}. Pass --tenant <id> to skip this.`);
|
|
@@ -3214,7 +3360,7 @@ async function ensureTenant(baseUrl, g, opts) {
|
|
|
3214
3360
|
}
|
|
3215
3361
|
}
|
|
3216
3362
|
const existingWorkspace = local.workspaceId ?? persisted.workspaceId ?? void 0;
|
|
3217
|
-
const wsClient = await makeClient({ baseUrl, tenant, clientId: persisted.clientId });
|
|
3363
|
+
const wsClient = await makeClient({ baseUrl, tenant, account: resolveAccountAlias(), clientId: persisted.clientId });
|
|
3218
3364
|
const workspaceId = await resolveWorkspaceBinding(wsClient, existingWorkspace, {
|
|
3219
3365
|
yes: opts.yes,
|
|
3220
3366
|
json: opts.json,
|
|
@@ -3249,7 +3395,7 @@ async function ensureTenant(baseUrl, g, opts) {
|
|
|
3249
3395
|
`);
|
|
3250
3396
|
}
|
|
3251
3397
|
}
|
|
3252
|
-
return { baseUrl, tenant, workspaceId, defaultProjectId, clientId: persisted.clientId };
|
|
3398
|
+
return { baseUrl, tenant, account: resolveAccountAlias(), workspaceId, defaultProjectId, clientId: persisted.clientId };
|
|
3253
3399
|
}
|
|
3254
3400
|
async function ensureAuth(cfg, yes) {
|
|
3255
3401
|
if (process.env.SECHROOM_TOKEN) return;
|
|
@@ -3432,13 +3578,13 @@ Examples:
|
|
|
3432
3578
|
if (opts.designLane) process.env.SECHROOM_DESIGN_LANE = opts.designLane;
|
|
3433
3579
|
if (opts.recurse) {
|
|
3434
3580
|
const baseUrl2 = resolveBaseUrl(g);
|
|
3435
|
-
await ensureAuth({ baseUrl: baseUrl2, tenant: "", clientId: readPersisted().clientId }, yes);
|
|
3581
|
+
await ensureAuth({ baseUrl: baseUrl2, tenant: "", account: resolveAccountAlias(), clientId: readPersisted().clientId }, yes);
|
|
3436
3582
|
const cfg2 = await ensureTenant(baseUrl2, g, { yes: true, json, persist: false });
|
|
3437
3583
|
await runRecurse(cfg2, g, { yes, dryRun, json, lane: opts.lane, designLane: opts.designLane });
|
|
3438
3584
|
return;
|
|
3439
3585
|
}
|
|
3440
3586
|
const baseUrl = resolveBaseUrl(g);
|
|
3441
|
-
await ensureAuth({ baseUrl, tenant: "", clientId: readPersisted().clientId }, yes);
|
|
3587
|
+
await ensureAuth({ baseUrl, tenant: "", account: resolveAccountAlias(), clientId: readPersisted().clientId }, yes);
|
|
3442
3588
|
const cfg = await ensureTenant(baseUrl, g, { yes, json, local: Boolean(opts.local), workspace: opts.workspace, persist: !check });
|
|
3443
3589
|
const tz = await ensureTimezone(cfg, { yes, dryRun: dryRun || check });
|
|
3444
3590
|
if (!json && tz.action !== "already-set") {
|
|
@@ -3935,9 +4081,23 @@ function removeMaterialisedSkills(dir) {
|
|
|
3935
4081
|
return removed;
|
|
3936
4082
|
}
|
|
3937
4083
|
function registerReset(program2) {
|
|
3938
|
-
program2.command("logout").description("Sign out \u2014 remove the cached (
|
|
4084
|
+
program2.command("logout").description("Sign out \u2014 remove the active account's cached token (--account <alias> for a specific one, --all for every account)").option("--account <alias>", "sign a specific account out").option("--all", "sign every account out").action((opts, cmd) => {
|
|
4085
|
+
const json = cmd.optsWithGlobals().json;
|
|
4086
|
+
if (opts.all) {
|
|
4087
|
+
const removed2 = listAccounts().map((a) => a.alias);
|
|
4088
|
+
for (const alias of removed2) removeAccount(alias);
|
|
4089
|
+
if (json) return emit({ removed: removed2 }, true);
|
|
4090
|
+
console.log(removed2.length > 0 ? style.green(`Signed out ${removed2.length} account(s): ${removed2.join(", ")}.`) : style.dim("Already signed out (no accounts)."));
|
|
4091
|
+
return;
|
|
4092
|
+
}
|
|
4093
|
+
if (opts.account) {
|
|
4094
|
+
const ok2 = removeAccount(opts.account);
|
|
4095
|
+
if (json) return emit({ removed: ok2 ? [opts.account] : [] }, true);
|
|
4096
|
+
console.log(ok2 ? style.green(`Signed out account "${opts.account}".`) : style.dim(`No account "${opts.account}".`));
|
|
4097
|
+
return;
|
|
4098
|
+
}
|
|
3939
4099
|
const removed = clearToken();
|
|
3940
|
-
if (
|
|
4100
|
+
if (json) return emit({ removed: removed ? [removed] : [] }, true);
|
|
3941
4101
|
console.log(
|
|
3942
4102
|
removed ? style.green("Signed out \u2014 auth token removed.") : style.dim("Already signed out (no token).")
|
|
3943
4103
|
);
|
|
@@ -4032,11 +4192,12 @@ Examples:
|
|
|
4032
4192
|
$ sechroom login sign in to the configured base URL + tenant
|
|
4033
4193
|
$ sechroom login --base-url https://staging.app.sechroom.ai/api
|
|
4034
4194
|
$ export SECHROOM_TOKEN=<bearer> headless: skip login entirely (CI / agents)`
|
|
4035
|
-
).action(async (
|
|
4195
|
+
).option("--account <alias>", "sign in under a named account alias (multi-account; default: the active alias)").action(async (opts, cmd) => {
|
|
4036
4196
|
const g = cmd.optsWithGlobals();
|
|
4037
4197
|
const persisted = readPersisted();
|
|
4038
4198
|
const baseUrl = g.baseUrl ?? process.env.SECHROOM_BASE_URL ?? persisted.baseUrl ?? "https://app.sechroom.ai/api";
|
|
4039
|
-
|
|
4199
|
+
const account = resolveAccountAlias(opts.account);
|
|
4200
|
+
await login({ baseUrl: baseUrl.replace(/\/$/, ""), tenant: g.tenant ?? "", account });
|
|
4040
4201
|
});
|
|
4041
4202
|
var config = program.command("config").description("Manage persisted CLI config");
|
|
4042
4203
|
config.addHelpText(
|
|
@@ -4093,6 +4254,7 @@ local: ${d.localPath ?? "(none)"} ${JSON.stringify(readLocalConfig())}
|
|
|
4093
4254
|
`
|
|
4094
4255
|
);
|
|
4095
4256
|
});
|
|
4257
|
+
registerAccounts(program);
|
|
4096
4258
|
registerMemory(program);
|
|
4097
4259
|
registerWorklog(program);
|
|
4098
4260
|
registerLookup(program);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sechroom/cli",
|
|
3
|
-
"version": "2026.6.
|
|
3
|
+
"version": "2026.6.30-rc.3b1b16ff",
|
|
4
4
|
"description": "Sechroom CLI — a thin, generated client over the Sechroom HTTP API. An agent/human surface alongside MCP.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|