@nulab/bee 0.0.0 → 1.0.0-rc.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.
Files changed (135) hide show
  1. package/README.md +36 -0
  2. package/bin/cli.mjs +2 -0
  3. package/dist/chunks/activities.mjs +90 -0
  4. package/dist/chunks/activities2.mjs +91 -0
  5. package/dist/chunks/activities3.mjs +91 -0
  6. package/dist/chunks/add-user.mjs +42 -0
  7. package/dist/chunks/add.mjs +62 -0
  8. package/dist/chunks/add2.mjs +40 -0
  9. package/dist/chunks/api.mjs +138 -0
  10. package/dist/chunks/attachments.mjs +48 -0
  11. package/dist/chunks/attachments2.mjs +48 -0
  12. package/dist/chunks/attachments3.mjs +49 -0
  13. package/dist/chunks/browse.mjs +270 -0
  14. package/dist/chunks/clone.mjs +61 -0
  15. package/dist/chunks/close.mjs +51 -0
  16. package/dist/chunks/comment.mjs +124 -0
  17. package/dist/chunks/comment2.mjs +112 -0
  18. package/dist/chunks/comments.mjs +58 -0
  19. package/dist/chunks/completion.mjs +118 -0
  20. package/dist/chunks/count.mjs +74 -0
  21. package/dist/chunks/count2.mjs +70 -0
  22. package/dist/chunks/count3.mjs +60 -0
  23. package/dist/chunks/count4.mjs +35 -0
  24. package/dist/chunks/count5.mjs +53 -0
  25. package/dist/chunks/create.mjs +61 -0
  26. package/dist/chunks/create2.mjs +83 -0
  27. package/dist/chunks/create3.mjs +65 -0
  28. package/dist/chunks/create4.mjs +74 -0
  29. package/dist/chunks/create5.mjs +57 -0
  30. package/dist/chunks/create6.mjs +38 -0
  31. package/dist/chunks/create7.mjs +46 -0
  32. package/dist/chunks/create8.mjs +50 -0
  33. package/dist/chunks/create9.mjs +50 -0
  34. package/dist/chunks/dashboard.mjs +85 -0
  35. package/dist/chunks/delete.mjs +48 -0
  36. package/dist/chunks/delete2.mjs +47 -0
  37. package/dist/chunks/delete3.mjs +47 -0
  38. package/dist/chunks/delete4.mjs +47 -0
  39. package/dist/chunks/delete5.mjs +48 -0
  40. package/dist/chunks/delete6.mjs +48 -0
  41. package/dist/chunks/delete7.mjs +55 -0
  42. package/dist/chunks/delete8.mjs +54 -0
  43. package/dist/chunks/delete9.mjs +49 -0
  44. package/dist/chunks/edit.mjs +56 -0
  45. package/dist/chunks/edit2.mjs +73 -0
  46. package/dist/chunks/edit3.mjs +65 -0
  47. package/dist/chunks/edit4.mjs +52 -0
  48. package/dist/chunks/edit5.mjs +38 -0
  49. package/dist/chunks/edit6.mjs +51 -0
  50. package/dist/chunks/edit7.mjs +47 -0
  51. package/dist/chunks/edit8.mjs +47 -0
  52. package/dist/chunks/history.mjs +57 -0
  53. package/dist/chunks/index.mjs +15 -0
  54. package/dist/chunks/index10.mjs +18 -0
  55. package/dist/chunks/index11.mjs +13 -0
  56. package/dist/chunks/index12.mjs +13 -0
  57. package/dist/chunks/index13.mjs +13 -0
  58. package/dist/chunks/index14.mjs +8 -0
  59. package/dist/chunks/index15.mjs +13 -0
  60. package/dist/chunks/index16.mjs +13 -0
  61. package/dist/chunks/index17.mjs +14 -0
  62. package/dist/chunks/index2.mjs +18 -0
  63. package/dist/chunks/index3.mjs +20 -0
  64. package/dist/chunks/index4.mjs +15 -0
  65. package/dist/chunks/index5.mjs +13 -0
  66. package/dist/chunks/index6.mjs +17 -0
  67. package/dist/chunks/index7.mjs +8 -0
  68. package/dist/chunks/index8.mjs +8 -0
  69. package/dist/chunks/index9.mjs +13 -0
  70. package/dist/chunks/list.mjs +53 -0
  71. package/dist/chunks/list10.mjs +44 -0
  72. package/dist/chunks/list11.mjs +49 -0
  73. package/dist/chunks/list12.mjs +45 -0
  74. package/dist/chunks/list13.mjs +45 -0
  75. package/dist/chunks/list14.mjs +55 -0
  76. package/dist/chunks/list15.mjs +47 -0
  77. package/dist/chunks/list2.mjs +95 -0
  78. package/dist/chunks/list3.mjs +86 -0
  79. package/dist/chunks/list4.mjs +80 -0
  80. package/dist/chunks/list5.mjs +78 -0
  81. package/dist/chunks/list6.mjs +45 -0
  82. package/dist/chunks/list7.mjs +49 -0
  83. package/dist/chunks/list8.mjs +47 -0
  84. package/dist/chunks/list9.mjs +53 -0
  85. package/dist/chunks/login.mjs +206 -0
  86. package/dist/chunks/logout.mjs +57 -0
  87. package/dist/chunks/me.mjs +49 -0
  88. package/dist/chunks/read-all.mjs +30 -0
  89. package/dist/chunks/read.mjs +30 -0
  90. package/dist/chunks/read2.mjs +28 -0
  91. package/dist/chunks/refresh.mjs +77 -0
  92. package/dist/chunks/remove-user.mjs +42 -0
  93. package/dist/chunks/remove.mjs +28 -0
  94. package/dist/chunks/reopen.mjs +43 -0
  95. package/dist/chunks/status.mjs +62 -0
  96. package/dist/chunks/status2.mjs +62 -0
  97. package/dist/chunks/status3.mjs +67 -0
  98. package/dist/chunks/switch.mjs +52 -0
  99. package/dist/chunks/tags.mjs +41 -0
  100. package/dist/chunks/token.mjs +39 -0
  101. package/dist/chunks/tree.mjs +61 -0
  102. package/dist/chunks/users.mjs +48 -0
  103. package/dist/chunks/view.mjs +58 -0
  104. package/dist/chunks/view2.mjs +95 -0
  105. package/dist/chunks/view3.mjs +69 -0
  106. package/dist/chunks/view4.mjs +71 -0
  107. package/dist/chunks/view5.mjs +62 -0
  108. package/dist/chunks/view6.mjs +53 -0
  109. package/dist/chunks/view7.mjs +49 -0
  110. package/dist/chunks/view8.mjs +62 -0
  111. package/dist/chunks/view9.mjs +49 -0
  112. package/dist/index.mjs +152 -0
  113. package/dist/shared/bee.-8tk76YJ.mjs +42 -0
  114. package/dist/shared/bee.BTBGpv4K.mjs +34 -0
  115. package/dist/shared/bee.BXiuAfjJ.mjs +10 -0
  116. package/dist/shared/bee.BeQSH2t0.mjs +25 -0
  117. package/dist/shared/bee.Btmq3TXs.mjs +19 -0
  118. package/dist/shared/bee.C--ZWPxf.mjs +14 -0
  119. package/dist/shared/bee.CCNmDHVv.mjs +33 -0
  120. package/dist/shared/bee.CQ3kBgas.mjs +58 -0
  121. package/dist/shared/bee.CThuQMit.mjs +124 -0
  122. package/dist/shared/bee.ChBdZ0cH.mjs +9 -0
  123. package/dist/shared/bee.CktwmH8R.mjs +25 -0
  124. package/dist/shared/bee.CzKcWSES.mjs +42 -0
  125. package/dist/shared/bee.D6yQ6Pqf.mjs +18 -0
  126. package/dist/shared/bee.DHTPkjMh.mjs +48 -0
  127. package/dist/shared/bee.DVTuFf-T.mjs +276 -0
  128. package/dist/shared/bee.DoTvz3uW.mjs +13 -0
  129. package/dist/shared/bee.Ds2l-nTJ.mjs +308 -0
  130. package/dist/shared/bee.IM3QELRf.mjs +32 -0
  131. package/dist/shared/bee.XxOB1Her.mjs +8 -0
  132. package/dist/shared/bee.n5MYN4a6.mjs +12 -0
  133. package/dist/shared/bee.sHWg0IFT.mjs +22 -0
  134. package/package.json +50 -2
  135. package/.github/workflows/initial-release.yml +0 -23
@@ -0,0 +1,48 @@
1
+ import consola from 'consola';
2
+ import { g as getClient } from '../shared/bee.CThuQMit.mjs';
3
+ import 'backlog-js';
4
+ import 'node:http';
5
+ import 'open';
6
+ import 'node:child_process';
7
+ import { o as outputResult } from '../shared/bee.BTBGpv4K.mjs';
8
+ import 'node:stream/consumers';
9
+ import 'valibot';
10
+ import { a as formatSize, f as formatDate } from '../shared/bee.n5MYN4a6.mjs';
11
+ import { p as printTable } from '../shared/bee.IM3QELRf.mjs';
12
+ import { B as BeeCommand, E as ENV_AUTH } from '../shared/bee.CQ3kBgas.mjs';
13
+ import { j as json, s as space } from '../shared/bee.DHTPkjMh.mjs';
14
+ import '../shared/bee.XxOB1Her.mjs';
15
+ import '../shared/bee.CktwmH8R.mjs';
16
+ import '../shared/bee.DVTuFf-T.mjs';
17
+ import 'node:fs';
18
+ import 'node:path';
19
+ import 'node:os';
20
+ import '../shared/bee.BeQSH2t0.mjs';
21
+ import '../shared/bee.-8tk76YJ.mjs';
22
+ import '../shared/bee.Ds2l-nTJ.mjs';
23
+ import 'commander';
24
+ import 'consola/utils';
25
+
26
+ const attachments = new BeeCommand("attachments").summary("List document attachments").description(`Shows file name, size, creator, and creation date.`).argument("<document>", "Document ID").addOption(json()).addOption(space()).envVars([...ENV_AUTH]).examples([
27
+ { description: "List attachments", command: "bee document attachments 12345" },
28
+ { description: "Output as JSON", command: "bee document attachments 12345 --json" }
29
+ ]).action(async (document, opts) => {
30
+ const { client } = await getClient(opts.space);
31
+ const doc = await client.getDocument(document);
32
+ outputResult(doc.attachments, opts, (data) => {
33
+ if (data.length === 0) {
34
+ consola.info("No attachments found.");
35
+ return;
36
+ }
37
+ const rows = data.map((file) => [
38
+ { header: "ID", value: String(file.id) },
39
+ { header: "NAME", value: file.name },
40
+ { header: "SIZE", value: formatSize(file.size) },
41
+ { header: "CREATED BY", value: file.createdUser?.name ?? "Unknown" },
42
+ { header: "CREATED", value: formatDate(file.created) }
43
+ ]);
44
+ printTable(rows);
45
+ });
46
+ });
47
+
48
+ export { attachments as default };
@@ -0,0 +1,49 @@
1
+ import consola from 'consola';
2
+ import { g as getClient } from '../shared/bee.CThuQMit.mjs';
3
+ import 'backlog-js';
4
+ import 'node:http';
5
+ import 'open';
6
+ import 'node:child_process';
7
+ import { o as outputResult } from '../shared/bee.BTBGpv4K.mjs';
8
+ import 'node:stream/consumers';
9
+ import 'valibot';
10
+ import { f as formatDate } from '../shared/bee.n5MYN4a6.mjs';
11
+ import { p as printTable } from '../shared/bee.IM3QELRf.mjs';
12
+ import { B as BeeCommand, E as ENV_AUTH } from '../shared/bee.CQ3kBgas.mjs';
13
+ import { j as json, s as space } from '../shared/bee.DHTPkjMh.mjs';
14
+ import '../shared/bee.XxOB1Her.mjs';
15
+ import '../shared/bee.CktwmH8R.mjs';
16
+ import '../shared/bee.DVTuFf-T.mjs';
17
+ import 'node:fs';
18
+ import 'node:path';
19
+ import 'node:os';
20
+ import '../shared/bee.BeQSH2t0.mjs';
21
+ import '../shared/bee.-8tk76YJ.mjs';
22
+ import '../shared/bee.Ds2l-nTJ.mjs';
23
+ import 'commander';
24
+ import 'consola/utils';
25
+
26
+ const attachments = new BeeCommand("attachments").summary("List wiki page attachments").description(`Shows file name, size, creator, and creation date.`).argument("<wiki>", "Wiki page ID").addOption(json()).addOption(space()).envVars([...ENV_AUTH]).examples([
27
+ { description: "List wiki attachments", command: "bee wiki attachments 12345" },
28
+ { description: "Output as JSON", command: "bee wiki attachments 12345 --json" }
29
+ ]).action(async (wiki, opts) => {
30
+ const { client } = await getClient(opts.space);
31
+ const files = await client.getWikisAttachments(Number(wiki));
32
+ outputResult(files, opts, (data) => {
33
+ if (data.length === 0) {
34
+ consola.info("No attachments found.");
35
+ return;
36
+ }
37
+ const rows = data.map(
38
+ (f) => [
39
+ { header: "NAME", value: f.name },
40
+ { header: "SIZE", value: String(f.size) },
41
+ { header: "CREATED BY", value: f.createdUser.name },
42
+ { header: "CREATED", value: formatDate(f.created) }
43
+ ]
44
+ );
45
+ printTable(rows);
46
+ });
47
+ });
48
+
49
+ export { attachments as default };
@@ -0,0 +1,270 @@
1
+ import consola from 'consola';
2
+ import { g as getClient } from '../shared/bee.CThuQMit.mjs';
3
+ import 'backlog-js';
4
+ import 'node:http';
5
+ import { i as issueUrl, b as buildBacklogUrl, p as projectUrl, r as repositoryUrl, d as dashboardUrl, g as gitCommitUrl, a as gitTreeUrl, c as gitBlobUrl, o as openOrPrintUrl } from '../shared/bee.CzKcWSES.mjs';
6
+ import { execFile } from 'node:child_process';
7
+ import { U as UserError } from '../shared/bee.XxOB1Her.mjs';
8
+ import 'node:stream/consumers';
9
+ import 'valibot';
10
+ import { B as BeeCommand, E as ENV_AUTH, a as ENV_PROJECT } from '../shared/bee.CQ3kBgas.mjs';
11
+ import { p as project, n as noBrowser, s as space } from '../shared/bee.DHTPkjMh.mjs';
12
+ import '../shared/bee.BeQSH2t0.mjs';
13
+ import '../shared/bee.CktwmH8R.mjs';
14
+ import '../shared/bee.DVTuFf-T.mjs';
15
+ import 'node:fs';
16
+ import 'node:path';
17
+ import 'node:os';
18
+ import '../shared/bee.-8tk76YJ.mjs';
19
+ import 'open';
20
+ import 'commander';
21
+ import 'consola/utils';
22
+
23
+ const parseBacklogRemoteUrl = (url) => {
24
+ const sshUrlMatch = url.match(
25
+ /^ssh:\/\/[^@]+@([^.]+)\.git\.(backlog\.(?:com|jp))\/([^/]+)\/([^/.]+?)(?:\.git)?$/
26
+ );
27
+ if (sshUrlMatch) {
28
+ const [, space, domain, projectKey, repoName] = sshUrlMatch;
29
+ return {
30
+ host: `${space}.${domain}`,
31
+ projectKey,
32
+ repoName
33
+ };
34
+ }
35
+ const scpMatch = url.match(
36
+ /^[^@]+@([^.]+)\.git\.(backlog\.(?:com|jp)):\/?([^/]+)\/([^/.]+?)(?:\.git)?$/
37
+ );
38
+ if (scpMatch) {
39
+ const [, space, domain, projectKey, repoName] = scpMatch;
40
+ return {
41
+ host: `${space}.${domain}`,
42
+ projectKey,
43
+ repoName
44
+ };
45
+ }
46
+ const httpsMatch = url.match(
47
+ /^https?:\/\/(.+\.backlog\.(?:com|jp))\/git\/([^/]+)\/([^/]+?)(?:\.git)?$/
48
+ );
49
+ if (httpsMatch) {
50
+ const [, host, projectKey, repoName] = httpsMatch;
51
+ return {
52
+ host,
53
+ projectKey,
54
+ repoName
55
+ };
56
+ }
57
+ return void 0;
58
+ };
59
+ const execGit = (args, cwd) => new Promise((resolve, reject) => {
60
+ execFile("git", args, { cwd }, (error, stdout) => {
61
+ if (error) {
62
+ reject(error);
63
+ return;
64
+ }
65
+ resolve(stdout.trim());
66
+ });
67
+ });
68
+ const detectGitContext = async (cwd) => {
69
+ try {
70
+ const remoteUrl = await execGit(["remote", "get-url", "origin"], cwd);
71
+ return parseBacklogRemoteUrl(remoteUrl);
72
+ } catch {
73
+ return void 0;
74
+ }
75
+ };
76
+ const getCurrentBranch = async (cwd) => {
77
+ try {
78
+ return await execGit(["rev-parse", "--abbrev-ref", "HEAD"], cwd);
79
+ } catch {
80
+ return void 0;
81
+ }
82
+ };
83
+ const getLatestCommit = async (cwd) => {
84
+ try {
85
+ return await execGit(["rev-parse", "HEAD"], cwd);
86
+ } catch {
87
+ return void 0;
88
+ }
89
+ };
90
+ const getRepoRelativePath = async (cwd) => {
91
+ try {
92
+ const prefix = await execGit(["rev-parse", "--show-prefix"], cwd);
93
+ return prefix || void 0;
94
+ } catch {
95
+ return void 0;
96
+ }
97
+ };
98
+
99
+ const ISSUE_KEY_PATTERN = /^[A-Z][A-Z0-9_]+-\d+$/;
100
+ const ISSUE_NUMBER_PATTERN = /^\d+$/;
101
+ const FILE_LINE_PATTERN = /^(.+):(\d+)$/;
102
+ const resolveUrl = (host, args, git) => {
103
+ if (args.target && ISSUE_KEY_PATTERN.test(args.target)) {
104
+ return { ok: true, url: issueUrl(host, args.target) };
105
+ }
106
+ if (args.target && ISSUE_NUMBER_PATTERN.test(args.target)) {
107
+ const projectKey2 = args.project ?? git.context?.projectKey;
108
+ if (projectKey2) {
109
+ return { ok: true, url: issueUrl(host, `${projectKey2}-${args.target}`) };
110
+ }
111
+ return {
112
+ ok: false,
113
+ error: "Cannot resolve issue number without a project. Use --project or run inside a Backlog repository."
114
+ };
115
+ }
116
+ if (args.target && isFilePath(args.target)) {
117
+ return resolveFileUrl(host, args, git);
118
+ }
119
+ const projectKey = args.target ?? args.project ?? git.context?.projectKey;
120
+ if (projectKey) {
121
+ if (args.issues) {
122
+ return { ok: true, url: buildBacklogUrl(host, `/find/${projectKey}`) };
123
+ }
124
+ if (args.board) {
125
+ return { ok: true, url: buildBacklogUrl(host, `/board/${projectKey}`) };
126
+ }
127
+ if (args.gantt) {
128
+ return { ok: true, url: buildBacklogUrl(host, `/gantt/${projectKey}`) };
129
+ }
130
+ if (args.wiki) {
131
+ return { ok: true, url: buildBacklogUrl(host, `/wiki/${projectKey}`) };
132
+ }
133
+ if (args.documents) {
134
+ return { ok: true, url: buildBacklogUrl(host, `/document/${projectKey}`) };
135
+ }
136
+ if (args.files) {
137
+ return { ok: true, url: buildBacklogUrl(host, `/file/${projectKey}`) };
138
+ }
139
+ if (args.git) {
140
+ return { ok: true, url: buildBacklogUrl(host, `/git/${projectKey}`) };
141
+ }
142
+ if (args.svn) {
143
+ return { ok: true, url: buildBacklogUrl(host, `/subversion/${projectKey}`) };
144
+ }
145
+ if (args.settings) {
146
+ return {
147
+ ok: true,
148
+ url: buildBacklogUrl(host, `/EditProject.action?project.id=${projectKey}`)
149
+ };
150
+ }
151
+ }
152
+ if (args.branch || args.commit) {
153
+ return resolveFileUrl(host, args, git);
154
+ }
155
+ if (args.target) {
156
+ return { ok: true, url: projectUrl(host, args.target) };
157
+ }
158
+ if (git.context) {
159
+ return {
160
+ ok: true,
161
+ url: repositoryUrl(host, git.context.projectKey, git.context.repoName)
162
+ };
163
+ }
164
+ return { ok: true, url: dashboardUrl(host) };
165
+ };
166
+ const isFilePath = (target) => {
167
+ if (target.includes("/")) {
168
+ return true;
169
+ }
170
+ if (FILE_LINE_PATTERN.test(target)) {
171
+ return true;
172
+ }
173
+ if (target.includes(".") && !ISSUE_KEY_PATTERN.test(target)) {
174
+ return true;
175
+ }
176
+ return false;
177
+ };
178
+ const resolveFileUrl = (host, args, git) => {
179
+ if (!git.context) {
180
+ return {
181
+ ok: false,
182
+ error: "Not inside a Backlog Git repository. Cannot resolve file path."
183
+ };
184
+ }
185
+ let ref;
186
+ if (args.commit) {
187
+ if (!git.latestCommit) {
188
+ return { ok: false, error: "Could not determine the latest commit." };
189
+ }
190
+ if (!args.target) {
191
+ return {
192
+ ok: true,
193
+ url: gitCommitUrl(host, git.context.projectKey, git.context.repoName, git.latestCommit)
194
+ };
195
+ }
196
+ ref = git.latestCommit;
197
+ } else if (args.branch) {
198
+ ref = args.branch;
199
+ } else {
200
+ ref = git.currentBranch ?? "main";
201
+ }
202
+ if (!args.target) {
203
+ return {
204
+ ok: true,
205
+ url: gitTreeUrl(host, git.context.projectKey, git.context.repoName, ref)
206
+ };
207
+ }
208
+ const lineMatch = args.target.match(FILE_LINE_PATTERN);
209
+ const filePath = lineMatch ? lineMatch[1] : args.target;
210
+ const line = lineMatch ? Number(lineMatch[2]) : void 0;
211
+ const fullPath = git.repoRelativePath ? `${git.repoRelativePath}${filePath}` : filePath;
212
+ const isDir = filePath.endsWith("/");
213
+ if (isDir) {
214
+ return {
215
+ ok: true,
216
+ url: gitTreeUrl(
217
+ host,
218
+ git.context.projectKey,
219
+ git.context.repoName,
220
+ ref,
221
+ fullPath.replace(/\/$/, "")
222
+ )
223
+ };
224
+ }
225
+ return {
226
+ ok: true,
227
+ url: gitBlobUrl(host, git.context.projectKey, git.context.repoName, ref, fullPath, line)
228
+ };
229
+ };
230
+
231
+ const browse = new BeeCommand("browse").summary("Open a Backlog page in the browser").description(
232
+ `With no arguments, opens the repository page (inside a Backlog repo) or the dashboard.
233
+
234
+ Accepts an issue key (\`PROJECT-123\`), bare number (\`123\`, project inferred from Git remote), file path (\`src/main.ts\`), or path with line (\`src/main.ts:42\`). Paths ending with \`/\` open the directory tree. Use \`--project\` with section flags (e.g. \`--issues\`, \`--board\`) for project pages.`
235
+ ).argument("[target]", "Issue key, issue number, file path, or project key").addOption(project().makeOptionMandatory(false).default(void 0)).option("-b, --branch <name>", "View file at a specific branch").option("-c, --commit", "View file at the latest commit").addOption(noBrowser()).option("--issues", "Open the issues page").option("--board", "Open the board page").option("--gantt", "Open the Gantt chart page").option("--wiki", "Open the wiki page").option("--documents", "Open the documents page").option("--files", "Open the shared files page").option("--git", "Open the git repositories page").option("--svn", "Open the Subversion page").option("--settings", "Open the project settings page").addOption(space()).envVars([...ENV_AUTH, ENV_PROJECT]).examples([
236
+ { description: "Open repository page (in a Backlog repo)", command: "bee browse" },
237
+ { description: "Open dashboard (outside a Backlog repo)", command: "bee browse" },
238
+ { description: "Open an issue", command: "bee browse PROJECT-123" },
239
+ { description: "Open issue by number (inferred project)", command: "bee browse 123" },
240
+ { description: "Open a file in git viewer", command: "bee browse src/main.ts" },
241
+ { description: "Open a file at a specific line", command: "bee browse src/main.ts:42" },
242
+ { description: "Open a directory in git viewer", command: "bee browse src/" },
243
+ { description: "Browse at a specific branch", command: "bee browse src/main.ts -b develop" },
244
+ { description: "Browse at the latest commit", command: "bee browse -c" },
245
+ { description: "Print URL without opening browser", command: "bee browse -n" },
246
+ { description: "Open project issues page", command: "bee browse -p PROJECT --issues" },
247
+ { description: "Open project board", command: "bee browse -p PROJECT --board" },
248
+ { description: "Open Gantt chart", command: "bee browse -p PROJECT --gantt" }
249
+ ]).action(async (target, opts) => {
250
+ const { host } = await getClient(opts.space);
251
+ const [context, currentBranch, latestCommit, repoRelativePath] = await Promise.all([
252
+ detectGitContext(),
253
+ getCurrentBranch(),
254
+ getLatestCommit(),
255
+ getRepoRelativePath()
256
+ ]);
257
+ const browseArgs = { target, ...opts };
258
+ const result = resolveUrl(context?.host ?? host, browseArgs, {
259
+ context,
260
+ currentBranch,
261
+ latestCommit,
262
+ repoRelativePath
263
+ });
264
+ if (!result.ok) {
265
+ throw new UserError(result.error);
266
+ }
267
+ await openOrPrintUrl(result.url, opts.browser === false, consola);
268
+ });
269
+
270
+ export { browse as default };
@@ -0,0 +1,61 @@
1
+ import { spawn } from 'node:child_process';
2
+ import consola from 'consola';
3
+ import { g as getClient } from '../shared/bee.CThuQMit.mjs';
4
+ import 'backlog-js';
5
+ import 'node:http';
6
+ import 'open';
7
+ import { o as outputResult } from '../shared/bee.BTBGpv4K.mjs';
8
+ import 'node:stream/consumers';
9
+ import 'valibot';
10
+ import { B as BeeCommand, E as ENV_AUTH, a as ENV_PROJECT } from '../shared/bee.CQ3kBgas.mjs';
11
+ import { p as project, j as json, s as space, r as resolveOptions } from '../shared/bee.DHTPkjMh.mjs';
12
+ import '../shared/bee.XxOB1Her.mjs';
13
+ import '../shared/bee.CktwmH8R.mjs';
14
+ import '../shared/bee.DVTuFf-T.mjs';
15
+ import 'node:fs';
16
+ import 'node:path';
17
+ import 'node:os';
18
+ import '../shared/bee.BeQSH2t0.mjs';
19
+ import '../shared/bee.-8tk76YJ.mjs';
20
+ import 'commander';
21
+ import 'consola/utils';
22
+
23
+ const gitClone = (gitArgs) => new Promise((resolve, reject) => {
24
+ const child = spawn("git", gitArgs, { stdio: "inherit" });
25
+ child.on("close", (code) => {
26
+ if (code === 0) {
27
+ resolve();
28
+ } else {
29
+ reject(new Error(`git clone exited with code ${code}`));
30
+ }
31
+ });
32
+ });
33
+ const clone = new BeeCommand("clone").summary("Clone a repository").description(`By default the SSH URL is used; pass \`--http\` to clone over HTTPS instead.`).argument("<repository>", "Repository name or ID").addOption(project()).option("-d, --directory <path>", "Directory to clone into").option("--http", "Clone using HTTP URL instead of SSH").addOption(json()).addOption(space()).envVars([...ENV_AUTH, ENV_PROJECT]).examples([
34
+ { description: "Clone a repository", command: "bee repo clone api-server -p PROJECT_KEY" },
35
+ {
36
+ description: "Clone to a specific directory",
37
+ command: "bee repo clone api-server -p PROJECT_KEY --directory ./dest"
38
+ },
39
+ {
40
+ description: "Clone using HTTP URL",
41
+ command: "bee repo clone api-server -p PROJECT_KEY --http"
42
+ }
43
+ ]).action(async (repository, opts, cmd) => {
44
+ await resolveOptions(cmd);
45
+ const { client } = await getClient(opts.space);
46
+ const repo = await client.getGitRepository(opts.project, repository);
47
+ if (opts.json !== void 0) {
48
+ outputResult(repo, opts, () => {
49
+ });
50
+ return;
51
+ }
52
+ const cloneUrl = opts.http ? repo.httpUrl : repo.sshUrl;
53
+ const gitArgs = ["clone", cloneUrl];
54
+ if (opts.directory) {
55
+ gitArgs.push(opts.directory);
56
+ }
57
+ consola.info(`Cloning into '${opts.directory ?? repo.name}'...`);
58
+ await gitClone(gitArgs);
59
+ });
60
+
61
+ export { clone as default };
@@ -0,0 +1,51 @@
1
+ import consola from 'consola';
2
+ import { R as ResolutionId, I as IssueStatusId } from '../shared/bee.Btmq3TXs.mjs';
3
+ import { g as getClient } from '../shared/bee.CThuQMit.mjs';
4
+ import 'backlog-js';
5
+ import 'node:http';
6
+ import 'open';
7
+ import 'node:child_process';
8
+ import { o as outputResult } from '../shared/bee.BTBGpv4K.mjs';
9
+ import 'node:stream/consumers';
10
+ import 'valibot';
11
+ import { B as BeeCommand, E as ENV_AUTH } from '../shared/bee.CQ3kBgas.mjs';
12
+ import { g as notify, j as json, s as space } from '../shared/bee.DHTPkjMh.mjs';
13
+ import '../shared/bee.XxOB1Her.mjs';
14
+ import '../shared/bee.CktwmH8R.mjs';
15
+ import '../shared/bee.DVTuFf-T.mjs';
16
+ import 'node:fs';
17
+ import 'node:path';
18
+ import 'node:os';
19
+ import '../shared/bee.BeQSH2t0.mjs';
20
+ import '../shared/bee.-8tk76YJ.mjs';
21
+ import 'commander';
22
+ import 'consola/utils';
23
+
24
+ const close = new BeeCommand("close").summary("Close an issue").description(
25
+ `Sets the status to Closed with resolution \`Fixed\` by default. Use \`--resolution\` for a different resolution.`
26
+ ).argument("<issue>", "Issue ID or issue key").option("-c, --comment <text>", "Comment to add when closing").option("--resolution <name>", `Resolution`).addOption(notify()).addOption(json()).addOption(space()).envVars([...ENV_AUTH]).examples([
27
+ { description: "Close an issue", command: "bee issue close PROJECT-123" },
28
+ {
29
+ description: "Close with a comment",
30
+ command: 'bee issue close PROJECT-123 -c "Done"'
31
+ },
32
+ {
33
+ description: "Close as duplicate",
34
+ command: "bee issue close PROJECT-123 --resolution duplicate"
35
+ }
36
+ ]).action(async (issue, opts) => {
37
+ const { client } = await getClient(opts.space);
38
+ const resolutionId = opts.resolution ? ResolutionId[opts.resolution] ?? Number(opts.resolution) : ResolutionId.fixed;
39
+ const notifiedUserId = opts.notify ?? [];
40
+ const issueData = await client.patchIssue(issue, {
41
+ statusId: IssueStatusId.Closed,
42
+ resolutionId,
43
+ comment: opts.comment,
44
+ notifiedUserId
45
+ });
46
+ outputResult(issueData, opts, (data) => {
47
+ consola.success(`Closed issue ${data.issueKey}: ${data.summary}`);
48
+ });
49
+ });
50
+
51
+ export { close as default };
@@ -0,0 +1,124 @@
1
+ import consola from 'consola';
2
+ import { g as getClient } from '../shared/bee.CThuQMit.mjs';
3
+ import 'backlog-js';
4
+ import 'node:http';
5
+ import 'open';
6
+ import 'node:child_process';
7
+ import { o as outputResult } from '../shared/bee.BTBGpv4K.mjs';
8
+ import { c as confirmOrExit } from '../shared/bee.DVTuFf-T.mjs';
9
+ import { a as resolveStdinArg } from '../shared/bee.C--ZWPxf.mjs';
10
+ import 'valibot';
11
+ import { f as formatDate } from '../shared/bee.n5MYN4a6.mjs';
12
+ import { p as printTable } from '../shared/bee.IM3QELRf.mjs';
13
+ import { B as BeeCommand, E as ENV_AUTH } from '../shared/bee.CQ3kBgas.mjs';
14
+ import { g as notify, j as json, s as space } from '../shared/bee.DHTPkjMh.mjs';
15
+ import '../shared/bee.XxOB1Her.mjs';
16
+ import 'node:stream/consumers';
17
+ import '../shared/bee.CktwmH8R.mjs';
18
+ import '../shared/bee.-8tk76YJ.mjs';
19
+ import 'node:fs';
20
+ import 'node:path';
21
+ import 'node:os';
22
+ import '../shared/bee.BeQSH2t0.mjs';
23
+ import '../shared/bee.Ds2l-nTJ.mjs';
24
+ import 'commander';
25
+ import 'consola/utils';
26
+
27
+ const comment = new BeeCommand("comment").summary("Add a comment to an issue").description(
28
+ `When input is piped, it is used as the body automatically.
29
+
30
+ Use \`--list\`, \`--edit-last\`, or \`--delete-last\` for other comment operations.`
31
+ ).argument("<issue>", "Issue ID or issue key").option("-b, --body <text>", "Comment body").addOption(notify()).option("--list", "List comments on the issue").option("--edit-last", "Edit your most recent comment").option("--delete-last", "Delete your most recent comment").option("--yes", "Skip confirmation prompt for delete").addOption(json()).addOption(space()).envVars([...ENV_AUTH]).examples([
32
+ {
33
+ description: "Add a comment",
34
+ command: 'bee issue comment PROJECT-123 -b "This is a comment"'
35
+ },
36
+ {
37
+ description: "Add a comment from stdin",
38
+ command: 'echo "Comment body" | bee issue comment PROJECT-123'
39
+ },
40
+ { description: "List all comments", command: "bee issue comment PROJECT-123 --list" },
41
+ {
42
+ description: "Edit your last comment",
43
+ command: 'bee issue comment PROJECT-123 --edit-last -b "Updated text"'
44
+ },
45
+ {
46
+ description: "Delete your last comment",
47
+ command: "bee issue comment PROJECT-123 --delete-last --yes"
48
+ }
49
+ ]).action(async (issue, opts) => {
50
+ const { client } = await getClient(opts.space);
51
+ if (opts.list) {
52
+ const comments = await client.getIssueComments(issue, { order: "asc" });
53
+ outputResult(comments, opts, (data) => {
54
+ const filtered = data.filter((c) => c.content);
55
+ if (filtered.length === 0) {
56
+ consola.info("No comments found.");
57
+ return;
58
+ }
59
+ const rows = filtered.map((c) => [
60
+ { header: "ID", value: String(c.id) },
61
+ { header: "AUTHOR", value: c.createdUser.name },
62
+ { header: "DATE", value: formatDate(c.created) },
63
+ { header: "CONTENT", value: c.content }
64
+ ]);
65
+ printTable(rows);
66
+ });
67
+ return;
68
+ }
69
+ if (opts.editLast) {
70
+ const myself = await client.getMyself();
71
+ const comments = await client.getIssueComments(issue, { order: "desc" });
72
+ const myComment = comments.find((c) => c.createdUser.id === myself.id);
73
+ if (!myComment) {
74
+ consola.error(`No comment by you was found on ${issue}.`);
75
+ return;
76
+ }
77
+ const content2 = await resolveStdinArg(opts.body) ?? opts.body;
78
+ if (!content2) {
79
+ consola.error("Comment body is required. Use --body or pipe input.");
80
+ return;
81
+ }
82
+ const result2 = await client.patchIssueComment(issue, myComment.id, { content: content2 });
83
+ outputResult(result2, opts, () => {
84
+ consola.success(`Updated comment on ${issue}`);
85
+ });
86
+ return;
87
+ }
88
+ if (opts.deleteLast) {
89
+ const myself = await client.getMyself();
90
+ const comments = await client.getIssueComments(issue, { order: "desc" });
91
+ const myComment = comments.find((c) => c.createdUser.id === myself.id);
92
+ if (!myComment) {
93
+ consola.error(`No comment by you was found on ${issue}.`);
94
+ return;
95
+ }
96
+ const confirmed = await confirmOrExit(
97
+ `Are you sure you want to delete your comment on ${issue}?`,
98
+ opts.yes
99
+ );
100
+ if (!confirmed) {
101
+ return;
102
+ }
103
+ const result2 = await client.deleteIssueComment(issue, myComment.id);
104
+ outputResult(result2, opts, () => {
105
+ consola.success(`Deleted comment on ${issue}`);
106
+ });
107
+ return;
108
+ }
109
+ const content = await resolveStdinArg(opts.body) ?? opts.body;
110
+ if (!content) {
111
+ consola.error("Comment body is required. Use --body or pipe input.");
112
+ return;
113
+ }
114
+ const notifiedUserId = opts.notify ?? [];
115
+ const result = await client.postIssueComments(issue, {
116
+ content,
117
+ notifiedUserId
118
+ });
119
+ outputResult(result, opts, () => {
120
+ consola.success(`Added comment to ${issue}`);
121
+ });
122
+ });
123
+
124
+ export { comment as default };