ya-git-jira 1.6.0 → 2.0.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/.opencode/skills/architecture/SKILL.md +45 -0
- package/.opencode/skills/code-style/SKILL.md +76 -0
- package/.opencode/skills/git-confluence/SKILL.md +82 -0
- package/.opencode/skills/git-jira/SKILL.md +63 -0
- package/.opencode/skills/git-lab/SKILL.md +102 -0
- package/AGENTS.md +50 -0
- package/README.md +106 -106
- package/bin/git-api.ts +70 -0
- package/bin/git-confluence-page-search.ts +58 -0
- package/bin/git-confluence-page-show.ts +61 -0
- package/bin/git-confluence-page-update.ts +77 -0
- package/bin/git-confluence-page.ts +28 -0
- package/bin/git-confluence-space-list.ts +34 -0
- package/bin/git-confluence-space.ts +24 -0
- package/bin/git-confluence-whoami.ts +33 -0
- package/bin/git-confluence.ts +27 -0
- package/bin/git-jira-start.ts +1 -1
- package/bin/git-jira-whoami.ts +32 -0
- package/bin/git-jira.ts +2 -0
- package/bin/git-lab-project-mr-list.ts +57 -0
- package/bin/git-lab-project-mr.ts +24 -0
- package/bin/git-lab-project-pipeline-jobs.ts +46 -0
- package/bin/git-lab-project-pipeline-latest.ts +47 -0
- package/bin/git-lab-project-pipeline-log.ts +49 -0
- package/bin/git-lab-project-pipeline.ts +6 -0
- package/bin/git-lab-project.ts +5 -1
- package/bin/gitj-install-skills.ts +126 -0
- package/bin/gitj.ts +12 -0
- package/dist/bin/git-api.js +2156 -0
- package/dist/bin/git-bump.js +132 -121
- package/dist/bin/git-confluence-page-search.js +2079 -0
- package/dist/bin/git-confluence-page-show.js +2082 -0
- package/dist/bin/git-confluence-page-update.js +2093 -0
- package/dist/bin/git-confluence-page.js +2186 -0
- package/dist/bin/git-confluence-space-list.js +2061 -0
- package/dist/bin/git-confluence-space.js +2073 -0
- package/dist/bin/git-confluence-whoami.js +2060 -0
- package/dist/bin/git-confluence.js +2251 -0
- package/dist/bin/git-jira-issue-list.js +136 -125
- package/dist/bin/git-jira-issue-show.js +136 -125
- package/dist/bin/git-jira-issue.js +140 -129
- package/dist/bin/git-jira-start.js +138 -127
- package/dist/bin/git-jira-whoami.js +1972 -0
- package/dist/bin/git-jira.js +170 -139
- package/dist/bin/git-lab-group-list.js +321 -279
- package/dist/bin/git-lab-group.js +323 -281
- package/dist/bin/git-lab-merge-active.js +321 -279
- package/dist/bin/git-lab-merge-todo.js +321 -279
- package/dist/bin/git-lab-merge-train-list.js +289 -273
- package/dist/bin/git-lab-merge-train.js +291 -275
- package/dist/bin/git-lab-merge.js +330 -288
- package/dist/bin/git-lab-namespace-list.js +138 -127
- package/dist/bin/git-lab-namespace.js +140 -129
- package/dist/bin/git-lab-project-list.js +288 -272
- package/dist/bin/git-lab-project-mr-list.js +2740 -0
- package/dist/bin/git-lab-project-mr.js +2752 -0
- package/dist/bin/git-lab-project-pipeline-jobs.js +2734 -0
- package/dist/bin/git-lab-project-pipeline-latest.js +2736 -0
- package/dist/bin/git-lab-project-pipeline-list.js +323 -281
- package/dist/bin/git-lab-project-pipeline-log.js +2739 -0
- package/dist/bin/git-lab-project-pipeline.js +437 -292
- package/dist/bin/git-lab-project-whereami.js +292 -276
- package/dist/bin/git-lab-project.js +563 -288
- package/dist/bin/git-lab-whoami.js +142 -131
- package/dist/bin/git-lab.js +575 -338
- package/dist/bin/gitj-install-skills.js +1954 -0
- package/dist/bin/gitj.js +1385 -473
- package/dist/index.js +371 -187
- package/index.ts +1 -0
- package/lib/api.ts +177 -0
- package/lib/confluence/api.ts +132 -0
- package/lib/confluence/config.ts +25 -0
- package/lib/confluence/index.ts +3 -0
- package/lib/confluence/types.ts +59 -0
- package/lib/gitlab/index.ts +1 -0
- package/lib/gitlab/job.ts +31 -0
- package/lib/gitlab/merge-request.ts +20 -0
- package/lib/gitlab/pipeline.ts +28 -1
- package/lib/gitlab/project.ts +14 -5
- package/lib/help.ts +40 -0
- package/lib/jira.ts +2 -2
- package/package.json +18 -2
- package/tests/all-help.test.ts +6 -1
- package/tests/gitj.test.ts +1 -1
- package/tests/help-all.test.ts +29 -0
- package/bun.lockb +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { isMain } from '../lib/is_main'
|
|
6
|
+
import whoami from './git-confluence-whoami'
|
|
7
|
+
import space from './git-confluence-space'
|
|
8
|
+
import page from './git-confluence-page'
|
|
9
|
+
const version = await getPackageVersion()
|
|
10
|
+
|
|
11
|
+
export function create(): Command {
|
|
12
|
+
const program: Command = new Command()
|
|
13
|
+
program
|
|
14
|
+
.version(version)
|
|
15
|
+
.name('confluence')
|
|
16
|
+
.description('Commands for working with Confluence')
|
|
17
|
+
.addCommand(whoami())
|
|
18
|
+
.addCommand(space())
|
|
19
|
+
.addCommand(page())
|
|
20
|
+
return program
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default create
|
|
24
|
+
|
|
25
|
+
if (isMain('git-confluence')) {
|
|
26
|
+
await create().parseAsync(Bun.argv)
|
|
27
|
+
}
|
package/bin/git-jira-start.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { isMain } from '../lib/is_main'
|
|
|
8
8
|
const version = await getPackageVersion()
|
|
9
9
|
|
|
10
10
|
function toKebab(s: string): string {
|
|
11
|
-
return s.replace(/([a-z]+)([A-Z]+)/g, "$
|
|
11
|
+
return s.replace(/([a-z]+)([A-Z]+)/g, "$1_$2").toLowerCase()
|
|
12
12
|
.replace(/(\W+)/g, "-")
|
|
13
13
|
.replace(/-$/, "")
|
|
14
14
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { getMyself } from '../lib/jira'
|
|
6
|
+
import { isMain } from '../lib/is_main'
|
|
7
|
+
const version = await getPackageVersion()
|
|
8
|
+
|
|
9
|
+
export function create(): Command {
|
|
10
|
+
const program: Command = new Command()
|
|
11
|
+
program
|
|
12
|
+
.version(version)
|
|
13
|
+
.name('whoami')
|
|
14
|
+
.description('Show the current Jira user')
|
|
15
|
+
.option('-v, --verbose', 'Verbose output')
|
|
16
|
+
.action(async (options) => {
|
|
17
|
+
const myself = await getMyself()
|
|
18
|
+
if (options.verbose) {
|
|
19
|
+
console.log(myself)
|
|
20
|
+
} else {
|
|
21
|
+
const { displayName, emailAddress, accountId } = myself as any
|
|
22
|
+
console.log({ displayName, emailAddress, accountId })
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
return program
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default create
|
|
29
|
+
|
|
30
|
+
if (isMain('git-jira-whoami')) {
|
|
31
|
+
await create().parseAsync(Bun.argv)
|
|
32
|
+
}
|
package/bin/git-jira.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { isMain } from '../lib/is_main'
|
|
|
6
6
|
import start from './git-jira-start'
|
|
7
7
|
import issue from './git-jira-issue'
|
|
8
8
|
import issues from './git-jira-issue-list'
|
|
9
|
+
import whoami from './git-jira-whoami'
|
|
9
10
|
const version = await getPackageVersion()
|
|
10
11
|
|
|
11
12
|
export function create(): Command {
|
|
@@ -17,6 +18,7 @@ export function create(): Command {
|
|
|
17
18
|
.addCommand(start())
|
|
18
19
|
.addCommand(issue())
|
|
19
20
|
.addCommand(issues())
|
|
21
|
+
.addCommand(whoami())
|
|
20
22
|
return program
|
|
21
23
|
}
|
|
22
24
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { getMergeRequestsByBranch, type MergeRequest } from "../lib/gitlab"
|
|
6
|
+
import { findProject } from '../lib/gitlab/project'
|
|
7
|
+
import { getRemote, getCurrentBranch } from '../lib/git'
|
|
8
|
+
import { isMain } from '../lib/is_main'
|
|
9
|
+
const version = await getPackageVersion()
|
|
10
|
+
|
|
11
|
+
export function create(): Command {
|
|
12
|
+
const program: Command = new Command()
|
|
13
|
+
program
|
|
14
|
+
.version(version)
|
|
15
|
+
.name('list')
|
|
16
|
+
.description('List open merge requests for a project and branch')
|
|
17
|
+
.option('-v, --verbose', 'Verbose output')
|
|
18
|
+
.option('-p, --project <path>', 'Project path (e.g. etagen-internal/eta-lib/base). Defaults to current directory remote.')
|
|
19
|
+
.option('-b, --branch <branch>', 'Source branch to filter on. Defaults to current branch.')
|
|
20
|
+
.action(async (options) => {
|
|
21
|
+
let projectPath = options.project
|
|
22
|
+
if (!projectPath) {
|
|
23
|
+
const remote = await getRemote()
|
|
24
|
+
const project = await findProject(remote)
|
|
25
|
+
if (!project) {
|
|
26
|
+
console.error(`Could not resolve project from remote: ${remote}`)
|
|
27
|
+
process.exit(1)
|
|
28
|
+
}
|
|
29
|
+
projectPath = project.path_with_namespace
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const branch = options.branch || await getCurrentBranch()
|
|
33
|
+
|
|
34
|
+
const mrs: Array<MergeRequest> = await getMergeRequestsByBranch(projectPath, branch)
|
|
35
|
+
if (!mrs.length) {
|
|
36
|
+
console.error(`No open MRs for branch '${branch}' in ${projectPath}`)
|
|
37
|
+
process.exit(0)
|
|
38
|
+
}
|
|
39
|
+
if (options.verbose) {
|
|
40
|
+
console.log(mrs)
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
const filtered = mrs.map(m => {
|
|
44
|
+
const { iid, title, web_url, source_branch, target_branch, state, draft } = m
|
|
45
|
+
return { iid, title, web_url, source_branch, target_branch, state, draft }
|
|
46
|
+
})
|
|
47
|
+
console.log(filtered)
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
return program
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export default create
|
|
54
|
+
|
|
55
|
+
if (isMain('git-lab-project-mr-list')) {
|
|
56
|
+
await create().parseAsync(Bun.argv)
|
|
57
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { isMain } from '../lib/is_main'
|
|
6
|
+
import list from './git-lab-project-mr-list'
|
|
7
|
+
const version = await getPackageVersion()
|
|
8
|
+
|
|
9
|
+
export function create(): Command {
|
|
10
|
+
const program: Command = new Command()
|
|
11
|
+
program
|
|
12
|
+
.version(version)
|
|
13
|
+
.name('mr')
|
|
14
|
+
.description('Commands for working with merge requests')
|
|
15
|
+
.addCommand(list())
|
|
16
|
+
.action(() => program.help())
|
|
17
|
+
return program
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default create
|
|
21
|
+
|
|
22
|
+
if (isMain('git-lab-project-mr')) {
|
|
23
|
+
await create().parseAsync(Bun.argv)
|
|
24
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { getPipelineJobs, type Job } from '../lib/gitlab'
|
|
6
|
+
import { isMain } from '../lib/is_main'
|
|
7
|
+
|
|
8
|
+
const version = await getPackageVersion()
|
|
9
|
+
|
|
10
|
+
export function create(): Command {
|
|
11
|
+
const program: Command = new Command()
|
|
12
|
+
program
|
|
13
|
+
.version(version)
|
|
14
|
+
.name('jobs')
|
|
15
|
+
.description('List jobs for a pipeline')
|
|
16
|
+
.requiredOption('-p, --pipeline <id>', 'Pipeline ID')
|
|
17
|
+
.option('-v, --verbose', 'Verbose output')
|
|
18
|
+
.action(async (options) => {
|
|
19
|
+
const pipelineId = parseInt(options.pipeline, 10)
|
|
20
|
+
if (isNaN(pipelineId)) {
|
|
21
|
+
console.error(`Invalid pipeline ID: ${options.pipeline}`)
|
|
22
|
+
process.exit(1)
|
|
23
|
+
}
|
|
24
|
+
const jobs: Array<Job> = await getPipelineJobs(pipelineId)
|
|
25
|
+
if (!jobs || jobs.length === 0) {
|
|
26
|
+
console.error(`No jobs found for pipeline ${pipelineId}`)
|
|
27
|
+
process.exit(1)
|
|
28
|
+
}
|
|
29
|
+
if (options.verbose) {
|
|
30
|
+
console.log(JSON.stringify(jobs, null, 2))
|
|
31
|
+
} else {
|
|
32
|
+
const filtered = jobs.map((j: Job) => {
|
|
33
|
+
const { id, name, stage, status, duration, failure_reason } = j
|
|
34
|
+
return { id, name, stage, status, duration, failure_reason }
|
|
35
|
+
})
|
|
36
|
+
console.log(JSON.stringify(filtered, null, 2))
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
return program
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default create
|
|
43
|
+
|
|
44
|
+
if (isMain('git-lab-project-pipeline-jobs')) {
|
|
45
|
+
await create().parseAsync(Bun.argv)
|
|
46
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { getLatestPipeline, type Pipeline, getPipelineJobs, type Job } from '../lib/gitlab'
|
|
6
|
+
import { isMain } from '../lib/is_main'
|
|
7
|
+
|
|
8
|
+
const version = await getPackageVersion()
|
|
9
|
+
|
|
10
|
+
export function create(): Command {
|
|
11
|
+
const program: Command = new Command()
|
|
12
|
+
program
|
|
13
|
+
.version(version)
|
|
14
|
+
.name('latest')
|
|
15
|
+
.description('Show jobs for the latest pipeline on the current branch')
|
|
16
|
+
.option('-v, --verbose', 'Verbose output')
|
|
17
|
+
.action(async (options) => {
|
|
18
|
+
const pipeline: Pipeline | undefined = await getLatestPipeline()
|
|
19
|
+
if (!pipeline) {
|
|
20
|
+
console.error('No pipeline found for the current branch')
|
|
21
|
+
process.exit(1)
|
|
22
|
+
}
|
|
23
|
+
const { id, status, ref, web_url } = pipeline
|
|
24
|
+
console.log(JSON.stringify({ id, status, ref, web_url }, null, 2))
|
|
25
|
+
const jobs: Array<Job> = await getPipelineJobs(pipeline.id)
|
|
26
|
+
if (!jobs || jobs.length === 0) {
|
|
27
|
+
console.error(`No jobs found for pipeline ${pipeline.id}`)
|
|
28
|
+
process.exit(1)
|
|
29
|
+
}
|
|
30
|
+
if (options.verbose) {
|
|
31
|
+
console.log(JSON.stringify(jobs, null, 2))
|
|
32
|
+
} else {
|
|
33
|
+
const filtered = jobs.map((j: Job) => {
|
|
34
|
+
const { id, name, stage, status, duration, failure_reason } = j
|
|
35
|
+
return { id, name, stage, status, duration, failure_reason }
|
|
36
|
+
})
|
|
37
|
+
console.log(JSON.stringify(filtered, null, 2))
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
return program
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default create
|
|
44
|
+
|
|
45
|
+
if (isMain('git-lab-project-pipeline-latest')) {
|
|
46
|
+
await create().parseAsync(Bun.argv)
|
|
47
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { getJobLog } from '../lib/gitlab'
|
|
6
|
+
import { isMain } from '../lib/is_main'
|
|
7
|
+
|
|
8
|
+
const version = await getPackageVersion()
|
|
9
|
+
|
|
10
|
+
export function create(): Command {
|
|
11
|
+
const program: Command = new Command()
|
|
12
|
+
program
|
|
13
|
+
.version(version)
|
|
14
|
+
.name('log')
|
|
15
|
+
.description('Download a job log')
|
|
16
|
+
.requiredOption('-j, --job <id>', 'Job ID')
|
|
17
|
+
.option('-t, --tail <lines>', 'Show only the last N lines')
|
|
18
|
+
.action(async (options) => {
|
|
19
|
+
const jobId = parseInt(options.job, 10)
|
|
20
|
+
if (isNaN(jobId)) {
|
|
21
|
+
console.error(`Invalid job ID: ${options.job}`)
|
|
22
|
+
process.exit(1)
|
|
23
|
+
}
|
|
24
|
+
const log = await getJobLog(jobId)
|
|
25
|
+
if (!log) {
|
|
26
|
+
console.error(`No log output for job ${jobId}`)
|
|
27
|
+
process.exit(1)
|
|
28
|
+
}
|
|
29
|
+
if (options.tail) {
|
|
30
|
+
const n = parseInt(options.tail, 10)
|
|
31
|
+
if (isNaN(n)) {
|
|
32
|
+
console.error(`Invalid --tail value: ${options.tail}`)
|
|
33
|
+
process.exit(1)
|
|
34
|
+
}
|
|
35
|
+
const lines = log.split('\n')
|
|
36
|
+
const tail = lines.slice(-n)
|
|
37
|
+
process.stdout.write(tail.join('\n'))
|
|
38
|
+
} else {
|
|
39
|
+
process.stdout.write(log)
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
return program
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default create
|
|
46
|
+
|
|
47
|
+
if (isMain('git-lab-project-pipeline-log')) {
|
|
48
|
+
await create().parseAsync(Bun.argv)
|
|
49
|
+
}
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
import { Command } from 'commander'
|
|
4
4
|
import { getPackageVersion } from '../lib/package'
|
|
5
5
|
import { isMain } from '../lib/is_main'
|
|
6
|
+
import jobs from './git-lab-project-pipeline-jobs'
|
|
7
|
+
import latest from './git-lab-project-pipeline-latest'
|
|
6
8
|
import list from './git-lab-project-pipeline-list'
|
|
9
|
+
import log from './git-lab-project-pipeline-log'
|
|
7
10
|
const version = await getPackageVersion()
|
|
8
11
|
|
|
9
12
|
export function create(): Command {
|
|
@@ -12,7 +15,10 @@ export function create(): Command {
|
|
|
12
15
|
.version(version)
|
|
13
16
|
.name('pipeline')
|
|
14
17
|
.description('Commands for working with GitLab pipelines')
|
|
18
|
+
.addCommand(jobs())
|
|
19
|
+
.addCommand(latest())
|
|
15
20
|
.addCommand(list())
|
|
21
|
+
.addCommand(log())
|
|
16
22
|
.action(() => program.help())
|
|
17
23
|
return program
|
|
18
24
|
}
|
package/bin/git-lab-project.ts
CHANGED
|
@@ -4,6 +4,8 @@ import { Command } from 'commander'
|
|
|
4
4
|
import { getPackageVersion } from '../lib/package'
|
|
5
5
|
import { isMain } from '../lib/is_main'
|
|
6
6
|
import list from './git-lab-project-list'
|
|
7
|
+
import mr from './git-lab-project-mr'
|
|
8
|
+
import pipeline from './git-lab-project-pipeline'
|
|
7
9
|
import whereami from './git-lab-project-whereami'
|
|
8
10
|
const version = await getPackageVersion()
|
|
9
11
|
|
|
@@ -11,9 +13,11 @@ export function create(): Command {
|
|
|
11
13
|
const program: Command = new Command()
|
|
12
14
|
program
|
|
13
15
|
.version(version)
|
|
14
|
-
.name('
|
|
16
|
+
.name('project')
|
|
15
17
|
.description('Commands for working with GitLab projects')
|
|
16
18
|
.addCommand(list())
|
|
19
|
+
.addCommand(mr())
|
|
20
|
+
.addCommand(pipeline())
|
|
17
21
|
.addCommand(whereami())
|
|
18
22
|
.action(() => {
|
|
19
23
|
program.help()
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import { getPackageVersion } from '../lib/package'
|
|
5
|
+
import { findPackageJson } from '../lib/package'
|
|
6
|
+
import { isMain } from '../lib/is_main'
|
|
7
|
+
import fs from 'node:fs'
|
|
8
|
+
import path from 'node:path'
|
|
9
|
+
import os from 'node:os'
|
|
10
|
+
|
|
11
|
+
const version = await getPackageVersion()
|
|
12
|
+
|
|
13
|
+
const frameworks = ['opencode', 'copilot', 'claude'] as const
|
|
14
|
+
type Framework = typeof frameworks[number]
|
|
15
|
+
|
|
16
|
+
const skillNames = ['git-jira', 'git-lab', 'git-confluence']
|
|
17
|
+
|
|
18
|
+
function getSkillsSourceDir(): string {
|
|
19
|
+
const packageJsonPath = findPackageJson()
|
|
20
|
+
if (!packageJsonPath) {
|
|
21
|
+
throw new Error('Cannot find package.json for ya-git-jira')
|
|
22
|
+
}
|
|
23
|
+
const packageRoot = path.dirname(packageJsonPath)
|
|
24
|
+
const skillsDir = path.join(packageRoot, '.opencode', 'skills')
|
|
25
|
+
if (!fs.existsSync(skillsDir)) {
|
|
26
|
+
throw new Error(`Skills directory not found: ${skillsDir}`)
|
|
27
|
+
}
|
|
28
|
+
return skillsDir
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function getTargetDir(framework: Framework): string {
|
|
32
|
+
const home = os.homedir()
|
|
33
|
+
switch (framework) {
|
|
34
|
+
case 'opencode':
|
|
35
|
+
return path.join(home, '.config', 'opencode', 'skills')
|
|
36
|
+
case 'copilot':
|
|
37
|
+
return path.join(home, '.copilot', 'skills')
|
|
38
|
+
case 'claude':
|
|
39
|
+
return path.join(process.cwd(), '.claude', 'skills')
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function installSkills(framework: Framework, copy: boolean): void {
|
|
44
|
+
const sourceDir = getSkillsSourceDir()
|
|
45
|
+
const targetDir = getTargetDir(framework)
|
|
46
|
+
|
|
47
|
+
fs.mkdirSync(targetDir, { recursive: true })
|
|
48
|
+
|
|
49
|
+
for (const name of skillNames) {
|
|
50
|
+
const source = path.join(sourceDir, name)
|
|
51
|
+
const target = path.join(targetDir, name)
|
|
52
|
+
|
|
53
|
+
if (fs.existsSync(target)) {
|
|
54
|
+
const stat = fs.lstatSync(target)
|
|
55
|
+
if (stat.isSymbolicLink()) {
|
|
56
|
+
fs.unlinkSync(target)
|
|
57
|
+
} else if (stat.isDirectory()) {
|
|
58
|
+
console.error(`${target} already exists as a directory -- skipping (use --force to overwrite)`)
|
|
59
|
+
continue
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (copy) {
|
|
64
|
+
fs.cpSync(source, target, { recursive: true })
|
|
65
|
+
console.log(`copied ${name} -> ${target}`)
|
|
66
|
+
} else {
|
|
67
|
+
fs.symlinkSync(source, target)
|
|
68
|
+
console.log(`linked ${name} -> ${target}`)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function forceInstallSkills(framework: Framework, copy: boolean): void {
|
|
74
|
+
const sourceDir = getSkillsSourceDir()
|
|
75
|
+
const targetDir = getTargetDir(framework)
|
|
76
|
+
|
|
77
|
+
fs.mkdirSync(targetDir, { recursive: true })
|
|
78
|
+
|
|
79
|
+
for (const name of skillNames) {
|
|
80
|
+
const source = path.join(sourceDir, name)
|
|
81
|
+
const target = path.join(targetDir, name)
|
|
82
|
+
|
|
83
|
+
if (fs.existsSync(target) || fs.lstatSync(target).isSymbolicLink()) {
|
|
84
|
+
fs.rmSync(target, { recursive: true, force: true })
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (copy) {
|
|
88
|
+
fs.cpSync(source, target, { recursive: true })
|
|
89
|
+
console.log(`copied ${name} -> ${target}`)
|
|
90
|
+
} else {
|
|
91
|
+
fs.symlinkSync(source, target)
|
|
92
|
+
console.log(`linked ${name} -> ${target}`)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function create(): Command {
|
|
98
|
+
const program: Command = new Command()
|
|
99
|
+
program
|
|
100
|
+
.version(version)
|
|
101
|
+
.name('install-skills')
|
|
102
|
+
.description('Install AI agent skills for a coding framework')
|
|
103
|
+
.argument('<framework>', `framework to install for (${frameworks.join(', ')})`)
|
|
104
|
+
.option('--copy', 'copy files instead of creating symlinks')
|
|
105
|
+
.option('--force', 'overwrite existing skill directories')
|
|
106
|
+
.action(async (framework: string, options: { copy?: boolean; force?: boolean }) => {
|
|
107
|
+
if (!frameworks.includes(framework as Framework)) {
|
|
108
|
+
console.error(`Unknown framework: ${framework}`)
|
|
109
|
+
console.error(`Supported frameworks: ${frameworks.join(', ')}`)
|
|
110
|
+
process.exit(1)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (options.force) {
|
|
114
|
+
forceInstallSkills(framework as Framework, !!options.copy)
|
|
115
|
+
} else {
|
|
116
|
+
installSkills(framework as Framework, !!options.copy)
|
|
117
|
+
}
|
|
118
|
+
})
|
|
119
|
+
return program
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export default create
|
|
123
|
+
|
|
124
|
+
if (isMain('gitj-install-skills')) {
|
|
125
|
+
await create().parseAsync(Bun.argv)
|
|
126
|
+
}
|
package/bin/gitj.ts
CHANGED
|
@@ -6,8 +6,12 @@
|
|
|
6
6
|
// from the command line and then call the appropriate subcommand.
|
|
7
7
|
|
|
8
8
|
import { Command } from 'commander'
|
|
9
|
+
import { formatCommandTree } from '../lib/help.ts'
|
|
9
10
|
import { getPackageVersion } from '../lib/package'
|
|
11
|
+
import api from './git-api'
|
|
10
12
|
import bump from './git-bump'
|
|
13
|
+
import confluence from './git-confluence'
|
|
14
|
+
import installSkills from './gitj-install-skills'
|
|
11
15
|
import jira from './git-jira'
|
|
12
16
|
import lab from './git-lab'
|
|
13
17
|
const version = await getPackageVersion()
|
|
@@ -16,10 +20,18 @@ export function create(): Command {
|
|
|
16
20
|
const program: Command = new Command()
|
|
17
21
|
program
|
|
18
22
|
.version(version)
|
|
23
|
+
.option('--help-all', 'Show full command tree')
|
|
24
|
+
.addCommand(api())
|
|
19
25
|
.addCommand(bump())
|
|
26
|
+
.addCommand(confluence())
|
|
27
|
+
.addCommand(installSkills())
|
|
20
28
|
.addCommand(jira())
|
|
21
29
|
.addCommand(lab())
|
|
22
30
|
.action(() => {
|
|
31
|
+
if (program.opts().helpAll) {
|
|
32
|
+
console.log(formatCommandTree(program))
|
|
33
|
+
return
|
|
34
|
+
}
|
|
23
35
|
program.help()
|
|
24
36
|
})
|
|
25
37
|
return program
|