@catalyst-cloud/cli 0.14.6 → 0.14.7
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 +5 -0
- package/README.md +5 -3
- package/dist/args.js +51 -13
- package/dist/cli.js +58 -10
- package/dist/config.js +16 -3
- package/dist/daemon-authority-lifetime.js +171 -0
- package/dist/daemon-authority.js +216 -0
- package/dist/daemon-cache.js +348 -0
- package/dist/daemon-store.js +370 -0
- package/dist/daemon-supervisor.js +460 -0
- package/dist/env/onboard-draft-store.js +243 -0
- package/dist/env/onboard-draft.js +33 -0
- package/dist/env/selected-import-writer.js +163 -0
- package/dist/env/settings-authority.js +203 -0
- package/dist/events-cloud-tail.js +134 -0
- package/dist/events-cloud.js +500 -0
- package/dist/events.js +13 -4
- package/dist/oauth.js +125 -33
- package/dist/onboard-accounts.js +259 -0
- package/dist/onboard-automation-management.js +15 -0
- package/dist/onboard-bootstrap.js +162 -0
- package/dist/onboard-capabilities.js +15 -7
- package/dist/onboard-capacity.js +226 -0
- package/dist/onboard-existing.js +106 -32
- package/dist/onboard-file-snapshot.js +45 -0
- package/dist/onboard-login-candidate.js +261 -0
- package/dist/onboard-projects.js +350 -0
- package/dist/onboard-repositories.js +147 -37
- package/dist/onboard-runtime.js +104 -9
- package/dist/onboard-settings-context.js +141 -0
- package/dist/onboard-settings-import.js +127 -0
- package/dist/onboard-settings.js +234 -0
- package/dist/onboard-ui.js +99 -11
- package/dist/onboard-workflow.js +316 -0
- package/dist/onboard.js +359 -27
- package/dist/owned-fetch.js +182 -0
- package/dist/query.js +77 -27
- package/dist/ready.js +143 -35
- package/dist/replica.js +11 -4
- package/dist/sdk.js +33 -0
- package/dist/watch.js +2 -2
- package/package.json +3 -2
- package/skills/catalyst-github/SKILL.md +2 -2
- package/skills/catalyst-github/references/is-it-mergeable.md +1 -1
- package/skills/catalyst-github/references/what-a-pr-accumulates.md +1 -1
- package/skills/catalyst-github/scripts/is-it-mergeable.mjs +210 -45
- package/skills/catalyst-github/scripts/read-pr.mjs +51 -15
- package/skills/catalyst-linear/SKILL.md +3 -3
- package/skills/catalyst-linear/references/reading-a-ticket.md +3 -3
- package/skills/catalyst-linear/scripts/read-ticket.mjs +37 -12
- package/skills/catalyst-onboard/SKILL.md +5 -4
- package/skills/catalyst-onboard/references/local-sync.md +3 -1
- package/skills/run-this-project/SKILL.md +1 -1
- package/skills/unstick/SKILL.md +1 -1
- package/skills/what-needs-me/SKILL.md +1 -1
- package/skills/what-this-repo-needs/SKILL.md +1 -1
- package/skills/whats-happening/SKILL.md +2 -2
- package/skills/whats-happening/references/status-reply.md +1 -1
- package/skills/whats-happening/scripts/snapshot.mjs +104 -26
- package/vendor/settings/index.d.ts +4 -0
- package/vendor/settings/index.js +2937 -0
- package/vendor/settings/provenance.json +148 -0
|
@@ -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.14.
|
|
7
|
+
<!-- vendored-from: @catalyst-cloud/catalyst-skills@0.14.7 — written in this repository for customer accounts -->
|
|
8
8
|
|
|
9
9
|
# What needs me
|
|
10
10
|
|
|
@@ -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.14.
|
|
7
|
+
<!-- vendored-from: @catalyst-cloud/catalyst-skills@0.14.7 — written in this repository for customer accounts -->
|
|
8
8
|
|
|
9
9
|
# What this repository needs
|
|
10
10
|
|
|
@@ -4,13 +4,13 @@ description: >-
|
|
|
4
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
5
|
allowed-tools: Bash(catalyst:*) Bash(npx -p @catalyst-cloud/cli catalyst:*)
|
|
6
6
|
---
|
|
7
|
-
<!-- vendored-from: @catalyst-cloud/catalyst-skills@0.14.
|
|
7
|
+
<!-- vendored-from: @catalyst-cloud/catalyst-skills@0.14.7 — 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
|
-
- `node scripts/snapshot.mjs`
|
|
13
|
+
- `node scripts/snapshot.mjs` reads contract, running work, queue and ranked asks from the cloud. --board adds stages, --accounts coding accounts, --team K narrows. --replica adds optional local diagnostics.
|
|
14
14
|
- `node scripts/explain.mjs <ticket>` explains eligibility; --history adds attempts, rounds, holds and releases.
|
|
15
15
|
- `node scripts/show-my-map.mjs [--team K]` prints stages, labels, ladder and thresholds.
|
|
16
16
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Status
|
|
2
2
|
|
|
3
|
-
Open with takenAt
|
|
3
|
+
Open with takenAt and the cloud source. Include a replica cursor only when optional local diagnostics were requested. Then:
|
|
4
4
|
|
|
5
5
|
1. In flight: ticket, phase and elapsed time from running.
|
|
6
6
|
2. Blocked: reason and release actor.
|
|
@@ -2,25 +2,48 @@
|
|
|
2
2
|
// snapshot.mjs — one call that answers "where are we?": the account's contract (trimmed to what a
|
|
3
3
|
// status reply needs), what is running, what is queued, what is waiting on a human, and whether the
|
|
4
4
|
// local replica is fresh. Prints ONE JSON document on stdout and the source line on stderr.
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
mustRun,
|
|
7
|
+
parseFlags,
|
|
8
|
+
parseJson,
|
|
9
|
+
printHelp,
|
|
10
|
+
runCli,
|
|
11
|
+
} from "./lib/cli.mjs";
|
|
6
12
|
|
|
7
13
|
const SPEC = {
|
|
8
14
|
team: { value: true, help: "limit the queue and the board to this team key" },
|
|
9
|
-
board: {
|
|
15
|
+
board: {
|
|
16
|
+
value: false,
|
|
17
|
+
help: "also include open tickets grouped by stage, in the contract's slot order",
|
|
18
|
+
},
|
|
10
19
|
limit: { value: true, help: "board: max tickets to read (default 200)" },
|
|
11
|
-
"full-contract": {
|
|
12
|
-
|
|
20
|
+
"full-contract": {
|
|
21
|
+
value: false,
|
|
22
|
+
help: "include the whole contract instead of the trimmed `tenant` block",
|
|
23
|
+
},
|
|
24
|
+
accounts: {
|
|
25
|
+
value: false,
|
|
26
|
+
help: "also include the coding accounts: provider, state, usage windows, walls, quarantine (never a credential)",
|
|
27
|
+
},
|
|
28
|
+
replica: {
|
|
29
|
+
value: false,
|
|
30
|
+
help: "also read optional local replica diagnostics",
|
|
31
|
+
},
|
|
13
32
|
};
|
|
14
33
|
|
|
15
34
|
const { help, flags } = parseFlags(process.argv.slice(2), SPEC);
|
|
16
35
|
if (help) {
|
|
17
|
-
printHelp(
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
36
|
+
printHelp(
|
|
37
|
+
"node scripts/snapshot.mjs [--team K] [--board] [--accounts] [--limit N] [--full-contract] [--help]",
|
|
38
|
+
SPEC,
|
|
39
|
+
[
|
|
40
|
+
"Reads catalyst contract, running, queue and ask list from the cloud (query issues with --board,",
|
|
41
|
+
"accounts with --accounts, optional local diagnostics with --replica).",
|
|
42
|
+
"Output: one JSON document {takenAt, source, tenant, running, queue, waitingOnHuman, board?, accounts?, errors?}.",
|
|
43
|
+
"A section the cloud refused is reported under errors and the rest still prints; exit 1 in that case.",
|
|
44
|
+
"Every account fact (stage names, thresholds, teams) comes from the contract in this output, never from prose.",
|
|
45
|
+
],
|
|
46
|
+
);
|
|
24
47
|
process.exit(0);
|
|
25
48
|
}
|
|
26
49
|
|
|
@@ -28,26 +51,40 @@ const errors = {};
|
|
|
28
51
|
const section = (name, args) => {
|
|
29
52
|
const r = runCli(args);
|
|
30
53
|
if (r.code !== 0) {
|
|
31
|
-
errors[name] = (r.stderr || r.stdout || `exit ${r.code}`)
|
|
54
|
+
errors[name] = (r.stderr || r.stdout || `exit ${r.code}`)
|
|
55
|
+
.trim()
|
|
56
|
+
.split("\n")
|
|
57
|
+
.at(-1);
|
|
32
58
|
return null;
|
|
33
59
|
}
|
|
34
60
|
return parseJson(r.stdout, name);
|
|
35
61
|
};
|
|
36
62
|
|
|
37
|
-
const contract = parseJson(
|
|
63
|
+
const contract = parseJson(
|
|
64
|
+
mustRun(["contract", "--json"], { quiet: true }).stdout,
|
|
65
|
+
"contract",
|
|
66
|
+
);
|
|
38
67
|
// `replica status` exits 0 fresh, 1 stale, 3 absent — all three are verdicts with JSON on stdout,
|
|
39
68
|
// not failures; only a non-JSON answer is an error.
|
|
40
69
|
const replica = (() => {
|
|
70
|
+
if (!flags.replica)
|
|
71
|
+
return { verdict: "not-selected", cursor: null, heartbeatAgeMs: null };
|
|
41
72
|
const r = runCli(["replica", "status", "--json"]);
|
|
42
73
|
try {
|
|
43
74
|
return JSON.parse(r.stdout.trim());
|
|
44
75
|
} catch {
|
|
45
|
-
errors.replica = (r.stderr || r.stdout || `exit ${r.code}`)
|
|
76
|
+
errors.replica = (r.stderr || r.stdout || `exit ${r.code}`)
|
|
77
|
+
.trim()
|
|
78
|
+
.split("\n")
|
|
79
|
+
.at(-1);
|
|
46
80
|
return { verdict: "unknown", cursor: null, heartbeatAgeMs: null };
|
|
47
81
|
}
|
|
48
82
|
})();
|
|
49
83
|
const running = section("running", ["running", "--json"]);
|
|
50
|
-
const queue = section(
|
|
84
|
+
const queue = section(
|
|
85
|
+
"queue",
|
|
86
|
+
flags.team ? ["queue", "--team", flags.team, "--json"] : ["queue", "--json"],
|
|
87
|
+
);
|
|
51
88
|
const asks = section("waitingOnHuman", ["ask", "list", "--json"]);
|
|
52
89
|
|
|
53
90
|
const out = {
|
|
@@ -58,7 +95,9 @@ const out = {
|
|
|
58
95
|
replicaCursor: replica.cursor ?? null,
|
|
59
96
|
replicaHeartbeatAgeMs: replica.heartbeatAgeMs ?? null,
|
|
60
97
|
},
|
|
61
|
-
tenant: flags["full-contract"]
|
|
98
|
+
tenant: flags["full-contract"]
|
|
99
|
+
? contract
|
|
100
|
+
: trimContract(contract, flags.team),
|
|
62
101
|
running,
|
|
63
102
|
queue,
|
|
64
103
|
waitingOnHuman: asks,
|
|
@@ -67,14 +106,23 @@ const out = {
|
|
|
67
106
|
if (flags.accounts) out.accounts = section("accounts", ["accounts", "--json"]);
|
|
68
107
|
|
|
69
108
|
if (flags.board) {
|
|
70
|
-
const args = [
|
|
109
|
+
const args = [
|
|
110
|
+
"query",
|
|
111
|
+
"issues",
|
|
112
|
+
"--source",
|
|
113
|
+
"api",
|
|
114
|
+
"--limit",
|
|
115
|
+
String(flags.limit ?? 200),
|
|
116
|
+
"--json",
|
|
117
|
+
];
|
|
71
118
|
if (flags.team) args.push("--team", flags.team);
|
|
72
119
|
const r = runCli(args);
|
|
73
120
|
const sourceLine = (r.stderr.match(/^source: .*$/m) ?? [null])[0];
|
|
74
121
|
// A board read is a window (`--limit` stays the default), and a window the cloud cut short must
|
|
75
122
|
// say so rather than reading as the whole team.
|
|
76
123
|
const truncatedLine = (r.stderr.match(/^truncated at .*$/m) ?? [null])[0];
|
|
77
|
-
if (r.code !== 0)
|
|
124
|
+
if (r.code !== 0)
|
|
125
|
+
errors.board = (r.stderr || `exit ${r.code}`).trim().split("\n").at(-1);
|
|
78
126
|
else {
|
|
79
127
|
const rows = parseJson(r.stdout, "issues");
|
|
80
128
|
out.board = groupByStage(rows, contract, flags.team);
|
|
@@ -84,18 +132,27 @@ if (flags.board) {
|
|
|
84
132
|
}
|
|
85
133
|
|
|
86
134
|
if (Object.keys(errors).length) out.errors = errors;
|
|
87
|
-
process.stderr.write(
|
|
135
|
+
process.stderr.write(
|
|
136
|
+
`source: api for running/queue/asks; replica ${replica.verdict}${replica.cursor != null ? ` (cursor ${replica.cursor})` : ""}${out.source.board ? `; board from ${out.source.board}` : ""}\n`,
|
|
137
|
+
);
|
|
88
138
|
process.stdout.write(JSON.stringify(out, null, 2) + "\n");
|
|
89
139
|
process.exit(Object.keys(errors).length ? 1 : 0);
|
|
90
140
|
|
|
91
141
|
/** The contract facts a status reply needs, and nothing a reply should not paste. */
|
|
92
142
|
function trimContract(doc, teamKey) {
|
|
93
|
-
const teams = (doc.teams ?? []).filter(
|
|
143
|
+
const teams = (doc.teams ?? []).filter(
|
|
144
|
+
(t) =>
|
|
145
|
+
!teamKey || String(t.key ?? "").toUpperCase() === teamKey.toUpperCase(),
|
|
146
|
+
);
|
|
94
147
|
return {
|
|
95
148
|
contractVersion: doc.contractVersion,
|
|
96
149
|
account: { slug: doc.account?.slug, name: doc.account?.name },
|
|
97
150
|
slots: doc.slots,
|
|
98
|
-
ladder: {
|
|
151
|
+
ladder: {
|
|
152
|
+
phases: doc.ladder?.phases,
|
|
153
|
+
intakeEnabled: doc.ladder?.intakeEnabled,
|
|
154
|
+
keying: doc.ladder?.keying,
|
|
155
|
+
},
|
|
99
156
|
thresholds: doc.thresholds,
|
|
100
157
|
mergeDefaultPolicy: doc.merge?.defaultPolicy,
|
|
101
158
|
teams: teams.map((t) => ({
|
|
@@ -106,7 +163,14 @@ function trimContract(doc, teamKey) {
|
|
|
106
163
|
stages: Object.fromEntries(
|
|
107
164
|
(doc.slots ?? Object.keys(t.stages ?? {}))
|
|
108
165
|
.filter((slot) => t.stages?.[slot])
|
|
109
|
-
.map((slot) => [
|
|
166
|
+
.map((slot) => [
|
|
167
|
+
slot,
|
|
168
|
+
{
|
|
169
|
+
name: t.stages[slot].name,
|
|
170
|
+
type: t.stages[slot].type,
|
|
171
|
+
stateStillExists: t.stages[slot].stateStillExists,
|
|
172
|
+
},
|
|
173
|
+
]),
|
|
110
174
|
),
|
|
111
175
|
labels: {
|
|
112
176
|
ask: (t.labels?.ask ?? []).map((l) => l.name),
|
|
@@ -124,11 +188,19 @@ function groupByStage(rows, doc, teamKey) {
|
|
|
124
188
|
const seen = new Set();
|
|
125
189
|
const terminal = new Set();
|
|
126
190
|
for (const t of doc.teams ?? []) {
|
|
127
|
-
if (teamKey && String(t.key ?? "").toUpperCase() !== teamKey.toUpperCase())
|
|
191
|
+
if (teamKey && String(t.key ?? "").toUpperCase() !== teamKey.toUpperCase())
|
|
192
|
+
continue;
|
|
128
193
|
for (const slot of doc.slots ?? []) {
|
|
129
194
|
const s = t.stages?.[slot];
|
|
130
195
|
if (!s?.name) continue;
|
|
131
|
-
if (
|
|
196
|
+
if (
|
|
197
|
+
slot === "done" ||
|
|
198
|
+
slot === "canceled" ||
|
|
199
|
+
["completed", "canceled", "cancelled"].includes(
|
|
200
|
+
String(s.type ?? "").toLowerCase(),
|
|
201
|
+
)
|
|
202
|
+
)
|
|
203
|
+
terminal.add(s.name);
|
|
132
204
|
else if (!seen.has(s.name)) {
|
|
133
205
|
seen.add(s.name);
|
|
134
206
|
order.push(s.name);
|
|
@@ -148,6 +220,12 @@ function groupByStage(rows, doc, teamKey) {
|
|
|
148
220
|
projectId: r.project_id ?? null,
|
|
149
221
|
});
|
|
150
222
|
}
|
|
151
|
-
const extra = Object.keys(byStage)
|
|
152
|
-
|
|
223
|
+
const extra = Object.keys(byStage)
|
|
224
|
+
.filter((s) => !seen.has(s))
|
|
225
|
+
.sort();
|
|
226
|
+
return {
|
|
227
|
+
stageOrder: [...order, ...extra],
|
|
228
|
+
byStage,
|
|
229
|
+
terminalStagesDropped: [...terminal],
|
|
230
|
+
};
|
|
153
231
|
}
|