@catalyst-cloud/cli 0.13.0 → 0.14.0
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 +10 -0
- package/README.md +27 -30
- package/dist/args.js +299 -61
- package/dist/ask.js +30 -18
- package/dist/capabilities.js +7 -0
- package/dist/cli.js +125 -20
- package/dist/config.js +3 -1
- package/dist/env/draft.js +134 -0
- package/dist/env/legacy.js +54 -0
- package/dist/env/parse-env.js +50 -0
- package/dist/env/settings-toml.js +66 -0
- package/dist/env.js +126 -26
- package/dist/environment.js +1 -1
- package/dist/legacy.js +224 -0
- package/dist/onboard-consent.js +65 -0
- package/dist/onboard.js +836 -0
- package/dist/project.js +191 -0
- package/dist/ready.js +11 -1
- package/dist/release.js +1 -1
- package/dist/repo.js +297 -0
- package/dist/runtime-verb.js +1 -1
- package/dist/secret.js +25 -4
- package/dist/skill-shape.js +21 -13
- package/dist/skills.js +44 -4
- package/dist/transport.js +26 -1
- package/dist/var.js +118 -0
- package/package.json +6 -4
- package/skills/catalyst-github/SKILL.md +7 -7
- package/skills/catalyst-github/references/is-it-mergeable.md +8 -2
- package/skills/catalyst-github/references/what-a-pr-accumulates.md +3 -3
- package/skills/catalyst-github/scripts/is-it-mergeable.mjs +3 -3
- package/skills/catalyst-github/scripts/lib/cli.mjs +9 -7
- package/skills/catalyst-github/scripts/lib/credential.mjs +2 -2
- package/skills/catalyst-github/scripts/read-pr.mjs +2 -2
- package/skills/catalyst-linear/SKILL.md +17 -19
- package/skills/catalyst-linear/agents/openai.yaml +1 -1
- package/skills/catalyst-linear/agents/portability.yaml +1 -1
- package/skills/catalyst-linear/references/reading-a-ticket.md +9 -26
- package/skills/catalyst-linear/references/what-a-ticket-accumulates.md +2 -2
- package/skills/catalyst-linear/references/writing-to-linear.md +7 -9
- package/skills/catalyst-linear/scripts/comment.mjs +1 -1
- package/skills/catalyst-linear/scripts/create-ticket.mjs +1 -1
- package/skills/catalyst-linear/scripts/label.mjs +1 -1
- package/skills/catalyst-linear/scripts/lib/cli.mjs +9 -7
- package/skills/catalyst-linear/scripts/lib/credential.mjs +2 -2
- package/skills/catalyst-linear/scripts/move.mjs +1 -1
- package/skills/catalyst-linear/scripts/read-ticket.mjs +1 -1
- package/skills/catalyst-linear/scripts/search.mjs +1 -1
- package/skills/catalyst-onboard/SKILL.md +37 -57
- package/skills/catalyst-onboard/agents/openai.yaml +2 -2
- package/skills/catalyst-onboard/agents/portability.yaml +1 -1
- package/skills/catalyst-onboard/references/connecting-this-machine.md +35 -0
- package/skills/catalyst-onboard/references/declaring-a-repository.md +18 -21
- package/skills/catalyst-onboard/references/local-sync.md +19 -7
- package/skills/catalyst-onboard/references/reading-ready.md +79 -0
- package/skills/catalyst-onboard/references/replacing-a-credential.md +8 -33
- package/skills/catalyst-onboard/references/repository-agent-setup.md +23 -0
- package/skills/catalyst-onboard/references/skill-sources.md +13 -19
- package/skills/catalyst-onboard/references/the-one-path.md +18 -74
- package/skills/catalyst-onboard/references/what-a-phase-needs.md +21 -28
- package/skills/catalyst-onboard/references/what-the-browser-owns.md +20 -37
- package/skills/{catalyst-setup → catalyst-onboard}/scripts/check.mjs +10 -9
- package/skills/catalyst-onboard/scripts/lib/cli.mjs +6 -4
- package/skills/catalyst-onboard/scripts/lib/credential.mjs +2 -2
- package/skills/catalyst-onboard/scripts/lib/project-coverage.mjs +53 -0
- package/skills/catalyst-onboard/scripts/where-am-i.mjs +929 -184
- package/skills/run-this-project/SKILL.md +23 -25
- package/skills/run-this-project/agents/openai.yaml +1 -1
- package/skills/run-this-project/agents/portability.yaml +1 -1
- package/skills/run-this-project/references/making-work-ready.md +20 -37
- package/skills/run-this-project/references/reacting-to-events.md +25 -48
- package/skills/run-this-project/references/stalls-and-escalation.md +20 -42
- package/skills/run-this-project/scripts/lib/cli.mjs +7 -5
- package/skills/run-this-project/scripts/lib/credential.mjs +2 -2
- package/skills/run-this-project/scripts/scope-status.mjs +0 -0
- package/skills/run-this-project/scripts/watch-scope.mjs +1 -1
- package/skills/unstick/SKILL.md +12 -12
- package/skills/unstick/agents/openai.yaml +1 -1
- package/skills/unstick/agents/portability.yaml +1 -1
- package/skills/unstick/references/playbook.md +13 -13
- package/skills/unstick/scripts/lib/cli.mjs +6 -4
- package/skills/unstick/scripts/lib/credential.mjs +2 -2
- package/skills/unstick/scripts/unstick.mjs +1 -1
- package/skills/what-needs-me/SKILL.md +12 -14
- package/skills/what-needs-me/agents/openai.yaml +2 -2
- package/skills/what-needs-me/agents/portability.yaml +1 -1
- package/skills/what-needs-me/references/raising-a-decision.md +8 -16
- package/skills/what-needs-me/references/reading-the-inbox.md +6 -13
- package/skills/what-needs-me/references/settling-an-answer.md +6 -12
- package/skills/what-needs-me/scripts/inbox.mjs +14 -13
- package/skills/what-needs-me/scripts/lib/cli.mjs +6 -4
- package/skills/what-needs-me/scripts/lib/credential.mjs +2 -2
- package/skills/what-needs-me/scripts/raise.mjs +1 -1
- package/skills/what-needs-me/scripts/settle.mjs +1 -1
- package/skills/what-this-repo-needs/SKILL.md +10 -19
- package/skills/what-this-repo-needs/references/what-each-group-means.md +14 -44
- package/skills/what-this-repo-needs/scripts/check.mjs +13 -14
- package/skills/what-this-repo-needs/scripts/inventory.mjs +2 -2
- package/skills/what-this-repo-needs/scripts/lib/cli.mjs +11 -9
- package/skills/what-this-repo-needs/scripts/lib/credential.mjs +2 -2
- package/skills/whats-happening/SKILL.md +20 -30
- package/skills/whats-happening/agents/openai.yaml +1 -1
- package/skills/whats-happening/references/coding-accounts.md +11 -0
- package/skills/whats-happening/references/routing-work.md +4 -33
- package/skills/whats-happening/references/settings-and-where-they-live.md +17 -0
- package/skills/whats-happening/references/stages-and-mapping.md +19 -0
- package/skills/whats-happening/references/status-reply.md +11 -31
- package/skills/whats-happening/references/the-ladder.md +20 -0
- package/skills/whats-happening/references/what-runs-next.md +13 -0
- package/skills/whats-happening/references/when-a-phase-fails.md +21 -0
- package/skills/whats-happening/references/why-is-it-stuck.md +38 -62
- package/skills/whats-happening/scripts/explain.mjs +1 -1
- package/skills/whats-happening/scripts/lib/cli.mjs +7 -5
- package/skills/whats-happening/scripts/lib/credential.mjs +2 -2
- package/skills/{how-catalyst-works → whats-happening}/scripts/show-my-map.mjs +18 -32
- package/skills/whats-happening/scripts/snapshot.mjs +10 -6
- package/dist/env/declaration-rules.js +0 -163
- package/skills/catalyst-onboard/references/choosing-a-coding-account.md +0 -52
- package/skills/catalyst-onboard/references/who-fixes-what.md +0 -64
- package/skills/catalyst-setup/SKILL.md +0 -36
- package/skills/catalyst-setup/agents/openai.yaml +0 -6
- package/skills/catalyst-setup/agents/portability.yaml +0 -4
- package/skills/catalyst-setup/references/what-each-check-means.md +0 -88
- package/skills/catalyst-setup/scripts/lib/cli.mjs +0 -103
- package/skills/catalyst-setup/scripts/lib/credential.mjs +0 -29
- package/skills/catalyst-setup/scripts/replica-status.mjs +0 -46
- package/skills/connect-me/SKILL.md +0 -63
- package/skills/connect-me/agents/openai.yaml +0 -6
- package/skills/connect-me/agents/portability.yaml +0 -5
- package/skills/connect-me/references/keeping-the-replica-running.md +0 -88
- package/skills/connect-me/scripts/lib/cli.mjs +0 -185
- package/skills/connect-me/scripts/lib/credential.mjs +0 -29
- package/skills/connect-me/scripts/verify-connection.mjs +0 -68
- package/skills/how-catalyst-works/SKILL.md +0 -45
- package/skills/how-catalyst-works/agents/openai.yaml +0 -6
- package/skills/how-catalyst-works/agents/portability.yaml +0 -4
- package/skills/how-catalyst-works/references/coding-accounts.md +0 -51
- package/skills/how-catalyst-works/references/settings-and-where-they-live.md +0 -20
- package/skills/how-catalyst-works/references/stages-and-mapping.md +0 -56
- package/skills/how-catalyst-works/references/the-ladder.md +0 -41
- package/skills/how-catalyst-works/references/what-catalyst-is.md +0 -30
- package/skills/how-catalyst-works/references/what-runs-next.md +0 -95
- package/skills/how-catalyst-works/references/when-a-phase-fails.md +0 -57
- package/skills/how-catalyst-works/scripts/explain-ticket.mjs +0 -41
- package/skills/how-catalyst-works/scripts/lib/cli.mjs +0 -164
- package/skills/how-catalyst-works/scripts/lib/credential.mjs +0 -29
- package/skills/how-catalyst-works/scripts/whats-running.mjs +0 -65
- package/skills/whats-happening/references/reading-the-board.md +0 -43
- package/skills/whats-happening/references/reprioritising.md +0 -37
|
@@ -1,68 +1,38 @@
|
|
|
1
1
|
# What each group means
|
|
2
2
|
|
|
3
|
-
`node scripts/inventory.mjs` sorts every environment variable name it finds into exactly one of
|
|
4
|
-
three groups. This page explains what each one means and why a name lands where it does — it never
|
|
5
|
-
restates a value, because the scan itself never reads one.
|
|
3
|
+
`node scripts/inventory.mjs` sorts every environment variable name it finds into exactly one of three groups. This page explains why a name lands where it does; the scan never reads a value.
|
|
6
4
|
|
|
7
5
|
## build/test
|
|
8
6
|
|
|
9
|
-
Needed to install, build and run the tests in a container. This is the default group: a name lands
|
|
10
|
-
here unless something specific pulls it into `deploy-only` or `bindings`. Examples: a name read by
|
|
11
|
-
the repository's own source (`process.env.X`), a name documented in a `.env.example`-shaped file, a
|
|
12
|
-
name a non-deploy workflow job uses.
|
|
7
|
+
Needed to install, build and run the tests in a container. This is the default group: a name lands here unless something specific pulls it into `deploy-only` or `bindings`. Examples: a name the source reads (`process.env.X`), a name in a `.env.example`-shaped file, a name a non-deploy workflow job uses.
|
|
13
8
|
|
|
14
|
-
The scan does not read `package.json` scripts. A name
|
|
15
|
-
and nothing else refers to is therefore not listed — add it by hand if the container needs it.
|
|
9
|
+
The scan does not read `package.json` scripts. A name only a script's shell line mentions is therefore not listed; add it by hand if the container needs it.
|
|
16
10
|
|
|
17
|
-
A name referenced from **both** a deploy job and a non-deploy job (or build step)
|
|
18
|
-
not in `deploy-only` — a container that builds and tests the repository needs it too, so the
|
|
19
|
-
stricter requirement wins.
|
|
11
|
+
A name referenced from **both** a deploy job and a non-deploy job (or build step) lands here, because a container that builds and tests the repository needs it too.
|
|
20
12
|
|
|
21
13
|
## deploy-only
|
|
22
14
|
|
|
23
|
-
A CI secret used **only** by a job the scan classifies as deploying
|
|
24
|
-
sets `environment:`, whose id looks like `deploy`, `publish`, `release` or `cd`, or that runs a
|
|
25
|
-
recognised deploy command (`wrangler deploy`, `npm publish`, `gh release create`, and similar). If
|
|
26
|
-
the same name is referenced anywhere outside a deploy job, it moves to `build/test` instead.
|
|
27
|
-
|
|
28
|
-
Its local value comes from a CI secret — something a repository or organisation admin sets in the
|
|
29
|
-
CI provider, not something a person types into a local `.env` file.
|
|
15
|
+
A CI secret used **only** by a job the scan classifies as deploying: a workflow job that sets `environment:`, whose id looks like `deploy`, `publish`, `release` or `cd`, or that runs a recognised deploy command (`wrangler deploy`, `npm publish`, `gh release create`, and similar). A reference anywhere outside a deploy job moves the name to `build/test`. Its local value is a CI secret a repository or organisation admin sets in the CI provider.
|
|
30
16
|
|
|
31
17
|
## bindings
|
|
32
18
|
|
|
33
|
-
A Cloudflare (or other platform) binding: a name bound to a resource
|
|
34
|
-
database, a Durable Object, an R2 bucket, a queue — declared in `wrangler.toml`. A binding is not an
|
|
35
|
-
environment value a process reads from `process.env`; it is wired up by the platform at deploy
|
|
36
|
-
time, which is why this scan keeps the two apart even though both are "names the container needs".
|
|
37
|
-
|
|
38
|
-
A `wrangler.toml` binding table names the binding through one attribute's value — `binding = "NAME"`
|
|
39
|
-
for most tables, `name = "NAME"` for `durable_objects.bindings` — never through the table's own key.
|
|
19
|
+
A Cloudflare (or other platform) binding: a name bound to a resource (a KV namespace, a D1 database, a Durable Object, an R2 bucket, a queue) declared in `wrangler.toml`. The platform wires it up at deploy time, so it is not a `process.env` value, and the scan keeps the two apart. A binding table names the binding through one attribute's value (`binding = "NAME"` for most tables, `name = "NAME"` for `durable_objects.bindings`), never through the table's own key.
|
|
40
20
|
|
|
41
21
|
## wrangler.toml `[vars]`: build/test, not a binding, and nothing to declare
|
|
42
22
|
|
|
43
|
-
A `[vars]` (or `[env.<name>.vars]`) table
|
|
44
|
-
the names, and their values are committed in `wrangler.toml` itself — checked into the repository,
|
|
45
|
-
not a secret and not something a person supplies locally. So a `[vars]` name lands in `build/test`
|
|
46
|
-
(it is a plain value a build or test step could read, not a resource binding), and the scan marks it
|
|
47
|
-
`needsDeclaration: false`: there is nothing for a customer to declare, because the value is already
|
|
48
|
-
sitting in the file everyone can already read.
|
|
23
|
+
A `[vars]` (or `[env.<name>.vars]`) table's keys ARE the names, and their values are committed in `wrangler.toml` itself, readable by everyone. So a `[vars]` name lands in `build/test` as a plain value a step could read, marked `needsDeclaration: false`: there is nothing to declare.
|
|
49
24
|
|
|
50
25
|
## Where a local value comes from
|
|
51
26
|
|
|
52
|
-
For every name,
|
|
27
|
+
For every name, one of:
|
|
53
28
|
|
|
54
|
-
- **a `.env` file or your shell
|
|
55
|
-
- **a CI secret
|
|
56
|
-
|
|
57
|
-
-
|
|
58
|
-
it up.
|
|
59
|
-
- **value committed in wrangler.toml — nothing to declare** — for a `[vars]` entry.
|
|
29
|
+
- **a `.env` file or your shell:** the ordinary case for `build/test`.
|
|
30
|
+
- **a CI secret:** for `deploy-only`, and for a `build/test` name whose only non-committed source is a workflow's `secrets.X` reference.
|
|
31
|
+
- **a Cloudflare binding:** for `bindings`; the platform wires it, so there is no local value.
|
|
32
|
+
- `value committed in wrangler.toml — nothing to declare`: for a `[vars]` entry.
|
|
60
33
|
|
|
61
|
-
|
|
62
|
-
knows what to check without this tool ever showing them what is actually set.
|
|
34
|
+
Each says where a value would come from, never the value, so a reviewer knows what to check without seeing what is set.
|
|
63
35
|
|
|
64
36
|
## A `wrangler.jsonc` or `wrangler.json` file
|
|
65
37
|
|
|
66
|
-
|
|
67
|
-
only Cloudflare config format it understands — so a repository configured that way gets a note
|
|
68
|
-
saying so, rather than a silent, confidently wrong "no bindings found".
|
|
38
|
+
The scan reads only `wrangler.toml`, so a repository configured with JSONC gets a note saying so rather than a confident "no bindings found".
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// check.mjs —
|
|
3
|
-
//
|
|
4
|
-
// wraps `catalyst-skills env check`.
|
|
2
|
+
// check.mjs — checks the repository settings TOML offline. Never reads or prints a value. Offline:
|
|
3
|
+
// no login, no network — wraps `catalyst env check`.
|
|
5
4
|
import { runCliOffline } from "./lib/cli.mjs";
|
|
6
5
|
|
|
7
|
-
const HELP = `Usage: node scripts/check.mjs
|
|
6
|
+
const HELP = `Usage: node scripts/check.mjs [path] [--json]
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
"valid" or
|
|
8
|
+
Checks TOML syntax and the environment variable table in .catalyst/catalyst.toml (default), or at
|
|
9
|
+
the repo-relative path you name. Prints "valid" or refusal reasons — never a value. A legacy root
|
|
10
|
+
catalyst.env.json is not read by the cloud. Exit 0 valid or absent, 1 invalid or unreadable.
|
|
11
11
|
|
|
12
12
|
--json prints {state, errors}. This is a local, offline check: no login, no network required.`;
|
|
13
13
|
|
|
@@ -18,19 +18,18 @@ if (args.includes("--help") || args.includes("-h")) {
|
|
|
18
18
|
}
|
|
19
19
|
const json = args.includes("--json");
|
|
20
20
|
const file = args.find((a) => a !== "--json");
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const res = runCliOffline(["env", "check", file, ...(json ? ["--json"] : [])]);
|
|
21
|
+
const res = runCliOffline([
|
|
22
|
+
"env",
|
|
23
|
+
"check",
|
|
24
|
+
...(file ? [file] : []),
|
|
25
|
+
...(json ? ["--json"] : []),
|
|
26
|
+
]);
|
|
28
27
|
if (res.stdout) process.stdout.write(res.stdout);
|
|
29
28
|
if (res.stderr) process.stderr.write(res.stderr);
|
|
30
29
|
await finish(res.code);
|
|
31
30
|
|
|
32
31
|
/**
|
|
33
|
-
* ⛔ NEVER `process.exit(code)` STRAIGHT AFTER A WRITE — the same rule `bin/
|
|
32
|
+
* ⛔ NEVER `process.exit(code)` STRAIGHT AFTER A WRITE — the same rule `bin/launch.js`
|
|
34
33
|
* states in full, reintroduced here at validate attempt 29 (M-3). When this script's own stdout is a
|
|
35
34
|
* PIPE — which is how an agent harness runs it — writes are asynchronous, so `process.exit` severs
|
|
36
35
|
* whatever is still in flight AND STILL REPORTS THE ORIGINAL EXIT CODE. Measured: a `--json` body of
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// inventory.mjs — lists the environment variable NAMES this repository needs, grouped build/test,
|
|
3
3
|
// deploy-only and bindings, each with where it was found, what uses it, and where a local value
|
|
4
4
|
// would come from. Never reads or prints a value. Offline: no login, no network — wraps
|
|
5
|
-
// `catalyst
|
|
5
|
+
// `catalyst env inventory`.
|
|
6
6
|
import { runCliOffline } from "./lib/cli.mjs";
|
|
7
7
|
|
|
8
8
|
const HELP = `Usage: node scripts/inventory.mjs [path] [--json]
|
|
@@ -27,7 +27,7 @@ if (res.stderr) process.stderr.write(res.stderr);
|
|
|
27
27
|
await finish(res.code);
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
* ⛔ NEVER `process.exit(code)` STRAIGHT AFTER A WRITE — the same rule `bin/
|
|
30
|
+
* ⛔ NEVER `process.exit(code)` STRAIGHT AFTER A WRITE — the same rule `bin/launch.js`
|
|
31
31
|
* states in full, reintroduced here at validate attempt 29 (M-3). When this script's own stdout is a
|
|
32
32
|
* PIPE — which is how an agent harness runs it — writes are asynchronous, so `process.exit` severs
|
|
33
33
|
* whatever is still in flight AND STILL REPORTS THE ORIGINAL EXIT CODE. Measured: a `--json` body of
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// lib/cli.mjs — the one way a skill script reaches the Catalyst Cloud SDK and API: by spawning the
|
|
3
|
-
// catalyst
|
|
3
|
+
// catalyst CLI this bundle installed. It reads customer.json to find that CLI and nothing
|
|
4
4
|
// else; it never holds the key itself. This file is a library — run a sibling script with
|
|
5
5
|
// --help for usage. Per-skill (skills install one directory at a time, so nothing shared outside the
|
|
6
6
|
// skill would ever be installed) — see runCliOffline below for the one way this skill's copy differs.
|
|
@@ -10,7 +10,9 @@ import { join } from "node:path";
|
|
|
10
10
|
import { fileURLToPath } from "node:url";
|
|
11
11
|
import { CONNECT_COMMAND, hasCredential } from "./credential.mjs";
|
|
12
12
|
|
|
13
|
-
export const PACKAGE = "@catalyst-cloud/
|
|
13
|
+
export const PACKAGE = "@catalyst-cloud/cli";
|
|
14
|
+
/** The package ships two commands, so npx needs the one to run named: `npx -p <package> catalyst`. */
|
|
15
|
+
export const NPX_ARGS = ["-p", PACKAGE, "catalyst"];
|
|
14
16
|
export const CONNECT_HINT = `this machine is not connected to a tenant yet — run: ${CONNECT_COMMAND}`;
|
|
15
17
|
|
|
16
18
|
/** ~/.config/catalyst-cloud/customer.json, honouring CATALYST_SKILLS_HOME before HOME. */
|
|
@@ -41,8 +43,8 @@ export function requireCustomerConfig() {
|
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
/**
|
|
44
|
-
* Run one catalyst
|
|
45
|
-
* connect step recorded in customer.json; falls back to `npx @catalyst-cloud/catalyst
|
|
46
|
+
* Run one catalyst verb and return {code, stdout, stderr}. Spawns the CLI whose path the
|
|
47
|
+
* connect step recorded in customer.json; falls back to `npx -p @catalyst-cloud/cli catalyst` when
|
|
46
48
|
* no path is recorded or it no longer exists. Exits 2 when the machine is not connected.
|
|
47
49
|
*/
|
|
48
50
|
export function runCli(args, opts = {}) {
|
|
@@ -51,12 +53,12 @@ export function runCli(args, opts = {}) {
|
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
/**
|
|
54
|
-
* Run `catalyst
|
|
56
|
+
* Run `catalyst env inventory` / `env check` without requiring a credential at all. Unlike
|
|
55
57
|
* every other verb this launcher can reach, `env inventory` and `env check` are LOCAL and OFFLINE —
|
|
56
58
|
* they never call the cloud — so gating them on `requireCustomerConfig` would break the feature they
|
|
57
59
|
* exist to provide. Still resolves the recorded `cliPath` when a customer.json happens to exist (so
|
|
58
60
|
* an already-connected machine reuses the same installed CLI), and still falls back to
|
|
59
|
-
* `npx @catalyst-cloud/catalyst
|
|
61
|
+
* `npx -p @catalyst-cloud/cli catalyst` otherwise.
|
|
60
62
|
*/
|
|
61
63
|
export function runCliOffline(args, opts = {}) {
|
|
62
64
|
let cfg = null;
|
|
@@ -72,7 +74,7 @@ export function runCliOffline(args, opts = {}) {
|
|
|
72
74
|
function spawnCli(cfg, args, opts) {
|
|
73
75
|
const recorded = Boolean(cfg) && typeof cfg.cliPath === "string" && existsSync(cfg.cliPath);
|
|
74
76
|
const command = recorded ? process.execPath : process.platform === "win32" ? "npx.cmd" : "npx";
|
|
75
|
-
const argv = recorded ? [cfg.cliPath, ...args] : [
|
|
77
|
+
const argv = recorded ? [cfg.cliPath, ...args] : [...NPX_ARGS, ...args];
|
|
76
78
|
const res = spawnSync(command, argv, {
|
|
77
79
|
encoding: "utf8",
|
|
78
80
|
input: opts.stdin,
|
|
@@ -81,7 +83,7 @@ function spawnCli(cfg, args, opts) {
|
|
|
81
83
|
shell: !recorded && process.platform === "win32",
|
|
82
84
|
});
|
|
83
85
|
if (res.error) {
|
|
84
|
-
console.error(`could not run ${recorded ? cfg.cliPath : `npx ${PACKAGE}`}: ${res.error.message}`);
|
|
86
|
+
console.error(`could not run ${recorded ? cfg.cliPath : `npx -p ${PACKAGE} catalyst`}: ${res.error.message}`);
|
|
85
87
|
process.exit(2);
|
|
86
88
|
}
|
|
87
89
|
return { code: res.status ?? 1, stdout: res.stdout ?? "", stderr: res.stderr ?? "" };
|
|
@@ -95,7 +97,7 @@ function spawnCli(cfg, args, opts) {
|
|
|
95
97
|
export function runCliOrExit(args, opts = {}) {
|
|
96
98
|
const res = runCli(args, opts);
|
|
97
99
|
if (res.code === 0) return res;
|
|
98
|
-
const why = res.stderr.trim() || res.stdout.trim() || `catalyst
|
|
100
|
+
const why = res.stderr.trim() || res.stdout.trim() || `catalyst ${args.join(" ")} exited ${res.code}`;
|
|
99
101
|
console.error(why);
|
|
100
102
|
process.exit(res.code === 2 ? 2 : 1);
|
|
101
103
|
}
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
//
|
|
7
7
|
// customer.json carries exactly one credential: a personal key (`key`), or the keyless login's
|
|
8
8
|
// session (`auth`, the recommended rail). A script never reads either for its value: it spawns the
|
|
9
|
-
// catalyst
|
|
9
|
+
// catalyst CLI, which authenticates with whichever is present and refreshes a login's token
|
|
10
10
|
// itself. A new credential kind lands here, once.
|
|
11
11
|
|
|
12
12
|
/** The command that connects this machine, as every not-connected line names it. */
|
|
13
13
|
export const CONNECT_COMMAND =
|
|
14
|
-
"npx @catalyst-cloud/catalyst
|
|
14
|
+
"npx -p @catalyst-cloud/cli catalyst login (or, with a personal key: CATALYST_CLOUD_TOKEN=<your personal key> npx -p @catalyst-cloud/cli catalyst login)";
|
|
15
15
|
|
|
16
16
|
/** True when `cfg` (parsed customer.json) holds a usable credential of either kind. Never throws. */
|
|
17
17
|
export function hasCredential(cfg) {
|
|
@@ -1,43 +1,33 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: whats-happening
|
|
3
3
|
description: >-
|
|
4
|
-
|
|
5
|
-
allowed-tools: Bash(catalyst
|
|
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.
|
|
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.14.0 — written in this repository for customer accounts -->
|
|
8
8
|
|
|
9
9
|
# What's happening
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Use one snapshot and the person's login. Run scripts, never read them. --help explains usage; exit 2 needs onboard, exit 1 means failure.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
- `node scripts/snapshot.mjs` prints contract, running work, queue, ranked asks, replica verdict. --board adds stages, --accounts coding accounts, --team K narrows.
|
|
14
|
+
- `node scripts/explain.mjs <ticket>` explains eligibility; --history adds attempts, rounds, holds and releases.
|
|
15
|
+
- `node scripts/show-my-map.mjs [--team K]` prints stages, labels, ladder and thresholds.
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- `node scripts/snapshot.mjs --help` — one JSON document: the trimmed contract (teams, stage names by slot, thresholds, ladder), what is running, the queue, the open asks ranked by what they hold, and the replica verdict. Add `--board` for open tickets grouped by stage in the contract's slot order, `--team K` to narrow.
|
|
18
|
-
- `node scripts/explain.mjs --help` — why nothing is offered for one ticket, in one paragraph.
|
|
19
|
-
|
|
20
|
-
For a single ticket's comments, relations and linked PRs use the `catalyst-linear` skill (`catalyst-skills query issue <id>`); for a pull request's checks and threads, `catalyst-github`.
|
|
17
|
+
Comments/relations: catalyst-linear. PRs: catalyst-github. Readiness: catalyst-onboard. Use current account facts/URLs, never memory. Unknown means inconclusive. PR labels/reactions are unmirrored; print their URL. Accounts/history are readable.
|
|
21
18
|
|
|
22
19
|
## Load on demand
|
|
23
20
|
|
|
24
|
-
|
|
|
21
|
+
| question | reference |
|
|
25
22
|
| -- | -- |
|
|
26
|
-
|
|
|
27
|
-
|
|
|
28
|
-
|
|
|
29
|
-
|
|
|
30
|
-
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
-
|
|
37
|
-
- **Tenant facts come from the contract, live.** Stage names, label names, team keys, thresholds and the ladder are in the snapshot's `tenant` block; read them there each time and never restate them from memory.
|
|
38
|
-
- **One reply, ticket ids on every line, source named.** The reply opens with when the snapshot was taken and whether the replica or the API answered. A stale replica is stated, never hidden.
|
|
39
|
-
- **Say what a key cannot see.** PR labels and reactions are not mirrored; the CLI prints the settings URL, and you repeat it instead of guessing. A park or hold is released from the person's own login once its cause is fixed: route that to the `unstick` skill (`catalyst-skills release`), never tell them it needs an operator. Coding-account status (`accounts`) and per-ticket execution history (`explain --history`) are readable — read them.
|
|
40
|
-
- **No polling.** One snapshot per question. Waiting on a change is the project owner's job (`run-this-project` subscribes to the tenant stream); the desk never loops a read.
|
|
41
|
-
- **You are not the owner.** You route work and make it visible; you do not dispatch, overrule a project owner, or run long work in this session.
|
|
42
|
-
- **Never answer as the human.** A decision is an ask through `what-needs-me`, filed before anyone proceeds on its default; the answer is recorded there as the app actor.
|
|
43
|
-
- **Cite an identifier only after a create call returned it.**
|
|
23
|
+
| status or stuck? | references/status-reply.md; schema assets/status-reply.json |
|
|
24
|
+
| eligibility reason? | references/why-is-it-stuck.md |
|
|
25
|
+
| order, capacity, WIP or routing? | references/what-runs-next.md |
|
|
26
|
+
| failure, park or hold? | references/when-a-phase-fails.md |
|
|
27
|
+
| request or decision? | references/routing-work.md |
|
|
28
|
+
| phases or Done? | references/the-ladder.md |
|
|
29
|
+
| columns or slots? | references/stages-and-mapping.md |
|
|
30
|
+
| accounts, windows, quarantine or provider? | references/coding-accounts.md |
|
|
31
|
+
| setting, screen, route or role? | references/settings-and-where-they-live.md |
|
|
32
|
+
|
|
33
|
+
Read-only: give ids, source, release and actor. Route releases to `unstick`, decisions to what-needs-me before defaults, ownership to run-this-project. Subscribe, never poll. Report each system cause once.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
interface:
|
|
2
2
|
display_name: "What's happening"
|
|
3
|
-
short_description: "Where your Catalyst work stands: in flight, blocked and on whom, closed,
|
|
3
|
+
short_description: "Where your Catalyst work stands and how Catalyst decides: in flight, blocked and on whom, closed, what runs next, and why"
|
|
4
4
|
default_prompt: "Use $whats-happening to tell me where my work stands and why anything is stuck."
|
|
5
5
|
policy:
|
|
6
6
|
allow_implicit_invocation: true
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Coding accounts
|
|
2
|
+
|
|
3
|
+
snapshot.mjs --accounts omits credentials/emails. An owner/admin enrols, pauses, removes or replaces credentials at `<their cloud>/settings/coding-accounts`.
|
|
4
|
+
|
|
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
|
+
|
|
7
|
+
Declared state is operator-set active/disabled. Observed health is healthy/degraded/unknown, polled every five minutes for active slots and daily for disabled ones. Credential conflicts/auth mismatches quarantine; Replace credential on the account's page clears it.
|
|
8
|
+
|
|
9
|
+
Subscriptions have 5-hour and 7-day windows. Walls kill sessions; phase burn must fit headroom. Claude slots allow concurrent phases up to a cap; Codex permits one because refresh tokens are single-use. Vendor status does not reveal account windows.
|
|
10
|
+
|
|
11
|
+
When idle, explain. routing_unavailable or no_eligible_account_slot points here. Read --accounts: empty means no enrolment; inspect walled, quarantined and reason. Silence proves nothing.
|
|
@@ -1,36 +1,7 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Route requests
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Classify first: question, work request, human decision, or both request/decision. Questions: status-reply.md. Decisions: what-needs-me before defaults.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Search projects with catalyst query projects and `catalyst query search <terms>`. Reuse fitting projects. Otherwise name outcome, one or two catalyst-linear tickets and owner; the person creates the project. Assign a person or run-this-project session, giving its start command. Report returned ids, owner and next event; never guess ids.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
1. **A question.** "Where is X? Why is Y stuck? What closed today?" Answer it in the one-reply shape (`references/status-reply.md`). No routing.
|
|
10
|
-
2. **A request for work.** "Get X done. Ship the Y change. Own this until it closes." Turn it into a project with an owner, in one pass, as below.
|
|
11
|
-
3. **A decision only they can make**, surfaced by you or by the cloud. That is never answered here; it goes to `what-needs-me`.
|
|
12
|
-
|
|
13
|
-
A request that contains a decision is both: route the work and raise the decision, and say in the reply that you did both.
|
|
14
|
-
|
|
15
|
-
## A request becomes a project with an owner, in one pass
|
|
16
|
-
|
|
17
|
-
You hold no authority over project owners. Your job is to make the work visible and hand it to a single-threaded owner, then get out of the way.
|
|
18
|
-
|
|
19
|
-
1. **Find the existing home first.** `catalyst-skills query projects` and `query search <terms>`. A request that fits an open project is a ticket in that project, not a new project. Duplicate projects split one goal's status across two places.
|
|
20
|
-
2. **Scaffold when there is no home.** State the outcome in one sentence, the first ticket or two, and who owns it. Tickets are created through the `catalyst-linear` skill (the app actor, the team key from the contract); a project itself is created by the person in Linear, so name what you want it called and ask them to create it if none fits.
|
|
21
|
-
3. **Name the owner.** The owner is a `run-this-project` session for that project, or a person. Say which, in the reply. Tell the person the one command that starts the owner session, and do not start long-running work inside this session: the desk answers questions; the owner reacts to events.
|
|
22
|
-
4. **Say what you did.** The reply ends with the identifiers created, the owner named, and the next thing the person will see.
|
|
23
|
-
|
|
24
|
-
Cite an identifier only after the create call returned it. A guessed number is usually a real, unrelated ticket.
|
|
25
|
-
|
|
26
|
-
## What goes to what-needs-me
|
|
27
|
-
|
|
28
|
-
Anything that gates active work on a choice only the human can make: a product call, a priority call between two things that cannot both go first, an approval, or an action only they can physically take (a click in settings, a credential). It is raised as an ask through the `what-needs-me` skill with the question, the options, the default that fires if they stay silent, and what it blocks, and it is raised **before** anyone proceeds on the default.
|
|
29
|
-
|
|
30
|
-
Not an ask: brainstorming, a design back-and-forth, a question the person asked first, a retry-or-abandon call an owner can make, a provider outage (that is one status line, not a per-ticket question).
|
|
31
|
-
|
|
32
|
-
## Three rules that bind this skill
|
|
33
|
-
|
|
34
|
-
- **Never answer as the human.** You do not pick an option on an open ask, close one, or post in their voice. When their answer arrives in chat, it is recorded on the ask through `what-needs-me` so the record is complete, and it is recorded as the app actor, never as them.
|
|
35
|
-
- **Escalate inward, never outward.** An instrument reports to the project owner; the owner asks the desk; the desk asks the human, as an ask. A single stuck ticket is never a page to the human. A system-level failure (provider down, out of capacity, rate-limited) is one line in the status reply, not a question per ticket.
|
|
36
|
-
- **One door.** If the person needs a second place to look after your reply, add the missing block to the reply next time rather than pointing them at a dashboard.
|
|
7
|
+
Pick no ask option, close no ask and post nothing in the human's voice. Record their chat answer through what-needs-me as the app actor.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Settings
|
|
2
|
+
|
|
3
|
+
Use live values and the person's cloud prefix. Owner/admin acts unless stated. Name screen, route, rule.
|
|
4
|
+
|
|
5
|
+
| screen and route | rule |
|
|
6
|
+
| -- | -- |
|
|
7
|
+
| Integrations, /settings/connections | Connecting Linear needs admin browser session, which chooses the account. 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. |
|
|
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. Manage the project, attach repositories, and choose the team's default repository here. |
|
|
11
|
+
| Merging, /settings/projects/$projectId/repositories/$repoId/merging | Merge policy is changed here; 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 or change policy. |
|
|
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
|
+
| 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; raise admin/operator fix as ask. |
|
|
17
|
+
| Routing, no settings page for this | Global stage defaults and empty per-account table select default provider; never promise Codex-first. |
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Stages
|
|
2
|
+
|
|
3
|
+
Slots are board positions; stages are Linear states. teams[].stages maps them per team; show-my-map.mjs stars required slots.
|
|
4
|
+
|
|
5
|
+
Order: dispatch, intake, research, plan, implement, remediate, verify, review, pr, done, canceled.
|
|
6
|
+
|
|
7
|
+
| required slot | allowed Linear type | purpose |
|
|
8
|
+
| -- | -- | -- |
|
|
9
|
+
| dispatch | unstarted/backlog | starts work |
|
|
10
|
+
| intake | unstarted/backlog, never triage | optional classification of unseen tickets |
|
|
11
|
+
| pr | started | permits merge phase |
|
|
12
|
+
| done | completed | merge webhook writes it |
|
|
13
|
+
| canceled | canceled | terminal |
|
|
14
|
+
|
|
15
|
+
Missing/wrong required mappings stop work; others warn. Dispatch/pr/done/canceled must be live. `teams[].gitAutomation` stores consent; nothing reads it.
|
|
16
|
+
|
|
17
|
+
workflowMode: adopted means Catalyst-created, mapped means human-chosen, mixed means both. Configure at `<their cloud>/settings/linear-teams`, never catalyst.toml.
|
|
18
|
+
|
|
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.
|
|
@@ -1,36 +1,16 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Status
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Open with takenAt, source and replica cursor/API reason. Then:
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
1. In flight: ticket, phase and elapsed time from running.
|
|
6
|
+
2. Blocked: reason and release actor.
|
|
7
|
+
3. Waiting on human: ranked waitingOnHuman asks, question and what each releases. Details belong to what-needs-me.
|
|
8
|
+
4. Closed: query issues at the contract's done stage or read the change feed for the requested window; otherwise since the last reply.
|
|
9
|
+
5. Next: queue order and phase.
|
|
10
|
+
6. Cannot see, when nonempty: unreadable facts and CLI-printed URLs. PR labels/reactions are not mirrored. Metrics such as cycle time, throughput, or how long pull requests have been open are not computed; never substitute ticket dates.
|
|
6
11
|
|
|
7
|
-
|
|
12
|
+
Lines use identifier, contract stage, then one clause. Age uses updated_at/lease start and expected phase duration. Omit empty blocks.
|
|
8
13
|
|
|
9
|
-
|
|
14
|
+
Read --board by slot. Long dispatch with nothing running: explain its first ticket. Unmoved cards may run, retry or remediate; count repair separately, never as progress. Asks wait on humans; local-lane work runs elsewhere. Comments and explain --history must agree.
|
|
10
15
|
|
|
11
|
-
|
|
12
|
-
2. **Blocked, and on whom.** Tickets nothing is offered for. Source: the queue's excluded rows, then `explain` on each one the person cares about. Every line carries the reason in the person's words and who releases it: the human (an ask), a role, the cloud itself (a backoff, a park that self-releases), or a clock. "On whom" is never blank; if you cannot tell, say the reason the cloud gave and that the release is unknown to a key.
|
|
13
|
-
3. **Waiting on the human.** The open asks, ranked by what each one holds. Source: `waitingOnHuman` in the snapshot. Keep this to identifier, the question, and what it releases; the `what-needs-me` skill owns the detail and the settling.
|
|
14
|
-
4. **Closed.** What reached the done slot in the window the person asked about (or since your last reply). Source: `query issues` filtered by the team's done-slot stage name from the contract, or the change feed for a time window. When you did not read a window, say "since my last reply" and mean it.
|
|
15
|
-
5. **Next.** What the queue picks up next, in the cloud's order, with the phase each will run. Source: the snapshot's `queue` block. Do not reorder it to what you think should be next; the levers are in `references/reprioritising.md`.
|
|
16
|
-
|
|
17
|
-
A sixth block, **cannot see**, appears only when it is non-empty: the facts your key cannot read (PR labels and reactions, which are not mirrored; an operator-only park release), each with the URL the CLI printed.
|
|
18
|
-
|
|
19
|
-
A flow number is named in that block by name, not left out: cycle time, throughput, or how long pull requests have been open are not computed by anything a key reads today. Say they are not computed rather than counting ticket dates or open pull requests and calling it that.
|
|
20
|
-
|
|
21
|
-
## The header line
|
|
22
|
-
|
|
23
|
-
The reply opens with one clause that says when and from where: the snapshot's `takenAt` and its source line. When the replica was stale or absent, the reply says the numbers came from the API; when it was fresh, it says the cursor. This is not decoration. A stale source that goes unmentioned is the way a wrong status reply happens.
|
|
24
|
-
|
|
25
|
-
## Writing the lines
|
|
26
|
-
|
|
27
|
-
- Identifier first, then the stage as the contract spells it for that team, then one clause. `KEY-123 · <stage name> · implement running 14 min`.
|
|
28
|
-
- Age in human units (minutes, hours, days), from `updated_at` or the lease's start, never a raw timestamp.
|
|
29
|
-
- A reason is the translation from `references/why-is-it-stuck.md`, not the cloud's snake_case token, unless the token is one the table does not know, in which case quote it as the cloud spelled it.
|
|
30
|
-
- No adjectives about health. "Stuck" has a definition (`references/reading-the-board.md`); use it only when it applies.
|
|
31
|
-
|
|
32
|
-
## What the reply never does
|
|
33
|
-
|
|
34
|
-
- It never restates a stage name, threshold or label from memory. The snapshot's `tenant` block carries the live values; read them there each time.
|
|
35
|
-
- It never answers an ask, proposes a default on the human's behalf inside the status reply, or moves anything. Routing a request is `references/routing-work.md`; a decision is the `what-needs-me` skill.
|
|
36
|
-
- It never pads a short answer. When one ticket is in flight and nothing is blocked, the reply is three lines.
|
|
16
|
+
Stuck: nothing offered, no automatic release, no ask or post-failure human comment/push. Otherwise name the wait. Move nothing; route requests to routing-work.md and decisions to what-needs-me.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Phases
|
|
2
|
+
|
|
3
|
+
Explain using their tickets/repos. Dispatch starts repository-configured cloud containers on enrolled accounts, never laptop coding sessions. Agents react to events; documents/outcome comments stay on the ticket.
|
|
4
|
+
|
|
5
|
+
Tickets need outcome title, acceptance criteria, priority, no open blocker and no assumed chat context. Catalyst owns working stages/Done. Draft PRs become ready; green, thread-free PRs queue-merge unless held. Linear asks carry options/default/blocked work. Human comments get eyes and threaded replies.
|
|
6
|
+
|
|
7
|
+
| phase | output or effect |
|
|
8
|
+
| -- | -- |
|
|
9
|
+
| intake | optional classification, no artifact; ladder.intakeEnabled |
|
|
10
|
+
| research | research.md, offered from dispatch |
|
|
11
|
+
| plan | plan.md |
|
|
12
|
+
| implement | implement.md; ticket-id branch and draft PR |
|
|
13
|
+
| validate | validation.md; success enters the shared verify/review stage |
|
|
14
|
+
| pr | pr.md, title first then body; rebase, force-push, mark ready |
|
|
15
|
+
| remediate | remediation.json; failure interrupt, never advances beyond PR |
|
|
16
|
+
| merge | receipt; evidence gate then queue-ready label |
|
|
17
|
+
|
|
18
|
+
Read ladder.advance and keying: trailing stages name the completed phase, leading stages the next. Failure, remediate and merge do not advance the card; see when-a-phase-fails.md. show-my-map.mjs translates stages; explain names the next phase.
|
|
19
|
+
|
|
20
|
+
Done means merged. The webhook writes it within seconds; a sweep recovers losses. Missing Done after one minute is a finding; never hand-close. Live requires deployment.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Dispatch
|
|
2
|
+
|
|
3
|
+
Queues update within seconds. Dispatch sorts by priority, created time, identifier; mid-ladder tickets precede them by phases completed. Order never grants eligibility.
|
|
4
|
+
|
|
5
|
+
An operator sets the repository concurrency cap, default 20, displayed in settings. Pause means zero, preserving the cap. Teams share capacity, including comment-wake.
|
|
6
|
+
|
|
7
|
+
WIP limits starts per project, one Linear team across repositories: project setting, operator's account value, then 12; zero prevents starts. Members read `catalyst project wip-limit get --team <KEY>`; owners/admins use `set <n>` or set default. Only first phases are held; later phases continue. Count live tickets past dispatch or granted a first phase, including waits/blocks/parks; exclude never-started, backlog and local-lane. Idle at the limit means started tickets wait; use unstick, catalyst-github or what-needs-me.
|
|
8
|
+
|
|
9
|
+
Routing selects the first candidate passing capability, configured model, provider availability, eligible slot/headroom when needed, and parameters. No survivor gives `no_eligible_account_slot` if capacity skipped a candidate, otherwise routing_unavailable. Stage defaults are global; no routing setting exists and a Codex-first pipeline cannot be promised.
|
|
10
|
+
|
|
11
|
+
Priority reorders; dispatch starts; backlog stops future phases/rounds without canceling. The person/project owner moves cards. Contract merge.prLabels holds keep PRs out of the queue; ask relations block tickets; the release label corrects ask-shape false positives. Nothing interrupts a running phase. Failed phases need no requeue; manual moves usually restart counts. Priority never overrides blockers.
|
|
12
|
+
|
|
13
|
+
Explain why not next: position means capacity, so report tickets ahead/running. With none running, read accounts. Reasons use why-is-it-stuck.md; missing means another team, terminal or unknown, so verify the id.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Failures
|
|
2
|
+
|
|
3
|
+
Quote live show-my-map.mjs thresholds; these are defaults. Failure itself moves no card.
|
|
4
|
+
|
|
5
|
+
- Pre-branch or infrastructure failures, including 5xx, stream loss, timeout and environment gaps, retry the same phase without repair.
|
|
6
|
+
- Retry and kickoff routing refusal back off 2, 5, 15 minutes, thresholds.retryBackoffMs.
|
|
7
|
+
- Other failures enter remediate; success restores the exact prior stage. Without a remediate stage, use teams[].labels.hold. thresholds.remediateRoundCap defaults to 3 per episode. Failed rounds queue no further round; repeated validate fingerprints consume one round per episode; no recorded branch means no round.
|
|
8
|
+
- thresholds.parkAfterConsecutiveFailures defaults to 3. Repeated-failure and round-cap parks need release after a fix, never a clock; cap release grants one extra round. The cloud's budgeted loop releases missing-branch/rebase-conflict parks.
|
|
9
|
+
|
|
10
|
+
unstick previews and runs `catalyst release <ticket> --because <change>`. Release clears all governors or none, naming required action. Without visible change, require --retry-unchanged.
|
|
11
|
+
|
|
12
|
+
| hold | trigger | release |
|
|
13
|
+
| -- | -- | -- |
|
|
14
|
+
| validate_class_spent | same validate failure after one repair | push, human non-bookkeeping comment, validate pass, ask answer; release after push/comment or --retry-unchanged plus --because; unanswered ask defaults to re-plan after 48 hours |
|
|
15
|
+
| round_threshold | lifetime repair budget | non-fleet push or ask answer grants one cycle; unanswered ask defaults to re-plan after 48 hours; comments and release refused |
|
|
16
|
+
| review_not_converging | nonconverging validate/repair cycles | human comment resumes validate; catalyst: resume implement resumes implement; push and release refused; no ask or 48-hour default |
|
|
17
|
+
| no_change_hold | repair changed nothing | push, human comment or release; never a clock |
|
|
18
|
+
| hand fix pending | ask answered human fixes it | commit on branch |
|
|
19
|
+
| runner pin | runner change merged before image covers it | image pin moves, then Done |
|
|
20
|
+
|
|
21
|
+
Only validate-budget/round-threshold asks default after 48 hours; others await answers. Runner image breaker needs three distinct tickets failing the same startup class on the live image; dispatch waits for the pin. Paused repositories need operator resume. Report each fleet cause once. explain --history prints attempts, rounds/cap, holds, release conditions and past releases.
|