@catalyst-cloud/catalyst-skills 0.1.1 → 0.2.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 +8 -0
- package/README.md +109 -53
- package/bin/catalyst-skills.js +42 -2
- package/dist/args.js +242 -0
- package/dist/ask.js +137 -0
- package/dist/cli.js +167 -279
- package/dist/config.js +106 -0
- package/dist/contract-types.js +4 -0
- package/dist/contract.js +178 -0
- package/dist/detach.js +10 -0
- package/dist/errors.js +27 -0
- package/dist/execution.js +308 -0
- package/dist/http.js +175 -0
- package/dist/prompt.js +35 -0
- package/dist/query.js +225 -0
- package/dist/ready.js +123 -0
- package/dist/replica.js +318 -0
- package/dist/sdk.js +26 -0
- package/dist/skill-shape.js +179 -0
- package/dist/skills.js +74 -0
- package/dist/ts-deps-loader.js +68 -0
- package/dist/watch/consumer.js +141 -0
- package/dist/watch/cursor-file.js +62 -0
- package/dist/watch.js +173 -0
- package/dist/write.js +224 -0
- package/package.json +12 -7
- package/skills/catalyst-github/SKILL.md +35 -0
- package/skills/catalyst-github/agents/openai.yaml +6 -0
- package/skills/catalyst-github/agents/portability.yaml +4 -0
- package/skills/catalyst-github/references/is-it-mergeable.md +57 -0
- package/skills/catalyst-github/references/what-a-pr-accumulates.md +61 -0
- package/skills/catalyst-github/scripts/is-it-mergeable.mjs +124 -0
- package/skills/catalyst-github/scripts/lib/cli.mjs +102 -0
- package/skills/catalyst-github/scripts/lib/pull.mjs +82 -0
- package/skills/catalyst-github/scripts/read-pr.mjs +97 -0
- package/skills/catalyst-linear/SKILL.md +43 -0
- package/skills/catalyst-linear/agents/openai.yaml +6 -0
- package/skills/catalyst-linear/agents/portability.yaml +5 -0
- package/skills/catalyst-linear/references/reading-a-ticket.md +50 -0
- package/skills/catalyst-linear/references/what-a-ticket-accumulates.md +53 -0
- package/skills/catalyst-linear/references/writing-to-linear.md +43 -0
- package/skills/catalyst-linear/scripts/comment.mjs +59 -0
- package/skills/catalyst-linear/scripts/create-ticket.mjs +44 -0
- package/skills/catalyst-linear/scripts/label.mjs +48 -0
- package/skills/catalyst-linear/scripts/lib/cli.mjs +163 -0
- package/skills/catalyst-linear/scripts/move.mjs +41 -0
- package/skills/catalyst-linear/scripts/read-ticket.mjs +93 -0
- package/skills/catalyst-linear/scripts/search.mjs +49 -0
- package/skills/catalyst-setup/SKILL.md +32 -0
- package/skills/catalyst-setup/agents/openai.yaml +6 -0
- package/skills/catalyst-setup/agents/portability.yaml +4 -0
- package/skills/catalyst-setup/references/what-each-check-means.md +61 -0
- package/skills/catalyst-setup/scripts/check.mjs +75 -0
- package/skills/catalyst-setup/scripts/lib/cli.mjs +102 -0
- package/skills/catalyst-setup/scripts/replica-status.mjs +46 -0
- package/skills/connect-me/SKILL.md +55 -0
- package/skills/connect-me/agents/openai.yaml +6 -0
- package/skills/connect-me/agents/portability.yaml +5 -0
- package/skills/connect-me/references/keeping-the-replica-running.md +88 -0
- package/skills/connect-me/scripts/lib/cli.mjs +184 -0
- package/skills/connect-me/scripts/verify-connection.mjs +68 -0
- package/skills/how-catalyst-works/SKILL.md +42 -0
- package/skills/how-catalyst-works/agents/openai.yaml +6 -0
- package/skills/how-catalyst-works/agents/portability.yaml +4 -0
- package/skills/how-catalyst-works/references/coding-accounts.md +51 -0
- package/skills/how-catalyst-works/references/stages-and-mapping.md +54 -0
- package/skills/how-catalyst-works/references/the-ladder.md +41 -0
- package/skills/how-catalyst-works/references/what-runs-next.md +77 -0
- package/skills/how-catalyst-works/references/when-a-phase-fails.md +57 -0
- package/skills/how-catalyst-works/scripts/explain-ticket.mjs +41 -0
- package/skills/how-catalyst-works/scripts/lib/cli.mjs +163 -0
- package/skills/how-catalyst-works/scripts/show-my-map.mjs +94 -0
- package/skills/how-catalyst-works/scripts/whats-running.mjs +66 -0
- package/skills/run-this-project/SKILL.md +45 -0
- package/skills/run-this-project/agents/openai.yaml +6 -0
- package/skills/run-this-project/agents/portability.yaml +5 -0
- package/skills/run-this-project/assets/stall-policy.json +15 -0
- package/skills/run-this-project/references/making-work-ready.md +60 -0
- package/skills/run-this-project/references/reacting-to-events.md +76 -0
- package/skills/run-this-project/references/stalls-and-escalation.md +63 -0
- package/skills/run-this-project/scripts/lib/cli.mjs +184 -0
- package/skills/run-this-project/scripts/make-ready.mjs +64 -0
- package/skills/run-this-project/scripts/scope-status.mjs +0 -0
- package/skills/run-this-project/scripts/watch-scope.mjs +61 -0
- package/skills/what-needs-me/SKILL.md +41 -0
- package/skills/what-needs-me/agents/openai.yaml +6 -0
- package/skills/what-needs-me/agents/portability.yaml +5 -0
- package/skills/what-needs-me/references/raising-a-decision.md +41 -0
- package/skills/what-needs-me/references/reading-the-inbox.md +38 -0
- package/skills/what-needs-me/references/settling-an-answer.md +37 -0
- package/skills/what-needs-me/scripts/inbox.mjs +47 -0
- package/skills/what-needs-me/scripts/lib/cli.mjs +134 -0
- package/skills/what-needs-me/scripts/raise.mjs +53 -0
- package/skills/what-needs-me/scripts/settle.mjs +73 -0
- package/skills/whats-happening/SKILL.md +43 -0
- package/skills/whats-happening/agents/openai.yaml +6 -0
- package/skills/whats-happening/agents/portability.yaml +4 -0
- package/skills/whats-happening/assets/status-reply.json +77 -0
- package/skills/whats-happening/references/reading-the-board.md +43 -0
- package/skills/whats-happening/references/reprioritising.md +37 -0
- package/skills/whats-happening/references/routing-work.md +36 -0
- package/skills/whats-happening/references/status-reply.md +34 -0
- package/skills/whats-happening/references/why-is-it-stuck.md +57 -0
- package/skills/whats-happening/scripts/explain.mjs +28 -0
- package/skills/whats-happening/scripts/lib/cli.mjs +134 -0
- package/skills/whats-happening/scripts/snapshot.mjs +145 -0
- package/skills/ask/SKILL.md +0 -37
- package/skills/concierge/SKILL.md +0 -41
- package/skills/join/SKILL.md +0 -30
- package/skills/linearis/SKILL.md +0 -40
- package/skills/setup/SKILL.md +0 -27
- package/skills/steward/SKILL.md +0 -30
package/dist/ask.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// ask.ts — `ask raise|accept|list`: raise a decision through the contract's ask route (the cloud
|
|
2
|
+
// renders the body from its own template, so this passes fields, never headings), record an answer
|
|
3
|
+
// through ask-accept, and list open asks ranked by the work each one holds.
|
|
4
|
+
import { flagBool, flagList, flagString, positionals } from "./args.js";
|
|
5
|
+
import { requireConfig } from "./config.js";
|
|
6
|
+
import { loadContract, teamByKey } from "./contract.js";
|
|
7
|
+
import { UsageError } from "./errors.js";
|
|
8
|
+
import { apiClient } from "./http.js";
|
|
9
|
+
import { rowsOf } from "./query.js";
|
|
10
|
+
import { fetchWorkflowStates, postAgent, resolveIssue } from "./write.js";
|
|
11
|
+
export async function cmdAsk(args, ctx) {
|
|
12
|
+
const [sub, ...rest] = positionals(args);
|
|
13
|
+
if (!sub)
|
|
14
|
+
throw new UsageError("ask needs a subcommand: raise | accept | list");
|
|
15
|
+
if (sub === "raise" && !flagBool(args, "nothing-to-block") && flagList(args, "blocks").length === 0) {
|
|
16
|
+
throw new UsageError("ask raise needs --blocks <ticket>... (what this decision holds) or --nothing-to-block");
|
|
17
|
+
}
|
|
18
|
+
const cfg = requireConfig(ctx);
|
|
19
|
+
const { doc } = await loadContract(ctx, cfg);
|
|
20
|
+
const api = apiClient(cfg, ctx);
|
|
21
|
+
switch (sub) {
|
|
22
|
+
case "raise":
|
|
23
|
+
return raise(args, ctx, doc, api);
|
|
24
|
+
case "accept":
|
|
25
|
+
return accept(args, ctx, doc, api, rest);
|
|
26
|
+
case "list":
|
|
27
|
+
return list(args, ctx, doc, api);
|
|
28
|
+
default:
|
|
29
|
+
throw new UsageError(`unknown ask subcommand: ${sub}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async function raise(args, ctx, doc, api) {
|
|
33
|
+
const teamKey = flagString(args, "team");
|
|
34
|
+
const title = flagString(args, "title");
|
|
35
|
+
if (!teamKey || !title)
|
|
36
|
+
throw new UsageError("ask raise needs --team <key> and --title <question>");
|
|
37
|
+
const team = teamByKey(doc, teamKey);
|
|
38
|
+
const options = flagList(args, "option");
|
|
39
|
+
if (options.length > doc.askTemplate.maxLetteredOptions) {
|
|
40
|
+
throw new UsageError(`ask raise takes at most ${doc.askTemplate.maxLetteredOptions} options`);
|
|
41
|
+
}
|
|
42
|
+
const blocks = [];
|
|
43
|
+
for (const t of flagList(args, "blocks"))
|
|
44
|
+
blocks.push((await resolveIssue(api, t)).id);
|
|
45
|
+
const body = { title, teamId: team.id };
|
|
46
|
+
if (flagString(args, "context"))
|
|
47
|
+
body.context = flagString(args, "context");
|
|
48
|
+
if (options.length)
|
|
49
|
+
body.options = options;
|
|
50
|
+
if (flagString(args, "default"))
|
|
51
|
+
body.defaultIfSilent = flagString(args, "default");
|
|
52
|
+
if (blocks.length)
|
|
53
|
+
body.blocks = blocks;
|
|
54
|
+
if (flagBool(args, "nothing-to-block"))
|
|
55
|
+
body.nothingToBlock = true;
|
|
56
|
+
if (flagString(args, "ask-key"))
|
|
57
|
+
body.askKey = flagString(args, "ask-key");
|
|
58
|
+
const result = await postAgent(api, doc, "ask", body);
|
|
59
|
+
ctx.stdout(args.json ? JSON.stringify(result) : `ask raised: ${String(result.identifier ?? result.id ?? "ok")}${blocks.length ? ` (blocks ${blocks.length})` : ""}`);
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
62
|
+
async function accept(args, ctx, doc, api, rest) {
|
|
63
|
+
const askTicket = rest[0];
|
|
64
|
+
const answer = flagString(args, "answer");
|
|
65
|
+
const role = flagString(args, "role");
|
|
66
|
+
if (!askTicket || !answer || !role)
|
|
67
|
+
throw new UsageError("ask accept needs <askTicket> --answer <commentId> --role <role>");
|
|
68
|
+
const ask = await resolveIssue(api, askTicket);
|
|
69
|
+
const result = await postAgent(api, doc, "ask-accept", {
|
|
70
|
+
askIssueId: ask.id,
|
|
71
|
+
answerCommentId: answer,
|
|
72
|
+
acceptedByRole: role,
|
|
73
|
+
});
|
|
74
|
+
ctx.stdout(args.json ? JSON.stringify(result) : `ask ${ask.identifier}: answer ${answer} recorded by ${role}`);
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
77
|
+
/** Rank open asks by the priority-weighted count of open tickets each one blocks. Priority 1 (urgent)
|
|
78
|
+
* weighs 4, 4 (low) weighs 1, 0 (none) weighs 1. */
|
|
79
|
+
export function rankAsks(issues, doc, openState) {
|
|
80
|
+
const askIds = new Set();
|
|
81
|
+
for (const team of doc.teams)
|
|
82
|
+
for (const l of team.labels.ask)
|
|
83
|
+
for (const id of [l.unscopedId, l.teamScopedId, l.preferredId])
|
|
84
|
+
if (id)
|
|
85
|
+
askIds.add(id);
|
|
86
|
+
const isAsk = (issue) => {
|
|
87
|
+
const labels = Array.isArray(issue.labels) ? issue.labels : [];
|
|
88
|
+
return labels.some((l) => (typeof l.id === "string" && askIds.has(l.id)) || (typeof l.name === "string" && (l.name === doc.vocabulary.askMarkerLabel || l.name.startsWith(doc.vocabulary.askLabelPrefix))));
|
|
89
|
+
};
|
|
90
|
+
const byIdentifier = new Map();
|
|
91
|
+
for (const i of issues)
|
|
92
|
+
if (typeof i.identifier === "string")
|
|
93
|
+
byIdentifier.set(i.identifier, i);
|
|
94
|
+
const weight = (issue) => {
|
|
95
|
+
const p = typeof issue?.priority === "number" ? issue.priority : 0;
|
|
96
|
+
return p >= 1 && p <= 4 ? 5 - p : 1;
|
|
97
|
+
};
|
|
98
|
+
const out = [];
|
|
99
|
+
for (const issue of issues) {
|
|
100
|
+
if (!isAsk(issue) || !openState(issue))
|
|
101
|
+
continue;
|
|
102
|
+
const relations = Array.isArray(issue.relations) ? issue.relations : [];
|
|
103
|
+
const blocked = relations
|
|
104
|
+
.filter((r) => r.type === "blocks" && r.issue_identifier === issue.identifier && typeof r.related_identifier === "string")
|
|
105
|
+
.map((r) => r.related_identifier)
|
|
106
|
+
.filter((id) => {
|
|
107
|
+
const t = byIdentifier.get(id);
|
|
108
|
+
return !t || openState(t);
|
|
109
|
+
});
|
|
110
|
+
out.push({
|
|
111
|
+
identifier: String(issue.identifier),
|
|
112
|
+
title: String(issue.title ?? ""),
|
|
113
|
+
state: String(issue.state ?? ""),
|
|
114
|
+
blocks: blocked,
|
|
115
|
+
score: blocked.reduce((sum, id) => sum + weight(byIdentifier.get(id)), 0),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return out.sort((a, b) => b.score - a.score || a.identifier.localeCompare(b.identifier));
|
|
119
|
+
}
|
|
120
|
+
async function list(args, ctx, doc, api) {
|
|
121
|
+
const [issuesRes, states] = await Promise.all([api.getJson("/api/v1/issues", { query: { limit: 500 } }), fetchWorkflowStates(api)]);
|
|
122
|
+
const issues = rowsOf(issuesRes.body);
|
|
123
|
+
const terminal = new Set(states.filter((s) => ["completed", "canceled", "cancelled"].includes(s.type.toLowerCase())).map((s) => s.name.toLowerCase()));
|
|
124
|
+
const openState = (issue) => !terminal.has(String(issue.state ?? "").toLowerCase());
|
|
125
|
+
const ranked = rankAsks(issues, doc, openState);
|
|
126
|
+
if (args.json) {
|
|
127
|
+
ctx.stdout(JSON.stringify(ranked));
|
|
128
|
+
return 0;
|
|
129
|
+
}
|
|
130
|
+
if (ranked.length === 0) {
|
|
131
|
+
ctx.stdout("no open asks");
|
|
132
|
+
return 0;
|
|
133
|
+
}
|
|
134
|
+
for (const a of ranked)
|
|
135
|
+
ctx.stdout(`${a.identifier} holds ${a.blocks.length} ticket${a.blocks.length === 1 ? "" : "s"} (weight ${a.score})${a.blocks.length ? `: ${a.blocks.join(", ")}` : ""} ${a.title}`);
|
|
136
|
+
return 0;
|
|
137
|
+
}
|