@craftsamo/github-tools 0.6.1 → 0.7.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/.antigravity-plugin/plugin.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +3 -0
- package/dist/cli.js +194 -72
- package/dist/mcp.js +195 -73
- package/dist/opencode.js +194 -72
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/plugin.yaml +1 -1
- package/skills/github-projects/SKILL.md +16 -1
package/dist/mcp.js
CHANGED
|
@@ -29830,7 +29830,7 @@ function issueFieldValues(connection) {
|
|
|
29830
29830
|
}
|
|
29831
29831
|
var SCHEMA_ERROR_PATTERNS = [
|
|
29832
29832
|
/issueFieldValues.*(?:doesn['’]t exist on type|is not defined on type).*['"`]?Issue['"`]?/i,
|
|
29833
|
-
/issueFields.*(?:doesn['’]t exist on type|is not defined on type).*['"`]?Repository['"`]?/i,
|
|
29833
|
+
/issueFields.*(?:doesn['’]t exist on type|is not defined on type).*['"`]?(?:Repository|Organization)['"`]?/i,
|
|
29834
29834
|
/(?:isIssueField|issueField).*(?:doesn['’]t exist on type|is not defined on type).*['"`]?ProjectV2/i,
|
|
29835
29835
|
/(?:No such type\s+['"`]?(?:ProjectV2ItemIssueFieldValue|ProjectV2IssueFieldValues)['"`]?|(?:ProjectV2ItemIssueFieldValue|ProjectV2IssueFieldValues).*(?:doesn['’]t exist|is not defined))/i
|
|
29836
29836
|
];
|
|
@@ -29849,7 +29849,9 @@ function isIssueFieldsMissingError(error62) {
|
|
|
29849
29849
|
var issueFieldInputSchema = issueFieldValuesSchema;
|
|
29850
29850
|
var ISSUE_FIELDS_ARGUMENT = `The organization's issue fields to set, by field name (without regard to case): {"Priority": "High", "Target date": "2026-12-01"}. Each takes a text, a number, a date as YYYY-MM-DD, an option name, or a list of option names for a multi-select field.`;
|
|
29851
29851
|
var MAX_ISSUE_FIELDS = 25;
|
|
29852
|
-
var
|
|
29852
|
+
var DEFINITION_SELECTION = "__typename ... on IssueFieldCommon{name dataType} ... on IssueFieldText{id} ... on IssueFieldNumber{id} ... on IssueFieldDate{id} ... on IssueFieldSingleSelect{id options{id name}} ... on IssueFieldMultiSelect{id options{id name}}";
|
|
29853
|
+
var DEFINITIONS_QUERY = `query($owner:String!,$name:String!){repository(owner:$owner,name:$name){issueFields(first:${MAX_ISSUE_FIELDS}){nodes{${DEFINITION_SELECTION}}}}}`;
|
|
29854
|
+
var ORGANIZATION_DEFINITIONS_QUERY = `query($login:String!){repositoryOwner(login:$login){__typename ... on Organization{issueFields(first:${MAX_ISSUE_FIELDS}){nodes{${DEFINITION_SELECTION}}}}}}`;
|
|
29853
29855
|
var VALUES_QUERY = `query($id:ID!){node(id:$id){... on Issue{${ISSUE_FIELD_VALUES_FRAGMENT}}}}`;
|
|
29854
29856
|
var issueFieldTypes = {
|
|
29855
29857
|
TEXT: "text",
|
|
@@ -29885,6 +29887,20 @@ async function readIssueFieldDefinitions(repo, ctx) {
|
|
|
29885
29887
|
}
|
|
29886
29888
|
return (data?.repository?.issueFields?.nodes ?? []).flatMap((raw) => definitionOf(raw) ?? []);
|
|
29887
29889
|
}
|
|
29890
|
+
async function readOrganizationIssueFields(login, ctx) {
|
|
29891
|
+
let data;
|
|
29892
|
+
try {
|
|
29893
|
+
data = await graphql(ORGANIZATION_DEFINITIONS_QUERY, { login }, ctx);
|
|
29894
|
+
} catch (error62) {
|
|
29895
|
+
if (isIssueFieldsMissingError(error62)) return null;
|
|
29896
|
+
throw error62;
|
|
29897
|
+
}
|
|
29898
|
+
if (data?.repositoryOwner?.__typename !== "Organization") return null;
|
|
29899
|
+
return (data.repositoryOwner.issueFields?.nodes ?? []).flatMap((raw) => definitionOf(raw) ?? []);
|
|
29900
|
+
}
|
|
29901
|
+
function findIssueField(definitions, name) {
|
|
29902
|
+
return definitions.find((candidate) => sameTitle(candidate.name, name));
|
|
29903
|
+
}
|
|
29888
29904
|
function invalid4(message) {
|
|
29889
29905
|
return new ToolError("invalid_argument", message);
|
|
29890
29906
|
}
|
|
@@ -29892,7 +29908,7 @@ function fieldNames(definitions) {
|
|
|
29892
29908
|
return listOf(definitions.map((field) => field.name));
|
|
29893
29909
|
}
|
|
29894
29910
|
function fieldOf(repo, definitions, name) {
|
|
29895
|
-
const field = definitions
|
|
29911
|
+
const field = findIssueField(definitions, name);
|
|
29896
29912
|
if (!field) throw invalid4(`${repo.full} has no issue field "${name}". Fields: ${fieldNames(definitions)}.`);
|
|
29897
29913
|
return field;
|
|
29898
29914
|
}
|
|
@@ -30938,6 +30954,7 @@ var STATUS_FIELD = "Status";
|
|
|
30938
30954
|
var FIELD_REPLY = `projectV2Field{${FIELD_SELECTION}}`;
|
|
30939
30955
|
var createFieldMutation = (type, options) => `mutation($project:ID!,$name:String!){createProjectV2Field(input:{projectId:$project,dataType:${type.toUpperCase()},name:$name${options}}){${FIELD_REPLY}}}`;
|
|
30940
30956
|
var updateOptionsMutation = (options) => `mutation($field:ID!){updateProjectV2Field(input:{fieldId:$field,singleSelectOptions:${options}}){${FIELD_REPLY}}}`;
|
|
30957
|
+
var createIssueFieldColumnMutation = `mutation($project:ID!,$field:ID!){createProjectV2IssueField(input:{projectId:$project,issueFieldId:$field}){projectV2Field{${READ_FIELD_SELECTION}}}}`;
|
|
30941
30958
|
function invalid7(message) {
|
|
30942
30959
|
return new ToolError("invalid_argument", message);
|
|
30943
30960
|
}
|
|
@@ -30950,6 +30967,29 @@ function fieldRequest(name, type, options) {
|
|
|
30950
30967
|
}
|
|
30951
30968
|
return { name: trimmed, type, options: parsed };
|
|
30952
30969
|
}
|
|
30970
|
+
function issueFieldColumnRequest(name, type) {
|
|
30971
|
+
const trimmed = name.trim();
|
|
30972
|
+
if (!trimmed) throw invalid7("name cannot be blank.");
|
|
30973
|
+
return { name: trimmed, type };
|
|
30974
|
+
}
|
|
30975
|
+
async function readOwnerIssueFields(owner, ctx) {
|
|
30976
|
+
return owner.owner_type === "organization" ? readOrganizationIssueFields(owner.owner, ctx) : null;
|
|
30977
|
+
}
|
|
30978
|
+
function requireIssueField(owner, definitions, request2) {
|
|
30979
|
+
if (owner.owner_type !== "organization") {
|
|
30980
|
+
throw invalid7(`Issue fields belong to an organization; ${owner.owner} is a user.`);
|
|
30981
|
+
}
|
|
30982
|
+
if (!definitions) throw invalid7("This GitHub has no issue fields.");
|
|
30983
|
+
const definition = findIssueField(definitions, request2.name);
|
|
30984
|
+
if (!definition) {
|
|
30985
|
+
const names = listOf(definitions.map((field) => field.name));
|
|
30986
|
+
throw invalid7(`${owner.owner} has no issue field "${request2.name}". Issue fields: ${names}.`);
|
|
30987
|
+
}
|
|
30988
|
+
if (request2.type && request2.type !== definition.type) {
|
|
30989
|
+
throw invalid7(`"${definition.name}" is ${definition.type}, not ${request2.type}.`);
|
|
30990
|
+
}
|
|
30991
|
+
return definition;
|
|
30992
|
+
}
|
|
30953
30993
|
function optionsLiteral(options) {
|
|
30954
30994
|
const items = options.map((option) => {
|
|
30955
30995
|
if (!OPTION_COLORS.some((color) => color === option.color)) {
|
|
@@ -31007,6 +31047,23 @@ async function ensureField(board, fields, request2, policy, ctx) {
|
|
|
31007
31047
|
const field = fieldOf2(data?.updateProjectV2Field ?? null, existing.name);
|
|
31008
31048
|
return { field, created: false, added_options: merge2.added, updated_options: merge2.updated };
|
|
31009
31049
|
}
|
|
31050
|
+
async function ensureIssueFieldColumn(board, fields, definitions, request2, ctx) {
|
|
31051
|
+
const definition = requireIssueField(board, definitions, request2);
|
|
31052
|
+
const existing = fields.find((field2) => sameTitle(field2.name, definition.name));
|
|
31053
|
+
if (existing?.issue_field) return { field: existing, created: false, added_options: [], updated_options: [] };
|
|
31054
|
+
if (existing) {
|
|
31055
|
+
throw invalid7(
|
|
31056
|
+
`The board has its own field "${existing.name}"; an issue field column cannot take the same name. Rename or delete the board's field in the web UI, or use the board's field.`
|
|
31057
|
+
);
|
|
31058
|
+
}
|
|
31059
|
+
const data = await graphql(
|
|
31060
|
+
createIssueFieldColumnMutation,
|
|
31061
|
+
{ project: board.id, field: definition.id },
|
|
31062
|
+
ctx
|
|
31063
|
+
);
|
|
31064
|
+
const field = fieldOf2(data?.createProjectV2IssueField ?? null, definition.name);
|
|
31065
|
+
return { field, created: true, added_options: [], updated_options: [] };
|
|
31066
|
+
}
|
|
31010
31067
|
|
|
31011
31068
|
// src/core/projects/support.ts
|
|
31012
31069
|
var BOARD_SELECTION = {
|
|
@@ -31030,60 +31087,65 @@ function boardSummary(board) {
|
|
|
31030
31087
|
// src/core/projects/template.ts
|
|
31031
31088
|
var STATUS_TODO = "Todo";
|
|
31032
31089
|
var STATUS_WAITING = "Waiting";
|
|
31033
|
-
var
|
|
31034
|
-
var
|
|
31035
|
-
var
|
|
31090
|
+
var DATE_MODES = ["board", "issue_fields"];
|
|
31091
|
+
var BOARD_DATE_FIELDS = { start: "Start", target: "Target" };
|
|
31092
|
+
var ISSUE_DATE_FIELDS = { start: "Start date", target: "Target date" };
|
|
31036
31093
|
var DEFAULT_VIEW_NAME = "View 1";
|
|
31037
|
-
|
|
31038
|
-
|
|
31039
|
-
|
|
31040
|
-
|
|
31041
|
-
|
|
31042
|
-
|
|
31043
|
-
|
|
31044
|
-
|
|
31094
|
+
function roadmapNote(dates) {
|
|
31095
|
+
return `Set the Roadmap view's date fields to ${dates.start} and ${dates.target} in the web UI; the API cannot set them.`;
|
|
31096
|
+
}
|
|
31097
|
+
var ROADMAP_NOTE = roadmapNote(BOARD_DATE_FIELDS);
|
|
31098
|
+
var STATUS_REQUEST = {
|
|
31099
|
+
name: STATUS_FIELD,
|
|
31100
|
+
type: "single_select",
|
|
31101
|
+
options: [
|
|
31102
|
+
{ name: STATUS_TODO, color: "BLUE", description: "Ready to start; nothing is in the way." },
|
|
31103
|
+
{ name: "In Progress", color: "YELLOW", description: "Being worked on now." },
|
|
31104
|
+
{
|
|
31105
|
+
name: STATUS_WAITING,
|
|
31106
|
+
color: "GRAY",
|
|
31107
|
+
description: "Cannot move until something else clears: an open blocking issue, a review or a reply."
|
|
31108
|
+
},
|
|
31109
|
+
{ name: "Done", color: "PURPLE", description: "Finished." },
|
|
31110
|
+
{ name: "Cancelled", color: "RED", description: "Will not be done; kept for the record." }
|
|
31111
|
+
]
|
|
31112
|
+
};
|
|
31113
|
+
function standardTemplate(dates) {
|
|
31114
|
+
const notDone = "-status:Done -status:Cancelled";
|
|
31115
|
+
return {
|
|
31116
|
+
roadmapNote: roadmapNote(dates),
|
|
31117
|
+
views: [
|
|
31118
|
+
{ name: "Roadmap", layout: "roadmap", filter: "-status:Cancelled", sort_by: dates.start },
|
|
31045
31119
|
{
|
|
31046
|
-
name:
|
|
31047
|
-
|
|
31048
|
-
|
|
31120
|
+
name: "Kanban",
|
|
31121
|
+
layout: "board",
|
|
31122
|
+
filter: notDone,
|
|
31123
|
+
column_by: STATUS_FIELD,
|
|
31124
|
+
fields: ["Title", "Assignees", "Repository", "Parent issue", dates.target],
|
|
31125
|
+
sort_by: dates.target
|
|
31049
31126
|
},
|
|
31050
|
-
{
|
|
31051
|
-
|
|
31127
|
+
{
|
|
31128
|
+
name: "Backlog",
|
|
31129
|
+
layout: "table",
|
|
31130
|
+
filter: notDone,
|
|
31131
|
+
fields: [
|
|
31132
|
+
"Title",
|
|
31133
|
+
STATUS_FIELD,
|
|
31134
|
+
"Assignees",
|
|
31135
|
+
"Repository",
|
|
31136
|
+
"Milestone",
|
|
31137
|
+
"Parent issue",
|
|
31138
|
+
"Sub-issues progress",
|
|
31139
|
+
dates.start,
|
|
31140
|
+
dates.target,
|
|
31141
|
+
"Linked pull requests"
|
|
31142
|
+
],
|
|
31143
|
+
group_by: STATUS_FIELD,
|
|
31144
|
+
sort_by: dates.target
|
|
31145
|
+
}
|
|
31052
31146
|
]
|
|
31053
|
-
}
|
|
31054
|
-
|
|
31055
|
-
{ name: TARGET_FIELD, type: "date", options: [] }
|
|
31056
|
-
];
|
|
31057
|
-
var STANDARD_VIEWS = [
|
|
31058
|
-
{ name: "Roadmap", layout: "roadmap", filter: "-status:Cancelled", sort_by: START_FIELD },
|
|
31059
|
-
{
|
|
31060
|
-
name: "Kanban",
|
|
31061
|
-
layout: "board",
|
|
31062
|
-
filter: NOT_DONE,
|
|
31063
|
-
column_by: STATUS_FIELD,
|
|
31064
|
-
fields: ["Title", "Assignees", "Repository", "Parent issue", TARGET_FIELD],
|
|
31065
|
-
sort_by: TARGET_FIELD
|
|
31066
|
-
},
|
|
31067
|
-
{
|
|
31068
|
-
name: "Backlog",
|
|
31069
|
-
layout: "table",
|
|
31070
|
-
filter: NOT_DONE,
|
|
31071
|
-
fields: [
|
|
31072
|
-
"Title",
|
|
31073
|
-
STATUS_FIELD,
|
|
31074
|
-
"Assignees",
|
|
31075
|
-
"Repository",
|
|
31076
|
-
"Milestone",
|
|
31077
|
-
"Parent issue",
|
|
31078
|
-
"Sub-issues progress",
|
|
31079
|
-
START_FIELD,
|
|
31080
|
-
TARGET_FIELD,
|
|
31081
|
-
"Linked pull requests"
|
|
31082
|
-
],
|
|
31083
|
-
group_by: STATUS_FIELD,
|
|
31084
|
-
sort_by: TARGET_FIELD
|
|
31085
|
-
}
|
|
31086
|
-
];
|
|
31147
|
+
};
|
|
31148
|
+
}
|
|
31087
31149
|
|
|
31088
31150
|
// src/core/projects/item-support.ts
|
|
31089
31151
|
var ITEM_BOARD_SELECTION = {
|
|
@@ -32318,6 +32380,9 @@ var input10 = external_exports.object({
|
|
|
32318
32380
|
"A board to copy, without its draft items, when the board has to be made: its number, owner/number or URL (a bare number or a title is looked up among owner's boards)."
|
|
32319
32381
|
),
|
|
32320
32382
|
standard: external_exports.boolean().optional().describe("Bring the board to the standard template: its fields and views (default true)."),
|
|
32383
|
+
dates: external_exports.enum(DATE_MODES).optional().describe(
|
|
32384
|
+
`"board" (default) makes the board's own date fields Start and Target; "issue_fields" uses the organization's issue fields Start date and Target date instead, so an issue carries the same dates on every board and they are set with the issue tools (a pull request or draft has none). Organization boards only.`
|
|
32385
|
+
),
|
|
32321
32386
|
link_repo: external_exports.string().optional().describe("owner/name of a repository to link the board to; needs write permission.")
|
|
32322
32387
|
});
|
|
32323
32388
|
var output10 = external_exports.object({
|
|
@@ -32349,23 +32414,41 @@ function openBoardTitled(boards, title) {
|
|
|
32349
32414
|
}
|
|
32350
32415
|
return matches[0];
|
|
32351
32416
|
}
|
|
32352
|
-
async function applyFields(board, fresh, report, ctx) {
|
|
32417
|
+
async function applyFields(board, fresh, mode, dates, definitions, report, ctx) {
|
|
32353
32418
|
const fields = await readBoardFields(board.id, ctx);
|
|
32354
|
-
|
|
32355
|
-
|
|
32356
|
-
|
|
32357
|
-
|
|
32358
|
-
|
|
32359
|
-
|
|
32360
|
-
|
|
32361
|
-
|
|
32362
|
-
|
|
32419
|
+
const status = await ensureField(board, fields, STATUS_REQUEST, fresh ? "replace" : "append", ctx);
|
|
32420
|
+
report.push({
|
|
32421
|
+
field: status.field.name,
|
|
32422
|
+
created: status.created,
|
|
32423
|
+
added_options: status.added_options,
|
|
32424
|
+
updated_options: status.updated_options
|
|
32425
|
+
});
|
|
32426
|
+
if (mode === "issue_fields") {
|
|
32427
|
+
for (const name of [dates.start, dates.target]) {
|
|
32428
|
+
const outcome = await ensureIssueFieldColumn(board, fields, definitions, { name, type: "date" }, ctx);
|
|
32429
|
+
report.push({
|
|
32430
|
+
field: outcome.field.name,
|
|
32431
|
+
created: outcome.created,
|
|
32432
|
+
added_options: outcome.added_options,
|
|
32433
|
+
updated_options: outcome.updated_options
|
|
32434
|
+
});
|
|
32435
|
+
}
|
|
32436
|
+
} else {
|
|
32437
|
+
for (const name of [dates.start, dates.target]) {
|
|
32438
|
+
const outcome = await ensureField(board, fields, { name, type: "date", options: [] }, "append", ctx);
|
|
32439
|
+
report.push({
|
|
32440
|
+
field: outcome.field.name,
|
|
32441
|
+
created: outcome.created,
|
|
32442
|
+
added_options: outcome.added_options,
|
|
32443
|
+
updated_options: outcome.updated_options
|
|
32444
|
+
});
|
|
32445
|
+
}
|
|
32363
32446
|
}
|
|
32364
32447
|
}
|
|
32365
|
-
async function applyViews(board, report, notes, ctx) {
|
|
32448
|
+
async function applyViews(board, templateViews, roadmapNote2, report, notes, ctx) {
|
|
32366
32449
|
const before = await readBoardViewNodes(board.id, ctx);
|
|
32367
32450
|
const readers = viewFieldReaders(board, ctx);
|
|
32368
|
-
for (const request2 of
|
|
32451
|
+
for (const request2 of templateViews) {
|
|
32369
32452
|
if (before.some((view5) => sameTitle(view5.name, request2.name))) {
|
|
32370
32453
|
report.push({ view: request2.name, created: false });
|
|
32371
32454
|
continue;
|
|
@@ -32377,7 +32460,7 @@ async function applyViews(board, report, notes, ctx) {
|
|
|
32377
32460
|
throw error62;
|
|
32378
32461
|
}
|
|
32379
32462
|
report.push({ view: request2.name, created: true });
|
|
32380
|
-
if (request2.layout === "roadmap") notes.push(
|
|
32463
|
+
if (request2.layout === "roadmap") notes.push(roadmapNote2);
|
|
32381
32464
|
}
|
|
32382
32465
|
return before;
|
|
32383
32466
|
}
|
|
@@ -32387,6 +32470,7 @@ var projectCreate = defineTool({
|
|
|
32387
32470
|
description: [
|
|
32388
32471
|
`Create a project board for a user or organization, or reuse the open board of that owner and exact title (case-insensitive; several are invalid_argument), and bring it to the standard template. The title defaults to ${DEFAULT_BOARD_TITLE}. A board that has to be made is empty, or a copy of template without its draft items.`,
|
|
32389
32472
|
"With standard (the default): the fields Status (Todo, In Progress, Waiting, Done, Cancelled, each with a color and a description), Start and Target (dates), and the views Roadmap, Kanban and Backlog. On a board this call made, Status gets exactly those options, keeping the ids of GitHub's own Todo, In Progress and Done, and GitHub's default view View 1 is deleted once the three views exist. On a reused or copied board only the missing fields, options and views are added, and nothing is deleted. A reused board must be one the viewer may update.",
|
|
32473
|
+
`dates: "issue_fields" uses the organization's issue fields Start date and Target date as the board's dates, refused before the board is made when the owner is a user or lacks them.`,
|
|
32390
32474
|
"link_repo links the board to a repository (needs write permission there) unless it is already linked. GitHub links only boards of the repository's own owner, so a repository of another owner is invalid_argument, before the board is made.",
|
|
32391
32475
|
"Once the board exists, a failed step does not fail the call: it is listed in errors and the board is still returned.",
|
|
32392
32476
|
`notes lists what the API cannot do, such as setting the Roadmap view's date fields. ${PROJECT_SCOPE_NOTE}`
|
|
@@ -32412,6 +32496,23 @@ var projectCreate = defineTool({
|
|
|
32412
32496
|
linkRepo = await writableContext(repo, ctx);
|
|
32413
32497
|
}
|
|
32414
32498
|
const owner = await readBoardOwner(login, ctx);
|
|
32499
|
+
const dateMode = args.dates ?? "board";
|
|
32500
|
+
let dateNames = BOARD_DATE_FIELDS;
|
|
32501
|
+
let definitions = null;
|
|
32502
|
+
if (dateMode === "issue_fields") {
|
|
32503
|
+
if (!standard) throw invalid5("dates applies only with standard.");
|
|
32504
|
+
definitions = await readOwnerIssueFields({ owner: owner.login, owner_type: owner.type }, ctx);
|
|
32505
|
+
const startDef = requireIssueField({ owner: owner.login, owner_type: owner.type }, definitions, {
|
|
32506
|
+
name: ISSUE_DATE_FIELDS.start,
|
|
32507
|
+
type: "date"
|
|
32508
|
+
});
|
|
32509
|
+
const targetDef = requireIssueField({ owner: owner.login, owner_type: owner.type }, definitions, {
|
|
32510
|
+
name: ISSUE_DATE_FIELDS.target,
|
|
32511
|
+
type: "date"
|
|
32512
|
+
});
|
|
32513
|
+
dateNames = { start: startDef.name, target: targetDef.name };
|
|
32514
|
+
}
|
|
32515
|
+
const template = standardTemplate(dateNames);
|
|
32415
32516
|
const reused = openBoardTitled((await ownerBoards(owner.login, ctx, owner.type)).boards, title);
|
|
32416
32517
|
if (reused) assertBoardWritable(reused);
|
|
32417
32518
|
const source = reused || !templateRef ? void 0 : (await resolveBoard({ project: templateRef, owner: ownerArg }, ctx)).project;
|
|
@@ -32424,8 +32525,11 @@ var projectCreate = defineTool({
|
|
|
32424
32525
|
const notes = [];
|
|
32425
32526
|
let deletedDefaultView = false;
|
|
32426
32527
|
if (standard) {
|
|
32427
|
-
await steps.record("fields", () => applyFields(board, fresh, fields, ctx));
|
|
32428
|
-
const before = await steps.record(
|
|
32528
|
+
await steps.record("fields", () => applyFields(board, fresh, dateMode, dateNames, definitions, fields, ctx));
|
|
32529
|
+
const before = await steps.record(
|
|
32530
|
+
"views",
|
|
32531
|
+
() => applyViews(board, template.views, template.roadmapNote, views, notes, ctx)
|
|
32532
|
+
);
|
|
32429
32533
|
const defaultView = fresh ? before?.find((view5) => view5.name === DEFAULT_VIEW_NAME) : void 0;
|
|
32430
32534
|
if (defaultView) {
|
|
32431
32535
|
deletedDefaultView = await steps.record("default_view", async () => {
|
|
@@ -32456,9 +32560,14 @@ var projectCreate = defineTool({
|
|
|
32456
32560
|
var input11 = external_exports.object({
|
|
32457
32561
|
...BOARD_SELECTION,
|
|
32458
32562
|
name: external_exports.string().describe("The field's name, matched without regard to case."),
|
|
32459
|
-
type: external_exports.enum(FIELD_TYPES).describe(
|
|
32563
|
+
type: external_exports.enum(FIELD_TYPES).optional().describe(
|
|
32564
|
+
"The field's type; a field of that name with another type is invalid_argument. Required unless issue_field is true, where it only checks the issue field's type."
|
|
32565
|
+
),
|
|
32460
32566
|
options: external_exports.array(external_exports.string()).optional().describe(
|
|
32461
|
-
`single_select only: Name, Name:COLOR or Name:COLOR:Description (the description is everything after the second colon). COLOR is one of ${OPTION_COLORS.join(", ")}, in any case; the default is GRAY.`
|
|
32567
|
+
`single_select only, not with issue_field: Name, Name:COLOR or Name:COLOR:Description (the description is everything after the second colon). COLOR is one of ${OPTION_COLORS.join(", ")}, in any case; the default is GRAY.`
|
|
32568
|
+
),
|
|
32569
|
+
issue_field: external_exports.boolean().optional().describe(
|
|
32570
|
+
"Add a column that mirrors the organization's issue field of that name instead of a field of the board's own; its options and values are the organization's and the issue's."
|
|
32462
32571
|
)
|
|
32463
32572
|
});
|
|
32464
32573
|
var output11 = external_exports.object({
|
|
@@ -32467,12 +32576,25 @@ var output11 = external_exports.object({
|
|
|
32467
32576
|
created: external_exports.boolean().describe("Whether this call made the field."),
|
|
32468
32577
|
added_options: external_exports.array(external_exports.string()).describe("The names of the options this call added; [] when none.")
|
|
32469
32578
|
});
|
|
32579
|
+
function planEnsure(args) {
|
|
32580
|
+
if (args.issue_field) {
|
|
32581
|
+
if (args.options && args.options.length > 0) {
|
|
32582
|
+
throw new ToolError("invalid_argument", "options are the organization's with issue_field; leave them out.");
|
|
32583
|
+
}
|
|
32584
|
+
const request3 = issueFieldColumnRequest(args.name, args.type);
|
|
32585
|
+
return async (board, fields, ctx) => ensureIssueFieldColumn(board, fields, await readOwnerIssueFields(board, ctx), request3, ctx);
|
|
32586
|
+
}
|
|
32587
|
+
if (!args.type) throw new ToolError("invalid_argument", "type is required unless issue_field is true.");
|
|
32588
|
+
const request2 = fieldRequest(args.name, args.type, args.options);
|
|
32589
|
+
return (board, fields, ctx) => ensureField(board, fields, request2, "append", ctx);
|
|
32590
|
+
}
|
|
32470
32591
|
var projectFieldEnsure = defineTool({
|
|
32471
32592
|
id: "github_project_field_ensure",
|
|
32472
32593
|
title: "Ensure a GitHub project field",
|
|
32473
32594
|
description: [
|
|
32474
32595
|
"Make sure a field exists on a project board the viewer may update, without ever making a second one: a missing field is created, and the missing options of an existing single select are appended after its own, which keep their id, name, color, description and order, so nothing already set moves.",
|
|
32475
32596
|
"A new single_select field needs options. Status can be extended but not created. A field of that name with another type, options on a field that is not single_select, a repeated option name and a color GitHub does not list are invalid_argument, before anything is written.",
|
|
32597
|
+
"With issue_field: true (organization boards only) the column mirrors the organization's issue field of that name, such as Priority, Start date or Target date; it is added when the board lacks it, and a field of the board's own with that name is invalid_argument.",
|
|
32476
32598
|
BOARD_LOOKUP_NOTE,
|
|
32477
32599
|
PROJECT_SCOPE_NOTE
|
|
32478
32600
|
].join(" "),
|
|
@@ -32482,11 +32604,11 @@ var projectFieldEnsure = defineTool({
|
|
|
32482
32604
|
input: input11,
|
|
32483
32605
|
output: output11,
|
|
32484
32606
|
async execute(args, ctx) {
|
|
32485
|
-
const
|
|
32607
|
+
const ensure = planEnsure(args);
|
|
32486
32608
|
const { project } = await resolveBoard(args, ctx);
|
|
32487
32609
|
assertBoardWritable(project);
|
|
32488
32610
|
const fields = await readBoardFields(project.id, ctx);
|
|
32489
|
-
const { field, created, added_options } = await
|
|
32611
|
+
const { field, created, added_options } = await ensure(project, fields, ctx);
|
|
32490
32612
|
return { project: boardSummary(project), field, created, added_options };
|
|
32491
32613
|
}
|
|
32492
32614
|
});
|
|
@@ -37967,7 +38089,7 @@ async function main() {
|
|
|
37967
38089
|
const settings = parseSettings(process.argv.slice(2), process.env);
|
|
37968
38090
|
server = createServer(ALL_TOOLS, settings, {
|
|
37969
38091
|
ownDir: packageRoot(import.meta.url),
|
|
37970
|
-
version: true ? "0.
|
|
38092
|
+
version: true ? "0.7.0" : void 0
|
|
37971
38093
|
});
|
|
37972
38094
|
} catch (error62) {
|
|
37973
38095
|
if (!isToolError(error62)) throw error62;
|