@catalyst-cloud/cli 0.15.6 → 0.16.1
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 +13 -0
- package/README.md +9 -6
- package/dist/args.js +26 -1
- package/dist/ask.js +56 -0
- package/dist/capabilities.js +3 -1
- package/dist/cli.js +10 -5
- package/dist/environment.js +1 -1
- package/dist/execution.js +2 -2
- package/dist/hosts.js +89 -0
- package/dist/legacy.js +12 -2
- package/dist/machine-inventory.js +37 -0
- package/dist/onboard-capacity.js +5 -6
- package/dist/onboard-github-copy.js +2 -0
- package/dist/onboard-github.js +2 -0
- package/dist/onboard-headless.js +2 -2
- package/dist/onboard-next.js +21 -12
- package/dist/onboard-project-cleanup.js +100 -0
- package/dist/onboard-returning.js +172 -0
- package/dist/onboard-runner.js +149 -34
- package/dist/onboard-runtime.js +26 -1
- package/dist/onboard-ui.js +67 -1
- package/dist/onboard-workflow.js +32 -7
- package/dist/onboard.js +9 -2
- package/dist/ready-copy.js +30 -24
- package/dist/ready.js +2 -2
- package/dist/secret.js +2 -2
- package/dist/setup-onboard-copy.js +37 -32
- package/dist/setup.js +4 -0
- package/dist/transport.js +18 -2
- package/package.json +8 -5
- package/skills/catalyst-github/SKILL.md +1 -1
- package/skills/catalyst-linear/SKILL.md +1 -1
- package/skills/catalyst-onboard/SKILL.md +3 -3
- package/skills/catalyst-onboard/references/connecting-this-machine.md +4 -4
- package/skills/catalyst-onboard/references/declaring-a-repository.md +1 -1
- package/skills/catalyst-onboard/references/reading-ready.md +14 -14
- package/skills/catalyst-onboard/references/replacing-a-credential.md +1 -1
- package/skills/catalyst-onboard/references/the-one-path.md +5 -5
- package/skills/catalyst-onboard/references/what-a-phase-needs.md +4 -4
- package/skills/catalyst-onboard/references/what-the-browser-owns.md +20 -10
- package/skills/catalyst-onboard/scripts/where-am-i.mjs +50 -27
- package/skills/run-this-project/SKILL.md +1 -1
- package/skills/run-this-project/references/stalls-and-escalation.md +1 -1
- package/skills/unstick/SKILL.md +1 -1
- package/skills/what-needs-me/SKILL.md +2 -2
- package/skills/what-needs-me/references/raising-a-decision.md +12 -1
- package/skills/what-needs-me/references/reading-the-inbox.md +1 -1
- package/skills/what-needs-me/scripts/raise.mjs +10 -1
- package/skills/what-this-repo-needs/SKILL.md +1 -1
- package/skills/whats-happening/SKILL.md +3 -2
- package/skills/whats-happening/references/coding-accounts.md +1 -1
- package/skills/whats-happening/references/machines.md +9 -0
- package/skills/whats-happening/references/settings-and-where-they-live.md +8 -8
- package/skills/whats-happening/references/stages-and-mapping.md +1 -1
|
@@ -8,9 +8,9 @@ One coding account is enough to start. A second gives the router somewhere to go
|
|
|
8
8
|
|
|
9
9
|
### The kinds, and enrolling
|
|
10
10
|
|
|
11
|
-
Settings → AI accounts lists the providers this workspace can connect and what each one asks for; an API key is billed per token by its provider. Do not promise a provider. Ask the person
|
|
11
|
+
Settings → AI accounts lists the providers this workspace can connect and what each one asks for; an API key is billed per token by its provider. Do not promise a provider. Ask which provider the person has a key for. No command lists the providers yet, so check the name against that page; if it is not there, say so and ask whether they have a key from one that is.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Adding an account has no command yet, so it is a browser step for now: on Settings → AI accounts, an owner or admin picks the provider, labels the account, and pastes the key into a write-only field. If the page says Catalyst takes over a login, say so before the paste. Call an account by its label, else its email, else its slot (`displayName` in `catalyst accounts --json`).
|
|
14
14
|
|
|
15
15
|
### The states
|
|
16
16
|
|
|
@@ -19,8 +19,8 @@ Enrolling is a browser step by construction: on Settings → AI accounts, an own
|
|
|
19
19
|
| state | what it says | what to do |
|
|
20
20
|
| -- | -- | -- |
|
|
21
21
|
| `enrolled` | one is active; another can still have a dead credential | "<provider> account <slot> needs a new credential" is the next step: `references/replacing-a-credential.md`. `unreadable` detail: read again later |
|
|
22
|
-
| `none_enrolled` | none enrolled | hand over the page to the enroller the contract names |
|
|
23
|
-
| `inactive` | every account is out of rotation | reactivate one on its page, never enrol another |
|
|
22
|
+
| `none_enrolled` | none enrolled | hand over the page to the enroller the contract names; there is no command to add one yet |
|
|
23
|
+
| `inactive` | every account is out of rotation | reactivate one on its page (no command does this yet), never enrol another |
|
|
24
24
|
| `unread` | the cloud could not read them | it is not "no accounts"; read again later |
|
|
25
25
|
|
|
26
26
|
**A cancelled or ended account** stays for reporting, unused, and does not hold setup up; say so in one clause. It keeps its own login: a token from another login would put a live account onto a dead slot. It stays enrolled rather than retired or deleted, and is reactivated on its page only if it can run again.
|
|
@@ -1,27 +1,37 @@
|
|
|
1
1
|
# What the browser owns
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Headless first: when the catalyst CLI, the SDK or an agent route can do a step, ask "Want me to do that for you?" and run it on a yes; name a web page only for a step that needs a person in a browser by nature (signing in, an OAuth or app-install consent), and then hand over the exact link the CLI printed. A step with no command yet is a gap: say so in one clause and hand over the exact page.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Commands you offer to run
|
|
6
6
|
|
|
7
|
-
| step |
|
|
7
|
+
| step | command |
|
|
8
|
+
| -- | -- |
|
|
9
|
+
| registering a repository and attaching it to a project | `catalyst onboard --team <KEY> --repo <owner/name>` (an owner or admin) |
|
|
10
|
+
| checking, mapping or adopting a project's stages | `catalyst team check <KEY>`, `catalyst team map <KEY>`, `catalyst team adopt <KEY>` |
|
|
11
|
+
| entering a repository's values | `catalyst var set NAME --repo <owner/name>`, `catalyst secret set NAME --repo <owner/name>` |
|
|
12
|
+
| creating `<your GitHub org>/thoughts` | `gh repo create <org>/thoughts --private --add-readme` |
|
|
13
|
+
|
|
14
|
+
## A browser by nature
|
|
15
|
+
|
|
16
|
+
Each is a sign-in or a consent a person grants in their own session. Start it with the command, then hand over only the link it printed.
|
|
17
|
+
|
|
18
|
+
| step | how it starts |
|
|
8
19
|
| -- | -- |
|
|
9
20
|
| approving the login | the URL and short code `catalyst login` printed |
|
|
10
|
-
|
|
|
11
|
-
|
|
|
12
|
-
| creating `<your GitHub org>/thoughts` and letting the App reach it | GitHub, then the App's installation page for that org: All repositories, or add `thoughts` (step 5 of `references/the-one-path.md`) |
|
|
21
|
+
| connecting the Linear integration, installing the GitHub App | `catalyst onboard` prints the consent link; without one, `<their cloud>/settings/connections` (Settings → Integrations) |
|
|
22
|
+
| letting the App reach `<your GitHub org>/thoughts` | the App's installation page for that org: All repositories, or add `thoughts` (step 5 of `references/the-one-path.md`) |
|
|
13
23
|
| connecting personal Linear, then personal GitHub | the URL `catalyst connections personal <linear\|github> start` printed |
|
|
14
24
|
|
|
15
25
|
## Not a command yet
|
|
16
26
|
|
|
17
|
-
|
|
27
|
+
These have no command in this CLI yet. Say so in one clause, hand over the page, and never guess at a route.
|
|
18
28
|
|
|
19
29
|
| step | where |
|
|
20
30
|
| -- | -- |
|
|
21
|
-
|
|
|
22
|
-
| approving one repository's declaration
|
|
31
|
+
| adding a coding account, or replacing its credential | the AI accounts page the script printed |
|
|
32
|
+
| approving one repository's declaration | that repository's Environment page (`references/declaring-a-repository.md`) |
|
|
23
33
|
|
|
24
|
-
`catalyst environment` handles a workspace-wide declaration. ⛔ Only the CLI makes requests; if you find yourself building a URL for one of these, stop.
|
|
34
|
+
`catalyst environment` handles a workspace-wide declaration. `catalyst capabilities` lists what this CLI can do; a verb it lists replaces the page for that step. ⛔ Only the CLI makes requests; if you find yourself building a URL for one of these, stop.
|
|
25
35
|
|
|
26
36
|
## The link to hand over
|
|
27
37
|
|
|
@@ -85,6 +85,10 @@ const verbAdminOnly = (verb) => {
|
|
|
85
85
|
const c = capability(verb);
|
|
86
86
|
return c?.availability === "available" && c.needs === "admin" && !canManage();
|
|
87
87
|
};
|
|
88
|
+
// `catalyst onboard` starts the workspace consents and registers a repository; an older CLI has no
|
|
89
|
+
// such verb, and then the step stays the page.
|
|
90
|
+
const onboardAvailable = () => capability("onboard")?.availability === "available";
|
|
91
|
+
const UPDATE_CLI = "npm install -g @catalyst-cloud/cli@latest";
|
|
88
92
|
// `blocking` is false for a finding that is real and reportable but does not stop the next step —
|
|
89
93
|
// an unmatched Linear identity is the one that matters: it must be said, and it must not become the
|
|
90
94
|
// thing the person is told to go and do before they can map a project.
|
|
@@ -335,12 +339,12 @@ if (!connected) {
|
|
|
335
339
|
? "you"
|
|
336
340
|
: matched
|
|
337
341
|
? null
|
|
338
|
-
: "
|
|
342
|
+
: "you",
|
|
339
343
|
personalGrantIncomplete
|
|
340
344
|
? "catalyst connections personal <provider> start or status"
|
|
341
345
|
: matched
|
|
342
346
|
? null
|
|
343
|
-
:
|
|
347
|
+
: "catalyst identity linear options",
|
|
344
348
|
false,
|
|
345
349
|
);
|
|
346
350
|
}
|
|
@@ -424,7 +428,7 @@ if (!connected) {
|
|
|
424
428
|
...envLines,
|
|
425
429
|
],
|
|
426
430
|
"a workspace owner or admin",
|
|
427
|
-
link("/settings/connections"),
|
|
431
|
+
onboardAvailable() ? "catalyst onboard" : link("/settings/connections"),
|
|
428
432
|
);
|
|
429
433
|
}
|
|
430
434
|
}
|
|
@@ -538,7 +542,7 @@ if (!connected) {
|
|
|
538
542
|
);
|
|
539
543
|
blockedProjects.push({
|
|
540
544
|
key,
|
|
541
|
-
action: `fix ${key}'s blocking check${ids.length === 1 ? "" : "s"} (${ids.join(", ") || "see the projects lines"}): ${how || owner}; then run catalyst team check ${key}
|
|
545
|
+
action: `fix ${key}'s blocking check${ids.length === 1 ? "" : "s"} (${ids.join(", ") || "see the projects lines"}): ${how || owner}; then run catalyst team check ${key} and run this again`,
|
|
542
546
|
owner,
|
|
543
547
|
});
|
|
544
548
|
}
|
|
@@ -565,7 +569,11 @@ if (!connected) {
|
|
|
565
569
|
: "a workspace owner or admin";
|
|
566
570
|
const mapWhere = verbAvailable("team map")
|
|
567
571
|
? "catalyst team list"
|
|
568
|
-
:
|
|
572
|
+
: verbAdminOnly("team map")
|
|
573
|
+
? "catalyst team map <KEY>"
|
|
574
|
+
: capability("team map")
|
|
575
|
+
? link("/settings/projects")
|
|
576
|
+
: UPDATE_CLI;
|
|
569
577
|
const projectOwner =
|
|
570
578
|
blockedProjects.length > 0 ? blockedProjects[0].owner : mapOwner;
|
|
571
579
|
const projectWhere = blockedProjects.length > 0 ? null : mapWhere;
|
|
@@ -653,7 +661,9 @@ if (!connected) {
|
|
|
653
661
|
rows.length > 0 ? "ok" : "unfinished",
|
|
654
662
|
lines,
|
|
655
663
|
"a workspace owner or admin",
|
|
656
|
-
|
|
664
|
+
onboardAvailable()
|
|
665
|
+
? "catalyst onboard --team <KEY> --repo <owner/name>"
|
|
666
|
+
: link("/settings/projects"),
|
|
657
667
|
);
|
|
658
668
|
}
|
|
659
669
|
}
|
|
@@ -908,8 +918,9 @@ if (!connected) {
|
|
|
908
918
|
}
|
|
909
919
|
}
|
|
910
920
|
|
|
911
|
-
// the
|
|
912
|
-
//
|
|
921
|
+
// the re-check step, always `catalyst team check`: run it when this person can, name the owner or
|
|
922
|
+
// admin who can otherwise. A CLI without the verb is told to update; only a cloud that does not
|
|
923
|
+
// serve the route yet falls back to the projects page.
|
|
913
924
|
const mappedKeys = () =>
|
|
914
925
|
(teamRows ?? [])
|
|
915
926
|
.map((t) => t.key ?? t.id)
|
|
@@ -925,14 +936,21 @@ const recheckStep = () => {
|
|
|
925
936
|
};
|
|
926
937
|
if (cmds.length > 0 && verbAdminOnly("team check"))
|
|
927
938
|
return {
|
|
928
|
-
action: `a workspace owner or admin runs ${cmds.join(" and ")}
|
|
939
|
+
action: `a workspace owner or admin runs ${cmds.join(" and ")}; then run this again`,
|
|
929
940
|
owner: "a workspace owner or admin",
|
|
930
|
-
where:
|
|
941
|
+
where: cmds[0],
|
|
942
|
+
};
|
|
943
|
+
if (capability("team check"))
|
|
944
|
+
return {
|
|
945
|
+
action:
|
|
946
|
+
"this cloud does not serve catalyst team check yet, so a workspace owner or admin re-checks the project on the projects page; then run this again",
|
|
947
|
+
owner: "a workspace owner or admin",
|
|
948
|
+
where: link("/settings/projects"),
|
|
931
949
|
};
|
|
932
950
|
return {
|
|
933
|
-
action:
|
|
951
|
+
action: `update the CLI (${UPDATE_CLI}), then a workspace owner or admin runs catalyst team check ${cmds.length > 0 ? mappedKeys()[0] : "<KEY>"}; then run this again`,
|
|
934
952
|
owner: "a workspace owner or admin",
|
|
935
|
-
where:
|
|
953
|
+
where: UPDATE_CLI,
|
|
936
954
|
};
|
|
937
955
|
};
|
|
938
956
|
|
|
@@ -989,7 +1007,7 @@ if (!connected) {
|
|
|
989
1007
|
: "no project has a readiness check yet, so whether a host is connected cannot be read.",
|
|
990
1008
|
],
|
|
991
1009
|
teamRows === null ? "a workspace owner or admin" : step.owner,
|
|
992
|
-
teamRows === null ?
|
|
1010
|
+
teamRows === null ? "catalyst contract --refresh" : step.where,
|
|
993
1011
|
).next =
|
|
994
1012
|
teamRows === null
|
|
995
1013
|
? "refresh the contract (catalyst contract --refresh), then run this again; the project list could not be read, so the host check cannot be either"
|
|
@@ -1030,7 +1048,7 @@ const DECL_INSTRUMENT =
|
|
|
1030
1048
|
"environment_declared in catalyst contract --path teams";
|
|
1031
1049
|
const DECL_REASONS = {
|
|
1032
1050
|
no_team_repo_default: {
|
|
1033
|
-
text: "no repository is the project's default yet: register one and make it the default",
|
|
1051
|
+
text: "no repository is the project's default yet: register one and make it the default (catalyst onboard --team <KEY> --repo <owner/name> registers it; the default is chosen on Your projects, with no command yet)",
|
|
1034
1052
|
who: "a workspace owner or admin",
|
|
1035
1053
|
page: "/settings/projects",
|
|
1036
1054
|
},
|
|
@@ -1050,7 +1068,7 @@ const DECL_REASONS = {
|
|
|
1050
1068
|
page: null,
|
|
1051
1069
|
},
|
|
1052
1070
|
declaration_awaiting_approval: {
|
|
1053
|
-
text: "the declaration is proposed and waits for approval: Settings → Your projects → the project → Repositories → the repository → Environment → Setup declaration → Approve this revision",
|
|
1071
|
+
text: "the declaration is proposed and waits for approval, because no review approved it (a non-author approval of the merged head, or a merge by an owner or admin): approve it at Settings → Your projects → the project → Repositories → the repository → Environment → Setup declaration → Approve this revision (no command approves one repository's revision yet)",
|
|
1054
1072
|
who: "a workspace owner or admin",
|
|
1055
1073
|
page: "/settings/projects",
|
|
1056
1074
|
},
|
|
@@ -1058,7 +1076,7 @@ const DECL_REASONS = {
|
|
|
1058
1076
|
const DECL_DO =
|
|
1059
1077
|
"write .catalyst/catalyst.toml with references/declaring-a-repository.md, then open a pull request";
|
|
1060
1078
|
let declNext =
|
|
1061
|
-
"
|
|
1079
|
+
"merge .catalyst/catalyst.toml through a pull request that someone other than the author approves; that review approves it";
|
|
1062
1080
|
if (!connected) {
|
|
1063
1081
|
add(
|
|
1064
1082
|
"repository declarations",
|
|
@@ -1123,9 +1141,10 @@ if (!connected) {
|
|
|
1123
1141
|
let unknown = false;
|
|
1124
1142
|
const describe = (reason) =>
|
|
1125
1143
|
DECL_REASONS[reason] ?? {
|
|
1126
|
-
text: `environment_declared ${reason ?? "failed"} (a reason this bundle does not know;
|
|
1144
|
+
text: `environment_declared ${reason ?? "failed"} (a reason this bundle does not know; catalyst ready --json prints its fix line)`,
|
|
1127
1145
|
who: "a workspace owner or admin",
|
|
1128
|
-
page:
|
|
1146
|
+
page: null,
|
|
1147
|
+
do: "catalyst ready --json",
|
|
1129
1148
|
};
|
|
1130
1149
|
const flag = (team, repo, reason) => {
|
|
1131
1150
|
const r = describe(reason);
|
|
@@ -1133,7 +1152,7 @@ if (!connected) {
|
|
|
1133
1152
|
if (verdict === "ok") declNext = `${repo ? `${repo}: ` : ""}${r.text}`;
|
|
1134
1153
|
verdict = "unfinished";
|
|
1135
1154
|
owner ??= r.who;
|
|
1136
|
-
where ??= r.page === null ? DECL_DO : link(r.page);
|
|
1155
|
+
where ??= r.do ?? (r.page === null ? DECL_DO : link(r.page));
|
|
1137
1156
|
};
|
|
1138
1157
|
if (found.length === 0) {
|
|
1139
1158
|
lines.push(
|
|
@@ -1169,7 +1188,7 @@ if (!connected) {
|
|
|
1169
1188
|
} else {
|
|
1170
1189
|
if (verdict !== "ok")
|
|
1171
1190
|
lines.push(
|
|
1172
|
-
"Names only: a value never passes through this script or the file. The person enters
|
|
1191
|
+
"Names only: a value never passes through this script or the file. The person enters each value at a hidden prompt: catalyst var set NAME --repo <owner/name>, or catalyst secret set NAME --repo <owner/name> for a secret.",
|
|
1173
1192
|
);
|
|
1174
1193
|
add(
|
|
1175
1194
|
"repository declarations",
|
|
@@ -1285,18 +1304,22 @@ const NEXT = {
|
|
|
1285
1304
|
: personalGithubIncomplete
|
|
1286
1305
|
? "install the tenant GitHub App and register its repository before connecting your personal GitHub account"
|
|
1287
1306
|
: "get this person's seat and Linear identity sorted",
|
|
1288
|
-
account:
|
|
1289
|
-
"
|
|
1307
|
+
account: onboardAvailable()
|
|
1308
|
+
? "start the Linear integration with catalyst onboard and hand over the consent link it prints (the GitHub App comes later, with the repository)"
|
|
1309
|
+
: "connect the Linear integration on the Integrations page (the GitHub App comes later, with the repository)",
|
|
1290
1310
|
projects:
|
|
1291
1311
|
blockedProjects.length > 0
|
|
1292
1312
|
? blockedProjects.map((b) => b.action).join("; and ")
|
|
1293
1313
|
: verbAvailable("team map")
|
|
1294
1314
|
? "pick ONE project: run catalyst team list, then catalyst team map <KEY> (or team adopt <KEY>) and approve its preview"
|
|
1295
1315
|
: verbAdminOnly("team map")
|
|
1296
|
-
? "a workspace owner or admin maps ONE project: catalyst team map <KEY
|
|
1297
|
-
: "
|
|
1298
|
-
|
|
1299
|
-
|
|
1316
|
+
? "a workspace owner or admin maps ONE project: catalyst team map <KEY> (or team adopt <KEY>), approving its preview"
|
|
1317
|
+
: capability("team map")
|
|
1318
|
+
? "pick ONE project and map its stages (or adopt the Catalyst workflow) on the projects page; this cloud does not serve catalyst team map yet"
|
|
1319
|
+
: `pick ONE project and map its stages with catalyst team map <KEY> (or team adopt <KEY>); this CLI is too old for that verb, so update it first: ${UPDATE_CLI}`,
|
|
1320
|
+
repositories: onboardAvailable()
|
|
1321
|
+
? "install the GitHub App from the link catalyst onboard prints, granting it the repository you want worked; then register it and attach it to the project with catalyst onboard --team <KEY> --repo <owner/name> before continuing"
|
|
1322
|
+
: "install the GitHub App on the Integrations page, granting it the repository you want worked; register it on Your projects and attach it to the project before continuing",
|
|
1300
1323
|
"coding accounts": accountsNext,
|
|
1301
1324
|
"repository declarations": declNext,
|
|
1302
1325
|
"repository agent setup": repoNext ?? "read the checkout's agent setup again",
|
|
@@ -1365,7 +1388,7 @@ function versionAdvice() {
|
|
|
1365
1388
|
const latest = npm.error || npm.status !== 0 ? null : semver(npm.stdout);
|
|
1366
1389
|
// The installer is the update path, not `catalyst install`. Its command is on the app's
|
|
1367
1390
|
// setup page; this names the script it fetches rather than composing the request here.
|
|
1368
|
-
const reinstall = `re-run the install
|
|
1391
|
+
const reinstall = `run ${UPDATE_CLI}, or re-run the install script at ${link("/install.sh")}`;
|
|
1369
1392
|
if (installed === null || latest === null) {
|
|
1370
1393
|
return {
|
|
1371
1394
|
text: `Whether a newer Catalyst CLI is published could not be checked. You can ${reinstall}; if this still appears afterwards, tell the Catalyst team.`,
|
|
@@ -4,7 +4,7 @@ description: >-
|
|
|
4
4
|
Own one Catalyst Cloud project end to end until it closes. Use when the person says "run this project for me", "own this until it ships", "keep this moving", or hands you a project id or a set of tickets to drive. Subscribes to the account's event stream for the scope through the catalyst CLI, reacts to each change in the same turn, makes tickets ready and moves them to dispatch, parks what should stop, chases stalls, escalates inward, and keeps one status summary current. Writes to Linear as the app actor; never polls.
|
|
5
5
|
allowed-tools: Bash(catalyst:*) Bash(npx -p @catalyst-cloud/cli catalyst:*)
|
|
6
6
|
---
|
|
7
|
-
<!-- vendored-from: @catalyst-cloud/catalyst-skills@0.
|
|
7
|
+
<!-- vendored-from: @catalyst-cloud/catalyst-skills@0.16.1 — written in this repository for customer accounts -->
|
|
8
8
|
|
|
9
9
|
# Run this project
|
|
10
10
|
|
|
@@ -17,7 +17,7 @@ Run `catalyst explain <ticket>` and look the reason up in the `whats-happening`
|
|
|
17
17
|
- **It releases itself:** wait for the outcome card.
|
|
18
18
|
- **The person, with their own login, acts:** do it when the move is yours (re-dispatch, a comment that clears a no-change or validate-budget hold, a question routed to `what-needs-me`), and file an ask when it is theirs.
|
|
19
19
|
- **A park or hold a release clears:** once its cause is fixed, the `unstick` skill releases it (`catalyst release <ticket> --because <what changed>`). A round-threshold hold and a review that will not converge refuse that release; the table says what clears each.
|
|
20
|
-
- **An owner or admin, in settings, or an operator:** one ask per repository or setting.
|
|
20
|
+
- **An owner or admin, in settings, or an operator:** when the person holds that seat and a command can make the change, offer to run it; otherwise one ask per repository or setting.
|
|
21
21
|
- **Finished:** close the loop in the summary.
|
|
22
22
|
|
|
23
23
|
Quote a reason the table does not know as the explainer spelled it.
|
package/skills/unstick/SKILL.md
CHANGED
|
@@ -4,7 +4,7 @@ description: >-
|
|
|
4
4
|
Get a stuck Catalyst Cloud ticket moving again. Use when the person asks "why is this parked and can you release it?", "unpark this", "get things flowing again", "the outage is over, retry what failed", or hands you a ticket that is not moving. Reads why nothing runs and what holds the ticket through the catalyst CLI, decides whether the recorded cause is fixed, previews the release, releases every governor holding the ticket the right way (or one failure class across a team), and raises an ask only for what a person has to do. Never releases a cause it cannot show changed without saying so.
|
|
5
5
|
allowed-tools: Bash(catalyst:*) Bash(npx -p @catalyst-cloud/cli catalyst:*)
|
|
6
6
|
---
|
|
7
|
-
<!-- vendored-from: @catalyst-cloud/catalyst-skills@0.
|
|
7
|
+
<!-- vendored-from: @catalyst-cloud/catalyst-skills@0.16.1 — written in this repository for customer accounts -->
|
|
8
8
|
|
|
9
9
|
# Unstick
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ description: >-
|
|
|
4
4
|
The human's decision inbox on Catalyst Cloud, and the one way an agent raises a decision on their behalf. Use when the person asks "what needs me?", "what am I blocking?", or when active work is gated on a choice only they can make. Lists open asks ranked by how much open work each one holds, files an ask through the cloud's ask route with the account's own template, and records the answer so the held work releases. Never answers as the human, never duplicates an open ask.
|
|
5
5
|
allowed-tools: Bash(catalyst:*) Bash(npx -p @catalyst-cloud/cli catalyst:*)
|
|
6
6
|
---
|
|
7
|
-
<!-- vendored-from: @catalyst-cloud/catalyst-skills@0.
|
|
7
|
+
<!-- vendored-from: @catalyst-cloud/catalyst-skills@0.16.1 — written in this repository for customer accounts -->
|
|
8
8
|
|
|
9
9
|
# What needs me
|
|
10
10
|
|
|
@@ -15,7 +15,7 @@ An ask is one decision only the human can make, filed as a ticket in their own L
|
|
|
15
15
|
Scripts are run, never read. Each prints `--help`; exit 2 means this machine is not connected (the `catalyst-onboard` skill connects it), exit 1 means the check itself failed or an argument was missing.
|
|
16
16
|
|
|
17
17
|
- `node scripts/inbox.mjs --help`: the open asks assigned to the connected person, most open tickets held first, then the oldest; `--anyone` for everyone's; `--json` for `{scope, asks}`.
|
|
18
|
-
- `node scripts/raise.mjs --help`: file one decision: `--team`, `--title`, `--option` (repeated), `--default`, and `--blocks` (repeated) or `--nothing-to-block`.
|
|
18
|
+
- `node scripts/raise.mjs --help`: file one decision: `--team`, `--title`, `--option` (repeated), `--default`, and `--blocks` (repeated) or `--nothing-to-block`. When the ask decides whether a held PR may merge, `--gates-pr` (repeated) with `--released-by <letter>` makes the answer lift that PR's hold label.
|
|
19
19
|
- `node scripts/settle.mjs --help`: record the answering comment on an ask and post a release note on every ticket it held; `--close` moves the ask to the done slot.
|
|
20
20
|
|
|
21
21
|
## Load on demand
|
|
@@ -4,7 +4,7 @@ The body, headings, option format and option cap come from the contract's `askTe
|
|
|
4
4
|
|
|
5
5
|
## When to file one
|
|
6
6
|
|
|
7
|
-
File an ask when active work is gated on a product call, a priority call between two things that cannot both go first, an approval, or an action only the human can take (a
|
|
7
|
+
File an ask when active work is gated on a product call, a priority call between two things that cannot both go first, an approval, or an action only the human can take (a sign-in or consent, a credential, a payment). A settings change a command can make is yours to offer, not an ask. File it **before** proceeding on the default. A TODO line, board row, handoff note or chat question may point at the ask's identifier, never replace it.
|
|
8
8
|
|
|
9
9
|
Brainstorming, design back-and-forth, a question the human asked first, a retry-or-abandon call a project owner can make, and a system-level failure (one status line; the tickets retry on their own) are not asks.
|
|
10
10
|
|
|
@@ -18,6 +18,17 @@ Brainstorming, design back-and-forth, a question the human asked first, a retry-
|
|
|
18
18
|
|
|
19
19
|
`--ask-key` is an idempotency key: a re-run with the same key does not file a second ask.
|
|
20
20
|
|
|
21
|
+
## When the answer releases a PR hold
|
|
22
|
+
|
|
23
|
+
When the decision is whether a held PR may merge, name the PR so the answer lifts the hold itself:
|
|
24
|
+
|
|
25
|
+
- `--gates-pr <n>` (repeated): each PR the answer releases.
|
|
26
|
+
- `--released-by <letter>` (repeated, required with `--gates-pr`): the option letters that release it. Options are lettered A, B, C in the order you gave them, and a letter outside that range is refused.
|
|
27
|
+
- `--gates-label hold|hold:preview` (repeated, default `hold`): the labels the answer removes. No other label is accepted.
|
|
28
|
+
- `--gates-repo <owner/name>`: the PR's repository. It defaults to the account's repository when the account registers exactly one, and must be one the account registers.
|
|
29
|
+
|
|
30
|
+
An answer with any other letter leaves the labels in place.
|
|
31
|
+
|
|
21
32
|
## One ask per decision
|
|
22
33
|
|
|
23
34
|
Run `node scripts/inbox.mjs` first. When the same decision is already open, attach the new held tickets to it (the `catalyst-linear` skill adds the relation or a comment) rather than filing a twin that splits its urgency.
|
|
@@ -19,7 +19,7 @@ So an ask that holds nothing is real, but the person may never see it in their o
|
|
|
19
19
|
|
|
20
20
|
## The identity is not the same as the personal Linear grant
|
|
21
21
|
|
|
22
|
-
When asks are not reaching someone, check the identity first, then the grant. The **identity** is who they are in Linear, resolved by an email match or matched by the person (`catalyst identity linear status`, `options`, then `catalyst identity linear set <linearUserId>`). The **personal Linear grant** is proven by connecting Linear themselves. Connecting Linear personally does **not** set the identity. An auto-resolved identity, or one another member claims, needs an owner or admin at Settings → Members. With no identity nothing is assigned to them, even after they connect Linear, so an `unmatched` scope is not an empty queue: say "nothing is assigned to you yet, so this is everyone's list; match your identity with `catalyst identity linear set` and it becomes yours".
|
|
22
|
+
When asks are not reaching someone, check the identity first, then the grant. The **identity** is who they are in Linear, resolved by an email match or matched by the person (`catalyst identity linear status`, `options`, then `catalyst identity linear set <linearUserId>`). The **personal Linear grant** is proven by connecting Linear themselves. Connecting Linear personally does **not** set the identity. An auto-resolved identity, or one another member claims, needs an owner or admin at Settings → Members; no command does this yet, so raise an ask to them. With no identity nothing is assigned to them, even after they connect Linear, so an `unmatched` scope is not an empty queue: say "nothing is assigned to you yet, so this is everyone's list; match your identity with `catalyst identity linear set` and it becomes yours".
|
|
23
23
|
|
|
24
24
|
## Presenting the queue
|
|
25
25
|
|
|
@@ -14,12 +14,16 @@ const SPEC = {
|
|
|
14
14
|
blocks: { value: true, repeat: true, help: "a ticket this decision holds (repeat per ticket)" },
|
|
15
15
|
"nothing-to-block": { value: false, help: "declare that no ticket is held (the ask then never shows in Waiting on me)" },
|
|
16
16
|
"ask-key": { value: true, help: "idempotency key so a re-run does not file a second ask" },
|
|
17
|
+
"gates-pr": { value: true, repeat: true, help: "a PR whose hold label the answer removes (repeat per PR; needs --released-by)" },
|
|
18
|
+
"gates-label": { value: true, repeat: true, help: "the hold the answer removes: hold or hold:preview (repeatable; default hold)" },
|
|
19
|
+
"released-by": { value: true, repeat: true, help: "an option letter whose answer releases the hold (repeat per letter)" },
|
|
20
|
+
"gates-repo": { value: true, help: "the --gates-pr repository as owner/name (default: the account's only repository)" },
|
|
17
21
|
json: { value: false, help: "print the cloud's response as JSON" },
|
|
18
22
|
};
|
|
19
23
|
|
|
20
24
|
const { help, flags } = parseFlags(process.argv.slice(2), SPEC);
|
|
21
25
|
if (help) {
|
|
22
|
-
printHelp("node scripts/raise.mjs --team <key> --title <question> [--context <text>] [--option <text>]... [--default <text>] --blocks <ticket>... | --nothing-to-block [--ask-key <key>] [--json] [--help]", SPEC, [
|
|
26
|
+
printHelp("node scripts/raise.mjs --team <key> --title <question> [--context <text>] [--option <text>]... [--default <text>] --blocks <ticket>... | --nothing-to-block [--ask-key <key>] [--gates-pr <n>... --released-by <letter>... [--gates-label hold|hold:preview]... [--gates-repo <owner/name>]] [--json] [--help]", SPEC, [
|
|
23
27
|
"Search for an existing ask first (node scripts/inbox.mjs); one decision, one ask.",
|
|
24
28
|
"File BEFORE proceeding on the default. Cite the identifier only from this script's output.",
|
|
25
29
|
]);
|
|
@@ -41,6 +45,10 @@ if (flags.default) args.push("--default", flags.default);
|
|
|
41
45
|
for (const b of flags.blocks ?? []) args.push("--blocks", b);
|
|
42
46
|
if (flags["nothing-to-block"]) args.push("--nothing-to-block");
|
|
43
47
|
if (flags["ask-key"]) args.push("--ask-key", flags["ask-key"]);
|
|
48
|
+
for (const n of flags["gates-pr"] ?? []) args.push("--gates-pr", n);
|
|
49
|
+
for (const l of flags["gates-label"] ?? []) args.push("--gates-label", l);
|
|
50
|
+
for (const l of flags["released-by"] ?? []) args.push("--released-by", l);
|
|
51
|
+
if (flags["gates-repo"]) args.push("--gates-repo", flags["gates-repo"]);
|
|
44
52
|
args.push("--json");
|
|
45
53
|
|
|
46
54
|
const result = parseJson(mustRun(args, { quiet: true }).stdout, "ask raise");
|
|
@@ -49,5 +57,6 @@ if (flags.json) process.stdout.write(JSON.stringify(result) + "\n");
|
|
|
49
57
|
else {
|
|
50
58
|
process.stdout.write(`ask raised: ${id ?? "(no identifier returned)"}${flags.blocks ? ` — holds ${flags.blocks.join(", ")}` : " — holds nothing"}\n`);
|
|
51
59
|
if (flags.default) process.stdout.write(`default if silent: ${flags.default}\n`);
|
|
60
|
+
if (flags["gates-pr"]) process.stdout.write(`answer ${flags["released-by"].join(" or ")} releases the hold on PR ${flags["gates-pr"].map((n) => `#${n}`).join(", ")}\n`);
|
|
52
61
|
}
|
|
53
62
|
process.exit(0);
|
|
@@ -4,7 +4,7 @@ description: >-
|
|
|
4
4
|
What environment variable names does this repository need, and where does each one come from? Scans the repository offline (no login, no network) and lists the names in three groups (build/test, deploy-only, bindings), each with where it was found, what uses it, and where a local value would come from. Never reads a value or prints one. Also checks the environment variable table in `.catalyst/catalyst.toml` offline. Use when someone asks "what does catalyst.env.json mean", "what env vars does this repo need", "why does the container need this", or before reviewing or writing the declaration.
|
|
5
5
|
allowed-tools: Bash(catalyst:*) Bash(npx -p @catalyst-cloud/cli catalyst:*)
|
|
6
6
|
---
|
|
7
|
-
<!-- vendored-from: @catalyst-cloud/catalyst-skills@0.
|
|
7
|
+
<!-- vendored-from: @catalyst-cloud/catalyst-skills@0.16.1 — written in this repository for customer accounts -->
|
|
8
8
|
|
|
9
9
|
# What this repository needs
|
|
10
10
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: whats-happening
|
|
3
3
|
description: >-
|
|
4
|
-
Use for "what's happening?", "where are we?", "why is that stuck?", "what closed?", "what's next?", "how does this work?", "why did it do that?", "how does it prioritise?" and "what does this setting do, where is it set?" in Catalyst Cloud, or asks for something to be done rather than known. Reads the contract via catalyst CLI. Read-only: route work/decisions, never answer as the human.
|
|
4
|
+
Use for "what's happening?", "what machines do we have?", "how much capacity do we have?", "where are we?", "why is that stuck?", "what closed?", "what's next?", "how does this work?", "why did it do that?", "how does it prioritise?" and "what does this setting do, where is it set?" in Catalyst Cloud, or asks for something to be done rather than known. Reads the contract via catalyst CLI. Read-only: route work/decisions, never answer as the human.
|
|
5
5
|
allowed-tools: Bash(catalyst:*) Bash(npx -p @catalyst-cloud/cli catalyst:*)
|
|
6
6
|
---
|
|
7
|
-
<!-- vendored-from: @catalyst-cloud/catalyst-skills@0.
|
|
7
|
+
<!-- vendored-from: @catalyst-cloud/catalyst-skills@0.16.1 — written in this repository for customer accounts -->
|
|
8
8
|
|
|
9
9
|
# What's happening
|
|
10
10
|
|
|
@@ -20,6 +20,7 @@ Comments/relations: catalyst-linear. PRs: catalyst-github. Readiness: catalyst-o
|
|
|
20
20
|
|
|
21
21
|
| question | reference |
|
|
22
22
|
| -- | -- |
|
|
23
|
+
| machines or machine capacity? | references/machines.md |
|
|
23
24
|
| status or stuck? | references/status-reply.md; schema assets/status-reply.json |
|
|
24
25
|
| eligibility reason? | references/why-is-it-stuck.md |
|
|
25
26
|
| order, capacity, WIP or routing? | references/what-runs-next.md |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Coding accounts
|
|
2
2
|
|
|
3
|
-
snapshot.mjs --accounts omits credentials/emails. An owner/admin enrols, pauses, removes or replaces credentials at `<their cloud>/settings/coding-accounts
|
|
3
|
+
snapshot.mjs --accounts omits credentials/emails. An owner/admin enrols, pauses, removes or replaces credentials at `<their cloud>/settings/coding-accounts`; no command does these yet. `catalyst accounts` reads them.
|
|
4
4
|
|
|
5
5
|
Slots identify credentials, not emails. Claude/GLM/Qwen use Claude CLI, Codex uses Codex; GLM/Qwen also use OpenCode. Routing names the model.
|
|
6
6
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Machines and capacity
|
|
2
|
+
|
|
3
|
+
Run `catalyst hosts --json` when someone asks what machines their account has or how much capacity is available. Name `catalyst hosts` as the command behind the answer. The same read is available through the SDK's `client.hosts.list()`.
|
|
4
|
+
|
|
5
|
+
List each machine's name, whether it is self-hosted or Catalyst's, its teams, slots in use and free, last check-in, and live or stale status. A self-hosted machine uses the name its customer chose. Catalyst's machines say Cloud followed by the server or service name.
|
|
6
|
+
|
|
7
|
+
Use the response's capacity total. It already counts a cloud machine shared across teams once and excludes stale machines. A machine is stale when its runtime proof has expired or it has not checked in for 15 minutes. A stale machine stays in the list, with its last check-in, but contributes no live capacity. A missing check-in is unknown, not proof that a machine is live. A failed read is inconclusive; never report zero machines or zero capacity from a failure.
|
|
8
|
+
|
|
9
|
+
For a requested change, an admin can run `catalyst hosts rename <name-or-id> <new-name>` or `catalyst hosts remove <name-or-id>`. Removal asks for confirmation; `--yes` records explicit consent for an unattended invocation. A member can read but cannot change machines. When a name matches more than one machine, use its ID. An admin choosing to run work on a new machine can name it during `catalyst setup`, or pass `--machine-name <name>`.
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# Settings
|
|
2
2
|
|
|
3
|
-
Use live values and the person's cloud prefix. Owner/admin acts unless stated. Name screen, route, rule.
|
|
3
|
+
Use live values and the person's cloud prefix. Owner/admin acts unless stated. Name screen, route, rule. Where a command does the change, offer to run it before naming the screen.
|
|
4
4
|
|
|
5
5
|
| screen and route | rule |
|
|
6
6
|
| -- | -- |
|
|
7
|
-
| Integrations, /settings/connections | Connecting Linear needs admin browser
|
|
8
|
-
| Profile, /settings/profile, then Connections | The personal GitHub grant comes first; missing identity or another person's installation refusal means grant personal GitHub first. |
|
|
7
|
+
| Integrations, /settings/connections | Connecting Linear needs an admin's consent in their browser, which chooses the account; `catalyst onboard` starts it and prints the consent link. A workspace binds to exactly one account and vice versa; a conflict needs a decision, not retry. |
|
|
8
|
+
| Profile, /settings/profile, then Connections | The personal GitHub grant comes first; missing identity or another person's installation refusal means grant personal GitHub first. Offer `catalyst connections personal github start` and hand over the link it prints. |
|
|
9
9
|
| Connections | Removing the App on GitHub self-heals the registry; Catalyst unlink uninstalls upstream; neither needs support. |
|
|
10
|
-
| Your projects, /settings/projects | Each Catalyst project pairs one Linear team with its registered GitHub repositories.
|
|
11
|
-
| Merging, /settings/projects/$projectId/repositories/$repoId/merging | Merge policy is
|
|
12
|
-
| Code reviews, /settings/projects/$projectId/repositories/$repoId/code-reviews | Post review requests as selects a connected member. Strict policy without reviewer never earns ready label; configure reviewer or change policy. |
|
|
10
|
+
| Your projects, /settings/projects | Each Catalyst project pairs one Linear team with its registered GitHub repositories. Attach a repository with `catalyst onboard --team <KEY> --repo <owner/name>`; choose the team's default repository here, with no command for that yet. |
|
|
11
|
+
| Merging, /settings/projects/$projectId/repositories/$repoId/merging | Merge policy is the variable `CATALYST_MERGE_EVIDENCE_POLICY`: offer `catalyst var set CATALYST_MERGE_EVIDENCE_POLICY --repo <owner/name>`, or change it here. A policy declared in `.catalyst/catalyst.toml` wins over the variable: change it there in a pull request; contract merge gives value/source; catalyst-github only reads. |
|
|
12
|
+
| Code reviews, /settings/projects/$projectId/repositories/$repoId/code-reviews | Post review requests as selects a connected member. Strict policy without reviewer never earns ready label; configure reviewer here (no command yet) or change policy. |
|
|
13
13
|
| Merge queue, no Catalyst page | After ready label, the merge itself is whatever the repository's own setup does with it; the repo admin owns this. This bundle cannot identify its queue vendor; never guess. |
|
|
14
14
|
| Repositories | Shows operator-set runner cap, default 20, paused effective zero; see what-runs-next.md. |
|
|
15
|
-
| Secrets /settings/secrets and Environment /settings/environment, plus repository sections | Secrets write-only, variables readable; names are never both. Repository values override account values. Variables may reference vault secrets, expanded only in container. |
|
|
16
|
-
| Repositories | Without a registered team nothing reaches a runner, and the failure is silent;
|
|
15
|
+
| Secrets /settings/secrets and Environment /settings/environment, plus repository sections | Secrets write-only, variables readable; names are never both. Repository values override account values. Variables may reference vault secrets, expanded only in container. Offer `catalyst var set NAME [--repo <owner/name>]` or `catalyst secret set NAME --repo <owner/name>`; a workspace-wide secret has no command yet. |
|
|
16
|
+
| Repositories | Without a registered team nothing reaches a runner, and the failure is silent; an owner or admin can register it with `catalyst onboard --team <KEY> --repo <owner/name>`, so offer that, otherwise raise the fix as an ask. |
|
|
17
17
|
| Routing, no settings page for this | Global stage defaults and empty per-account table select default provider; never promise Codex-first. |
|
|
@@ -14,6 +14,6 @@ Order: dispatch, intake, research, plan, implement, remediate, verify, review, p
|
|
|
14
14
|
|
|
15
15
|
Missing/wrong required mappings stop work; others warn. Dispatch/pr/done/canceled must be live. `teams[].gitAutomation` stores consent; nothing reads it.
|
|
16
16
|
|
|
17
|
-
workflowMode: adopted means Catalyst-created, mapped means human-chosen, mixed means both. Configure
|
|
17
|
+
workflowMode: adopted means Catalyst-created, mapped means human-chosen, mixed means both. Configure with `catalyst team map <KEY>` or `catalyst team adopt <KEY>` (offer to run it for an owner or admin), never catalyst.toml.
|
|
18
18
|
|
|
19
19
|
stateId is authoritative; imports can replace ids but keep names. catalyst-linear resolves slots to ids. stateStillExists: false refuses the move; remap with `catalyst team map <KEY>`. Backlog is not a slot: parking resolves a live backlog-type state. catalyst-onboard explains readiness and who fixes it.
|