specweave 0.6.8 ā 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/README.md +1 -1
- package/CLAUDE.md +903 -99
- package/README.md +143 -207
- package/bin/specweave.js +67 -0
- package/dist/cli/commands/abandon.d.ts +13 -0
- package/dist/cli/commands/abandon.d.ts.map +1 -0
- package/dist/cli/commands/abandon.js +15 -0
- package/dist/cli/commands/abandon.js.map +1 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +94 -18
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/pause.d.ts +13 -0
- package/dist/cli/commands/pause.d.ts.map +1 -0
- package/dist/cli/commands/pause.js +15 -0
- package/dist/cli/commands/pause.js.map +1 -0
- package/dist/cli/commands/qa.d.ts +54 -0
- package/dist/cli/commands/qa.d.ts.map +1 -0
- package/dist/cli/commands/qa.js +98 -0
- package/dist/cli/commands/qa.js.map +1 -0
- package/dist/cli/commands/resume.d.ts +12 -0
- package/dist/cli/commands/resume.d.ts.map +1 -0
- package/dist/cli/commands/resume.js +14 -0
- package/dist/cli/commands/resume.js.map +1 -0
- package/dist/cli/commands/status.d.ts +12 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +23 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/helpers/issue-tracker/ado.d.ts +57 -0
- package/dist/cli/helpers/issue-tracker/ado.d.ts.map +1 -0
- package/dist/cli/helpers/issue-tracker/ado.js +223 -0
- package/dist/cli/helpers/issue-tracker/ado.js.map +1 -0
- package/dist/cli/helpers/issue-tracker/github.d.ts +65 -0
- package/dist/cli/helpers/issue-tracker/github.d.ts.map +1 -0
- package/dist/cli/helpers/issue-tracker/github.js +284 -0
- package/dist/cli/helpers/issue-tracker/github.js.map +1 -0
- package/dist/cli/helpers/issue-tracker/index.d.ts +22 -0
- package/dist/cli/helpers/issue-tracker/index.d.ts.map +1 -0
- package/dist/cli/helpers/issue-tracker/index.js +270 -0
- package/dist/cli/helpers/issue-tracker/index.js.map +1 -0
- package/dist/cli/helpers/issue-tracker/jira.d.ts +61 -0
- package/dist/cli/helpers/issue-tracker/jira.d.ts.map +1 -0
- package/dist/cli/helpers/issue-tracker/jira.js +265 -0
- package/dist/cli/helpers/issue-tracker/jira.js.map +1 -0
- package/dist/cli/helpers/issue-tracker/types.d.ts +86 -0
- package/dist/cli/helpers/issue-tracker/types.d.ts.map +1 -0
- package/dist/cli/helpers/issue-tracker/types.js +16 -0
- package/dist/cli/helpers/issue-tracker/types.js.map +1 -0
- package/dist/cli/helpers/issue-tracker/utils.d.ts +103 -0
- package/dist/cli/helpers/issue-tracker/utils.d.ts.map +1 -0
- package/dist/cli/helpers/issue-tracker/utils.js +240 -0
- package/dist/cli/helpers/issue-tracker/utils.js.map +1 -0
- package/dist/core/increment/limits.d.ts +68 -0
- package/dist/core/increment/limits.d.ts.map +1 -0
- package/dist/core/increment/limits.js +224 -0
- package/dist/core/increment/limits.js.map +1 -0
- package/dist/core/increment/metadata-manager.d.ts +114 -0
- package/dist/core/increment/metadata-manager.d.ts.map +1 -0
- package/dist/core/increment/metadata-manager.js +320 -0
- package/dist/core/increment/metadata-manager.js.map +1 -0
- package/dist/core/increment/status-commands.d.ts +43 -0
- package/dist/core/increment/status-commands.d.ts.map +1 -0
- package/dist/core/increment/status-commands.js +277 -0
- package/dist/core/increment/status-commands.js.map +1 -0
- package/dist/core/plugin-detector.d.ts +1 -0
- package/dist/core/plugin-detector.d.ts.map +1 -1
- package/dist/core/plugin-detector.js +25 -0
- package/dist/core/plugin-detector.js.map +1 -1
- package/dist/core/qa/qa-runner.d.ts +16 -0
- package/dist/core/qa/qa-runner.d.ts.map +1 -0
- package/dist/core/qa/qa-runner.js +404 -0
- package/dist/core/qa/qa-runner.js.map +1 -0
- package/dist/core/qa/quality-gate-decider.d.ts +53 -0
- package/dist/core/qa/quality-gate-decider.d.ts.map +1 -0
- package/dist/core/qa/quality-gate-decider.js +268 -0
- package/dist/core/qa/quality-gate-decider.js.map +1 -0
- package/dist/core/qa/risk-calculator.d.ts +126 -0
- package/dist/core/qa/risk-calculator.d.ts.map +1 -0
- package/dist/core/qa/risk-calculator.js +247 -0
- package/dist/core/qa/risk-calculator.js.map +1 -0
- package/dist/core/qa/types.d.ts +315 -0
- package/dist/core/qa/types.d.ts.map +1 -0
- package/dist/core/qa/types.js +8 -0
- package/dist/core/qa/types.js.map +1 -0
- package/dist/core/types/config.d.ts +35 -0
- package/dist/core/types/config.d.ts.map +1 -1
- package/dist/core/types/config.js +16 -0
- package/dist/core/types/config.js.map +1 -1
- package/dist/core/types/increment-metadata.d.ts +120 -0
- package/dist/core/types/increment-metadata.d.ts.map +1 -0
- package/dist/core/types/increment-metadata.js +138 -0
- package/dist/core/types/increment-metadata.js.map +1 -0
- package/dist/hooks/lib/invoke-translator-skill.d.ts +60 -0
- package/dist/hooks/lib/invoke-translator-skill.d.ts.map +1 -0
- package/dist/hooks/lib/invoke-translator-skill.js +201 -0
- package/dist/hooks/lib/invoke-translator-skill.js.map +1 -0
- package/dist/hooks/lib/translate-file.d.ts +59 -0
- package/dist/hooks/lib/translate-file.d.ts.map +1 -0
- package/dist/hooks/lib/translate-file.js +350 -0
- package/dist/hooks/lib/translate-file.js.map +1 -0
- package/dist/locales/en/cli.json +3 -1
- package/dist/metrics/calculators/change-failure-rate.d.ts +22 -0
- package/dist/metrics/calculators/change-failure-rate.d.ts.map +1 -0
- package/dist/metrics/calculators/change-failure-rate.js +70 -0
- package/dist/metrics/calculators/change-failure-rate.js.map +1 -0
- package/dist/metrics/calculators/deployment-frequency.d.ts +20 -0
- package/dist/metrics/calculators/deployment-frequency.d.ts.map +1 -0
- package/dist/metrics/calculators/deployment-frequency.js +61 -0
- package/dist/metrics/calculators/deployment-frequency.js.map +1 -0
- package/dist/metrics/calculators/lead-time.d.ts +22 -0
- package/dist/metrics/calculators/lead-time.d.ts.map +1 -0
- package/dist/metrics/calculators/lead-time.js +82 -0
- package/dist/metrics/calculators/lead-time.js.map +1 -0
- package/dist/metrics/calculators/mttr.d.ts +21 -0
- package/dist/metrics/calculators/mttr.d.ts.map +1 -0
- package/dist/metrics/calculators/mttr.js +60 -0
- package/dist/metrics/calculators/mttr.js.map +1 -0
- package/dist/metrics/dora-calculator.d.ts +24 -0
- package/dist/metrics/dora-calculator.d.ts.map +1 -0
- package/dist/metrics/dora-calculator.js +104 -0
- package/dist/metrics/dora-calculator.js.map +1 -0
- package/dist/metrics/github-client.d.ts +51 -0
- package/dist/metrics/github-client.d.ts.map +1 -0
- package/dist/metrics/github-client.js +133 -0
- package/dist/metrics/github-client.js.map +1 -0
- package/dist/metrics/types.d.ts +112 -0
- package/dist/metrics/types.d.ts.map +1 -0
- package/dist/metrics/types.js +10 -0
- package/dist/metrics/types.js.map +1 -0
- package/dist/metrics/utils/percentile.d.ts +25 -0
- package/dist/metrics/utils/percentile.d.ts.map +1 -0
- package/dist/metrics/utils/percentile.js +46 -0
- package/dist/metrics/utils/percentile.js.map +1 -0
- package/dist/metrics/utils/tier-classifier.d.ts +61 -0
- package/dist/metrics/utils/tier-classifier.d.ts.map +1 -0
- package/dist/metrics/utils/tier-classifier.js +100 -0
- package/dist/metrics/utils/tier-classifier.js.map +1 -0
- package/dist/utils/auth-helpers.d.ts +58 -0
- package/dist/utils/auth-helpers.d.ts.map +1 -0
- package/dist/utils/auth-helpers.js +108 -0
- package/dist/utils/auth-helpers.js.map +1 -0
- package/dist/utils/env-file.d.ts +88 -0
- package/dist/utils/env-file.d.ts.map +1 -0
- package/dist/utils/env-file.js +180 -0
- package/dist/utils/env-file.js.map +1 -0
- package/dist/utils/plugin-detection.d.ts +50 -0
- package/dist/utils/plugin-detection.d.ts.map +1 -0
- package/dist/utils/plugin-detection.js +229 -0
- package/dist/utils/plugin-detection.js.map +1 -0
- package/dist/utils/secrets-loader.d.ts +88 -0
- package/dist/utils/secrets-loader.d.ts.map +1 -0
- package/dist/utils/secrets-loader.js +271 -0
- package/dist/utils/secrets-loader.js.map +1 -0
- package/dist/utils/translation.d.ts +187 -0
- package/dist/utils/translation.d.ts.map +1 -0
- package/dist/utils/translation.js +414 -0
- package/dist/utils/translation.js.map +1 -0
- package/package.json +28 -44
- package/plugins/specweave/.claude-plugin/plugin.json +3 -3
- package/plugins/specweave/agents/pm/AGENT.md +330 -54
- package/plugins/specweave/agents/test-aware-planner/AGENT.md +1035 -0
- package/plugins/specweave/agents/test-aware-planner/templates/README.md +118 -0
- package/plugins/specweave/agents/test-aware-planner/templates/task-non-testable.md.template +24 -0
- package/plugins/specweave/agents/test-aware-planner/templates/task-testable.md.template +53 -0
- package/plugins/specweave/agents/test-aware-planner/templates/tasks-frontmatter.md.template +11 -0
- package/plugins/specweave/commands/README.md +88 -163
- package/plugins/specweave/commands/specweave-abandon.md +314 -0
- package/plugins/specweave/commands/specweave-check-tests.md +546 -0
- package/plugins/specweave/commands/{do.md ā specweave-do.md} +5 -7
- package/plugins/specweave/commands/{increment.md ā specweave-increment.md} +231 -4
- package/plugins/specweave/commands/specweave-pause.md +189 -0
- package/plugins/specweave/commands/specweave-qa.md +245 -0
- package/plugins/specweave/commands/specweave-resume.md +216 -0
- package/plugins/specweave/commands/specweave-status.md +397 -0
- package/plugins/specweave/commands/specweave-sync-tasks.md +256 -0
- package/plugins/specweave/commands/{translate.md ā specweave-translate.md} +3 -3
- package/plugins/specweave/commands/specweave-update-scope.md +351 -0
- package/plugins/specweave/commands/specweave.md +21 -21
- package/plugins/specweave/hooks/post-increment-planning.sh +335 -0
- package/plugins/specweave/hooks/post-task-completion.sh +141 -0
- package/plugins/specweave/skills/SKILLS-INDEX.md +1 -1
- package/plugins/specweave/skills/brownfield-analyzer/SKILL.md +9 -9
- package/plugins/specweave/skills/increment-planner/SKILL.md +400 -212
- package/plugins/specweave/skills/increment-quality-judge-v2/SKILL.md +499 -0
- package/plugins/specweave/skills/plugin-detector/SKILL.md +114 -1
- package/plugins/specweave/skills/project-kickstarter/SKILL.md +74 -1
- package/plugins/specweave/skills/{rfc-generator ā spec-generator}/SKILL.md +22 -29
- package/plugins/specweave/skills/specweave-detector/SKILL.md +3 -3
- package/plugins/specweave/skills/specweave-framework/SKILL.md +2 -2
- package/plugins/specweave-ado/.claude-plugin/plugin.json +18 -4
- package/plugins/specweave-ado/agents/ado-manager/AGENT.md +426 -0
- package/plugins/specweave-ado/commands/close-workitem.md +52 -0
- package/plugins/specweave-ado/commands/create-workitem.md +53 -0
- package/plugins/specweave-ado/commands/status.md +53 -0
- package/plugins/specweave-ado/commands/sync.md +55 -0
- package/plugins/specweave-ado/lib/ado-client.ts +361 -0
- package/plugins/specweave-ado/reference/ado-specweave-mapping.md +552 -0
- package/plugins/specweave-ado/skills/ado-sync/SKILL.md +344 -193
- package/plugins/specweave-docs/skills/docusaurus/SKILL.md +73 -0
- package/plugins/specweave-github/agents/github-manager/AGENT.md +49 -0
- package/plugins/specweave-github/commands/{github-close-issue.md ā close-issue.md} +1 -1
- package/plugins/specweave-github/commands/{github-create-issue.md ā create-issue.md} +1 -1
- package/plugins/specweave-github/commands/{github-status.md ā status.md} +1 -1
- package/plugins/specweave-github/commands/{github-sync-tasks.md ā sync-tasks.md} +1 -1
- package/plugins/specweave-github/commands/{github-sync.md ā sync.md} +1 -1
- package/plugins/specweave-github/reference/github-specweave-mapping.md +377 -0
- package/plugins/specweave-github/skills/github-sync/SKILL.md +11 -3
- package/plugins/specweave-infrastructure/commands/{specweave.monitor-setup.md ā monitor-setup.md} +5 -0
- package/plugins/specweave-infrastructure/commands/{specweave.slo-implement.md ā slo-implement.md} +5 -0
- package/plugins/specweave-jira/agents/jira-manager/AGENT.md +380 -0
- package/plugins/specweave-jira/commands/{specweave.sync-jira.md ā sync.md} +1 -1
- package/plugins/specweave-jira/reference/jira-specweave-mapping.md +508 -0
- package/plugins/specweave-ml/commands/ml-deploy.md +1 -1
- package/plugins/specweave-ml/commands/ml-evaluate.md +1 -1
- package/plugins/specweave-ml/commands/ml-explain.md +1 -1
- package/plugins/specweave-ml/commands/{specweave.ml-pipeline.md ā ml-pipeline.md} +5 -0
- package/src/templates/AGENTS.md.template +331 -31
- package/src/templates/CLAUDE.md.template +36 -21
- package/src/templates/COMPLETION-REPORT.template.md +128 -0
- package/src/templates/README.md.template +17 -16
- package/src/templates/docs/README.md +11 -9
- package/src/templates/docs/spec-template.md +229 -0
- package/plugins/specweave/commands/inc.md +0 -85
- package/plugins/specweave/commands/list-increments.md +0 -180
- package/src/adapters/README.md +0 -275
- package/src/adapters/adapter-base.ts +0 -182
- package/src/adapters/adapter-interface.ts +0 -166
- package/src/adapters/adapter-loader.ts +0 -256
- package/src/adapters/agents-md-generator.ts +0 -228
- package/src/adapters/claude/README.md +0 -233
- package/src/adapters/claude/adapter.ts +0 -468
- package/src/adapters/claude-md-generator.ts +0 -377
- package/src/adapters/codex/README.md +0 -105
- package/src/adapters/codex/adapter.ts +0 -333
- package/src/adapters/cursor/.cursor/context/docs-context.md +0 -62
- package/src/adapters/cursor/.cursor/context/increments-context.md +0 -71
- package/src/adapters/cursor/.cursor/context/strategy-context.md +0 -73
- package/src/adapters/cursor/.cursor/context/tests-context.md +0 -89
- package/src/adapters/cursor/README.md +0 -283
- package/src/adapters/cursor/adapter.ts +0 -451
- package/src/adapters/doc-generator.ts +0 -331
- package/src/adapters/gemini/README.md +0 -97
- package/src/adapters/gemini/adapter.ts +0 -298
- package/src/adapters/generic/README.md +0 -277
- package/src/adapters/generic/adapter.ts +0 -378
- package/src/adapters/registry.yaml +0 -187
- /package/plugins/specweave/commands/{costs.md ā specweave-costs.md} +0 -0
- /package/plugins/specweave/commands/{done.md ā specweave-done.md} +0 -0
- /package/plugins/specweave/commands/{next.md ā specweave-next.md} +0 -0
- /package/plugins/specweave/commands/{progress.md ā specweave-progress.md} +0 -0
- /package/plugins/specweave/commands/{sync-docs.md ā specweave-sync-docs.md} +0 -0
- /package/plugins/specweave/commands/{tdd-cycle.md ā specweave-tdd-cycle.md} +0 -0
- /package/plugins/specweave/commands/{tdd-green.md ā specweave-tdd-green.md} +0 -0
- /package/plugins/specweave/commands/{tdd-red.md ā specweave-tdd-red.md} +0 -0
- /package/plugins/specweave/commands/{tdd-refactor.md ā specweave-tdd-refactor.md} +0 -0
- /package/plugins/specweave/commands/{validate.md ā specweave-validate.md} +0 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { showStatus } from '../../core/increment/status-commands.js';
|
|
2
|
+
/**
|
|
3
|
+
* CLI command to show increment status overview
|
|
4
|
+
*
|
|
5
|
+
* @param options - Command options (verbose, type filter)
|
|
6
|
+
*/
|
|
7
|
+
export async function statusCommand(options = {}) {
|
|
8
|
+
const statusOptions = {
|
|
9
|
+
verbose: options.verbose
|
|
10
|
+
};
|
|
11
|
+
// Validate and convert type if provided
|
|
12
|
+
if (options.type) {
|
|
13
|
+
const validTypes = ['feature', 'hotfix', 'bug', 'change-request', 'refactor', 'experiment'];
|
|
14
|
+
if (!validTypes.includes(options.type)) {
|
|
15
|
+
console.error(`Invalid type: ${options.type}`);
|
|
16
|
+
console.error(`Valid types: ${validTypes.join(', ')}`);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
statusOptions.type = options.type;
|
|
20
|
+
}
|
|
21
|
+
await showStatus(statusOptions);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/cli/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAiB,MAAM,yCAAyC,CAAC;AAQpF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,UAAgC,EAAE;IACpE,MAAM,aAAa,GAAkB;QACnC,OAAO,EAAE,OAAO,CAAC,OAAO;KACzB,CAAC;IAEF,wCAAwC;IACxC,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,MAAM,UAAU,GAAa,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;QACtG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACvC,OAAO,CAAC,KAAK,CAAC,iBAAiB,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;YAC/C,OAAO,CAAC,KAAK,CAAC,gBAAgB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,aAAa,CAAC,IAAI,GAAG,OAAO,CAAC,IAAqB,CAAC;IACrD,CAAC;IAED,MAAM,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Azure DevOps Integration for Issue Tracker Setup
|
|
3
|
+
*
|
|
4
|
+
* Handles Azure DevOps authentication and connection validation
|
|
5
|
+
*
|
|
6
|
+
* @module cli/helpers/issue-tracker/ado
|
|
7
|
+
*/
|
|
8
|
+
import type { AzureDevOpsCredentials, ExistingCredentials, ValidationResult } from './types.js';
|
|
9
|
+
import type { SupportedLanguage } from '../../../core/i18n/types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Check for existing Azure DevOps credentials
|
|
12
|
+
*
|
|
13
|
+
* @param projectPath - Path to project root
|
|
14
|
+
* @returns Existing credentials or null
|
|
15
|
+
*/
|
|
16
|
+
export declare function checkExistingAzureDevOpsCredentials(projectPath: string): Promise<ExistingCredentials | null>;
|
|
17
|
+
/**
|
|
18
|
+
* Prompt user for Azure DevOps credentials
|
|
19
|
+
*
|
|
20
|
+
* @param language - User's language
|
|
21
|
+
* @returns Credentials or null if skipped
|
|
22
|
+
*/
|
|
23
|
+
export declare function promptAzureDevOpsCredentials(language: SupportedLanguage): Promise<AzureDevOpsCredentials | null>;
|
|
24
|
+
/**
|
|
25
|
+
* Validate Azure DevOps connection
|
|
26
|
+
*
|
|
27
|
+
* Tests authentication and returns project information
|
|
28
|
+
* Handles rate limiting with retry logic
|
|
29
|
+
*
|
|
30
|
+
* @param credentials - Azure DevOps credentials
|
|
31
|
+
* @param maxRetries - Maximum retry attempts (default: 3)
|
|
32
|
+
* @returns Validation result
|
|
33
|
+
*/
|
|
34
|
+
export declare function validateAzureDevOpsConnection(credentials: AzureDevOpsCredentials, maxRetries?: number): Promise<ValidationResult>;
|
|
35
|
+
/**
|
|
36
|
+
* Get Azure DevOps environment variables for .env file
|
|
37
|
+
*
|
|
38
|
+
* @param credentials - Azure DevOps credentials
|
|
39
|
+
* @returns Array of key-value pairs for .env
|
|
40
|
+
*/
|
|
41
|
+
export declare function getAzureDevOpsEnvVars(credentials: AzureDevOpsCredentials): Array<{
|
|
42
|
+
key: string;
|
|
43
|
+
value: string;
|
|
44
|
+
}>;
|
|
45
|
+
/**
|
|
46
|
+
* Show Azure DevOps setup complete message
|
|
47
|
+
*
|
|
48
|
+
* @param language - User's language
|
|
49
|
+
*/
|
|
50
|
+
export declare function showAzureDevOpsSetupComplete(language: SupportedLanguage): void;
|
|
51
|
+
/**
|
|
52
|
+
* Show Azure DevOps setup skipped message
|
|
53
|
+
*
|
|
54
|
+
* @param language - User's language
|
|
55
|
+
*/
|
|
56
|
+
export declare function showAzureDevOpsSetupSkipped(language: SupportedLanguage): void;
|
|
57
|
+
//# sourceMappingURL=ado.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ado.d.ts","sourceRoot":"","sources":["../../../../src/cli/helpers/issue-tracker/ado.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,OAAO,KAAK,EACV,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAKpB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAIrE;;;;;GAKG;AACH,wBAAsB,mCAAmC,CACvD,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CA2BrC;AAED;;;;;GAKG;AACH,wBAAsB,4BAA4B,CAChD,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAyExC;AAED;;;;;;;;;GASG;AACH,wBAAsB,6BAA6B,CACjD,WAAW,EAAE,sBAAsB,EACnC,UAAU,GAAE,MAAU,GACrB,OAAO,CAAC,gBAAgB,CAAC,CA+D3B;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,sBAAsB,GAClC,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAMvC;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAS9E;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAO7E"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Azure DevOps Integration for Issue Tracker Setup
|
|
3
|
+
*
|
|
4
|
+
* Handles Azure DevOps authentication and connection validation
|
|
5
|
+
*
|
|
6
|
+
* @module cli/helpers/issue-tracker/ado
|
|
7
|
+
*/
|
|
8
|
+
import chalk from 'chalk';
|
|
9
|
+
import inquirer from 'inquirer';
|
|
10
|
+
import ora from 'ora';
|
|
11
|
+
import { getAzureDevOpsAuth } from '../../../utils/auth-helpers.js';
|
|
12
|
+
import { parseEnvFile, readEnvFile } from '../../../utils/env-file.js';
|
|
13
|
+
import { retryWithBackoff, checkRateLimit } from './utils.js';
|
|
14
|
+
import { getLocaleManager } from '../../../core/i18n/locale-manager.js';
|
|
15
|
+
import { RateLimitError } from './types.js';
|
|
16
|
+
/**
|
|
17
|
+
* Check for existing Azure DevOps credentials
|
|
18
|
+
*
|
|
19
|
+
* @param projectPath - Path to project root
|
|
20
|
+
* @returns Existing credentials or null
|
|
21
|
+
*/
|
|
22
|
+
export async function checkExistingAzureDevOpsCredentials(projectPath) {
|
|
23
|
+
// 1. Check project .env file
|
|
24
|
+
const envContent = readEnvFile(projectPath);
|
|
25
|
+
if (envContent) {
|
|
26
|
+
const parsed = parseEnvFile(envContent);
|
|
27
|
+
if (parsed.AZURE_DEVOPS_PAT && parsed.AZURE_DEVOPS_ORG && parsed.AZURE_DEVOPS_PROJECT) {
|
|
28
|
+
return {
|
|
29
|
+
source: '.env',
|
|
30
|
+
credentials: {
|
|
31
|
+
pat: parsed.AZURE_DEVOPS_PAT,
|
|
32
|
+
org: parsed.AZURE_DEVOPS_ORG,
|
|
33
|
+
project: parsed.AZURE_DEVOPS_PROJECT
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// 2. Check environment variables
|
|
39
|
+
const auth = getAzureDevOpsAuth();
|
|
40
|
+
if (auth) {
|
|
41
|
+
return {
|
|
42
|
+
source: 'env-vars',
|
|
43
|
+
credentials: auth
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Prompt user for Azure DevOps credentials
|
|
50
|
+
*
|
|
51
|
+
* @param language - User's language
|
|
52
|
+
* @returns Credentials or null if skipped
|
|
53
|
+
*/
|
|
54
|
+
export async function promptAzureDevOpsCredentials(language) {
|
|
55
|
+
const locale = getLocaleManager(language);
|
|
56
|
+
console.log(chalk.white('\nš Azure DevOps Integration Setup\n'));
|
|
57
|
+
console.log(chalk.gray('SpecWeave will sync increments with Azure DevOps Work Items.\n'));
|
|
58
|
+
// Show setup instructions
|
|
59
|
+
console.log(chalk.cyan('š Quick Setup:'));
|
|
60
|
+
console.log(chalk.gray(' 1. Go to: https://dev.azure.com/{org}/_usersSettings/tokens'));
|
|
61
|
+
console.log(chalk.gray(' 2. Click "New Token"'));
|
|
62
|
+
console.log(chalk.gray(' 3. Scopes: Work Items (Read, Write, Manage), Code (Read), Project (Read)'));
|
|
63
|
+
console.log(chalk.gray(' 4. Copy the token\n'));
|
|
64
|
+
const { continueSetup } = await inquirer.prompt([{
|
|
65
|
+
type: 'confirm',
|
|
66
|
+
name: 'continueSetup',
|
|
67
|
+
message: 'Continue with Azure DevOps setup?',
|
|
68
|
+
default: true
|
|
69
|
+
}]);
|
|
70
|
+
if (!continueSetup) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
// Collect credentials
|
|
74
|
+
const questions = [
|
|
75
|
+
{
|
|
76
|
+
type: 'input',
|
|
77
|
+
name: 'org',
|
|
78
|
+
message: 'Azure DevOps organization name:',
|
|
79
|
+
validate: (input) => {
|
|
80
|
+
if (!input || input.trim() === '') {
|
|
81
|
+
return 'Organization cannot be empty';
|
|
82
|
+
}
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
type: 'input',
|
|
88
|
+
name: 'project',
|
|
89
|
+
message: 'Project name:',
|
|
90
|
+
validate: (input) => {
|
|
91
|
+
if (!input || input.trim() === '') {
|
|
92
|
+
return 'Project cannot be empty';
|
|
93
|
+
}
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
type: 'password',
|
|
99
|
+
name: 'pat',
|
|
100
|
+
message: 'Paste your Personal Access Token:',
|
|
101
|
+
mask: '*',
|
|
102
|
+
validate: (input) => {
|
|
103
|
+
if (!input || input.length === 0) {
|
|
104
|
+
return 'Token cannot be empty';
|
|
105
|
+
}
|
|
106
|
+
// ADO PATs are typically 52 characters, but fine-grained tokens can be >= 40
|
|
107
|
+
if (input.length < 40) {
|
|
108
|
+
return 'Azure DevOps tokens should be at least 40 characters';
|
|
109
|
+
}
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
];
|
|
114
|
+
const answers = await inquirer.prompt(questions);
|
|
115
|
+
return {
|
|
116
|
+
pat: answers.pat,
|
|
117
|
+
org: answers.org,
|
|
118
|
+
project: answers.project
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Validate Azure DevOps connection
|
|
123
|
+
*
|
|
124
|
+
* Tests authentication and returns project information
|
|
125
|
+
* Handles rate limiting with retry logic
|
|
126
|
+
*
|
|
127
|
+
* @param credentials - Azure DevOps credentials
|
|
128
|
+
* @param maxRetries - Maximum retry attempts (default: 3)
|
|
129
|
+
* @returns Validation result
|
|
130
|
+
*/
|
|
131
|
+
export async function validateAzureDevOpsConnection(credentials, maxRetries = 3) {
|
|
132
|
+
const spinner = ora('Testing connection...').start();
|
|
133
|
+
try {
|
|
134
|
+
const result = await retryWithBackoff(async () => {
|
|
135
|
+
// Test connection by fetching project details
|
|
136
|
+
const projectEndpoint = `https://dev.azure.com/${credentials.org}/_apis/projects/${credentials.project}?api-version=7.0`;
|
|
137
|
+
// Basic auth with PAT (username can be empty)
|
|
138
|
+
const auth = Buffer.from(`:${credentials.pat}`).toString('base64');
|
|
139
|
+
const response = await fetch(projectEndpoint, {
|
|
140
|
+
headers: {
|
|
141
|
+
'Authorization': `Basic ${auth}`,
|
|
142
|
+
'Accept': 'application/json'
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
// Check for rate limiting
|
|
146
|
+
const rateLimitInfo = checkRateLimit(response);
|
|
147
|
+
if (rateLimitInfo) {
|
|
148
|
+
throw new RateLimitError('Azure DevOps API rate limit exceeded', rateLimitInfo);
|
|
149
|
+
}
|
|
150
|
+
if (!response.ok) {
|
|
151
|
+
const errorText = await response.text();
|
|
152
|
+
let errorMessage = 'Authentication failed';
|
|
153
|
+
if (response.status === 401) {
|
|
154
|
+
errorMessage = 'Invalid Personal Access Token';
|
|
155
|
+
}
|
|
156
|
+
else if (response.status === 403) {
|
|
157
|
+
errorMessage = 'Access forbidden (check token scopes)';
|
|
158
|
+
}
|
|
159
|
+
else if (response.status === 404) {
|
|
160
|
+
errorMessage = 'Project not found (check organization and project name)';
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
errorMessage = `HTTP ${response.status}: ${errorText}`;
|
|
164
|
+
}
|
|
165
|
+
throw new Error(errorMessage);
|
|
166
|
+
}
|
|
167
|
+
const project = await response.json();
|
|
168
|
+
return project;
|
|
169
|
+
}, maxRetries);
|
|
170
|
+
spinner.succeed(`Connected to Azure DevOps project: ${result.name}`);
|
|
171
|
+
return {
|
|
172
|
+
success: true,
|
|
173
|
+
username: result.name
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
spinner.fail('Azure DevOps authentication failed');
|
|
178
|
+
return {
|
|
179
|
+
success: false,
|
|
180
|
+
error: error.message || 'Unknown error'
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Get Azure DevOps environment variables for .env file
|
|
186
|
+
*
|
|
187
|
+
* @param credentials - Azure DevOps credentials
|
|
188
|
+
* @returns Array of key-value pairs for .env
|
|
189
|
+
*/
|
|
190
|
+
export function getAzureDevOpsEnvVars(credentials) {
|
|
191
|
+
return [
|
|
192
|
+
{ key: 'AZURE_DEVOPS_PAT', value: credentials.pat },
|
|
193
|
+
{ key: 'AZURE_DEVOPS_ORG', value: credentials.org },
|
|
194
|
+
{ key: 'AZURE_DEVOPS_PROJECT', value: credentials.project }
|
|
195
|
+
];
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Show Azure DevOps setup complete message
|
|
199
|
+
*
|
|
200
|
+
* @param language - User's language
|
|
201
|
+
*/
|
|
202
|
+
export function showAzureDevOpsSetupComplete(language) {
|
|
203
|
+
const locale = getLocaleManager(language);
|
|
204
|
+
console.log(chalk.green.bold('\nā
Azure DevOps integration complete!\n'));
|
|
205
|
+
console.log(chalk.white('Available commands:'));
|
|
206
|
+
console.log(chalk.gray(' /specweave-ado:sync'));
|
|
207
|
+
console.log(chalk.gray(' /specweave-ado:status\n'));
|
|
208
|
+
console.log(chalk.cyan('š” Tip: Use /specweave:inc "feature" to create an increment'));
|
|
209
|
+
console.log(chalk.gray(' It will automatically sync to Azure DevOps Work Items!\n'));
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Show Azure DevOps setup skipped message
|
|
213
|
+
*
|
|
214
|
+
* @param language - User's language
|
|
215
|
+
*/
|
|
216
|
+
export function showAzureDevOpsSetupSkipped(language) {
|
|
217
|
+
const locale = getLocaleManager(language);
|
|
218
|
+
console.log(chalk.yellow('\nāļø Skipped Azure DevOps setup\n'));
|
|
219
|
+
console.log(chalk.white('You can configure later:'));
|
|
220
|
+
console.log(chalk.gray(' 1. Add AZURE_DEVOPS_PAT, AZURE_DEVOPS_ORG, AZURE_DEVOPS_PROJECT to .env'));
|
|
221
|
+
console.log(chalk.gray(' 2. Install plugin: /plugin install specweave-ado@specweave\n'));
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=ado.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ado.js","sourceRoot":"","sources":["../../../../src/cli/helpers/issue-tracker/ado.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub Integration for Issue Tracker Setup
|
|
3
|
+
*
|
|
4
|
+
* Handles GitHub.com and GitHub Enterprise authentication
|
|
5
|
+
* Supports manual token entry and gh CLI auto-detection
|
|
6
|
+
*
|
|
7
|
+
* @module cli/helpers/issue-tracker/github
|
|
8
|
+
*/
|
|
9
|
+
import type { GitHubCredentials, ExistingCredentials, ValidationResult } from './types.js';
|
|
10
|
+
import type { SupportedLanguage } from '../../../core/i18n/types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Check for existing GitHub credentials
|
|
13
|
+
*
|
|
14
|
+
* Priority: .env > GH_TOKEN > GITHUB_TOKEN > gh CLI config
|
|
15
|
+
*
|
|
16
|
+
* @param projectPath - Path to project root
|
|
17
|
+
* @returns Existing credentials or null
|
|
18
|
+
*/
|
|
19
|
+
export declare function checkExistingGitHubCredentials(projectPath: string): Promise<ExistingCredentials | null>;
|
|
20
|
+
/**
|
|
21
|
+
* Prompt user for GitHub credentials
|
|
22
|
+
*
|
|
23
|
+
* Supports:
|
|
24
|
+
* - Manual token entry
|
|
25
|
+
* - gh CLI auto-detection
|
|
26
|
+
* - GitHub.com vs GitHub Enterprise selection
|
|
27
|
+
*
|
|
28
|
+
* @param language - User's language
|
|
29
|
+
* @returns Credentials or null if skipped
|
|
30
|
+
*/
|
|
31
|
+
export declare function promptGitHubCredentials(language: SupportedLanguage): Promise<GitHubCredentials | null>;
|
|
32
|
+
/**
|
|
33
|
+
* Validate GitHub connection
|
|
34
|
+
*
|
|
35
|
+
* Tests authentication and returns user information
|
|
36
|
+
* Handles rate limiting with retry logic
|
|
37
|
+
*
|
|
38
|
+
* @param credentials - GitHub credentials
|
|
39
|
+
* @param maxRetries - Maximum retry attempts (default: 3)
|
|
40
|
+
* @returns Validation result
|
|
41
|
+
*/
|
|
42
|
+
export declare function validateGitHubConnection(credentials: GitHubCredentials, maxRetries?: number): Promise<ValidationResult>;
|
|
43
|
+
/**
|
|
44
|
+
* Get GitHub environment variables for .env file
|
|
45
|
+
*
|
|
46
|
+
* @param credentials - GitHub credentials
|
|
47
|
+
* @returns Array of key-value pairs for .env
|
|
48
|
+
*/
|
|
49
|
+
export declare function getGitHubEnvVars(credentials: GitHubCredentials): Array<{
|
|
50
|
+
key: string;
|
|
51
|
+
value: string;
|
|
52
|
+
}>;
|
|
53
|
+
/**
|
|
54
|
+
* Show GitHub setup complete message
|
|
55
|
+
*
|
|
56
|
+
* @param language - User's language
|
|
57
|
+
*/
|
|
58
|
+
export declare function showGitHubSetupComplete(language: SupportedLanguage): void;
|
|
59
|
+
/**
|
|
60
|
+
* Show GitHub setup skipped message
|
|
61
|
+
*
|
|
62
|
+
* @param language - User's language
|
|
63
|
+
*/
|
|
64
|
+
export declare function showGitHubSetupSkipped(language: SupportedLanguage): void;
|
|
65
|
+
//# sourceMappingURL=github.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../../../src/cli/helpers/issue-tracker/github.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAUH,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAEjB,MAAM,YAAY,CAAC;AAOpB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAIrE;;;;;;;GAOG;AACH,wBAAsB,8BAA8B,CAClD,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CA6BrC;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAoInC;AAED;;;;;;;;;GASG;AACH,wBAAsB,wBAAwB,CAC5C,WAAW,EAAE,iBAAiB,EAC9B,UAAU,GAAE,MAAU,GACrB,OAAO,CAAC,gBAAgB,CAAC,CA2D3B;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,iBAAiB,GAAG,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAWtG;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAWzE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAOxE"}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub Integration for Issue Tracker Setup
|
|
3
|
+
*
|
|
4
|
+
* Handles GitHub.com and GitHub Enterprise authentication
|
|
5
|
+
* Supports manual token entry and gh CLI auto-detection
|
|
6
|
+
*
|
|
7
|
+
* @module cli/helpers/issue-tracker/github
|
|
8
|
+
*/
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
import inquirer from 'inquirer';
|
|
11
|
+
import ora from 'ora';
|
|
12
|
+
import { getGitHubAuth } from '../../../utils/auth-helpers.js';
|
|
13
|
+
import { parseEnvFile, readEnvFile } from '../../../utils/env-file.js';
|
|
14
|
+
import { isGhCliAvailable, retryWithBackoff, checkRateLimit } from './utils.js';
|
|
15
|
+
import { getLocaleManager } from '../../../core/i18n/locale-manager.js';
|
|
16
|
+
import { RateLimitError } from './types.js';
|
|
17
|
+
/**
|
|
18
|
+
* Check for existing GitHub credentials
|
|
19
|
+
*
|
|
20
|
+
* Priority: .env > GH_TOKEN > GITHUB_TOKEN > gh CLI config
|
|
21
|
+
*
|
|
22
|
+
* @param projectPath - Path to project root
|
|
23
|
+
* @returns Existing credentials or null
|
|
24
|
+
*/
|
|
25
|
+
export async function checkExistingGitHubCredentials(projectPath) {
|
|
26
|
+
// 1. Check project .env file
|
|
27
|
+
const envContent = readEnvFile(projectPath);
|
|
28
|
+
if (envContent) {
|
|
29
|
+
const parsed = parseEnvFile(envContent);
|
|
30
|
+
if (parsed.GH_TOKEN) {
|
|
31
|
+
return {
|
|
32
|
+
source: '.env',
|
|
33
|
+
credentials: {
|
|
34
|
+
token: parsed.GH_TOKEN,
|
|
35
|
+
instanceType: 'cloud' // Assume cloud unless specified
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// 2. Check environment variables and gh CLI
|
|
41
|
+
const auth = getGitHubAuth();
|
|
42
|
+
if (auth.source !== 'none') {
|
|
43
|
+
return {
|
|
44
|
+
source: auth.source,
|
|
45
|
+
credentials: {
|
|
46
|
+
token: auth.token,
|
|
47
|
+
instanceType: 'cloud'
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Prompt user for GitHub credentials
|
|
55
|
+
*
|
|
56
|
+
* Supports:
|
|
57
|
+
* - Manual token entry
|
|
58
|
+
* - gh CLI auto-detection
|
|
59
|
+
* - GitHub.com vs GitHub Enterprise selection
|
|
60
|
+
*
|
|
61
|
+
* @param language - User's language
|
|
62
|
+
* @returns Credentials or null if skipped
|
|
63
|
+
*/
|
|
64
|
+
export async function promptGitHubCredentials(language) {
|
|
65
|
+
const locale = getLocaleManager(language);
|
|
66
|
+
console.log(chalk.white('\nš GitHub Integration Setup\n'));
|
|
67
|
+
console.log(chalk.gray('SpecWeave will sync increments with GitHub Issues.\n'));
|
|
68
|
+
// Step 1: Ask about instance type (Cloud vs Enterprise)
|
|
69
|
+
const { instanceType } = await inquirer.prompt([{
|
|
70
|
+
type: 'list',
|
|
71
|
+
name: 'instanceType',
|
|
72
|
+
message: 'Which GitHub instance are you using?',
|
|
73
|
+
choices: [
|
|
74
|
+
{ name: 'GitHub.com (cloud)', value: 'cloud' },
|
|
75
|
+
{ name: 'GitHub Enterprise (self-hosted)', value: 'enterprise' }
|
|
76
|
+
],
|
|
77
|
+
default: 'cloud'
|
|
78
|
+
}]);
|
|
79
|
+
let apiEndpoint;
|
|
80
|
+
// Step 2: If Enterprise, ask for API endpoint
|
|
81
|
+
if (instanceType === 'enterprise') {
|
|
82
|
+
console.log(chalk.gray('\nGitHub Enterprise requires a custom API endpoint.\n'));
|
|
83
|
+
const { endpoint } = await inquirer.prompt([{
|
|
84
|
+
type: 'input',
|
|
85
|
+
name: 'endpoint',
|
|
86
|
+
message: 'GitHub Enterprise API endpoint:',
|
|
87
|
+
default: 'https://github.company.com/api/v3',
|
|
88
|
+
validate: (input) => {
|
|
89
|
+
if (!input.startsWith('https://')) {
|
|
90
|
+
return 'API endpoint must use HTTPS (http:// is not secure)';
|
|
91
|
+
}
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
}]);
|
|
95
|
+
apiEndpoint = endpoint;
|
|
96
|
+
}
|
|
97
|
+
// Step 3: Show setup instructions
|
|
98
|
+
console.log(chalk.cyan('\nš Quick Setup:'));
|
|
99
|
+
if (instanceType === 'cloud') {
|
|
100
|
+
console.log(chalk.gray(' 1. Go to: https://github.com/settings/tokens/new'));
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
console.log(chalk.gray(` 1. Go to: ${apiEndpoint}/settings/tokens/new`));
|
|
104
|
+
}
|
|
105
|
+
console.log(chalk.gray(' 2. Token name: "SpecWeave - [your-project]"'));
|
|
106
|
+
console.log(chalk.gray(' 3. Scopes needed: ā repo, ā workflow'));
|
|
107
|
+
console.log(chalk.gray(' 4. Click "Generate token"'));
|
|
108
|
+
console.log(chalk.gray(' 5. Copy the token (ghp_...)\n'));
|
|
109
|
+
// Step 4: Check if gh CLI is available (only for GitHub.com)
|
|
110
|
+
const ghCliAvailable = instanceType === 'cloud' && await isGhCliAvailable();
|
|
111
|
+
const choices = [
|
|
112
|
+
{ name: 'Enter token manually', value: 'manual' },
|
|
113
|
+
...(ghCliAvailable ? [{ name: 'Use gh CLI (auto-detect)', value: 'gh-cli' }] : []),
|
|
114
|
+
{ name: 'Skip for now', value: 'skip' }
|
|
115
|
+
];
|
|
116
|
+
const { method } = await inquirer.prompt([{
|
|
117
|
+
type: 'list',
|
|
118
|
+
name: 'method',
|
|
119
|
+
message: 'How would you like to authenticate?',
|
|
120
|
+
choices
|
|
121
|
+
}]);
|
|
122
|
+
if (method === 'skip') {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
// Step 5: Get token based on method
|
|
126
|
+
let token;
|
|
127
|
+
if (method === 'gh-cli') {
|
|
128
|
+
const auth = getGitHubAuth();
|
|
129
|
+
if (auth.source === 'gh-cli') {
|
|
130
|
+
console.log(chalk.green('ā Found gh CLI token'));
|
|
131
|
+
token = auth.token;
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
console.log(chalk.red('ā Could not detect gh CLI token'));
|
|
135
|
+
console.log(chalk.yellow(' Make sure you\'re logged in: gh auth login\n'));
|
|
136
|
+
// Fallback to manual entry
|
|
137
|
+
const { retryMethod } = await inquirer.prompt([{
|
|
138
|
+
type: 'list',
|
|
139
|
+
name: 'retryMethod',
|
|
140
|
+
message: 'What would you like to do?',
|
|
141
|
+
choices: [
|
|
142
|
+
{ name: 'Enter token manually', value: 'manual' },
|
|
143
|
+
{ name: 'Skip for now', value: 'skip' }
|
|
144
|
+
]
|
|
145
|
+
}]);
|
|
146
|
+
if (retryMethod === 'skip') {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
// Fall through to manual entry
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// Manual token entry
|
|
153
|
+
if (method === 'manual' || !token) {
|
|
154
|
+
const { manualToken } = await inquirer.prompt([{
|
|
155
|
+
type: 'password',
|
|
156
|
+
name: 'manualToken',
|
|
157
|
+
message: 'Paste your GitHub token:',
|
|
158
|
+
mask: '*',
|
|
159
|
+
validate: (input) => {
|
|
160
|
+
if (!input || input.length < 20) {
|
|
161
|
+
return 'Invalid token format (should be at least 20 characters)';
|
|
162
|
+
}
|
|
163
|
+
// GitHub tokens start with ghp_ (classic) or github_pat_ (fine-grained)
|
|
164
|
+
if (instanceType === 'cloud') {
|
|
165
|
+
if (!input.startsWith('ghp_') && !input.startsWith('github_pat_')) {
|
|
166
|
+
return 'GitHub tokens typically start with "ghp_" or "github_pat_"';
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
}]);
|
|
172
|
+
token = manualToken;
|
|
173
|
+
}
|
|
174
|
+
return {
|
|
175
|
+
token,
|
|
176
|
+
instanceType: instanceType,
|
|
177
|
+
apiEndpoint
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Validate GitHub connection
|
|
182
|
+
*
|
|
183
|
+
* Tests authentication and returns user information
|
|
184
|
+
* Handles rate limiting with retry logic
|
|
185
|
+
*
|
|
186
|
+
* @param credentials - GitHub credentials
|
|
187
|
+
* @param maxRetries - Maximum retry attempts (default: 3)
|
|
188
|
+
* @returns Validation result
|
|
189
|
+
*/
|
|
190
|
+
export async function validateGitHubConnection(credentials, maxRetries = 3) {
|
|
191
|
+
const spinner = ora('Testing connection...').start();
|
|
192
|
+
try {
|
|
193
|
+
const result = await retryWithBackoff(async () => {
|
|
194
|
+
// Determine API endpoint
|
|
195
|
+
const apiBase = credentials.apiEndpoint || 'https://api.github.com';
|
|
196
|
+
const userEndpoint = `${apiBase}/user`;
|
|
197
|
+
const response = await fetch(userEndpoint, {
|
|
198
|
+
headers: {
|
|
199
|
+
'Authorization': `Bearer ${credentials.token}`,
|
|
200
|
+
'Accept': 'application/vnd.github+json',
|
|
201
|
+
'X-GitHub-Api-Version': '2022-11-28'
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
// Check for rate limiting
|
|
205
|
+
const rateLimitInfo = checkRateLimit(response);
|
|
206
|
+
if (rateLimitInfo) {
|
|
207
|
+
throw new RateLimitError('GitHub API rate limit exceeded', rateLimitInfo);
|
|
208
|
+
}
|
|
209
|
+
if (!response.ok) {
|
|
210
|
+
const errorText = await response.text();
|
|
211
|
+
let errorMessage = 'Authentication failed';
|
|
212
|
+
if (response.status === 401) {
|
|
213
|
+
errorMessage = 'Invalid authentication credentials';
|
|
214
|
+
}
|
|
215
|
+
else if (response.status === 403) {
|
|
216
|
+
errorMessage = 'Access forbidden (check token scopes)';
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
errorMessage = `HTTP ${response.status}: ${errorText}`;
|
|
220
|
+
}
|
|
221
|
+
throw new Error(errorMessage);
|
|
222
|
+
}
|
|
223
|
+
const user = await response.json();
|
|
224
|
+
return user;
|
|
225
|
+
}, maxRetries);
|
|
226
|
+
spinner.succeed(`Connected to GitHub as @${result.login}`);
|
|
227
|
+
return {
|
|
228
|
+
success: true,
|
|
229
|
+
username: result.login
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
spinner.fail('GitHub authentication failed');
|
|
234
|
+
return {
|
|
235
|
+
success: false,
|
|
236
|
+
error: error.message || 'Unknown error'
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Get GitHub environment variables for .env file
|
|
242
|
+
*
|
|
243
|
+
* @param credentials - GitHub credentials
|
|
244
|
+
* @returns Array of key-value pairs for .env
|
|
245
|
+
*/
|
|
246
|
+
export function getGitHubEnvVars(credentials) {
|
|
247
|
+
const vars = [
|
|
248
|
+
{ key: 'GH_TOKEN', value: credentials.token }
|
|
249
|
+
];
|
|
250
|
+
// Add Enterprise-specific variables
|
|
251
|
+
if (credentials.instanceType === 'enterprise' && credentials.apiEndpoint) {
|
|
252
|
+
vars.push({ key: 'GITHUB_API_URL', value: credentials.apiEndpoint });
|
|
253
|
+
}
|
|
254
|
+
return vars;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Show GitHub setup complete message
|
|
258
|
+
*
|
|
259
|
+
* @param language - User's language
|
|
260
|
+
*/
|
|
261
|
+
export function showGitHubSetupComplete(language) {
|
|
262
|
+
const locale = getLocaleManager(language);
|
|
263
|
+
console.log(chalk.green.bold('\nā
GitHub integration complete!\n'));
|
|
264
|
+
console.log(chalk.white('Available commands:'));
|
|
265
|
+
console.log(chalk.gray(' /specweave-github:create-issue'));
|
|
266
|
+
console.log(chalk.gray(' /specweave-github:sync'));
|
|
267
|
+
console.log(chalk.gray(' /specweave-github:close-issue'));
|
|
268
|
+
console.log(chalk.gray(' /specweave-github:status\n'));
|
|
269
|
+
console.log(chalk.cyan('š” Tip: Use /specweave:inc "feature" to create an increment'));
|
|
270
|
+
console.log(chalk.gray(' It will automatically sync to GitHub Issues!\n'));
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Show GitHub setup skipped message
|
|
274
|
+
*
|
|
275
|
+
* @param language - User's language
|
|
276
|
+
*/
|
|
277
|
+
export function showGitHubSetupSkipped(language) {
|
|
278
|
+
const locale = getLocaleManager(language);
|
|
279
|
+
console.log(chalk.yellow('\nāļø Skipped GitHub setup\n'));
|
|
280
|
+
console.log(chalk.white('You can configure later:'));
|
|
281
|
+
console.log(chalk.gray(' 1. Add GH_TOKEN to .env file'));
|
|
282
|
+
console.log(chalk.gray(' 2. Install plugin: /plugin install specweave-github@specweave\n'));
|
|
283
|
+
}
|
|
284
|
+
//# sourceMappingURL=github.js.map
|