@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.
Files changed (2) hide show
  1. package/dist/index.js +12 -66
  2. 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", "workspaces"];
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 = 3;
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, opts) {
171
- const home = (opts?.here ? process.cwd() : findConfigHome()) ?? process.cwd();
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 binding = selectWorkspaceBinding(local, flags.binding ?? process.env.SECHROOM_BINDING);
224
- const workspaceId = process.env.SECHROOM_WORKSPACE ?? binding?.workspaceId ?? local.workspaceId ?? persisted.workspaceId ?? void 0;
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, { here: Boolean(opts.here) });
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("--here", "with --local: write the binding at THIS directory even when a parent already carries one \u2014 binds a subtree (e.g. a monorepo's frontend/) to its own workspace", 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(
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("--binding <name>", "Named workspace binding from .sechroom.json `workspaces` (overrides path auto-selection / SECHROOM_BINDING)").option("--json", "Emit compact JSON (for scripts and agents)", false);
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, binding: g.binding });
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sechroom/cli",
3
- "version": "2026.6.29",
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",