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