@shirokuma-library/shirokuma-docs 0.1.0-alpha.5
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.
Potentially problematic release.
This version of @shirokuma-library/shirokuma-docs might be problematic. Click here for more details.
- package/LICENSE +21 -0
- package/README.en.md +308 -0
- package/README.md +308 -0
- package/THIRD_PARTY_NOTICES.md +18 -0
- package/bin/shirokuma-docs +2 -0
- package/dist/analyzers/details-test-analysis.d.ts +31 -0
- package/dist/analyzers/details-test-analysis.d.ts.map +1 -0
- package/dist/analyzers/details-test-analysis.js +172 -0
- package/dist/analyzers/details-test-analysis.js.map +1 -0
- package/dist/analyzers/feature-map-builder.d.ts +20 -0
- package/dist/analyzers/feature-map-builder.d.ts.map +1 -0
- package/dist/analyzers/feature-map-builder.js +154 -0
- package/dist/analyzers/feature-map-builder.js.map +1 -0
- package/dist/analyzers/feature-map-references.d.ts +34 -0
- package/dist/analyzers/feature-map-references.d.ts.map +1 -0
- package/dist/analyzers/feature-map-references.js +249 -0
- package/dist/analyzers/feature-map-references.js.map +1 -0
- package/dist/analyzers/reference-analyzer.d.ts +95 -0
- package/dist/analyzers/reference-analyzer.d.ts.map +1 -0
- package/dist/analyzers/reference-analyzer.js +372 -0
- package/dist/analyzers/reference-analyzer.js.map +1 -0
- package/dist/commands/adr.d.ts +26 -0
- package/dist/commands/adr.d.ts.map +1 -0
- package/dist/commands/adr.js +129 -0
- package/dist/commands/adr.js.map +1 -0
- package/dist/commands/api-tools.d.ts +83 -0
- package/dist/commands/api-tools.d.ts.map +1 -0
- package/dist/commands/api-tools.js +775 -0
- package/dist/commands/api-tools.js.map +1 -0
- package/dist/commands/coverage.d.ts +139 -0
- package/dist/commands/coverage.d.ts.map +1 -0
- package/dist/commands/coverage.js +481 -0
- package/dist/commands/coverage.js.map +1 -0
- package/dist/commands/deps.d.ts +24 -0
- package/dist/commands/deps.d.ts.map +1 -0
- package/dist/commands/deps.js +211 -0
- package/dist/commands/deps.js.map +1 -0
- package/dist/commands/details-context.d.ts +38 -0
- package/dist/commands/details-context.d.ts.map +1 -0
- package/dist/commands/details-context.js +193 -0
- package/dist/commands/details-context.js.map +1 -0
- package/dist/commands/details-types.d.ts +315 -0
- package/dist/commands/details-types.d.ts.map +1 -0
- package/dist/commands/details-types.js +7 -0
- package/dist/commands/details-types.js.map +1 -0
- package/dist/commands/details.d.ts +24 -0
- package/dist/commands/details.d.ts.map +1 -0
- package/dist/commands/details.js +299 -0
- package/dist/commands/details.js.map +1 -0
- package/dist/commands/discussion-templates.d.ts +26 -0
- package/dist/commands/discussion-templates.d.ts.map +1 -0
- package/dist/commands/discussion-templates.js +270 -0
- package/dist/commands/discussion-templates.js.map +1 -0
- package/dist/commands/discussions.d.ts +31 -0
- package/dist/commands/discussions.d.ts.map +1 -0
- package/dist/commands/discussions.js +743 -0
- package/dist/commands/discussions.js.map +1 -0
- package/dist/commands/feature-map-types.d.ts +294 -0
- package/dist/commands/feature-map-types.d.ts.map +1 -0
- package/dist/commands/feature-map-types.js +8 -0
- package/dist/commands/feature-map-types.js.map +1 -0
- package/dist/commands/feature-map.d.ts +30 -0
- package/dist/commands/feature-map.d.ts.map +1 -0
- package/dist/commands/feature-map.js +137 -0
- package/dist/commands/feature-map.js.map +1 -0
- package/dist/commands/generate.d.ts +16 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +88 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/gh-discussions.d.ts +31 -0
- package/dist/commands/gh-discussions.d.ts.map +1 -0
- package/dist/commands/gh-discussions.js +743 -0
- package/dist/commands/gh-discussions.js.map +1 -0
- package/dist/commands/gh-issues-pr.d.ts +74 -0
- package/dist/commands/gh-issues-pr.d.ts.map +1 -0
- package/dist/commands/gh-issues-pr.js +417 -0
- package/dist/commands/gh-issues-pr.js.map +1 -0
- package/dist/commands/gh-issues.d.ts +90 -0
- package/dist/commands/gh-issues.d.ts.map +1 -0
- package/dist/commands/gh-issues.js +1297 -0
- package/dist/commands/gh-issues.js.map +1 -0
- package/dist/commands/gh-projects.d.ts +54 -0
- package/dist/commands/gh-projects.d.ts.map +1 -0
- package/dist/commands/gh-projects.js +966 -0
- package/dist/commands/gh-projects.js.map +1 -0
- package/dist/commands/gh-repo.d.ts +18 -0
- package/dist/commands/gh-repo.d.ts.map +1 -0
- package/dist/commands/gh-repo.js +253 -0
- package/dist/commands/gh-repo.js.map +1 -0
- package/dist/commands/github-data.d.ts +67 -0
- package/dist/commands/github-data.d.ts.map +1 -0
- package/dist/commands/github-data.js +361 -0
- package/dist/commands/github-data.js.map +1 -0
- package/dist/commands/i18n.d.ts +102 -0
- package/dist/commands/i18n.d.ts.map +1 -0
- package/dist/commands/i18n.js +829 -0
- package/dist/commands/i18n.js.map +1 -0
- package/dist/commands/impact.d.ts +14 -0
- package/dist/commands/impact.d.ts.map +1 -0
- package/dist/commands/impact.js +263 -0
- package/dist/commands/impact.js.map +1 -0
- package/dist/commands/init.d.ts +53 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +429 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/issues-pr.d.ts +74 -0
- package/dist/commands/issues-pr.d.ts.map +1 -0
- package/dist/commands/issues-pr.js +417 -0
- package/dist/commands/issues-pr.js.map +1 -0
- package/dist/commands/issues.d.ts +76 -0
- package/dist/commands/issues.d.ts.map +1 -0
- package/dist/commands/issues.js +1285 -0
- package/dist/commands/issues.js.map +1 -0
- package/dist/commands/link-docs.d.ts +21 -0
- package/dist/commands/link-docs.d.ts.map +1 -0
- package/dist/commands/link-docs.js +990 -0
- package/dist/commands/link-docs.js.map +1 -0
- package/dist/commands/lint-annotations.d.ts +28 -0
- package/dist/commands/lint-annotations.d.ts.map +1 -0
- package/dist/commands/lint-annotations.js +511 -0
- package/dist/commands/lint-annotations.js.map +1 -0
- package/dist/commands/lint-code.d.ts +26 -0
- package/dist/commands/lint-code.d.ts.map +1 -0
- package/dist/commands/lint-code.js +428 -0
- package/dist/commands/lint-code.js.map +1 -0
- package/dist/commands/lint-coverage.d.ts +33 -0
- package/dist/commands/lint-coverage.d.ts.map +1 -0
- package/dist/commands/lint-coverage.js +379 -0
- package/dist/commands/lint-coverage.js.map +1 -0
- package/dist/commands/lint-docs.d.ts +23 -0
- package/dist/commands/lint-docs.d.ts.map +1 -0
- package/dist/commands/lint-docs.js +338 -0
- package/dist/commands/lint-docs.js.map +1 -0
- package/dist/commands/lint-structure.d.ts +38 -0
- package/dist/commands/lint-structure.d.ts.map +1 -0
- package/dist/commands/lint-structure.js +350 -0
- package/dist/commands/lint-structure.js.map +1 -0
- package/dist/commands/lint-tests.d.ts +25 -0
- package/dist/commands/lint-tests.d.ts.map +1 -0
- package/dist/commands/lint-tests.js +105 -0
- package/dist/commands/lint-tests.js.map +1 -0
- package/dist/commands/lint-workflow.d.ts +36 -0
- package/dist/commands/lint-workflow.d.ts.map +1 -0
- package/dist/commands/lint-workflow.js +255 -0
- package/dist/commands/lint-workflow.js.map +1 -0
- package/dist/commands/overview.d.ts +21 -0
- package/dist/commands/overview.d.ts.map +1 -0
- package/dist/commands/overview.js +1300 -0
- package/dist/commands/overview.js.map +1 -0
- package/dist/commands/packages.d.ts +107 -0
- package/dist/commands/packages.d.ts.map +1 -0
- package/dist/commands/packages.js +308 -0
- package/dist/commands/packages.js.map +1 -0
- package/dist/commands/portal-nextjs.d.ts +23 -0
- package/dist/commands/portal-nextjs.d.ts.map +1 -0
- package/dist/commands/portal-nextjs.js +336 -0
- package/dist/commands/portal-nextjs.js.map +1 -0
- package/dist/commands/portal.d.ts +24 -0
- package/dist/commands/portal.d.ts.map +1 -0
- package/dist/commands/portal.js +16 -0
- package/dist/commands/portal.js.map +1 -0
- package/dist/commands/projects.d.ts +54 -0
- package/dist/commands/projects.d.ts.map +1 -0
- package/dist/commands/projects.js +969 -0
- package/dist/commands/projects.js.map +1 -0
- package/dist/commands/repo-pairs.d.ts +19 -0
- package/dist/commands/repo-pairs.d.ts.map +1 -0
- package/dist/commands/repo-pairs.js +529 -0
- package/dist/commands/repo-pairs.js.map +1 -0
- package/dist/commands/repo.d.ts +18 -0
- package/dist/commands/repo.d.ts.map +1 -0
- package/dist/commands/repo.js +253 -0
- package/dist/commands/repo.js.map +1 -0
- package/dist/commands/schema.d.ts +49 -0
- package/dist/commands/schema.d.ts.map +1 -0
- package/dist/commands/schema.js +830 -0
- package/dist/commands/schema.js.map +1 -0
- package/dist/commands/screenshots.d.ts +203 -0
- package/dist/commands/screenshots.d.ts.map +1 -0
- package/dist/commands/screenshots.js +1234 -0
- package/dist/commands/screenshots.js.map +1 -0
- package/dist/commands/search-index.d.ts +83 -0
- package/dist/commands/search-index.d.ts.map +1 -0
- package/dist/commands/search-index.js +389 -0
- package/dist/commands/search-index.js.map +1 -0
- package/dist/commands/session.d.ts +153 -0
- package/dist/commands/session.d.ts.map +1 -0
- package/dist/commands/session.js +1243 -0
- package/dist/commands/session.js.map +1 -0
- package/dist/commands/test-cases-types.d.ts +154 -0
- package/dist/commands/test-cases-types.d.ts.map +1 -0
- package/dist/commands/test-cases-types.js +7 -0
- package/dist/commands/test-cases-types.js.map +1 -0
- package/dist/commands/test-cases.d.ts +28 -0
- package/dist/commands/test-cases.d.ts.map +1 -0
- package/dist/commands/test-cases.js +192 -0
- package/dist/commands/test-cases.js.map +1 -0
- package/dist/commands/typedoc.d.ts +21 -0
- package/dist/commands/typedoc.d.ts.map +1 -0
- package/dist/commands/typedoc.js +192 -0
- package/dist/commands/typedoc.js.map +1 -0
- package/dist/commands/update-skills.d.ts +56 -0
- package/dist/commands/update-skills.d.ts.map +1 -0
- package/dist/commands/update-skills.js +620 -0
- package/dist/commands/update-skills.js.map +1 -0
- package/dist/generators/details-entity-pages.d.ts +40 -0
- package/dist/generators/details-entity-pages.d.ts.map +1 -0
- package/dist/generators/details-entity-pages.js +301 -0
- package/dist/generators/details-entity-pages.js.map +1 -0
- package/dist/generators/details-html.d.ts +23 -0
- package/dist/generators/details-html.d.ts.map +1 -0
- package/dist/generators/details-html.js +324 -0
- package/dist/generators/details-html.js.map +1 -0
- package/dist/generators/details-module-page.d.ts +33 -0
- package/dist/generators/details-module-page.d.ts.map +1 -0
- package/dist/generators/details-module-page.js +408 -0
- package/dist/generators/details-module-page.js.map +1 -0
- package/dist/generators/details-styles.d.ts +39 -0
- package/dist/generators/details-styles.d.ts.map +1 -0
- package/dist/generators/details-styles.js +409 -0
- package/dist/generators/details-styles.js.map +1 -0
- package/dist/generators/feature-map-html.d.ts +66 -0
- package/dist/generators/feature-map-html.d.ts.map +1 -0
- package/dist/generators/feature-map-html.js +569 -0
- package/dist/generators/feature-map-html.js.map +1 -0
- package/dist/generators/feature-map-styles.d.ts +39 -0
- package/dist/generators/feature-map-styles.d.ts.map +1 -0
- package/dist/generators/feature-map-styles.js +449 -0
- package/dist/generators/feature-map-styles.js.map +1 -0
- package/dist/generators/test-cases-hierarchy.d.ts +21 -0
- package/dist/generators/test-cases-hierarchy.d.ts.map +1 -0
- package/dist/generators/test-cases-hierarchy.js +336 -0
- package/dist/generators/test-cases-hierarchy.js.map +1 -0
- package/dist/generators/test-cases-main.d.ts +20 -0
- package/dist/generators/test-cases-main.d.ts.map +1 -0
- package/dist/generators/test-cases-main.js +439 -0
- package/dist/generators/test-cases-main.js.map +1 -0
- package/dist/generators/test-cases-styles.d.ts +64 -0
- package/dist/generators/test-cases-styles.d.ts.map +1 -0
- package/dist/generators/test-cases-styles.js +1277 -0
- package/dist/generators/test-cases-styles.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +517 -0
- package/dist/index.js.map +1 -0
- package/dist/lint/annotation-lint.d.ts +198 -0
- package/dist/lint/annotation-lint.d.ts.map +1 -0
- package/dist/lint/annotation-lint.js +510 -0
- package/dist/lint/annotation-lint.js.map +1 -0
- package/dist/lint/annotation-types.d.ts +161 -0
- package/dist/lint/annotation-types.d.ts.map +1 -0
- package/dist/lint/annotation-types.js +31 -0
- package/dist/lint/annotation-types.js.map +1 -0
- package/dist/lint/code-types.d.ts +135 -0
- package/dist/lint/code-types.d.ts.map +1 -0
- package/dist/lint/code-types.js +25 -0
- package/dist/lint/code-types.js.map +1 -0
- package/dist/lint/coverage-types.d.ts +128 -0
- package/dist/lint/coverage-types.d.ts.map +1 -0
- package/dist/lint/coverage-types.js +24 -0
- package/dist/lint/coverage-types.js.map +1 -0
- package/dist/lint/docs-types.d.ts +214 -0
- package/dist/lint/docs-types.d.ts.map +1 -0
- package/dist/lint/docs-types.js +18 -0
- package/dist/lint/docs-types.js.map +1 -0
- package/dist/lint/formatters/index.d.ts +14 -0
- package/dist/lint/formatters/index.d.ts.map +1 -0
- package/dist/lint/formatters/index.js +28 -0
- package/dist/lint/formatters/index.js.map +1 -0
- package/dist/lint/formatters/json.d.ts +11 -0
- package/dist/lint/formatters/json.d.ts.map +1 -0
- package/dist/lint/formatters/json.js +12 -0
- package/dist/lint/formatters/json.js.map +1 -0
- package/dist/lint/formatters/summary.d.ts +11 -0
- package/dist/lint/formatters/summary.d.ts.map +1 -0
- package/dist/lint/formatters/summary.js +37 -0
- package/dist/lint/formatters/summary.js.map +1 -0
- package/dist/lint/formatters/terminal.d.ts +11 -0
- package/dist/lint/formatters/terminal.d.ts.map +1 -0
- package/dist/lint/formatters/terminal.js +99 -0
- package/dist/lint/formatters/terminal.js.map +1 -0
- package/dist/lint/index.d.ts +18 -0
- package/dist/lint/index.d.ts.map +1 -0
- package/dist/lint/index.js +103 -0
- package/dist/lint/index.js.map +1 -0
- package/dist/lint/rules/annotation-required.d.ts +35 -0
- package/dist/lint/rules/annotation-required.d.ts.map +1 -0
- package/dist/lint/rules/annotation-required.js +127 -0
- package/dist/lint/rules/annotation-required.js.map +1 -0
- package/dist/lint/rules/code-rules.d.ts +12 -0
- package/dist/lint/rules/code-rules.d.ts.map +1 -0
- package/dist/lint/rules/code-rules.js +11 -0
- package/dist/lint/rules/code-rules.js.map +1 -0
- package/dist/lint/rules/describe-coverage.d.ts +8 -0
- package/dist/lint/rules/describe-coverage.d.ts.map +1 -0
- package/dist/lint/rules/describe-coverage.js +43 -0
- package/dist/lint/rules/describe-coverage.js.map +1 -0
- package/dist/lint/rules/duplicate-testdoc.d.ts +8 -0
- package/dist/lint/rules/duplicate-testdoc.d.ts.map +1 -0
- package/dist/lint/rules/duplicate-testdoc.js +38 -0
- package/dist/lint/rules/duplicate-testdoc.js.map +1 -0
- package/dist/lint/rules/index.d.ts +29 -0
- package/dist/lint/rules/index.d.ts.map +1 -0
- package/dist/lint/rules/index.js +55 -0
- package/dist/lint/rules/index.js.map +1 -0
- package/dist/lint/rules/server-action-structure.d.ts +37 -0
- package/dist/lint/rules/server-action-structure.d.ts.map +1 -0
- package/dist/lint/rules/server-action-structure.js +151 -0
- package/dist/lint/rules/server-action-structure.js.map +1 -0
- package/dist/lint/rules/skipped-test-report.d.ts +11 -0
- package/dist/lint/rules/skipped-test-report.d.ts.map +1 -0
- package/dist/lint/rules/skipped-test-report.js +31 -0
- package/dist/lint/rules/skipped-test-report.js.map +1 -0
- package/dist/lint/rules/structure-rules.d.ts +67 -0
- package/dist/lint/rules/structure-rules.d.ts.map +1 -0
- package/dist/lint/rules/structure-rules.js +615 -0
- package/dist/lint/rules/structure-rules.js.map +1 -0
- package/dist/lint/rules/testdoc-japanese.d.ts +8 -0
- package/dist/lint/rules/testdoc-japanese.d.ts.map +1 -0
- package/dist/lint/rules/testdoc-japanese.js +31 -0
- package/dist/lint/rules/testdoc-japanese.js.map +1 -0
- package/dist/lint/rules/testdoc-min-length.d.ts +8 -0
- package/dist/lint/rules/testdoc-min-length.d.ts.map +1 -0
- package/dist/lint/rules/testdoc-min-length.js +31 -0
- package/dist/lint/rules/testdoc-min-length.js.map +1 -0
- package/dist/lint/rules/testdoc-required.d.ts +8 -0
- package/dist/lint/rules/testdoc-required.d.ts.map +1 -0
- package/dist/lint/rules/testdoc-required.js +27 -0
- package/dist/lint/rules/testdoc-required.js.map +1 -0
- package/dist/lint/rules/workflow-branch-naming.d.ts +20 -0
- package/dist/lint/rules/workflow-branch-naming.d.ts.map +1 -0
- package/dist/lint/rules/workflow-branch-naming.js +85 -0
- package/dist/lint/rules/workflow-branch-naming.js.map +1 -0
- package/dist/lint/rules/workflow-commit-format.d.ts +27 -0
- package/dist/lint/rules/workflow-commit-format.d.ts.map +1 -0
- package/dist/lint/rules/workflow-commit-format.js +92 -0
- package/dist/lint/rules/workflow-commit-format.js.map +1 -0
- package/dist/lint/rules/workflow-issue-fields.d.ts +24 -0
- package/dist/lint/rules/workflow-issue-fields.d.ts.map +1 -0
- package/dist/lint/rules/workflow-issue-fields.js +89 -0
- package/dist/lint/rules/workflow-issue-fields.js.map +1 -0
- package/dist/lint/rules/workflow-main-protection.d.ts +32 -0
- package/dist/lint/rules/workflow-main-protection.d.ts.map +1 -0
- package/dist/lint/rules/workflow-main-protection.js +114 -0
- package/dist/lint/rules/workflow-main-protection.js.map +1 -0
- package/dist/lint/structure-types.d.ts +216 -0
- package/dist/lint/structure-types.d.ts.map +1 -0
- package/dist/lint/structure-types.js +96 -0
- package/dist/lint/structure-types.js.map +1 -0
- package/dist/lint/types.d.ts +154 -0
- package/dist/lint/types.d.ts.map +1 -0
- package/dist/lint/types.js +21 -0
- package/dist/lint/types.js.map +1 -0
- package/dist/lint/workflow-types.d.ts +90 -0
- package/dist/lint/workflow-types.d.ts.map +1 -0
- package/dist/lint/workflow-types.js +7 -0
- package/dist/lint/workflow-types.js.map +1 -0
- package/dist/md/analyzer/index.d.ts +46 -0
- package/dist/md/analyzer/index.d.ts.map +1 -0
- package/dist/md/analyzer/index.js +288 -0
- package/dist/md/analyzer/index.js.map +1 -0
- package/dist/md/builder/index.d.ts +91 -0
- package/dist/md/builder/index.d.ts.map +1 -0
- package/dist/md/builder/index.js +446 -0
- package/dist/md/builder/index.js.map +1 -0
- package/dist/md/cli/analyze.d.ts +11 -0
- package/dist/md/cli/analyze.d.ts.map +1 -0
- package/dist/md/cli/analyze.js +118 -0
- package/dist/md/cli/analyze.js.map +1 -0
- package/dist/md/cli/build.d.ts +11 -0
- package/dist/md/cli/build.d.ts.map +1 -0
- package/dist/md/cli/build.js +74 -0
- package/dist/md/cli/build.js.map +1 -0
- package/dist/md/cli/extract.d.ts +25 -0
- package/dist/md/cli/extract.d.ts.map +1 -0
- package/dist/md/cli/extract.js +230 -0
- package/dist/md/cli/extract.js.map +1 -0
- package/dist/md/cli/index.d.ts +3 -0
- package/dist/md/cli/index.d.ts.map +1 -0
- package/dist/md/cli/index.js +99 -0
- package/dist/md/cli/index.js.map +1 -0
- package/dist/md/cli/lint.d.ts +11 -0
- package/dist/md/cli/lint.d.ts.map +1 -0
- package/dist/md/cli/lint.js +165 -0
- package/dist/md/cli/lint.js.map +1 -0
- package/dist/md/cli/list.d.ts +16 -0
- package/dist/md/cli/list.d.ts.map +1 -0
- package/dist/md/cli/list.js +85 -0
- package/dist/md/cli/list.js.map +1 -0
- package/dist/md/cli/program.d.ts +11 -0
- package/dist/md/cli/program.d.ts.map +1 -0
- package/dist/md/cli/program.js +104 -0
- package/dist/md/cli/program.js.map +1 -0
- package/dist/md/cli/validate.d.ts +8 -0
- package/dist/md/cli/validate.d.ts.map +1 -0
- package/dist/md/cli/validate.js +82 -0
- package/dist/md/cli/validate.js.map +1 -0
- package/dist/md/constants.d.ts +69 -0
- package/dist/md/constants.d.ts.map +1 -0
- package/dist/md/constants.js +69 -0
- package/dist/md/constants.js.map +1 -0
- package/dist/md/extractor/index.d.ts +57 -0
- package/dist/md/extractor/index.d.ts.map +1 -0
- package/dist/md/extractor/index.js +359 -0
- package/dist/md/extractor/index.js.map +1 -0
- package/dist/md/index.d.ts +26 -0
- package/dist/md/index.d.ts.map +1 -0
- package/dist/md/index.js +30 -0
- package/dist/md/index.js.map +1 -0
- package/dist/md/linter/index.d.ts +20 -0
- package/dist/md/linter/index.d.ts.map +1 -0
- package/dist/md/linter/index.js +412 -0
- package/dist/md/linter/index.js.map +1 -0
- package/dist/md/linter/token-optimizer.d.ts +66 -0
- package/dist/md/linter/token-optimizer.d.ts.map +1 -0
- package/dist/md/linter/token-optimizer.js +292 -0
- package/dist/md/linter/token-optimizer.js.map +1 -0
- package/dist/md/lister/index.d.ts +42 -0
- package/dist/md/lister/index.d.ts.map +1 -0
- package/dist/md/lister/index.js +317 -0
- package/dist/md/lister/index.js.map +1 -0
- package/dist/md/parser/heading-numbers.d.ts +43 -0
- package/dist/md/parser/heading-numbers.d.ts.map +1 -0
- package/dist/md/parser/heading-numbers.js +97 -0
- package/dist/md/parser/heading-numbers.js.map +1 -0
- package/dist/md/parser/section-meta.d.ts +50 -0
- package/dist/md/parser/section-meta.d.ts.map +1 -0
- package/dist/md/parser/section-meta.js +212 -0
- package/dist/md/parser/section-meta.js.map +1 -0
- package/dist/md/parser/template.d.ts +56 -0
- package/dist/md/parser/template.d.ts.map +1 -0
- package/dist/md/parser/template.js +122 -0
- package/dist/md/parser/template.js.map +1 -0
- package/dist/md/plugins/loader.d.ts +15 -0
- package/dist/md/plugins/loader.d.ts.map +1 -0
- package/dist/md/plugins/loader.js +80 -0
- package/dist/md/plugins/loader.js.map +1 -0
- package/dist/md/plugins/normalize-headings.d.ts +43 -0
- package/dist/md/plugins/normalize-headings.d.ts.map +1 -0
- package/dist/md/plugins/normalize-headings.js +51 -0
- package/dist/md/plugins/normalize-headings.js.map +1 -0
- package/dist/md/plugins/normalize-whitespace.d.ts +46 -0
- package/dist/md/plugins/normalize-whitespace.d.ts.map +1 -0
- package/dist/md/plugins/normalize-whitespace.js +86 -0
- package/dist/md/plugins/normalize-whitespace.js.map +1 -0
- package/dist/md/plugins/remove-badges.d.ts +36 -0
- package/dist/md/plugins/remove-badges.d.ts.map +1 -0
- package/dist/md/plugins/remove-badges.js +59 -0
- package/dist/md/plugins/remove-badges.js.map +1 -0
- package/dist/md/plugins/remove-comments.d.ts +27 -0
- package/dist/md/plugins/remove-comments.d.ts.map +1 -0
- package/dist/md/plugins/remove-comments.js +40 -0
- package/dist/md/plugins/remove-comments.js.map +1 -0
- package/dist/md/plugins/remove-duplicates.d.ts +40 -0
- package/dist/md/plugins/remove-duplicates.d.ts.map +1 -0
- package/dist/md/plugins/remove-duplicates.js +72 -0
- package/dist/md/plugins/remove-duplicates.js.map +1 -0
- package/dist/md/plugins/remove-internal-links.d.ts +38 -0
- package/dist/md/plugins/remove-internal-links.d.ts.map +1 -0
- package/dist/md/plugins/remove-internal-links.js +66 -0
- package/dist/md/plugins/remove-internal-links.js.map +1 -0
- package/dist/md/plugins/strip-heading-numbers.d.ts +35 -0
- package/dist/md/plugins/strip-heading-numbers.d.ts.map +1 -0
- package/dist/md/plugins/strip-heading-numbers.js +59 -0
- package/dist/md/plugins/strip-heading-numbers.js.map +1 -0
- package/dist/md/plugins/strip-section-meta.d.ts +37 -0
- package/dist/md/plugins/strip-section-meta.d.ts.map +1 -0
- package/dist/md/plugins/strip-section-meta.js +62 -0
- package/dist/md/plugins/strip-section-meta.js.map +1 -0
- package/dist/md/types/config.d.ts +260 -0
- package/dist/md/types/config.d.ts.map +1 -0
- package/dist/md/types/config.js +156 -0
- package/dist/md/types/config.js.map +1 -0
- package/dist/md/types/document.d.ts +37 -0
- package/dist/md/types/document.d.ts.map +1 -0
- package/dist/md/types/document.js +2 -0
- package/dist/md/types/document.js.map +1 -0
- package/dist/md/types/validation.d.ts +107 -0
- package/dist/md/types/validation.d.ts.map +1 -0
- package/dist/md/types/validation.js +2 -0
- package/dist/md/types/validation.js.map +1 -0
- package/dist/md/utils/code-blocks.d.ts +136 -0
- package/dist/md/utils/code-blocks.d.ts.map +1 -0
- package/dist/md/utils/code-blocks.js +178 -0
- package/dist/md/utils/code-blocks.js.map +1 -0
- package/dist/md/utils/config.d.ts +10 -0
- package/dist/md/utils/config.d.ts.map +1 -0
- package/dist/md/utils/config.js +99 -0
- package/dist/md/utils/config.js.map +1 -0
- package/dist/md/utils/file-collector.d.ts +78 -0
- package/dist/md/utils/file-collector.d.ts.map +1 -0
- package/dist/md/utils/file-collector.js +100 -0
- package/dist/md/utils/file-collector.js.map +1 -0
- package/dist/md/utils/markdown.d.ts +18 -0
- package/dist/md/utils/markdown.d.ts.map +1 -0
- package/dist/md/utils/markdown.js +93 -0
- package/dist/md/utils/markdown.js.map +1 -0
- package/dist/md/utils/remark.d.ts +91 -0
- package/dist/md/utils/remark.d.ts.map +1 -0
- package/dist/md/utils/remark.js +125 -0
- package/dist/md/utils/remark.js.map +1 -0
- package/dist/md/utils/tokens.d.ts +9 -0
- package/dist/md/utils/tokens.d.ts.map +1 -0
- package/dist/md/utils/tokens.js +31 -0
- package/dist/md/utils/tokens.js.map +1 -0
- package/dist/md/validator/index.d.ts +40 -0
- package/dist/md/validator/index.d.ts.map +1 -0
- package/dist/md/validator/index.js +289 -0
- package/dist/md/validator/index.js.map +1 -0
- package/dist/parsers/details-jsdoc.d.ts +46 -0
- package/dist/parsers/details-jsdoc.d.ts.map +1 -0
- package/dist/parsers/details-jsdoc.js +262 -0
- package/dist/parsers/details-jsdoc.js.map +1 -0
- package/dist/parsers/details-zod.d.ts +22 -0
- package/dist/parsers/details-zod.d.ts.map +1 -0
- package/dist/parsers/details-zod.js +145 -0
- package/dist/parsers/details-zod.js.map +1 -0
- package/dist/parsers/drizzle-schema.d.ts +92 -0
- package/dist/parsers/drizzle-schema.d.ts.map +1 -0
- package/dist/parsers/drizzle-schema.js +376 -0
- package/dist/parsers/drizzle-schema.js.map +1 -0
- package/dist/parsers/feature-map-tags.d.ts +45 -0
- package/dist/parsers/feature-map-tags.d.ts.map +1 -0
- package/dist/parsers/feature-map-tags.js +292 -0
- package/dist/parsers/feature-map-tags.js.map +1 -0
- package/dist/parsers/feature-map-type-extraction.d.ts +62 -0
- package/dist/parsers/feature-map-type-extraction.d.ts.map +1 -0
- package/dist/parsers/feature-map-type-extraction.js +347 -0
- package/dist/parsers/feature-map-type-extraction.js.map +1 -0
- package/dist/parsers/feature-map-utils.d.ts +34 -0
- package/dist/parsers/feature-map-utils.d.ts.map +1 -0
- package/dist/parsers/feature-map-utils.js +101 -0
- package/dist/parsers/feature-map-utils.js.map +1 -0
- package/dist/parsers/jsdoc-common.d.ts +209 -0
- package/dist/parsers/jsdoc-common.d.ts.map +1 -0
- package/dist/parsers/jsdoc-common.js +655 -0
- package/dist/parsers/jsdoc-common.js.map +1 -0
- package/dist/parsers/jsdoc.d.ts +76 -0
- package/dist/parsers/jsdoc.d.ts.map +1 -0
- package/dist/parsers/jsdoc.js +238 -0
- package/dist/parsers/jsdoc.js.map +1 -0
- package/dist/parsers/screenshot-annotations.d.ts +96 -0
- package/dist/parsers/screenshot-annotations.d.ts.map +1 -0
- package/dist/parsers/screenshot-annotations.js +227 -0
- package/dist/parsers/screenshot-annotations.js.map +1 -0
- package/dist/parsers/test-annotations.d.ts +46 -0
- package/dist/parsers/test-annotations.d.ts.map +1 -0
- package/dist/parsers/test-annotations.js +393 -0
- package/dist/parsers/test-annotations.js.map +1 -0
- package/dist/parsers/test-categorization.d.ts +42 -0
- package/dist/parsers/test-categorization.d.ts.map +1 -0
- package/dist/parsers/test-categorization.js +182 -0
- package/dist/parsers/test-categorization.js.map +1 -0
- package/dist/parsers/zod-schema.d.ts +105 -0
- package/dist/parsers/zod-schema.d.ts.map +1 -0
- package/dist/parsers/zod-schema.js +270 -0
- package/dist/parsers/zod-schema.js.map +1 -0
- package/dist/utils/action-inference.d.ts +23 -0
- package/dist/utils/action-inference.d.ts.map +1 -0
- package/dist/utils/action-inference.js +36 -0
- package/dist/utils/action-inference.js.map +1 -0
- package/dist/utils/app-inference.d.ts +31 -0
- package/dist/utils/app-inference.d.ts.map +1 -0
- package/dist/utils/app-inference.js +41 -0
- package/dist/utils/app-inference.js.map +1 -0
- package/dist/utils/auto-infer.d.ts +93 -0
- package/dist/utils/auto-infer.d.ts.map +1 -0
- package/dist/utils/auto-infer.js +184 -0
- package/dist/utils/auto-infer.js.map +1 -0
- package/dist/utils/config.d.ts +709 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +504 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/file.d.ts +46 -0
- package/dist/utils/file.d.ts.map +1 -0
- package/dist/utils/file.js +103 -0
- package/dist/utils/file.js.map +1 -0
- package/dist/utils/formatters.d.ts +111 -0
- package/dist/utils/formatters.d.ts.map +1 -0
- package/dist/utils/formatters.js +164 -0
- package/dist/utils/formatters.js.map +1 -0
- package/dist/utils/gh-config.d.ts +99 -0
- package/dist/utils/gh-config.d.ts.map +1 -0
- package/dist/utils/gh-config.js +247 -0
- package/dist/utils/gh-config.js.map +1 -0
- package/dist/utils/github.d.ts +98 -0
- package/dist/utils/github.d.ts.map +1 -0
- package/dist/utils/github.js +295 -0
- package/dist/utils/github.js.map +1 -0
- package/dist/utils/html.d.ts +107 -0
- package/dist/utils/html.d.ts.map +1 -0
- package/dist/utils/html.js +376 -0
- package/dist/utils/html.js.map +1 -0
- package/dist/utils/i18n.d.ts +40 -0
- package/dist/utils/i18n.d.ts.map +1 -0
- package/dist/utils/i18n.js +148 -0
- package/dist/utils/i18n.js.map +1 -0
- package/dist/utils/logger.d.ts +20 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +49 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/project-fields.d.ts +71 -0
- package/dist/utils/project-fields.d.ts.map +1 -0
- package/dist/utils/project-fields.js +318 -0
- package/dist/utils/project-fields.js.map +1 -0
- package/dist/utils/repo-pairs.d.ts +94 -0
- package/dist/utils/repo-pairs.d.ts.map +1 -0
- package/dist/utils/repo-pairs.js +196 -0
- package/dist/utils/repo-pairs.js.map +1 -0
- package/dist/utils/route-inference.d.ts +81 -0
- package/dist/utils/route-inference.d.ts.map +1 -0
- package/dist/utils/route-inference.js +137 -0
- package/dist/utils/route-inference.js.map +1 -0
- package/dist/utils/setup-check.d.ts +34 -0
- package/dist/utils/setup-check.d.ts.map +1 -0
- package/dist/utils/setup-check.js +136 -0
- package/dist/utils/setup-check.js.map +1 -0
- package/dist/utils/shirokumaignore.d.ts +55 -0
- package/dist/utils/shirokumaignore.d.ts.map +1 -0
- package/dist/utils/shirokumaignore.js +94 -0
- package/dist/utils/shirokumaignore.js.map +1 -0
- package/dist/utils/skills-repo.d.ts +353 -0
- package/dist/utils/skills-repo.d.ts.map +1 -0
- package/dist/utils/skills-repo.js +793 -0
- package/dist/utils/skills-repo.js.map +1 -0
- package/dist/utils/status-workflow.d.ts +54 -0
- package/dist/utils/status-workflow.d.ts.map +1 -0
- package/dist/utils/status-workflow.js +103 -0
- package/dist/utils/status-workflow.js.map +1 -0
- package/dist/validators/frontmatter.d.ts +41 -0
- package/dist/validators/frontmatter.d.ts.map +1 -0
- package/dist/validators/frontmatter.js +117 -0
- package/dist/validators/frontmatter.js.map +1 -0
- package/dist/validators/link-checker.d.ts +48 -0
- package/dist/validators/link-checker.d.ts.map +1 -0
- package/dist/validators/link-checker.js +108 -0
- package/dist/validators/link-checker.js.map +1 -0
- package/dist/validators/markdown-structure.d.ts +50 -0
- package/dist/validators/markdown-structure.d.ts.map +1 -0
- package/dist/validators/markdown-structure.js +253 -0
- package/dist/validators/markdown-structure.js.map +1 -0
- package/i18n/cli/en.json +155 -0
- package/i18n/cli/ja.json +155 -0
- package/i18n/discussion/en.json +191 -0
- package/i18n/discussion/ja.json +191 -0
- package/package.json +113 -0
- package/portal/app/api-tools/api-tools-client.tsx +411 -0
- package/portal/app/api-tools/api-tools-document.tsx +240 -0
- package/portal/app/api-tools/page.tsx +56 -0
- package/portal/app/api-tools/swagger-view.tsx +114 -0
- package/portal/app/apps/[appId]/[type]/[module]/[item]/item-tabs-client.tsx +71 -0
- package/portal/app/apps/[appId]/[type]/[module]/[item]/page.tsx +1422 -0
- package/portal/app/apps/[appId]/[type]/[module]/page.tsx +373 -0
- package/portal/app/apps/[appId]/feature-map/feature-map-app-document.tsx +298 -0
- package/portal/app/apps/[appId]/feature-map/page.tsx +224 -0
- package/portal/app/apps/[appId]/i18n/page.tsx +139 -0
- package/portal/app/apps/[appId]/test-cases/page.tsx +840 -0
- package/portal/app/apps/[appId]/tools/[tool]/page.tsx +351 -0
- package/portal/app/apps/[appId]/tools/api-tools-client.tsx +429 -0
- package/portal/app/apps/[appId]/tools/page.tsx +119 -0
- package/portal/app/db-schema/[db]/[table]/page.tsx +235 -0
- package/portal/app/db-schema/[db]/diagram/page.tsx +81 -0
- package/portal/app/db-schema/[db]/page.tsx +148 -0
- package/portal/app/db-schema/db-schema-document.tsx +100 -0
- package/portal/app/db-schema/diagram/client.tsx +211 -0
- package/portal/app/db-schema/diagram/page.tsx +20 -0
- package/portal/app/db-schema/page.tsx +145 -0
- package/portal/app/db-schema/table-detail-document.tsx +710 -0
- package/portal/app/db-schema/table-detail.tsx +747 -0
- package/portal/app/db-schema/table-list-document.tsx +224 -0
- package/portal/app/db-schema/table-list.tsx +247 -0
- package/portal/app/details/[type]/[module]/[item]/item-tabs-client.tsx +71 -0
- package/portal/app/details/[type]/[module]/[item]/page.tsx +1286 -0
- package/portal/app/details/[type]/[module]/page.tsx +884 -0
- package/portal/app/feature-map/feature-map-client.tsx +681 -0
- package/portal/app/feature-map/feature-map-document.tsx +313 -0
- package/portal/app/feature-map/page.tsx +438 -0
- package/portal/app/globals.css +205 -0
- package/portal/app/i18n/[...namespace]/page.tsx +190 -0
- package/portal/app/i18n/i18n-client.tsx +369 -0
- package/portal/app/i18n/page.tsx +339 -0
- package/portal/app/layout.tsx +37 -0
- package/portal/app/overview/page.tsx +65 -0
- package/portal/app/packages/[packageId]/page.tsx +201 -0
- package/portal/app/packages/page.tsx +148 -0
- package/portal/app/page.tsx +568 -0
- package/portal/app/test-cases/[file]/[line]/page.tsx +455 -0
- package/portal/app/test-cases/[file]/[line]/test-detail-document.tsx +335 -0
- package/portal/app/test-cases/[file]/page.tsx +323 -0
- package/portal/app/test-cases/[file]/test-file-document.tsx +335 -0
- package/portal/app/test-cases/page.tsx +546 -0
- package/portal/app/test-cases/test-cases-document.tsx +384 -0
- package/portal/components/code-block.tsx +57 -0
- package/portal/components/document/doc-params-table.tsx +71 -0
- package/portal/components/document/doc-section.tsx +133 -0
- package/portal/components/document/doc-table.tsx +119 -0
- package/portal/components/document/index.ts +9 -0
- package/portal/components/drawflow-er-diagram.tsx +607 -0
- package/portal/components/interactive-er-diagram.tsx +228 -0
- package/portal/components/layout/app-sidebar.tsx +490 -0
- package/portal/components/layout/er-sidebar.tsx +116 -0
- package/portal/components/layout/global-header.tsx +117 -0
- package/portal/components/layout/layout-content.tsx +48 -0
- package/portal/components/markdown-content.tsx +120 -0
- package/portal/components/mermaid-diagram.tsx +83 -0
- package/portal/components/reactflow-er-diagram.tsx +475 -0
- package/portal/components/search-dialog.tsx +268 -0
- package/portal/components/shared/coverage-score-bar.tsx +144 -0
- package/portal/components/swagger/endpoint-accordion.tsx +117 -0
- package/portal/components/swagger/index.ts +7 -0
- package/portal/components/swagger/method-badge.tsx +55 -0
- package/portal/components/swagger/params-table.tsx +78 -0
- package/portal/components/tabs-with-hash.tsx +43 -0
- package/portal/components/test/index.ts +2 -0
- package/portal/components/test/test-bdd-card.tsx +192 -0
- package/portal/components/test/test-matrix.tsx +242 -0
- package/portal/components/ui/accordion.tsx +66 -0
- package/portal/components/ui/badge.tsx +46 -0
- package/portal/components/ui/breadcrumb.tsx +109 -0
- package/portal/components/ui/button.tsx +62 -0
- package/portal/components/ui/card.tsx +92 -0
- package/portal/components/ui/collapsible.tsx +33 -0
- package/portal/components/ui/dialog.tsx +118 -0
- package/portal/components/ui/progress.tsx +28 -0
- package/portal/components/ui/scroll-area.tsx +58 -0
- package/portal/components/ui/sheet.tsx +139 -0
- package/portal/components/ui/table.tsx +116 -0
- package/portal/components/ui/tabs.tsx +66 -0
- package/portal/components.json +21 -0
- package/portal/lib/constants/test-categories.ts +186 -0
- package/portal/lib/data-loader.ts +1181 -0
- package/portal/lib/db-schema-utils.ts +182 -0
- package/portal/lib/format.ts +43 -0
- package/portal/lib/hooks/use-hash-tab.ts +144 -0
- package/portal/lib/path-utils.ts +25 -0
- package/portal/lib/search-index-generator.ts +214 -0
- package/portal/lib/search.ts +126 -0
- package/portal/lib/sidebar-context.tsx +111 -0
- package/portal/lib/types.ts +740 -0
- package/portal/lib/utils.ts +6 -0
- package/portal/next.config.ts +21 -0
- package/portal/package.json +45 -0
- package/portal/postcss.config.mjs +8 -0
- package/portal/tsconfig.json +41 -0
- package/portal/types/drawflow.d.ts +80 -0
- package/templates/README.md +73 -0
- package/templates/coverage.html +367 -0
- package/templates/dark-theme.css +443 -0
- package/templates/discussion/adr.yml.hbs +65 -0
- package/templates/discussion/handovers.yml.hbs +57 -0
- package/templates/discussion/knowledge.yml.hbs +60 -0
- package/templates/discussion/reports.yml.hbs +68 -0
- package/templates/discussion/research.yml.hbs +61 -0
|
@@ -0,0 +1,1297 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gh-issues command - GitHub Issues management with Projects integration
|
|
3
|
+
*
|
|
4
|
+
* This is the main user-facing command that abstracts Issues + Projects.
|
|
5
|
+
*
|
|
6
|
+
* Subcommands:
|
|
7
|
+
* - list: List issues (with Projects field filtering)
|
|
8
|
+
* - get: Get issue details including Projects fields
|
|
9
|
+
* - create: Create issue and optionally add to project with fields
|
|
10
|
+
* - update: Update issue and/or project fields
|
|
11
|
+
* - comment: Add comment to issue
|
|
12
|
+
* - close: Close an issue (with optional comment)
|
|
13
|
+
*
|
|
14
|
+
* Key design:
|
|
15
|
+
* - Issues provide: #number references, comments, PR links
|
|
16
|
+
* - Projects provide: Status/Priority/Type/Size field management
|
|
17
|
+
* - This command unifies both for a seamless experience
|
|
18
|
+
*/
|
|
19
|
+
import { createLogger } from "../utils/logger.js";
|
|
20
|
+
import { runGhCommand, runGraphQL, getRepoName, getRepoInfo, validateTitle, validateBody, isIssueNumber, parseIssueNumber, } from "../utils/github.js";
|
|
21
|
+
import { cmdPrComments, cmdMerge, cmdPrReply, cmdResolve, } from "./gh-issues-pr.js";
|
|
22
|
+
import { loadGhConfig, getDefaultLimit, getDefaultStatus } from "../utils/gh-config.js";
|
|
23
|
+
import { formatOutput, GH_ISSUES_LIST_COLUMNS, } from "../utils/formatters.js";
|
|
24
|
+
import { resolveTargetRepo, detectCurrentRepoPair, parseRepoFullName, validateCrossRepoAlias, } from "../utils/repo-pairs.js";
|
|
25
|
+
// =============================================================================
|
|
26
|
+
// Field Name Fallbacks
|
|
27
|
+
// =============================================================================
|
|
28
|
+
// GitHub Projects V2 reserves certain field names (e.g., "Type").
|
|
29
|
+
// Users must create them with alternative names (e.g., "Item Type").
|
|
30
|
+
// This mapping provides fallback names for field resolution.
|
|
31
|
+
export const FIELD_FALLBACKS = {
|
|
32
|
+
Type: ["Item Type", "ItemType"],
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Resolve a field name against project fields, trying fallbacks if needed.
|
|
36
|
+
* Returns the actual field name found in the project, or null.
|
|
37
|
+
*/
|
|
38
|
+
export function resolveFieldName(fieldName, projectFields) {
|
|
39
|
+
if (projectFields[fieldName])
|
|
40
|
+
return fieldName;
|
|
41
|
+
const fallbacks = FIELD_FALLBACKS[fieldName];
|
|
42
|
+
if (fallbacks) {
|
|
43
|
+
for (const alt of fallbacks) {
|
|
44
|
+
if (projectFields[alt])
|
|
45
|
+
return alt;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
// =============================================================================
|
|
51
|
+
// GraphQL Queries
|
|
52
|
+
// =============================================================================
|
|
53
|
+
// Note: We don't use $states variable because gh CLI has issues with GraphQL enum arrays
|
|
54
|
+
// Instead, we filter by state client-side
|
|
55
|
+
const GRAPHQL_QUERY_ISSUES_WITH_PROJECTS = `
|
|
56
|
+
query($owner: String!, $name: String!, $first: Int!, $cursor: String) {
|
|
57
|
+
repository(owner: $owner, name: $name) {
|
|
58
|
+
issues(first: $first, after: $cursor, orderBy: {field: CREATED_AT, direction: DESC}) {
|
|
59
|
+
pageInfo { hasNextPage endCursor }
|
|
60
|
+
nodes {
|
|
61
|
+
number
|
|
62
|
+
title
|
|
63
|
+
url
|
|
64
|
+
state
|
|
65
|
+
createdAt
|
|
66
|
+
updatedAt
|
|
67
|
+
labels(first: 10) {
|
|
68
|
+
nodes { name }
|
|
69
|
+
}
|
|
70
|
+
projectItems(first: 5) {
|
|
71
|
+
nodes {
|
|
72
|
+
id
|
|
73
|
+
project { title }
|
|
74
|
+
status: fieldValueByName(name: "Status") {
|
|
75
|
+
... on ProjectV2ItemFieldSingleSelectValue { name }
|
|
76
|
+
}
|
|
77
|
+
priority: fieldValueByName(name: "Priority") {
|
|
78
|
+
... on ProjectV2ItemFieldSingleSelectValue { name }
|
|
79
|
+
}
|
|
80
|
+
type: fieldValueByName(name: "Type") {
|
|
81
|
+
... on ProjectV2ItemFieldSingleSelectValue { name }
|
|
82
|
+
}
|
|
83
|
+
itemType: fieldValueByName(name: "Item Type") {
|
|
84
|
+
... on ProjectV2ItemFieldSingleSelectValue { name }
|
|
85
|
+
}
|
|
86
|
+
size: fieldValueByName(name: "Size") {
|
|
87
|
+
... on ProjectV2ItemFieldSingleSelectValue { name }
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
`;
|
|
96
|
+
const GRAPHQL_QUERY_ISSUE_DETAIL = `
|
|
97
|
+
query($owner: String!, $name: String!, $number: Int!) {
|
|
98
|
+
repository(owner: $owner, name: $name) {
|
|
99
|
+
issue(number: $number) {
|
|
100
|
+
number
|
|
101
|
+
title
|
|
102
|
+
body
|
|
103
|
+
url
|
|
104
|
+
state
|
|
105
|
+
createdAt
|
|
106
|
+
updatedAt
|
|
107
|
+
labels(first: 20) {
|
|
108
|
+
nodes { name }
|
|
109
|
+
}
|
|
110
|
+
projectItems(first: 5) {
|
|
111
|
+
nodes {
|
|
112
|
+
id
|
|
113
|
+
project { id title }
|
|
114
|
+
status: fieldValueByName(name: "Status") {
|
|
115
|
+
... on ProjectV2ItemFieldSingleSelectValue { name optionId }
|
|
116
|
+
}
|
|
117
|
+
priority: fieldValueByName(name: "Priority") {
|
|
118
|
+
... on ProjectV2ItemFieldSingleSelectValue { name optionId }
|
|
119
|
+
}
|
|
120
|
+
type: fieldValueByName(name: "Type") {
|
|
121
|
+
... on ProjectV2ItemFieldSingleSelectValue { name optionId }
|
|
122
|
+
}
|
|
123
|
+
itemType: fieldValueByName(name: "Item Type") {
|
|
124
|
+
... on ProjectV2ItemFieldSingleSelectValue { name optionId }
|
|
125
|
+
}
|
|
126
|
+
size: fieldValueByName(name: "Size") {
|
|
127
|
+
... on ProjectV2ItemFieldSingleSelectValue { name optionId }
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
`;
|
|
135
|
+
const GRAPHQL_QUERY_REPO_ID = `
|
|
136
|
+
query($owner: String!, $name: String!) {
|
|
137
|
+
repository(owner: $owner, name: $name) {
|
|
138
|
+
id
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
`;
|
|
142
|
+
const GRAPHQL_QUERY_LABELS = `
|
|
143
|
+
query($owner: String!, $name: String!) {
|
|
144
|
+
repository(owner: $owner, name: $name) {
|
|
145
|
+
labels(first: 50) {
|
|
146
|
+
nodes { id name }
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
`;
|
|
151
|
+
const GRAPHQL_MUTATION_CREATE_ISSUE = `
|
|
152
|
+
mutation($repositoryId: ID!, $title: String!, $body: String, $labelIds: [ID!]) {
|
|
153
|
+
createIssue(input: {repositoryId: $repositoryId, title: $title, body: $body, labelIds: $labelIds}) {
|
|
154
|
+
issue { id number url title }
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
`;
|
|
158
|
+
const GRAPHQL_MUTATION_UPDATE_ISSUE = `
|
|
159
|
+
mutation($id: ID!, $title: String, $body: String) {
|
|
160
|
+
updateIssue(input: {id: $id, title: $title, body: $body}) {
|
|
161
|
+
issue { id number title body }
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
`;
|
|
165
|
+
const GRAPHQL_MUTATION_ADD_COMMENT = `
|
|
166
|
+
mutation($subjectId: ID!, $body: String!) {
|
|
167
|
+
addComment(input: {subjectId: $subjectId, body: $body}) {
|
|
168
|
+
commentEdge {
|
|
169
|
+
node { id url }
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
`;
|
|
174
|
+
const GRAPHQL_MUTATION_ADD_TO_PROJECT = `
|
|
175
|
+
mutation($projectId: ID!, $contentId: ID!) {
|
|
176
|
+
addProjectV2ItemById(input: {projectId: $projectId, contentId: $contentId}) {
|
|
177
|
+
item { id }
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
`;
|
|
181
|
+
const GRAPHQL_MUTATION_UPDATE_FIELD = `
|
|
182
|
+
mutation($projectId: ID!, $itemId: ID!, $fieldId: ID!, $optionId: String!) {
|
|
183
|
+
updateProjectV2ItemFieldValue(input: {
|
|
184
|
+
projectId: $projectId
|
|
185
|
+
itemId: $itemId
|
|
186
|
+
fieldId: $fieldId
|
|
187
|
+
value: { singleSelectOptionId: $optionId }
|
|
188
|
+
}) { projectV2Item { id } }
|
|
189
|
+
}
|
|
190
|
+
`;
|
|
191
|
+
const GRAPHQL_QUERY_FIELDS = `
|
|
192
|
+
query($projectId: ID!) {
|
|
193
|
+
node(id: $projectId) {
|
|
194
|
+
... on ProjectV2 {
|
|
195
|
+
title
|
|
196
|
+
fields(first: 20) {
|
|
197
|
+
nodes {
|
|
198
|
+
... on ProjectV2SingleSelectField {
|
|
199
|
+
id name
|
|
200
|
+
options { id name }
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
`;
|
|
208
|
+
const GRAPHQL_MUTATION_CLOSE_ISSUE = `
|
|
209
|
+
mutation($issueId: ID!, $stateReason: IssueClosedStateReason) {
|
|
210
|
+
closeIssue(input: {issueId: $issueId, stateReason: $stateReason}) {
|
|
211
|
+
issue { id number state }
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
`;
|
|
215
|
+
const GRAPHQL_MUTATION_REOPEN_ISSUE = `
|
|
216
|
+
mutation($issueId: ID!) {
|
|
217
|
+
reopenIssue(input: {issueId: $issueId}) {
|
|
218
|
+
issue { id number state }
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
`;
|
|
222
|
+
const GRAPHQL_MUTATION_ADD_LABELS = `
|
|
223
|
+
mutation($labelableId: ID!, $labelIds: [ID!]!) {
|
|
224
|
+
addLabelsToLabelable(input: {labelableId: $labelableId, labelIds: $labelIds}) {
|
|
225
|
+
labelable { ... on Issue { id number labels(first: 20) { nodes { name } } } }
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
`;
|
|
229
|
+
const GRAPHQL_MUTATION_REMOVE_LABELS = `
|
|
230
|
+
mutation($labelableId: ID!, $labelIds: [ID!]!) {
|
|
231
|
+
removeLabelsFromLabelable(input: {labelableId: $labelableId, labelIds: $labelIds}) {
|
|
232
|
+
labelable { ... on Issue { id number labels(first: 20) { nodes { name } } } }
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
`;
|
|
236
|
+
const GRAPHQL_QUERY_ISSUE_ID = `
|
|
237
|
+
query($owner: String!, $name: String!, $number: Int!) {
|
|
238
|
+
repository(owner: $owner, name: $name) {
|
|
239
|
+
issue(number: $number) {
|
|
240
|
+
id
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
`;
|
|
245
|
+
const GRAPHQL_MUTATION_DELETE_ITEM = `
|
|
246
|
+
mutation($projectId: ID!, $itemId: ID!) {
|
|
247
|
+
deleteProjectV2Item(input: {projectId: $projectId, itemId: $itemId}) {
|
|
248
|
+
deletedItemId
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
`;
|
|
252
|
+
// =============================================================================
|
|
253
|
+
// Helper Functions
|
|
254
|
+
// =============================================================================
|
|
255
|
+
/**
|
|
256
|
+
* Get project ID by name (defaults to repository name)
|
|
257
|
+
*/
|
|
258
|
+
export function getProjectId(owner, projectName) {
|
|
259
|
+
const targetName = projectName || getRepoName();
|
|
260
|
+
if (!targetName)
|
|
261
|
+
return null;
|
|
262
|
+
const result = runGhCommand(["project", "list", "--owner", owner, "--format", "json"], { silent: true });
|
|
263
|
+
if (!result.success || !result.data?.projects)
|
|
264
|
+
return null;
|
|
265
|
+
for (const project of result.data.projects) {
|
|
266
|
+
if (project.title === targetName) {
|
|
267
|
+
return project.id;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return result.data.projects[0]?.id ?? null;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Get repository ID
|
|
274
|
+
*/
|
|
275
|
+
function getRepoId(owner, repo) {
|
|
276
|
+
const result = runGraphQL(GRAPHQL_QUERY_REPO_ID, { owner, name: repo });
|
|
277
|
+
if (!result.success)
|
|
278
|
+
return null;
|
|
279
|
+
return result.data?.data?.repository?.id ?? null;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Get issue GraphQL ID by number
|
|
283
|
+
*/
|
|
284
|
+
export function getIssueId(owner, repo, number) {
|
|
285
|
+
const result = runGraphQL(GRAPHQL_QUERY_ISSUE_ID, { owner, name: repo, number });
|
|
286
|
+
if (!result.success)
|
|
287
|
+
return null;
|
|
288
|
+
return result.data?.data?.repository?.issue?.id ?? null;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Get project field definitions
|
|
292
|
+
*/
|
|
293
|
+
export function getProjectFields(projectId) {
|
|
294
|
+
const result = runGraphQL(GRAPHQL_QUERY_FIELDS, { projectId });
|
|
295
|
+
if (!result.success)
|
|
296
|
+
return {};
|
|
297
|
+
const fields = {};
|
|
298
|
+
const nodes = result.data?.data?.node?.fields?.nodes ?? [];
|
|
299
|
+
for (const node of nodes) {
|
|
300
|
+
if (node?.name && node?.options && node?.id) {
|
|
301
|
+
const options = {};
|
|
302
|
+
for (const opt of node.options) {
|
|
303
|
+
options[opt.name] = opt.id;
|
|
304
|
+
}
|
|
305
|
+
fields[node.name] = { id: node.id, options };
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return fields;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Get repository labels
|
|
312
|
+
*/
|
|
313
|
+
function getLabels(owner, repo) {
|
|
314
|
+
const result = runGraphQL(GRAPHQL_QUERY_LABELS, { owner, name: repo });
|
|
315
|
+
if (!result.success)
|
|
316
|
+
return {};
|
|
317
|
+
const labels = {};
|
|
318
|
+
const nodes = result.data?.data?.repository?.labels?.nodes ?? [];
|
|
319
|
+
for (const node of nodes) {
|
|
320
|
+
if (node?.name && node?.id) {
|
|
321
|
+
labels[node.name] = node.id;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return labels;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Update project item field
|
|
328
|
+
*/
|
|
329
|
+
function updateField(projectId, itemId, fieldId, optionId) {
|
|
330
|
+
const result = runGraphQL(GRAPHQL_MUTATION_UPDATE_FIELD, {
|
|
331
|
+
projectId,
|
|
332
|
+
itemId,
|
|
333
|
+
fieldId,
|
|
334
|
+
optionId,
|
|
335
|
+
});
|
|
336
|
+
return result.success;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Set multiple project fields on an item
|
|
340
|
+
*/
|
|
341
|
+
export function setItemFields(projectId, itemId, fields, logger) {
|
|
342
|
+
if (Object.keys(fields).length === 0)
|
|
343
|
+
return 0;
|
|
344
|
+
const projectFields = getProjectFields(projectId);
|
|
345
|
+
let updatedCount = 0;
|
|
346
|
+
for (const [fieldName, value] of Object.entries(fields)) {
|
|
347
|
+
const resolvedName = resolveFieldName(fieldName, projectFields);
|
|
348
|
+
if (!resolvedName) {
|
|
349
|
+
const fallbacks = FIELD_FALLBACKS[fieldName];
|
|
350
|
+
const hint = fallbacks ? ` (also tried: ${fallbacks.join(", ")})` : "";
|
|
351
|
+
logger?.warn(`Field '${fieldName}' not found in project${hint}`);
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
const fieldInfo = projectFields[resolvedName];
|
|
355
|
+
const optionId = fieldInfo.options[value];
|
|
356
|
+
if (optionId) {
|
|
357
|
+
if (updateField(projectId, itemId, fieldInfo.id, optionId)) {
|
|
358
|
+
updatedCount++;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
const available = Object.keys(fieldInfo.options).sort().join(", ");
|
|
363
|
+
logger?.error(`Invalid ${fieldName} value '${value}'`);
|
|
364
|
+
logger?.info(` Available options: ${available}`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return updatedCount;
|
|
368
|
+
}
|
|
369
|
+
// =============================================================================
|
|
370
|
+
// Subcommand Handlers
|
|
371
|
+
// =============================================================================
|
|
372
|
+
/**
|
|
373
|
+
* list subcommand
|
|
374
|
+
*/
|
|
375
|
+
async function cmdList(options, logger) {
|
|
376
|
+
const repoInfo = resolveTargetRepo(options);
|
|
377
|
+
if (!repoInfo) {
|
|
378
|
+
logger.error("Could not determine repository");
|
|
379
|
+
return 1;
|
|
380
|
+
}
|
|
381
|
+
// Load config for defaults
|
|
382
|
+
const config = loadGhConfig();
|
|
383
|
+
const { owner, name: repo } = repoInfo;
|
|
384
|
+
const projectName = repo; // Project name = repo name convention
|
|
385
|
+
// Map state option for client-side filtering
|
|
386
|
+
// --all is shortcut for --state all
|
|
387
|
+
const stateFilter = options.all ? "all" : (options.state ?? "open");
|
|
388
|
+
const allIssues = [];
|
|
389
|
+
let cursor = null;
|
|
390
|
+
const limit = options.limit ?? getDefaultLimit(config);
|
|
391
|
+
while (allIssues.length < limit) {
|
|
392
|
+
const remaining = limit - allIssues.length;
|
|
393
|
+
const fetchCount = Math.min(remaining, 50);
|
|
394
|
+
const result = runGraphQL(GRAPHQL_QUERY_ISSUES_WITH_PROJECTS, {
|
|
395
|
+
owner,
|
|
396
|
+
name: repo,
|
|
397
|
+
first: fetchCount,
|
|
398
|
+
cursor: cursor,
|
|
399
|
+
});
|
|
400
|
+
if (!result.success || !result.data?.data?.repository?.issues)
|
|
401
|
+
break;
|
|
402
|
+
const issuesData = result.data.data.repository.issues;
|
|
403
|
+
const nodes = issuesData.nodes ?? [];
|
|
404
|
+
for (const node of nodes) {
|
|
405
|
+
if (!node?.number)
|
|
406
|
+
continue;
|
|
407
|
+
// Client-side state filter
|
|
408
|
+
const nodeState = node.state ?? "OPEN";
|
|
409
|
+
if (stateFilter === "open" && nodeState !== "OPEN")
|
|
410
|
+
continue;
|
|
411
|
+
if (stateFilter === "closed" && nodeState !== "CLOSED")
|
|
412
|
+
continue;
|
|
413
|
+
const projectItems = node.projectItems?.nodes ?? [];
|
|
414
|
+
const matchingItem = projectItems.find((p) => p?.project?.title === projectName);
|
|
415
|
+
const labelNodes = node.labels?.nodes ?? [];
|
|
416
|
+
const issueLabels = labelNodes.map((l) => l?.name ?? "").filter(Boolean);
|
|
417
|
+
// Client-side label filter
|
|
418
|
+
if (options.labels && options.labels.length > 0) {
|
|
419
|
+
const hasAllLabels = options.labels.every((label) => issueLabels.includes(label));
|
|
420
|
+
if (!hasAllLabels)
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
const issue = {
|
|
424
|
+
number: node.number,
|
|
425
|
+
title: node.title ?? "",
|
|
426
|
+
url: node.url ?? "",
|
|
427
|
+
state: nodeState,
|
|
428
|
+
labels: issueLabels,
|
|
429
|
+
createdAt: node.createdAt ?? "",
|
|
430
|
+
updatedAt: node.updatedAt ?? "",
|
|
431
|
+
projectItemId: matchingItem?.id,
|
|
432
|
+
status: matchingItem?.status?.name,
|
|
433
|
+
priority: matchingItem?.priority?.name,
|
|
434
|
+
type: matchingItem?.type?.name ?? matchingItem?.itemType?.name,
|
|
435
|
+
size: matchingItem?.size?.name,
|
|
436
|
+
};
|
|
437
|
+
allIssues.push(issue);
|
|
438
|
+
}
|
|
439
|
+
const pageInfo = issuesData.pageInfo ?? {};
|
|
440
|
+
if (!pageInfo.hasNextPage)
|
|
441
|
+
break;
|
|
442
|
+
cursor = pageInfo.endCursor ?? null;
|
|
443
|
+
}
|
|
444
|
+
// Apply status filter (from Projects) if specified
|
|
445
|
+
let filteredIssues = allIssues;
|
|
446
|
+
if (options.status && options.status.length > 0) {
|
|
447
|
+
filteredIssues = allIssues.filter((i) => options.status.includes(i.status ?? ""));
|
|
448
|
+
}
|
|
449
|
+
// Note: state filter (open/closed/all) is applied client-side during fetch
|
|
450
|
+
// Done/Released items are typically closed, so --state open (default) excludes them
|
|
451
|
+
const output = {
|
|
452
|
+
repository: `${owner}/${repo}`,
|
|
453
|
+
issues: filteredIssues.map((i) => ({
|
|
454
|
+
number: i.number,
|
|
455
|
+
title: i.title,
|
|
456
|
+
url: i.url,
|
|
457
|
+
state: i.state,
|
|
458
|
+
labels: i.labels,
|
|
459
|
+
status: i.status,
|
|
460
|
+
priority: i.priority,
|
|
461
|
+
type: i.type,
|
|
462
|
+
size: i.size,
|
|
463
|
+
project_item_id: i.projectItemId,
|
|
464
|
+
})),
|
|
465
|
+
total_count: filteredIssues.length,
|
|
466
|
+
};
|
|
467
|
+
const outputFormat = options.format ?? "json";
|
|
468
|
+
const formatted = formatOutput(output, outputFormat, {
|
|
469
|
+
arrayKey: "issues",
|
|
470
|
+
columns: GH_ISSUES_LIST_COLUMNS,
|
|
471
|
+
});
|
|
472
|
+
console.log(formatted);
|
|
473
|
+
return 0;
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* get subcommand
|
|
477
|
+
*/
|
|
478
|
+
async function cmdGet(issueNumberStr, options, logger) {
|
|
479
|
+
const repoInfo = resolveTargetRepo(options);
|
|
480
|
+
if (!repoInfo) {
|
|
481
|
+
logger.error("Could not determine repository");
|
|
482
|
+
return 1;
|
|
483
|
+
}
|
|
484
|
+
const { owner, name: repo } = repoInfo;
|
|
485
|
+
const issueNumber = parseIssueNumber(issueNumberStr);
|
|
486
|
+
const projectName = repo;
|
|
487
|
+
const result = runGraphQL(GRAPHQL_QUERY_ISSUE_DETAIL, {
|
|
488
|
+
owner,
|
|
489
|
+
name: repo,
|
|
490
|
+
number: issueNumber,
|
|
491
|
+
});
|
|
492
|
+
if (!result.success || !result.data?.data?.repository?.issue) {
|
|
493
|
+
logger.error(`Issue #${issueNumber} not found`);
|
|
494
|
+
return 1;
|
|
495
|
+
}
|
|
496
|
+
const node = result.data.data.repository.issue;
|
|
497
|
+
const projectItems = node.projectItems?.nodes ?? [];
|
|
498
|
+
const matchingItem = projectItems.find((p) => p?.project?.title === projectName);
|
|
499
|
+
// Merge "Type" and "Item Type" fields (GitHub reserves "Type" name)
|
|
500
|
+
const typeField = matchingItem?.type ?? matchingItem?.itemType;
|
|
501
|
+
const output = {
|
|
502
|
+
number: node.number,
|
|
503
|
+
title: node.title,
|
|
504
|
+
body: node.body,
|
|
505
|
+
url: node.url,
|
|
506
|
+
state: node.state,
|
|
507
|
+
labels: (node.labels?.nodes ?? []).map((l) => l?.name ?? "").filter(Boolean),
|
|
508
|
+
created_at: node.createdAt,
|
|
509
|
+
updated_at: node.updatedAt,
|
|
510
|
+
// Projects fields
|
|
511
|
+
project_item_id: matchingItem?.id,
|
|
512
|
+
project_id: matchingItem?.project?.id,
|
|
513
|
+
status: matchingItem?.status?.name,
|
|
514
|
+
status_option_id: matchingItem?.status?.optionId,
|
|
515
|
+
priority: matchingItem?.priority?.name,
|
|
516
|
+
priority_option_id: matchingItem?.priority?.optionId,
|
|
517
|
+
type: typeField?.name,
|
|
518
|
+
type_option_id: typeField?.optionId,
|
|
519
|
+
size: matchingItem?.size?.name,
|
|
520
|
+
size_option_id: matchingItem?.size?.optionId,
|
|
521
|
+
};
|
|
522
|
+
console.log(JSON.stringify(output, null, 2));
|
|
523
|
+
return 0;
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* create subcommand
|
|
527
|
+
*/
|
|
528
|
+
async function cmdCreate(options, logger) {
|
|
529
|
+
// Validation
|
|
530
|
+
if (!options.title) {
|
|
531
|
+
logger.error("--title is required");
|
|
532
|
+
return 1;
|
|
533
|
+
}
|
|
534
|
+
const titleError = validateTitle(options.title);
|
|
535
|
+
if (titleError) {
|
|
536
|
+
logger.error(titleError);
|
|
537
|
+
return 1;
|
|
538
|
+
}
|
|
539
|
+
const bodyError = validateBody(options.body);
|
|
540
|
+
if (bodyError) {
|
|
541
|
+
logger.error(bodyError);
|
|
542
|
+
return 1;
|
|
543
|
+
}
|
|
544
|
+
const repoInfo = resolveTargetRepo(options);
|
|
545
|
+
if (!repoInfo) {
|
|
546
|
+
logger.error("Could not determine repository");
|
|
547
|
+
return 1;
|
|
548
|
+
}
|
|
549
|
+
const { owner, name: repo } = repoInfo;
|
|
550
|
+
// Get repository ID
|
|
551
|
+
const repoId = getRepoId(owner, repo);
|
|
552
|
+
if (!repoId) {
|
|
553
|
+
logger.error("Could not get repository ID");
|
|
554
|
+
return 1;
|
|
555
|
+
}
|
|
556
|
+
// Resolve label names to IDs
|
|
557
|
+
let labelIds = null;
|
|
558
|
+
if (options.labels && options.labels.length > 0) {
|
|
559
|
+
const allLabels = getLabels(owner, repo);
|
|
560
|
+
labelIds = [];
|
|
561
|
+
for (const labelName of options.labels) {
|
|
562
|
+
if (allLabels[labelName]) {
|
|
563
|
+
labelIds.push(allLabels[labelName]);
|
|
564
|
+
}
|
|
565
|
+
else {
|
|
566
|
+
logger.warn(`Label '${labelName}' not found`);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
const createResult = runGraphQL(GRAPHQL_MUTATION_CREATE_ISSUE, {
|
|
571
|
+
repositoryId: repoId,
|
|
572
|
+
title: options.title,
|
|
573
|
+
body: options.body ?? "",
|
|
574
|
+
labelIds: labelIds ?? null,
|
|
575
|
+
});
|
|
576
|
+
if (!createResult.success) {
|
|
577
|
+
logger.error("Failed to create issue");
|
|
578
|
+
return 1;
|
|
579
|
+
}
|
|
580
|
+
const issue = createResult.data?.data?.createIssue?.issue;
|
|
581
|
+
if (!issue?.id || !issue?.number) {
|
|
582
|
+
logger.error("Failed to create issue");
|
|
583
|
+
return 1;
|
|
584
|
+
}
|
|
585
|
+
logger.success(`Created issue #${issue.number}`);
|
|
586
|
+
// Always add to project and set default Status if not explicitly provided.
|
|
587
|
+
// --status is array (for list filtering), --field-status is string (for setting)
|
|
588
|
+
// Accept --status as fallback when --field-status is not provided
|
|
589
|
+
const createStatusValue = options.fieldStatus ?? options.status?.[0] ?? getDefaultStatus();
|
|
590
|
+
let projectItemId = null;
|
|
591
|
+
const projectId = getProjectId(owner, repo);
|
|
592
|
+
if (!projectId) {
|
|
593
|
+
logger.warn("No project found. Issue created but not added to project.");
|
|
594
|
+
}
|
|
595
|
+
else {
|
|
596
|
+
const addResult = runGraphQL(GRAPHQL_MUTATION_ADD_TO_PROJECT, {
|
|
597
|
+
projectId,
|
|
598
|
+
contentId: issue.id,
|
|
599
|
+
});
|
|
600
|
+
if (addResult.success) {
|
|
601
|
+
projectItemId = addResult.data?.data?.addProjectV2ItemById?.item?.id ?? null;
|
|
602
|
+
if (projectItemId) {
|
|
603
|
+
logger.success("Added to project");
|
|
604
|
+
// Set project fields
|
|
605
|
+
const fields = {};
|
|
606
|
+
if (createStatusValue)
|
|
607
|
+
fields["Status"] = createStatusValue;
|
|
608
|
+
if (options.priority)
|
|
609
|
+
fields["Priority"] = options.priority;
|
|
610
|
+
if (options.type)
|
|
611
|
+
fields["Type"] = options.type;
|
|
612
|
+
if (options.size)
|
|
613
|
+
fields["Size"] = options.size;
|
|
614
|
+
if (Object.keys(fields).length > 0) {
|
|
615
|
+
setItemFields(projectId, projectItemId, fields, logger);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
else {
|
|
620
|
+
logger.warn("Failed to add to project");
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
// Warn about missing fields (field completeness check)
|
|
624
|
+
const missingFields = [];
|
|
625
|
+
if (!options.priority)
|
|
626
|
+
missingFields.push("Priority");
|
|
627
|
+
if (!options.type)
|
|
628
|
+
missingFields.push("Type");
|
|
629
|
+
if (!options.size)
|
|
630
|
+
missingFields.push("Size");
|
|
631
|
+
if (missingFields.length > 0) {
|
|
632
|
+
logger.warn(`Issue #${issue.number} created without: ${missingFields.join(", ")}. ` +
|
|
633
|
+
`Consider setting them with: shirokuma-docs gh-issues update ${issue.number} ` +
|
|
634
|
+
missingFields.map((f) => `--${f.toLowerCase()} <value>`).join(" "));
|
|
635
|
+
}
|
|
636
|
+
// Output created issue info
|
|
637
|
+
const output = {
|
|
638
|
+
number: issue.number,
|
|
639
|
+
title: issue.title,
|
|
640
|
+
url: issue.url,
|
|
641
|
+
project_item_id: projectItemId,
|
|
642
|
+
};
|
|
643
|
+
console.log(JSON.stringify(output, null, 2));
|
|
644
|
+
return 0;
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* update subcommand
|
|
648
|
+
*/
|
|
649
|
+
async function cmdUpdate(issueNumberStr, options, logger) {
|
|
650
|
+
const repoInfo = resolveTargetRepo(options);
|
|
651
|
+
if (!repoInfo) {
|
|
652
|
+
logger.error("Could not determine repository");
|
|
653
|
+
return 1;
|
|
654
|
+
}
|
|
655
|
+
const { owner, name: repo } = repoInfo;
|
|
656
|
+
const issueNumber = parseIssueNumber(issueNumberStr);
|
|
657
|
+
const getResult = runGraphQL(GRAPHQL_QUERY_ISSUE_DETAIL, {
|
|
658
|
+
owner,
|
|
659
|
+
name: repo,
|
|
660
|
+
number: issueNumber,
|
|
661
|
+
});
|
|
662
|
+
if (!getResult.success || !getResult.data?.data?.repository?.issue) {
|
|
663
|
+
logger.error(`Issue #${issueNumber} not found`);
|
|
664
|
+
return 1;
|
|
665
|
+
}
|
|
666
|
+
const issueNode = getResult.data.data.repository.issue;
|
|
667
|
+
const projectName = repo;
|
|
668
|
+
const projectItems = issueNode.projectItems?.nodes ?? [];
|
|
669
|
+
const matchingItem = projectItems.find((p) => p?.project?.title === projectName);
|
|
670
|
+
let updated = false;
|
|
671
|
+
// Update issue fields (title, body)
|
|
672
|
+
if (options.title || options.body !== undefined) {
|
|
673
|
+
const issueId = getIssueId(owner, repo, issueNumber);
|
|
674
|
+
if (issueId) {
|
|
675
|
+
const updateResult = runGraphQL(GRAPHQL_MUTATION_UPDATE_ISSUE, {
|
|
676
|
+
id: issueId,
|
|
677
|
+
title: options.title ?? null,
|
|
678
|
+
body: options.body ?? null,
|
|
679
|
+
});
|
|
680
|
+
if (updateResult.success) {
|
|
681
|
+
updated = true;
|
|
682
|
+
logger.success("Updated issue");
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
// Update labels
|
|
687
|
+
if ((options.addLabel && options.addLabel.length > 0) ||
|
|
688
|
+
(options.removeLabel && options.removeLabel.length > 0)) {
|
|
689
|
+
const issueId = getIssueId(owner, repo, issueNumber);
|
|
690
|
+
if (issueId) {
|
|
691
|
+
const allLabels = getLabels(owner, repo);
|
|
692
|
+
// Add labels
|
|
693
|
+
if (options.addLabel && options.addLabel.length > 0) {
|
|
694
|
+
const addIds = [];
|
|
695
|
+
for (const name of options.addLabel) {
|
|
696
|
+
if (allLabels[name]) {
|
|
697
|
+
addIds.push(allLabels[name]);
|
|
698
|
+
}
|
|
699
|
+
else {
|
|
700
|
+
logger.warn(`Label '${name}' not found`);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
if (addIds.length > 0) {
|
|
704
|
+
const addResult = runGraphQL(GRAPHQL_MUTATION_ADD_LABELS, {
|
|
705
|
+
labelableId: issueId,
|
|
706
|
+
labelIds: addIds,
|
|
707
|
+
});
|
|
708
|
+
if (addResult.success) {
|
|
709
|
+
updated = true;
|
|
710
|
+
logger.success(`Added ${addIds.length} label(s)`);
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
// Remove labels
|
|
715
|
+
if (options.removeLabel && options.removeLabel.length > 0) {
|
|
716
|
+
const removeIds = [];
|
|
717
|
+
for (const name of options.removeLabel) {
|
|
718
|
+
if (allLabels[name]) {
|
|
719
|
+
removeIds.push(allLabels[name]);
|
|
720
|
+
}
|
|
721
|
+
else {
|
|
722
|
+
logger.warn(`Label '${name}' not found`);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
if (removeIds.length > 0) {
|
|
726
|
+
const removeResult = runGraphQL(GRAPHQL_MUTATION_REMOVE_LABELS, {
|
|
727
|
+
labelableId: issueId,
|
|
728
|
+
labelIds: removeIds,
|
|
729
|
+
});
|
|
730
|
+
if (removeResult.success) {
|
|
731
|
+
updated = true;
|
|
732
|
+
logger.success(`Removed ${removeIds.length} label(s)`);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
// Update project fields
|
|
739
|
+
// --status is array (for list filtering), --field-status is string (for setting)
|
|
740
|
+
// Accept --status as fallback when --field-status is not provided
|
|
741
|
+
const statusValue = options.fieldStatus ?? options.status?.[0];
|
|
742
|
+
const fields = {};
|
|
743
|
+
if (statusValue)
|
|
744
|
+
fields["Status"] = statusValue;
|
|
745
|
+
if (options.priority)
|
|
746
|
+
fields["Priority"] = options.priority;
|
|
747
|
+
if (options.type)
|
|
748
|
+
fields["Type"] = options.type;
|
|
749
|
+
if (options.size)
|
|
750
|
+
fields["Size"] = options.size;
|
|
751
|
+
if (Object.keys(fields).length > 0) {
|
|
752
|
+
if (matchingItem?.id && matchingItem?.project?.id) {
|
|
753
|
+
const count = setItemFields(matchingItem.project.id, matchingItem.id, fields, logger);
|
|
754
|
+
if (count > 0) {
|
|
755
|
+
updated = true;
|
|
756
|
+
logger.success(`Updated ${count} project field(s)`);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
else {
|
|
760
|
+
// Issue not in project, add it first
|
|
761
|
+
const projectId = getProjectId(owner, repo);
|
|
762
|
+
if (projectId) {
|
|
763
|
+
const issueId = getIssueId(owner, repo, issueNumber);
|
|
764
|
+
if (issueId) {
|
|
765
|
+
const addResult = runGraphQL(GRAPHQL_MUTATION_ADD_TO_PROJECT, {
|
|
766
|
+
projectId,
|
|
767
|
+
contentId: issueId,
|
|
768
|
+
});
|
|
769
|
+
if (addResult.success) {
|
|
770
|
+
const itemId = addResult.data?.data?.addProjectV2ItemById?.item?.id;
|
|
771
|
+
if (itemId) {
|
|
772
|
+
logger.success("Added to project");
|
|
773
|
+
const count = setItemFields(projectId, itemId, fields, logger);
|
|
774
|
+
if (count > 0) {
|
|
775
|
+
updated = true;
|
|
776
|
+
logger.success(`Updated ${count} project field(s)`);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
else {
|
|
783
|
+
logger.warn("No project found. Cannot update project fields.");
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
if (!updated) {
|
|
788
|
+
logger.info("No changes made");
|
|
789
|
+
}
|
|
790
|
+
// Output updated issue info
|
|
791
|
+
return cmdGet(issueNumberStr, options, logger);
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* comment subcommand
|
|
795
|
+
*/
|
|
796
|
+
async function cmdComment(issueNumberStr, options, logger) {
|
|
797
|
+
if (!options.body) {
|
|
798
|
+
logger.error("--body is required for comment");
|
|
799
|
+
return 1;
|
|
800
|
+
}
|
|
801
|
+
const repoInfo = resolveTargetRepo(options);
|
|
802
|
+
if (!repoInfo) {
|
|
803
|
+
logger.error("Could not determine repository");
|
|
804
|
+
return 1;
|
|
805
|
+
}
|
|
806
|
+
const { owner, name: repo } = repoInfo;
|
|
807
|
+
const issueNumber = parseIssueNumber(issueNumberStr);
|
|
808
|
+
// Get issue ID
|
|
809
|
+
const issueId = getIssueId(owner, repo, issueNumber);
|
|
810
|
+
if (!issueId) {
|
|
811
|
+
logger.error(`Issue #${issueNumber} not found`);
|
|
812
|
+
return 1;
|
|
813
|
+
}
|
|
814
|
+
const result = runGraphQL(GRAPHQL_MUTATION_ADD_COMMENT, {
|
|
815
|
+
subjectId: issueId,
|
|
816
|
+
body: options.body,
|
|
817
|
+
});
|
|
818
|
+
if (!result.success) {
|
|
819
|
+
logger.error("Failed to add comment");
|
|
820
|
+
return 1;
|
|
821
|
+
}
|
|
822
|
+
const comment = result.data?.data?.addComment?.commentEdge?.node;
|
|
823
|
+
logger.success(`Added comment to #${issueNumber}`);
|
|
824
|
+
const output = {
|
|
825
|
+
issue_number: issueNumber,
|
|
826
|
+
comment_id: comment?.id,
|
|
827
|
+
comment_url: comment?.url,
|
|
828
|
+
};
|
|
829
|
+
console.log(JSON.stringify(output, null, 2));
|
|
830
|
+
return 0;
|
|
831
|
+
}
|
|
832
|
+
// =============================================================================
|
|
833
|
+
// Close / Reopen Issue
|
|
834
|
+
// =============================================================================
|
|
835
|
+
/**
|
|
836
|
+
* close subcommand - Close an issue with optional comment.
|
|
837
|
+
*
|
|
838
|
+
* Supports:
|
|
839
|
+
* - --body: Add a closing comment before closing
|
|
840
|
+
* - --state-reason: COMPLETED (default) or NOT_PLANNED
|
|
841
|
+
* - --repo: Cross-repo support
|
|
842
|
+
*/
|
|
843
|
+
async function cmdClose(issueNumberStr, options, logger) {
|
|
844
|
+
const repoInfo = resolveTargetRepo(options);
|
|
845
|
+
if (!repoInfo) {
|
|
846
|
+
logger.error("Could not determine repository");
|
|
847
|
+
return 1;
|
|
848
|
+
}
|
|
849
|
+
const { owner, name: repo } = repoInfo;
|
|
850
|
+
const issueNumber = parseIssueNumber(issueNumberStr);
|
|
851
|
+
// Get issue ID
|
|
852
|
+
const issueId = getIssueId(owner, repo, issueNumber);
|
|
853
|
+
if (!issueId) {
|
|
854
|
+
logger.error(`Issue #${issueNumber} not found`);
|
|
855
|
+
return 1;
|
|
856
|
+
}
|
|
857
|
+
// Add closing comment if --body is provided
|
|
858
|
+
if (options.body) {
|
|
859
|
+
const commentResult = runGraphQL(GRAPHQL_MUTATION_ADD_COMMENT, {
|
|
860
|
+
subjectId: issueId,
|
|
861
|
+
body: options.body,
|
|
862
|
+
});
|
|
863
|
+
if (commentResult.success) {
|
|
864
|
+
logger.success(`Added closing comment to #${issueNumber}`);
|
|
865
|
+
}
|
|
866
|
+
else {
|
|
867
|
+
logger.warn("Failed to add closing comment, proceeding with close");
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
// Close the issue
|
|
871
|
+
const stateReason = options.stateReason === "NOT_PLANNED" ? "NOT_PLANNED" : "COMPLETED";
|
|
872
|
+
const result = runGraphQL(GRAPHQL_MUTATION_CLOSE_ISSUE, {
|
|
873
|
+
issueId,
|
|
874
|
+
stateReason,
|
|
875
|
+
});
|
|
876
|
+
if (!result.success) {
|
|
877
|
+
logger.error(`Failed to close issue #${issueNumber}`);
|
|
878
|
+
return 1;
|
|
879
|
+
}
|
|
880
|
+
logger.success(`Closed #${issueNumber} (${stateReason})`);
|
|
881
|
+
const output = {
|
|
882
|
+
number: issueNumber,
|
|
883
|
+
state: "CLOSED",
|
|
884
|
+
stateReason,
|
|
885
|
+
url: `https://github.com/${owner}/${repo}/issues/${issueNumber}`,
|
|
886
|
+
};
|
|
887
|
+
console.log(JSON.stringify(output, null, 2));
|
|
888
|
+
return 0;
|
|
889
|
+
}
|
|
890
|
+
/**
|
|
891
|
+
* reopen subcommand - Reopen a closed issue.
|
|
892
|
+
*/
|
|
893
|
+
async function cmdReopen(issueNumberStr, options, logger) {
|
|
894
|
+
const repoInfo = resolveTargetRepo(options);
|
|
895
|
+
if (!repoInfo) {
|
|
896
|
+
logger.error("Could not determine repository");
|
|
897
|
+
return 1;
|
|
898
|
+
}
|
|
899
|
+
const { owner, name: repo } = repoInfo;
|
|
900
|
+
const issueNumber = parseIssueNumber(issueNumberStr);
|
|
901
|
+
const issueId = getIssueId(owner, repo, issueNumber);
|
|
902
|
+
if (!issueId) {
|
|
903
|
+
logger.error(`Issue #${issueNumber} not found`);
|
|
904
|
+
return 1;
|
|
905
|
+
}
|
|
906
|
+
const result = runGraphQL(GRAPHQL_MUTATION_REOPEN_ISSUE, {
|
|
907
|
+
issueId,
|
|
908
|
+
});
|
|
909
|
+
if (!result.success) {
|
|
910
|
+
logger.error(`Failed to reopen issue #${issueNumber}`);
|
|
911
|
+
return 1;
|
|
912
|
+
}
|
|
913
|
+
logger.success(`Reopened #${issueNumber}`);
|
|
914
|
+
const output = {
|
|
915
|
+
number: issueNumber,
|
|
916
|
+
state: "OPEN",
|
|
917
|
+
url: `https://github.com/${owner}/${repo}/issues/${issueNumber}`,
|
|
918
|
+
};
|
|
919
|
+
console.log(JSON.stringify(output, null, 2));
|
|
920
|
+
return 0;
|
|
921
|
+
}
|
|
922
|
+
// =============================================================================
|
|
923
|
+
// Import from Public Repo
|
|
924
|
+
// =============================================================================
|
|
925
|
+
/**
|
|
926
|
+
* import subcommand - Import an issue from public repo to private repo.
|
|
927
|
+
*
|
|
928
|
+
* Workflow:
|
|
929
|
+
* 1. Resolve current repo pair (private ← public)
|
|
930
|
+
* 2. Fetch issue from public repo
|
|
931
|
+
* 3. Create issue in private repo with cross-reference
|
|
932
|
+
* 4. Add comment to public issue noting internal tracking
|
|
933
|
+
*/
|
|
934
|
+
async function cmdImport(options, logger) {
|
|
935
|
+
if (!options.fromPublic) {
|
|
936
|
+
logger.error("--from-public <number> is required for import");
|
|
937
|
+
logger.info("Usage: shirokuma-docs gh-issues import --from-public 5");
|
|
938
|
+
return 1;
|
|
939
|
+
}
|
|
940
|
+
const publicIssueNumber = parseIssueNumber(options.fromPublic);
|
|
941
|
+
// Resolve private (current) and public repos from pair config
|
|
942
|
+
const privateRepo = getRepoInfo();
|
|
943
|
+
if (!privateRepo) {
|
|
944
|
+
logger.error("Could not determine current repository");
|
|
945
|
+
return 1;
|
|
946
|
+
}
|
|
947
|
+
const pair = detectCurrentRepoPair();
|
|
948
|
+
if (!pair) {
|
|
949
|
+
logger.error("No repo pair found for current repository. Configure repoPairs in config.");
|
|
950
|
+
return 1;
|
|
951
|
+
}
|
|
952
|
+
const publicRepoParsed = parseRepoFullName(pair.public);
|
|
953
|
+
if (!publicRepoParsed) {
|
|
954
|
+
logger.error(`Invalid public repo: ${pair.public}`);
|
|
955
|
+
return 1;
|
|
956
|
+
}
|
|
957
|
+
logger.info(`Importing issue #${publicIssueNumber} from ${pair.public}`);
|
|
958
|
+
const fetchResult = runGraphQL(GRAPHQL_QUERY_ISSUE_DETAIL, {
|
|
959
|
+
owner: publicRepoParsed.owner,
|
|
960
|
+
name: publicRepoParsed.name,
|
|
961
|
+
number: publicIssueNumber,
|
|
962
|
+
});
|
|
963
|
+
if (!fetchResult.success || !fetchResult.data?.data?.repository?.issue) {
|
|
964
|
+
logger.error(`Issue #${publicIssueNumber} not found in ${pair.public}`);
|
|
965
|
+
return 1;
|
|
966
|
+
}
|
|
967
|
+
const publicIssue = fetchResult.data.data.repository.issue;
|
|
968
|
+
const publicUrl = publicIssue.url ?? `https://github.com/${pair.public}/issues/${publicIssueNumber}`;
|
|
969
|
+
// Create issue in private repo
|
|
970
|
+
const importTitle = `[Public #${publicIssueNumber}] ${publicIssue.title ?? "Imported Issue"}`;
|
|
971
|
+
const importBody = [
|
|
972
|
+
`> Imported from public repo: ${publicUrl}`,
|
|
973
|
+
"",
|
|
974
|
+
"---",
|
|
975
|
+
"",
|
|
976
|
+
publicIssue.body ?? "",
|
|
977
|
+
].join("\n");
|
|
978
|
+
const { owner, name: repo } = privateRepo;
|
|
979
|
+
const repoId = getRepoId(owner, repo);
|
|
980
|
+
if (!repoId) {
|
|
981
|
+
logger.error("Could not get repository ID for private repo");
|
|
982
|
+
return 1;
|
|
983
|
+
}
|
|
984
|
+
const createResult = runGraphQL(GRAPHQL_MUTATION_CREATE_ISSUE, {
|
|
985
|
+
repositoryId: repoId,
|
|
986
|
+
title: importTitle,
|
|
987
|
+
body: importBody,
|
|
988
|
+
labelIds: null,
|
|
989
|
+
});
|
|
990
|
+
if (!createResult.success) {
|
|
991
|
+
logger.error("Failed to create issue in private repo");
|
|
992
|
+
return 1;
|
|
993
|
+
}
|
|
994
|
+
const privateIssue = createResult.data?.data?.createIssue?.issue;
|
|
995
|
+
if (!privateIssue?.number) {
|
|
996
|
+
logger.error("Failed to create issue in private repo");
|
|
997
|
+
return 1;
|
|
998
|
+
}
|
|
999
|
+
logger.success(`Created private issue #${privateIssue.number}`);
|
|
1000
|
+
// Always add imported issue to project with default Status
|
|
1001
|
+
const importStatusValue = options.fieldStatus ?? getDefaultStatus();
|
|
1002
|
+
const projectId = getProjectId(owner, repo);
|
|
1003
|
+
if (projectId && privateIssue.id) {
|
|
1004
|
+
const addResult = runGraphQL(GRAPHQL_MUTATION_ADD_TO_PROJECT, {
|
|
1005
|
+
projectId,
|
|
1006
|
+
contentId: privateIssue.id,
|
|
1007
|
+
});
|
|
1008
|
+
if (addResult.success) {
|
|
1009
|
+
const itemId = addResult.data?.data?.addProjectV2ItemById?.item?.id;
|
|
1010
|
+
if (itemId) {
|
|
1011
|
+
logger.success("Added to project");
|
|
1012
|
+
const fields = {};
|
|
1013
|
+
if (importStatusValue)
|
|
1014
|
+
fields["Status"] = importStatusValue;
|
|
1015
|
+
if (options.priority)
|
|
1016
|
+
fields["Priority"] = options.priority;
|
|
1017
|
+
if (options.type)
|
|
1018
|
+
fields["Type"] = options.type;
|
|
1019
|
+
if (options.size)
|
|
1020
|
+
fields["Size"] = options.size;
|
|
1021
|
+
if (Object.keys(fields).length > 0) {
|
|
1022
|
+
setItemFields(projectId, itemId, fields, logger);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
// Comment on public issue to note internal tracking
|
|
1028
|
+
const publicIssueId = getIssueId(publicRepoParsed.owner, publicRepoParsed.name, publicIssueNumber);
|
|
1029
|
+
if (publicIssueId) {
|
|
1030
|
+
const commentBody = `This issue is being tracked internally. Thank you for the report.`;
|
|
1031
|
+
runGraphQL(GRAPHQL_MUTATION_ADD_COMMENT, {
|
|
1032
|
+
subjectId: publicIssueId,
|
|
1033
|
+
body: commentBody,
|
|
1034
|
+
});
|
|
1035
|
+
logger.debug("Added tracking comment to public issue");
|
|
1036
|
+
}
|
|
1037
|
+
// Output
|
|
1038
|
+
const output = {
|
|
1039
|
+
private_issue: {
|
|
1040
|
+
number: privateIssue.number,
|
|
1041
|
+
title: privateIssue.title,
|
|
1042
|
+
url: privateIssue.url,
|
|
1043
|
+
},
|
|
1044
|
+
public_issue: {
|
|
1045
|
+
number: publicIssueNumber,
|
|
1046
|
+
url: publicUrl,
|
|
1047
|
+
repo: pair.public,
|
|
1048
|
+
},
|
|
1049
|
+
};
|
|
1050
|
+
console.log(JSON.stringify(output, null, 2));
|
|
1051
|
+
return 0;
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* fields subcommand - Show project field definitions
|
|
1055
|
+
* (Migrated from gh-projects fields)
|
|
1056
|
+
*/
|
|
1057
|
+
async function cmdFields(options, logger) {
|
|
1058
|
+
const resolved = resolveTargetRepo(options);
|
|
1059
|
+
const repoInfo = getRepoInfo();
|
|
1060
|
+
const owner = resolved?.owner ?? options.owner ?? repoInfo?.owner;
|
|
1061
|
+
const repoName = resolved?.name ?? repoInfo?.name;
|
|
1062
|
+
if (!owner) {
|
|
1063
|
+
logger.error("Could not determine repository owner");
|
|
1064
|
+
return 1;
|
|
1065
|
+
}
|
|
1066
|
+
const projectId = getProjectId(owner, repoName ?? undefined);
|
|
1067
|
+
if (!projectId) {
|
|
1068
|
+
logger.error(`No project found for owner '${owner}'`);
|
|
1069
|
+
return 1;
|
|
1070
|
+
}
|
|
1071
|
+
const fields = getProjectFields(projectId);
|
|
1072
|
+
console.log(JSON.stringify(fields, null, 2));
|
|
1073
|
+
return 0;
|
|
1074
|
+
}
|
|
1075
|
+
/**
|
|
1076
|
+
* remove subcommand - Remove issue from project
|
|
1077
|
+
* (Migrated from gh-projects delete)
|
|
1078
|
+
*/
|
|
1079
|
+
async function cmdRemove(target, options, logger) {
|
|
1080
|
+
if (!isIssueNumber(target)) {
|
|
1081
|
+
logger.error("Issue number required");
|
|
1082
|
+
return 1;
|
|
1083
|
+
}
|
|
1084
|
+
const issueNumber = parseIssueNumber(target);
|
|
1085
|
+
const resolved = resolveTargetRepo(options);
|
|
1086
|
+
const repoInfo = getRepoInfo();
|
|
1087
|
+
const owner = resolved?.owner ?? options.owner ?? repoInfo?.owner;
|
|
1088
|
+
const repo = resolved?.name ?? repoInfo?.name;
|
|
1089
|
+
if (!owner) {
|
|
1090
|
+
logger.error("Could not determine repository owner");
|
|
1091
|
+
return 1;
|
|
1092
|
+
}
|
|
1093
|
+
if (!repo) {
|
|
1094
|
+
logger.error("Could not determine repository name");
|
|
1095
|
+
return 1;
|
|
1096
|
+
}
|
|
1097
|
+
const projectId = getProjectId(owner, repo);
|
|
1098
|
+
if (!projectId) {
|
|
1099
|
+
logger.error(`No project found for owner '${owner}'`);
|
|
1100
|
+
return 1;
|
|
1101
|
+
}
|
|
1102
|
+
// Find project item for this issue
|
|
1103
|
+
// Fetch the issue to find its project item ID
|
|
1104
|
+
const issueResult = cmdGetIssueDetail(owner, repo, issueNumber);
|
|
1105
|
+
if (!issueResult) {
|
|
1106
|
+
logger.error(`Issue #${issueNumber} not found`);
|
|
1107
|
+
return 1;
|
|
1108
|
+
}
|
|
1109
|
+
const projectItemId = issueResult.projectItemId;
|
|
1110
|
+
if (!projectItemId) {
|
|
1111
|
+
logger.error(`Issue #${issueNumber} is not in any project`);
|
|
1112
|
+
return 1;
|
|
1113
|
+
}
|
|
1114
|
+
// Remove from project
|
|
1115
|
+
const result = runGraphQL(GRAPHQL_MUTATION_DELETE_ITEM, {
|
|
1116
|
+
projectId,
|
|
1117
|
+
itemId: projectItemId,
|
|
1118
|
+
});
|
|
1119
|
+
if (result.success) {
|
|
1120
|
+
const output = {
|
|
1121
|
+
removed: true,
|
|
1122
|
+
issue_number: issueNumber,
|
|
1123
|
+
note: "Issue removed from project. Issue still exists.",
|
|
1124
|
+
};
|
|
1125
|
+
console.log(JSON.stringify(output, null, 2));
|
|
1126
|
+
return 0;
|
|
1127
|
+
}
|
|
1128
|
+
else {
|
|
1129
|
+
logger.error(`Failed to remove Issue #${issueNumber} from project`);
|
|
1130
|
+
return 1;
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
/**
|
|
1134
|
+
* Issue の projectItemId と projectId を GraphQL で取得する
|
|
1135
|
+
*/
|
|
1136
|
+
export function cmdGetIssueDetail(owner, repo, issueNumber) {
|
|
1137
|
+
const result = runGraphQL(GRAPHQL_QUERY_ISSUE_DETAIL, {
|
|
1138
|
+
owner,
|
|
1139
|
+
name: repo,
|
|
1140
|
+
number: issueNumber,
|
|
1141
|
+
});
|
|
1142
|
+
if (!result.success)
|
|
1143
|
+
return null;
|
|
1144
|
+
const issue = result.data?.data?.repository?.issue;
|
|
1145
|
+
if (!issue)
|
|
1146
|
+
return null;
|
|
1147
|
+
// Match by project name convention, fallback to first item
|
|
1148
|
+
const projectItems = issue.projectItems?.nodes ?? [];
|
|
1149
|
+
const projectItem = projectItems.find((p) => p?.project?.title === repo) ?? projectItems[0];
|
|
1150
|
+
return {
|
|
1151
|
+
projectItemId: projectItem?.id,
|
|
1152
|
+
projectId: projectItem?.project?.id,
|
|
1153
|
+
};
|
|
1154
|
+
}
|
|
1155
|
+
// =============================================================================
|
|
1156
|
+
// Main Command Handler
|
|
1157
|
+
// =============================================================================
|
|
1158
|
+
/**
|
|
1159
|
+
* gh-issues command handler
|
|
1160
|
+
*/
|
|
1161
|
+
export async function ghIssuesCommand(action, target, options) {
|
|
1162
|
+
const logger = createLogger(options.verbose);
|
|
1163
|
+
logger.debug(`Action: ${action}`);
|
|
1164
|
+
logger.debug(`Target: ${target ?? "(none)"}`);
|
|
1165
|
+
// Validate --repo alias early
|
|
1166
|
+
if (options.repo) {
|
|
1167
|
+
const aliasError = validateCrossRepoAlias(options.repo);
|
|
1168
|
+
if (aliasError) {
|
|
1169
|
+
logger.error(aliasError);
|
|
1170
|
+
process.exit(1);
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
let exitCode = 0;
|
|
1174
|
+
switch (action) {
|
|
1175
|
+
case "list":
|
|
1176
|
+
exitCode = await cmdList(options, logger);
|
|
1177
|
+
break;
|
|
1178
|
+
case "get":
|
|
1179
|
+
if (!target) {
|
|
1180
|
+
logger.error("Issue number required");
|
|
1181
|
+
logger.info("Usage: shirokuma-docs gh-issues get <number>");
|
|
1182
|
+
exitCode = 1;
|
|
1183
|
+
}
|
|
1184
|
+
else {
|
|
1185
|
+
exitCode = await cmdGet(target, options, logger);
|
|
1186
|
+
}
|
|
1187
|
+
break;
|
|
1188
|
+
case "create":
|
|
1189
|
+
exitCode = await cmdCreate(options, logger);
|
|
1190
|
+
break;
|
|
1191
|
+
case "update":
|
|
1192
|
+
if (!target) {
|
|
1193
|
+
logger.error("Issue number required");
|
|
1194
|
+
logger.info("Usage: shirokuma-docs gh-issues update <number> --status ...");
|
|
1195
|
+
exitCode = 1;
|
|
1196
|
+
}
|
|
1197
|
+
else {
|
|
1198
|
+
exitCode = await cmdUpdate(target, options, logger);
|
|
1199
|
+
}
|
|
1200
|
+
break;
|
|
1201
|
+
case "comment":
|
|
1202
|
+
if (!target) {
|
|
1203
|
+
logger.error("Issue number required");
|
|
1204
|
+
logger.info("Usage: shirokuma-docs gh-issues comment <number> --body ...");
|
|
1205
|
+
exitCode = 1;
|
|
1206
|
+
}
|
|
1207
|
+
else {
|
|
1208
|
+
exitCode = await cmdComment(target, options, logger);
|
|
1209
|
+
}
|
|
1210
|
+
break;
|
|
1211
|
+
case "close":
|
|
1212
|
+
if (!target) {
|
|
1213
|
+
logger.error("Issue number required");
|
|
1214
|
+
logger.info("Usage: shirokuma-docs gh-issues close <number> [--body ...] [--state-reason COMPLETED|NOT_PLANNED]");
|
|
1215
|
+
exitCode = 1;
|
|
1216
|
+
}
|
|
1217
|
+
else {
|
|
1218
|
+
exitCode = await cmdClose(target, options, logger);
|
|
1219
|
+
}
|
|
1220
|
+
break;
|
|
1221
|
+
case "reopen":
|
|
1222
|
+
if (!target) {
|
|
1223
|
+
logger.error("Issue number required");
|
|
1224
|
+
logger.info("Usage: shirokuma-docs gh-issues reopen <number>");
|
|
1225
|
+
exitCode = 1;
|
|
1226
|
+
}
|
|
1227
|
+
else {
|
|
1228
|
+
exitCode = await cmdReopen(target, options, logger);
|
|
1229
|
+
}
|
|
1230
|
+
break;
|
|
1231
|
+
case "import":
|
|
1232
|
+
exitCode = await cmdImport(options, logger);
|
|
1233
|
+
break;
|
|
1234
|
+
case "fields":
|
|
1235
|
+
exitCode = await cmdFields(options, logger);
|
|
1236
|
+
break;
|
|
1237
|
+
case "remove":
|
|
1238
|
+
if (!target) {
|
|
1239
|
+
logger.error("Issue number required");
|
|
1240
|
+
logger.info("Usage: shirokuma-docs gh-issues remove <number>");
|
|
1241
|
+
exitCode = 1;
|
|
1242
|
+
}
|
|
1243
|
+
else {
|
|
1244
|
+
exitCode = await cmdRemove(target, options, logger);
|
|
1245
|
+
}
|
|
1246
|
+
break;
|
|
1247
|
+
case "pr-comments":
|
|
1248
|
+
if (!target) {
|
|
1249
|
+
logger.error("PR number required");
|
|
1250
|
+
logger.info("Usage: shirokuma-docs gh-issues pr-comments <number>");
|
|
1251
|
+
exitCode = 1;
|
|
1252
|
+
}
|
|
1253
|
+
else {
|
|
1254
|
+
exitCode = await cmdPrComments(target, options, logger);
|
|
1255
|
+
}
|
|
1256
|
+
break;
|
|
1257
|
+
case "merge":
|
|
1258
|
+
if (!target && !options.head) {
|
|
1259
|
+
logger.error("PR number or --head <branch> required");
|
|
1260
|
+
logger.info("Usage: shirokuma-docs gh-issues merge <number> [--squash|--merge|--rebase]\n" +
|
|
1261
|
+
" shirokuma-docs gh-issues merge --head <branch>");
|
|
1262
|
+
exitCode = 1;
|
|
1263
|
+
}
|
|
1264
|
+
else {
|
|
1265
|
+
exitCode = await cmdMerge(target, options, logger);
|
|
1266
|
+
}
|
|
1267
|
+
break;
|
|
1268
|
+
case "pr-reply":
|
|
1269
|
+
if (!target) {
|
|
1270
|
+
logger.error("PR number required");
|
|
1271
|
+
logger.info("Usage: shirokuma-docs gh-issues pr-reply <number> --reply-to <id> --body ...");
|
|
1272
|
+
exitCode = 1;
|
|
1273
|
+
}
|
|
1274
|
+
else {
|
|
1275
|
+
exitCode = await cmdPrReply(target, options, logger);
|
|
1276
|
+
}
|
|
1277
|
+
break;
|
|
1278
|
+
case "resolve":
|
|
1279
|
+
if (!target) {
|
|
1280
|
+
logger.error("PR number required");
|
|
1281
|
+
logger.info("Usage: shirokuma-docs gh-issues resolve <number> --thread-id <id>");
|
|
1282
|
+
exitCode = 1;
|
|
1283
|
+
}
|
|
1284
|
+
else {
|
|
1285
|
+
exitCode = await cmdResolve(target, options, logger);
|
|
1286
|
+
}
|
|
1287
|
+
break;
|
|
1288
|
+
default:
|
|
1289
|
+
logger.error(`Unknown action: ${action}`);
|
|
1290
|
+
logger.info("Available actions: list, get, create, update, comment, close, reopen, import, fields, remove, pr-comments, merge, pr-reply, resolve");
|
|
1291
|
+
exitCode = 1;
|
|
1292
|
+
}
|
|
1293
|
+
if (exitCode !== 0) {
|
|
1294
|
+
process.exit(exitCode);
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
//# sourceMappingURL=gh-issues.js.map
|