@catalyst-cloud/cli 0.16.32 → 0.16.34
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/CHANGELOG.md +12 -0
- package/README.md +20 -1
- package/dist/approved-release.js +3 -4
- package/dist/args.js +25 -1
- package/dist/capabilities.js +2 -0
- package/dist/cli.js +36 -46
- package/dist/codex-attribution.js +685 -0
- package/dist/codex-env.js +222 -0
- package/dist/config.js +4 -0
- package/dist/runner-auto-update.js +5 -3
- package/dist/runner-update.js +48 -16
- package/dist/update-inventory.js +13 -28
- package/dist/update-plugin.js +181 -58
- package/dist/update-skill-source.js +145 -0
- package/dist/update-skill-state.js +175 -0
- package/dist/update-skills.js +247 -48
- package/dist/update.js +62 -52
- package/package.json +1 -1
- package/skills/catalyst-github/SKILL.md +1 -1
- package/skills/catalyst-linear/SKILL.md +1 -1
- package/skills/catalyst-onboard/SKILL.md +1 -1
- package/skills/catalyst-onboard/references/skill-sources.md +5 -4
- package/skills/run-this-project/SKILL.md +1 -1
- package/skills/unstick/SKILL.md +1 -1
- package/skills/what-needs-me/SKILL.md +1 -1
- package/skills/what-this-repo-needs/SKILL.md +1 -1
- package/skills/whats-happening/SKILL.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.16.34
|
|
4
|
+
|
|
5
|
+
`catalyst runner update` now tells Catalyst how its previous run went when it reads the approved release. A self-hosted machine that keeps waiting, refusing or rolling back an update shows up without anyone reading its local log. It sends a short report: the outcome, its reason code, the release it runs, the release that run was offered, when it ran and the CLI version. `--check` sends nothing, and nothing beyond that fixed set of words leaves the machine. When a self-hosted Mac cannot re-check its private storage during an update, the update log now names the reason instead of a generic failure.
|
|
6
|
+
|
|
7
|
+
`catalyst update` now puts the Cloud and Dev skills packs and the Cloud Claude plugin at the exact commits the approved release names. Before, a matching version number read as current even from a different commit, and a pack ahead of the approved release stayed ahead. The Cloud plugin moves through Claude Code from the same verified copy, and the CLI no longer copies its bundled skills over an approved installation when it starts.
|
|
8
|
+
|
|
9
|
+
`catalyst codex-env` adds the AI account and the machine name to the telemetry attributes a Codex launch reports, so its usage can be summed per account. `--print` prints the value, `--apply` sets it for apps opened from the Dock on macOS, and `--refresh` fetches the workspace's AI accounts again. `catalyst setup` now installs this for you when Codex is on the machine: a small `codex` wrapper in `~/.zshrc` and `~/.bashrc` for terminal launches, and on macOS a login item that covers Codex opened from the Dock. If the CLI cannot answer, Codex starts exactly as before. `catalyst setup --no-shell-hook` skips both, `catalyst setup --remove-codex-attribution` removes them, and `catalyst status` says whether they are installed.
|
|
10
|
+
|
|
11
|
+
## 0.16.33
|
|
12
|
+
|
|
13
|
+
On a self-hosted machine, `catalyst update` now sees the approved versions of the CLI and the Cloud and Dev skills, and moves them. Before this release it reported "no approved version" for all three on every self-hosted machine and left them where they were. The runner images were not affected.
|
|
14
|
+
|
|
3
15
|
## 0.16.32
|
|
4
16
|
|
|
5
17
|
The 15-minute release check now moves a self-hosted machine to a newer runner release at set times of day, 03:00, 11:00, 16:00 and 22:00 in the machine's time zone, instead of whenever a release is approved. `catalyst update policy windows 06:00,18:00 --time-zone America/Chicago` sets your own times, `catalyst update policy windows default` goes back to these, and `catalyst update policy` lists them. `catalyst runner update` and `catalyst update` still apply a release at once. A machine that an earlier CLI moved onto the current release now records what it needs to take the next release in place, so it no longer waits for one more release first.
|
package/README.md
CHANGED
|
@@ -138,6 +138,14 @@ catalyst ready --onboarding --json
|
|
|
138
138
|
|
|
139
139
|
The dry run writes no files. `--only <step>` runs one step and reports its scope separately from full onboarding. Exit 10 means a failed step, 11 means waiting, and 12 means a guard refused the action. The private receipt is `install/last-run.json` under your machine's Catalyst state directory; credentials stay in the login config. A fake HOME reports old services and keeps them intact.
|
|
140
140
|
|
|
141
|
+
### Codex launches name their coding account
|
|
142
|
+
|
|
143
|
+
When Codex is on this computer (a `codex` command on your PATH, or `Codex.app` in `/Applications` or `~/Applications`), setup adds a `codex` shell function to `~/.zshrc` and `~/.bashrc`, between the lines `# >>> catalyst codex attribution >>>` and `# <<< catalyst codex attribution <<<`. It writes to each of those files that exists, and creates one only for your login shell (`$SHELL`), so a Mac that uses only zsh gets no `~/.bashrc`. Bash on macOS reads `~/.bash_profile` rather than `~/.bashrc`, so if you use bash and your `~/.bash_profile` does not already source `~/.bashrc`, add the line `[ -f ~/.bashrc ] && . ~/.bashrc` to it. Each time you run `codex`, the function asks `catalyst codex-env --print` which coding account the Codex home in use (`$CODEX_HOME`, else `~/.codex`) is signed in to, and passes the answer to that one launch as `OTEL_RESOURCE_ATTRIBUTES`. The answer comes from a local cache, so a launch never waits on the network. Running setup again replaces the block in place. Setup leaves a file alone, and says why, when it already defines `codex` as a function or an alias of yours, or when it is a link to a file outside your home folder. A link to a file inside your home folder is followed, and the file keeps its permissions.
|
|
144
|
+
|
|
145
|
+
On a Mac, setup also installs the `dev.catalystcloud.codex-attribution` LaunchAgent. It runs `catalyst codex-env --apply` when you log in, and again whenever Codex signs in to another account in its default home, so apps you start from the Dock or Finder, the Codex desktop app included, carry the same attributes. An app that is already open keeps the environment it started with. It picks up a change the next time it starts. On Linux, setup adds the shell function only. Without Codex, setup adds nothing and says it skipped this. Run `catalyst setup` again after you install Codex to add it.
|
|
146
|
+
|
|
147
|
+
`catalyst status` ends with one line that says whether this is installed, which coding account the Codex home resolves to, and how old the cached account list is. `catalyst setup --no-shell-hook` skips all of it. `catalyst setup --remove-codex-attribution` removes it and runs nothing else. Each file goes back to exactly what it was before the block was added, the LaunchAgent is unloaded and deleted, and the two attributes it set (the coding account and the machine name) are taken back out of the launch environment. Attributes you set there yourself are kept. A fake HOME gets none of this.
|
|
148
|
+
|
|
141
149
|
### Headless setup (CI, image builds, agent VMs)
|
|
142
150
|
|
|
143
151
|
`catalyst onboard --headless` (or `CATALYST_ONBOARD_HEADLESS=1`) is for a machine with no person at it. It assumes every browser approval already happened: the person's key exists, and Linear and GitHub are connected for the workspace and the person. It never prompts, never opens a browser and never starts the device sign-in. Every input comes from a flag, an environment variable or a file:
|
|
@@ -298,6 +306,7 @@ The package pins the contract range `1.x || 2.x`, recorded in `package.json` und
|
|
|
298
306
|
- `~/.config/catalyst-cloud/customer.json`, written with mode `0600`, holding your personal key, who you are, and the CLI path.
|
|
299
307
|
- `~/.config/catalyst-cloud/contract.json`, your account's cached contract.
|
|
300
308
|
- `~/.config/catalyst-cloud/published.json`, the cached answer to "what is the newest release" — no credential in it.
|
|
309
|
+
- The Codex launch hook: one marked block in `~/.zshrc` and `~/.bashrc`, and on a Mac `~/Library/LaunchAgents/dev.catalystcloud.codex-attribution.plist` with its log at `~/.config/catalyst-cloud/codex-attribution.log` (see "Codex launches name their coding account").
|
|
301
310
|
- After `catalyst update` moves the CLI: `~/.config/catalyst-cloud/cli-runtimes/`, one directory per CLI version it installed and `active.json` naming the one your `catalyst` command runs.
|
|
302
311
|
- Only if you start them: `~/.config/catalyst-cloud/replica.db` with its `.pid`, `.writer.lock` and `.writer.state` sidecars, `$XDG_STATE_HOME/catalyst/events/<tenant>/backbone/` (or the home-directory fallback) with bounded daily event segments, and `~/.config/catalyst-cloud/watch-cursor.json`.
|
|
303
312
|
|
|
@@ -305,7 +314,15 @@ The skill files themselves are written by whichever install command you ran, in
|
|
|
305
314
|
|
|
306
315
|
## Updating
|
|
307
316
|
|
|
308
|
-
`catalyst update --check` lists each installed component beside the version your workspace approved
|
|
317
|
+
`catalyst update --check` lists each installed component beside the version your workspace approved and changes nothing. For skills packs and the Cloud plugin, the report also compares `installedCommit` with `approvedCommit`. Matching versions alone do not establish that the installed skills match approval. Add `--json` for the machine-readable report, or `--project <absolute path>` to include a project's SDK. A project's files change only when you run `catalyst update sdk --project <path>`, or after you turn its SDK updates on with `catalyst update policy sdk on --project <path>`.
|
|
318
|
+
|
|
319
|
+
`catalyst update` moves enabled components to the approved release. Owned skills packs move to the exact approved repository commits, including correction of a pack ahead of approval. It verifies existing contents before replacing them, preserves independent skills and local edits, and adds no missing skill names. The Cloud plugin uses the same verified Cloud checkout as a local user-scope marketplace. Run `/reload-plugins` or restart Claude Code after it updates. A missing `claude` executable, unsupported plugin scope or uncertain ownership leaves the plugin in place with a reason. Dev skills move only when the approved release includes a Dev pack; `pack_not_approved` means the installed pack was kept.
|
|
320
|
+
|
|
321
|
+
The new CLI is installed beside the old one, and your `catalyst` command runs it at the same path. A running local replica restarts on it and keeps its synced data; a stopped one stays stopped. CLI, SDK and image updates keep their existing policy against moving to an older version. Ordinary CLI startup never replaces skills with its bundled copy.
|
|
322
|
+
|
|
323
|
+
On a machine checking for releases every 15 minutes (`catalyst runner auto-update on`), that check applies the same component policies. Otherwise components move when you run `catalyst update`. That check moves the runner images to a newer release only at set times of day, 03:00, 11:00, 16:00 and 22:00 in the machine's time zone, so a busy machine is not restarted every time a release is approved. `catalyst update policy windows 06:00,18:00 --time-zone America/Chicago` sets your own times, `catalyst update policy windows default` goes back to these, and `catalyst runner update` or `catalyst update` applies a waiting release at once. Each component is on by default; turn one off with `catalyst update policy <component> off` (for example `cli`), and `catalyst update policy` lists every setting. If you turned the installer's daily update off, the CLI and both skills packs start held, and `catalyst update policy cli on` turns the CLI back on.
|
|
324
|
+
|
|
325
|
+
The installer's daily job runs the same release check, so it moves the CLI and the Cloud skills only to the approved release and keeps your holds. Until the development skills join the release, it refreshes them from their repository.
|
|
309
326
|
|
|
310
327
|
A CLI older than `catalyst update` cannot move itself: install it once with `npm install -g @catalyst-cloud/cli@latest && catalyst login`. The re-login rewrites the CLI path the skills spawn, so they stop running the old bundle. To run one command against the latest publish without installing, use `npx -p @catalyst-cloud/cli@latest catalyst login`. The next `catalyst` run prints a one-line notice:
|
|
311
328
|
|
|
@@ -325,10 +342,12 @@ Remove the skills the way you installed them: `/plugin uninstall catalyst@cataly
|
|
|
325
342
|
|
|
326
343
|
```sh
|
|
327
344
|
catalyst replica stop
|
|
345
|
+
catalyst setup --remove-codex-attribution
|
|
328
346
|
rm -f ~/.config/catalyst-cloud/customer.json ~/.config/catalyst-cloud/contract.json ~/.config/catalyst-cloud/published.json ~/.config/catalyst-cloud/watch-cursor.json
|
|
329
347
|
rm -f ~/.config/catalyst-cloud/replica.db ~/.config/catalyst-cloud/replica.db.pid ~/.config/catalyst-cloud/replica.db.writer.lock ~/.config/catalyst-cloud/replica.db.writer.state
|
|
330
348
|
rm -rf "${XDG_STATE_HOME:-$HOME/.local/state}/catalyst/events"
|
|
331
349
|
rm -rf ~/.config/catalyst-cloud/cli-runtimes
|
|
350
|
+
rm -f ~/.config/catalyst-cloud/codex-accounts.json ~/.config/catalyst-cloud/codex-attribution.log
|
|
332
351
|
npm uninstall -g @catalyst-cloud/cli
|
|
333
352
|
```
|
|
334
353
|
|
package/dist/approved-release.js
CHANGED
|
@@ -152,8 +152,9 @@ export async function readMemberApproval(ctx) {
|
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
154
|
/** The component record a host's desired-release answer carries, from the same read the image
|
|
155
|
-
* update used. A legacy answer with images only reads
|
|
156
|
-
*
|
|
155
|
+
* update used, so the two halves are one snapshot. A legacy answer with images only reads
|
|
156
|
+
* `not_provided`. The record's generation counts component approvals and the answer's counts host
|
|
157
|
+
* releases: two ledgers, so the numbers differ and are never compared (CTC-6890). */
|
|
157
158
|
export function hostApproval(read) {
|
|
158
159
|
if (read.kind === "no_credential")
|
|
159
160
|
return { kind: "unavailable", reason: "host_unreadable" };
|
|
@@ -174,8 +175,6 @@ export function hostApproval(read) {
|
|
|
174
175
|
const parsed = parseApprovedRelease(release.components);
|
|
175
176
|
if (!parsed.ok)
|
|
176
177
|
return { kind: "unavailable", reason: parsed.reason };
|
|
177
|
-
if (parsed.release.generation !== release.generation)
|
|
178
|
-
return { kind: "unavailable", reason: "envelope_mismatch" };
|
|
179
178
|
return { kind: "approved", release: parsed.release, source: "host" };
|
|
180
179
|
}
|
|
181
180
|
export function approvalCachePathFor(home) {
|
package/dist/args.js
CHANGED
|
@@ -91,6 +91,14 @@ export const FLAG_TABLES = {
|
|
|
91
91
|
value: false,
|
|
92
92
|
help: "print setup in plain text, without colour or the Catalyst Cloud mark",
|
|
93
93
|
},
|
|
94
|
+
"no-shell-hook": {
|
|
95
|
+
value: false,
|
|
96
|
+
help: "do not add the Codex launch hooks: the codex function in ~/.zshrc and ~/.bashrc, and on macOS the dev.catalystcloud.codex-attribution LaunchAgent",
|
|
97
|
+
},
|
|
98
|
+
"remove-codex-attribution": {
|
|
99
|
+
value: false,
|
|
100
|
+
help: "remove the Codex launch hooks setup added (each rc file goes back to what it was), unload and delete the LaunchAgent, and take its attributes out of the launch environment; runs nothing else",
|
|
101
|
+
},
|
|
94
102
|
"resume-from": {
|
|
95
103
|
value: true,
|
|
96
104
|
help: "resume at a verified onboarding step",
|
|
@@ -527,6 +535,21 @@ export const FLAG_TABLES = {
|
|
|
527
535
|
work: {
|
|
528
536
|
team: { value: true, help: "available: one team's key (default: every team in the workspace contract)" },
|
|
529
537
|
},
|
|
538
|
+
"codex-env": {
|
|
539
|
+
print: {
|
|
540
|
+
value: false,
|
|
541
|
+
help: "print the OTEL_RESOURCE_ATTRIBUTES value a Codex launch should carry: the attributes already set, plus the coding account's slot and this machine's short name",
|
|
542
|
+
},
|
|
543
|
+
apply: {
|
|
544
|
+
value: false,
|
|
545
|
+
help: "macOS: set that value with launchctl for apps started from now on, the Codex desktop app included, for the default Codex home",
|
|
546
|
+
},
|
|
547
|
+
refresh: {
|
|
548
|
+
value: false,
|
|
549
|
+
help: "fetch this workspace's coding accounts now and update the cache --print and --apply read",
|
|
550
|
+
},
|
|
551
|
+
"codex-home": { value: true, help: "print: the Codex home to read (default: $CODEX_HOME, else ~/.codex)" },
|
|
552
|
+
},
|
|
530
553
|
repo: {
|
|
531
554
|
reason: { value: true, help: "pause: required; resume: optional; 1 to 500 characters after trimming (owner or admin)" },
|
|
532
555
|
write: {
|
|
@@ -584,7 +607,7 @@ export const VERB_USAGE = {
|
|
|
584
607
|
update: "update [--check] [--project <absolute path>] [--dir <runner directory>] | update sdk --project <absolute path> | update policy [<component> on|off] | update policy sdk on|off --project <absolute path> | update policy windows <HH:MM,...>|default [--time-zone <zone>] [--json] (components: runner, supervisor, watchdog, cli, skills-cloud, skills-dev, replica)",
|
|
585
608
|
setup: "setup [onboard options] (sets up Catalyst step by step; same as catalyst onboard) | setup --engine <file> --engine-sha256 <hex> [-- <install options>] (run by install.sh; install.sh --help lists the options)",
|
|
586
609
|
login: "login [--base-url <url>] [--start-replica] (keyless; or --key <personal-key> / CATALYST_CLOUD_TOKEN)",
|
|
587
|
-
onboard: "onboard [--team <ID|key>] [--repo <owner/name>]... [--coding-account <slot>] [--resume-from <step>] [--only <step>] [--local-sync] [--remove-local-data] [--runner|--no-runner] [--no-color] [--yes] [--dry-run] [--json] | onboard --headless [--key-file <path>] [--team ...] [--repo ...]... [--coding-account ...] [--runner yes|no] [--remove-local-data] [--json]",
|
|
610
|
+
onboard: "onboard [--team <ID|key>] [--repo <owner/name>]... [--coding-account <slot>] [--resume-from <step>] [--only <step>] [--local-sync] [--remove-local-data] [--runner|--no-runner] [--no-shell-hook] [--no-color] [--yes] [--dry-run] [--json] | onboard --remove-codex-attribution [--json] | onboard --headless [--key-file <path>] [--team ...] [--repo ...]... [--coding-account ...] [--runner yes|no] [--remove-local-data] [--json]",
|
|
588
611
|
install: "install [--skills-dir <dir>] [--force]",
|
|
589
612
|
status: "status",
|
|
590
613
|
notice: "notice",
|
|
@@ -615,6 +638,7 @@ export const VERB_USAGE = {
|
|
|
615
638
|
capabilities: "capabilities [--json]",
|
|
616
639
|
project: "project <list [--json] | wip-limit <get|set <n>|set default> [--team K] [--json]>",
|
|
617
640
|
lease: "lease <take <ticket> --agent <seat> [--ttl <minutes>] | renew <ticket> (--commit <sha>|--artifact <path or id>|--finding <id>|--pr <number>) [--note <text>] [--agent <seat>] [--generation <n>] | release <ticket> [--agent <seat>] [--generation <n>] | show <ticket>> [--json] (a seat's ticket lease: take, renew with new progress, release, read; needs login)",
|
|
641
|
+
"codex-env": "codex-env --print [--codex-home <dir>] | --apply | --refresh [--json] (the telemetry attributes naming the coding account and machine a Codex launch runs as; only --refresh waits on the network)",
|
|
618
642
|
work: "work available [--team K] [--json] (per team: tickets nobody holds, with the last holder and progress, and open pull requests no live lease covers, drafts included)",
|
|
619
643
|
repo: "repo <status|pause <owner/name> --reason <text>|resume <owner/name> [--reason <text>]|agents-block <path> [--write]|agent-setup <path> [--apply] [--with-check]> [--json] (status: visible workspace repositories; agents-block/agent-setup: local checkout)",
|
|
620
644
|
legacy: "legacy [--remove [--data] [--yes]] [--json]",
|
package/dist/capabilities.js
CHANGED
|
@@ -48,6 +48,8 @@ export const CAPABILITIES = [
|
|
|
48
48
|
{ verb: "var set|import", does: "enter plain environment variable values from this terminal, never echoed", needs: "admin", routes: [], since: "0.13.2" },
|
|
49
49
|
{ verb: "env import", does: "store this computer's values for the names .catalyst/catalyst.toml declares, never printed", needs: "admin", routes: [], since: "0.16.20" },
|
|
50
50
|
{ verb: "accounts", does: "read the workspace's coding accounts and which can take work", needs: "member", routes: [], since: "0.5.0" },
|
|
51
|
+
{ verb: "codex-env", does: "name the coding account and the machine on every Codex launch's telemetry: print the attributes, set them for apps on macOS, or refresh the account cache", needs: "member", routes: [], since: "0.16.33" },
|
|
52
|
+
{ verb: "setup --remove-codex-attribution", does: "take out the Codex launch hooks setup adds: the codex function in the shell rc files, and on macOS the login agent and the attributes it set", needs: "member", routes: [], since: "0.16.34" },
|
|
51
53
|
{ verb: "explain|running|queue|history", does: "read why a ticket runs or waits, what runs now, and what is queued", needs: "member", routes: [], since: "0.1.0" },
|
|
52
54
|
{ verb: "write comment|state|label|create|reaction|attachment|session", does: "act on a ticket as the person, through the agent proxy", needs: "member", routes: [agent("POST", "issue-comment"), agent("POST", "issue-state"), agent("POST", "issue-label"), agent("POST", "issue-create")], since: "0.1.0" },
|
|
53
55
|
{ verb: "ask raise|accept|list", does: "raise a decision to a human, or answer one", needs: "member", routes: [agent("POST", "ask"), agent("POST", "ask-accept")], since: "0.1.0" },
|
package/dist/cli.js
CHANGED
|
@@ -8,9 +8,9 @@ import { createSetupRenderer, setupBanner, } from "./setup-render.js";
|
|
|
8
8
|
import { existsSync, openSync, closeSync } from "node:fs";
|
|
9
9
|
import { ReadStream as TerminalInput } from "node:tty";
|
|
10
10
|
import { Writable } from "node:stream";
|
|
11
|
-
import { parseArgs, positionals, verbHelp } from "./args.js";
|
|
11
|
+
import { flagBool, parseArgs, positionals, verbHelp } from "./args.js";
|
|
12
12
|
import { reportCliVersion } from "./cli-version.js";
|
|
13
|
-
import { CONFIG_MODE, DEFAULT_BASE_URL, LEGACY_PACKAGE_NAME, PACKAGE_NAME, cliPath, configPathFor, contractPathFor, defaultCtx, defaultReplicaDbFor, defaultSkillsDirFor, formatMode,
|
|
13
|
+
import { CONFIG_MODE, DEFAULT_BASE_URL, LEGACY_PACKAGE_NAME, PACKAGE_NAME, cliPath, configPathFor, contractPathFor, defaultCtx, defaultReplicaDbFor, defaultSkillsDirFor, formatMode, loadConfig, modernCliPath, normalizeBaseUrl, readManifest, requireConfig, saveConfig, writeConfig, } from "./config.js";
|
|
14
14
|
import { loadContract, pickPath } from "./contract.js";
|
|
15
15
|
import { CliError, MeError, UsageError } from "./errors.js";
|
|
16
16
|
import { fetchMe } from "./transport.js";
|
|
@@ -50,6 +50,8 @@ import { cmdProject } from "./project.js";
|
|
|
50
50
|
import { cmdRepo } from "./repo.js";
|
|
51
51
|
import { cmdLease, cmdWork } from "./lease.js";
|
|
52
52
|
import { cmdLegacy } from "./legacy.js";
|
|
53
|
+
import { cmdCodexEnv } from "./codex-env.js";
|
|
54
|
+
import { codexAttributionAfterSetup, codexAttributionStatusLine, removeCodexAttribution, } from "./codex-attribution.js";
|
|
53
55
|
import { cmdIdentity } from "./identity.js";
|
|
54
56
|
import { cmdMessages } from "./messages.js";
|
|
55
57
|
import { cmdConnections } from "./connections.js";
|
|
@@ -85,7 +87,8 @@ export function usageText() {
|
|
|
85
87
|
" catalyst login --key <personal-key> [--base-url <url>] (or CATALYST_CLOUD_TOKEN, for a key)",
|
|
86
88
|
" catalyst join ... (deprecated alias of login; removed in the next minor version)",
|
|
87
89
|
" catalyst install [--skills-dir <dir>] [--force] (repair path; your agent's own command installs the skills)",
|
|
88
|
-
" catalyst onboard [--resume-from <step>] [--only <step>] [--runner|--no-runner] [--yes] [--dry-run] [--json]",
|
|
90
|
+
" catalyst onboard [--resume-from <step>] [--only <step>] [--runner|--no-runner] [--no-shell-hook] [--yes] [--dry-run] [--json]",
|
|
91
|
+
" catalyst setup --remove-codex-attribution (take out the Codex launch hook and login agent setup added)",
|
|
89
92
|
` catalyst ${SETUP_USAGE}`,
|
|
90
93
|
" catalyst status | notice | me | ready | accounts",
|
|
91
94
|
" catalyst seat checkout --size big|med --harness claude,codex,opencode [--session-id ID] [--stage STAGE]",
|
|
@@ -119,6 +122,7 @@ export function usageText() {
|
|
|
119
122
|
" catalyst repo <agents-block <path> [--write]|agent-setup <path> [--apply] [--with-check]> (a checkout's AGENTS.md block and portable agent layout; working tree only)",
|
|
120
123
|
" catalyst lease <take <ticket> --agent <seat> [--ttl <minutes>]|renew <ticket> --commit|--artifact|--finding|--pr <ref> [--note <text>]|release <ticket>|show <ticket>> [--json] (a seat's ticket lease; needs login)",
|
|
121
124
|
" catalyst work available [--team K] [--json] (tickets nobody holds and open pull requests no lease covers)",
|
|
125
|
+
" catalyst codex-env --print [--codex-home <dir>] | --apply | --refresh (the telemetry attributes naming the coding account and machine a Codex launch runs as)",
|
|
122
126
|
" catalyst legacy [--remove [--data] [--yes]] (leftovers of the old local Catalyst runtime: list them; remove them only on a yes)",
|
|
123
127
|
" catalyst identity linear <status|options|set> [<linearUserId>] [--json]",
|
|
124
128
|
" catalyst messages read --ticket CTC-N [--since SEQUENCE] [--json] (messages sent to a ticket on your teams)",
|
|
@@ -183,10 +187,7 @@ function migrateLegacyCliPath(ctx) {
|
|
|
183
187
|
// Best effort: the old launcher still works, it only prints the notice.
|
|
184
188
|
}
|
|
185
189
|
}
|
|
186
|
-
/**
|
|
187
|
-
* The Tier-2 update path: when the bundle on disk is newer than the version the config last
|
|
188
|
-
* recorded, refresh the copied skills FIRST and record the new version only once that succeeded.
|
|
189
|
-
*/
|
|
190
|
+
/** Announce a new CLI bundle without changing approved skills. */
|
|
190
191
|
function maybePrintUpdateNotice(args, ctx) {
|
|
191
192
|
const say = HUMAN_VERBS.has(args.command ?? "") ? ctx.stdout : ctx.stderr;
|
|
192
193
|
let cfg;
|
|
@@ -199,46 +200,16 @@ function maybePrintUpdateNotice(args, ctx) {
|
|
|
199
200
|
if (!cfg)
|
|
200
201
|
return;
|
|
201
202
|
const manifest = readManifest();
|
|
202
|
-
if (cfg.lastSkillBundleVersion === manifest.version)
|
|
203
|
-
return;
|
|
204
|
-
// CTC-6741: a newer CLI selected by `catalyst update` records its own bundle here, and the older
|
|
205
|
-
// npm-installed one still runs for `catalyst runtime`. Copied skills only ever move forward.
|
|
206
|
-
if (cfg.lastSkillBundleVersion && semverOlder(manifest.version, cfg.lastSkillBundleVersion))
|
|
207
|
-
return;
|
|
208
203
|
const previous = cfg.lastSkillBundleVersion;
|
|
209
|
-
if (previous)
|
|
210
|
-
const entry = parseChangelogEntry(readChangelog(), manifest.version);
|
|
211
|
-
say(updateNoticeLine(previous, manifest.version, entry));
|
|
212
|
-
}
|
|
213
|
-
if (installerOwnsSkills(ctx.home, ctx.env)) {
|
|
214
|
-
cfg.lastSkillBundleVersion = manifest.version;
|
|
215
|
-
try {
|
|
216
|
-
saveConfig(ctx.home, cfg);
|
|
217
|
-
}
|
|
218
|
-
catch {
|
|
219
|
-
// Best effort: the notice prints again next time, and nothing else depends on it.
|
|
220
|
-
}
|
|
204
|
+
if (previous === manifest.version || previous && semverOlder(manifest.version, previous))
|
|
221
205
|
return;
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
206
|
+
if (previous)
|
|
207
|
+
say(updateNoticeLine(previous, manifest.version, parseChangelogEntry(readChangelog(), manifest.version)));
|
|
208
|
+
cfg.lastSkillBundleVersion = manifest.version;
|
|
225
209
|
try {
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
catch (err) {
|
|
229
|
-
ctx.stderr(`[catalyst] could not refresh the skills at ${skillsDir} (${err instanceof Error ? err.message : String(err)}) — the ${manifest.version} skills are not installed yet; re-run the install command: ${INSTALL_COMMAND}`);
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
if (refreshed.installed.length > 0)
|
|
233
|
-
say(`[catalyst] refreshed ${refreshed.installed.join(", ")} at ${skillsDir} to ${manifest.version}`);
|
|
234
|
-
if (refreshed.removed.length > 0)
|
|
235
|
-
say(`[catalyst] removed retired skills ${refreshed.removed.join(", ")} from ${skillsDir}; their work moved into the skills this bundle ships`);
|
|
236
|
-
for (const s of refreshed.skipped) {
|
|
237
|
-
say(`[catalyst] left "${s.name}" alone: ${skillsDir}/${s.name} was not installed by this package (catalyst install --force to replace)`);
|
|
210
|
+
saveConfig(ctx.home, cfg);
|
|
238
211
|
}
|
|
239
|
-
|
|
240
|
-
cfg.skillsDir = skillsDir;
|
|
241
|
-
saveConfig(ctx.home, cfg);
|
|
212
|
+
catch { /* The notice can repeat on the next ordinary command. */ }
|
|
242
213
|
}
|
|
243
214
|
export async function main(argv, ctx = defaultCtx(), deps = {}) {
|
|
244
215
|
// CTC-4625: setup passes the install options through to its engine untouched, so they never meet
|
|
@@ -305,7 +276,7 @@ export async function main(argv, ctx = defaultCtx(), deps = {}) {
|
|
|
305
276
|
}),
|
|
306
277
|
};
|
|
307
278
|
try {
|
|
308
|
-
if (args.command !== "onboard") {
|
|
279
|
+
if (args.command !== "onboard" && !(flagBool(args, "check") && (args.command === "update" || args.command === "runner"))) {
|
|
309
280
|
migrateLegacyCliPath(ctx);
|
|
310
281
|
maybePrintUpdateNotice(args, ctx);
|
|
311
282
|
}
|
|
@@ -323,6 +294,19 @@ export async function main(argv, ctx = defaultCtx(), deps = {}) {
|
|
|
323
294
|
throw new UsageError(`--${flag} needs --headless`);
|
|
324
295
|
if (typeof args.flags.runner === "string" && !onboardHeadlessRequested(args, ctx.env))
|
|
325
296
|
throw new UsageError("--runner yes|no needs --headless; use --runner or --no-runner interactively");
|
|
297
|
+
// The Codex launch hooks' removal runs on its own, with no onboarding around it.
|
|
298
|
+
if (args.flags["remove-codex-attribution"] === true) {
|
|
299
|
+
if (args.flags["dry-run"] === true)
|
|
300
|
+
throw new UsageError("--remove-codex-attribution changes files; run it without --dry-run");
|
|
301
|
+
deps.setupUi?.dispose();
|
|
302
|
+
const removal = removeCodexAttribution(ctx, deps.codexAttribution);
|
|
303
|
+
if (args.json)
|
|
304
|
+
ctx.stdout(JSON.stringify({ removed: removal.ok, files: removal.files, agent: removal.agent }));
|
|
305
|
+
else
|
|
306
|
+
for (const line of removal.lines)
|
|
307
|
+
ctx.stdout(line);
|
|
308
|
+
return removal.ok ? 0 : 1;
|
|
309
|
+
}
|
|
326
310
|
// Headless runs drop the terminal UI, browser sign-in and every browser action (CTC-4633).
|
|
327
311
|
const runOnboard = async (args, ctx, headless) => {
|
|
328
312
|
let ui = headless ? undefined : deps.setupUi;
|
|
@@ -485,6 +469,8 @@ export async function main(argv, ctx = defaultCtx(), deps = {}) {
|
|
|
485
469
|
}
|
|
486
470
|
for (const line of jsonLines)
|
|
487
471
|
ctx.stdout(line);
|
|
472
|
+
// The Codex launch hooks follow every full run, done or waiting, and never change its exit code.
|
|
473
|
+
codexAttributionAfterSetup(args, ctx, deps.codexAttribution);
|
|
488
474
|
return code;
|
|
489
475
|
};
|
|
490
476
|
if (!onboardHeadlessRequested(args, ctx.env))
|
|
@@ -497,7 +483,7 @@ export async function main(argv, ctx = defaultCtx(), deps = {}) {
|
|
|
497
483
|
case "notice":
|
|
498
484
|
return 0;
|
|
499
485
|
case "status":
|
|
500
|
-
return cmdStatus(ctx);
|
|
486
|
+
return cmdStatus(ctx, deps);
|
|
501
487
|
case "me":
|
|
502
488
|
return await cmdMe(args, ctx);
|
|
503
489
|
case "contract":
|
|
@@ -564,6 +550,8 @@ export async function main(argv, ctx = defaultCtx(), deps = {}) {
|
|
|
564
550
|
return await cmdWork(args, ctx);
|
|
565
551
|
case "legacy":
|
|
566
552
|
return await cmdLegacy(args, ctx, { localSyncSelected: savedLocalSync(ctx), ...deps.legacy });
|
|
553
|
+
case "codex-env":
|
|
554
|
+
return await cmdCodexEnv(args, ctx, deps.codexEnv ?? {});
|
|
567
555
|
case "identity":
|
|
568
556
|
return await cmdIdentity(args, ctx, deps.identity ?? {});
|
|
569
557
|
case "messages":
|
|
@@ -643,6 +631,7 @@ const VERB_HELP_KNOWN = Object.fromEntries([
|
|
|
643
631
|
"lease",
|
|
644
632
|
"work",
|
|
645
633
|
"legacy",
|
|
634
|
+
"codex-env",
|
|
646
635
|
"onboard",
|
|
647
636
|
"update",
|
|
648
637
|
].map((v) => [v, true]));
|
|
@@ -852,7 +841,7 @@ function cmdInstall(args, ctx) {
|
|
|
852
841
|
ctx.stdout(`Removed retired skills from ${skillsDir}: ${result.removed.join(", ")}`);
|
|
853
842
|
return 0;
|
|
854
843
|
}
|
|
855
|
-
function cmdStatus(ctx) {
|
|
844
|
+
function cmdStatus(ctx, deps = {}) {
|
|
856
845
|
const manifest = readManifest();
|
|
857
846
|
const cfg = loadConfig(ctx.home);
|
|
858
847
|
if (!cfg) {
|
|
@@ -871,6 +860,7 @@ function cmdStatus(ctx) {
|
|
|
871
860
|
if (cfg.cliPath)
|
|
872
861
|
ctx.stdout(`CLI: ${cfg.cliPath}${existsSync(cfg.cliPath) ? "" : " (missing — re-run login)"}`);
|
|
873
862
|
ctx.stdout(`Contract: ${existsSync(contractPathFor(ctx.home)) ? contractPathFor(ctx.home) : "not cached (run: catalyst contract --refresh)"}`);
|
|
863
|
+
ctx.stdout(codexAttributionStatusLine(ctx, deps.codexAttribution));
|
|
874
864
|
return 0;
|
|
875
865
|
}
|
|
876
866
|
/** A short human relative time for an ISO expiry, e.g. "in 14m", "in 2h", "in 6d", or "now" once past. */
|