@rosthq/cli 0.7.10 → 0.7.11
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 +118 -35
- package/dist/index.js.map +3 -3
- package/dist/runner-service.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -47455,7 +47455,7 @@ The Compass is drafted, then activated by a human through supersession.
|
|
|
47455
47455
|
order: 15,
|
|
47456
47456
|
title: "AICOS chat guide",
|
|
47457
47457
|
summary: "How the AI Chief of Staff chat works in the authenticated app shell and what it can safely do today.",
|
|
47458
|
-
version: "2026-07-03.
|
|
47458
|
+
version: "2026-07-03.3",
|
|
47459
47459
|
public: true,
|
|
47460
47460
|
audiences: ["human", "in_app_agent"],
|
|
47461
47461
|
stages: ["company_setup", "operating_rhythm"],
|
|
@@ -47499,7 +47499,7 @@ You can reopen prior threads, search thread titles and summaries, or start a new
|
|
|
47499
47499
|
|
|
47500
47500
|
New companies receive the governed AICOS foundation during provisioning. Existing companies can also set it up later from **Settings -> AICOS**. Owners and admins can see whether the foundation exists, repair it if needed, and choose the run location after setup.
|
|
47501
47501
|
|
|
47502
|
-
The repair action ensures the same structure new companies receive: a Founder/CEO root seat, an owner occupancy for stewardship, an **AI Chief of Staff** seat, the stock AICOS agent, and
|
|
47502
|
+
The repair action ensures the same structure new companies receive: a Founder/CEO root seat, an owner occupancy for stewardship, an **AI Chief of Staff** seat, the stock AICOS agent, and one active agent occupancy. It is idempotent; running it again repairs missing pieces instead of creating a second AICOS. If older setup attempts left more than one active AICOS occupancy, the repair path keeps the best current stock AICOS agent \u2014 live before dry-run, draft, or paused \u2014 and ends the extra AICOS occupancies so Settings, lane readiness, and chat resolve the same governed agent.
|
|
47503
47503
|
|
|
47504
47504
|
Settings is the infrastructure surface for AICOS. Use it to confirm foundation status, inspect the current lane, see whether a seat-scoped MCP token exists, and choose **Cloud**, **Runner**, or **MCP** when the server-side readiness checks allow it. The richer agent controls remain with the agent itself: open the AICOS seat from Settings or the agent fleet to manage Charter, tool permissions, approvals, go-live state, and run evidence.
|
|
47505
47505
|
|
|
@@ -48330,7 +48330,7 @@ External connectors are being rolled out provider by provider, conservatively (r
|
|
|
48330
48330
|
order: 48,
|
|
48331
48331
|
title: "CLI and MCP installation guide",
|
|
48332
48332
|
summary: "Install the public CLI, register remote token-backed MCP clients, and find the full command and tool catalog.",
|
|
48333
|
-
version: "2026-07-03.
|
|
48333
|
+
version: "2026-07-03.10",
|
|
48334
48334
|
public: true,
|
|
48335
48335
|
audiences: ["human", "cli", "mcp", "in_app_agent"],
|
|
48336
48336
|
stages: ["company_setup", "staffing"],
|
|
@@ -49063,6 +49063,8 @@ Several rows here are seat-operating commands (\`task.create\`, the \`signal.*\`
|
|
|
49063
49063
|
| \`rost_create_a_forge_github_installation_token\` | \`software_factory.github.installation_token.create\` | Mint a short-lived GitHub App installation token for one bound repository after policy evaluation. The token is returned once and never stored. | Tenant | Call with \`{"software_project_id":"<project-id>","repository_id":789,"requested_actions":["read"],"requested_automation_mode":"plan_only"}\`. |
|
|
49064
49064
|
| \`rost_list_forge_runner_capacity\` | \`software_factory.capacity.list\` | List Forge runner capacity observations (advisory scheduling input only, never an authority input). Read-only; requires the Forge add-on. | Tenant | Call with \`{}\` or \`{"runner_id":"<runner-id>"}\`. |
|
|
49065
49065
|
|
|
49066
|
+
The web Forge control room at \`/forge\` uses the same command path for project selection, build request creation/list/detail reads, runner capacity, configuration status, and Developer Team template install. The template install button deliberately stages a pending confirmation before durable seats, Skills, or authority grants are applied.
|
|
49067
|
+
|
|
49066
49068
|
#### Forge GitHub App access
|
|
49067
49069
|
|
|
49068
49070
|
Forge repository access is through a tenant-bound GitHub App installation, not through a human's ambient \`git\` or \`gh\` credentials. The server verifies GitHub webhook signatures before parsing payloads, resolves the installation and repository against active tenant bindings, records delivery ids for idempotency, and creates GitHub issue build requests only when an active repo binding and policy allow intake.
|
|
@@ -49410,7 +49412,7 @@ Set \`ROST_SKILL_INSTALL_ROOT\` only for a sandbox or CI override. Local copies
|
|
|
49410
49412
|
order: 55,
|
|
49411
49413
|
title: "Agent reference map",
|
|
49412
49414
|
summary: "Where CLI sessions, MCP clients, and in-app agents should retrieve {{brand}} guidance before recommending setup changes.",
|
|
49413
|
-
version: "2026-
|
|
49415
|
+
version: "2026-06-27.2",
|
|
49414
49416
|
public: true,
|
|
49415
49417
|
audiences: ["cli", "mcp", "in_app_agent"],
|
|
49416
49418
|
stages: ["company_setup", "graph_design", "charter_design", "staffing", "operating_rhythm"],
|
|
@@ -49907,7 +49909,7 @@ Keep agent scope tight at first. Approve more autonomy only after evidence. Use
|
|
|
49907
49909
|
order: 71,
|
|
49908
49910
|
title: "Confirmations and human gates guide",
|
|
49909
49911
|
summary: "How {{brand}} routes authority-changing work through human confirmation, and why agents never approve their own requests.",
|
|
49910
|
-
version: "2026-
|
|
49912
|
+
version: "2026-07-03.1",
|
|
49911
49913
|
public: true,
|
|
49912
49914
|
audiences: ["human", "cli", "mcp", "in_app_agent"],
|
|
49913
49915
|
stages: ["graph_design", "charter_design", "staffing", "operating_rhythm"],
|
|
@@ -49944,6 +49946,8 @@ A gated command does not mutate when an agent calls it. It returns a pending con
|
|
|
49944
49946
|
|
|
49945
49947
|
When an **agent** triggers a gate, {{brand}} also notifies the seat's steward (Slack with an email fallback) so the held action does not sit silent \u2014 a human is told a decision is waiting and given the approve link. A human pausing their own gated command does not self-notify. See the notifications guide.
|
|
49946
49948
|
|
|
49949
|
+
Approval replays are validated again before execution. If the stored confirmation input no longer matches the original command schema, the approval fails without consuming the pending confirmation or running the durable command; reject it and re-issue the gated action from the current product surface.
|
|
49950
|
+
|
|
49947
49951
|
\`\`\`bash
|
|
49948
49952
|
# Human approves a pending confirmation
|
|
49949
49953
|
{{cli}} command confirmation.approve --json '{"confirmation_id":"<confirmation-id>"}'
|
|
@@ -50169,7 +50173,7 @@ Agents may explain which setting is needed and why. They should not ask users to
|
|
|
50169
50173
|
order: 73,
|
|
50170
50174
|
title: "Members and invites guide",
|
|
50171
50175
|
summary: "How to invite humans into the company without confusing user access with seat accountability.",
|
|
50172
|
-
version: "2026-07-03.
|
|
50176
|
+
version: "2026-07-03.2",
|
|
50173
50177
|
public: true,
|
|
50174
50178
|
audiences: ["human", "cli", "mcp", "in_app_agent"],
|
|
50175
50179
|
stages: ["company_setup", "staffing"],
|
|
@@ -50248,7 +50252,7 @@ Every notification should include the seat, cause, evidence, and requested decis
|
|
|
50248
50252
|
order: 75,
|
|
50249
50253
|
title: "Local runner guide",
|
|
50250
50254
|
summary: "How local agent sessions and runner surfaces should operate through {{brand}} without bypassing Charters or audit.",
|
|
50251
|
-
version: "2026-07-03.
|
|
50255
|
+
version: "2026-07-03.2",
|
|
50252
50256
|
public: true,
|
|
50253
50257
|
audiences: ["human", "cli", "mcp", "in_app_agent"],
|
|
50254
50258
|
stages: ["staffing", "operating_rhythm"],
|
|
@@ -50280,13 +50284,13 @@ Use Local Runner when a Seat should run on a machine you control. Install it fro
|
|
|
50280
50284
|
|
|
50281
50285
|
Recommended paths:
|
|
50282
50286
|
|
|
50283
|
-
- **Always-on host:** \`{{cli}} runner install-service --name <runner-name> --execute\` installs a background service (macOS launchd user agent
|
|
50287
|
+
- **Always-on host:** \`{{cli}} runner install-service --name <runner-name> --execute\` installs a background service (macOS launchd user agent) that keeps the runner online. Manage it with \`{{cli}} runner start|stop|restart|status|logs|uninstall --name <runner-name>\`. On macOS the CLI tries both \`user/<uid>\` and \`gui/<uid>\` launchd domains because session behavior differs across console and SSH contexts; \`runner status --name <runner-name>\` prints the loaded domain.
|
|
50284
50288
|
- **Manual smoke:** \`{{cli}} runner serve --once\` heartbeats once and exits; \`{{cli}} runner serve --execute\` claims and executes runner work orders while it runs.
|
|
50285
50289
|
|
|
50286
50290
|
Two ways to authenticate and pair \u2014 both first-class, an agent can drive either entirely from the terminal:
|
|
50287
50291
|
|
|
50288
50292
|
- **CLI-native (agent):** \`{{cli}} login --device\` prints a code for one human OAuth approval; after that the session is stored locally and the agent runs unattended ("approve once, then autonomous"). Then \`{{cli}} runner serve\`/\`install-service\` pairs against your active company \u2014 an authenticated CLI can also self-issue a pairing code with \`runner.pairing.start\` and claim it.
|
|
50289
|
-
- **Web-guided (human):** issue a pairing code from Settings > Runners > Add a Runner, then on the host run \`{{cli}} runner serve --user-code <code>\`. The host stores only the runner bearer secret in an owner-only file and never logs in.
|
|
50293
|
+
- **Web-guided (human):** issue a pairing code from Settings > Runners > Add a Runner, then on the host run \`{{cli}} runner serve --user-code <code>\`. An explicit user code always claims that code, even if the host has an older local runner state file, so the browser and terminal do not accidentally point at different runner ids. The host stores only the runner bearer secret in an owner-only file and never logs in.
|
|
50290
50294
|
|
|
50291
50295
|
Headless and service accounts are supported first-class: when no usable OS keychain exists (for example a service or SSH account), the CLI stores the session in an owner-only file (directory 0700, file 0600) automatically \u2014 no development flag. That file holds only the CLI session token, never tenant secrets, API keys, or vault refs.
|
|
50292
50296
|
|
|
@@ -54927,11 +54931,13 @@ async function pairIfNeeded(client, fetchImpl, appUrl2, config2, io) {
|
|
|
54927
54931
|
config2.expectedTenantId = expectedTenantId;
|
|
54928
54932
|
}
|
|
54929
54933
|
}
|
|
54930
|
-
|
|
54931
|
-
|
|
54932
|
-
|
|
54934
|
+
if (config2.userCode === void 0) {
|
|
54935
|
+
const existing = await loadState(config2.stateFile, config2.expectedTenantId);
|
|
54936
|
+
if (existing) {
|
|
54937
|
+
io.stdout.write(`reusing paired runner ${existing.runner_id}
|
|
54933
54938
|
`);
|
|
54934
|
-
|
|
54939
|
+
return existing;
|
|
54940
|
+
}
|
|
54935
54941
|
}
|
|
54936
54942
|
let userCode;
|
|
54937
54943
|
if (config2.userCode !== void 0) {
|
|
@@ -55286,7 +55292,12 @@ async function installService(options) {
|
|
|
55286
55292
|
await writeFile3(paths.launchAgentPath, plist, { mode: 420 });
|
|
55287
55293
|
await bootoutQuietly(options.exec, options.uid, paths.launchAgentPath);
|
|
55288
55294
|
try {
|
|
55289
|
-
await options.exec
|
|
55295
|
+
const bootstrapped = await bootstrapService(options.exec, options.uid, paths.launchAgentPath);
|
|
55296
|
+
options.io.stdout.write(
|
|
55297
|
+
bootstrapped.alreadyLoaded ? `Runner service was already loaded in launchd domain ${bootstrapped.domain}.
|
|
55298
|
+
` : `Loaded runner service in launchd domain ${bootstrapped.domain}.
|
|
55299
|
+
`
|
|
55300
|
+
);
|
|
55290
55301
|
} catch (error51) {
|
|
55291
55302
|
options.io.stderr.write(
|
|
55292
55303
|
`Failed to load the runner service: ${redactForLog(error51 instanceof Error ? error51.message : String(error51))}
|
|
@@ -55321,15 +55332,13 @@ async function startService(options) {
|
|
|
55321
55332
|
);
|
|
55322
55333
|
return 1;
|
|
55323
55334
|
}
|
|
55335
|
+
let bootstrapped;
|
|
55324
55336
|
try {
|
|
55325
|
-
await options.exec
|
|
55326
|
-
|
|
55327
|
-
`);
|
|
55328
|
-
return 0;
|
|
55329
|
-
} catch (bootstrapError) {
|
|
55337
|
+
bootstrapped = await bootstrapService(options.exec, options.uid, paths.launchAgentPath);
|
|
55338
|
+
} catch {
|
|
55330
55339
|
try {
|
|
55331
|
-
await options.exec
|
|
55332
|
-
options.io.stdout.write(`Runner service ${label} was already loaded; restarted it.
|
|
55340
|
+
const target2 = await kickstartService(options.exec, options.uid, label);
|
|
55341
|
+
options.io.stdout.write(`Runner service ${label} was already loaded at ${target2}; restarted it.
|
|
55333
55342
|
`);
|
|
55334
55343
|
return 0;
|
|
55335
55344
|
} catch (kickstartError) {
|
|
@@ -55340,6 +55349,24 @@ async function startService(options) {
|
|
|
55340
55349
|
return 1;
|
|
55341
55350
|
}
|
|
55342
55351
|
}
|
|
55352
|
+
if (!bootstrapped.alreadyLoaded) {
|
|
55353
|
+
options.io.stdout.write(`Started runner service ${label} in launchd domain ${bootstrapped.domain}.
|
|
55354
|
+
`);
|
|
55355
|
+
return 0;
|
|
55356
|
+
}
|
|
55357
|
+
const target = `${bootstrapped.domain}/${label}`;
|
|
55358
|
+
try {
|
|
55359
|
+
await kickstartServiceTarget(options.exec, target);
|
|
55360
|
+
options.io.stdout.write(`Runner service ${label} was already loaded at ${target}; restarted it.
|
|
55361
|
+
`);
|
|
55362
|
+
return 0;
|
|
55363
|
+
} catch (kickstartError) {
|
|
55364
|
+
options.io.stderr.write(
|
|
55365
|
+
`Failed to start runner service ${label}: ${redactForLog(kickstartError instanceof Error ? kickstartError.message : String(kickstartError))}
|
|
55366
|
+
`
|
|
55367
|
+
);
|
|
55368
|
+
return 1;
|
|
55369
|
+
}
|
|
55343
55370
|
}
|
|
55344
55371
|
async function stopService(options) {
|
|
55345
55372
|
if (options.platform !== "darwin") {
|
|
@@ -55348,11 +55375,11 @@ async function stopService(options) {
|
|
|
55348
55375
|
const safeName = safeRunnerName(options.runnerName);
|
|
55349
55376
|
const paths = runnerServicePaths(options.homeDir, safeName);
|
|
55350
55377
|
const label = serviceLabel(safeName);
|
|
55351
|
-
|
|
55352
|
-
|
|
55378
|
+
const stopped = await bootoutAllDomains(options.exec, options.uid, paths.launchAgentPath);
|
|
55379
|
+
if (stopped) {
|
|
55353
55380
|
options.io.stdout.write(`Stopped runner service ${label}.
|
|
55354
55381
|
`);
|
|
55355
|
-
}
|
|
55382
|
+
} else {
|
|
55356
55383
|
options.io.stdout.write(`Runner service ${label} was not running.
|
|
55357
55384
|
`);
|
|
55358
55385
|
}
|
|
@@ -55365,8 +55392,8 @@ async function restartService(options) {
|
|
|
55365
55392
|
const safeName = safeRunnerName(options.runnerName);
|
|
55366
55393
|
const label = serviceLabel(safeName);
|
|
55367
55394
|
try {
|
|
55368
|
-
await options.exec
|
|
55369
|
-
options.io.stdout.write(`Restarted runner service ${label}.
|
|
55395
|
+
const target = await kickstartService(options.exec, options.uid, label);
|
|
55396
|
+
options.io.stdout.write(`Restarted runner service ${label} at ${target}.
|
|
55370
55397
|
`);
|
|
55371
55398
|
return 0;
|
|
55372
55399
|
} catch (error51) {
|
|
@@ -55386,13 +55413,14 @@ async function statusService(options) {
|
|
|
55386
55413
|
const label = serviceLabel(safeName);
|
|
55387
55414
|
const installed = await fileExists(paths.launchAgentPath);
|
|
55388
55415
|
try {
|
|
55389
|
-
const
|
|
55390
|
-
const state = extractLaunchdState(stdout);
|
|
55416
|
+
const printed = await printService(options.exec, options.uid, label);
|
|
55417
|
+
const state = extractLaunchdState(printed.stdout);
|
|
55391
55418
|
options.io.stdout.write(
|
|
55392
55419
|
`${[
|
|
55393
55420
|
`runner service: ${label}`,
|
|
55394
55421
|
`installed: ${installed ? "yes" : "no"}`,
|
|
55395
55422
|
`loaded: yes`,
|
|
55423
|
+
`domain: ${printed.target}`,
|
|
55396
55424
|
`state: ${state ?? "unknown"}`,
|
|
55397
55425
|
`plist: ${paths.launchAgentPath}`,
|
|
55398
55426
|
`logs: ${paths.logDir}`
|
|
@@ -55510,17 +55538,72 @@ function safeRunnerName(runnerName) {
|
|
|
55510
55538
|
function serviceLabel(safeName) {
|
|
55511
55539
|
return `com.${cliBrand.binName}.runner.${safeName}`;
|
|
55512
55540
|
}
|
|
55513
|
-
function
|
|
55514
|
-
return `user/${uid}
|
|
55541
|
+
function launchdDomains(uid) {
|
|
55542
|
+
return [`user/${uid}`, `gui/${uid}`];
|
|
55515
55543
|
}
|
|
55516
|
-
function
|
|
55517
|
-
return
|
|
55544
|
+
function serviceTargets(uid, label) {
|
|
55545
|
+
return launchdDomains(uid).map((domain2) => `${domain2}/${label}`);
|
|
55518
55546
|
}
|
|
55519
55547
|
async function bootoutQuietly(exec, uid, plistPath) {
|
|
55520
|
-
|
|
55521
|
-
|
|
55522
|
-
|
|
55548
|
+
await bootoutAllDomains(exec, uid, plistPath);
|
|
55549
|
+
}
|
|
55550
|
+
async function bootoutAllDomains(exec, uid, plistPath) {
|
|
55551
|
+
let bootedOut = false;
|
|
55552
|
+
for (const domain2 of launchdDomains(uid)) {
|
|
55553
|
+
try {
|
|
55554
|
+
await exec("launchctl", ["bootout", domain2, plistPath]);
|
|
55555
|
+
bootedOut = true;
|
|
55556
|
+
} catch {
|
|
55557
|
+
}
|
|
55558
|
+
}
|
|
55559
|
+
return bootedOut;
|
|
55560
|
+
}
|
|
55561
|
+
async function bootstrapService(exec, uid, plistPath) {
|
|
55562
|
+
const errors = [];
|
|
55563
|
+
for (const domain2 of launchdDomains(uid)) {
|
|
55564
|
+
try {
|
|
55565
|
+
await exec("launchctl", ["bootstrap", domain2, plistPath]);
|
|
55566
|
+
return { domain: domain2, alreadyLoaded: false };
|
|
55567
|
+
} catch (error51) {
|
|
55568
|
+
const message = error51 instanceof Error ? error51.message : String(error51);
|
|
55569
|
+
if (isLaunchdAlreadyLoadedError(message)) {
|
|
55570
|
+
return { domain: domain2, alreadyLoaded: true };
|
|
55571
|
+
}
|
|
55572
|
+
errors.push(`${domain2}: ${message}`);
|
|
55573
|
+
}
|
|
55574
|
+
}
|
|
55575
|
+
throw new Error(errors.join("; "));
|
|
55576
|
+
}
|
|
55577
|
+
function isLaunchdAlreadyLoadedError(message) {
|
|
55578
|
+
const normalized = message.toLowerCase();
|
|
55579
|
+
return normalized.includes("service is already loaded") || normalized.includes("service already loaded") || normalized.includes("already bootstrapped") || normalized.includes("already exists");
|
|
55580
|
+
}
|
|
55581
|
+
async function kickstartService(exec, uid, label) {
|
|
55582
|
+
const errors = [];
|
|
55583
|
+
for (const target of serviceTargets(uid, label)) {
|
|
55584
|
+
try {
|
|
55585
|
+
await kickstartServiceTarget(exec, target);
|
|
55586
|
+
return target;
|
|
55587
|
+
} catch (error51) {
|
|
55588
|
+
errors.push(`${target}: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
55589
|
+
}
|
|
55590
|
+
}
|
|
55591
|
+
throw new Error(errors.join("; "));
|
|
55592
|
+
}
|
|
55593
|
+
async function kickstartServiceTarget(exec, target) {
|
|
55594
|
+
await exec("launchctl", ["kickstart", "-k", target]);
|
|
55595
|
+
}
|
|
55596
|
+
async function printService(exec, uid, label) {
|
|
55597
|
+
const errors = [];
|
|
55598
|
+
for (const target of serviceTargets(uid, label)) {
|
|
55599
|
+
try {
|
|
55600
|
+
const { stdout } = await exec("launchctl", ["print", target]);
|
|
55601
|
+
return { target, stdout };
|
|
55602
|
+
} catch (error51) {
|
|
55603
|
+
errors.push(`${target}: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
55604
|
+
}
|
|
55523
55605
|
}
|
|
55606
|
+
throw new Error(errors.join("; "));
|
|
55524
55607
|
}
|
|
55525
55608
|
function unsupportedPlatform(io, platform2) {
|
|
55526
55609
|
io.stderr.write(
|