standup-mr 0.2.0 → 0.3.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 +48 -0
- package/README.md +49 -1
- package/dist/{chunk-MIQ7FQS6.js → chunk-DL2P3XR6.js} +14 -3
- package/dist/cli.js +45 -4
- package/dist/index.js +1 -1
- package/dist/mcp/server.js +20 -14
- package/mcp/README.md +22 -8
- package/package.json +28 -13
- package/skills/standup/SKILL.md +37 -12
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,54 @@ All notable changes to standup-mr are recorded here. The format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses
|
|
5
5
|
[semantic versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.3.0] - 2026-09-01
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `standup mcp` — starts the stdio MCP server directly from the CLI, so
|
|
12
|
+
`npx -y standup-mr mcp` works without a local clone.
|
|
13
|
+
- `standup instructions` — prints the note-writing playbook (the standup
|
|
14
|
+
skill body, minus its YAML frontmatter) to stdout, for teaching a
|
|
15
|
+
non-Claude assistant the same rules, e.g.
|
|
16
|
+
`npx standup-mr instructions >> AGENTS.md`.
|
|
17
|
+
- README section for using the MCP server from Cursor, Codex, or another
|
|
18
|
+
assistant.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- The skill wrote the note in English even when the user was speaking Turkish.
|
|
23
|
+
The language rule was buried as a clause inside a sentence about section
|
|
24
|
+
structure, and `fetch` was called with no `--lang`, so every date label in
|
|
25
|
+
the JSON came back English and outweighed it. The rule is now a standalone,
|
|
26
|
+
unmissable line, and the skill passes `--lang` to match the user's language
|
|
27
|
+
so the payload reinforces the note instead of fighting it.
|
|
28
|
+
- On a machine where both `gh` and `glab` are authenticated, every run failed
|
|
29
|
+
once before succeeding: the skill called `fetch` with no `--provider`, hit
|
|
30
|
+
the "both authenticated" error, then retried with the flag. The skill now
|
|
31
|
+
passes `--provider` on the first call whenever it's known, and only asks the
|
|
32
|
+
user (instead of guessing) when it genuinely isn't.
|
|
33
|
+
|
|
34
|
+
Nothing breaking. `@modelcontextprotocol/sdk` moves from a dev dependency to
|
|
35
|
+
a regular dependency, since the CLI can now start the MCP server itself; the
|
|
36
|
+
CLI's `fetch`/`post`/`instructions` path still pulls nothing.
|
|
37
|
+
|
|
38
|
+
## [0.2.1] - 2026-08-31
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- A pull request whose CI timed out was reported as ready to merge. GitHub
|
|
43
|
+
reports a timed-out job with the conclusion `cancelled`, not `timed_out`, so
|
|
44
|
+
it normalised to a `canceled` pipeline — and a canceled pipeline was treated
|
|
45
|
+
as a green light. A canceled pipeline now blocks, on both providers: GitLab's
|
|
46
|
+
`canceled` status took the same path.
|
|
47
|
+
- Every error line in a GitHub blocker was reported twice. GitHub Actions echoes
|
|
48
|
+
a step's script inside a `##[group]Run …` block before running it, and those
|
|
49
|
+
echoed lines matched the error patterns. The body of a `Run` group is now
|
|
50
|
+
suppressed; other groups are still scanned, since they carry real output.
|
|
51
|
+
|
|
52
|
+
Both were found by testing 0.2.0 against the real GitHub Actions API — neither
|
|
53
|
+
was reachable from the test fixtures.
|
|
54
|
+
|
|
7
55
|
## [0.2.0] - 2026-08-31
|
|
8
56
|
|
|
9
57
|
GitHub joins GitLab as a first-class provider, and the previous-day report
|
package/README.md
CHANGED
|
@@ -76,6 +76,52 @@ skill. From inside Claude Code:
|
|
|
76
76
|
|
|
77
77
|
Then type `/standup`. Updates come with `/plugin marketplace update standup-mr`.
|
|
78
78
|
|
|
79
|
+
### Using it from Cursor, Codex, or another assistant
|
|
80
|
+
|
|
81
|
+
If you're not using Claude Code, wire up the MCP server for live data and
|
|
82
|
+
paste in the note-writing rules separately.
|
|
83
|
+
|
|
84
|
+
**Cursor** — add to `~/.cursor/mcp.json` (global) or `.cursor/mcp.json`
|
|
85
|
+
(project-local):
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"mcpServers": {
|
|
90
|
+
"standup": {
|
|
91
|
+
"command": "npx",
|
|
92
|
+
"args": ["-y", "standup-mr", "mcp"],
|
|
93
|
+
"env": {
|
|
94
|
+
"GITHUB_TOKEN": "ghp_..."
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Codex** — add to `~/.codex/config.toml`:
|
|
102
|
+
|
|
103
|
+
```toml
|
|
104
|
+
[mcp_servers.standup]
|
|
105
|
+
command = "npx"
|
|
106
|
+
args = ["-y", "standup-mr", "mcp"]
|
|
107
|
+
|
|
108
|
+
[mcp_servers.standup.env]
|
|
109
|
+
GITHUB_TOKEN = "ghp_..."
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The exact config key and file path are version-dependent for both clients —
|
|
113
|
+
if a snippet above doesn't work, check [Cursor's MCP
|
|
114
|
+
docs](https://docs.cursor.com/context/mcp) or Codex's own config
|
|
115
|
+
documentation for the current format rather than trusting this file blindly.
|
|
116
|
+
|
|
117
|
+
The tool only returns data; the assistant still needs the note-writing rules
|
|
118
|
+
that the Claude Code skill carries. Paste them into whatever instructions
|
|
119
|
+
file your assistant reads (e.g. `AGENTS.md`):
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
npx standup-mr instructions >> AGENTS.md
|
|
123
|
+
```
|
|
124
|
+
|
|
79
125
|
## `--markdown` is a digest, not a written note
|
|
80
126
|
|
|
81
127
|
`--markdown` organizes the raw material into readable sections. It does **not**
|
|
@@ -162,7 +208,9 @@ the `standup` skill changed along with the report shape.
|
|
|
162
208
|
|
|
163
209
|
## Requirements
|
|
164
210
|
|
|
165
|
-
Node 20 or newer.
|
|
211
|
+
Node 20 or newer. The CLI core (`fetch`, `post`, `instructions`) pulls no
|
|
212
|
+
runtime dependencies. The MCP server (`mcp` command) brings one:
|
|
213
|
+
`@modelcontextprotocol/sdk`.
|
|
166
214
|
|
|
167
215
|
## License
|
|
168
216
|
|
|
@@ -80,7 +80,7 @@ function previousActiveDays(eventDates, today) {
|
|
|
80
80
|
// src/buckets/buckets.ts
|
|
81
81
|
function classify(mr, today, staleDays = STALE_DAYS) {
|
|
82
82
|
if (mr.draft) return "draft";
|
|
83
|
-
if (mr.pipeline === "failed" || mr.unresolved > 0) return "blocked";
|
|
83
|
+
if (mr.pipeline === "failed" || mr.pipeline === "canceled" || mr.unresolved > 0) return "blocked";
|
|
84
84
|
const age = Math.round(
|
|
85
85
|
(Date.parse(`${isoDay(today)}T00:00:00Z`) - Date.parse(`${mr.updated}T00:00:00Z`)) / MS_PER_DAY
|
|
86
86
|
);
|
|
@@ -274,7 +274,9 @@ var NOISE = /^(Cleaning up|Job failed: exit status|ERROR: Job failed|Uploading a
|
|
|
274
274
|
var MAX_LINE = 200;
|
|
275
275
|
var TIMESTAMP = /^\d{4}-\d{2}-\d{2}T[\d:.]+Z\s+/;
|
|
276
276
|
var ERROR_MARKER = /^##\[error\]\s*/;
|
|
277
|
-
var
|
|
277
|
+
var GROUP_START = /^##\[group\]/;
|
|
278
|
+
var GROUP_END = /^##\[endgroup\]/;
|
|
279
|
+
var RUN_GROUP = /^##\[group\]Run\s/;
|
|
278
280
|
|
|
279
281
|
// src/trace/trace.ts
|
|
280
282
|
function extractErrors(rawTrace, limit = 8) {
|
|
@@ -282,9 +284,18 @@ function extractErrors(rawTrace, limit = 8) {
|
|
|
282
284
|
const cleaned = rawTrace.replace(ANSI, "").replace(SECTION, "");
|
|
283
285
|
const seen = /* @__PURE__ */ new Set();
|
|
284
286
|
const hits = [];
|
|
287
|
+
let suppressing = false;
|
|
285
288
|
for (const rawLine of cleaned.split("\n")) {
|
|
286
289
|
const stamped = rawLine.trim().replace(TIMESTAMP, "");
|
|
287
|
-
if (
|
|
290
|
+
if (GROUP_START.test(stamped)) {
|
|
291
|
+
suppressing = RUN_GROUP.test(stamped);
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
if (GROUP_END.test(stamped)) {
|
|
295
|
+
suppressing = false;
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
if (suppressing) continue;
|
|
288
299
|
if (!stamped || NOISE.test(stamped) || !SIGNAL.test(stamped)) continue;
|
|
289
300
|
const line = stamped.replace(ERROR_MARKER, "").trim();
|
|
290
301
|
if (!line) continue;
|
package/dist/cli.js
CHANGED
|
@@ -5,11 +5,12 @@ import {
|
|
|
5
5
|
connect,
|
|
6
6
|
postWebhook,
|
|
7
7
|
toMarkdown
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-DL2P3XR6.js";
|
|
9
9
|
|
|
10
10
|
// src/cli/cli.ts
|
|
11
|
-
import { realpathSync } from "fs";
|
|
12
|
-
import {
|
|
11
|
+
import { existsSync, readFileSync, realpathSync } from "fs";
|
|
12
|
+
import { dirname, join } from "path";
|
|
13
|
+
import { fileURLToPath, pathToFileURL } from "url";
|
|
13
14
|
import { parseArgs } from "util";
|
|
14
15
|
|
|
15
16
|
// src/cli/cli.constants.ts
|
|
@@ -19,13 +20,20 @@ Usage:
|
|
|
19
20
|
standup fetch [--provider github|gitlab] [--host H] [--token T]
|
|
20
21
|
[--lang en|tr] [--markdown]
|
|
21
22
|
standup post (--slack URL | --discord URL) [--text TEXT]
|
|
23
|
+
standup mcp
|
|
24
|
+
standup instructions
|
|
22
25
|
|
|
23
26
|
The provider is taken from --provider, then STANDUP_PROVIDER, then whichever of
|
|
24
27
|
GITHUB_* / GITLAB_* is set, then whichever of gh / glab is logged in.
|
|
25
28
|
|
|
26
29
|
Credentials resolve as: flag, then GITHUB_HOST / GITHUB_TOKEN (or GITLAB_HOST /
|
|
27
30
|
GITLAB_TOKEN), then the gh or glab config.
|
|
28
|
-
--text defaults to '-', meaning read stdin
|
|
31
|
+
--text defaults to '-', meaning read stdin.
|
|
32
|
+
|
|
33
|
+
standup mcp starts the stdio MCP server, exposing get_standup_data.
|
|
34
|
+
standup instructions prints the note-writing playbook (the standup skill body)
|
|
35
|
+
to stdout, for teaching a non-Claude assistant the same rules, e.g.:
|
|
36
|
+
npx standup-mr instructions >> AGENTS.md`;
|
|
29
37
|
|
|
30
38
|
// src/cli/cli.ts
|
|
31
39
|
async function readStdin() {
|
|
@@ -33,6 +41,27 @@ async function readStdin() {
|
|
|
33
41
|
for await (const chunk of process.stdin) chunks.push(Buffer.from(chunk));
|
|
34
42
|
return Buffer.concat(chunks).toString("utf8");
|
|
35
43
|
}
|
|
44
|
+
function findPackageRoot(startDir) {
|
|
45
|
+
let dir = startDir;
|
|
46
|
+
while (!existsSync(join(dir, "package.json"))) {
|
|
47
|
+
const parent = dirname(dir);
|
|
48
|
+
if (parent === dir) {
|
|
49
|
+
throw new Error(`Could not locate package.json above ${startDir}`);
|
|
50
|
+
}
|
|
51
|
+
dir = parent;
|
|
52
|
+
}
|
|
53
|
+
return dir;
|
|
54
|
+
}
|
|
55
|
+
function readStandupSkillBody() {
|
|
56
|
+
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
57
|
+
const skillPath = join(findPackageRoot(moduleDir), "skills", "standup", "SKILL.md");
|
|
58
|
+
if (!existsSync(skillPath)) {
|
|
59
|
+
throw new Error(`Cannot find the standup skill file at ${skillPath}`);
|
|
60
|
+
}
|
|
61
|
+
const content = readFileSync(skillPath, "utf8");
|
|
62
|
+
const withoutFrontmatter = content.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n/, "");
|
|
63
|
+
return withoutFrontmatter.replace(/^\n+/, "");
|
|
64
|
+
}
|
|
36
65
|
async function main(argv) {
|
|
37
66
|
const [command, ...rest] = argv;
|
|
38
67
|
if (!command || command === "--help" || command === "-h") {
|
|
@@ -80,6 +109,18 @@ async function main(argv) {
|
|
|
80
109
|
await postWebhook(url, text, values.slack ? "slack" : "discord");
|
|
81
110
|
return 0;
|
|
82
111
|
}
|
|
112
|
+
if (command === "mcp") {
|
|
113
|
+
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
114
|
+
const serverPath = join(findPackageRoot(moduleDir), "dist", "mcp", "server.js");
|
|
115
|
+
const serverUrl = pathToFileURL(serverPath).href;
|
|
116
|
+
const { main: startMcpServer } = await import(serverUrl);
|
|
117
|
+
await startMcpServer();
|
|
118
|
+
return 0;
|
|
119
|
+
}
|
|
120
|
+
if (command === "instructions") {
|
|
121
|
+
process.stdout.write(readStandupSkillBody());
|
|
122
|
+
return 0;
|
|
123
|
+
}
|
|
83
124
|
process.stderr.write(`Unknown command: ${command}
|
|
84
125
|
|
|
85
126
|
${USAGE}
|
package/dist/index.js
CHANGED
package/dist/mcp/server.js
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
// mcp/server.ts
|
|
4
4
|
import { realpathSync } from "fs";
|
|
5
5
|
import { pathToFileURL } from "url";
|
|
6
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
8
|
|
|
7
9
|
// src/config/config.ts
|
|
8
10
|
import { execFileSync } from "child_process";
|
|
@@ -176,7 +178,7 @@ function previousActiveDays(eventDates, today) {
|
|
|
176
178
|
// src/buckets/buckets.ts
|
|
177
179
|
function classify(mr, today, staleDays = STALE_DAYS) {
|
|
178
180
|
if (mr.draft) return "draft";
|
|
179
|
-
if (mr.pipeline === "failed" || mr.unresolved > 0) return "blocked";
|
|
181
|
+
if (mr.pipeline === "failed" || mr.pipeline === "canceled" || mr.unresolved > 0) return "blocked";
|
|
180
182
|
const age = Math.round(
|
|
181
183
|
(Date.parse(`${isoDay(today)}T00:00:00Z`) - Date.parse(`${mr.updated}T00:00:00Z`)) / MS_PER_DAY
|
|
182
184
|
);
|
|
@@ -197,7 +199,9 @@ var NOISE = /^(Cleaning up|Job failed: exit status|ERROR: Job failed|Uploading a
|
|
|
197
199
|
var MAX_LINE = 200;
|
|
198
200
|
var TIMESTAMP = /^\d{4}-\d{2}-\d{2}T[\d:.]+Z\s+/;
|
|
199
201
|
var ERROR_MARKER = /^##\[error\]\s*/;
|
|
200
|
-
var
|
|
202
|
+
var GROUP_START = /^##\[group\]/;
|
|
203
|
+
var GROUP_END = /^##\[endgroup\]/;
|
|
204
|
+
var RUN_GROUP = /^##\[group\]Run\s/;
|
|
201
205
|
|
|
202
206
|
// src/trace/trace.ts
|
|
203
207
|
function extractErrors(rawTrace, limit = 8) {
|
|
@@ -205,9 +209,18 @@ function extractErrors(rawTrace, limit = 8) {
|
|
|
205
209
|
const cleaned = rawTrace.replace(ANSI, "").replace(SECTION, "");
|
|
206
210
|
const seen = /* @__PURE__ */ new Set();
|
|
207
211
|
const hits = [];
|
|
212
|
+
let suppressing = false;
|
|
208
213
|
for (const rawLine of cleaned.split("\n")) {
|
|
209
214
|
const stamped = rawLine.trim().replace(TIMESTAMP, "");
|
|
210
|
-
if (
|
|
215
|
+
if (GROUP_START.test(stamped)) {
|
|
216
|
+
suppressing = RUN_GROUP.test(stamped);
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
if (GROUP_END.test(stamped)) {
|
|
220
|
+
suppressing = false;
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (suppressing) continue;
|
|
211
224
|
if (!stamped || NOISE.test(stamped) || !SIGNAL.test(stamped)) continue;
|
|
212
225
|
const line = stamped.replace(ERROR_MARKER, "").trim();
|
|
213
226
|
if (!line) continue;
|
|
@@ -953,9 +966,7 @@ async function collect(options = {}) {
|
|
|
953
966
|
return buildReport(provider, /* @__PURE__ */ new Date(), options.lang ?? "en");
|
|
954
967
|
}
|
|
955
968
|
async function main() {
|
|
956
|
-
const
|
|
957
|
-
const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
|
|
958
|
-
const server = new McpServer({ name: "standup-mr", version: "0.2.0" });
|
|
969
|
+
const server = new McpServer({ name: "standup-mr", version: "0.3.0" });
|
|
959
970
|
server.tool(
|
|
960
971
|
"get_standup_data",
|
|
961
972
|
"Collect merge-request-based standup data from GitLab or GitHub. Returns the previous working day activity, open merge requests or pull requests bucketed by state (ready / blocked / draft / stale), pending reviews, and the error lines from any failed pipeline or check.",
|
|
@@ -976,14 +987,9 @@ try {
|
|
|
976
987
|
}
|
|
977
988
|
if (entryUrl && import.meta.url === entryUrl) {
|
|
978
989
|
main().catch((error) => {
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
);
|
|
983
|
-
process.exitCode = 1;
|
|
984
|
-
return;
|
|
985
|
-
}
|
|
986
|
-
throw error;
|
|
990
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}
|
|
991
|
+
`);
|
|
992
|
+
process.exitCode = 1;
|
|
987
993
|
});
|
|
988
994
|
}
|
|
989
995
|
export {
|
package/mcp/README.md
CHANGED
|
@@ -3,12 +3,6 @@
|
|
|
3
3
|
Exposes one tool, `get_standup_data`, for either GitLab or GitHub, returning
|
|
4
4
|
the same JSON as `standup fetch`.
|
|
5
5
|
|
|
6
|
-
## Install
|
|
7
|
-
|
|
8
|
-
```bash
|
|
9
|
-
npm install standup-mr @modelcontextprotocol/sdk
|
|
10
|
-
```
|
|
11
|
-
|
|
12
6
|
## Configure
|
|
13
7
|
|
|
14
8
|
GitLab:
|
|
@@ -17,8 +11,8 @@ GitLab:
|
|
|
17
11
|
{
|
|
18
12
|
"mcpServers": {
|
|
19
13
|
"standup": {
|
|
20
|
-
"command": "
|
|
21
|
-
"args": ["
|
|
14
|
+
"command": "npx",
|
|
15
|
+
"args": ["-y", "standup-mr", "mcp"],
|
|
22
16
|
"env": {
|
|
23
17
|
"GITLAB_HOST": "gitlab.example.com",
|
|
24
18
|
"GITLAB_TOKEN": "glpat-..."
|
|
@@ -30,6 +24,26 @@ GitLab:
|
|
|
30
24
|
|
|
31
25
|
GitHub:
|
|
32
26
|
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"mcpServers": {
|
|
30
|
+
"standup": {
|
|
31
|
+
"command": "npx",
|
|
32
|
+
"args": ["-y", "standup-mr", "mcp"],
|
|
33
|
+
"env": {
|
|
34
|
+
"GITHUB_HOST": "github.com",
|
|
35
|
+
"GITHUB_TOKEN": "ghp_..."
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Running from a clone
|
|
43
|
+
|
|
44
|
+
If you're working from a local clone instead of the published package, point
|
|
45
|
+
`command` at `node` and `args` at the absolute path to the built server:
|
|
46
|
+
|
|
33
47
|
```json
|
|
34
48
|
{
|
|
35
49
|
"mcpServers": {
|
package/package.json
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "standup-mr",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Standup notes from merge request state, not commit logs.",
|
|
5
|
-
"keywords": [
|
|
5
|
+
"keywords": [
|
|
6
|
+
"standup",
|
|
7
|
+
"gitlab",
|
|
8
|
+
"github",
|
|
9
|
+
"merge-request",
|
|
10
|
+
"pull-request",
|
|
11
|
+
"cli",
|
|
12
|
+
"mcp"
|
|
13
|
+
],
|
|
6
14
|
"license": "MIT",
|
|
7
15
|
"author": {
|
|
8
|
-
"name": "
|
|
16
|
+
"name": "\u0130lker Balc\u0131lar",
|
|
9
17
|
"email": "ilkerbalcilartr@gmail.com"
|
|
10
18
|
},
|
|
11
19
|
"repository": {
|
|
@@ -27,11 +35,22 @@
|
|
|
27
35
|
}
|
|
28
36
|
],
|
|
29
37
|
"type": "module",
|
|
30
|
-
"engines": {
|
|
31
|
-
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=20"
|
|
40
|
+
},
|
|
41
|
+
"bin": {
|
|
42
|
+
"standup": "./dist/cli.js"
|
|
43
|
+
},
|
|
32
44
|
"main": "./dist/index.js",
|
|
33
45
|
"types": "./dist/index.d.ts",
|
|
34
|
-
"files": [
|
|
46
|
+
"files": [
|
|
47
|
+
"dist",
|
|
48
|
+
"skills",
|
|
49
|
+
"mcp/README.md",
|
|
50
|
+
"README.md",
|
|
51
|
+
"CHANGELOG.md",
|
|
52
|
+
"LICENSE"
|
|
53
|
+
],
|
|
35
54
|
"scripts": {
|
|
36
55
|
"build": "tsup",
|
|
37
56
|
"test": "bun test",
|
|
@@ -39,17 +58,13 @@
|
|
|
39
58
|
"typecheck": "tsc --noEmit",
|
|
40
59
|
"prepublishOnly": "tsup"
|
|
41
60
|
},
|
|
61
|
+
"dependencies": {
|
|
62
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
63
|
+
},
|
|
42
64
|
"devDependencies": {
|
|
43
|
-
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
44
65
|
"@types/bun": "^1.0.0",
|
|
45
66
|
"@types/node": "^22.0.0",
|
|
46
67
|
"tsup": "^8.0.0",
|
|
47
68
|
"typescript": "^5.5.0"
|
|
48
|
-
},
|
|
49
|
-
"peerDependencies": {
|
|
50
|
-
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
51
|
-
},
|
|
52
|
-
"peerDependenciesMeta": {
|
|
53
|
-
"@modelcontextprotocol/sdk": { "optional": true }
|
|
54
69
|
}
|
|
55
70
|
}
|
package/skills/standup/SKILL.md
CHANGED
|
@@ -19,22 +19,43 @@ Not a commit log — what finished, what is waiting, what is stuck.
|
|
|
19
19
|
npx standup-mr fetch
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
Prints one JSON document.
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
Prints one JSON document. Nothing else needs running: the command resolves
|
|
23
|
+
the host and token, works out which day to report on, and reads failed job
|
|
24
|
+
logs itself.
|
|
25
|
+
|
|
26
|
+
**Know the provider before the first call, don't discover it from a failure.**
|
|
27
|
+
If the user has named GitHub or GitLab, or it is otherwise obvious from
|
|
28
|
+
context, pass it on the very first invocation:
|
|
25
29
|
|
|
26
30
|
```bash
|
|
27
31
|
npx standup-mr fetch --provider github
|
|
28
32
|
npx standup-mr fetch --provider gitlab
|
|
29
33
|
```
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
which
|
|
35
|
+
If it is not known, do not guess. The command resolves it itself, in order:
|
|
36
|
+
`--provider` → a recognisable `--host` → `STANDUP_PROVIDER` → the
|
|
37
|
+
`GITHUB_*`/`GITLAB_*` env pair → whichever of `gh`/`glab` is logged in → an
|
|
38
|
+
error naming what it found. On a machine where both `gh` and `glab` are
|
|
39
|
+
authenticated, that resolution is ambiguous and the bare call fails with
|
|
40
|
+
`Both gh and glab are authenticated. Pass --provider github or --provider
|
|
41
|
+
gitlab.` — if you hit that, ask the user which one they mean rather than
|
|
42
|
+
picking one silently, unless the conversation already makes it obvious, in
|
|
43
|
+
which case pass that provider and say so in the note.
|
|
44
|
+
|
|
45
|
+
If the command exits non-zero for any other reason, relay its stderr verbatim
|
|
46
|
+
— do not invent a cause. The usual fix is `gh auth login` or `glab auth
|
|
47
|
+
login`, depending on which provider it was trying to reach.
|
|
48
|
+
|
|
49
|
+
**Pass `--lang` to match the language the user is speaking** — `--lang tr`
|
|
50
|
+
for Turkish. It only affects the date labels inside the JSON (`"label":
|
|
51
|
+
"Friday, 28 August"` → `"Cuma, 28 Ağustos"`); the prose of the note is always
|
|
52
|
+
your own work, in the user's language, regardless of this flag. Passing it
|
|
53
|
+
matters because the payload is otherwise ~1000 lines of English labels
|
|
54
|
+
fighting a note you're trying to write in another language. Today `--lang`
|
|
55
|
+
supports only `en` (default) and `tr` — any other value silently falls back
|
|
56
|
+
to English labels. If the user speaks a language `--lang` doesn't cover,
|
|
57
|
+
still write the note in their language; just leave the date labels in
|
|
58
|
+
English rather than passing a value that won't take effect.
|
|
38
59
|
|
|
39
60
|
## 2. Shape of the JSON
|
|
40
61
|
|
|
@@ -57,8 +78,12 @@ under its own `label`, never merged into a single "yesterday".
|
|
|
57
78
|
|
|
58
79
|
## 3. Write the note
|
|
59
80
|
|
|
60
|
-
|
|
61
|
-
|
|
81
|
+
**Write in the language the user is speaking, not the language of the JSON.**
|
|
82
|
+
The payload's labels and field names are English regardless of `--lang`
|
|
83
|
+
coverage — that is source data, not a cue for what language to write in.
|
|
84
|
+
|
|
85
|
+
Three sections: **Previous day · Today · Blockers**. Short, phrased the way
|
|
86
|
+
the user would say it out loud.
|
|
62
87
|
|
|
63
88
|
### Previous day
|
|
64
89
|
|