@jonit-dev/night-watch-cli 1.7.18 → 1.7.20
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/bin/night-watch.mjs +1 -1
- package/dist/src/cli.js +13 -4
- package/dist/src/cli.js.map +1 -1
- package/dist/src/server/index.d.ts.map +1 -1
- package/dist/src/server/index.js +14 -22
- package/dist/src/server/index.js.map +1 -1
- package/dist/src/slack/client.d.ts +4 -0
- package/dist/src/slack/client.d.ts.map +1 -1
- package/dist/src/slack/client.js +6 -0
- package/dist/src/slack/client.js.map +1 -1
- package/dist/src/slack/interaction-listener.d.ts +2 -3
- package/dist/src/slack/interaction-listener.d.ts.map +1 -1
- package/dist/src/slack/interaction-listener.js +30 -14
- package/dist/src/slack/interaction-listener.js.map +1 -1
- package/dist/src/storage/repositories/sqlite/agent-persona-repository.js +1 -1
- package/dist/src/storage/repositories/sqlite/agent-persona-repository.js.map +1 -1
- package/package.json +1 -1
- package/web/dist/assets/index-DOzZY27d.js +473 -0
- package/web/dist/assets/index-w6Q6gxCS.css +1 -0
- package/web/dist/index.html +2 -2
- package/dist/board/factory.d.ts +0 -3
- package/dist/board/factory.d.ts.map +0 -1
- package/dist/board/factory.js +0 -10
- package/dist/board/factory.js.map +0 -1
- package/dist/board/providers/github-graphql.d.ts +0 -16
- package/dist/board/providers/github-graphql.d.ts.map +0 -1
- package/dist/board/providers/github-graphql.js +0 -43
- package/dist/board/providers/github-graphql.js.map +0 -1
- package/dist/board/providers/github-projects.d.ts +0 -51
- package/dist/board/providers/github-projects.d.ts.map +0 -1
- package/dist/board/providers/github-projects.js +0 -672
- package/dist/board/providers/github-projects.js.map +0 -1
- package/dist/board/types.d.ts +0 -60
- package/dist/board/types.d.ts.map +0 -1
- package/dist/board/types.js +0 -4
- package/dist/board/types.js.map +0 -1
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -80
- package/dist/cli.js.map +0 -1
- package/dist/commands/board.d.ts +0 -9
- package/dist/commands/board.d.ts.map +0 -1
- package/dist/commands/board.js +0 -294
- package/dist/commands/board.js.map +0 -1
- package/dist/commands/cancel.d.ts +0 -46
- package/dist/commands/cancel.d.ts.map +0 -1
- package/dist/commands/cancel.js +0 -241
- package/dist/commands/cancel.js.map +0 -1
- package/dist/commands/dashboard/tab-actions.d.ts +0 -10
- package/dist/commands/dashboard/tab-actions.d.ts.map +0 -1
- package/dist/commands/dashboard/tab-actions.js +0 -245
- package/dist/commands/dashboard/tab-actions.js.map +0 -1
- package/dist/commands/dashboard/tab-config.d.ts +0 -21
- package/dist/commands/dashboard/tab-config.d.ts.map +0 -1
- package/dist/commands/dashboard/tab-config.js +0 -829
- package/dist/commands/dashboard/tab-config.js.map +0 -1
- package/dist/commands/dashboard/tab-logs.d.ts +0 -10
- package/dist/commands/dashboard/tab-logs.d.ts.map +0 -1
- package/dist/commands/dashboard/tab-logs.js +0 -178
- package/dist/commands/dashboard/tab-logs.js.map +0 -1
- package/dist/commands/dashboard/tab-schedules.d.ts +0 -21
- package/dist/commands/dashboard/tab-schedules.d.ts.map +0 -1
- package/dist/commands/dashboard/tab-schedules.js +0 -304
- package/dist/commands/dashboard/tab-schedules.js.map +0 -1
- package/dist/commands/dashboard/tab-status.d.ts +0 -32
- package/dist/commands/dashboard/tab-status.d.ts.map +0 -1
- package/dist/commands/dashboard/tab-status.js +0 -421
- package/dist/commands/dashboard/tab-status.js.map +0 -1
- package/dist/commands/dashboard/types.d.ts +0 -43
- package/dist/commands/dashboard/types.d.ts.map +0 -1
- package/dist/commands/dashboard/types.js +0 -5
- package/dist/commands/dashboard/types.js.map +0 -1
- package/dist/commands/dashboard.d.ts +0 -11
- package/dist/commands/dashboard.d.ts.map +0 -1
- package/dist/commands/dashboard.js +0 -239
- package/dist/commands/dashboard.js.map +0 -1
- package/dist/commands/doctor.d.ts +0 -16
- package/dist/commands/doctor.d.ts.map +0 -1
- package/dist/commands/doctor.js +0 -202
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/history.d.ts +0 -7
- package/dist/commands/history.d.ts.map +0 -1
- package/dist/commands/history.js +0 -56
- package/dist/commands/history.js.map +0 -1
- package/dist/commands/init.d.ts +0 -25
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js +0 -534
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/install.d.ts +0 -48
- package/dist/commands/install.d.ts.map +0 -1
- package/dist/commands/install.js +0 -303
- package/dist/commands/install.js.map +0 -1
- package/dist/commands/logs.d.ts +0 -15
- package/dist/commands/logs.d.ts.map +0 -1
- package/dist/commands/logs.js +0 -104
- package/dist/commands/logs.js.map +0 -1
- package/dist/commands/prd-state.d.ts +0 -12
- package/dist/commands/prd-state.d.ts.map +0 -1
- package/dist/commands/prd-state.js +0 -47
- package/dist/commands/prd-state.js.map +0 -1
- package/dist/commands/prd.d.ts +0 -24
- package/dist/commands/prd.d.ts.map +0 -1
- package/dist/commands/prd.js +0 -283
- package/dist/commands/prd.js.map +0 -1
- package/dist/commands/prds.d.ts +0 -13
- package/dist/commands/prds.d.ts.map +0 -1
- package/dist/commands/prds.js +0 -196
- package/dist/commands/prds.js.map +0 -1
- package/dist/commands/prs.d.ts +0 -14
- package/dist/commands/prs.d.ts.map +0 -1
- package/dist/commands/prs.js +0 -106
- package/dist/commands/prs.js.map +0 -1
- package/dist/commands/qa.d.ts +0 -30
- package/dist/commands/qa.d.ts.map +0 -1
- package/dist/commands/qa.js +0 -159
- package/dist/commands/qa.js.map +0 -1
- package/dist/commands/retry.d.ts +0 -9
- package/dist/commands/retry.d.ts.map +0 -1
- package/dist/commands/retry.js +0 -72
- package/dist/commands/retry.js.map +0 -1
- package/dist/commands/review.d.ts +0 -35
- package/dist/commands/review.d.ts.map +0 -1
- package/dist/commands/review.js +0 -252
- package/dist/commands/review.js.map +0 -1
- package/dist/commands/run.d.ts +0 -61
- package/dist/commands/run.d.ts.map +0 -1
- package/dist/commands/run.js +0 -364
- package/dist/commands/run.js.map +0 -1
- package/dist/commands/serve.d.ts +0 -7
- package/dist/commands/serve.d.ts.map +0 -1
- package/dist/commands/serve.js +0 -27
- package/dist/commands/serve.js.map +0 -1
- package/dist/commands/slice.d.ts +0 -26
- package/dist/commands/slice.d.ts.map +0 -1
- package/dist/commands/slice.js +0 -175
- package/dist/commands/slice.js.map +0 -1
- package/dist/commands/state.d.ts +0 -8
- package/dist/commands/state.d.ts.map +0 -1
- package/dist/commands/state.js +0 -56
- package/dist/commands/state.js.map +0 -1
- package/dist/commands/status.d.ts +0 -14
- package/dist/commands/status.d.ts.map +0 -1
- package/dist/commands/status.js +0 -147
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/uninstall.d.ts +0 -25
- package/dist/commands/uninstall.d.ts.map +0 -1
- package/dist/commands/uninstall.js +0 -141
- package/dist/commands/uninstall.js.map +0 -1
- package/dist/commands/update.d.ts +0 -21
- package/dist/commands/update.d.ts.map +0 -1
- package/dist/commands/update.js +0 -87
- package/dist/commands/update.js.map +0 -1
- package/dist/config.d.ts +0 -23
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -601
- package/dist/config.js.map +0 -1
- package/dist/constants.d.ts +0 -59
- package/dist/constants.d.ts.map +0 -1
- package/dist/constants.js +0 -110
- package/dist/constants.js.map +0 -1
- package/dist/server/index.d.ts +0 -23
- package/dist/server/index.d.ts.map +0 -1
- package/dist/server/index.js +0 -1074
- package/dist/server/index.js.map +0 -1
- package/dist/storage/json-state-migrator.d.ts +0 -24
- package/dist/storage/json-state-migrator.d.ts.map +0 -1
- package/dist/storage/json-state-migrator.js +0 -197
- package/dist/storage/json-state-migrator.js.map +0 -1
- package/dist/storage/repositories/index.d.ts +0 -23
- package/dist/storage/repositories/index.d.ts.map +0 -1
- package/dist/storage/repositories/index.js +0 -37
- package/dist/storage/repositories/index.js.map +0 -1
- package/dist/storage/repositories/interfaces.d.ts +0 -37
- package/dist/storage/repositories/interfaces.d.ts.map +0 -1
- package/dist/storage/repositories/interfaces.js +0 -6
- package/dist/storage/repositories/interfaces.js.map +0 -1
- package/dist/storage/repositories/sqlite/execution-history-repository.d.ts +0 -21
- package/dist/storage/repositories/sqlite/execution-history-repository.d.ts.map +0 -1
- package/dist/storage/repositories/sqlite/execution-history-repository.js +0 -94
- package/dist/storage/repositories/sqlite/execution-history-repository.js.map +0 -1
- package/dist/storage/repositories/sqlite/prd-state-repository.d.ts +0 -17
- package/dist/storage/repositories/sqlite/prd-state-repository.d.ts.map +0 -1
- package/dist/storage/repositories/sqlite/prd-state-repository.js +0 -74
- package/dist/storage/repositories/sqlite/prd-state-repository.js.map +0 -1
- package/dist/storage/repositories/sqlite/project-registry-repository.d.ts +0 -16
- package/dist/storage/repositories/sqlite/project-registry-repository.d.ts.map +0 -1
- package/dist/storage/repositories/sqlite/project-registry-repository.js +0 -34
- package/dist/storage/repositories/sqlite/project-registry-repository.js.map +0 -1
- package/dist/storage/repositories/sqlite/roadmap-state-repository.d.ts +0 -14
- package/dist/storage/repositories/sqlite/roadmap-state-repository.d.ts.map +0 -1
- package/dist/storage/repositories/sqlite/roadmap-state-repository.js +0 -47
- package/dist/storage/repositories/sqlite/roadmap-state-repository.js.map +0 -1
- package/dist/storage/sqlite/client.d.ts +0 -23
- package/dist/storage/sqlite/client.d.ts.map +0 -1
- package/dist/storage/sqlite/client.js +0 -47
- package/dist/storage/sqlite/client.js.map +0 -1
- package/dist/storage/sqlite/migrations.d.ts +0 -11
- package/dist/storage/sqlite/migrations.d.ts.map +0 -1
- package/dist/storage/sqlite/migrations.js +0 -57
- package/dist/storage/sqlite/migrations.js.map +0 -1
- package/dist/templates/prd-template.d.ts +0 -11
- package/dist/templates/prd-template.d.ts.map +0 -1
- package/dist/templates/prd-template.js +0 -166
- package/dist/templates/prd-template.js.map +0 -1
- package/dist/templates/slicer-prompt.d.ts +0 -54
- package/dist/templates/slicer-prompt.d.ts.map +0 -1
- package/dist/templates/slicer-prompt.js +0 -163
- package/dist/templates/slicer-prompt.js.map +0 -1
- package/dist/types.d.ts +0 -123
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -5
- package/dist/types.js.map +0 -1
- package/dist/utils/checks.d.ts +0 -55
- package/dist/utils/checks.d.ts.map +0 -1
- package/dist/utils/checks.js +0 -246
- package/dist/utils/checks.js.map +0 -1
- package/dist/utils/config-writer.d.ts +0 -16
- package/dist/utils/config-writer.d.ts.map +0 -1
- package/dist/utils/config-writer.js +0 -45
- package/dist/utils/config-writer.js.map +0 -1
- package/dist/utils/crontab.d.ts +0 -62
- package/dist/utils/crontab.d.ts.map +0 -1
- package/dist/utils/crontab.js +0 -168
- package/dist/utils/crontab.js.map +0 -1
- package/dist/utils/execution-history.d.ts +0 -54
- package/dist/utils/execution-history.d.ts.map +0 -1
- package/dist/utils/execution-history.js +0 -80
- package/dist/utils/execution-history.js.map +0 -1
- package/dist/utils/github.d.ts +0 -40
- package/dist/utils/github.d.ts.map +0 -1
- package/dist/utils/github.js +0 -126
- package/dist/utils/github.js.map +0 -1
- package/dist/utils/notify.d.ts +0 -63
- package/dist/utils/notify.d.ts.map +0 -1
- package/dist/utils/notify.js +0 -264
- package/dist/utils/notify.js.map +0 -1
- package/dist/utils/prd-states.d.ts +0 -16
- package/dist/utils/prd-states.d.ts.map +0 -1
- package/dist/utils/prd-states.js +0 -28
- package/dist/utils/prd-states.js.map +0 -1
- package/dist/utils/registry.d.ts +0 -44
- package/dist/utils/registry.d.ts.map +0 -1
- package/dist/utils/registry.js +0 -86
- package/dist/utils/registry.js.map +0 -1
- package/dist/utils/roadmap-parser.d.ts +0 -45
- package/dist/utils/roadmap-parser.d.ts.map +0 -1
- package/dist/utils/roadmap-parser.js +0 -136
- package/dist/utils/roadmap-parser.js.map +0 -1
- package/dist/utils/roadmap-scanner.d.ts +0 -92
- package/dist/utils/roadmap-scanner.d.ts.map +0 -1
- package/dist/utils/roadmap-scanner.js +0 -349
- package/dist/utils/roadmap-scanner.js.map +0 -1
- package/dist/utils/roadmap-state.d.ts +0 -90
- package/dist/utils/roadmap-state.d.ts.map +0 -1
- package/dist/utils/roadmap-state.js +0 -154
- package/dist/utils/roadmap-state.js.map +0 -1
- package/dist/utils/script-result.d.ts +0 -12
- package/dist/utils/script-result.d.ts.map +0 -1
- package/dist/utils/script-result.js +0 -46
- package/dist/utils/script-result.js.map +0 -1
- package/dist/utils/shell.d.ts +0 -27
- package/dist/utils/shell.d.ts.map +0 -1
- package/dist/utils/shell.js +0 -64
- package/dist/utils/shell.js.map +0 -1
- package/dist/utils/status-data.d.ts +0 -148
- package/dist/utils/status-data.d.ts.map +0 -1
- package/dist/utils/status-data.js +0 -593
- package/dist/utils/status-data.js.map +0 -1
- package/dist/utils/ui.d.ts +0 -55
- package/dist/utils/ui.d.ts.map +0 -1
- package/dist/utils/ui.js +0 -121
- package/dist/utils/ui.js.map +0 -1
- package/web/dist/assets/index-BtxQU4oX.css +0 -1
- package/web/dist/assets/index-D3awZ0gS.js +0 -473
|
@@ -1,672 +0,0 @@
|
|
|
1
|
-
import { execFileSync } from "child_process";
|
|
2
|
-
import { BOARD_COLUMNS, } from "../../board/types.js";
|
|
3
|
-
import { getRepoNwo, getViewerLogin, graphql } from "./github-graphql.js";
|
|
4
|
-
// ---------------------------------------------------------------------------
|
|
5
|
-
// GitHubProjectsProvider
|
|
6
|
-
// ---------------------------------------------------------------------------
|
|
7
|
-
export class GitHubProjectsProvider {
|
|
8
|
-
config;
|
|
9
|
-
cwd;
|
|
10
|
-
cachedProjectId = null;
|
|
11
|
-
cachedFieldId = null;
|
|
12
|
-
cachedOptionIds = new Map();
|
|
13
|
-
cachedOwner = null;
|
|
14
|
-
cachedRepositoryId = null;
|
|
15
|
-
constructor(config, cwd) {
|
|
16
|
-
this.config = config;
|
|
17
|
-
this.cwd = cwd;
|
|
18
|
-
}
|
|
19
|
-
// -------------------------------------------------------------------------
|
|
20
|
-
// Helpers
|
|
21
|
-
// -------------------------------------------------------------------------
|
|
22
|
-
getRepo() {
|
|
23
|
-
return this.config.repo ?? getRepoNwo(this.cwd);
|
|
24
|
-
}
|
|
25
|
-
getRepoParts() {
|
|
26
|
-
const repo = this.getRepo();
|
|
27
|
-
const [owner, name] = repo.split("/");
|
|
28
|
-
if (!owner || !name) {
|
|
29
|
-
throw new Error(`Invalid repository slug: "${repo}". Expected "owner/repo".`);
|
|
30
|
-
}
|
|
31
|
-
return { owner, name };
|
|
32
|
-
}
|
|
33
|
-
getRepoOwnerLogin() {
|
|
34
|
-
return this.getRepoParts().owner;
|
|
35
|
-
}
|
|
36
|
-
getRepoOwner() {
|
|
37
|
-
if (this.cachedOwner && this.cachedRepositoryId) {
|
|
38
|
-
return this.cachedOwner;
|
|
39
|
-
}
|
|
40
|
-
const { owner, name } = this.getRepoParts();
|
|
41
|
-
const data = graphql(`query ResolveRepoOwner($owner: String!, $name: String!) {
|
|
42
|
-
repository(owner: $owner, name: $name) {
|
|
43
|
-
id
|
|
44
|
-
owner {
|
|
45
|
-
__typename
|
|
46
|
-
id
|
|
47
|
-
login
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}`, { owner, name }, this.cwd);
|
|
51
|
-
if (!data.repository) {
|
|
52
|
-
throw new Error(`Repository ${owner}/${name} not found.`);
|
|
53
|
-
}
|
|
54
|
-
const ownerNode = data.repository.owner;
|
|
55
|
-
if (!ownerNode ||
|
|
56
|
-
(ownerNode.__typename !== "User" && ownerNode.__typename !== "Organization")) {
|
|
57
|
-
throw new Error(`Failed to resolve repository owner for ${owner}/${name}.`);
|
|
58
|
-
}
|
|
59
|
-
this.cachedRepositoryId = data.repository.id;
|
|
60
|
-
this.cachedOwner = {
|
|
61
|
-
id: ownerNode.id,
|
|
62
|
-
login: ownerNode.login,
|
|
63
|
-
type: ownerNode.__typename,
|
|
64
|
-
};
|
|
65
|
-
return this.cachedOwner;
|
|
66
|
-
}
|
|
67
|
-
getRepositoryNodeId() {
|
|
68
|
-
if (this.cachedRepositoryId) {
|
|
69
|
-
return this.cachedRepositoryId;
|
|
70
|
-
}
|
|
71
|
-
this.getRepoOwner();
|
|
72
|
-
if (!this.cachedRepositoryId) {
|
|
73
|
-
throw new Error(`Failed to resolve repository ID for ${this.getRepo()}.`);
|
|
74
|
-
}
|
|
75
|
-
return this.cachedRepositoryId;
|
|
76
|
-
}
|
|
77
|
-
linkProjectToRepository(projectId) {
|
|
78
|
-
const repositoryId = this.getRepositoryNodeId();
|
|
79
|
-
try {
|
|
80
|
-
graphql(`mutation LinkProjectToRepository($projectId: ID!, $repositoryId: ID!) {
|
|
81
|
-
linkProjectV2ToRepository(input: { projectId: $projectId, repositoryId: $repositoryId }) {
|
|
82
|
-
repository {
|
|
83
|
-
id
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}`, { projectId, repositoryId }, this.cwd);
|
|
87
|
-
}
|
|
88
|
-
catch (err) {
|
|
89
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
90
|
-
const normalized = message.toLowerCase();
|
|
91
|
-
if (normalized.includes("already") && normalized.includes("project")) {
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
throw err;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
fetchStatusField(projectId) {
|
|
98
|
-
const fieldData = graphql(`query GetStatusField($projectId: ID!) {
|
|
99
|
-
node(id: $projectId) {
|
|
100
|
-
... on ProjectV2 {
|
|
101
|
-
field(name: "Status") {
|
|
102
|
-
... on ProjectV2SingleSelectField {
|
|
103
|
-
id
|
|
104
|
-
options {
|
|
105
|
-
id
|
|
106
|
-
name
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}`, { projectId }, this.cwd);
|
|
113
|
-
const field = fieldData.node?.field;
|
|
114
|
-
if (!field) {
|
|
115
|
-
throw new Error(`Status field not found on project ${projectId}. ` +
|
|
116
|
-
`Run \`night-watch board setup\` to create it.`);
|
|
117
|
-
}
|
|
118
|
-
return {
|
|
119
|
-
fieldId: field.id,
|
|
120
|
-
optionIds: new Map(field.options.map((o) => [o.name, o.id])),
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Fetch and cache the project node ID, Status field ID, and option IDs.
|
|
125
|
-
* Throws if the project cannot be found or has no Status field.
|
|
126
|
-
*/
|
|
127
|
-
async ensureProjectCache() {
|
|
128
|
-
if (this.cachedProjectId !== null &&
|
|
129
|
-
this.cachedFieldId !== null &&
|
|
130
|
-
this.cachedOptionIds.size > 0) {
|
|
131
|
-
return {
|
|
132
|
-
projectId: this.cachedProjectId,
|
|
133
|
-
fieldId: this.cachedFieldId,
|
|
134
|
-
optionIds: this.cachedOptionIds,
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
if (this.cachedProjectId !== null) {
|
|
138
|
-
const statusField = this.fetchStatusField(this.cachedProjectId);
|
|
139
|
-
this.cachedFieldId = statusField.fieldId;
|
|
140
|
-
this.cachedOptionIds = statusField.optionIds;
|
|
141
|
-
return {
|
|
142
|
-
projectId: this.cachedProjectId,
|
|
143
|
-
fieldId: this.cachedFieldId,
|
|
144
|
-
optionIds: this.cachedOptionIds,
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
const projectNumber = this.config.projectNumber;
|
|
148
|
-
if (!projectNumber) {
|
|
149
|
-
throw new Error("No projectNumber configured. Run `night-watch board setup` first.");
|
|
150
|
-
}
|
|
151
|
-
const ownerLogins = new Set([this.getRepoOwnerLogin()]);
|
|
152
|
-
try {
|
|
153
|
-
ownerLogins.add(getViewerLogin(this.cwd));
|
|
154
|
-
}
|
|
155
|
-
catch {
|
|
156
|
-
// ignore fallback if viewer lookup fails
|
|
157
|
-
}
|
|
158
|
-
let projectNode = null;
|
|
159
|
-
for (const login of ownerLogins) {
|
|
160
|
-
projectNode = this.fetchProjectNode(login, projectNumber);
|
|
161
|
-
if (projectNode) {
|
|
162
|
-
break;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
if (!projectNode) {
|
|
166
|
-
throw new Error(`GitHub Project #${projectNumber} not found for repository owner "${this.getRepoOwnerLogin()}".`);
|
|
167
|
-
}
|
|
168
|
-
this.cachedProjectId = projectNode.id;
|
|
169
|
-
const statusField = this.fetchStatusField(projectNode.id);
|
|
170
|
-
this.cachedFieldId = statusField.fieldId;
|
|
171
|
-
this.cachedOptionIds = statusField.optionIds;
|
|
172
|
-
return {
|
|
173
|
-
projectId: this.cachedProjectId,
|
|
174
|
-
fieldId: this.cachedFieldId,
|
|
175
|
-
optionIds: this.cachedOptionIds,
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
/** Try user query first, fall back to org query. */
|
|
179
|
-
fetchProjectNode(login, projectNumber) {
|
|
180
|
-
try {
|
|
181
|
-
const userData = graphql(`query GetProject($login: String!, $number: Int!) {
|
|
182
|
-
user(login: $login) {
|
|
183
|
-
projectV2(number: $number) {
|
|
184
|
-
id
|
|
185
|
-
number
|
|
186
|
-
title
|
|
187
|
-
url
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}`, { login, number: projectNumber }, this.cwd);
|
|
191
|
-
if (userData.user?.projectV2) {
|
|
192
|
-
return userData.user.projectV2;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
catch {
|
|
196
|
-
// Swallow — try org query next
|
|
197
|
-
}
|
|
198
|
-
try {
|
|
199
|
-
const orgData = graphql(`query GetOrgProject($login: String!, $number: Int!) {
|
|
200
|
-
organization(login: $login) {
|
|
201
|
-
projectV2(number: $number) {
|
|
202
|
-
id
|
|
203
|
-
number
|
|
204
|
-
title
|
|
205
|
-
url
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}`, { login, number: projectNumber }, this.cwd);
|
|
209
|
-
if (orgData.organization?.projectV2) {
|
|
210
|
-
return orgData.organization.projectV2;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
catch {
|
|
214
|
-
// Swallow
|
|
215
|
-
}
|
|
216
|
-
return null;
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* Parse a raw project item node into IBoardIssue, returning null for items
|
|
220
|
-
* that are not issues.
|
|
221
|
-
*/
|
|
222
|
-
parseItem(item) {
|
|
223
|
-
const content = item.content;
|
|
224
|
-
if (!content || content.number === undefined) {
|
|
225
|
-
return null;
|
|
226
|
-
}
|
|
227
|
-
// Find the Status column value from the field values
|
|
228
|
-
let column = null;
|
|
229
|
-
for (const fv of item.fieldValues.nodes) {
|
|
230
|
-
if (fv.field?.name === "Status" && fv.name) {
|
|
231
|
-
const candidate = fv.name;
|
|
232
|
-
if (BOARD_COLUMNS.includes(candidate)) {
|
|
233
|
-
column = candidate;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
return {
|
|
238
|
-
id: content.id ?? item.id,
|
|
239
|
-
number: content.number,
|
|
240
|
-
title: content.title ?? "",
|
|
241
|
-
body: content.body ?? "",
|
|
242
|
-
url: content.url ?? "",
|
|
243
|
-
column,
|
|
244
|
-
labels: content.labels?.nodes.map((l) => l.name) ?? [],
|
|
245
|
-
assignees: content.assignees?.nodes.map((a) => a.login) ?? [],
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
// -------------------------------------------------------------------------
|
|
249
|
-
// IBoardProvider implementation
|
|
250
|
-
// -------------------------------------------------------------------------
|
|
251
|
-
/**
|
|
252
|
-
* Find an existing project by title among the repository owner's first 50 projects.
|
|
253
|
-
* Returns null if not found.
|
|
254
|
-
*/
|
|
255
|
-
findExistingProject(owner, title) {
|
|
256
|
-
try {
|
|
257
|
-
if (owner.type === "User") {
|
|
258
|
-
const data = graphql(`query ListUserProjects($login: String!) {
|
|
259
|
-
user(login: $login) {
|
|
260
|
-
projectsV2(first: 50) {
|
|
261
|
-
nodes { id number title url }
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}`, { login: owner.login }, this.cwd);
|
|
265
|
-
return data.user?.projectsV2.nodes.find((p) => p.title === title) ?? null;
|
|
266
|
-
}
|
|
267
|
-
const data = graphql(`query ListOrgProjects($login: String!) {
|
|
268
|
-
organization(login: $login) {
|
|
269
|
-
projectsV2(first: 50) {
|
|
270
|
-
nodes { id number title url }
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
}`, { login: owner.login }, this.cwd);
|
|
274
|
-
return data.organization?.projectsV2.nodes.find((p) => p.title === title) ?? null;
|
|
275
|
-
}
|
|
276
|
-
catch {
|
|
277
|
-
return null;
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
/**
|
|
281
|
-
* Ensure the Status field on an existing project has all five Night Watch
|
|
282
|
-
* lifecycle columns, updating it via GraphQL if any are missing.
|
|
283
|
-
*/
|
|
284
|
-
ensureStatusColumns(projectId) {
|
|
285
|
-
const fieldData = graphql(`query GetStatusField($projectId: ID!) {
|
|
286
|
-
node(id: $projectId) {
|
|
287
|
-
... on ProjectV2 {
|
|
288
|
-
field(name: "Status") {
|
|
289
|
-
... on ProjectV2SingleSelectField {
|
|
290
|
-
id
|
|
291
|
-
options { id name }
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
}`, { projectId }, this.cwd);
|
|
297
|
-
const field = fieldData.node?.field;
|
|
298
|
-
if (!field)
|
|
299
|
-
return;
|
|
300
|
-
const existing = new Set(field.options.map((o) => o.name));
|
|
301
|
-
const required = ["Draft", "Ready", "In Progress", "Review", "Done"];
|
|
302
|
-
const missing = required.filter((n) => !existing.has(n));
|
|
303
|
-
if (missing.length === 0)
|
|
304
|
-
return;
|
|
305
|
-
const colorMap = {
|
|
306
|
-
Draft: "GRAY",
|
|
307
|
-
Ready: "BLUE",
|
|
308
|
-
"In Progress": "YELLOW",
|
|
309
|
-
Review: "ORANGE",
|
|
310
|
-
Done: "GREEN",
|
|
311
|
-
};
|
|
312
|
-
const allOptions = required.map((name) => ({
|
|
313
|
-
name,
|
|
314
|
-
color: colorMap[name],
|
|
315
|
-
description: "",
|
|
316
|
-
}));
|
|
317
|
-
graphql(`mutation UpdateField($fieldId: ID!) {
|
|
318
|
-
updateProjectV2Field(input: {
|
|
319
|
-
fieldId: $fieldId,
|
|
320
|
-
singleSelectOptions: [
|
|
321
|
-
{ name: "Draft", color: GRAY, description: "" },
|
|
322
|
-
{ name: "Ready", color: BLUE, description: "" },
|
|
323
|
-
{ name: "In Progress", color: YELLOW, description: "" },
|
|
324
|
-
{ name: "Review", color: ORANGE, description: "" },
|
|
325
|
-
{ name: "Done", color: GREEN, description: "" }
|
|
326
|
-
]
|
|
327
|
-
}) {
|
|
328
|
-
projectV2Field {
|
|
329
|
-
... on ProjectV2SingleSelectField {
|
|
330
|
-
id
|
|
331
|
-
options { id name }
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
}`, { fieldId: field.id, allOptions }, this.cwd);
|
|
336
|
-
}
|
|
337
|
-
async setupBoard(title) {
|
|
338
|
-
const owner = this.getRepoOwner();
|
|
339
|
-
// Find or create — avoid duplicating boards on re-runs
|
|
340
|
-
const existing = this.findExistingProject(owner, title);
|
|
341
|
-
if (existing) {
|
|
342
|
-
this.cachedProjectId = existing.id;
|
|
343
|
-
this.linkProjectToRepository(existing.id);
|
|
344
|
-
this.ensureStatusColumns(existing.id);
|
|
345
|
-
return { id: existing.id, number: existing.number, title: existing.title, url: existing.url };
|
|
346
|
-
}
|
|
347
|
-
// Create the project
|
|
348
|
-
const createData = graphql(`mutation CreateProject($ownerId: ID!, $title: String!) {
|
|
349
|
-
createProjectV2(input: { ownerId: $ownerId, title: $title }) {
|
|
350
|
-
projectV2 {
|
|
351
|
-
id
|
|
352
|
-
number
|
|
353
|
-
url
|
|
354
|
-
title
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
}`, { ownerId: owner.id, title }, this.cwd);
|
|
358
|
-
const project = createData.createProjectV2.projectV2;
|
|
359
|
-
this.cachedProjectId = project.id;
|
|
360
|
-
this.linkProjectToRepository(project.id);
|
|
361
|
-
// New projects may already have a default Status field. Reuse/update it.
|
|
362
|
-
try {
|
|
363
|
-
const statusField = this.fetchStatusField(project.id);
|
|
364
|
-
this.cachedFieldId = statusField.fieldId;
|
|
365
|
-
this.cachedOptionIds = statusField.optionIds;
|
|
366
|
-
this.ensureStatusColumns(project.id);
|
|
367
|
-
const refreshed = this.fetchStatusField(project.id);
|
|
368
|
-
this.cachedFieldId = refreshed.fieldId;
|
|
369
|
-
this.cachedOptionIds = refreshed.optionIds;
|
|
370
|
-
}
|
|
371
|
-
catch (err) {
|
|
372
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
373
|
-
if (!message.includes("Status field not found")) {
|
|
374
|
-
throw err;
|
|
375
|
-
}
|
|
376
|
-
const createFieldData = graphql(`mutation CreateStatusField($projectId: ID!) {
|
|
377
|
-
createProjectV2Field(input: {
|
|
378
|
-
projectId: $projectId,
|
|
379
|
-
dataType: SINGLE_SELECT,
|
|
380
|
-
name: "Status",
|
|
381
|
-
singleSelectOptions: [
|
|
382
|
-
{ name: "Draft", color: GRAY, description: "" },
|
|
383
|
-
{ name: "Ready", color: BLUE, description: "" },
|
|
384
|
-
{ name: "In Progress", color: YELLOW, description: "" },
|
|
385
|
-
{ name: "Review", color: ORANGE, description: "" },
|
|
386
|
-
{ name: "Done", color: GREEN, description: "" }
|
|
387
|
-
]
|
|
388
|
-
}) {
|
|
389
|
-
projectV2Field {
|
|
390
|
-
... on ProjectV2SingleSelectField {
|
|
391
|
-
id
|
|
392
|
-
options { id name }
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
}`, { projectId: project.id }, this.cwd);
|
|
397
|
-
const field = createFieldData.createProjectV2Field.projectV2Field;
|
|
398
|
-
this.cachedFieldId = field.id;
|
|
399
|
-
this.cachedOptionIds = new Map(field.options.map((o) => [o.name, o.id]));
|
|
400
|
-
}
|
|
401
|
-
return { id: project.id, number: project.number, title: project.title, url: project.url };
|
|
402
|
-
}
|
|
403
|
-
async getBoard() {
|
|
404
|
-
const projectNumber = this.config.projectNumber;
|
|
405
|
-
if (!projectNumber) {
|
|
406
|
-
return null;
|
|
407
|
-
}
|
|
408
|
-
try {
|
|
409
|
-
const ownerLogins = new Set([this.getRepoOwnerLogin()]);
|
|
410
|
-
try {
|
|
411
|
-
ownerLogins.add(getViewerLogin(this.cwd));
|
|
412
|
-
}
|
|
413
|
-
catch {
|
|
414
|
-
// ignore fallback if viewer lookup fails
|
|
415
|
-
}
|
|
416
|
-
let node = null;
|
|
417
|
-
for (const login of ownerLogins) {
|
|
418
|
-
node = this.fetchProjectNode(login, projectNumber);
|
|
419
|
-
if (node) {
|
|
420
|
-
break;
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
if (!node) {
|
|
424
|
-
return null;
|
|
425
|
-
}
|
|
426
|
-
return { id: node.id, number: node.number, title: node.title, url: node.url };
|
|
427
|
-
}
|
|
428
|
-
catch {
|
|
429
|
-
return null;
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
async getColumns() {
|
|
433
|
-
const { fieldId, optionIds } = await this.ensureProjectCache();
|
|
434
|
-
return BOARD_COLUMNS.map((name) => ({
|
|
435
|
-
id: optionIds.get(name) ?? fieldId,
|
|
436
|
-
name,
|
|
437
|
-
}));
|
|
438
|
-
}
|
|
439
|
-
async createIssue(input) {
|
|
440
|
-
const repo = this.getRepo();
|
|
441
|
-
const { projectId, fieldId, optionIds } = await this.ensureProjectCache();
|
|
442
|
-
// Create the issue via gh CLI (outputs URL, e.g. https://github.com/owner/repo/issues/123)
|
|
443
|
-
const issueArgs = [
|
|
444
|
-
"issue",
|
|
445
|
-
"create",
|
|
446
|
-
"--title",
|
|
447
|
-
input.title,
|
|
448
|
-
"--body",
|
|
449
|
-
input.body,
|
|
450
|
-
"--repo",
|
|
451
|
-
repo,
|
|
452
|
-
];
|
|
453
|
-
if (input.labels && input.labels.length > 0) {
|
|
454
|
-
issueArgs.push("--label", input.labels.join(","));
|
|
455
|
-
}
|
|
456
|
-
const issueUrl = execFileSync("gh", issueArgs, {
|
|
457
|
-
cwd: this.cwd,
|
|
458
|
-
encoding: "utf-8",
|
|
459
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
460
|
-
}).trim();
|
|
461
|
-
const issueNumber = parseInt(issueUrl.split("/").pop() ?? "", 10);
|
|
462
|
-
if (!issueNumber) {
|
|
463
|
-
throw new Error(`Failed to parse issue number from URL: ${issueUrl}`);
|
|
464
|
-
}
|
|
465
|
-
// Fetch the node ID needed for the GraphQL project mutation
|
|
466
|
-
const [owner, repoName] = repo.split("/");
|
|
467
|
-
const nodeIdOutput = execFileSync("gh", ["api", `repos/${owner}/${repoName}/issues/${issueNumber}`, "--jq", ".node_id"], { cwd: this.cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
468
|
-
const issueJson = { number: issueNumber, id: nodeIdOutput, url: issueUrl };
|
|
469
|
-
// Add the issue to the project board
|
|
470
|
-
const addData = graphql(`mutation AddProjectItem($projectId: ID!, $contentId: ID!) {
|
|
471
|
-
addProjectV2ItemById(input: { projectId: $projectId, contentId: $contentId }) {
|
|
472
|
-
item {
|
|
473
|
-
id
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
}`, { projectId, contentId: issueJson.id }, this.cwd);
|
|
477
|
-
const itemId = addData.addProjectV2ItemById.item.id;
|
|
478
|
-
const targetColumn = input.column ?? "Draft";
|
|
479
|
-
const optionId = optionIds.get(targetColumn);
|
|
480
|
-
if (optionId) {
|
|
481
|
-
graphql(`mutation UpdateItemField(
|
|
482
|
-
$projectId: ID!,
|
|
483
|
-
$itemId: ID!,
|
|
484
|
-
$fieldId: ID!,
|
|
485
|
-
$optionId: String!
|
|
486
|
-
) {
|
|
487
|
-
updateProjectV2ItemFieldValue(input: {
|
|
488
|
-
projectId: $projectId,
|
|
489
|
-
itemId: $itemId,
|
|
490
|
-
fieldId: $fieldId,
|
|
491
|
-
value: { singleSelectOptionId: $optionId }
|
|
492
|
-
}) {
|
|
493
|
-
projectV2Item {
|
|
494
|
-
id
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
}`, { projectId, itemId, fieldId, optionId }, this.cwd);
|
|
498
|
-
}
|
|
499
|
-
// Fetch the full issue details so we can return a complete IBoardIssue
|
|
500
|
-
const fullIssue = await this.getIssue(issueJson.number);
|
|
501
|
-
if (fullIssue) {
|
|
502
|
-
return { ...fullIssue, column: targetColumn };
|
|
503
|
-
}
|
|
504
|
-
return {
|
|
505
|
-
id: issueJson.id,
|
|
506
|
-
number: issueJson.number,
|
|
507
|
-
title: input.title,
|
|
508
|
-
body: input.body,
|
|
509
|
-
url: issueJson.url,
|
|
510
|
-
column: targetColumn,
|
|
511
|
-
labels: input.labels ?? [],
|
|
512
|
-
assignees: [],
|
|
513
|
-
};
|
|
514
|
-
}
|
|
515
|
-
async getIssue(issueNumber) {
|
|
516
|
-
const repo = this.getRepo();
|
|
517
|
-
let rawIssue;
|
|
518
|
-
try {
|
|
519
|
-
const output = execFileSync("gh", [
|
|
520
|
-
"issue",
|
|
521
|
-
"view",
|
|
522
|
-
String(issueNumber),
|
|
523
|
-
"--repo",
|
|
524
|
-
repo,
|
|
525
|
-
"--json",
|
|
526
|
-
"number,title,body,url,id,labels,assignees",
|
|
527
|
-
], { cwd: this.cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
|
|
528
|
-
rawIssue = JSON.parse(output);
|
|
529
|
-
}
|
|
530
|
-
catch {
|
|
531
|
-
return null;
|
|
532
|
-
}
|
|
533
|
-
// Find which column this issue sits in by scanning all board items
|
|
534
|
-
let column = null;
|
|
535
|
-
try {
|
|
536
|
-
const allIssues = await this.getAllIssues();
|
|
537
|
-
const match = allIssues.find((i) => i.number === issueNumber);
|
|
538
|
-
if (match) {
|
|
539
|
-
column = match.column;
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
catch {
|
|
543
|
-
// Column stays null
|
|
544
|
-
}
|
|
545
|
-
return {
|
|
546
|
-
id: rawIssue.id,
|
|
547
|
-
number: rawIssue.number,
|
|
548
|
-
title: rawIssue.title,
|
|
549
|
-
body: rawIssue.body,
|
|
550
|
-
url: rawIssue.url,
|
|
551
|
-
column,
|
|
552
|
-
labels: rawIssue.labels.map((l) => l.name),
|
|
553
|
-
assignees: rawIssue.assignees.map((a) => a.login),
|
|
554
|
-
};
|
|
555
|
-
}
|
|
556
|
-
async getIssuesByColumn(column) {
|
|
557
|
-
const all = await this.getAllIssues();
|
|
558
|
-
return all.filter((issue) => issue.column === column);
|
|
559
|
-
}
|
|
560
|
-
async getAllIssues() {
|
|
561
|
-
const { projectId } = await this.ensureProjectCache();
|
|
562
|
-
const data = graphql(`query GetProjectItems($projectId: ID!) {
|
|
563
|
-
node(id: $projectId) {
|
|
564
|
-
... on ProjectV2 {
|
|
565
|
-
items(first: 100) {
|
|
566
|
-
nodes {
|
|
567
|
-
id
|
|
568
|
-
content {
|
|
569
|
-
... on Issue {
|
|
570
|
-
number
|
|
571
|
-
title
|
|
572
|
-
body
|
|
573
|
-
url
|
|
574
|
-
id
|
|
575
|
-
labels(first: 10) { nodes { name } }
|
|
576
|
-
assignees(first: 10) { nodes { login } }
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
fieldValues(first: 10) {
|
|
580
|
-
nodes {
|
|
581
|
-
... on ProjectV2ItemFieldSingleSelectValue {
|
|
582
|
-
name
|
|
583
|
-
field {
|
|
584
|
-
... on ProjectV2SingleSelectField {
|
|
585
|
-
name
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
}`, { projectId }, this.cwd);
|
|
596
|
-
const results = [];
|
|
597
|
-
for (const item of data.node.items.nodes) {
|
|
598
|
-
const parsed = this.parseItem(item);
|
|
599
|
-
if (parsed) {
|
|
600
|
-
results.push(parsed);
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
return results;
|
|
604
|
-
}
|
|
605
|
-
async moveIssue(issueNumber, targetColumn) {
|
|
606
|
-
const { projectId, fieldId, optionIds } = await this.ensureProjectCache();
|
|
607
|
-
// Fetch project items to find the item node ID for the target issue
|
|
608
|
-
const data = graphql(`query GetProjectItems($projectId: ID!) {
|
|
609
|
-
node(id: $projectId) {
|
|
610
|
-
... on ProjectV2 {
|
|
611
|
-
items(first: 100) {
|
|
612
|
-
nodes {
|
|
613
|
-
id
|
|
614
|
-
content {
|
|
615
|
-
... on Issue {
|
|
616
|
-
number
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
fieldValues(first: 10) {
|
|
620
|
-
nodes {
|
|
621
|
-
... on ProjectV2ItemFieldSingleSelectValue {
|
|
622
|
-
name
|
|
623
|
-
field {
|
|
624
|
-
... on ProjectV2SingleSelectField {
|
|
625
|
-
name
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
}`, { projectId }, this.cwd);
|
|
636
|
-
// Find the project item for this issue number
|
|
637
|
-
const itemNode = data.node.items.nodes.find((n) => n.content?.number === issueNumber);
|
|
638
|
-
if (!itemNode) {
|
|
639
|
-
throw new Error(`Issue #${issueNumber} not found on the project board.`);
|
|
640
|
-
}
|
|
641
|
-
const optionId = optionIds.get(targetColumn);
|
|
642
|
-
if (!optionId) {
|
|
643
|
-
throw new Error(`Column "${targetColumn}" not found on the project board.`);
|
|
644
|
-
}
|
|
645
|
-
graphql(`mutation UpdateItemField(
|
|
646
|
-
$projectId: ID!,
|
|
647
|
-
$itemId: ID!,
|
|
648
|
-
$fieldId: ID!,
|
|
649
|
-
$optionId: String!
|
|
650
|
-
) {
|
|
651
|
-
updateProjectV2ItemFieldValue(input: {
|
|
652
|
-
projectId: $projectId,
|
|
653
|
-
itemId: $itemId,
|
|
654
|
-
fieldId: $fieldId,
|
|
655
|
-
value: { singleSelectOptionId: $optionId }
|
|
656
|
-
}) {
|
|
657
|
-
projectV2Item {
|
|
658
|
-
id
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
}`, { projectId, itemId: itemNode.id, fieldId, optionId }, this.cwd);
|
|
662
|
-
}
|
|
663
|
-
async closeIssue(issueNumber) {
|
|
664
|
-
const repo = this.getRepo();
|
|
665
|
-
execFileSync("gh", ["issue", "close", String(issueNumber), "--repo", repo], { cwd: this.cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
|
|
666
|
-
}
|
|
667
|
-
async commentOnIssue(issueNumber, body) {
|
|
668
|
-
const repo = this.getRepo();
|
|
669
|
-
execFileSync("gh", ["issue", "comment", String(issueNumber), "--repo", repo, "--body", body], { cwd: this.cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
//# sourceMappingURL=github-projects.js.map
|