@catalyst-cloud/catalyst-skills 0.3.0 → 0.3.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 +4 -0
- package/README.md +2 -2
- package/dist/contract.js +1 -1
- package/dist/execution.js +19 -4
- package/dist/ready.js +42 -2
- package/dist/skills.js +5 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.1
|
|
4
|
+
|
|
5
|
+
`ready` now names the person you connected as: when your key is a personal key, the config line reads "joined <tenant> as <you> (<role>)" instead of the generic "as service" that every api key showed, and an account (host) key still names the tenant with no person. `ready` also learns the bundle version your tenant expects, when the cloud publishes one: if this installed bundle is older than that minimum you get a one-line warning that names both versions and the upgrade command, but it stays a note — `ready` never refuses over a stale bundle, and a cloud that does not publish a minimum changes nothing. `explain` no longer calls every ticket with no dispatch row "unknown": a ticket that merely sits in Backlog (or any non-dispatch state) is now named as known to the mirror with the state it is in, and only a ticket the mirror has never seen keeps the unknown wording.
|
|
6
|
+
|
|
3
7
|
## 0.3.0
|
|
4
8
|
|
|
5
9
|
You connect with your own personal key now, not the tenant's shared account key: mint it yourself at Settings → API keys in the Catalyst Cloud app (every member can; no admin needed), and `login` prints who you connected as beside which tenant. Your agent acts as you — an ask it raises names you, and "what needs me" means you: `ask list` (and the what-needs-me skill) keeps only the asks assigned to your Linear user by default, `--anyone` lists the whole tenant, and when your Linear identity is not matched yet it says so and shows everything rather than an empty list. `customer.json` gains a `user` block (id, label, role, your Linear user id); an older config is still read unchanged. Connecting with the account key still works — it is the right credential for a host or daemon — but `login` tells you it names no person. Every skill, reference and help line that said "account key", or said execution history and coding-account status were not readable, has been rewritten: `explain --history` and `accounts` read them, and the two things your key genuinely cannot do (release a park, read PR labels or reactions) are named instead. The catalyst-setup reference now lists all eleven team checks, including `environment_declared`. Needs a cloud that admits personal keys on the agent routes; on an older cloud the contract read says so by name, and the account key still works until it is updated.
|
package/README.md
CHANGED
|
@@ -145,10 +145,10 @@ The skill files themselves are written by whichever install command you ran, in
|
|
|
145
145
|
|
|
146
146
|
## Updating
|
|
147
147
|
|
|
148
|
-
A plugin install updates when we ship. Skills copied by `npx skills add` do not; run `npx skills update -y` to refresh them. Update the CLI with `npm
|
|
148
|
+
A plugin install updates when we ship. Skills copied by `npx skills add` do not; run `npx skills update -y` to refresh them. Update the CLI with `npm install -g @catalyst-cloud/catalyst-skills@latest && catalyst-skills login` — the re-login rewrites the CLI path the skills spawn, so they stop running the old bundle. To run one command against the latest publish without installing, use `npx @catalyst-cloud/catalyst-skills@latest login`. The next `catalyst-skills` run prints a one-line notice:
|
|
149
149
|
|
|
150
150
|
```
|
|
151
|
-
[catalyst-skills] updated 0.1.1 → 0.2.0: <that version's CHANGELOG.md summary> · update with: npm
|
|
151
|
+
[catalyst-skills] updated 0.1.1 → 0.2.0: <that version's CHANGELOG.md summary> · update with: npm install -g @catalyst-cloud/catalyst-skills@latest && catalyst-skills login
|
|
152
152
|
```
|
|
153
153
|
|
|
154
154
|
A `customer.json` written by an older bundle is still read unchanged; it gains the CLI path and the cached contract the next time you run `catalyst-skills login`.
|
package/dist/contract.js
CHANGED
|
@@ -45,7 +45,7 @@ export function assertContractRange(version, range) {
|
|
|
45
45
|
if (ok === null)
|
|
46
46
|
throw new CliError(`tenantContractRange "${range}" in package.json is not a range this CLI understands`, "contract-range");
|
|
47
47
|
if (!ok) {
|
|
48
|
-
throw new CliError(`the tenant serves contract version ${version} but this bundle accepts ${range} — update the bundle (npm
|
|
48
|
+
throw new CliError(`the tenant serves contract version ${version} but this bundle accepts ${range} — update the bundle (npm install -g @catalyst-cloud/catalyst-skills@latest && catalyst-skills login) or ask your tenant admin which version is live`, "contract-version");
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
/**
|
package/dist/execution.js
CHANGED
|
@@ -61,9 +61,15 @@ export function describeReason(reason) {
|
|
|
61
61
|
return "no reason was given";
|
|
62
62
|
return EXCLUSION_REASONS[reason] ?? UNKNOWN_REASONS[reason] ?? `reason "${reason}" (not in this bundle's table; read it as the cloud spelled it)`;
|
|
63
63
|
}
|
|
64
|
-
export function renderExplain(ticket, row, team) {
|
|
65
|
-
if (!row)
|
|
64
|
+
export function renderExplain(ticket, row, team, knownState) {
|
|
65
|
+
if (!row) {
|
|
66
|
+
// A null dispatch row is not proof the ticket does not exist — the explainer is a dispatch scan. When
|
|
67
|
+
// `knownState` is set (the mirror answered GET /issues/:id) the ticket is real; it just sits outside a
|
|
68
|
+
// dispatch column. Only a 404 (knownState null/absent) is truly unknown to the mirror.
|
|
69
|
+
if (knownState)
|
|
70
|
+
return `${ticket}: known to the mirror; state ${knownState} is not a dispatch state.`;
|
|
66
71
|
return `${ticket}: not in the ${team} eligibility explainer — the ticket is unknown to the mirror, terminal, or on another team.`;
|
|
72
|
+
}
|
|
67
73
|
const parts = [];
|
|
68
74
|
const pos = typeof row.position === "number" ? `position ${row.position}` : "no queue position";
|
|
69
75
|
const status = row.status ?? "unknown";
|
|
@@ -115,11 +121,20 @@ export async function cmdExplain(args, ctx) {
|
|
|
115
121
|
});
|
|
116
122
|
const rows = res.body.eligibility?.rows ?? res.body.rows ?? [];
|
|
117
123
|
const row = rows.find((r) => String(r.ticket ?? "").toUpperCase() === ticket.toUpperCase()) ?? null;
|
|
124
|
+
// No dispatch row is not proof of non-existence: probe the mirror so a Backlog ticket reads as known.
|
|
125
|
+
// The mirror compares identifiers exactly, so normalize (uppercase) as the row lookup above does —
|
|
126
|
+
// otherwise `explain eng-7` probes a lowercase id, 404s, and reports an existing ENG-7 as unknown.
|
|
127
|
+
let knownState = null;
|
|
128
|
+
if (!row) {
|
|
129
|
+
const probe = await api.getJson(`/api/v1/issues/${encodeURIComponent(ticket.toUpperCase())}`, { accept: [404] });
|
|
130
|
+
if (probe.status !== 404)
|
|
131
|
+
knownState = typeof probe.body?.state === "string" ? probe.body.state : "unknown";
|
|
132
|
+
}
|
|
118
133
|
if (args.json) {
|
|
119
|
-
ctx.stdout(JSON.stringify({ ticket, row, explanation: renderExplain(ticket, row, team) }));
|
|
134
|
+
ctx.stdout(JSON.stringify({ ticket, row, explanation: renderExplain(ticket, row, team, knownState) }));
|
|
120
135
|
}
|
|
121
136
|
else {
|
|
122
|
-
ctx.stdout(renderExplain(ticket, row, team));
|
|
137
|
+
ctx.stdout(renderExplain(ticket, row, team, knownState));
|
|
123
138
|
}
|
|
124
139
|
return 0;
|
|
125
140
|
}
|
package/dist/ready.js
CHANGED
|
@@ -8,6 +8,22 @@ import { contractVersionInRange, readContractCache } from "./contract.js";
|
|
|
8
8
|
import { CliError } from "./errors.js";
|
|
9
9
|
import { replicaStatus, statusLine } from "./replica.js";
|
|
10
10
|
import { loadSdk } from "./sdk.js";
|
|
11
|
+
/** True when `a` is a semver-older release than `b`. Prerelease/build metadata is ignored; a segment
|
|
12
|
+
* that does not parse counts as 0. A tiny compare on purpose — no dependency for three fields. */
|
|
13
|
+
export function semverOlder(a, b) {
|
|
14
|
+
const parse = (v) => {
|
|
15
|
+
const core = v.split("-")[0].split("+")[0];
|
|
16
|
+
const p = core.split(".");
|
|
17
|
+
return [Number(p[0]) || 0, Number(p[1]) || 0, Number(p[2]) || 0];
|
|
18
|
+
};
|
|
19
|
+
const [a0, a1, a2] = parse(a);
|
|
20
|
+
const [b0, b1, b2] = parse(b);
|
|
21
|
+
if (a0 !== b0)
|
|
22
|
+
return a0 < b0;
|
|
23
|
+
if (a1 !== b1)
|
|
24
|
+
return a1 < b1;
|
|
25
|
+
return a2 < b2;
|
|
26
|
+
}
|
|
11
27
|
function whoCanAnswer(doc) {
|
|
12
28
|
const roles = doc.humans.map((h) => `${h.role} ${h.linearUserId}`);
|
|
13
29
|
return roles.length ? roles.join(", ") : "a tenant owner or admin (none resolved on the contract)";
|
|
@@ -22,7 +38,16 @@ export async function readyReport(ctx, deps) {
|
|
|
22
38
|
try {
|
|
23
39
|
cfg = loadConfig(ctx.home);
|
|
24
40
|
checks.push(cfg
|
|
25
|
-
? {
|
|
41
|
+
? {
|
|
42
|
+
id: "config",
|
|
43
|
+
ok: true,
|
|
44
|
+
// `principal` is "service" for every api key (it means "a key, not a browser session"); it
|
|
45
|
+
// never names a person. Since CTC-2076 a personal key's /me carries a `user` block, so name
|
|
46
|
+
// the connected person when there is one, and fall back to the account for a host key.
|
|
47
|
+
line: cfg.user
|
|
48
|
+
? `config: joined ${cfg.name} as ${cfg.user.label} (${cfg.user.role})`
|
|
49
|
+
: `config: joined ${cfg.name} (${cfg.slug}) as ${cfg.principal}`,
|
|
50
|
+
}
|
|
26
51
|
: { id: "config", ok: false, line: "config: not connected", fix: "CATALYST_CLOUD_TOKEN=<your personal key> npx @catalyst-cloud/catalyst-skills login", who: "you (mint the key at Settings → API keys)" });
|
|
27
52
|
}
|
|
28
53
|
catch (err) {
|
|
@@ -34,11 +59,26 @@ export async function readyReport(ctx, deps) {
|
|
|
34
59
|
checks.push({ id: "contract", ok: false, line: "contract: not cached", fix: "catalyst-skills contract --refresh", who: "you" });
|
|
35
60
|
}
|
|
36
61
|
else if (contractVersionInRange(cache.contractVersion, range) !== true) {
|
|
37
|
-
checks.push({ id: "contract", ok: false, line: `contract: version ${cache.contractVersion} is outside this bundle's range ${range}`, fix: "npm
|
|
62
|
+
checks.push({ id: "contract", ok: false, line: `contract: version ${cache.contractVersion} is outside this bundle's range ${range}`, fix: "npm install -g @catalyst-cloud/catalyst-skills@latest && catalyst-skills login", who: "you" });
|
|
38
63
|
}
|
|
39
64
|
else {
|
|
40
65
|
checks.push({ id: "contract", ok: true, line: `contract: ${cache.contractVersion} cached ${cache.fetchedAt} (range ${range})` });
|
|
41
66
|
}
|
|
67
|
+
// The cloud MAY publish the bundle it expects (catalyst-cloud#3746). Read it defensively: warn (never
|
|
68
|
+
// refuse) when this installed bundle is older than the minimum, and emit nothing when the field is
|
|
69
|
+
// absent (an older cloud) — a stale bundle is a degrading note, so `ready` still returns READY.
|
|
70
|
+
const minVersion = cache?.doc.skillsBundle?.minVersion;
|
|
71
|
+
if (minVersion) {
|
|
72
|
+
const installed = readManifest().version;
|
|
73
|
+
if (semverOlder(installed, minVersion)) {
|
|
74
|
+
checks.push({
|
|
75
|
+
id: "bundle",
|
|
76
|
+
ok: false,
|
|
77
|
+
note: true,
|
|
78
|
+
line: `bundle: ${installed} installed is older than the tenant's minimum ${minVersion} — upgrade: npm install -g @catalyst-cloud/catalyst-skills@latest && catalyst-skills login`,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
42
82
|
if (cfg) {
|
|
43
83
|
checks.push(cfg.cliPath && existsSync(cfg.cliPath)
|
|
44
84
|
? { id: "cliPath", ok: true, line: `cliPath: ${cfg.cliPath}` }
|
package/dist/skills.js
CHANGED
|
@@ -70,5 +70,9 @@ export function readChangelog() {
|
|
|
70
70
|
}
|
|
71
71
|
export function updateNoticeLine(previous, current, entry) {
|
|
72
72
|
const summary = entry ?? "see CHANGELOG.md";
|
|
73
|
-
|
|
73
|
+
// `npm update -g` treats a global install as a caret range, and a caret below 1.0.0 never moves a
|
|
74
|
+
// minor — so it never crosses 0.2.x → 0.3.0. Pin @latest via `npm install`, THEN re-run login: the
|
|
75
|
+
// install alone does not rewrite customer.json.cliPath, so the skill helpers would keep spawning the
|
|
76
|
+
// stale recorded bundle and repeat this notice forever; the new global bin records its own path.
|
|
77
|
+
return `[catalyst-skills] updated ${previous} → ${current}: ${summary} · update with: npm install -g ${PACKAGE_NAME}@latest && catalyst-skills login`;
|
|
74
78
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@catalyst-cloud/catalyst-skills",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Customer skill bundle for Catalyst Cloud: eight skills named from the executive's seat (whats-happening, what-needs-me, run-this-project, catalyst-setup, catalyst-linear, catalyst-github, how-catalyst-works, connect-me) plus the catalyst-skills CLI that reads through the Catalyst Cloud SDK, writes through the agent proxy, and connects your machine to your tenant with one command.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|