@rosthq/cli 0.7.9 → 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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-manifest.d.ts","sourceRoot":"","sources":["../../src/generated/command-manifest.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAE3E,eAAO,MAAM,gBAAgB,EAAE,SAAS,oBAAoB,
|
|
1
|
+
{"version":3,"file":"command-manifest.d.ts","sourceRoot":"","sources":["../../src/generated/command-manifest.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAE3E,eAAO,MAAM,gBAAgB,EAAE,SAAS,oBAAoB,EAkN3D,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -46165,6 +46165,17 @@ var softwareGrantStatusSchema = external_exports2.enum(["active", "revoked"]);
|
|
|
46165
46165
|
var softwareConfigValueKindSchema = external_exports2.enum(["plain", "secret_ref"]);
|
|
46166
46166
|
var softwareCredentialRequestStatusSchema = external_exports2.enum(["pending", "fulfilled", "rejected", "canceled"]);
|
|
46167
46167
|
var softwareSecretAccessOperationSchema = external_exports2.enum(["use", "vercel_env_sync", "test_execution"]);
|
|
46168
|
+
var softwareProjectSummarySchema = external_exports2.object({
|
|
46169
|
+
id: uuid10,
|
|
46170
|
+
name: external_exports2.string().min(1),
|
|
46171
|
+
slug: external_exports2.string().min(1),
|
|
46172
|
+
base_branch: external_exports2.string().min(1),
|
|
46173
|
+
repo_ref: external_exports2.string().nullable()
|
|
46174
|
+
});
|
|
46175
|
+
var softwareProjectListInputSchema = external_exports2.object({}).strict();
|
|
46176
|
+
var softwareProjectListOutputSchema = external_exports2.object({
|
|
46177
|
+
projects: external_exports2.array(softwareProjectSummarySchema)
|
|
46178
|
+
});
|
|
46168
46179
|
var VAULT_REF_PROVIDER = /^(?:infisical|doppler|local-dev):\/\/\S+$/;
|
|
46169
46180
|
var RAW_SECRET_SUBSTRING = /sk-ant-|sk-proj-|sk-live-|BEGIN |PRIVATE KEY|api[_-]?key=|secret=/i;
|
|
46170
46181
|
var softwareVaultRefSchema = external_exports2.string().min(1).max(500).regex(VAULT_REF_PROVIDER, "vault_ref must be a provider URI, e.g. infisical://path, doppler://path, or local-dev://path").refine((value) => !RAW_SECRET_SUBSTRING.test(value), {
|
|
@@ -47444,11 +47455,11 @@ The Compass is drafted, then activated by a human through supersession.
|
|
|
47444
47455
|
order: 15,
|
|
47445
47456
|
title: "AICOS chat guide",
|
|
47446
47457
|
summary: "How the AI Chief of Staff chat works in the authenticated app shell and what it can safely do today.",
|
|
47447
|
-
version: "2026-07-03.
|
|
47458
|
+
version: "2026-07-03.3",
|
|
47448
47459
|
public: true,
|
|
47449
47460
|
audiences: ["human", "in_app_agent"],
|
|
47450
47461
|
stages: ["company_setup", "operating_rhythm"],
|
|
47451
|
-
relatedCommandIds: ["confirmation.approve", "onboarding.status", "graph.get", "seat.get"],
|
|
47462
|
+
relatedCommandIds: ["confirmation.approve", "onboarding.status", "graph.get", "seat.get", "mcp_token.list", "runner.list"],
|
|
47452
47463
|
legal: {
|
|
47453
47464
|
publicRisk: "low",
|
|
47454
47465
|
notes: [
|
|
@@ -47484,6 +47495,14 @@ Each thread has a purpose:
|
|
|
47484
47495
|
|
|
47485
47496
|
You can reopen prior threads, search thread titles and summaries, or start a new one. Session history is stored in tenant-scoped conversation tables so chat history is not reconstructed from analytics, events, or run logs.
|
|
47486
47497
|
|
|
47498
|
+
## Set up AICOS for an existing company
|
|
47499
|
+
|
|
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
|
+
|
|
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
|
+
|
|
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
|
+
|
|
47487
47506
|
## What context AICOS receives
|
|
47488
47507
|
|
|
47489
47508
|
Each turn carries server-normalized page context: route template, current path, safe search state, selected seat or object ids when authorized, and onboarding state when relevant. The server derives tenant and user authority from the authenticated session. Client-supplied tenant context is never accepted as authority.
|
|
@@ -48311,7 +48330,7 @@ External connectors are being rolled out provider by provider, conservatively (r
|
|
|
48311
48330
|
order: 48,
|
|
48312
48331
|
title: "CLI and MCP installation guide",
|
|
48313
48332
|
summary: "Install the public CLI, register remote token-backed MCP clients, and find the full command and tool catalog.",
|
|
48314
|
-
version: "2026-07-03.
|
|
48333
|
+
version: "2026-07-03.10",
|
|
48315
48334
|
public: true,
|
|
48316
48335
|
audiences: ["human", "cli", "mcp", "in_app_agent"],
|
|
48317
48336
|
stages: ["company_setup", "staffing"],
|
|
@@ -49024,6 +49043,7 @@ Several rows here are seat-operating commands (\`task.create\`, the \`signal.*\`
|
|
|
49024
49043
|
| \`rost_revoke_skill_from_seat\` | \`skill.revoke_from_seat\` | Human-gated revocation that stops future Skill use without deleting historical activations. | Tenant-admin | Call with \`{"assignment_id":"<assignment-id>"}\`; non-interactive callers receive a confirmation handoff. |
|
|
49025
49044
|
| \`rost_list_model_catalog\` | \`model.catalog\` | List guided model tiers \u2014 recommendations, token prices, cost bands, best-fit work, and model ids for \`--model\`. | Tenant | Call with \`{}\`. |
|
|
49026
49045
|
| \`rost_create_a_forge_build_request\` | \`software_factory.request.create\` | Open a governed Forge build request against a connected software project; records the request plus its initial intake phase run. Requires the Forge add-on; the title is untrusted display text. | Tenant | Call with \`{"software_project_id":"<project-id>","title":"Add invoice export"}\`. |
|
|
49046
|
+
| \`rost_list_forge_projects\` | \`software_factory.project.list\` | List active Forge software projects so a tenant can choose a project for build requests, GitHub repository bindings, and config. | Tenant | Call with \`{}\`; use the returned \`id\` as \`software_project_id\`. |
|
|
49027
49047
|
| \`rost_list_forge_build_requests\` | \`software_factory.request.list\` | The Forge control-room board: build requests with status, current phase, and risk. Read-only; requires the Forge add-on. | Tenant | Call with \`{}\` or \`{"limit":20}\`. |
|
|
49028
49048
|
| \`rost_show_a_forge_build_request\` | \`software_factory.request.show\` | The Forge request detail: the request, current phase, phase-run history, and gates. Read-only; requires the Forge add-on. | Tenant | Call with \`{"build_request_id":"<request-id>"}\`. |
|
|
49029
49049
|
| \`rost_advance_a_forge_build_request_phase\` | \`software_factory.phase.advance\` | Advance a build request to its next phase; the server enforces the closed phase state machine and rejects an illegal transition. | Tenant | Call with \`{"build_request_id":"<request-id>","to_phase":"discovery_scoping"}\`. |
|
|
@@ -49038,18 +49058,20 @@ Several rows here are seat-operating commands (\`task.create\`, the \`signal.*\`
|
|
|
49038
49058
|
| \`rost_list_forge_secret_requests\` | \`software_factory.secret_request.list\` | List missing-secret requests and their approval Task ids/statuses. It returns request metadata only \u2014 no secret values and no vault refs. | Tenant | Call with \`{}\` or \`{"status":"pending"}\`. |
|
|
49039
49059
|
| \`rost_grant_a_forge_secret\` | \`software_factory.secret.grant\` | A human grants a seat scoped access to a project secret by vault ref (Postgres stores only the pointer, never secret material). Owner-only and human-gated. | Tenant-admin | Call with \`{"software_project_id":"<project-id>","environment":"production","seat_id":"<seat-id>","action":"vercel.env.sync","key_name":"OPENAI_API_KEY","vault_ref":"infisical://prod/OPENAI_API_KEY"}\`. |
|
|
49040
49060
|
| \`rost_revoke_a_forge_secret_grant\` | \`software_factory.secret.revoke\` | Revoke a Forge secret grant (teardown \u2014 cut a compromised seat's access immediately). Owner-only and human-gated. | Tenant-admin | Call with \`{"grant_id":"<grant-id>"}\`; non-interactive callers receive a confirmation handoff. |
|
|
49041
|
-
| \`rost_bind_a_forge_github_installation\` | \`software_factory.github.installation.bind\` | Bind a GitHub App installation and selected repositories to Forge projects. Owner-only and human-gated. | Tenant-admin |
|
|
49061
|
+
| \`rost_bind_a_forge_github_installation\` | \`software_factory.github.installation.bind\` | Bind a GitHub App installation and selected repositories to Forge projects. Owner-only and human-gated; the settings UI uses the same command after GitHub redirects back with an installation id. | Tenant-admin | First run \`rost command software_factory.project.list --json '{}'\` to choose a project id. Then call \`{"installation_id":123,"account_login":"acme","account_id":456,"account_type":"Organization","repositories":[{"software_project_id":"<project-id>","repository_id":789,"repository_name":"app","repository_full_name":"acme/app","private":true,"default_branch":"main","permissions":{"metadata":"read","contents":"write","pull_requests":"write","issues":"write"}}]}\`. |
|
|
49042
49062
|
| \`rost_set_a_forge_github_automation_policy\` | \`software_factory.github.policy.upsert\` | Set the server-side GitHub automation policy: allowed actions, automation-mode ceiling, and operations requiring humans. Owner-only and human-gated. | Tenant-admin | Call with \`{"software_project_id":"<project-id>","automation_mode_ceiling":"pr_only","allowed_actions":["webhook_intake","installation_token"],"requires_human_for":["deploy_production"]}\`. |
|
|
49043
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"}\`. |
|
|
49044
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>"}\`. |
|
|
49045
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
|
+
|
|
49046
49068
|
#### Forge GitHub App access
|
|
49047
49069
|
|
|
49048
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.
|
|
49049
49071
|
|
|
49050
49072
|
Installation tokens are short lived and are not stored. The durable record is audit metadata: installation id, repository id, requested action, policy decision, reason, and related Forge request when one exists. GitHub issue titles, labels, and bodies are treated as untrusted source content; labels may request an automation mode, but only server-side Forge automation policy can allow \`pr_only\`, \`merge_after_checks\`, \`deploy_preview\`, or \`deploy_production\`. Production deploy remains human-gated.
|
|
49051
49073
|
|
|
49052
|
-
The Forge GitHub App itself is org-owned. App private key, webhook secret, and client secret values are stored through the vault and
|
|
49074
|
+
The Forge GitHub App itself is org-owned. App private key, webhook secret, and client secret values are platform-owned ROST operator credentials stored through the vault's reserved ROST system namespace, not through a customer tenant namespace or a tenant UUID deployment variable. Manifest conversion and manual secret storage also require the app-level \`GITHUB_APP_OPERATOR_EMAILS\` allowlist, which should contain only approved ROST platform operator emails. Deployment config carries only refs (\`GITHUB_APP_PRIVATE_KEY_REF\`, \`GITHUB_APP_WEBHOOK_SECRET_REF\`, \`GITHUB_APP_CLIENT_SECRET_REF\`); raw secret env vars are local/legacy compatibility only. The dogfood app is \`ROST Forge\` under \`agenticoperatingsystem\` with App ID \`4208495\` and Client ID \`Iv23liImH7qlBvXYQ0Wx\`. The base app omits \`administration\` and \`workflows\`; elevated repo creation or workflow mutation needs a separate human-approved power path.
|
|
49053
49075
|
|
|
49054
49076
|
### Seat-scoped operating tools
|
|
49055
49077
|
|
|
@@ -49390,7 +49412,7 @@ Set \`ROST_SKILL_INSTALL_ROOT\` only for a sandbox or CI override. Local copies
|
|
|
49390
49412
|
order: 55,
|
|
49391
49413
|
title: "Agent reference map",
|
|
49392
49414
|
summary: "Where CLI sessions, MCP clients, and in-app agents should retrieve {{brand}} guidance before recommending setup changes.",
|
|
49393
|
-
version: "2026-
|
|
49415
|
+
version: "2026-06-27.2",
|
|
49394
49416
|
public: true,
|
|
49395
49417
|
audiences: ["cli", "mcp", "in_app_agent"],
|
|
49396
49418
|
stages: ["company_setup", "graph_design", "charter_design", "staffing", "operating_rhythm"],
|
|
@@ -49887,7 +49909,7 @@ Keep agent scope tight at first. Approve more autonomy only after evidence. Use
|
|
|
49887
49909
|
order: 71,
|
|
49888
49910
|
title: "Confirmations and human gates guide",
|
|
49889
49911
|
summary: "How {{brand}} routes authority-changing work through human confirmation, and why agents never approve their own requests.",
|
|
49890
|
-
version: "2026-
|
|
49912
|
+
version: "2026-07-03.1",
|
|
49891
49913
|
public: true,
|
|
49892
49914
|
audiences: ["human", "cli", "mcp", "in_app_agent"],
|
|
49893
49915
|
stages: ["graph_design", "charter_design", "staffing", "operating_rhythm"],
|
|
@@ -49924,6 +49946,8 @@ A gated command does not mutate when an agent calls it. It returns a pending con
|
|
|
49924
49946
|
|
|
49925
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.
|
|
49926
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
|
+
|
|
49927
49951
|
\`\`\`bash
|
|
49928
49952
|
# Human approves a pending confirmation
|
|
49929
49953
|
{{cli}} command confirmation.approve --json '{"confirmation_id":"<confirmation-id>"}'
|
|
@@ -50149,7 +50173,7 @@ Agents may explain which setting is needed and why. They should not ask users to
|
|
|
50149
50173
|
order: 73,
|
|
50150
50174
|
title: "Members and invites guide",
|
|
50151
50175
|
summary: "How to invite humans into the company without confusing user access with seat accountability.",
|
|
50152
|
-
version: "2026-07-03.
|
|
50176
|
+
version: "2026-07-03.2",
|
|
50153
50177
|
public: true,
|
|
50154
50178
|
audiences: ["human", "cli", "mcp", "in_app_agent"],
|
|
50155
50179
|
stages: ["company_setup", "staffing"],
|
|
@@ -50228,7 +50252,7 @@ Every notification should include the seat, cause, evidence, and requested decis
|
|
|
50228
50252
|
order: 75,
|
|
50229
50253
|
title: "Local runner guide",
|
|
50230
50254
|
summary: "How local agent sessions and runner surfaces should operate through {{brand}} without bypassing Charters or audit.",
|
|
50231
|
-
version: "2026-07-03.
|
|
50255
|
+
version: "2026-07-03.2",
|
|
50232
50256
|
public: true,
|
|
50233
50257
|
audiences: ["human", "cli", "mcp", "in_app_agent"],
|
|
50234
50258
|
stages: ["staffing", "operating_rhythm"],
|
|
@@ -50260,13 +50284,13 @@ Use Local Runner when a Seat should run on a machine you control. Install it fro
|
|
|
50260
50284
|
|
|
50261
50285
|
Recommended paths:
|
|
50262
50286
|
|
|
50263
|
-
- **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.
|
|
50264
50288
|
- **Manual smoke:** \`{{cli}} runner serve --once\` heartbeats once and exits; \`{{cli}} runner serve --execute\` claims and executes runner work orders while it runs.
|
|
50265
50289
|
|
|
50266
50290
|
Two ways to authenticate and pair \u2014 both first-class, an agent can drive either entirely from the terminal:
|
|
50267
50291
|
|
|
50268
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.
|
|
50269
|
-
- **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.
|
|
50270
50294
|
|
|
50271
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.
|
|
50272
50296
|
|
|
@@ -52216,6 +52240,7 @@ var COMMAND_MANIFEST = [
|
|
|
52216
52240
|
{ "id": "software_factory.github.installation.bind", "namespace": "software_factory", "action": "github.installation.bind", "title": "Bind a Forge GitHub installation", "description": "Bind a signed GitHub App installation and selected repositories to Forge projects. Owner-only and human-gated; webhook payloads never supply tenant authority.", "requiredScope": "tenant_admin", "confirmation": "human_required", "exposeOverMcp": true, "fields": [{ "name": "app_slug", "flag": "app-slug", "type": "string", "required": false }, { "name": "installation_id", "flag": "installation-id", "type": "integer", "required": true }, { "name": "account_login", "flag": "account-login", "type": "string", "required": true }, { "name": "account_id", "flag": "account-id", "type": "integer", "required": true }, { "name": "account_type", "flag": "account-type", "type": "string", "required": true }], "hasComplexInput": true, "help": "Bind a GitHub App installation and selected repositories to Forge projects. Owner-only and human-gated." },
|
|
52217
52241
|
{ "id": "software_factory.github.policy.upsert", "namespace": "software_factory", "action": "github.policy.upsert", "title": "Set a Forge GitHub automation policy", "description": "Set the server-side policy for GitHub actions and automation-mode ceilings. Owner-only and human-gated; production deploy remains human-gated.", "requiredScope": "tenant_admin", "confirmation": "human_required", "exposeOverMcp": true, "fields": [{ "name": "software_project_id", "flag": "software-project-id", "type": "string", "required": true }, { "name": "authority_profile_id", "flag": "authority-profile-id", "type": "string", "required": false }, { "name": "automation_mode_ceiling", "flag": "automation-mode-ceiling", "type": "enum", "required": false, "enumValues": ["plan_only", "pr_only", "merge_after_checks", "deploy_preview", "deploy_production"] }, { "name": "allowed_actions", "flag": "allowed-actions", "type": "array", "required": true, "itemType": "string" }, { "name": "requires_human_for", "flag": "requires-human-for", "type": "array", "required": true, "itemType": "string" }], "hasComplexInput": false, "help": "Set Forge's server-side GitHub automation policy for actions, mode ceilings, and human-gated operations." },
|
|
52218
52242
|
{ "id": "software_factory.phase.advance", "namespace": "software_factory", "action": "phase.advance", "title": "Advance a Forge build request phase", "description": "Advance a build request to the next phase, enforcing the closed phase state machine server-side (an illegal transition is rejected). Writes a phase-run row and updates the current phase. Entitlement-gated.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [{ "name": "build_request_id", "flag": "build-request-id", "type": "string", "required": true }, { "name": "to_phase", "flag": "to-phase", "type": "enum", "required": true, "enumValues": ["intake", "discovery_scoping", "plan_review", "implementation", "plan_conformance_review", "security_review", "qa_verification", "release_preview", "merge_or_deploy_gate", "closeout"] }, { "name": "owning_seat_id", "flag": "owning-seat-id", "type": "string", "required": false }, { "name": "note", "flag": "note", "type": "string", "required": false }], "hasComplexInput": false, "help": "Advance a build request to its next phase; the server enforces the closed phase state machine and rejects an illegal transition." },
|
|
52243
|
+
{ "id": "software_factory.project.list", "namespace": "software_factory", "action": "project.list", "title": "List Forge projects", "description": "List active Forge software projects so a tenant can choose a project for build requests, GitHub repository bindings, and config. Read-only and entitlement-gated.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [], "hasComplexInput": false, "help": "List active Forge software projects so a tenant can choose a project for build requests, GitHub repository bindings, and config. Read-only; requires the Forge add-on." },
|
|
52219
52244
|
{ "id": "software_factory.request.create", "namespace": "software_factory", "action": "request.create", "title": "Create a Forge build request", "description": "Open a governed Forge build request against a connected software project. Records the request plus its initial intake phase run. Entitlement-gated (Forge add-on); the title is untrusted display text, never an instruction.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [{ "name": "software_project_id", "flag": "software-project-id", "type": "string", "required": true }, { "name": "title", "flag": "title", "type": "string", "required": true }, { "name": "source_channel", "flag": "source-channel", "type": "enum", "required": false, "enumValues": ["ui", "cli", "github_issue", "linear", "api"] }, { "name": "source_ref", "flag": "source-ref", "type": "string", "required": false }], "hasComplexInput": true, "help": "Open a governed Forge build request against a connected software project; the title is untrusted display text. Requires the Forge add-on." },
|
|
52220
52245
|
{ "id": "software_factory.request.list", "namespace": "software_factory", "action": "request.list", "title": "List Forge build requests", "description": "The Forge control-room board: the tenant's build requests with status, current phase, and risk/automation mode. Read-only, entitlement-gated.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [{ "name": "limit", "flag": "limit", "type": "integer", "required": false }], "hasComplexInput": false, "help": "List Forge build requests (the control-room board) with status, current phase, and risk. Read-only; requires the Forge add-on." },
|
|
52221
52246
|
{ "id": "software_factory.request.show", "namespace": "software_factory", "action": "request.show", "title": "Show a Forge build request", "description": "The Forge request detail: the build request, its current phase, phase-run history, and gates. Read-only, entitlement-gated, tenant-scoped.", "requiredScope": "tenant", "confirmation": "none", "exposeOverMcp": true, "fields": [{ "name": "build_request_id", "flag": "build-request-id", "type": "string", "required": true }], "hasComplexInput": false, "help": "Show a Forge build request's detail: current phase, phase-run history, and gates. Read-only; requires the Forge add-on." },
|
|
@@ -54906,11 +54931,13 @@ async function pairIfNeeded(client, fetchImpl, appUrl2, config2, io) {
|
|
|
54906
54931
|
config2.expectedTenantId = expectedTenantId;
|
|
54907
54932
|
}
|
|
54908
54933
|
}
|
|
54909
|
-
|
|
54910
|
-
|
|
54911
|
-
|
|
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}
|
|
54912
54938
|
`);
|
|
54913
|
-
|
|
54939
|
+
return existing;
|
|
54940
|
+
}
|
|
54914
54941
|
}
|
|
54915
54942
|
let userCode;
|
|
54916
54943
|
if (config2.userCode !== void 0) {
|
|
@@ -55265,7 +55292,12 @@ async function installService(options) {
|
|
|
55265
55292
|
await writeFile3(paths.launchAgentPath, plist, { mode: 420 });
|
|
55266
55293
|
await bootoutQuietly(options.exec, options.uid, paths.launchAgentPath);
|
|
55267
55294
|
try {
|
|
55268
|
-
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
|
+
);
|
|
55269
55301
|
} catch (error51) {
|
|
55270
55302
|
options.io.stderr.write(
|
|
55271
55303
|
`Failed to load the runner service: ${redactForLog(error51 instanceof Error ? error51.message : String(error51))}
|
|
@@ -55300,15 +55332,13 @@ async function startService(options) {
|
|
|
55300
55332
|
);
|
|
55301
55333
|
return 1;
|
|
55302
55334
|
}
|
|
55335
|
+
let bootstrapped;
|
|
55303
55336
|
try {
|
|
55304
|
-
await options.exec
|
|
55305
|
-
|
|
55306
|
-
`);
|
|
55307
|
-
return 0;
|
|
55308
|
-
} catch (bootstrapError) {
|
|
55337
|
+
bootstrapped = await bootstrapService(options.exec, options.uid, paths.launchAgentPath);
|
|
55338
|
+
} catch {
|
|
55309
55339
|
try {
|
|
55310
|
-
await options.exec
|
|
55311
|
-
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.
|
|
55312
55342
|
`);
|
|
55313
55343
|
return 0;
|
|
55314
55344
|
} catch (kickstartError) {
|
|
@@ -55319,6 +55349,24 @@ async function startService(options) {
|
|
|
55319
55349
|
return 1;
|
|
55320
55350
|
}
|
|
55321
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
|
+
}
|
|
55322
55370
|
}
|
|
55323
55371
|
async function stopService(options) {
|
|
55324
55372
|
if (options.platform !== "darwin") {
|
|
@@ -55327,11 +55375,11 @@ async function stopService(options) {
|
|
|
55327
55375
|
const safeName = safeRunnerName(options.runnerName);
|
|
55328
55376
|
const paths = runnerServicePaths(options.homeDir, safeName);
|
|
55329
55377
|
const label = serviceLabel(safeName);
|
|
55330
|
-
|
|
55331
|
-
|
|
55378
|
+
const stopped = await bootoutAllDomains(options.exec, options.uid, paths.launchAgentPath);
|
|
55379
|
+
if (stopped) {
|
|
55332
55380
|
options.io.stdout.write(`Stopped runner service ${label}.
|
|
55333
55381
|
`);
|
|
55334
|
-
}
|
|
55382
|
+
} else {
|
|
55335
55383
|
options.io.stdout.write(`Runner service ${label} was not running.
|
|
55336
55384
|
`);
|
|
55337
55385
|
}
|
|
@@ -55344,8 +55392,8 @@ async function restartService(options) {
|
|
|
55344
55392
|
const safeName = safeRunnerName(options.runnerName);
|
|
55345
55393
|
const label = serviceLabel(safeName);
|
|
55346
55394
|
try {
|
|
55347
|
-
await options.exec
|
|
55348
|
-
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}.
|
|
55349
55397
|
`);
|
|
55350
55398
|
return 0;
|
|
55351
55399
|
} catch (error51) {
|
|
@@ -55365,13 +55413,14 @@ async function statusService(options) {
|
|
|
55365
55413
|
const label = serviceLabel(safeName);
|
|
55366
55414
|
const installed = await fileExists(paths.launchAgentPath);
|
|
55367
55415
|
try {
|
|
55368
|
-
const
|
|
55369
|
-
const state = extractLaunchdState(stdout);
|
|
55416
|
+
const printed = await printService(options.exec, options.uid, label);
|
|
55417
|
+
const state = extractLaunchdState(printed.stdout);
|
|
55370
55418
|
options.io.stdout.write(
|
|
55371
55419
|
`${[
|
|
55372
55420
|
`runner service: ${label}`,
|
|
55373
55421
|
`installed: ${installed ? "yes" : "no"}`,
|
|
55374
55422
|
`loaded: yes`,
|
|
55423
|
+
`domain: ${printed.target}`,
|
|
55375
55424
|
`state: ${state ?? "unknown"}`,
|
|
55376
55425
|
`plist: ${paths.launchAgentPath}`,
|
|
55377
55426
|
`logs: ${paths.logDir}`
|
|
@@ -55489,17 +55538,72 @@ function safeRunnerName(runnerName) {
|
|
|
55489
55538
|
function serviceLabel(safeName) {
|
|
55490
55539
|
return `com.${cliBrand.binName}.runner.${safeName}`;
|
|
55491
55540
|
}
|
|
55492
|
-
function
|
|
55493
|
-
return `user/${uid}
|
|
55541
|
+
function launchdDomains(uid) {
|
|
55542
|
+
return [`user/${uid}`, `gui/${uid}`];
|
|
55494
55543
|
}
|
|
55495
|
-
function
|
|
55496
|
-
return
|
|
55544
|
+
function serviceTargets(uid, label) {
|
|
55545
|
+
return launchdDomains(uid).map((domain2) => `${domain2}/${label}`);
|
|
55497
55546
|
}
|
|
55498
55547
|
async function bootoutQuietly(exec, uid, plistPath) {
|
|
55499
|
-
|
|
55500
|
-
|
|
55501
|
-
|
|
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
|
+
}
|
|
55502
55605
|
}
|
|
55606
|
+
throw new Error(errors.join("; "));
|
|
55503
55607
|
}
|
|
55504
55608
|
function unsupportedPlatform(io, platform2) {
|
|
55505
55609
|
io.stderr.write(
|