selector: --org and --business in case2 persona-import and precheck

Rename design r2, "Selector scopes and parser matrix". case2-persona-import.mjs takes --org
through selectorScope and case2-precheck.sh through scripts/selector.sh, one scope each. Both
keep their exit codes and their old business-id wording; a repeated or conflicting selector
says why. persona-import now checks the id while parsing, so stage refuses an invalid
selector before it reads anything.

The case2-install fake stack copy carries packages/business/src/selector.mjs, which the real
copy already does (COPY_PATHS takes packages/business/src).
This commit is contained in:
jason.woltje committed 2026-11-08 21:25:49 -06:00
1 parent 259302a368
commit 3baf6f2297
5 files changed
+127 -5

No files matched your search

+15 -1
View File
@@ -5,6 +5,7 @@
// case2-persona-import.mjs stage --hermes-root DIR --pair PROFILE=NAME --pair PROFILE=NAME
// (--staging DIR | --dry-run)
// case2-persona-import.mjs install --staging DIR --config-dir DIR --business ID
// (--org ID is the same option)
//
// stage runs as whoever can read her Hermes home. Per profile it reads SOUL.md, the persona Hermes
// loads (agent/prompt_builder.py:1829-1855 at df5700ebe), and config.yaml for the per-channel prompt
@@ -31,6 +32,7 @@ import { createHash } from "node:crypto";
import { join } from "node:path";
import { parse as parseYaml } from "yaml";
import { PERSONA_CHARS, personaTextFault } from "../packages/harness/src/bundle.mjs";
import { selectorScope } from "../packages/business/src/selector.mjs";
// The tool names registered in hermes-agent's tools/*.py at df5700ebe (literal `name="..."` in
// registry.register calls; the MCP and plugin tools get their names at run time), plus Hermes and
@@ -67,9 +69,21 @@ class Usage extends Error {}
function args(argv) {
const out = { pairs: [] };
// --org and --business are one selector in these options (rename design r2). A missing value or
// one starting "--" is a usage error, as before; an id outside this script's grammar is its
// refusal, now while parsing; a repeated or conflicting selector is a usage error.
let given;
const selector = selectorScope({
valid: (id) => BUSINESS_ID.test(id),
refuse: (kind, why) => {
if (kind === "invalid" || (kind === "flag" && !given.startsWith("--"))) throw new Refusal(`business ${given} isn't a business id`);
throw new Usage(why);
},
});
for (let i = 0; i < argv.length; i++) {
const flag = argv[i];
if (flag === "--dry-run") { out.dryRun = true; continue; }
if (selector.owns(flag)) { given = argv[i + 1]; selector.take(flag, given); i++; continue; }
const value = argv[i + 1];
if (value === undefined || value.startsWith("--")) throw new Usage(`${flag} needs a value`);
i++;
@@ -77,9 +91,9 @@ function args(argv) {
else if (flag === "--hermes-root") out.hermesRoot = value;
else if (flag === "--staging") out.staging = value;
else if (flag === "--config-dir") out.configDir = value;
else if (flag === "--business") out.business = value;
else throw new Usage(`unknown option ${flag}`);
}
if (selector.given) out.business = selector.value;
return out;
}
+16 -1
View File
@@ -7,6 +7,8 @@
# case2-precheck.sh --business ID [--profile factory|library]
# case2-precheck.sh --business ID --library-status
#
# --org ID is the same option as --business ID.
#
# Checks: the config and business file validate; `sudo -n true` fails and
# `id -G` prints one group; bus.tester is off for library and on for factory,
# the explicit notifier config is valid at 0600 in a private 0700 directory;
@@ -53,11 +55,24 @@ WEBUI_UNIT="$UNIT_DIR/mosaic-webui.service"
MARKER_TOKEN_CEILING=2000
usage() { echo 'usage: case2-precheck.sh --business ID [--profile factory|library] | --business ID --library-status' >&2; exit 4; }
# shellcheck source=scripts/selector.sh
. "$REPO/scripts/selector.sh"
# --org and --business are one selector here (rename design r2). A missing value is a usage error,
# a flag-shaped or invalid one the business-id refusal below, and a repeated or conflicting one
# says why; all exit 4, as before.
selector_refused() {
case "$1" in
missing) usage ;;
flag|invalid) echo "case2-precheck: --business must be a business id: $BUSINESS" >&2; exit 4 ;;
*) echo "case2-precheck: $2" >&2; exit 4 ;;
esac
}
business_id_ok() { [[ "$1" =~ ^[a-z0-9][a-z0-9._-]{0,63}$ ]]; }
PROFILE=library PROFILE_SET=0 BUSINESS='' STATUS=0
while [ $# -gt 0 ]; do
case "$1" in
--profile) [ $# -ge 2 ] || usage; PROFILE="$2"; PROFILE_SET=1; shift 2 ;;
--business) [ $# -ge 2 ] || usage; BUSINESS="$2"; shift 2 ;;
--business|--org) BUSINESS="${2-}"; selector_take args id selector_refused business_id_ok "$1" "${@:2:1}"; shift 2 ;;
--library-status) STATUS=1; shift ;;
*) usage ;;
esac