Commit Graph
19 Commits
Author SHA1 Message Date
jason.woltje 211b32ef1a fix(cli): f6c re-check, a failed released-marker write still removes the start lock; docs name the new warning and code (#1873) 2026-11-13 20:14:21 -06:00
jason.woltje 163972e08e fix(cli): f6c review round, released start locks, ENOENT and path cut (#1873)
P3-1: releasing a console start lock marks it released through its own
descriptor and removes the path only while it is still that file; a
released lock put back by a racing clear is cleared by the next start or
stop.
P3-2: org definitions reports unknown-organization only when the
organization file itself is missing; another missing file names the
operation.
P3-3: the path cut also covers a path after ':' or inside backticks.
2026-11-13 20:14:21 -06:00
jason.woltje 23e504f331 fix(cli,bus,organization): E2E6 lane f6c, refusal lines name the next step (#1873)
1. Stale bus host lock refusals from bus status, start, stop and restart
   name mosaic bus recover ORG.
2. org definitions: unknown org, unknown or malformed name and bad id give
   one refusal or usage line, no stack trace, no host path.
3. Pack, board and workflow refusals print their hint as template save does;
   tested with the real CliError transport shape.
4. console start and stop clear a console/start.lock whose named supervisor
   (pid and start time) is gone; a live or unnamed holder refuses.
5. Template save keeps free text verbatim and writes no placeholders; the
   preview lists each field that mentions an org-specific name.
6. A request the shim never sent (no socket, connect refused) exits 5 and
   the CLI reports bus-not-running with the start and recover line.
7. autonomy-precondition carries the check that failed, including on the
   hire paths.
8. Saving under an existing template name refuses template-exists with a
   next step; refusal table entry added, channel-proof pins moved.
2026-11-13 20:14:21 -06:00
jason.woltje 666f4d6864 fix(cli): build review fixes for the parity verbs (#1873, P1-3)
- autonomy set: an empty --authority-resolver clears the resolver as the
  panel does; --reverse-window-hours takes 1 to 168, as the page and bus do.
- The default instance gets a one-line refusal (exit 3) naming the named
  instance and --dev-local-owner, not a stack trace.
- tasks create|edit|archive: a value starting with -- is a usage error;
  --business is checked before the agent guard, and the guard also reads
  process.env.
- Drop the unused consoleRefusal export.
- Docs: --business is required, resolver clearing, window range, and the
  named-instance requirement.
2026-11-11 20:47:35 -06:00
jason.woltje 550bd084d0 feat(cli): hire, autonomy and task-board verbs for WebUI parity (#1873, P1-3)
mosaic org role-templates|hire|change|fire and mosaic org autonomy
[set|review] send the hire form's and the autonomy panel's own requests
to the running Console's org route, so the Console runs the same owner,
send, origin, body and revision checks and the same bus verbs. They
refuse inside an agent run after their usage checks.

mosaic tasks create|edit|archive pass the board's parseTaskWrite and go
to the bus as the person (tasks.create|edit|archive).

Docs: cli README, docs/TOOLS.md, webui README Console actions table.
2026-11-11 20:47:34 -06:00
jason.woltje 6f18f3d015 fix(cli): bus and Console lifecycle verbs refuse inside an agent run (#1873)
D2 security re-check P1 (agent-guard). mosaic bus start|stop|restart and
mosaic console start (with or without --dev-local-owner), stop and restart
refuse inside an agent run with refuseInsideAgent's refusal (exit 3), as
bus recover does. The check reads the given environment and this process's
own, so a sanitized io.env does not hide a marker; bus recover and console
restart now check both too. consoleStart refuses for every Console. Status
verbs stay open. No new marker list and no new human gate.

The Console's Restart bus runs org-bus.mjs in the Console process; its new
host goes through the guarded CLI entry with the Console's own environment.
Restart Console relaunches under the supervisor without the CLI.
2026-11-11 16:15:51 -06:00
jason.woltje ebe2af86de fix(console): D1 security re-check fixes for the dev-owner start (#1873)
The agent-run refusal on a dev-local-owner start now checks the starting
process's own environment as well as the environment given for the
Console, so a caller cannot pass a clean env to get past it.

The start lock now names its holder (pid and start time). A detached
start that times out and kills its supervisor's process group clears the
lock only when it names that supervisor and the supervisor is gone, so a
forced kill no longer blocks every later start.
2026-11-11 14:16:09 -06:00
jason.woltje 1947a056fb fix(console): D1 review fixes for the detached dev-owner supervisor (#1873)
Build review P2: the supervisor ignores a lost reply pipe and keeps
supervising. Security P2: a stop signal during start is held until the
start settles, and the CLI's start timeout signals the supervisor's
process group. Security P1 (part): console start --dev-local-owner
refuses inside an agent run. Tests cover review, confirm and reverse on
the org autonomy route; TOOLS.md and the webui README are corrected.
2026-11-11 14:16:09 -06:00
jason.woltje 7ffe932250 feat(console): dev-local-owner Console writes autonomy and restarts when detached (#1873)
A --dev-local-owner Console's organization pages read writable:false because
the per-org options had no autonomy writer and the route fell back to the
request transport, which org options never set. The org options now carry an
autonomy writer on the organization's console transport, fenced to the four
owner autonomy verbs. The route prefers it and keeps requestWrite otherwise.

mosaic console start --dev-local-owner --detach now runs the Console under a
detached supervisor, so Restart Console (exit 75) relaunches it on the same
address. A non-dev detached Console is unchanged. A deployed --sso --send
Console has no organization routes and keeps its root autonomy transport;
a test pins both.
2026-11-11 14:16:09 -06:00
jason.woltje d085b16136 fix(organization,cli): review round: raw fs and git errors, console entry, config, document and --vars refusals name labels
Sol review (org-redact5, changes 6):
- org-service: Node filesystem errors become "cannot <syscall> <label> (<CODE>)";
  code, syscall, deleteStep and deleteReceipt stay. git failures name the verb
  and exit code, never git's stderr.
- org-console: consoleStop names "another checkout", not the entry path. Exit 3.
- config-command: the system config is named by where it came from. Exit 3.
- cli org: documents and raw fs errors are named by kind and code. Exit 2.
- instances: --vars file named by flag and kind. Exit 4.
- hosts: a refused command is named by the basename refusedCommand matched.
- role.mjs (T1): the change is back to the readJsonFile label only.
Sentinel tests for each; pins in last-values, rename-b-commands, org-recovery.
2026-11-11 01:04:15 -06:00
jason.woltje 4c8bf9ca4e fix(organization,cli): refusals name the file by label, never by host path
PR #1916 rule: a refusal names the field or file, never a config value
or a host path. readJsonFile's three refusals and parseJsonFileText now
name the file by its `what` label only. Callers whose label alone is
ambiguous add a name that already passed a strict pattern (business id,
role name, org id, turn id, project key) or a fixed path under the data
root. Exit codes, refusal codes and check order are unchanged.

organization: util, access, project, config-command, library-seats,
org-service deleteOrg receipt, agent-levels regex; T1 files role.mjs and
organization-config.mjs change only the readJsonFile label.
cli: access lock, accounts owner, host state/lock, notifier journal,
notify-config, run-evidence, dev-fixture, git-socket, org-bus, org-console.
discord: turn record label names the turn id.

Sentinel tests (sk-test-NOT-A-SECRET-1234 as a path component) cover each
changed refusal and fail on BASE; old path pins updated.
2026-11-11 01:04:15 -06:00
jason.woltje 2109458b3f feat(webui,cli): U1 cross-organization read model and console verbs (#1873)
GET /api/workspace on the dev-local-owner Console: one snapshot of
projects, sessions, inbox, tasks and per-org metrics across every
organization the owner belongs to. Membership reuses the org list's
admission (organizations.members); each org is read over the same
per-org options the org pages use, with one deadline per org (4000 ms)
and a state (ok, down, starting, timeout, invalid) with a time. Every
row carries its org id; decide commands carry --org. Granted users
and the tester get 403 owner-only. Polling at 10 s, no push.

mosaic console restart and mosaic org reload <id> call the Console's
F3 routes (POST /api/console/restart, POST /api/orgs/<id>/restart/bus)
so gating, proof and trail are the Console's own; both refuse inside
an agent run first.

The cross-org assistant read is designed and stopped: it needs a new
broker read verb or role authority.
2026-11-09 17:54:06 -06:00
jason.woltje e98909d907 Merge refactor 2bed0aebe into F3 (console restart, owner settings writes)
Conflicts kept both sides: rename stage B organization paths and the
relative-launch re-exec with F3 imports, F2 onboarding script and the
north-star fence exemption with F3 console-restart.js and ORG_OWNER_WRITE,
and the /api/config fields from both.
2026-11-09 13:41:20 -06:00
jason.woltje 1b6cac2bdf feat(webui): restart the Console, the org bus and agents from the WebUI (F3)
Self-service operation from the WebUI, for a dev instance first.

- Settings > Console > Restart Console. A foreground `mosaic console
  start` now supervises the webui: the child exits 75 after answering a
  restart and the supervisor relaunches it with the same argv. Org buses
  keep running. /api/config carries a per-process boot id, so the open
  page polls until a new process answers and then reloads. A detached
  Console has no supervisor and answers 409.
- Restart bus on every "Restart needed" receipt and on the bus-down
  banner: POST /api/orgs/<id>/restart/bus restarts a running bus or
  starts a stopped one, then shows a done receipt with the time.
- Settings > Routing: after a save, the page lists how the change
  reaches each agent (next start, session end, thread idle) and offers
  "Restart <agent> now" for a running one. A session is terminated with
  the reason "route change" and launched again; a thread is terminated.
- Organization settings: the signed-in owner's settings, routing,
  agent, plug-in and Model proxy writes now reach the selected org's
  bus instead of answering 403. Org mode exists only under
  --dev-local-owner. Proxy setup stays a terminal step; a dev-only note
  names the two commands.

Every control needs the signed-in owner session, the page's exact
Origin and Sec-Fetch-Site: same-origin. The tester listener, granted
users, API tokens, agents and bus roles are refused before any work.
Each use is written to <dataRoot>/console/actions.jsonl (0600, no
symlinks) with who, when, what and the outcome. The Console and bus
restart trails fail closed. No change to credential handling, the
broker, the bus tenant boundary or v2 schemas.
2026-11-09 13:37:28 -06:00
jason.woltje a8d9eecf65 organization: move packages/business to packages/organization (rename r2 stage B1)
git mv packages/business -> packages/organization (@mosaic/organization). The
old package stays as one-line re-export shims of each moved module, with
src/business.mjs re-exporting src/organization-config.mjs and src/cli.mjs
forwarding to the moved executable. BusinessError is OrganizationConfigError
(one constructor, name kept BusinessError); OrganizationError stays distinct.
The bus adapter gains organization-context.mjs (busOrganization), with
business.mjs (busBusiness) as the same function.

Import consumers, manifests, the lockfile, scripts/mosaic, stack-copy.sh
COPY_PATHS (both roots), seat sandbox RUNNER_FILES and the copy closure
walker (organization-imports.mjs, both roots required) move to the new path.
v1 serialization, v1 writers and the stage A fixtures are unchanged; the stage
A contract tests stay where they were and pass as before.
2026-11-09 11:47:48 -06:00
jason.woltje 665a5148d4 Open the dev owner Console to allowed LAN names
mosaic console start --dev-local-owner --dev-insecure-bind ADDR
--dev-allow-host NAME[,NAME...] binds 0.0.0.0 or an IPv4 address and
answers only NAME:<bound port> plus the loopback names. Both flags are
refused without the dev owner, the bind without an allowed name, and a
specific ADDR that is not itself a name. Start and console status print
the no-sign-in warning; the state file records bind and allowHosts.

serve.mjs takes devAllowHosts only with the dev owner; SSO, preview and
tester listeners stay loopback. Writes need Origin http://<same Host>.
Chromium sends no Fetch Metadata from a LAN http origin, so for an
allowed name a write with that exact Origin and no Sec-Fetch-Site counts
as same-origin; an explicit header is still judged by the routes.
chat.js builds its operation keys without crypto.randomUUID, which an
insecure context lacks.
2026-11-08 21:13:53 -06:00
jason.woltje d68e7b0976 Fix recovery review findings: live Console identity, crashed clear fence, atomic quarantine (P19 #857, #862)
- A Console is stale only when its pid is gone or its start time differs. A live Console
  started from another entry path is never quarantined; stop refuses to signal it and
  names the path it was started from.
- The lock-clear fence records the clearer's pid and start time. A fence left by a dead
  clearer is moved aside and recovery continues; a live or unreadable fence refuses.
  lock show reports a fence.
- Console state is moved aside with one atomic rename after an inode re-check.
2026-11-08 14:52:42 -06:00
jason.woltje e9a7adab11 Recover stale Console state, dead org locks and wedged bus hosts
console start and stop move a console.json whose recorded process is gone
aside instead of refusing (P19 #857). mosaic org lock show|clear reports a
lifecycle lock holder and clears it only when the holder is dead.
mosaic bus recover marks a bus host stopped when its process is gone and its
socket does not answer, and writes a recovery receipt (P19 #862).
2026-11-08 14:11:13 -06:00
jason.woltje 24e240d44e Scope buses to organization roots 2026-11-07 11:29:13 -06:00