@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,51 +1,34 @@
|
|
|
1
1
|
# What the browser owns
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Browser by construction
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Each is an authorization a person grants in their own session, so no command will ever do it. Say **by construction**; a person told "not supported yet" waits for a feature that will never come.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
| step | where |
|
|
8
|
+
| -- | -- |
|
|
9
|
+
| approving the login | the URL and short code `catalyst login` printed |
|
|
10
|
+
| enrolling a coding account, or replacing its credential | the AI accounts page the script printed |
|
|
11
|
+
| connecting the Linear integration, installing the GitHub App | `<their cloud>/settings/connections` (Settings → Integrations) |
|
|
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`) |
|
|
13
|
+
| connecting personal Linear, then personal GitHub | the URL `catalyst connections personal <linear\|github> start` printed |
|
|
8
14
|
|
|
9
|
-
|
|
10
|
-
| -- | -- | -- |
|
|
11
|
-
| approving the login | the URL and short code that `catalyst login` printed | "I have started the login. It printed this code and this URL — approve it in your browser, or on your phone, and tell me when it is done." |
|
|
12
|
-
| enrolling a coding account, or replacing its credential | the AI accounts page the script printed for the `coding accounts` part | "Choose the provider, give the account a label you will recognise, and paste the credential the page asks for. Nothing on this side sees it. Tell me when it is saved and I will read it back." |
|
|
13
|
-
| connecting the Linear integration | `<their cloud>/settings/connections` (the Integrations page; Settings labels it Connections today) | "Open this page and connect Linear. It will send you to Linear to authorize it and bring you back." |
|
|
14
|
-
| installing the GitHub App | `<their cloud>/settings/connections` | "Open the same page and install the GitHub App, granting it the repository you want worked and `<your GitHub org>/thoughts`." |
|
|
15
|
-
| creating or confirming `<your GitHub org>/thoughts`, and letting the GitHub App reach it | GitHub, then the GitHub App's installation page for that org | "Catalyst's cloud phases write their notes to `<your GitHub org>/thoughts`, in the org that owns the code repository. Check it exists. If not, create a private repository named `thoughts`, initialized with a README. Then, on the GitHub App's installation page for that org, choose All repositories, or add `thoughts` to the selected repositories." |
|
|
16
|
-
| connecting personal Linear | the URL printed by `catalyst connections personal linear start` | "Approve your own Linear account in this browser. I will check the grant status afterward." |
|
|
17
|
-
| connecting personal GitHub, after the tenant GitHub App is installed and its repository is registered | the URL printed by `catalyst connections personal github start` | "Approve your own GitHub account in this browser. I will check the grant status afterward." |
|
|
15
|
+
## Not a command yet
|
|
18
16
|
|
|
19
|
-
|
|
17
|
+
Their routes take a browser session, not a key. Call them gaps, route the person through the browser, and never guess at a route.
|
|
20
18
|
|
|
21
|
-
|
|
19
|
+
| step | where |
|
|
20
|
+
| -- | -- |
|
|
21
|
+
| registering a repository and attaching it to a project | `<their cloud>/settings/projects` (Settings → Your projects) |
|
|
22
|
+
| approving one repository's declaration, and entering its values | that repository's Environment page (`references/declaring-a-repository.md`) |
|
|
22
23
|
|
|
23
|
-
|
|
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.
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
| -- | -- | -- |
|
|
27
|
-
| registering a repository | `<their cloud>/settings/repositories` | "Add the repository here, and attach it to the project you just mapped, in the same form." |
|
|
28
|
-
| approving the environment **for one repository**, and entering its values | that repository's Environment page under `<their cloud>/settings/repositories`: the Setup declaration tab's Approve this revision button approves, and the Environment variables and Secrets tabs take the values | "The names come from `.catalyst/catalyst.toml` in the repository, which I can write with you. Approving it and entering the values happen here, once, by you. Nothing I run ever sees a value." (Account-wide names are **not** on this list: `catalyst environment` does those.) |
|
|
26
|
+
## The link to hand over
|
|
29
27
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
## The URL to hand over
|
|
33
|
-
|
|
34
|
-
Never type a host from memory. `catalyst status` prints the API it is connected to on its `API:` line, and `node scripts/where-am-i.mjs` prints ready-made links built from it. Use those. A person pointed at the wrong tenant's settings page has a worse afternoon than one pointed at no page at all.
|
|
28
|
+
Use the links `node scripts/where-am-i.mjs` prints, built from the `API:` line of `catalyst status`, never a host from memory: the wrong account's settings page costs more than none.
|
|
35
29
|
|
|
36
30
|
## Handing over, and coming back
|
|
37
31
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
1. **What to open.** One link, and what they will see on it.
|
|
41
|
-
2. **What to do there.** One action, named the way the page names it.
|
|
42
|
-
3. **What you need back.** Not "let me know when you are done" — say what you will check and how. "When you have saved it, say so and I will re-read your tenant and tell you what it now says."
|
|
43
|
-
|
|
44
|
-
Then **wait**. Do not run anything while they are mid-flow, do not narrate, and do not move to the next step.
|
|
45
|
-
|
|
46
|
-
When they come back:
|
|
32
|
+
Hand over one link, one action named the way the page names it, and what you will check when they are back. Then wait, without running anything.
|
|
47
33
|
|
|
48
|
-
|
|
49
|
-
- If it changed, say what it now says and move on.
|
|
50
|
-
- If it did not, refresh the contract once (`catalyst contract --refresh`) and read it again — the contract is cached, and a page can be ahead of it by a few seconds.
|
|
51
|
-
- If it still did not, report both: what the page told them, and what the instrument says. Ask what they saw. **Never mark a step done because the person said a page worked** — the instrument is the record, and this is exactly where a confident false "all set" costs them an hour later.
|
|
34
|
+
When they come back, read the part again (step 5 of a turn in `SKILL.md`). The contract is cached, so a page can be seconds ahead of it: refresh once before reporting a disagreement, then ask what they saw. A step is done when the instrument reads done.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// check.mjs — "am I set up?" in one verdict: the machine checks the CLI runs (Node, the connection,
|
|
3
3
|
// the cached contract, the CLI path, the skills, the SDK, the optional replica) plus every team's
|
|
4
|
-
// readiness
|
|
5
|
-
// `catalyst
|
|
6
|
-
import {
|
|
4
|
+
// readiness from the account's contract, then the list of who can click what. Wraps
|
|
5
|
+
// `catalyst ready --json`; reports, never repairs. Exit 0 READY, 1 NOT READY, 2 not connected.
|
|
6
|
+
import { runCli, tryJson } from "./lib/cli.mjs";
|
|
7
7
|
|
|
8
8
|
const HELP = `Usage: node scripts/check.mjs [--json]
|
|
9
9
|
|
|
@@ -12,7 +12,8 @@ verdict, and a "who can click what" list grouped by the person or role each fix
|
|
|
12
12
|
A note never flips the verdict (the replica is optional; an informational readiness check is a note).
|
|
13
13
|
|
|
14
14
|
--json prints the CLI's report document {ready, checks[]} unchanged.
|
|
15
|
-
Exit 0 READY, 1 NOT READY, 2 this machine is not connected
|
|
15
|
+
Exit 0 READY, 1 NOT READY, 2 this machine is not connected yet or the CLI could not run.
|
|
16
|
+
How to read each line: references/reading-ready.md.`;
|
|
16
17
|
|
|
17
18
|
const args = process.argv.slice(2);
|
|
18
19
|
if (args.includes("--help") || args.includes("-h")) {
|
|
@@ -27,13 +28,13 @@ if (unknown.length > 0) {
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
const res = runCli(["ready", "--json"]);
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
const report = tryJson(res.stdout);
|
|
32
|
+
if (!res.ran || (res.code === 2 && !report)) {
|
|
33
|
+
console.error(res.stderr.trim() || "catalyst ready refused");
|
|
32
34
|
process.exit(2);
|
|
33
35
|
}
|
|
34
|
-
const report = parseJson(res.stdout);
|
|
35
36
|
if (!report || !Array.isArray(report.checks)) {
|
|
36
|
-
console.error(res.stderr.trim() || res.stdout.trim() || "catalyst
|
|
37
|
+
console.error(res.stderr.trim() || res.stdout.trim() || "catalyst ready printed no report");
|
|
37
38
|
process.exit(res.code === 0 ? 1 : res.code);
|
|
38
39
|
}
|
|
39
40
|
if (args.includes("--json")) {
|
|
@@ -70,6 +71,6 @@ if (failures.length > 0) {
|
|
|
70
71
|
const notes = report.checks.filter((c) => c.note && !c.ok);
|
|
71
72
|
if (notes.length > 0) {
|
|
72
73
|
console.log("");
|
|
73
|
-
console.log(`Notes that do not block: ${notes.map((c) => c.id).join(", ")} — see references/
|
|
74
|
+
console.log(`Notes that do not block: ${notes.map((c) => c.id).join(", ")} — see references/reading-ready.md`);
|
|
74
75
|
}
|
|
75
76
|
process.exit(report.ready ? 0 : 1);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// lib/cli.mjs — the one way a skill script reaches Catalyst Cloud: spawn the catalyst
|
|
2
|
+
// lib/cli.mjs — the one way a skill script reaches Catalyst Cloud: spawn the catalyst CLI.
|
|
3
3
|
// The CLI holds the SDK and the key; this file holds neither. It reads customer.json only to learn
|
|
4
4
|
// where the CLI lives. Run any script beside this one with --help; this file is a library.
|
|
5
5
|
//
|
|
@@ -13,7 +13,9 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
13
13
|
import { join } from "node:path";
|
|
14
14
|
import { CONNECT_COMMAND, hasCredential } from "./credential.mjs";
|
|
15
15
|
|
|
16
|
-
export const PACKAGE = "@catalyst-cloud/
|
|
16
|
+
export const PACKAGE = "@catalyst-cloud/cli";
|
|
17
|
+
/** The package ships two commands, so npx needs the one to run named: `npx -p <package> catalyst`. */
|
|
18
|
+
export const NPX_ARGS = ["-p", PACKAGE, "catalyst"];
|
|
17
19
|
export const NOT_CONFIGURED_EXIT = 2;
|
|
18
20
|
export const CONNECT_LINE = CONNECT_COMMAND;
|
|
19
21
|
|
|
@@ -53,11 +55,11 @@ export function cliTarget(cfg = tryLoadConfig()) {
|
|
|
53
55
|
const recorded = recordedPath !== null;
|
|
54
56
|
return recorded
|
|
55
57
|
? { command: process.execPath, prefix: [cfg.cliPath], via: `node ${cfg.cliPath}`, recorded: true }
|
|
56
|
-
: { command: "npx", prefix:
|
|
58
|
+
: { command: "npx", prefix: NPX_ARGS, via: `npx -p ${PACKAGE} catalyst`, recorded: false };
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
/**
|
|
60
|
-
* Run one catalyst
|
|
62
|
+
* Run one catalyst verb. Returns {code, stdout, stderr, ran} and never exits: a verb that
|
|
61
63
|
* refuses because the machine is not connected is a READING, not a failure of this script.
|
|
62
64
|
* `ran` is false when the CLI could not be started at all.
|
|
63
65
|
*/
|
|
@@ -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) {
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Shared coverage formatter used by where-am-i; --help documents its input contract.
|
|
3
|
+
if (process.argv.includes("--help")) {
|
|
4
|
+
process.stdout.write(
|
|
5
|
+
"Usage: imported by where-am-i; compares project rows with saved team stage mappings.\n",
|
|
6
|
+
);
|
|
7
|
+
process.exit(0);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** Compare the full Catalyst project inventory with teams that actually have saved stage rows. */
|
|
11
|
+
export function projectCoverage(projects, teams) {
|
|
12
|
+
const mappedTeamIds = new Set(
|
|
13
|
+
teams
|
|
14
|
+
.filter(
|
|
15
|
+
(team) =>
|
|
16
|
+
team &&
|
|
17
|
+
(team.id ?? team.teamId) &&
|
|
18
|
+
team.stages &&
|
|
19
|
+
Object.keys(team.stages).length > 0,
|
|
20
|
+
)
|
|
21
|
+
.map((team) => team.id ?? team.teamId),
|
|
22
|
+
);
|
|
23
|
+
const mapped = [];
|
|
24
|
+
const unmapped = [];
|
|
25
|
+
for (const project of projects) {
|
|
26
|
+
(mappedTeamIds.has(project.linearTeamId) ? mapped : unmapped).push(project);
|
|
27
|
+
}
|
|
28
|
+
return { mapped, unmapped, total: projects.length };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function projectCoverageLines(projects, teams) {
|
|
32
|
+
const coverage = projectCoverage(projects, teams);
|
|
33
|
+
const teamById = new Map(teams.map((team) => [team.id ?? team.teamId, team]));
|
|
34
|
+
const lines = [
|
|
35
|
+
`${coverage.mapped.length} of your ${coverage.total} projects have their Linear team mapped.`,
|
|
36
|
+
];
|
|
37
|
+
for (const project of coverage.mapped) {
|
|
38
|
+
const team = teamById.get(project.linearTeamId);
|
|
39
|
+
const readiness = team?.readiness ?? {};
|
|
40
|
+
const bad = Array.isArray(readiness.checks)
|
|
41
|
+
? readiness.checks.filter((check) => check.state !== "pass")
|
|
42
|
+
: [];
|
|
43
|
+
lines.push(
|
|
44
|
+
`${project.name} (${project.linearTeamKey ?? team?.teamKey ?? project.linearTeamId}): ${readiness.status ?? "unchecked"}${bad.length ? ` — ${bad.map((check) => `${check.id} ${check.state}`).join(", ")}` : ""}`,
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
if (coverage.unmapped.length > 0) {
|
|
48
|
+
lines.push(
|
|
49
|
+
`These ${coverage.unmapped.length} do not: ${coverage.unmapped.map((project) => project.name).join(", ")}`,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
return { ...coverage, lines };
|
|
53
|
+
}
|