feat: «Mi día», the few tickets I pick for today
A home panel with the tickets picked for today (10 at most), crossed out
as they get done and counted («1 de 3 terminados»), my open tickets to
add with one click, and what was left unfinished on my last day to carry
over. «☀ Mi día» on a ticket adds it or takes it out. The day is the
person's own (YYYY-MM-DD from the browser); private, no history (Mongo
`my_days`).
API: myDay(day), addToMyDay, removeFromMyDay; GET /api/me/day,
PUT/DELETE /api/me/day/{issue}. MCP: my_day.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2776,6 +2776,294 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/me/day": {
|
||||
"get": {
|
||||
"description": "And what was left unfinished on my latest earlier day.",
|
||||
"operationId": "IssuesController_myDay",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "day",
|
||||
"required": true,
|
||||
"in": "query",
|
||||
"description": "Today, in my time zone",
|
||||
"schema": {
|
||||
"example": "2026-10-20",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/MyDayDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid input",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Missing or rejected Pireon token",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Not a member of the project (or not allowed)",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"pireon-oauth": []
|
||||
},
|
||||
{
|
||||
"pireon": []
|
||||
}
|
||||
],
|
||||
"summary": "«Mi día»: the tickets I picked for today",
|
||||
"tags": [
|
||||
"Issues"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/me/day/{issue}": {
|
||||
"put": {
|
||||
"operationId": "IssuesController_addToMyDay",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "issue",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"description": "Ticket id or key",
|
||||
"schema": {
|
||||
"example": "WEB-12",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "day",
|
||||
"required": true,
|
||||
"in": "query",
|
||||
"description": "Today, in my time zone",
|
||||
"schema": {
|
||||
"example": "2026-10-20",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": ""
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid input",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Missing or rejected Pireon token",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Not a member of the project (or not allowed)",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"409": {
|
||||
"description": "Someone changed it at the same time: retry",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Business rule (e.g. a transition the workflow forbids)",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"pireon-oauth": []
|
||||
},
|
||||
{
|
||||
"pireon": []
|
||||
}
|
||||
],
|
||||
"summary": "Add a ticket to «Mi día» (10 at most)",
|
||||
"tags": [
|
||||
"Issues"
|
||||
]
|
||||
},
|
||||
"delete": {
|
||||
"operationId": "IssuesController_removeFromMyDay",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "issue",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"description": "Ticket id or key",
|
||||
"schema": {
|
||||
"example": "WEB-12",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "day",
|
||||
"required": true,
|
||||
"in": "query",
|
||||
"description": "Today, in my time zone",
|
||||
"schema": {
|
||||
"example": "2026-10-20",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": ""
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid input",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Missing or rejected Pireon token",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Not a member of the project (or not allowed)",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"409": {
|
||||
"description": "Someone changed it at the same time: retry",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Business rule (e.g. a transition the workflow forbids)",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiErrorDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"pireon-oauth": []
|
||||
},
|
||||
{
|
||||
"pireon": []
|
||||
}
|
||||
],
|
||||
"summary": "Take a ticket out of «Mi día»",
|
||||
"tags": [
|
||||
"Issues"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/me/reminders": {
|
||||
"get": {
|
||||
"operationId": "IssuesController_myReminders",
|
||||
@@ -16339,6 +16627,53 @@
|
||||
"at"
|
||||
]
|
||||
},
|
||||
"MyDayLeftoverDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"day": {
|
||||
"type": "string"
|
||||
},
|
||||
"issues": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/IssueDto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"day",
|
||||
"issues"
|
||||
]
|
||||
},
|
||||
"MyDayDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"day": {
|
||||
"type": "string",
|
||||
"description": "YYYY-MM-DD, in my time zone"
|
||||
},
|
||||
"issues": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/IssueDto"
|
||||
}
|
||||
},
|
||||
"leftover": {
|
||||
"nullable": true,
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/MyDayLeftoverDto"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"day",
|
||||
"issues",
|
||||
"leftover"
|
||||
]
|
||||
},
|
||||
"IssueReminderDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -957,6 +957,9 @@ type Mutation {
|
||||
"""Add a Pireon user to the project"""
|
||||
addProjectMember(input: ProjectMemberInput!): CommandResult!
|
||||
|
||||
"""Add tickets to «Mi día» (10 at most)"""
|
||||
addToMyDay(day: String!, issueIds: [ID!]!): Boolean!
|
||||
|
||||
"""
|
||||
Archive the project (owner only): everything stays readable, nothing changes until it is unarchived
|
||||
"""
|
||||
@@ -1073,6 +1076,9 @@ type Mutation {
|
||||
removeAttachment(attachmentId: ID!, issueId: ID!): CommandResult!
|
||||
removeChecklistItem(issueId: ID!, itemId: ID!): CommandResult!
|
||||
|
||||
"""Take a ticket out of «Mi día»"""
|
||||
removeFromMyDay(day: String!, issueId: ID!): Boolean!
|
||||
|
||||
"""Remove a repository; what it linked stays on the tickets"""
|
||||
removeGitRepository(projectId: ID!, repositoryId: ID!): Boolean!
|
||||
removeProjectMember(projectId: ID!, userId: ID!): CommandResult!
|
||||
@@ -1210,6 +1216,22 @@ type Mutation {
|
||||
writeReleaseNotes(notes: String, releaseId: ID!): CommandResult!
|
||||
}
|
||||
|
||||
"""«Mi día»: the tickets I picked for today"""
|
||||
type MyDay {
|
||||
"""YYYY-MM-DD, in my time zone"""
|
||||
day: String!
|
||||
|
||||
"""In order, done ones included"""
|
||||
issues: [Issue!]!
|
||||
leftover: MyDayLeftover
|
||||
}
|
||||
|
||||
"""What was left unfinished on the latest earlier day"""
|
||||
type MyDayLeftover {
|
||||
day: String!
|
||||
issues: [Issue!]!
|
||||
}
|
||||
|
||||
type MyNotifications {
|
||||
items: [Notification!]!
|
||||
|
||||
@@ -1625,6 +1647,14 @@ type Query {
|
||||
"""My calendar URL, if I made one"""
|
||||
myCalendarFeed: CalendarFeed
|
||||
|
||||
"""
|
||||
«Mi día»: the tickets I picked for today, and what was left on my last day
|
||||
"""
|
||||
myDay(
|
||||
"""Today, YYYY-MM-DD in my time zone"""
|
||||
day: String!
|
||||
): MyDay!
|
||||
|
||||
"""
|
||||
The home page beyond my work: agenda of the week, activity of my projects, the week in numbers, sprints, project cards, suggestions, first steps and who is on what now
|
||||
"""
|
||||
|
||||
@@ -502,6 +502,44 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/me/day": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/**
|
||||
* «Mi día»: the tickets I picked for today
|
||||
* @description And what was left unfinished on my latest earlier day.
|
||||
*/
|
||||
get: operations["IssuesController_myDay"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/me/day/{issue}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
/** Add a ticket to «Mi día» (10 at most) */
|
||||
put: operations["IssuesController_addToMyDay"];
|
||||
post?: never;
|
||||
/** Take a ticket out of «Mi día» */
|
||||
delete: operations["IssuesController_removeFromMyDay"];
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/me/reminders": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -2951,6 +2989,16 @@ export interface components {
|
||||
*/
|
||||
at: string;
|
||||
};
|
||||
MyDayLeftoverDto: {
|
||||
day: string;
|
||||
issues: components["schemas"]["IssueDto"][];
|
||||
};
|
||||
MyDayDto: {
|
||||
/** @description YYYY-MM-DD, in my time zone */
|
||||
day: string;
|
||||
issues: components["schemas"]["IssueDto"][];
|
||||
leftover: components["schemas"]["MyDayLeftoverDto"] | null;
|
||||
};
|
||||
IssueReminderDto: {
|
||||
/** Format: date-time */
|
||||
at: string;
|
||||
@@ -5809,6 +5857,218 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
IssuesController_myDay: {
|
||||
parameters: {
|
||||
query: {
|
||||
/** @description Today, in my time zone */
|
||||
day: string;
|
||||
};
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["MyDayDto"];
|
||||
};
|
||||
};
|
||||
/** @description Invalid input */
|
||||
400: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ApiErrorDto"];
|
||||
};
|
||||
};
|
||||
/** @description Missing or rejected Pireon token */
|
||||
401: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ApiErrorDto"];
|
||||
};
|
||||
};
|
||||
/** @description Not a member of the project (or not allowed) */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ApiErrorDto"];
|
||||
};
|
||||
};
|
||||
/** @description Not found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ApiErrorDto"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
IssuesController_addToMyDay: {
|
||||
parameters: {
|
||||
query: {
|
||||
/** @description Today, in my time zone */
|
||||
day: string;
|
||||
};
|
||||
header?: never;
|
||||
path: {
|
||||
/** @description Ticket id or key */
|
||||
issue: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
204: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content?: never;
|
||||
};
|
||||
/** @description Invalid input */
|
||||
400: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ApiErrorDto"];
|
||||
};
|
||||
};
|
||||
/** @description Missing or rejected Pireon token */
|
||||
401: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ApiErrorDto"];
|
||||
};
|
||||
};
|
||||
/** @description Not a member of the project (or not allowed) */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ApiErrorDto"];
|
||||
};
|
||||
};
|
||||
/** @description Not found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ApiErrorDto"];
|
||||
};
|
||||
};
|
||||
/** @description Someone changed it at the same time: retry */
|
||||
409: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ApiErrorDto"];
|
||||
};
|
||||
};
|
||||
/** @description Business rule (e.g. a transition the workflow forbids) */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ApiErrorDto"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
IssuesController_removeFromMyDay: {
|
||||
parameters: {
|
||||
query: {
|
||||
/** @description Today, in my time zone */
|
||||
day: string;
|
||||
};
|
||||
header?: never;
|
||||
path: {
|
||||
/** @description Ticket id or key */
|
||||
issue: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
204: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content?: never;
|
||||
};
|
||||
/** @description Invalid input */
|
||||
400: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ApiErrorDto"];
|
||||
};
|
||||
};
|
||||
/** @description Missing or rejected Pireon token */
|
||||
401: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ApiErrorDto"];
|
||||
};
|
||||
};
|
||||
/** @description Not a member of the project (or not allowed) */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ApiErrorDto"];
|
||||
};
|
||||
};
|
||||
/** @description Not found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ApiErrorDto"];
|
||||
};
|
||||
};
|
||||
/** @description Someone changed it at the same time: retry */
|
||||
409: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ApiErrorDto"];
|
||||
};
|
||||
};
|
||||
/** @description Business rule (e.g. a transition the workflow forbids) */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ApiErrorDto"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
IssuesController_myReminders: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
||||
@@ -783,6 +783,50 @@ export class IssuesResolver {
|
||||
);
|
||||
}
|
||||
|
||||
@Tool({
|
||||
name: 'my_day',
|
||||
description:
|
||||
'«Mi día»: the tickets I picked for today (done ones marked), and what was left unfinished on my last day. Optionally add or remove one first. day is today in my time zone, YYYY-MM-DD.',
|
||||
paramsSchema: z.object({
|
||||
day: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
|
||||
add: issueRef.optional(),
|
||||
remove: issueRef.optional(),
|
||||
}),
|
||||
annotations: WRITE,
|
||||
})
|
||||
myDay(
|
||||
params: { day: string; add?: string; remove?: string },
|
||||
ctx: McpContext,
|
||||
) {
|
||||
const client = this.api.as(ctx);
|
||||
const query = { day: params.day };
|
||||
return toolResult(async () => {
|
||||
if (params.add)
|
||||
await this.api.data(
|
||||
client.PUT('/api/me/day/{issue}', {
|
||||
params: { path: { issue: params.add }, query },
|
||||
}),
|
||||
);
|
||||
if (params.remove)
|
||||
await this.api.data(
|
||||
client.DELETE('/api/me/day/{issue}', {
|
||||
params: { path: { issue: params.remove }, query },
|
||||
}),
|
||||
);
|
||||
const myDay = await this.api.data(
|
||||
client.GET('/api/me/day', { params: { query } }),
|
||||
);
|
||||
return {
|
||||
day: myDay.day,
|
||||
issues: myDay.issues.map(issueLine),
|
||||
leftover: myDay.leftover && {
|
||||
day: myDay.leftover.day,
|
||||
issues: myDay.leftover.issues.map(issueLine),
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@Tool({
|
||||
name: 'remind_me',
|
||||
description:
|
||||
|
||||
Reference in New Issue
Block a user