@sechroom/cli 2026.6.29 → 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 +12 -66
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21,9 +21,9 @@ var DEFAULT_ACCOUNT = "default";
|
|
|
21
21
|
var STATE_DIR_NAME = ".sechroom";
|
|
22
22
|
var BASELINE_CONFIG_NAME = ".sechroom.json";
|
|
23
23
|
var OVERRIDE_CONFIG_NAME = join(STATE_DIR_NAME, "config.json");
|
|
24
|
-
var BINDING_FIELDS = ["schemaVersion", "baseUrl", "tenant", "workspaceId", "defaultProjectId"
|
|
24
|
+
var BINDING_FIELDS = ["schemaVersion", "baseUrl", "tenant", "workspaceId", "defaultProjectId"];
|
|
25
25
|
var DEFAULT_BASE_URL = "https://app.sechroom.ai/api";
|
|
26
|
-
var LOCAL_CONFIG_SCHEMA_VERSION =
|
|
26
|
+
var LOCAL_CONFIG_SCHEMA_VERSION = 2;
|
|
27
27
|
function ensureDir() {
|
|
28
28
|
if (!existsSync(CONFIG_DIR)) mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
|
|
29
29
|
}
|
|
@@ -161,14 +161,12 @@ function readLocalConfig() {
|
|
|
161
161
|
tenant: merged.tenant,
|
|
162
162
|
workspaceId: merged.workspaceId,
|
|
163
163
|
defaultProjectId: merged.defaultProjectId,
|
|
164
|
-
workspaces: merged.workspaces,
|
|
165
164
|
account: merged.account,
|
|
166
|
-
path: existsSync(baselinePath) ? baselinePath : overridePath
|
|
167
|
-
home
|
|
165
|
+
path: existsSync(baselinePath) ? baselinePath : overridePath
|
|
168
166
|
};
|
|
169
167
|
}
|
|
170
|
-
function writeLocalConfig(patch
|
|
171
|
-
const home =
|
|
168
|
+
function writeLocalConfig(patch) {
|
|
169
|
+
const home = findConfigHome() ?? process.cwd();
|
|
172
170
|
const baselinePath = join(home, BASELINE_CONFIG_NAME);
|
|
173
171
|
const overridePath = join(home, OVERRIDE_CONFIG_NAME);
|
|
174
172
|
const current = readJsonConfig(baselinePath) ?? {};
|
|
@@ -186,30 +184,6 @@ function committedBindingPath(dir) {
|
|
|
186
184
|
const p = join(dir, BASELINE_CONFIG_NAME);
|
|
187
185
|
return existsSync(p) ? p : void 0;
|
|
188
186
|
}
|
|
189
|
-
function selectWorkspaceBinding(local, explicitName) {
|
|
190
|
-
const bindings = local.workspaces ?? [];
|
|
191
|
-
if (explicitName) {
|
|
192
|
-
const hit = bindings.find((b) => b.name === explicitName);
|
|
193
|
-
if (!hit)
|
|
194
|
-
throw new Error(
|
|
195
|
-
`No workspace binding named "${explicitName}" in ${local.home ?? "this repo"}'s .sechroom.json` + (bindings.length > 0 ? ` (have: ${bindings.map((b) => b.name).join(", ")})` : "") + ". Add one with `sechroom workspace bind`."
|
|
196
|
-
);
|
|
197
|
-
return hit;
|
|
198
|
-
}
|
|
199
|
-
if (!local.home || bindings.length === 0) return void 0;
|
|
200
|
-
const rel = process.cwd().startsWith(local.home) ? process.cwd().slice(local.home.length).replace(/^[/\\]/, "") : "";
|
|
201
|
-
const norm = (p) => p.replace(/\/\*\*$/, "").replace(/[/\\]+$/, "");
|
|
202
|
-
let best;
|
|
203
|
-
for (const b of bindings) {
|
|
204
|
-
for (const raw of b.paths ?? []) {
|
|
205
|
-
const prefix = norm(raw);
|
|
206
|
-
if (prefix.length === 0) continue;
|
|
207
|
-
const matches = rel === prefix || rel.startsWith(prefix + "/");
|
|
208
|
-
if (matches && (!best || prefix.length > best.len)) best = { binding: b, len: prefix.length };
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
return best?.binding;
|
|
212
|
-
}
|
|
213
187
|
function resolveConfig(flags) {
|
|
214
188
|
const local = readLocalConfig();
|
|
215
189
|
const persisted = readPersisted();
|
|
@@ -220,9 +194,8 @@ function resolveConfig(flags) {
|
|
|
220
194
|
"No tenant set. The Sechroom API rejects untenanted requests (HTTP 400). Pass --tenant <id>, set SECHROOM_TENANT, run `sechroom config set tenant <id>`, or `sechroom config set --local tenant <id>` for this directory."
|
|
221
195
|
);
|
|
222
196
|
}
|
|
223
|
-
const
|
|
224
|
-
const
|
|
225
|
-
const defaultProjectId = (binding ? binding.defaultProjectId : void 0) ?? local.defaultProjectId ?? persisted.defaultProjectId ?? void 0;
|
|
197
|
+
const workspaceId = process.env.SECHROOM_WORKSPACE ?? local.workspaceId ?? persisted.workspaceId ?? void 0;
|
|
198
|
+
const defaultProjectId = local.defaultProjectId ?? persisted.defaultProjectId ?? void 0;
|
|
226
199
|
const account = resolveAccountAlias(flags.account);
|
|
227
200
|
return { baseUrl: baseUrl.replace(/\/$/, ""), tenant, account, workspaceId, defaultProjectId, clientId: persisted.clientId };
|
|
228
201
|
}
|
|
@@ -239,17 +212,10 @@ function describeConfig(flags) {
|
|
|
239
212
|
return { value: void 0, source: "unset" };
|
|
240
213
|
};
|
|
241
214
|
const baseUrl = pick(flags.baseUrl, process.env.SECHROOM_BASE_URL, local.baseUrl, g.baseUrl, DEFAULT_BASE_URL);
|
|
242
|
-
let binding;
|
|
243
|
-
try {
|
|
244
|
-
binding = selectWorkspaceBinding(local, flags.binding ?? process.env.SECHROOM_BINDING);
|
|
245
|
-
} catch {
|
|
246
|
-
binding = void 0;
|
|
247
|
-
}
|
|
248
|
-
const workspaceId = process.env.SECHROOM_WORKSPACE ? { value: process.env.SECHROOM_WORKSPACE, source: "env" } : binding ? { value: binding.workspaceId, source: `binding "${binding.name}"${localTag !== "local" ? ` (${local.path})` : ""}` } : pick(void 0, void 0, local.workspaceId, g.workspaceId);
|
|
249
215
|
return {
|
|
250
216
|
baseUrl: { value: baseUrl.value, source: baseUrl.source },
|
|
251
217
|
tenant: pick(flags.tenant, process.env.SECHROOM_TENANT, local.tenant, g.tenant),
|
|
252
|
-
workspaceId,
|
|
218
|
+
workspaceId: pick(void 0, process.env.SECHROOM_WORKSPACE, local.workspaceId, g.workspaceId),
|
|
253
219
|
localPath: local.path
|
|
254
220
|
};
|
|
255
221
|
}
|
|
@@ -1202,26 +1168,6 @@ Examples:
|
|
|
1202
1168
|
// src/commands/workspace.ts
|
|
1203
1169
|
function registerWorkspace(program2) {
|
|
1204
1170
|
const workspace = program2.command("workspace").description("Create, browse, and manage workspaces");
|
|
1205
|
-
workspace.command("bind <workspaceId>").description("Bind a workspace to this repo (.sechroom.json). With --name it becomes a NAMED v3 binding (multi-workspace); --paths scopes it to subtrees.").option("--name <name>", "binding name (enables multi-workspace; selectable via --binding / path match)").option("--paths <csv>", "comma-separated directory prefixes (relative to the repo root) this binding covers, e.g. frontend,docs").option("--default-project <id>", "informational default project for this binding").option("--here", "write the binding file at THIS directory even when a parent already carries one").action((workspaceId, opts, cmd) => {
|
|
1206
|
-
const json = cmd.optsWithGlobals().json;
|
|
1207
|
-
if (!opts.name) {
|
|
1208
|
-
const path2 = writeLocalConfig({ workspaceId, ...opts.defaultProject ? { defaultProjectId: opts.defaultProject } : {} }, { here: Boolean(opts.here) });
|
|
1209
|
-
if (json) return emit({ workspaceId, path: path2 }, true);
|
|
1210
|
-
console.log(style.green(`Workspace ${workspaceId} bound (${path2}).`));
|
|
1211
|
-
return;
|
|
1212
|
-
}
|
|
1213
|
-
const local = readLocalConfig();
|
|
1214
|
-
const bindings = (local.workspaces ?? []).filter((b) => b.name !== opts.name);
|
|
1215
|
-
bindings.push({
|
|
1216
|
-
name: opts.name,
|
|
1217
|
-
workspaceId,
|
|
1218
|
-
...opts.defaultProject ? { defaultProjectId: opts.defaultProject } : {},
|
|
1219
|
-
...opts.paths ? { paths: String(opts.paths).split(",").map((p) => p.trim()).filter(Boolean) } : {}
|
|
1220
|
-
});
|
|
1221
|
-
const path = writeLocalConfig({ workspaces: bindings }, { here: Boolean(opts.here) });
|
|
1222
|
-
if (json) return emit({ binding: opts.name, workspaceId, paths: opts.paths ?? null, path }, true);
|
|
1223
|
-
console.log(style.green(`Binding "${opts.name}" \u2192 ${workspaceId} saved (${path}).`));
|
|
1224
|
-
});
|
|
1225
1171
|
workspace.addHelpText(
|
|
1226
1172
|
"after",
|
|
1227
1173
|
`
|
|
@@ -3436,7 +3382,7 @@ async function ensureTenant(baseUrl, g, opts) {
|
|
|
3436
3382
|
if (opts.persist !== false) {
|
|
3437
3383
|
const patch = { baseUrl, tenant, ...workspaceId ? { workspaceId } : {} };
|
|
3438
3384
|
if (storeLocal) {
|
|
3439
|
-
const path = writeLocalConfig(patch
|
|
3385
|
+
const path = writeLocalConfig(patch);
|
|
3440
3386
|
if (!opts.json) process.stderr.write(`${ok("\u2713")} config saved to ${path} (directory-local)
|
|
3441
3387
|
`);
|
|
3442
3388
|
} else {
|
|
@@ -3606,7 +3552,7 @@ async function runRecurse(cfg, g, opts) {
|
|
|
3606
3552
|
summarizeFanout(results, { dryRun });
|
|
3607
3553
|
}
|
|
3608
3554
|
function registerOnboard(program2) {
|
|
3609
|
-
program2.command("onboard").description("Guided first-run setup: configure, sign in, set timezone, detect clients, and wire this project").option("--recurse", "orchestration-root mode: onboard every child repo under this dir (auto-discovered, or from ./.sechroom/repos.json) \u2014 refreshes bound repos, prompts a workspace per new one", false).option("--lane <id>", "set the code-lane (substrate source identity) explicitly instead of inferring it; with --recurse it's used for every child repo").option("--design-lane <id>", "set the design-lane explicitly (substrate-authoring identity); with --recurse applies to every child").option("--client <list>", `comma-separated clients (${ALL_CLIENT_KEYS.join(", ")}) or 'all' (default: auto-detected)`).option("--local", "save the binding (tenant + base URL + workspace) to a committed .sechroom.json in this repo instead of the global config", false).option("--
|
|
3555
|
+
program2.command("onboard").description("Guided first-run setup: configure, sign in, set timezone, detect clients, and wire this project").option("--recurse", "orchestration-root mode: onboard every child repo under this dir (auto-discovered, or from ./.sechroom/repos.json) \u2014 refreshes bound repos, prompts a workspace per new one", false).option("--lane <id>", "set the code-lane (substrate source identity) explicitly instead of inferring it; with --recurse it's used for every child repo").option("--design-lane <id>", "set the design-lane explicitly (substrate-authoring identity); with --recurse applies to every child").option("--client <list>", `comma-separated clients (${ALL_CLIENT_KEYS.join(", ")}) or 'all' (default: auto-detected)`).option("--local", "save the binding (tenant + base URL + workspace) to a committed .sechroom.json in this repo instead of the global config", false).option("--workspace <id>", "bind this directory to a workspace (skips the interactive workspace pick)").option("--cli-only", "configure the CLI only \u2014 don't wire any AI client (no MCP config, no agent files)", false).option("--no-mcp", "skip the MCP server config (.mcp.json etc.); still write the agent instruction files").option("--copy", "make a personal copy of the agent instructions you can edit (default: prompt on a TTY, else skip)").option("--dry-run", "walk through without writing files or changing the profile", false).option("--refresh", "re-fetch descriptors and refresh any out-of-date managed blocks (local edits preserved to .proposed)", false).option("--force", "rewrite every managed block, overwriting local edits inside the markers (content outside untouched)", false).option("--check", "report whether anything would change and exit (0 = all current, 1 = stale/drift/absent); writes nothing", false).option("-y, --yes", "non-interactive: accept defaults (system timezone, detected clients, global config, full wire)", false).addHelpText(
|
|
3610
3556
|
"after",
|
|
3611
3557
|
`
|
|
3612
3558
|
Examples:
|
|
@@ -4213,7 +4159,7 @@ function resolveVersion() {
|
|
|
4213
4159
|
}
|
|
4214
4160
|
}
|
|
4215
4161
|
var program = new Command();
|
|
4216
|
-
program.name("sechroom").description("Sechroom CLI \u2014 thin generated client over the Sechroom HTTP API. An agent/human surface alongside MCP.").version(resolveVersion()).option("--base-url <url>", "API base URL (overrides config / SECHROOM_BASE_URL)").option("--tenant <tenant>", "Tenant id (required by the API; overrides config / SECHROOM_TENANT)").option("--
|
|
4162
|
+
program.name("sechroom").description("Sechroom CLI \u2014 thin generated client over the Sechroom HTTP API. An agent/human surface alongside MCP.").version(resolveVersion()).option("--base-url <url>", "API base URL (overrides config / SECHROOM_BASE_URL)").option("--tenant <tenant>", "Tenant id (required by the API; overrides config / SECHROOM_TENANT)").option("--json", "Emit compact JSON (for scripts and agents)", false);
|
|
4217
4163
|
program.addHelpText(
|
|
4218
4164
|
"after",
|
|
4219
4165
|
`
|
|
@@ -4287,7 +4233,7 @@ config.command("set <key> <value>").description("Set baseUrl | tenant | workspac
|
|
|
4287
4233
|
});
|
|
4288
4234
|
config.command("show").description("Print resolved config + sources (flag > env > local > global > default)").action((_opts, cmd) => {
|
|
4289
4235
|
const g = cmd.optsWithGlobals();
|
|
4290
|
-
const d = describeConfig({ baseUrl: g.baseUrl, tenant: g.tenant
|
|
4236
|
+
const d = describeConfig({ baseUrl: g.baseUrl, tenant: g.tenant });
|
|
4291
4237
|
if (g.json) {
|
|
4292
4238
|
process.stdout.write(
|
|
4293
4239
|
JSON.stringify({
|
package/package.json
CHANGED