@catalyst-cloud/cli 0.9.2 → 0.9.4
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 +14 -0
- package/dist/cli.js +20 -4
- package/dist/config.js +16 -0
- package/dist/execution.js +14 -2
- package/dist/skills.js +13 -1
- 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 +50 -34
- package/skills/catalyst-onboard/references/choosing-a-coding-account.md +52 -0
- package/skills/catalyst-onboard/references/declaring-a-repository.md +4 -2
- package/skills/catalyst-onboard/references/replacing-a-credential.md +5 -1
- package/skills/catalyst-onboard/references/the-one-path.md +52 -86
- package/skills/catalyst-onboard/references/what-a-phase-needs.md +1 -1
- package/skills/catalyst-onboard/references/what-the-browser-owns.md +2 -1
- package/skills/catalyst-onboard/references/who-fixes-what.md +4 -3
- package/skills/catalyst-onboard/scripts/lib/cli.mjs +15 -1
- package/skills/catalyst-onboard/scripts/where-am-i.mjs +195 -34
- package/skills/catalyst-setup/SKILL.md +1 -1
- package/skills/connect-me/SKILL.md +1 -1
- package/skills/how-catalyst-works/SKILL.md +1 -1
- 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/whats-happening/SKILL.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.4
|
|
4
|
+
|
|
5
|
+
`/catalyst-onboard` walks a new member through setup one step at a time, in the order a person can act on it: coding account, Linear integration, project, GitHub App and repository, connected accounts, the repository's `.catalyst/catalyst.toml` declaration, then the host, ending with one ticket moving. Each turn asks one question, says why in a line, and checks the result after. A new reference covers choosing a coding account (a Claude setup token, a Codex `auth.json`, or a GLM or Qwen API key), and it says plainly that a plain Anthropic or OpenAI API key cannot be enrolled today. Accounts are named by their label. The skills use the product's own nouns (workspace, project, repository, integration, connected account).
|
|
6
|
+
|
|
7
|
+
An ended or cancelled coding account is kept for reporting and not used. Onboarding no longer tells you to retire or delete it, and never to put another login's credential on it; reactivate it only if its subscription is live again. `catalyst accounts` marks it "subscription canceled — kept for reporting, not used".
|
|
8
|
+
|
|
9
|
+
The onboarding step engine never names a next step it cannot back with a check, and it says when a newer CLI is announced but not yet published.
|
|
10
|
+
|
|
11
|
+
## 0.9.3
|
|
12
|
+
|
|
13
|
+
A machine the Catalyst installer moved from `@catalyst-cloud/catalyst-skills` to `@catalyst-cloud/cli` works without logging in again. The recorded launcher pointed into the removed package, so `ready` failed its CLI-path check and skill scripts could not start the CLI; any command now repoints it at the launcher that is running. The CLI also leaves the installer's skills alone: it never writes through a symlinked skill folder, and when the installer owns skill placement it does not refresh skills at all. When a refresh does fail, it tells you to re-run the install command.
|
|
14
|
+
|
|
15
|
+
Onboarding no longer tells you to re-credential an ended or cancelled coding account: it says to retire it on the AI accounts page, and such an account no longer leaves setup unfinished. Before you mint a replacement token, it has you check that your terminal is logged into the account the slot belongs to. `catalyst accounts` names each account by its label, else its email, with the slot id second, adds `displayName` to `--json`, and marks a cancelled subscription "subscription canceled — retire on the AI accounts page".
|
|
16
|
+
|
|
3
17
|
## 0.9.2
|
|
4
18
|
|
|
5
19
|
The CLI works against a tenant serving contract 2.x. Catalyst Cloud's tenant contract moved to 2.0.0 when it removed `merge.cloudRemediateRequiredChecks`, and every earlier bundle accepted only 1.x, so `ready`, onboarding and most commands stopped with "the tenant serves contract version 2.2.0 but this bundle accepts 1.x". This bundle accepts `1.x || 2.x`. The one place that read the removed field already treated it as absent.
|
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// their own modules; this file keeps every export the 0.1 tests and the bin import.
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import { parseArgs, positionals, verbHelp } from "./args.js";
|
|
5
|
-
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";
|
|
5
|
+
import { CONFIG_MODE, DEFAULT_BASE_URL, LEGACY_PACKAGE_NAME, PACKAGE_NAME, cliPath, configPathFor, contractPathFor, defaultCtx, defaultReplicaDbFor, defaultSkillsDirFor, formatMode, installerOwnsSkills, INSTALL_COMMAND, loadConfig, modernCliPath, normalizeBaseUrl, readManifest, requireConfig, saveConfig, writeConfig, } from "./config.js";
|
|
6
6
|
import { loadContract, pickPath } from "./contract.js";
|
|
7
7
|
import { CliError, MeError, UsageError } from "./errors.js";
|
|
8
8
|
import { fetchMe } from "./transport.js";
|
|
@@ -100,8 +100,14 @@ function migrateLegacyCliPath(ctx) {
|
|
|
100
100
|
}
|
|
101
101
|
if (!cfg)
|
|
102
102
|
return;
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
let next = modernCliPath(cfg.cliPath);
|
|
104
|
+
// An upgrade from @catalyst-cloud/catalyst-skills to @catalyst-cloud/cli removes the old package
|
|
105
|
+
// folder, so the recorded launcher no longer exists and has no sibling. Point it at the launcher
|
|
106
|
+
// that is running now, so `ready` and every skill script work without another login.
|
|
107
|
+
if (next === null && typeof cfg.cliPath === "string" && cfg.cliPath !== "" && !existsSync(cfg.cliPath)) {
|
|
108
|
+
next = cliPath();
|
|
109
|
+
}
|
|
110
|
+
if (next === null || next === cfg.cliPath)
|
|
105
111
|
return;
|
|
106
112
|
cfg.cliPath = next;
|
|
107
113
|
try {
|
|
@@ -134,13 +140,23 @@ function maybePrintUpdateNotice(args, ctx) {
|
|
|
134
140
|
const entry = parseChangelogEntry(readChangelog(), manifest.version);
|
|
135
141
|
say(updateNoticeLine(previous, manifest.version, entry));
|
|
136
142
|
}
|
|
143
|
+
if (installerOwnsSkills(ctx.home, ctx.env)) {
|
|
144
|
+
cfg.lastSkillBundleVersion = manifest.version;
|
|
145
|
+
try {
|
|
146
|
+
saveConfig(ctx.home, cfg);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
// Best effort: the notice prints again next time, and nothing else depends on it.
|
|
150
|
+
}
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
137
153
|
const skillsDir = resolveSkillsDir(args, ctx, cfg);
|
|
138
154
|
let refreshed;
|
|
139
155
|
try {
|
|
140
156
|
refreshed = installSkills(skillsDir, { force: false, onlyExisting: true });
|
|
141
157
|
}
|
|
142
158
|
catch (err) {
|
|
143
|
-
ctx.stderr(`[catalyst-skills] could not refresh the skills at ${skillsDir} (${err instanceof Error ? err.message : String(err)}) — the ${manifest.version} skills are not installed yet; run
|
|
159
|
+
ctx.stderr(`[catalyst-skills] 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}`);
|
|
144
160
|
return;
|
|
145
161
|
}
|
|
146
162
|
if (refreshed.installed.length > 0)
|
package/dist/config.js
CHANGED
|
@@ -91,6 +91,8 @@ export function updatePackageName(root = packageRoot()) {
|
|
|
91
91
|
return LEGACY_PACKAGE_NAME;
|
|
92
92
|
return PACKAGE_NAME;
|
|
93
93
|
}
|
|
94
|
+
/** The Catalyst installer, which owns skill placement and switches a machine between packages. */
|
|
95
|
+
export const INSTALL_COMMAND = "curl -fsSL https://staging.catalystcloud.dev/install.sh | sh";
|
|
94
96
|
/** The one upgrade command every hint prints: update the installed package, then log in again so
|
|
95
97
|
* customer.json records the new launcher path. */
|
|
96
98
|
export function upgradeCommand(root) {
|
|
@@ -115,6 +117,20 @@ export function normalizeBaseUrl(url) {
|
|
|
115
117
|
export function apiBase(cfg) {
|
|
116
118
|
return `${normalizeBaseUrl(cfg.baseUrl)}/api/v1`;
|
|
117
119
|
}
|
|
120
|
+
/** True when the Catalyst installer owns skill placement on this machine: it exports
|
|
121
|
+
* CATALYST_SKILLS_DIR, or it wrote the machine paths file (every v1 record carries a skills role).
|
|
122
|
+
* The CLI then never refreshes skill folders itself; the installer's own refresh does. */
|
|
123
|
+
export function installerOwnsSkills(home, env = {}) {
|
|
124
|
+
if (env.CATALYST_SKILLS_DIR !== undefined && env.CATALYST_SKILLS_DIR !== "")
|
|
125
|
+
return true;
|
|
126
|
+
try {
|
|
127
|
+
const file = machinePathsFile({ env: { ...env, HOME: home } });
|
|
128
|
+
return Boolean(file && machineFilePresent(file));
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
118
134
|
function machineFilePresent(file) {
|
|
119
135
|
try {
|
|
120
136
|
lstatSync(file);
|
package/dist/execution.js
CHANGED
|
@@ -318,12 +318,23 @@ export const ACCOUNT_STATUS = {
|
|
|
318
318
|
attested: "attested — healthy at last check, no work observed since",
|
|
319
319
|
unobserved: "unobserved — enrolled, but nothing has been seen from it yet",
|
|
320
320
|
};
|
|
321
|
+
/** The name a person or agent calls an account by: its label, else its email, else its slot id. */
|
|
322
|
+
export function accountDisplayName(a) {
|
|
323
|
+
for (const v of [a.label, a.email])
|
|
324
|
+
if (typeof v === "string" && v.trim() !== "")
|
|
325
|
+
return v.trim();
|
|
326
|
+
return a.accountSlot ?? "?";
|
|
327
|
+
}
|
|
321
328
|
/** One slot as a line a human reads: who it is, what state it is in, and what it is spending on. */
|
|
322
329
|
export function renderAccount(a) {
|
|
323
|
-
const
|
|
330
|
+
const display = accountDisplayName(a);
|
|
331
|
+
const name = display === (a.accountSlot ?? "?") ? display : `${display} (${a.accountSlot ?? "?"})`;
|
|
324
332
|
const harness = a.harness ? `/${a.harness}` : "";
|
|
325
333
|
const status = a.status ? (ACCOUNT_STATUS[a.status] ?? a.status) : "status unknown";
|
|
326
334
|
const bits = [`${name} ${a.provider ?? "?"}${harness} ${status}`];
|
|
335
|
+
// CTC-4199: a cancelled subscription is kept for reporting and not used; never re-credential it (Ryan, 2026-09-29).
|
|
336
|
+
if (a.renewalStatus === "canceled")
|
|
337
|
+
bits.push("subscription canceled — kept for reporting, not used");
|
|
327
338
|
if (typeof a.bindingUsedPercent === "number") {
|
|
328
339
|
const resets = typeof a.bindingResetsAtMs === "number" ? `, resets ${new Date(a.bindingResetsAtMs).toISOString()}` : "";
|
|
329
340
|
bits.push(`usage ${a.bindingUsedPercent}% of the ${a.bindingWindow ?? "binding"} window${resets}`);
|
|
@@ -356,7 +367,8 @@ export async function cmdAccounts(args, ctx) {
|
|
|
356
367
|
throw needsNewerCloud("coding-account status", cfg);
|
|
357
368
|
const accounts = Array.isArray(res.body) ? res.body : (res.body?.accounts ?? []);
|
|
358
369
|
if (args.json) {
|
|
359
|
-
|
|
370
|
+
const named = accounts.map((a) => ({ ...a, displayName: accountDisplayName(a) }));
|
|
371
|
+
ctx.stdout(JSON.stringify(Array.isArray(res.body) ? named : { ...res.body, accounts: named }));
|
|
360
372
|
return 0;
|
|
361
373
|
}
|
|
362
374
|
if (accounts.length === 0) {
|
package/dist/skills.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// skills.ts — copying the bundled skills into the user's skills directory, and the one-line update
|
|
2
2
|
// notice a new version prints on its next session.
|
|
3
|
-
import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
3
|
+
import { cpSync, existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { defaultSkillsDirFor, upgradeCommand } from "./config.js";
|
|
@@ -31,6 +31,10 @@ export function installSkills(targetDir, opts, sourceDir = skillsSourceDir()) {
|
|
|
31
31
|
if (!existsSync(join(src, "SKILL.md")))
|
|
32
32
|
continue;
|
|
33
33
|
const dst = join(targetDir, name);
|
|
34
|
+
// A symlinked entry belongs to whoever linked it (the Catalyst installer links its skills in);
|
|
35
|
+
// this package never writes through one, and says nothing about it.
|
|
36
|
+
if (isSymlink(dst))
|
|
37
|
+
continue;
|
|
34
38
|
const existingMd = join(dst, "SKILL.md");
|
|
35
39
|
if (opts.onlyExisting && !existsSync(existingMd))
|
|
36
40
|
continue;
|
|
@@ -47,6 +51,14 @@ export function installSkills(targetDir, opts, sourceDir = skillsSourceDir()) {
|
|
|
47
51
|
}
|
|
48
52
|
return result;
|
|
49
53
|
}
|
|
54
|
+
function isSymlink(path) {
|
|
55
|
+
try {
|
|
56
|
+
return lstatSync(path).isSymbolicLink();
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
50
62
|
export function resolveSkillsDir(args, ctx, cfg) {
|
|
51
63
|
return args.skillsDir ?? ctx.env.CATALYST_SKILLS_CLAUDE_DIR ?? cfg?.skillsDir ?? defaultSkillsDirFor(ctx.home);
|
|
52
64
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@catalyst-cloud/cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.4",
|
|
4
4
|
"description": "Customer skill bundle for Catalyst Cloud, named from the executive's seat — get set up, see what is happening, see what needs you, run a project, unstick what is stuck — plus the catalyst CLI that reads through the Catalyst Cloud SDK, writes through the agent proxy, and connects your machine to your tenant with one command. The skills directory is the roster; this line never counts it.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -4,7 +4,7 @@ description: >-
|
|
|
4
4
|
Catalyst's GitHub: show a ticket's pull request with its checks, reviews and review threads, say whether it is mergeable under this repository's policy, and explain what a PR accumulates as the ticket moves (the branch, the draft, the rewrite, the force-pushes, the labels, the queue). Use when someone asks "show me the PR", "what are the checks saying", "why hasn't it merged", "what does the queue need", "what does that label mean", or wants the branch and merge conventions Catalyst follows.
|
|
5
5
|
allowed-tools: Bash(catalyst-skills:*) Bash(npx @catalyst-cloud/catalyst-skills:*)
|
|
6
6
|
---
|
|
7
|
-
<!-- vendored-from: @catalyst-cloud/catalyst-skills@0.9.
|
|
7
|
+
<!-- vendored-from: @catalyst-cloud/catalyst-skills@0.9.4 — written in this repository for customer tenants -->
|
|
8
8
|
|
|
9
9
|
# Catalyst's GitHub
|
|
10
10
|
|
|
@@ -5,7 +5,7 @@ description: >-
|
|
|
5
5
|
allowed-tools: Bash(catalyst-skills:*) Bash(npx @catalyst-cloud/catalyst-skills:*)
|
|
6
6
|
disable-model-invocation: true
|
|
7
7
|
---
|
|
8
|
-
<!-- vendored-from: @catalyst-cloud/catalyst-skills@0.9.
|
|
8
|
+
<!-- vendored-from: @catalyst-cloud/catalyst-skills@0.9.4 — written in this repository for customer tenants -->
|
|
9
9
|
|
|
10
10
|
# Catalyst Linear
|
|
11
11
|
|
|
@@ -1,63 +1,79 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: catalyst-onboard
|
|
3
3
|
description: >-
|
|
4
|
-
Walk a person from nothing to their first Catalyst Cloud ticket running, one step at a time, hand-held. Use when someone says "set me up", "onboard me", "I just signed up", "get me started", "what do I do first", or when they have the Catalyst Cloud skills installed and nothing else.
|
|
4
|
+
Walk a person from nothing to their first Catalyst Cloud ticket running, one step at a time, hand-held. Use when someone says "set me up", "onboard me", "I just signed up", "get me started", "what do I do first", or when they have the Catalyst Cloud skills installed and nothing else. Starts with the coding account, then the project, the integrations and the person's connected accounts, each repository's settings file, and ends with one real ticket moving. Reads each part of the setup with the instrument that owns it, does every step a key can do through the catalyst-skills CLI, and for the steps only a browser can do hands over the exact page and says what to come back with. Never claims a step it did not watch succeed.
|
|
5
5
|
disable-model-invocation: true
|
|
6
6
|
allowed-tools: Bash(catalyst-skills:*) Bash(npx @catalyst-cloud/catalyst-skills:*)
|
|
7
7
|
---
|
|
8
|
-
<!-- vendored-from: @catalyst-cloud/catalyst-skills@0.9.
|
|
8
|
+
<!-- vendored-from: @catalyst-cloud/catalyst-skills@0.9.4 — written in this repository for customer tenants -->
|
|
9
9
|
|
|
10
10
|
# Onboard me
|
|
11
11
|
|
|
12
|
-
You take one person from "the skills are installed" to "a ticket is running on my own
|
|
12
|
+
You are the guide a new member gets on their first day with Catalyst Cloud. You take one person from "the skills are installed" to "a ticket is running on my own workspace", and you do it the way a good colleague would at their desk: one step at a time, one question at a time, saying why each step matters, and checking that it landed before you go on. You never print the whole ladder at them, and you never batch several steps into one turn.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
The path has five stops, in this order: a **coding account** the work will run on, one **project** (a Linear team plus its repositories, which needs the Linear integration first), the **integrations** and the person's own **connected accounts**, each repository's **settings file**, and then a green `ready` with **one real ticket moving**. `node scripts/where-am-i.mjs --next` always says which stop you are at; your memory of the last turn never does.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
## How a turn goes
|
|
17
|
+
|
|
18
|
+
1. Run `node scripts/where-am-i.mjs --next` and read the one line it prints. If a `note:` line follows it, say the note in one clause in the same turn (a cancelled account is kept for reporting, not used, never re-tokened); it is information, not a task.
|
|
19
|
+
2. Say, in one or two sentences, what that step is for. The person should always know why they are doing it.
|
|
20
|
+
3. Ask one question, or do one thing. If it is a command a key can run, run it and show the lines it printed. If it needs a browser, hand over one link, one action named the way the page names it, and say what you will check when they are back.
|
|
21
|
+
4. Stop. Wait for their answer.
|
|
22
|
+
5. When they answer, run the script again and read them the part that should have changed. If it changed, say so and move on. If it did not, refresh the contract once (`catalyst-skills contract --refresh`) and read it again; if it still did not, say what the page told them and what the instrument says, and ask what they saw.
|
|
23
|
+
|
|
24
|
+
Two or three short sentences per turn is the right size. A turn that lists every part's verdict is a wall of status, not help. The full report exists for you to read, not to paste.
|
|
17
25
|
|
|
18
26
|
## Run first
|
|
19
27
|
|
|
20
28
|
Scripts are run, never read. Each prints `--help`.
|
|
21
29
|
|
|
22
|
-
- `node scripts/where-am-i.mjs
|
|
23
|
-
- `node scripts/where-am-i.mjs
|
|
24
|
-
- `node scripts/where-am-i.mjs --json
|
|
25
|
-
- `node scripts/local-sync.mjs
|
|
26
|
-
|
|
27
|
-
Start every session with it, and run it again after every step the person completes. It is the only thing that decides where you are.
|
|
30
|
+
- `node scripts/where-am-i.mjs --next`: the single next step, with who owns it and where.
|
|
31
|
+
- `node scripts/where-am-i.mjs`: every part in the order above, each with its instrument, its verdict, and for anything unfinished who can fix it and the page it is on. Works before the machine is connected.
|
|
32
|
+
- `node scripts/where-am-i.mjs --json`: the same document for you to branch on.
|
|
33
|
+
- `node scripts/local-sync.mjs`: optional local replica and event sync status. Run `--start` only after the person chooses local sync.
|
|
28
34
|
|
|
29
35
|
## Load on demand
|
|
30
36
|
|
|
31
37
|
| when | read |
|
|
32
38
|
| -- | -- |
|
|
33
|
-
| walking the steps
|
|
34
|
-
| the
|
|
35
|
-
|
|
|
39
|
+
| walking the steps: what each is for, what to ask, what to read back, when it is done | `references/the-one-path.md` |
|
|
40
|
+
| the coding account: which kinds exist, what each one asks for, a cancelled or ended one | `references/choosing-a-coding-account.md` |
|
|
41
|
+
| the script says a coding account needs a new credential | `references/replacing-a-credential.md` |
|
|
36
42
|
| the next step is a browser page, or a page said it worked and you have to confirm it | `references/what-the-browser-owns.md` |
|
|
37
|
-
|
|
|
43
|
+
| anything reports not ready, or you are about to say who should fix something | `references/who-fixes-what.md` |
|
|
44
|
+
| the repository's settings file, `.catalyst/catalyst.toml`, and its approval | `references/declaring-a-repository.md` |
|
|
45
|
+
| the `host` part is not ok, or you are about to say work can run | `references/what-a-phase-needs.md` |
|
|
46
|
+
| the person chooses an optional local event and replica cache | `references/local-sync.md` |
|
|
47
|
+
| the person asks what Catalyst is, or how a ticket gets worked | the `how-catalyst-works` skill |
|
|
38
48
|
| the machine will not connect, or a login expired | the `connect-me` skill |
|
|
39
49
|
| the person asks how to install, update, or migrate Catalyst skills | `references/skill-sources.md` |
|
|
40
|
-
| the person's repository needs environment names declared | `references/declaring-a-repository.md` |
|
|
41
|
-
| the `coding accounts` or `host` part is not ok, or you are about to say work can run | `references/what-a-phase-needs.md` |
|
|
42
|
-
| the script says a coding account needs a new credential | `references/replacing-a-credential.md` |
|
|
43
50
|
| setup is finished and they want the standing readiness verdict | the `catalyst-setup` skill |
|
|
44
51
|
| the first ticket did not start and you need the reason | the `how-catalyst-works` skill, then `unstick` |
|
|
45
52
|
|
|
53
|
+
## Words
|
|
54
|
+
|
|
55
|
+
Use the product's words, and name the page label Settings shows today when it differs. **Workspace** is the whole customer account. **Project** is one Linear team plus the repositories registered to it. **Repository** is one `owner/name`. **Integration** is a workspace-level connection, the Linear connection or the GitHub App (the page is Settings → Connections). **Connected account** is the person's own Linear or GitHub login. **Member** is a person who can sign in. A **coding account** is an AI provider login the work runs on (Settings → AI accounts). Say "tenant" and "org" only when quoting a command's output.
|
|
56
|
+
|
|
46
57
|
## Rules
|
|
47
58
|
|
|
48
|
-
- **One step, then stop.** Say what you are about to do, do it, show the real output, say what it means
|
|
49
|
-
- **
|
|
50
|
-
- **
|
|
51
|
-
- **
|
|
52
|
-
- **
|
|
53
|
-
- **
|
|
54
|
-
- **
|
|
55
|
-
- **
|
|
56
|
-
- **
|
|
57
|
-
- **
|
|
58
|
-
- **
|
|
59
|
-
- **
|
|
60
|
-
- **
|
|
61
|
-
- **
|
|
62
|
-
- **
|
|
63
|
-
- **
|
|
59
|
+
- **One step, then stop.** Say what you are about to do and why, do it, show the real output, say what it means, ask the one question. Never queue several steps into one message, and never move on from a step you did not watch finish.
|
|
60
|
+
- **Open with the step, not a recap.** At most one clause on what is already done ("your coding account is in place"), then the step. Never list the parts with a status each; that is the report, and the report is for you.
|
|
61
|
+
- **One question has one answer.** Ask a yes-or-no, or one fact. Never offer two alternatives to choose between, and never pair a page to open with a second thing to do after it. If two things are needed, the second one waits for the next turn.
|
|
62
|
+
- **Say who can do a step; do not ask whether they are that person.** The script's `person` line already says their role. "This needs a workspace owner or admin, which you are" is a statement, not a question, and it never becomes a second thing to answer.
|
|
63
|
+
- **No internal labels reach the person.** Never cite a step number, a reference file, or "the script"; say what to do. The status line's `Tenant:` is their workspace; say "your workspace", never a tenant number.
|
|
64
|
+
- **Name accounts by their label.** "Your Claude account, Work laptop, is ready", never a slot id or "account 2". The script prints the label when the cloud has one.
|
|
65
|
+
- **Report what you observed, not what you expected.** Print the lines the command produced. "That worked" without the output is the easiest thing to get wrong here, and a person who later finds it did not work stops trusting every other step.
|
|
66
|
+
- **Each part by its own instrument.** The script labels every finding with the part it belongs to. Keep that when you summarize: a project problem is never a machine problem, and re-running a local command cannot move a check that belongs to an owner, an admin, or a browser page.
|
|
67
|
+
- **Not ready is a question about who.** Name which check, who can fix it, and where. If the owner is not the person in front of you, say so and stop.
|
|
68
|
+
- **Never invent a count or a list.** Every number and every name comes from what a command printed.
|
|
69
|
+
- **Provider consent belongs to the person in a browser.** Login approval, the workspace's Linear connection and GitHub App install, and the person's own connected accounts. Give the printed URL, then check `status`. Never claim a grant succeeded because a browser opened.
|
|
70
|
+
- **Some steps a key cannot do yet.** Listing every project, saving a stage mapping, adopting the workflow, registering a repository and approving one repository's settings file are settings-page work today. Route those through the browser and say plainly that it is a gap, not the design. Never guess at a route.
|
|
71
|
+
- **The workspace-wide environment declaration is the one setup write you can perform.** `catalyst-skills environment` reads it, proposes it and approves it.
|
|
72
|
+
- **Local sync is opt-in.** API-backed skills work without it. Ask before running `local-sync.mjs --start`; a detached process starting is not evidence of freshness. See `references/local-sync.md`.
|
|
73
|
+
- **A cancelled or ended coding account is kept, not retired.** It stays for reporting, is not used, and is never given a new token; a token minted from a live login must never land on it. Reactivating it is the person's call if the subscription comes back. Never tell anyone to retire or delete it.
|
|
74
|
+
- **Their workspace, as them.** Everything goes through the CLI and the person's own login. You never name another workspace, never ask for a key you could avoid, and never see a credential or a secret's value.
|
|
75
|
+
- **Ask once before you write to their machine or their repository.** Say what you found, what you will write and where, then wait for a yes.
|
|
76
|
+
- **A blocked command is the person's call.** If the harness blocks `npx`, a global install, or a tool, ask or hand them the command. Never skip it silently, never edit your own permission settings.
|
|
77
|
+
- **An older cloud is not a broken command.** When the CLI says the cloud is older than the bundle, say so and move on.
|
|
78
|
+
- **Stop at a wall you cannot pass.** A suspended workspace, a seat that is not active, a person who is not an owner or admin where one is required: say what you found, name who can act, and stop.
|
|
79
|
+
- **Write like a capable colleague.** Plain words, short sentences, one idea each, active voice, warm and unhurried. No em dashes, no emoji, no chatbot openers or flattery, and bold only the rare thing. Reread each message before you send it.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Choosing a coding account
|
|
2
|
+
|
|
3
|
+
A coding account is the AI provider login the work runs on. It is the first thing to settle, because nothing else in setup produces any work without one, and because it needs nothing else in setup to be done. Read the part with `node scripts/where-am-i.mjs`; it says whether one is enrolled, whether each enrolled one can still take work, and who may enrol one.
|
|
4
|
+
|
|
5
|
+
## The first question
|
|
6
|
+
|
|
7
|
+
Ask it plainly: "Do you already have a coding account you want Catalyst to run on?" Then wait.
|
|
8
|
+
|
|
9
|
+
Say why in one line: Catalyst runs each stage of a ticket on an account you own, so you pay your own provider at your own rate and keep the usage under your own name.
|
|
10
|
+
|
|
11
|
+
## What we support today
|
|
12
|
+
|
|
13
|
+
Four kinds. Name the one they have in their words, then in the page's words.
|
|
14
|
+
|
|
15
|
+
| they say | kind | what enrolling asks for | how they get it |
|
|
16
|
+
| -- | -- | -- | -- |
|
|
17
|
+
| "a Claude subscription", "Claude Pro or Max", "I use Claude Code" | Claude, a setup token | the token `claude setup-token` prints | on their own machine: run `claude`, check `/status` shows the account they mean, then run `claude setup-token` and copy the token |
|
|
18
|
+
| "ChatGPT", "Codex", "a ChatGPT Plus or Pro plan" | Codex, an auth file | the contents of `~/.codex/auth.json` | run `codex login`, choose "Sign in with ChatGPT"; the login writes the file. `$CODEX_HOME/auth.json` if `CODEX_HOME` is set. On macOS `pbcopy < ~/.codex/auth.json` copies it |
|
|
19
|
+
| "a GLM key", "Z.ai", "a GLM coding plan" | GLM, an API key | the provider's API key | from the provider's console |
|
|
20
|
+
| "a Qwen key", "Alibaba Model Studio", "a Qwen coding plan" | Qwen, an API key | the provider's API key | from the provider's console |
|
|
21
|
+
|
|
22
|
+
A plain Anthropic or OpenAI API key is not something the page can enrol today. If that is what they have, say so in one sentence and ask whether they also have one of the four above. Do not improvise a way in.
|
|
23
|
+
|
|
24
|
+
Codex has one more thing to say, before they paste: Catalyst takes over that login. Its refresh token is single-use, so the copy on their machine stops working once Catalyst uses it. To keep using Codex locally, they sign in again afterwards, separately.
|
|
25
|
+
|
|
26
|
+
## Enrolling one
|
|
27
|
+
|
|
28
|
+
Enrolling is a browser step, by construction: the person pastes a credential into a write-only field, and nothing you run ever sees it.
|
|
29
|
+
|
|
30
|
+
1. Hand over the page the script printed for the part (Settings → AI accounts). Say: "Choose the provider, give the account a label you will recognise, and paste the credential the page asks for. Nothing on this side sees it."
|
|
31
|
+
2. Wait. Do not run anything while they are on the page.
|
|
32
|
+
3. When they say it is saved, run `node scripts/where-am-i.mjs` and read them the `coding accounts` part. An enrolled and active account, named by its label, is proof. If the part still says none is enrolled, refresh the contract once (`catalyst-skills contract --refresh`) and read it again.
|
|
33
|
+
|
|
34
|
+
Only a workspace owner or admin can enrol one (the page still says "tenant" in places). If the person is neither, say who can, and stop this step there.
|
|
35
|
+
|
|
36
|
+
## Naming accounts
|
|
37
|
+
|
|
38
|
+
Call an account what the page calls it: its label, else its email, else its slot. `catalyst-skills accounts --json` carries this as `displayName`. Never call one "the first account" or "account 2", and never read out a credential.
|
|
39
|
+
|
|
40
|
+
## An account that already exists
|
|
41
|
+
|
|
42
|
+
The script reads each enrolled account. Read it back in their words:
|
|
43
|
+
|
|
44
|
+
- **Active, or attested.** "Your Claude account, Work laptop, is enrolled and can take work." Move on.
|
|
45
|
+
- **Out of rotation.** Every account is deactivated. Reactivate one on its own page. Never enrol another.
|
|
46
|
+
- **Needs a new credential.** Quarantined, expired or revoked, or its last polls failed on the credential itself. Replace the credential on that account's own page, with a credential from that same login. The steps, and the login check that has to come first, are in `references/replacing-a-credential.md`. Never enrol a second account for this.
|
|
47
|
+
- **Cancelled or ended.** The subscription was cancelled, or the provider ended the account. Say so in one clause and move on: it stays for reporting, it is not used, and it is not counted against setup. Never paste a token from another login into it, which would put a live account's credential onto a dead slot, and never tell them to retire or delete it. If the subscription comes back, they reactivate it on its own page.
|
|
48
|
+
- **Could not be read.** Say the accounts could not be read this time and read again later. It is not "no accounts". Do not tell them to enrol one on this reading.
|
|
49
|
+
|
|
50
|
+
## When more than one is right
|
|
51
|
+
|
|
52
|
+
One account is enough to start. A second one, on a different provider or plan, gives the router somewhere to go when the first is at its limit. Offer it as a later improvement, not as a step now.
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
The cloud containers build and test the repository. They need the names of the variables and secrets it reads. You write the names; the person enters the values in the app. Never read or print a value.
|
|
4
4
|
|
|
5
|
+
This is step 8 of `references/the-one-path.md`. Offer to draft the file from the repository's own build files, say which files you will read and what you will write, and wait for a yes before you write anything. If the repository already has one, verify it against the inventory below instead of rewriting it.
|
|
6
|
+
|
|
5
7
|
## The inventory, in order
|
|
6
8
|
|
|
7
|
-
1. Start from the commands that already build and test the repository: the README's setup section, the scripts in `package.json` or its equivalent, and the build and test steps in CI. Those are what the container runs. A name they never read does not belong in the file.
|
|
9
|
+
1. Start from the commands that already build and test the repository: the README's setup section, the scripts in `package.json` or its equivalent, and the build and test steps in CI. Those are what the container runs. A name they never read does not belong in the file. Read these files directly; the inventory needs no git command.
|
|
8
10
|
2. For each name, record the file it came from: a `.env.example` (never `.env`, which holds live values), a CI secret in a workflow's `env:` block, or a platform binding. A name you cannot tie to a file is a guess. Say so instead of listing it.
|
|
9
11
|
3. Mark whether the container needs it to build and test, or only to deploy. Containers build and test. They do not deploy.
|
|
10
12
|
4. Leave platform bindings and deploy-only CI secrets out by default. The platform supplies a binding at run time, and no build or test reads a deploy-only secret. Include one only when the person says the build needs it, and say why.
|
|
@@ -41,4 +43,4 @@ run = ["npm", "ci"]
|
|
|
41
43
|
|
|
42
44
|
## After the merge
|
|
43
45
|
|
|
44
|
-
`catalyst-skills ready` reports `environment_declared` for the team's default repository and names the next step: commit the file, fix it, or approve it. The `catalyst-setup` check table has each reason. The
|
|
46
|
+
`catalyst-skills ready` reports `environment_declared` for the team's default repository and names the next step: commit the file, fix it, or approve it. The `catalyst-setup` check table has each reason. The workspace-wide declaration is separate; `catalyst-skills environment` handles it (also step 8 of `references/the-one-path.md`).
|
|
@@ -34,7 +34,11 @@ Say these two things plainly:
|
|
|
34
34
|
|
|
35
35
|
## Claude
|
|
36
36
|
|
|
37
|
-
The same page takes a Claude account's new credential. Its field is "Replacement setup token".
|
|
37
|
+
The same page takes a Claude account's new credential. Its field is "Replacement setup token". `claude setup-token` mints a token for whichever Claude account the terminal is logged into, not for the slot. So first match them: read the slot's account on the AI accounts page (its label or email), then have the person run `claude` and `/status` to see the email the terminal is logged into. If they differ, stop, and log in to the slot's account first. Only then run `claude setup-token`, paste the token into that field, and press Replace credential. Then re-run the script.
|
|
38
|
+
|
|
39
|
+
## A cancelled or ended account
|
|
40
|
+
|
|
41
|
+
An account whose subscription is cancelled, or which has ended, is not a credential problem, and no token revives it. It stays enrolled for reporting, is not used, and is not something to retire or delete. Never replace its credential with a token from another account: that puts a working account's login onto a dead slot. If the subscription is live again, the person reactivates it on its own page.
|
|
38
42
|
|
|
39
43
|
## Any other provider
|
|
40
44
|
|