@craftsamo/github-tools 0.6.0 → 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 +6 -1
- package/dist/cli.js +315 -122
- package/dist/mcp.js +316 -123
- package/dist/opencode.js +315 -122
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/plugin.yaml +1 -1
- package/skills/github-projects/SKILL.md +26 -4
package/dist/mcp.js
CHANGED
|
@@ -29679,11 +29679,18 @@ function listOf(names) {
|
|
|
29679
29679
|
return names.length > 0 ? names.map((name) => `"${name}"`).join(", ") : "none";
|
|
29680
29680
|
}
|
|
29681
29681
|
function settableNames(fields) {
|
|
29682
|
-
return listOf(fields.filter((field) => isSettable(field.type)).map((field) => field.name));
|
|
29682
|
+
return listOf(fields.filter((field) => isSettable(field.type) && !field.issue_field).map((field) => field.name));
|
|
29683
29683
|
}
|
|
29684
|
-
function settableField(fields, name) {
|
|
29684
|
+
function settableField(fields, name, action = "set") {
|
|
29685
29685
|
const field = fields.find((candidate) => sameTitle(candidate.name, name));
|
|
29686
29686
|
if (!field) throw invalid3(`The board has no field "${name}". Fields that can be set: ${settableNames(fields)}.`);
|
|
29687
|
+
if (field.issue_field) {
|
|
29688
|
+
const verb = action === "clear" ? "cleared" : "set";
|
|
29689
|
+
const fix = action === "clear" ? "Clear it with clear_issue_fields in github_issue_edit." : "Set it with issue_fields in github_issue_edit or github_issue_create.";
|
|
29690
|
+
throw invalid3(
|
|
29691
|
+
`"${field.name}" mirrors the organization's issue field; its value is the issue's own and cannot be ${verb} on a board. ${fix} Fields that can be set: ${settableNames(fields)}.`
|
|
29692
|
+
);
|
|
29693
|
+
}
|
|
29687
29694
|
if (!isSettable(field.type)) {
|
|
29688
29695
|
const hint = ISSUE_FIELD_TYPES.includes(field.type) ? " github_issue_edit sets assignees, labels and milestone on the issue." : "";
|
|
29689
29696
|
throw invalid3(
|
|
@@ -29763,7 +29770,7 @@ function planValue(field, value, now) {
|
|
|
29763
29770
|
function planFieldValues(fields, values, now = /* @__PURE__ */ new Date()) {
|
|
29764
29771
|
const writes = [];
|
|
29765
29772
|
for (const [name, value] of Object.entries(values)) {
|
|
29766
|
-
const field = settableField(fields, name);
|
|
29773
|
+
const field = settableField(fields, name, "set");
|
|
29767
29774
|
if (writes.some((write) => write.field.id === field.id)) {
|
|
29768
29775
|
throw invalid3(`fields names "${field.name}" twice; field names are matched without regard to case.`);
|
|
29769
29776
|
}
|
|
@@ -29774,7 +29781,7 @@ function planFieldValues(fields, values, now = /* @__PURE__ */ new Date()) {
|
|
|
29774
29781
|
function planClears(fields, names) {
|
|
29775
29782
|
const cleared = [];
|
|
29776
29783
|
for (const name of names) {
|
|
29777
|
-
const field = settableField(fields, name);
|
|
29784
|
+
const field = settableField(fields, name, "clear");
|
|
29778
29785
|
if (!cleared.some((each) => each.id === field.id)) cleared.push(field);
|
|
29779
29786
|
}
|
|
29780
29787
|
return cleared;
|
|
@@ -29789,38 +29796,43 @@ function isHeld(write, current) {
|
|
|
29789
29796
|
|
|
29790
29797
|
// src/core/github/issue-fields.ts
|
|
29791
29798
|
var issueFieldValuesSchema = external_exports.record(external_exports.string(), external_exports.union([external_exports.string(), external_exports.number(), external_exports.array(external_exports.string())]));
|
|
29792
|
-
var
|
|
29799
|
+
var ISSUE_FIELD_VALUE_SELECTION = "__typename ... on IssueFieldTextValue{value} ... on IssueFieldNumberValue{value} ... on IssueFieldDateValue{value} ... on IssueFieldSingleSelectValue{name} ... on IssueFieldMultiSelectValue{options{name}}";
|
|
29800
|
+
var ISSUE_FIELD_VALUES_FRAGMENT = `issueFieldValues(first:25){nodes{... on IssueFieldValueCommon{field{... on IssueFieldCommon{name}}} ${ISSUE_FIELD_VALUE_SELECTION}}}`;
|
|
29801
|
+
function issueFieldValueOf(node2) {
|
|
29802
|
+
if (!node2) return void 0;
|
|
29803
|
+
switch (node2.__typename) {
|
|
29804
|
+
case "IssueFieldTextValue":
|
|
29805
|
+
return typeof node2.value === "string" ? node2.value : void 0;
|
|
29806
|
+
case "IssueFieldNumberValue":
|
|
29807
|
+
return typeof node2.value === "number" && !Number.isNaN(node2.value) ? node2.value : void 0;
|
|
29808
|
+
case "IssueFieldDateValue":
|
|
29809
|
+
return typeof node2.value === "string" ? node2.value : void 0;
|
|
29810
|
+
case "IssueFieldSingleSelectValue":
|
|
29811
|
+
return typeof node2.name === "string" ? node2.name : void 0;
|
|
29812
|
+
case "IssueFieldMultiSelectValue": {
|
|
29813
|
+
const options = (node2.options ?? []).map((opt) => opt?.name).filter((name) => typeof name === "string");
|
|
29814
|
+
return options.length > 0 ? options : void 0;
|
|
29815
|
+
}
|
|
29816
|
+
default:
|
|
29817
|
+
return void 0;
|
|
29818
|
+
}
|
|
29819
|
+
}
|
|
29793
29820
|
function issueFieldValues(connection) {
|
|
29794
29821
|
const values = {};
|
|
29795
29822
|
for (const node2 of connection?.nodes ?? []) {
|
|
29796
29823
|
if (!node2) continue;
|
|
29797
29824
|
const fieldName = node2.field?.name?.trim();
|
|
29798
29825
|
if (!fieldName) continue;
|
|
29799
|
-
|
|
29800
|
-
|
|
29801
|
-
if (typeof node2.value === "string") values[fieldName] = node2.value;
|
|
29802
|
-
break;
|
|
29803
|
-
case "IssueFieldNumberValue":
|
|
29804
|
-
if (typeof node2.value === "number" && !Number.isNaN(node2.value)) values[fieldName] = node2.value;
|
|
29805
|
-
break;
|
|
29806
|
-
case "IssueFieldDateValue":
|
|
29807
|
-
if (typeof node2.value === "string") values[fieldName] = node2.value;
|
|
29808
|
-
break;
|
|
29809
|
-
case "IssueFieldSingleSelectValue":
|
|
29810
|
-
if (typeof node2.name === "string") values[fieldName] = node2.name;
|
|
29811
|
-
break;
|
|
29812
|
-
case "IssueFieldMultiSelectValue": {
|
|
29813
|
-
const options = (node2.options ?? []).map((opt) => opt?.name).filter((name) => typeof name === "string");
|
|
29814
|
-
if (options.length > 0) values[fieldName] = options;
|
|
29815
|
-
break;
|
|
29816
|
-
}
|
|
29817
|
-
}
|
|
29826
|
+
const val = issueFieldValueOf(node2);
|
|
29827
|
+
if (val !== void 0) values[fieldName] = val;
|
|
29818
29828
|
}
|
|
29819
29829
|
return values;
|
|
29820
29830
|
}
|
|
29821
29831
|
var SCHEMA_ERROR_PATTERNS = [
|
|
29822
29832
|
/issueFieldValues.*(?:doesn['’]t exist on type|is not defined on type).*['"`]?Issue['"`]?/i,
|
|
29823
|
-
/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
|
+
/(?:isIssueField|issueField).*(?:doesn['’]t exist on type|is not defined on type).*['"`]?ProjectV2/i,
|
|
29835
|
+
/(?:No such type\s+['"`]?(?:ProjectV2ItemIssueFieldValue|ProjectV2IssueFieldValues)['"`]?|(?:ProjectV2ItemIssueFieldValue|ProjectV2IssueFieldValues).*(?:doesn['’]t exist|is not defined))/i
|
|
29824
29836
|
];
|
|
29825
29837
|
function matchesSchemaError(text) {
|
|
29826
29838
|
return SCHEMA_ERROR_PATTERNS.some((pattern) => pattern.test(text));
|
|
@@ -29837,7 +29849,9 @@ function isIssueFieldsMissingError(error62) {
|
|
|
29837
29849
|
var issueFieldInputSchema = issueFieldValuesSchema;
|
|
29838
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.`;
|
|
29839
29851
|
var MAX_ISSUE_FIELDS = 25;
|
|
29840
|
-
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}}}}}}`;
|
|
29841
29855
|
var VALUES_QUERY = `query($id:ID!){node(id:$id){... on Issue{${ISSUE_FIELD_VALUES_FRAGMENT}}}}`;
|
|
29842
29856
|
var issueFieldTypes = {
|
|
29843
29857
|
TEXT: "text",
|
|
@@ -29873,6 +29887,20 @@ async function readIssueFieldDefinitions(repo, ctx) {
|
|
|
29873
29887
|
}
|
|
29874
29888
|
return (data?.repository?.issueFields?.nodes ?? []).flatMap((raw) => definitionOf(raw) ?? []);
|
|
29875
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
|
+
}
|
|
29876
29904
|
function invalid4(message) {
|
|
29877
29905
|
return new ToolError("invalid_argument", message);
|
|
29878
29906
|
}
|
|
@@ -29880,7 +29908,7 @@ function fieldNames(definitions) {
|
|
|
29880
29908
|
return listOf(definitions.map((field) => field.name));
|
|
29881
29909
|
}
|
|
29882
29910
|
function fieldOf(repo, definitions, name) {
|
|
29883
|
-
const field = definitions
|
|
29911
|
+
const field = findIssueField(definitions, name);
|
|
29884
29912
|
if (!field) throw invalid4(`${repo.full} has no issue field "${name}". Fields: ${fieldNames(definitions)}.`);
|
|
29885
29913
|
return field;
|
|
29886
29914
|
}
|
|
@@ -30633,12 +30661,18 @@ var issueComment = defineTool({
|
|
|
30633
30661
|
// src/core/github/board-fields.ts
|
|
30634
30662
|
var VIEW_LAYOUT_SUFFIX = /_LAYOUT$/;
|
|
30635
30663
|
var FIELD_SELECTION = "__typename ... on ProjectV2FieldCommon{id name dataType} ... on ProjectV2SingleSelectField{options{id name color description}} ... on ProjectV2IterationField{configuration{iterations{id title startDate duration}}}";
|
|
30636
|
-
var
|
|
30664
|
+
var ISSUE_FIELD_SELECTION = "isIssueField issueField{__typename ... on IssueFieldSingleSelect{options{id name color description}}}";
|
|
30665
|
+
var READ_FIELD_SELECTION = `${FIELD_SELECTION} ... on ProjectV2Field{${ISSUE_FIELD_SELECTION}} ... on ProjectV2SingleSelectField{${ISSUE_FIELD_SELECTION}}`;
|
|
30666
|
+
var FIELDS_QUERY2 = `query($id:ID!,$after:String){node(id:$id){... on ProjectV2{fields(first:${PAGE_SIZE},after:$after){${PAGE_INFO} nodes{${READ_FIELD_SELECTION}}}}}}`;
|
|
30667
|
+
var FALLBACK_FIELDS_QUERY = `query($id:ID!,$after:String){node(id:$id){... on ProjectV2{fields(first:${PAGE_SIZE},after:$after){${PAGE_INFO} nodes{${FIELD_SELECTION}}}}}}`;
|
|
30637
30668
|
var VIEWS_QUERY = `query($id:ID!,$after:String){node(id:$id){... on ProjectV2{views(first:${PAGE_SIZE},after:$after){${PAGE_INFO} nodes{id number name layout filter}}}}}`;
|
|
30638
30669
|
var boardFieldSchema = external_exports.object({
|
|
30639
30670
|
id: external_exports.string(),
|
|
30640
30671
|
name: external_exports.string(),
|
|
30641
30672
|
type: external_exports.string().describe("GitHub's data type in lower case: text, number, date, single_select, iteration, title, assignees, \u2026"),
|
|
30673
|
+
issue_field: external_exports.boolean().describe(
|
|
30674
|
+
"Whether the column mirrors one of the organization's issue fields: its value is the issue's own, set with the issue tools, not on the board."
|
|
30675
|
+
),
|
|
30642
30676
|
options: external_exports.array(external_exports.object({ id: external_exports.string(), name: external_exports.string(), color: external_exports.string(), description: external_exports.string() })).optional().describe("single_select: the options, in order."),
|
|
30643
30677
|
iterations: external_exports.array(external_exports.object({ id: external_exports.string(), title: external_exports.string(), start_date: external_exports.string(), duration: external_exports.number().int() })).optional().describe("iteration: the iterations; duration is in days.")
|
|
30644
30678
|
});
|
|
@@ -30649,9 +30683,16 @@ var boardViewSchema = external_exports.object({
|
|
|
30649
30683
|
filter: external_exports.string().nullable()
|
|
30650
30684
|
});
|
|
30651
30685
|
function toField(raw) {
|
|
30652
|
-
const
|
|
30653
|
-
|
|
30654
|
-
|
|
30686
|
+
const isIssueField = Boolean(raw.isIssueField);
|
|
30687
|
+
const field = {
|
|
30688
|
+
id: raw.id,
|
|
30689
|
+
name: raw.name ?? "",
|
|
30690
|
+
type: (raw.dataType ?? "").toLowerCase(),
|
|
30691
|
+
issue_field: isIssueField
|
|
30692
|
+
};
|
|
30693
|
+
const rawOptions = isIssueField ? raw.issueField?.options ?? (field.type === "single_select" ? [] : void 0) : raw.options;
|
|
30694
|
+
if (rawOptions) {
|
|
30695
|
+
field.options = rawOptions.map((option) => ({
|
|
30655
30696
|
id: option.id,
|
|
30656
30697
|
name: option.name,
|
|
30657
30698
|
color: option.color ?? "",
|
|
@@ -30669,11 +30710,21 @@ function toField(raw) {
|
|
|
30669
30710
|
return field;
|
|
30670
30711
|
}
|
|
30671
30712
|
async function readBoardFields(projectId, ctx) {
|
|
30672
|
-
const
|
|
30673
|
-
|
|
30674
|
-
|
|
30675
|
-
|
|
30676
|
-
|
|
30713
|
+
const fetchFields = async (query) => {
|
|
30714
|
+
const { items } = await paginate(query, { id: projectId }, (data) => data?.node?.fields, {
|
|
30715
|
+
cwd: ctx.cwd,
|
|
30716
|
+
signal: ctx.signal
|
|
30717
|
+
});
|
|
30718
|
+
return items.filter((raw) => Boolean(raw?.id)).map(toField);
|
|
30719
|
+
};
|
|
30720
|
+
try {
|
|
30721
|
+
return await fetchFields(FIELDS_QUERY2);
|
|
30722
|
+
} catch (error62) {
|
|
30723
|
+
if (isIssueFieldsMissingError(error62)) {
|
|
30724
|
+
return await fetchFields(FALLBACK_FIELDS_QUERY);
|
|
30725
|
+
}
|
|
30726
|
+
throw error62;
|
|
30727
|
+
}
|
|
30677
30728
|
}
|
|
30678
30729
|
async function readBoardViewNodes(projectId, ctx) {
|
|
30679
30730
|
const { items } = await paginate(VIEWS_QUERY, { id: projectId }, (data) => data?.node?.views, {
|
|
@@ -30903,6 +30954,7 @@ var STATUS_FIELD = "Status";
|
|
|
30903
30954
|
var FIELD_REPLY = `projectV2Field{${FIELD_SELECTION}}`;
|
|
30904
30955
|
var createFieldMutation = (type, options) => `mutation($project:ID!,$name:String!){createProjectV2Field(input:{projectId:$project,dataType:${type.toUpperCase()},name:$name${options}}){${FIELD_REPLY}}}`;
|
|
30905
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}}}}`;
|
|
30906
30958
|
function invalid7(message) {
|
|
30907
30959
|
return new ToolError("invalid_argument", message);
|
|
30908
30960
|
}
|
|
@@ -30915,6 +30967,29 @@ function fieldRequest(name, type, options) {
|
|
|
30915
30967
|
}
|
|
30916
30968
|
return { name: trimmed, type, options: parsed };
|
|
30917
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
|
+
}
|
|
30918
30993
|
function optionsLiteral(options) {
|
|
30919
30994
|
const items = options.map((option) => {
|
|
30920
30995
|
if (!OPTION_COLORS.some((color) => color === option.color)) {
|
|
@@ -30959,6 +31034,11 @@ async function ensureField(board, fields, request2, policy, ctx) {
|
|
|
30959
31034
|
if (request2.type !== "single_select" || request2.options.length === 0) return unchanged;
|
|
30960
31035
|
const merge2 = (policy === "replace" ? replaceOptions : appendOptions)(existing.options ?? [], request2.options);
|
|
30961
31036
|
if (!merge2.changed) return unchanged;
|
|
31037
|
+
if (existing.issue_field) {
|
|
31038
|
+
throw invalid7(
|
|
31039
|
+
`"${existing.name}" mirrors the organization's issue field; its options are the organization's and cannot be changed on a board.`
|
|
31040
|
+
);
|
|
31041
|
+
}
|
|
30962
31042
|
const data = await graphql(
|
|
30963
31043
|
updateOptionsMutation(optionsLiteral(merge2.options)),
|
|
30964
31044
|
{ field: existing.id },
|
|
@@ -30967,6 +31047,23 @@ async function ensureField(board, fields, request2, policy, ctx) {
|
|
|
30967
31047
|
const field = fieldOf2(data?.updateProjectV2Field ?? null, existing.name);
|
|
30968
31048
|
return { field, created: false, added_options: merge2.added, updated_options: merge2.updated };
|
|
30969
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
|
+
}
|
|
30970
31067
|
|
|
30971
31068
|
// src/core/projects/support.ts
|
|
30972
31069
|
var BOARD_SELECTION = {
|
|
@@ -30990,60 +31087,65 @@ function boardSummary(board) {
|
|
|
30990
31087
|
// src/core/projects/template.ts
|
|
30991
31088
|
var STATUS_TODO = "Todo";
|
|
30992
31089
|
var STATUS_WAITING = "Waiting";
|
|
30993
|
-
var
|
|
30994
|
-
var
|
|
30995
|
-
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" };
|
|
30996
31093
|
var DEFAULT_VIEW_NAME = "View 1";
|
|
30997
|
-
|
|
30998
|
-
|
|
30999
|
-
|
|
31000
|
-
|
|
31001
|
-
|
|
31002
|
-
|
|
31003
|
-
|
|
31004
|
-
|
|
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 },
|
|
31005
31119
|
{
|
|
31006
|
-
name:
|
|
31007
|
-
|
|
31008
|
-
|
|
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
|
|
31009
31126
|
},
|
|
31010
|
-
{
|
|
31011
|
-
|
|
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
|
+
}
|
|
31012
31146
|
]
|
|
31013
|
-
}
|
|
31014
|
-
|
|
31015
|
-
{ name: TARGET_FIELD, type: "date", options: [] }
|
|
31016
|
-
];
|
|
31017
|
-
var STANDARD_VIEWS = [
|
|
31018
|
-
{ name: "Roadmap", layout: "roadmap", filter: "-status:Cancelled", sort_by: START_FIELD },
|
|
31019
|
-
{
|
|
31020
|
-
name: "Kanban",
|
|
31021
|
-
layout: "board",
|
|
31022
|
-
filter: NOT_DONE,
|
|
31023
|
-
column_by: STATUS_FIELD,
|
|
31024
|
-
fields: ["Title", "Assignees", "Repository", "Parent issue", TARGET_FIELD],
|
|
31025
|
-
sort_by: TARGET_FIELD
|
|
31026
|
-
},
|
|
31027
|
-
{
|
|
31028
|
-
name: "Backlog",
|
|
31029
|
-
layout: "table",
|
|
31030
|
-
filter: NOT_DONE,
|
|
31031
|
-
fields: [
|
|
31032
|
-
"Title",
|
|
31033
|
-
STATUS_FIELD,
|
|
31034
|
-
"Assignees",
|
|
31035
|
-
"Repository",
|
|
31036
|
-
"Milestone",
|
|
31037
|
-
"Parent issue",
|
|
31038
|
-
"Sub-issues progress",
|
|
31039
|
-
START_FIELD,
|
|
31040
|
-
TARGET_FIELD,
|
|
31041
|
-
"Linked pull requests"
|
|
31042
|
-
],
|
|
31043
|
-
group_by: STATUS_FIELD,
|
|
31044
|
-
sort_by: TARGET_FIELD
|
|
31045
|
-
}
|
|
31046
|
-
];
|
|
31147
|
+
};
|
|
31148
|
+
}
|
|
31047
31149
|
|
|
31048
31150
|
// src/core/projects/item-support.ts
|
|
31049
31151
|
var ITEM_BOARD_SELECTION = {
|
|
@@ -31056,10 +31158,10 @@ var itemArgument = external_exports.string().describe(
|
|
|
31056
31158
|
"The board item: its node ID (PVTI_\u2026), or an issue or pull request as 12, #12, owner/repo#12 or its URL, found on the board that project, owner and repo choose. A draft can only be named by its ID."
|
|
31057
31159
|
);
|
|
31058
31160
|
var ITEM_NOTE = "An item is named by its node ID (PVTI_\u2026), which also tells its board (a project given beside it must be that board), or by an issue or pull request (12, #12, owner/repo#12 or its URL) that is on the board the lookup finds. A draft can only be named by its ID.";
|
|
31059
|
-
var FIELDS_NOTE = "Field values are set by field name and option or iteration name, matched without regard to case: text as a string, number as a number or numeric string, date as YYYY-MM-DD, single select as an option name, iteration as an iteration title or @current (the iteration containing today, UTC). Only text, number, date, single select and iteration fields can be set; GitHub's own (Title, Assignees, Labels, Milestone, Repository, Linked pull requests, \u2026) are set on the issue, and github_issue_edit sets assignees, labels and milestone. Every field and value is checked before anything is written.";
|
|
31161
|
+
var FIELDS_NOTE = "Field values are set by field name and option or iteration name, matched without regard to case: text as a string, number as a number or numeric string, date as YYYY-MM-DD, single select as an option name, iteration as an iteration title or @current (the iteration containing today, UTC). Only text, number, date, single select and iteration fields can be set; a column that mirrors an issue field is set with the issue tools' issue_fields, not here. GitHub's own (Title, Assignees, Labels, Milestone, Repository, Linked pull requests, \u2026) are set on the issue, and github_issue_edit sets assignees, labels and milestone. Every field and value is checked before anything is written.";
|
|
31060
31162
|
var fieldValuesSchema = external_exports.record(external_exports.string(), external_exports.union([external_exports.string(), external_exports.number()]));
|
|
31061
31163
|
var fieldValuesArgument = fieldValuesSchema.optional().describe(
|
|
31062
|
-
|
|
31164
|
+
`Field values to set, by field name: {"Status": "Todo", "Target": "2026-12-01"}. Values are text, a number, a YYYY-MM-DD date, an option name or an iteration title (@current is the one containing today). A column that mirrors an issue field is set with the issue tools' issue_fields, not here.`
|
|
31063
31165
|
);
|
|
31064
31166
|
var fieldsResultSchema = fieldValuesSchema.describe(
|
|
31065
31167
|
"The values that were set, by field name as the board spells it: an option or iteration by its name, a number as a number."
|
|
@@ -32278,6 +32380,9 @@ var input10 = external_exports.object({
|
|
|
32278
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)."
|
|
32279
32381
|
),
|
|
32280
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
|
+
),
|
|
32281
32386
|
link_repo: external_exports.string().optional().describe("owner/name of a repository to link the board to; needs write permission.")
|
|
32282
32387
|
});
|
|
32283
32388
|
var output10 = external_exports.object({
|
|
@@ -32309,23 +32414,41 @@ function openBoardTitled(boards, title) {
|
|
|
32309
32414
|
}
|
|
32310
32415
|
return matches[0];
|
|
32311
32416
|
}
|
|
32312
|
-
async function applyFields(board, fresh, report, ctx) {
|
|
32417
|
+
async function applyFields(board, fresh, mode, dates, definitions, report, ctx) {
|
|
32313
32418
|
const fields = await readBoardFields(board.id, ctx);
|
|
32314
|
-
|
|
32315
|
-
|
|
32316
|
-
|
|
32317
|
-
|
|
32318
|
-
|
|
32319
|
-
|
|
32320
|
-
|
|
32321
|
-
|
|
32322
|
-
|
|
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
|
+
}
|
|
32323
32446
|
}
|
|
32324
32447
|
}
|
|
32325
|
-
async function applyViews(board, report, notes, ctx) {
|
|
32448
|
+
async function applyViews(board, templateViews, roadmapNote2, report, notes, ctx) {
|
|
32326
32449
|
const before = await readBoardViewNodes(board.id, ctx);
|
|
32327
32450
|
const readers = viewFieldReaders(board, ctx);
|
|
32328
|
-
for (const request2 of
|
|
32451
|
+
for (const request2 of templateViews) {
|
|
32329
32452
|
if (before.some((view5) => sameTitle(view5.name, request2.name))) {
|
|
32330
32453
|
report.push({ view: request2.name, created: false });
|
|
32331
32454
|
continue;
|
|
@@ -32337,7 +32460,7 @@ async function applyViews(board, report, notes, ctx) {
|
|
|
32337
32460
|
throw error62;
|
|
32338
32461
|
}
|
|
32339
32462
|
report.push({ view: request2.name, created: true });
|
|
32340
|
-
if (request2.layout === "roadmap") notes.push(
|
|
32463
|
+
if (request2.layout === "roadmap") notes.push(roadmapNote2);
|
|
32341
32464
|
}
|
|
32342
32465
|
return before;
|
|
32343
32466
|
}
|
|
@@ -32347,6 +32470,7 @@ var projectCreate = defineTool({
|
|
|
32347
32470
|
description: [
|
|
32348
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.`,
|
|
32349
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.`,
|
|
32350
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.",
|
|
32351
32475
|
"Once the board exists, a failed step does not fail the call: it is listed in errors and the board is still returned.",
|
|
32352
32476
|
`notes lists what the API cannot do, such as setting the Roadmap view's date fields. ${PROJECT_SCOPE_NOTE}`
|
|
@@ -32372,6 +32496,23 @@ var projectCreate = defineTool({
|
|
|
32372
32496
|
linkRepo = await writableContext(repo, ctx);
|
|
32373
32497
|
}
|
|
32374
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);
|
|
32375
32516
|
const reused = openBoardTitled((await ownerBoards(owner.login, ctx, owner.type)).boards, title);
|
|
32376
32517
|
if (reused) assertBoardWritable(reused);
|
|
32377
32518
|
const source = reused || !templateRef ? void 0 : (await resolveBoard({ project: templateRef, owner: ownerArg }, ctx)).project;
|
|
@@ -32384,8 +32525,11 @@ var projectCreate = defineTool({
|
|
|
32384
32525
|
const notes = [];
|
|
32385
32526
|
let deletedDefaultView = false;
|
|
32386
32527
|
if (standard) {
|
|
32387
|
-
await steps.record("fields", () => applyFields(board, fresh, fields, ctx));
|
|
32388
|
-
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
|
+
);
|
|
32389
32533
|
const defaultView = fresh ? before?.find((view5) => view5.name === DEFAULT_VIEW_NAME) : void 0;
|
|
32390
32534
|
if (defaultView) {
|
|
32391
32535
|
deletedDefaultView = await steps.record("default_view", async () => {
|
|
@@ -32416,9 +32560,14 @@ var projectCreate = defineTool({
|
|
|
32416
32560
|
var input11 = external_exports.object({
|
|
32417
32561
|
...BOARD_SELECTION,
|
|
32418
32562
|
name: external_exports.string().describe("The field's name, matched without regard to case."),
|
|
32419
|
-
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
|
+
),
|
|
32420
32566
|
options: external_exports.array(external_exports.string()).optional().describe(
|
|
32421
|
-
`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."
|
|
32422
32571
|
)
|
|
32423
32572
|
});
|
|
32424
32573
|
var output11 = external_exports.object({
|
|
@@ -32427,12 +32576,25 @@ var output11 = external_exports.object({
|
|
|
32427
32576
|
created: external_exports.boolean().describe("Whether this call made the field."),
|
|
32428
32577
|
added_options: external_exports.array(external_exports.string()).describe("The names of the options this call added; [] when none.")
|
|
32429
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
|
+
}
|
|
32430
32591
|
var projectFieldEnsure = defineTool({
|
|
32431
32592
|
id: "github_project_field_ensure",
|
|
32432
32593
|
title: "Ensure a GitHub project field",
|
|
32433
32594
|
description: [
|
|
32434
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.",
|
|
32435
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.",
|
|
32436
32598
|
BOARD_LOOKUP_NOTE,
|
|
32437
32599
|
PROJECT_SCOPE_NOTE
|
|
32438
32600
|
].join(" "),
|
|
@@ -32442,11 +32604,11 @@ var projectFieldEnsure = defineTool({
|
|
|
32442
32604
|
input: input11,
|
|
32443
32605
|
output: output11,
|
|
32444
32606
|
async execute(args, ctx) {
|
|
32445
|
-
const
|
|
32607
|
+
const ensure = planEnsure(args);
|
|
32446
32608
|
const { project } = await resolveBoard(args, ctx);
|
|
32447
32609
|
assertBoardWritable(project);
|
|
32448
32610
|
const fields = await readBoardFields(project.id, ctx);
|
|
32449
|
-
const { field, created, added_options } = await
|
|
32611
|
+
const { field, created, added_options } = await ensure(project, fields, ctx);
|
|
32450
32612
|
return { project: boardSummary(project), field, created, added_options };
|
|
32451
32613
|
}
|
|
32452
32614
|
});
|
|
@@ -32526,7 +32688,10 @@ var FIELD_LABELS = 20;
|
|
|
32526
32688
|
var FIELD_USERS = 10;
|
|
32527
32689
|
var FIELD_PULL_REQUESTS = 10;
|
|
32528
32690
|
var FIELD_NAME = "field{... on ProjectV2FieldCommon{name}}";
|
|
32529
|
-
|
|
32691
|
+
function itemFields(includeIssueFields = true) {
|
|
32692
|
+
const issueFieldSelection = includeIssueFields ? `
|
|
32693
|
+
... on ProjectV2ItemIssueFieldValue{${FIELD_NAME} issueFieldValue{${ISSUE_FIELD_VALUE_SELECTION}}}` : "";
|
|
32694
|
+
return `id isArchived
|
|
32530
32695
|
fieldValues(first:${FIELD_VALUES}){nodes{
|
|
32531
32696
|
... on ProjectV2ItemFieldTextValue{text ${FIELD_NAME}}
|
|
32532
32697
|
... on ProjectV2ItemFieldNumberValue{number ${FIELD_NAME}}
|
|
@@ -32537,15 +32702,22 @@ fieldValues(first:${FIELD_VALUES}){nodes{
|
|
|
32537
32702
|
... on ProjectV2ItemFieldRepositoryValue{repository{nameWithOwner} ${FIELD_NAME}}
|
|
32538
32703
|
... on ProjectV2ItemFieldLabelValue{labels(first:${FIELD_LABELS}){nodes{name}} ${FIELD_NAME}}
|
|
32539
32704
|
... on ProjectV2ItemFieldUserValue{users(first:${FIELD_USERS}){nodes{login}} ${FIELD_NAME}}
|
|
32540
|
-
... on ProjectV2ItemFieldPullRequestValue{pullRequests(first:${FIELD_PULL_REQUESTS}){nodes{number}} ${FIELD_NAME}}
|
|
32705
|
+
... on ProjectV2ItemFieldPullRequestValue{pullRequests(first:${FIELD_PULL_REQUESTS}){nodes{number}} ${FIELD_NAME}}${issueFieldSelection}
|
|
32541
32706
|
}}
|
|
32542
32707
|
content{__typename
|
|
32543
32708
|
... on DraftIssue{id title body}
|
|
32544
32709
|
... on Issue{number title url issueState: state repository{nameWithOwner} issueType{name} labels(first:${CONTENT_LABELS}){nodes{name}} assignees(first:${CONTENT_ASSIGNEES}){nodes{login}} parent{number repository{nameWithOwner}} subIssuesSummary{total completed}}
|
|
32545
32710
|
... on PullRequest{number title url pullRequestState: state repository{nameWithOwner} labels(first:${CONTENT_LABELS}){nodes{name}} assignees(first:${CONTENT_ASSIGNEES}){nodes{login}}}
|
|
32546
32711
|
}`;
|
|
32547
|
-
|
|
32548
|
-
var
|
|
32712
|
+
}
|
|
32713
|
+
var ITEM_FIELDS = itemFields(true);
|
|
32714
|
+
var ITEM_FIELDS_WITHOUT_ISSUE_FIELDS = itemFields(false);
|
|
32715
|
+
var itemsQuery = (fields) => `query($id:ID!,$after:String){node(id:$id){... on ProjectV2{items(first:${PAGE_SIZE2},after:$after){pageInfo{hasNextPage endCursor} nodes{${fields}}}}}}`;
|
|
32716
|
+
var itemQuery = (fields) => `query($id:ID!){node(id:$id){... on ProjectV2Item{${fields}}}}`;
|
|
32717
|
+
var ITEMS_QUERY = itemsQuery(ITEM_FIELDS);
|
|
32718
|
+
var ITEMS_QUERY_WITHOUT_ISSUE_FIELDS = itemsQuery(ITEM_FIELDS_WITHOUT_ISSUE_FIELDS);
|
|
32719
|
+
var ITEM_QUERY = itemQuery(ITEM_FIELDS);
|
|
32720
|
+
var ITEM_QUERY_WITHOUT_ISSUE_FIELDS = itemQuery(ITEM_FIELDS_WITHOUT_ISSUE_FIELDS);
|
|
32549
32721
|
var iterationValueSchema = external_exports.object({
|
|
32550
32722
|
title: external_exports.string(),
|
|
32551
32723
|
start_date: external_exports.string(),
|
|
@@ -32576,7 +32748,7 @@ var boardItemSchema = external_exports.object({
|
|
|
32576
32748
|
item_id: external_exports.string(),
|
|
32577
32749
|
archived: external_exports.boolean(),
|
|
32578
32750
|
fields: external_exports.record(external_exports.string(), itemFieldValueSchema).describe(
|
|
32579
|
-
"Values by field name: text, number, date and single select as they are (the option's name), iteration as { title, start_date, duration }, milestone as its title, repository as owner/name, labels as names, users as logins, linked pull requests as numbers."
|
|
32751
|
+
"Values by field name: text, number, date and single select as they are (the option's name), a column mirroring an organization issue field as the issue's value (an option's name, or a list of names for a multi-select), iteration as { title, start_date, duration }, milestone as its title, repository as owner/name, labels as names, users as logins, linked pull requests as numbers."
|
|
32580
32752
|
),
|
|
32581
32753
|
content: itemContentSchema.nullable().describe("What the item stands for; null when GitHub did not return it.")
|
|
32582
32754
|
});
|
|
@@ -32584,6 +32756,7 @@ function nodesOf2(connection) {
|
|
|
32584
32756
|
return (connection?.nodes ?? []).filter((node2) => node2 != null);
|
|
32585
32757
|
}
|
|
32586
32758
|
function fieldValue(raw) {
|
|
32759
|
+
if ("issueFieldValue" in raw) return issueFieldValueOf(raw.issueFieldValue);
|
|
32587
32760
|
if ("text" in raw) return raw.text ?? null;
|
|
32588
32761
|
if ("number" in raw) return raw.number ?? null;
|
|
32589
32762
|
if ("date" in raw) return raw.date ?? null;
|
|
@@ -32647,16 +32820,34 @@ function toItem(raw) {
|
|
|
32647
32820
|
};
|
|
32648
32821
|
}
|
|
32649
32822
|
async function readBoardItems(projectId, ctx) {
|
|
32650
|
-
const
|
|
32651
|
-
|
|
32652
|
-
|
|
32653
|
-
|
|
32654
|
-
|
|
32655
|
-
|
|
32656
|
-
|
|
32823
|
+
const run = (query) => paginate(query, { id: projectId }, (data) => data?.node?.items, {
|
|
32824
|
+
cwd: ctx.cwd,
|
|
32825
|
+
signal: ctx.signal,
|
|
32826
|
+
limit: MAX_BOARD_ITEMS
|
|
32827
|
+
});
|
|
32828
|
+
let result;
|
|
32829
|
+
try {
|
|
32830
|
+
result = await run(ITEMS_QUERY);
|
|
32831
|
+
} catch (error62) {
|
|
32832
|
+
if (isIssueFieldsMissingError(error62)) {
|
|
32833
|
+
result = await run(ITEMS_QUERY_WITHOUT_ISSUE_FIELDS);
|
|
32834
|
+
} else {
|
|
32835
|
+
throw error62;
|
|
32836
|
+
}
|
|
32837
|
+
}
|
|
32838
|
+
return { items: result.items.filter((raw) => raw != null).map(toItem), truncated: result.truncated };
|
|
32657
32839
|
}
|
|
32658
32840
|
async function readBoardItem(itemId, ctx) {
|
|
32659
|
-
|
|
32841
|
+
let data;
|
|
32842
|
+
try {
|
|
32843
|
+
data = await graphql(ITEM_QUERY, { id: itemId }, ctx);
|
|
32844
|
+
} catch (error62) {
|
|
32845
|
+
if (isIssueFieldsMissingError(error62)) {
|
|
32846
|
+
data = await graphql(ITEM_QUERY_WITHOUT_ISSUE_FIELDS, { id: itemId }, ctx);
|
|
32847
|
+
} else {
|
|
32848
|
+
throw error62;
|
|
32849
|
+
}
|
|
32850
|
+
}
|
|
32660
32851
|
const raw = data?.node;
|
|
32661
32852
|
if (!raw?.id) return null;
|
|
32662
32853
|
return { item: toItem(raw), draftId: raw.content?.__typename === "DraftIssue" ? raw.content.id ?? null : null };
|
|
@@ -32881,7 +33072,9 @@ var input16 = external_exports.object({
|
|
|
32881
33072
|
item: itemArgument,
|
|
32882
33073
|
...ITEM_BOARD_SELECTION,
|
|
32883
33074
|
fields: fieldValuesArgument,
|
|
32884
|
-
clear_fields: external_exports.array(external_exports.string()).optional().describe(
|
|
33075
|
+
clear_fields: external_exports.array(external_exports.string()).optional().describe(
|
|
33076
|
+
"Names of the fields to empty. A column that mirrors an issue field is cleared with clear_issue_fields in github_issue_edit, not here."
|
|
33077
|
+
),
|
|
32885
33078
|
title: external_exports.string().optional().describe("Drafts only: the new title."),
|
|
32886
33079
|
body: external_exports.string().optional().describe("Drafts only: the new body, which replaces the whole old one; empty clears it."),
|
|
32887
33080
|
append_body: external_exports.string().optional().describe("Drafts only: text added after the current body, set off by a blank line.")
|
|
@@ -33189,7 +33382,7 @@ var projectRead = defineTool({
|
|
|
33189
33382
|
id: "github_project_read",
|
|
33190
33383
|
title: "Read GitHub project boards",
|
|
33191
33384
|
description: [
|
|
33192
|
-
'Read GitHub project boards (Projects v2). method "view": the board the lookup finds, its fields (with single-select options and iterations) and its views, with the route that found it and what every route considered.',
|
|
33385
|
+
'Read GitHub project boards (Projects v2). method "view": the board the lookup finds, its fields (with single-select options and iterations; a field mirroring an issue field is marked issue_field) and its views, with the route that found it and what every route considered.',
|
|
33193
33386
|
`method "list": an owner's boards (owner, a login or @me) or the boards linked to a repository (repo, default the working tree's), open ones unless include_closed; truncated says more matched than limit (default ${DEFAULT_LIST_LIMIT}).`,
|
|
33194
33387
|
`method "item_list": the board's items, filtered here by status (names, comma-separated, "-Name" leaves one out), content_type (issue, pr, draft), content_repo, search in the title and include_archived, with field values flattened by field name; truncated says the board holds more than ${MAX_BOARD_ITEMS} items or more matched than limit (default ${DEFAULT_ITEM_LIMIT}).`,
|
|
33195
33388
|
"A board is named by project: its number, owner/number or its URL, used as it is (closed too); a bare number takes owner, else the owner of repo or of the working tree's repository.",
|
|
@@ -37896,7 +38089,7 @@ async function main() {
|
|
|
37896
38089
|
const settings = parseSettings(process.argv.slice(2), process.env);
|
|
37897
38090
|
server = createServer(ALL_TOOLS, settings, {
|
|
37898
38091
|
ownDir: packageRoot(import.meta.url),
|
|
37899
|
-
version: true ? "0.
|
|
38092
|
+
version: true ? "0.7.0" : void 0
|
|
37900
38093
|
});
|
|
37901
38094
|
} catch (error62) {
|
|
37902
38095
|
if (!isToolError(error62)) throw error62;
|