Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,105 @@ jobs:
- name: Emit exact-head production package report
run: npm run verify:production

# Install the PACKED tarball into an empty project and drive the CLI, on both
# release platforms. `npm pack --dry-run` in supply-chain proves a tarball can
# be built; it does not prove the tarball contains what the CLI needs at
# runtime. A module that compiles but is not covered by package.json "files"
# passes every other job here and throws MODULE_NOT_FOUND on a user's first
# command, which is the failure this job exists to catch.
clean-install:
name: Clean install (${{ matrix.os }})
needs: build-and-test
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- windows-latest
runs-on: ${{ matrix.os }}
timeout-minutes: 20
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
ref: ${{ github.event.pull_request.head.sha || github.sha }}

- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '24'
cache: 'npm'

- name: Install dependencies
run: npm ci --ignore-scripts --no-audit

- name: Build and pack
run: |
npm run build
npm pack --pack-destination "${RUNNER_TEMP}"
shell: bash

- name: Install the tarball into an empty project
run: |
set -euo pipefail
mkdir -p "${RUNNER_TEMP}/cleanroom"
cd "${RUNNER_TEMP}/cleanroom"
npm init -y > /dev/null
npm install --no-audit --no-fund "${RUNNER_TEMP}"/aether-agents-*.tgz
shell: bash

- name: Drive the CLI from the installed package
run: |
set -euo pipefail
cd "${RUNNER_TEMP}/cleanroom"
AGENT="node ./node_modules/aether-agents/dist/src/main.js"
$AGENT --version
$AGENT rc --help
$AGENT rc status | tee status.txt
$AGENT rc exposure | tee exposure.txt
# A headless runner has no desktop, so detection must say so rather
# than claiming a browser: BROWSER_HEADLESS on Linux, and on Windows
# whatever the image actually registers. Either way it must not be
# blank, and status must state the two NONE guarantees.
node -e "
const fs = require('node:fs');
const status = fs.readFileSync('status.txt', 'utf8');
const exposure = fs.readFileSync('exposure.txt', 'utf8');
const need = [
[status, /Viewer events\s+\d+ \/ \d+ available/, 'coverage fraction'],
[status, /Control\s+NONE/, 'Control NONE'],
[status, /Inbound socket\s+NONE/, 'Inbound socket NONE'],
[status, /Browser\s+BROWSER_[A-Z_]+/, 'a typed browser code'],
[exposure, /No terminal or tool control/, 'the no-control line'],
[exposure, /Never shared/, 'the never-shared list'],
];
for (const [text, pattern, what] of need) {
if (!pattern.test(text)) throw new Error('missing ' + what);
}
if (/13 \/ 13 available/.test(status) === false) {
throw new Error('producer coverage is not 13/13 in the installed package');
}
console.log('clean-install CLI surface verified');
"
shell: bash

- name: The installed package pulled in no dependencies
run: |
set -euo pipefail
cd "${RUNNER_TEMP}/cleanroom"
# aether-agents declares none; anything else here came from nowhere.
test "$(npm ls --omit=dev --depth=1 --json | node -e "
let raw='';
process.stdin.on('data', (c) => (raw += c));
process.stdin.on('end', () => {
const tree = JSON.parse(raw);
const agent = (tree.dependencies || {})['aether-agents'] || {};
console.log(Object.keys(agent.dependencies || {}).length);
});
")" = "0"
shell: bash

supply-chain:
runs-on: ubuntu-latest
timeout-minutes: 20
Expand Down
2 changes: 1 addition & 1 deletion docs/generated/commands.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!-- GENERATED FILE: run `npm run docs:generate`; do not edit by hand. -->
<!-- manifest-digest: sha256:7a10b8ff538bf0bb2872c51dbb4ed85fb21fc8cd9243cd1baac7b14035d681c3 -->
<!-- manifest-digest: sha256:f6f7f724a5341a6c3e9ee82a3fca45145f95013bc80f0a1fedf8621ae64acb50 -->
# Generated command reference

This reference is generated from the validated, versioned command manifest. Availability is evaluated at runtime; a listed command may still require authentication, a hosted capability, or local tooling.
Expand Down
10 changes: 10 additions & 0 deletions src/commands/cli_registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,16 @@ export const SHELL_RUNTIME_HANDLERS: Array<Pick<DispatchedCommand, "name" | "loa
return (ctx, argv, flags) => cmdDevice(ctx, argv, flags);
},
},
{
// Lane RC-02. A real dispatch-table entry so `aether rc ...` runs the
// command group instead of billing a chat turn. It owns --name and reads
// only the global flags off ctx.flags, exactly as `device` does.
name: "rc",
load: async () => {
const { cmdRc } = await import("./rc.js");
return (ctx, argv, flags) => cmdRc(ctx, argv, flags);
},
},
{
name: "doctor",
// doctor parses its own argv (parseDoctorArgs). It never saw these flags:
Expand Down
79 changes: 79 additions & 0 deletions src/commands/command_manifest_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,85 @@ export const COMMAND_MANIFEST_SOURCE: readonly CommandManifestEntry[] = [
"note": "SC-DEVICE-01: dev-only, default-off Windows device runtime (outbound-only telemetry, signed command execution, Job Object containment)."
}
},
{
"key": "shell:rc",
"surface": "shell",
"name": "rc",
"aliases": [],
"compatibilityAliases": [],
"deprecatedAliases": [],
"args": "<subcommand>",
"summary": "publish a viewer-only observation stream for this session",
"detailedHelp": "aether rc <subcommand>\npublish a viewer-only observation stream for this session\n\nstart [--name <name>] begin publishing\nstatus what is being published\nexposure what an observer can see\nviewers who is observing\noff end publishing and revoke the session\n\nObservation only. Run `aether rc exposure` for the full disclosure.",
"section": "Account",
"hidden": true,
"permissionClass": "account",
"availability": {
"state": "runtime-dependent",
"capabilityRequirements": []
},
"telemetryName": "shell.rc",
"acceptedGlobalFlags": [
"agent",
"all",
"apply",
"audit",
"available",
"ci",
"cwd",
"effort",
"help",
"interactive",
"json",
"junit",
"license-key",
"local",
"model",
"no-browser",
"no-log",
"no-skills",
"out",
"password",
"pool",
"quiet",
"repo",
"resume",
"scope",
"skill",
"swarm",
"test-cmd",
"token",
"username",
"version",
"with-token",
"worktree",
"yes"
],
"ownedFlags": {
"name": {
"type": "string"
}
},
"handler": {
"id": "handler:shell:rc",
"kind": "lazy",
"module": "src/commands/cli_registry.ts",
"symbol": "DISPATCH_COMMANDS"
},
"docs": {
"kind": "manifest",
"module": "src/commands/command_manifest_data.ts",
"symbol": "COMMAND_MANIFEST_SOURCE",
"target": "rc",
"usage": "aether rc <subcommand>",
"visible": false,
"disposition": "generated"
},
"release": {
"disposition": "new",
"note": "RC-02: outbound-only viewer host. Publishes bounded, redacted observation events; opens no listening socket and accepts no inbound command."
}
},
{
"key": "shell:login",
"surface": "shell",
Expand Down
Loading
Loading