@braingrid/cli 0.1.0 → 0.1.2
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/CHANGELOG.md +36 -0
- package/README.md +26 -24
- package/dist/cli.js +37 -17
- package/dist/cli.js.map +1 -1
- package/dist/handlers/agent.handlers.d.ts +12 -0
- package/dist/handlers/agent.handlers.d.ts.map +1 -0
- package/dist/handlers/agent.handlers.js +130 -0
- package/dist/handlers/agent.handlers.js.map +1 -0
- package/dist/handlers/index.d.ts +1 -0
- package/dist/handlers/index.d.ts.map +1 -1
- package/dist/handlers/index.js +1 -0
- package/dist/handlers/index.js.map +1 -1
- package/dist/handlers/init.handlers.d.ts +0 -1
- package/dist/handlers/init.handlers.d.ts.map +1 -1
- package/dist/handlers/init.handlers.js +481 -43
- package/dist/handlers/init.handlers.js.map +1 -1
- package/dist/handlers/project.handlers.d.ts +2 -3
- package/dist/handlers/project.handlers.d.ts.map +1 -1
- package/dist/handlers/project.handlers.js +80 -71
- package/dist/handlers/project.handlers.js.map +1 -1
- package/dist/handlers/requirement.handlers.d.ts.map +1 -1
- package/dist/handlers/requirement.handlers.js +21 -20
- package/dist/handlers/requirement.handlers.js.map +1 -1
- package/dist/handlers/status.handlers.d.ts.map +1 -1
- package/dist/handlers/status.handlers.js +11 -8
- package/dist/handlers/status.handlers.js.map +1 -1
- package/dist/handlers/task.handlers.d.ts.map +1 -1
- package/dist/handlers/task.handlers.js +45 -26
- package/dist/handlers/task.handlers.js.map +1 -1
- package/dist/rpc/server.d.ts +2 -0
- package/dist/rpc/server.d.ts.map +1 -1
- package/dist/rpc/server.js +28 -11
- package/dist/rpc/server.js.map +1 -1
- package/dist/services/agent-service.d.ts +29 -0
- package/dist/services/agent-service.d.ts.map +1 -0
- package/dist/services/agent-service.js +273 -0
- package/dist/services/agent-service.js.map +1 -0
- package/dist/services/credential-store.d.ts.map +1 -1
- package/dist/services/credential-store.js +1 -0
- package/dist/services/credential-store.js.map +1 -1
- package/dist/services/internal/github-service.d.ts +67 -0
- package/dist/services/internal/github-service.d.ts.map +1 -0
- package/dist/services/internal/github-service.js +81 -0
- package/dist/services/internal/github-service.js.map +1 -0
- package/dist/services/internal/repository-service.d.ts +79 -0
- package/dist/services/internal/repository-service.d.ts.map +1 -0
- package/dist/services/internal/repository-service.js +88 -0
- package/dist/services/internal/repository-service.js.map +1 -0
- package/dist/types/github.d.ts +105 -0
- package/dist/types/github.d.ts.map +1 -0
- package/dist/types/github.js +6 -0
- package/dist/types/github.js.map +1 -0
- package/dist/types/project.d.ts +1 -0
- package/dist/types/project.d.ts.map +1 -1
- package/dist/utils/cli-tools.d.ts.map +1 -1
- package/dist/utils/cli-tools.js +9 -1
- package/dist/utils/cli-tools.js.map +1 -1
- package/dist/utils/config.d.ts +1 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +18 -0
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/gh-installer.d.ts +31 -0
- package/dist/utils/gh-installer.d.ts.map +1 -0
- package/dist/utils/gh-installer.js +296 -0
- package/dist/utils/gh-installer.js.map +1 -0
- package/dist/utils/git-installer.d.ts +31 -0
- package/dist/utils/git-installer.d.ts.map +1 -0
- package/dist/utils/git-installer.js +290 -0
- package/dist/utils/git-installer.js.map +1 -0
- package/dist/utils/git.d.ts +5 -0
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +13 -0
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/github-repo.d.ts +43 -0
- package/dist/utils/github-repo.d.ts.map +1 -0
- package/dist/utils/github-repo.js +113 -0
- package/dist/utils/github-repo.js.map +1 -0
- package/dist/utils/id-normalization.d.ts +26 -0
- package/dist/utils/id-normalization.d.ts.map +1 -0
- package/dist/utils/id-normalization.js +45 -0
- package/dist/utils/id-normalization.js.map +1 -0
- package/dist/utils/local-store.d.ts +7 -7
- package/dist/utils/local-store.d.ts.map +1 -1
- package/dist/utils/local-store.js +29 -17
- package/dist/utils/local-store.js.map +1 -1
- package/dist/utils/package-manager-installer.d.ts +36 -0
- package/dist/utils/package-manager-installer.d.ts.map +1 -0
- package/dist/utils/package-manager-installer.js +106 -0
- package/dist/utils/package-manager-installer.js.map +1 -0
- package/dist/utils/projects.d.ts +23 -0
- package/dist/utils/projects.d.ts.map +1 -0
- package/dist/utils/projects.js +36 -0
- package/dist/utils/projects.js.map +1 -0
- package/dist/utils/repository-access.d.ts +89 -0
- package/dist/utils/repository-access.d.ts.map +1 -0
- package/dist/utils/repository-access.js +132 -0
- package/dist/utils/repository-access.js.map +1 -0
- package/dist/utils/requirements.d.ts +15 -0
- package/dist/utils/requirements.d.ts.map +1 -1
- package/dist/utils/requirements.js +32 -7
- package/dist/utils/requirements.js.map +1 -1
- package/dist/utils/spinner.d.ts +47 -0
- package/dist/utils/spinner.d.ts.map +1 -0
- package/dist/utils/spinner.js +101 -0
- package/dist/utils/spinner.js.map +1 -0
- package/dist/utils/tasks.d.ts +12 -0
- package/dist/utils/tasks.d.ts.map +1 -1
- package/dist/utils/tasks.js +31 -6
- package/dist/utils/tasks.js.map +1 -1
- package/dist/utils/workspace-manager.d.ts +65 -0
- package/dist/utils/workspace-manager.d.ts.map +1 -0
- package/dist/utils/workspace-manager.js +98 -0
- package/dist/utils/workspace-manager.js.map +1 -0
- package/package.json +4 -1
- package/dist/services/context-manager.d.ts +0 -170
- package/dist/services/context-manager.d.ts.map +0 -1
- package/dist/services/context-manager.js +0 -261
- package/dist/services/context-manager.js.map +0 -1
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Project } from '../types/project.js';
|
|
2
|
+
/**
|
|
3
|
+
* Format a project with friendly PROJ-<number> format
|
|
4
|
+
* Note: short_id already contains "PROJ-123" format
|
|
5
|
+
*/
|
|
6
|
+
export declare function formatProjectId(project: Project): string;
|
|
7
|
+
/**
|
|
8
|
+
* Normalize project ID from various formats to API-compatible format:
|
|
9
|
+
* - "PROJ-123" -> "PROJ-123" (already normalized)
|
|
10
|
+
* - "proj-123" -> "PROJ-123" (uppercase)
|
|
11
|
+
* - "PROJ 123" -> "PROJ-123" (add dash, uppercase)
|
|
12
|
+
* - "proj 123" -> "PROJ-123" (add dash, uppercase)
|
|
13
|
+
* - "123" -> "PROJ-123" (add prefix)
|
|
14
|
+
* - "uuid-string" -> "uuid-string" (UUID, return as-is)
|
|
15
|
+
*
|
|
16
|
+
* This function takes user input and returns the ID that should be used in API calls
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseProjectId(input: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Find a project by either short_id or UUID
|
|
21
|
+
*/
|
|
22
|
+
export declare function findProjectById(projects: Project[], identifier: string): Project | undefined;
|
|
23
|
+
//# sourceMappingURL=projects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/utils/projects.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAG9C;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAExD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAW5F"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { normalizeId } from './id-normalization.js';
|
|
2
|
+
/**
|
|
3
|
+
* Format a project with friendly PROJ-<number> format
|
|
4
|
+
* Note: short_id already contains "PROJ-123" format
|
|
5
|
+
*/
|
|
6
|
+
export function formatProjectId(project) {
|
|
7
|
+
return project.short_id;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Normalize project ID from various formats to API-compatible format:
|
|
11
|
+
* - "PROJ-123" -> "PROJ-123" (already normalized)
|
|
12
|
+
* - "proj-123" -> "PROJ-123" (uppercase)
|
|
13
|
+
* - "PROJ 123" -> "PROJ-123" (add dash, uppercase)
|
|
14
|
+
* - "proj 123" -> "PROJ-123" (add dash, uppercase)
|
|
15
|
+
* - "123" -> "PROJ-123" (add prefix)
|
|
16
|
+
* - "uuid-string" -> "uuid-string" (UUID, return as-is)
|
|
17
|
+
*
|
|
18
|
+
* This function takes user input and returns the ID that should be used in API calls
|
|
19
|
+
*/
|
|
20
|
+
export function parseProjectId(input) {
|
|
21
|
+
return normalizeId('PROJ', input);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Find a project by either short_id or UUID
|
|
25
|
+
*/
|
|
26
|
+
export function findProjectById(projects, identifier) {
|
|
27
|
+
const normalized = parseProjectId(identifier);
|
|
28
|
+
// Try to find by short_id first (handles PROJ-X format)
|
|
29
|
+
const byShortId = projects.find(proj => proj.short_id === normalized);
|
|
30
|
+
if (byShortId) {
|
|
31
|
+
return byShortId;
|
|
32
|
+
}
|
|
33
|
+
// Try to find by UUID
|
|
34
|
+
return projects.find(proj => proj.id === normalized);
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=projects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/utils/projects.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,OAAgB;IAC/C,OAAO,OAAO,CAAC,QAAQ,CAAC;AACzB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,KAAa;IAC3C,OAAO,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AACnC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,QAAmB,EAAE,UAAkB;IACtE,MAAM,UAAU,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;IAE9C,wDAAwD;IACxD,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC;IACtE,IAAI,SAAS,EAAE,CAAC;QACf,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,sBAAsB;IACtB,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,UAAU,CAAC,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repository Access Utility
|
|
3
|
+
*
|
|
4
|
+
* Helpers for checking GitHub installation and repository access during project initialization.
|
|
5
|
+
* Handles detection of owner-specific installations and repository visibility in BrainGrid.
|
|
6
|
+
*/
|
|
7
|
+
import { GitHubInstallation } from '../types/github.js';
|
|
8
|
+
import { RepositoryService } from '../services/internal/repository-service.js';
|
|
9
|
+
/**
|
|
10
|
+
* Find a GitHub installation for a specific repository owner
|
|
11
|
+
*
|
|
12
|
+
* @param owner - The GitHub repository owner (org or user)
|
|
13
|
+
* @param installations - List of GitHub installations to search
|
|
14
|
+
* @returns The matching installation or null if not found
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const installation = findInstallationForOwner('myorg', installations);
|
|
19
|
+
* if (installation) {
|
|
20
|
+
* console.log(`Found installation for ${installation.account_name}`);
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare function findInstallationForOwner(owner: string, installations: GitHubInstallation[]): GitHubInstallation | null;
|
|
25
|
+
/**
|
|
26
|
+
* Check if a repository is accessible in BrainGrid
|
|
27
|
+
*
|
|
28
|
+
* Queries the repository API to see if the specific owner/name combination
|
|
29
|
+
* is visible to the authenticated user's organization.
|
|
30
|
+
*
|
|
31
|
+
* @param repositoryService - Repository service instance
|
|
32
|
+
* @param owner - GitHub repository owner
|
|
33
|
+
* @param name - GitHub repository name
|
|
34
|
+
* @returns True if repository is accessible, false otherwise
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* const hasAccess = await checkRepositoryAccess(repoService, 'myorg', 'myrepo');
|
|
39
|
+
* if (hasAccess) {
|
|
40
|
+
* console.log('Repository is accessible in BrainGrid');
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare function checkRepositoryAccess(repositoryService: RepositoryService, owner: string, name: string): Promise<boolean>;
|
|
45
|
+
/**
|
|
46
|
+
* Poll for repository access with timeout
|
|
47
|
+
*
|
|
48
|
+
* Continuously checks if a repository becomes accessible in BrainGrid.
|
|
49
|
+
* Useful when waiting for a user to grant access through the web UI.
|
|
50
|
+
*
|
|
51
|
+
* @param repositoryService - Repository service instance
|
|
52
|
+
* @param owner - GitHub repository owner
|
|
53
|
+
* @param name - GitHub repository name
|
|
54
|
+
* @param intervalMs - Polling interval in milliseconds (default: 3000)
|
|
55
|
+
* @param maxAttempts - Maximum number of polling attempts (default: 60 = 3 minutes at 3s interval)
|
|
56
|
+
* @returns Promise that resolves to true if access is granted, false if timeout
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* const granted = await pollForRepositoryAccess(repoService, 'myorg', 'myrepo');
|
|
61
|
+
* if (granted) {
|
|
62
|
+
* console.log('Access granted!');
|
|
63
|
+
* } else {
|
|
64
|
+
* console.log('Timeout - access not granted within 3 minutes');
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export declare function pollForRepositoryAccess(repositoryService: RepositoryService, owner: string, name: string, intervalMs?: number, maxAttempts?: number): Promise<boolean>;
|
|
69
|
+
/**
|
|
70
|
+
* Get repository ID from BrainGrid API
|
|
71
|
+
*
|
|
72
|
+
* Fetches the repository details to get its BrainGrid UUID, which is needed
|
|
73
|
+
* for linking repositories to projects.
|
|
74
|
+
*
|
|
75
|
+
* @param repositoryService - Repository service instance
|
|
76
|
+
* @param owner - GitHub repository owner
|
|
77
|
+
* @param name - GitHub repository name
|
|
78
|
+
* @returns Repository UUID or null if not found
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* const repoId = await getRepositoryId(repoService, 'myorg', 'myrepo');
|
|
83
|
+
* if (repoId) {
|
|
84
|
+
* await projectService.createProject({ name: 'My Project', repository_ids: [repoId] });
|
|
85
|
+
* }
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export declare function getRepositoryId(repositoryService: RepositoryService, owner: string, name: string): Promise<string | null>;
|
|
89
|
+
//# sourceMappingURL=repository-access.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-access.d.ts","sourceRoot":"","sources":["../../src/utils/repository-access.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AAE/E;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CACvC,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,kBAAkB,EAAE,GACjC,kBAAkB,GAAG,IAAI,CAK3B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,qBAAqB,CAC1C,iBAAiB,EAAE,iBAAiB,EACpC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACV,OAAO,CAAC,OAAO,CAAC,CAclB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,uBAAuB,CAC5C,iBAAiB,EAAE,iBAAiB,EACpC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,UAAU,GAAE,MAAa,EACzB,WAAW,GAAE,MAAW,GACtB,OAAO,CAAC,OAAO,CAAC,CAelB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,eAAe,CACpC,iBAAiB,EAAE,iBAAiB,EACpC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAgBxB"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repository Access Utility
|
|
3
|
+
*
|
|
4
|
+
* Helpers for checking GitHub installation and repository access during project initialization.
|
|
5
|
+
* Handles detection of owner-specific installations and repository visibility in BrainGrid.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Find a GitHub installation for a specific repository owner
|
|
9
|
+
*
|
|
10
|
+
* @param owner - The GitHub repository owner (org or user)
|
|
11
|
+
* @param installations - List of GitHub installations to search
|
|
12
|
+
* @returns The matching installation or null if not found
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const installation = findInstallationForOwner('myorg', installations);
|
|
17
|
+
* if (installation) {
|
|
18
|
+
* console.log(`Found installation for ${installation.account_name}`);
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function findInstallationForOwner(owner, installations) {
|
|
23
|
+
// Case-insensitive match on account_name
|
|
24
|
+
const normalizedOwner = owner.toLowerCase();
|
|
25
|
+
return installations.find(inst => inst.account_name.toLowerCase() === normalizedOwner) || null;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Check if a repository is accessible in BrainGrid
|
|
29
|
+
*
|
|
30
|
+
* Queries the repository API to see if the specific owner/name combination
|
|
31
|
+
* is visible to the authenticated user's organization.
|
|
32
|
+
*
|
|
33
|
+
* @param repositoryService - Repository service instance
|
|
34
|
+
* @param owner - GitHub repository owner
|
|
35
|
+
* @param name - GitHub repository name
|
|
36
|
+
* @returns True if repository is accessible, false otherwise
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* const hasAccess = await checkRepositoryAccess(repoService, 'myorg', 'myrepo');
|
|
41
|
+
* if (hasAccess) {
|
|
42
|
+
* console.log('Repository is accessible in BrainGrid');
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export async function checkRepositoryAccess(repositoryService, owner, name) {
|
|
47
|
+
try {
|
|
48
|
+
const response = await repositoryService.listRepositories({
|
|
49
|
+
owner,
|
|
50
|
+
name,
|
|
51
|
+
limit: 1,
|
|
52
|
+
});
|
|
53
|
+
// If we get results, the repository is accessible
|
|
54
|
+
return response.repositories.length > 0;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// If the API call fails, assume no access
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Poll for repository access with timeout
|
|
63
|
+
*
|
|
64
|
+
* Continuously checks if a repository becomes accessible in BrainGrid.
|
|
65
|
+
* Useful when waiting for a user to grant access through the web UI.
|
|
66
|
+
*
|
|
67
|
+
* @param repositoryService - Repository service instance
|
|
68
|
+
* @param owner - GitHub repository owner
|
|
69
|
+
* @param name - GitHub repository name
|
|
70
|
+
* @param intervalMs - Polling interval in milliseconds (default: 3000)
|
|
71
|
+
* @param maxAttempts - Maximum number of polling attempts (default: 60 = 3 minutes at 3s interval)
|
|
72
|
+
* @returns Promise that resolves to true if access is granted, false if timeout
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const granted = await pollForRepositoryAccess(repoService, 'myorg', 'myrepo');
|
|
77
|
+
* if (granted) {
|
|
78
|
+
* console.log('Access granted!');
|
|
79
|
+
* } else {
|
|
80
|
+
* console.log('Timeout - access not granted within 3 minutes');
|
|
81
|
+
* }
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export async function pollForRepositoryAccess(repositoryService, owner, name, intervalMs = 3000, maxAttempts = 60) {
|
|
85
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
86
|
+
const hasAccess = await checkRepositoryAccess(repositoryService, owner, name);
|
|
87
|
+
if (hasAccess) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
// Wait before next attempt (unless this was the last attempt)
|
|
91
|
+
if (attempt < maxAttempts - 1) {
|
|
92
|
+
await new Promise(resolve => setTimeout(resolve, intervalMs));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get repository ID from BrainGrid API
|
|
99
|
+
*
|
|
100
|
+
* Fetches the repository details to get its BrainGrid UUID, which is needed
|
|
101
|
+
* for linking repositories to projects.
|
|
102
|
+
*
|
|
103
|
+
* @param repositoryService - Repository service instance
|
|
104
|
+
* @param owner - GitHub repository owner
|
|
105
|
+
* @param name - GitHub repository name
|
|
106
|
+
* @returns Repository UUID or null if not found
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* const repoId = await getRepositoryId(repoService, 'myorg', 'myrepo');
|
|
111
|
+
* if (repoId) {
|
|
112
|
+
* await projectService.createProject({ name: 'My Project', repository_ids: [repoId] });
|
|
113
|
+
* }
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export async function getRepositoryId(repositoryService, owner, name) {
|
|
117
|
+
try {
|
|
118
|
+
const response = await repositoryService.listRepositories({
|
|
119
|
+
owner,
|
|
120
|
+
name,
|
|
121
|
+
limit: 1,
|
|
122
|
+
});
|
|
123
|
+
if (response.repositories.length === 0) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
return response.repositories[0].id;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=repository-access.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-access.js","sourceRoot":"","sources":["../../src/utils/repository-access.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,wBAAwB,CACvC,KAAa,EACb,aAAmC;IAEnC,yCAAyC;IACzC,MAAM,eAAe,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAE5C,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,KAAK,eAAe,CAAC,IAAI,IAAI,CAAC;AAChG,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAC1C,iBAAoC,EACpC,KAAa,EACb,IAAY;IAEZ,IAAI,CAAC;QACJ,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,gBAAgB,CAAC;YACzD,KAAK;YACL,IAAI;YACJ,KAAK,EAAE,CAAC;SACR,CAAC,CAAC;QAEH,kDAAkD;QAClD,OAAO,QAAQ,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACR,0CAA0C;QAC1C,OAAO,KAAK,CAAC;IACd,CAAC;AACF,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC5C,iBAAoC,EACpC,KAAa,EACb,IAAY,EACZ,aAAqB,IAAI,EACzB,cAAsB,EAAE;IAExB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;QACxD,MAAM,SAAS,GAAG,MAAM,qBAAqB,CAAC,iBAAiB,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QAE9E,IAAI,SAAS,EAAE,CAAC;YACf,OAAO,IAAI,CAAC;QACb,CAAC;QAED,8DAA8D;QAC9D,IAAI,OAAO,GAAG,WAAW,GAAG,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;QAC/D,CAAC;IACF,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACpC,iBAAoC,EACpC,KAAa,EACb,IAAY;IAEZ,IAAI,CAAC;QACJ,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,gBAAgB,CAAC;YACzD,KAAK;YACL,IAAI;YACJ,KAAK,EAAE,CAAC;SACR,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxC,OAAO,IAAI,CAAC;QACb,CAAC;QAED,OAAO,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;AACF,CAAC"}
|
|
@@ -4,9 +4,24 @@ import { Requirement } from '../types/requirement.js';
|
|
|
4
4
|
* Note: short_id already contains "REQ-123" format
|
|
5
5
|
*/
|
|
6
6
|
export declare function formatRequirementId(requirement: Requirement): string;
|
|
7
|
+
/**
|
|
8
|
+
* Normalize requirement ID from various formats to API-compatible format:
|
|
9
|
+
* - "REQ-123" -> "REQ-123" (already normalized)
|
|
10
|
+
* - "req-123" -> "REQ-123" (uppercase)
|
|
11
|
+
* - "REQ 123" -> "REQ-123" (add dash, uppercase)
|
|
12
|
+
* - "req 123" -> "REQ-123" (add dash, uppercase)
|
|
13
|
+
* - "123" -> "REQ-123" (add prefix)
|
|
14
|
+
* - "uuid-string" -> "uuid-string" (UUID, return as-is)
|
|
15
|
+
*
|
|
16
|
+
* This function takes user input and returns the ID that should be used in API calls
|
|
17
|
+
*/
|
|
18
|
+
export declare function normalizeRequirementId(input: string): string;
|
|
7
19
|
/**
|
|
8
20
|
* Parse a requirement ID from various formats:
|
|
9
21
|
* - "REQ-123" -> { type: 'req_id', value: 123 }
|
|
22
|
+
* - "req-123" -> { type: 'req_id', value: 123 }
|
|
23
|
+
* - "REQ 123" -> { type: 'req_id', value: 123 }
|
|
24
|
+
* - "req 123" -> { type: 'req_id', value: 123 }
|
|
10
25
|
* - "123" -> { type: 'req_id', value: 123 }
|
|
11
26
|
* - "uuid-string" -> { type: 'uuid', value: 'uuid-string' }
|
|
12
27
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requirements.d.ts","sourceRoot":"","sources":["../../src/utils/requirements.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"requirements.d.ts","sourceRoot":"","sources":["../../src/utils/requirements.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAGtD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAEpE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG;IAClD,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;CACvB,CAwBA;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAClC,YAAY,EAAE,WAAW,EAAE,EAC3B,UAAU,EAAE,MAAM,GAChB,WAAW,GAAG,SAAS,CAQzB;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAS7E"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizeId } from './id-normalization.js';
|
|
1
2
|
/**
|
|
2
3
|
* Format a requirement with friendly REQ-<number> format
|
|
3
4
|
* Note: short_id already contains "REQ-123" format
|
|
@@ -5,25 +6,49 @@
|
|
|
5
6
|
export function formatRequirementId(requirement) {
|
|
6
7
|
return requirement.short_id || `REQ-${requirement.req_id || 0}`;
|
|
7
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* Normalize requirement ID from various formats to API-compatible format:
|
|
11
|
+
* - "REQ-123" -> "REQ-123" (already normalized)
|
|
12
|
+
* - "req-123" -> "REQ-123" (uppercase)
|
|
13
|
+
* - "REQ 123" -> "REQ-123" (add dash, uppercase)
|
|
14
|
+
* - "req 123" -> "REQ-123" (add dash, uppercase)
|
|
15
|
+
* - "123" -> "REQ-123" (add prefix)
|
|
16
|
+
* - "uuid-string" -> "uuid-string" (UUID, return as-is)
|
|
17
|
+
*
|
|
18
|
+
* This function takes user input and returns the ID that should be used in API calls
|
|
19
|
+
*/
|
|
20
|
+
export function normalizeRequirementId(input) {
|
|
21
|
+
return normalizeId('REQ', input);
|
|
22
|
+
}
|
|
8
23
|
/**
|
|
9
24
|
* Parse a requirement ID from various formats:
|
|
10
25
|
* - "REQ-123" -> { type: 'req_id', value: 123 }
|
|
26
|
+
* - "req-123" -> { type: 'req_id', value: 123 }
|
|
27
|
+
* - "REQ 123" -> { type: 'req_id', value: 123 }
|
|
28
|
+
* - "req 123" -> { type: 'req_id', value: 123 }
|
|
11
29
|
* - "123" -> { type: 'req_id', value: 123 }
|
|
12
30
|
* - "uuid-string" -> { type: 'uuid', value: 'uuid-string' }
|
|
13
31
|
*/
|
|
14
32
|
export function parseRequirementId(input) {
|
|
15
|
-
//
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
33
|
+
// Trim whitespace
|
|
34
|
+
const trimmed = input.trim();
|
|
35
|
+
// Handle "REQ-123" or "req-123" format (with dash)
|
|
36
|
+
const reqDashMatch = trimmed.match(/^REQ-(\d+)$/i);
|
|
37
|
+
if (reqDashMatch) {
|
|
38
|
+
return { type: 'req_id', value: parseInt(reqDashMatch[1], 10) };
|
|
39
|
+
}
|
|
40
|
+
// Handle "REQ 123" or "req 123" format (with space)
|
|
41
|
+
const reqSpaceMatch = trimmed.match(/^REQ\s+(\d+)$/i);
|
|
42
|
+
if (reqSpaceMatch) {
|
|
43
|
+
return { type: 'req_id', value: parseInt(reqSpaceMatch[1], 10) };
|
|
19
44
|
}
|
|
20
45
|
// Handle plain number format
|
|
21
|
-
const numberMatch =
|
|
46
|
+
const numberMatch = trimmed.match(/^\d+$/);
|
|
22
47
|
if (numberMatch) {
|
|
23
|
-
return { type: 'req_id', value: parseInt(
|
|
48
|
+
return { type: 'req_id', value: parseInt(trimmed, 10) };
|
|
24
49
|
}
|
|
25
50
|
// Assume it's a UUID
|
|
26
|
-
return { type: 'uuid', value:
|
|
51
|
+
return { type: 'uuid', value: trimmed };
|
|
27
52
|
}
|
|
28
53
|
/**
|
|
29
54
|
* Find a requirement by either req_id or UUID
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requirements.js","sourceRoot":"","sources":["../../src/utils/requirements.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"requirements.js","sourceRoot":"","sources":["../../src/utils/requirements.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,WAAwB;IAC3D,OAAO,WAAW,CAAC,QAAQ,IAAI,OAAO,WAAW,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;AACjE,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAa;IACnD,OAAO,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAClC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAa;IAI/C,kBAAkB;IAClB,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAE7B,mDAAmD;IACnD,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IACnD,IAAI,YAAY,EAAE,CAAC;QAClB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;IACjE,CAAC;IAED,oDAAoD;IACpD,MAAM,aAAa,GAAG,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACtD,IAAI,aAAa,EAAE,CAAC;QACnB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;IAClE,CAAC;IAED,6BAA6B;IAC7B,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3C,IAAI,WAAW,EAAE,CAAC;QACjB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC;IACzD,CAAC;IAED,qBAAqB;IACrB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AACzC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAClC,YAA2B,EAC3B,UAAkB;IAElB,MAAM,MAAM,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAE9C,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,KAAK,OAAO,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IACzE,CAAC;SAAM,CAAC;QACP,OAAO,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,MAAM,CAAC,KAAK,CAAC,CAAC;IAC1D,CAAC;AACF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,UAAkB;IAC3D,MAAM,MAAM,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAE9C,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC5B,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,KAAe,EAAE,CAAC;IACvC,CAAC;SAAM,CAAC;QACP,+CAA+C;QAC/C,OAAO,EAAE,CAAC;IACX,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spinner Utility
|
|
3
|
+
*
|
|
4
|
+
* Provides a simple polling spinner for async operations with user feedback.
|
|
5
|
+
* Shows an animated spinner while waiting for a condition to become true.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Wait for a condition with animated spinner
|
|
9
|
+
*
|
|
10
|
+
* Polls an async check function and displays a spinner while waiting.
|
|
11
|
+
* Clears the spinner on completion or timeout.
|
|
12
|
+
*
|
|
13
|
+
* @param message - Message to display next to spinner
|
|
14
|
+
* @param checkFn - Async function that returns true when condition is met
|
|
15
|
+
* @param intervalMs - Polling interval in milliseconds (default: 3000)
|
|
16
|
+
* @param maxAttempts - Maximum number of attempts (default: 60 = 3 minutes at 3s interval)
|
|
17
|
+
* @returns Promise that resolves to true if condition met, false if timeout
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* const success = await waitWithSpinner(
|
|
22
|
+
* 'Waiting for repository access',
|
|
23
|
+
* async () => await checkAccess(),
|
|
24
|
+
* 3000,
|
|
25
|
+
* 60
|
|
26
|
+
* );
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function waitWithSpinner(message: string, checkFn: () => Promise<boolean>, intervalMs?: number, maxAttempts?: number): Promise<boolean>;
|
|
30
|
+
/**
|
|
31
|
+
* Simple one-time spinner display
|
|
32
|
+
*
|
|
33
|
+
* Shows a spinner without polling. Useful for operations that manage their own timing.
|
|
34
|
+
* Returns a cleanup function to clear the spinner.
|
|
35
|
+
*
|
|
36
|
+
* @param message - Message to display
|
|
37
|
+
* @returns Cleanup function to stop and clear the spinner
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const stop = showSpinner('Loading');
|
|
42
|
+
* await doWork();
|
|
43
|
+
* stop();
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function showSpinner(message: string): () => void;
|
|
47
|
+
//# sourceMappingURL=spinner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spinner.d.ts","sourceRoot":"","sources":["../../src/utils/spinner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,eAAe,CACpC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAC/B,UAAU,GAAE,MAAa,EACzB,WAAW,GAAE,MAAW,GACtB,OAAO,CAAC,OAAO,CAAC,CA4ClB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,IAAI,CAYvD"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spinner Utility
|
|
3
|
+
*
|
|
4
|
+
* Provides a simple polling spinner for async operations with user feedback.
|
|
5
|
+
* Shows an animated spinner while waiting for a condition to become true.
|
|
6
|
+
*/
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
9
|
+
/**
|
|
10
|
+
* Wait for a condition with animated spinner
|
|
11
|
+
*
|
|
12
|
+
* Polls an async check function and displays a spinner while waiting.
|
|
13
|
+
* Clears the spinner on completion or timeout.
|
|
14
|
+
*
|
|
15
|
+
* @param message - Message to display next to spinner
|
|
16
|
+
* @param checkFn - Async function that returns true when condition is met
|
|
17
|
+
* @param intervalMs - Polling interval in milliseconds (default: 3000)
|
|
18
|
+
* @param maxAttempts - Maximum number of attempts (default: 60 = 3 minutes at 3s interval)
|
|
19
|
+
* @returns Promise that resolves to true if condition met, false if timeout
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const success = await waitWithSpinner(
|
|
24
|
+
* 'Waiting for repository access',
|
|
25
|
+
* async () => await checkAccess(),
|
|
26
|
+
* 3000,
|
|
27
|
+
* 60
|
|
28
|
+
* );
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export async function waitWithSpinner(message, checkFn, intervalMs = 3000, maxAttempts = 60) {
|
|
32
|
+
let frameIndex = 0;
|
|
33
|
+
let spinnerInterval = null;
|
|
34
|
+
// Function to update spinner
|
|
35
|
+
const updateSpinner = () => {
|
|
36
|
+
const frame = SPINNER_FRAMES[frameIndex];
|
|
37
|
+
frameIndex = (frameIndex + 1) % SPINNER_FRAMES.length;
|
|
38
|
+
// Clear current line and write new spinner
|
|
39
|
+
process.stdout.write(`\r${chalk.cyan(frame)} ${message}...`);
|
|
40
|
+
};
|
|
41
|
+
// Start spinner animation (update every 100ms for smooth animation)
|
|
42
|
+
spinnerInterval = setInterval(updateSpinner, 100);
|
|
43
|
+
try {
|
|
44
|
+
// Poll with the specified interval
|
|
45
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
46
|
+
const result = await checkFn();
|
|
47
|
+
if (result) {
|
|
48
|
+
// Success! Clear spinner and return
|
|
49
|
+
if (spinnerInterval)
|
|
50
|
+
clearInterval(spinnerInterval);
|
|
51
|
+
process.stdout.write('\r' + ' '.repeat(message.length + 10) + '\r'); // Clear line
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
// Wait before next attempt (unless this was the last attempt)
|
|
55
|
+
if (attempt < maxAttempts - 1) {
|
|
56
|
+
await new Promise(resolve => setTimeout(resolve, intervalMs));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Timeout - clear spinner and return false
|
|
60
|
+
if (spinnerInterval)
|
|
61
|
+
clearInterval(spinnerInterval);
|
|
62
|
+
process.stdout.write('\r' + ' '.repeat(message.length + 10) + '\r'); // Clear line
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
// Error during polling - clean up and rethrow
|
|
67
|
+
if (spinnerInterval)
|
|
68
|
+
clearInterval(spinnerInterval);
|
|
69
|
+
process.stdout.write('\r' + ' '.repeat(message.length + 10) + '\r'); // Clear line
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Simple one-time spinner display
|
|
75
|
+
*
|
|
76
|
+
* Shows a spinner without polling. Useful for operations that manage their own timing.
|
|
77
|
+
* Returns a cleanup function to clear the spinner.
|
|
78
|
+
*
|
|
79
|
+
* @param message - Message to display
|
|
80
|
+
* @returns Cleanup function to stop and clear the spinner
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* const stop = showSpinner('Loading');
|
|
85
|
+
* await doWork();
|
|
86
|
+
* stop();
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export function showSpinner(message) {
|
|
90
|
+
let frameIndex = 0;
|
|
91
|
+
const interval = setInterval(() => {
|
|
92
|
+
const frame = SPINNER_FRAMES[frameIndex];
|
|
93
|
+
frameIndex = (frameIndex + 1) % SPINNER_FRAMES.length;
|
|
94
|
+
process.stdout.write(`\r${chalk.cyan(frame)} ${message}...`);
|
|
95
|
+
}, 100);
|
|
96
|
+
return () => {
|
|
97
|
+
clearInterval(interval);
|
|
98
|
+
process.stdout.write('\r' + ' '.repeat(message.length + 10) + '\r');
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=spinner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spinner.js","sourceRoot":"","sources":["../../src/utils/spinner.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/tasks.d.ts
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import { RequirementTask as Task } from '../types/requirement.js';
|
|
2
2
|
export declare function formatTaskId(task: Task): string;
|
|
3
|
+
/**
|
|
4
|
+
* Normalize task ID from various formats to API-compatible format:
|
|
5
|
+
* - "TASK-123" -> "TASK-123" (already normalized)
|
|
6
|
+
* - "task-123" -> "TASK-123" (uppercase)
|
|
7
|
+
* - "TASK 123" -> "TASK-123" (add dash, uppercase)
|
|
8
|
+
* - "task 123" -> "TASK-123" (add dash, uppercase)
|
|
9
|
+
* - "123" -> "TASK-123" (add prefix)
|
|
10
|
+
* - "uuid-string" -> "uuid-string" (UUID, return as-is)
|
|
11
|
+
*
|
|
12
|
+
* This function takes user input and returns the ID that should be used in API calls
|
|
13
|
+
*/
|
|
14
|
+
export declare function normalizeTaskId(input: string): string;
|
|
3
15
|
export declare function parseTaskId(input: string): {
|
|
4
16
|
type: 'number' | 'uuid';
|
|
5
17
|
value: string | number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../../src/utils/tasks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,IAAI,IAAI,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../../src/utils/tasks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,IAAI,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAGlE,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE/C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAwB9F;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAQ3E;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAaxD"}
|
package/dist/utils/tasks.js
CHANGED
|
@@ -1,16 +1,41 @@
|
|
|
1
|
+
import { normalizeId } from './id-normalization.js';
|
|
1
2
|
export function formatTaskId(task) {
|
|
2
3
|
return `TASK-${task.number}`;
|
|
3
4
|
}
|
|
5
|
+
/**
|
|
6
|
+
* Normalize task ID from various formats to API-compatible format:
|
|
7
|
+
* - "TASK-123" -> "TASK-123" (already normalized)
|
|
8
|
+
* - "task-123" -> "TASK-123" (uppercase)
|
|
9
|
+
* - "TASK 123" -> "TASK-123" (add dash, uppercase)
|
|
10
|
+
* - "task 123" -> "TASK-123" (add dash, uppercase)
|
|
11
|
+
* - "123" -> "TASK-123" (add prefix)
|
|
12
|
+
* - "uuid-string" -> "uuid-string" (UUID, return as-is)
|
|
13
|
+
*
|
|
14
|
+
* This function takes user input and returns the ID that should be used in API calls
|
|
15
|
+
*/
|
|
16
|
+
export function normalizeTaskId(input) {
|
|
17
|
+
return normalizeId('TASK', input);
|
|
18
|
+
}
|
|
4
19
|
export function parseTaskId(input) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
20
|
+
// Trim whitespace
|
|
21
|
+
const trimmed = input.trim();
|
|
22
|
+
// Handle "TASK-123" or "task-123" format (with dash)
|
|
23
|
+
const taskDashMatch = trimmed.match(/^TASK-(\d+)$/i);
|
|
24
|
+
if (taskDashMatch) {
|
|
25
|
+
return { type: 'number', value: parseInt(taskDashMatch[1], 10) };
|
|
26
|
+
}
|
|
27
|
+
// Handle "TASK 123" or "task 123" format (with space)
|
|
28
|
+
const taskSpaceMatch = trimmed.match(/^TASK\s+(\d+)$/i);
|
|
29
|
+
if (taskSpaceMatch) {
|
|
30
|
+
return { type: 'number', value: parseInt(taskSpaceMatch[1], 10) };
|
|
8
31
|
}
|
|
9
|
-
|
|
32
|
+
// Handle plain number format
|
|
33
|
+
const numberMatch = trimmed.match(/^\d+$/);
|
|
10
34
|
if (numberMatch) {
|
|
11
|
-
return { type: 'number', value: parseInt(
|
|
35
|
+
return { type: 'number', value: parseInt(trimmed, 10) };
|
|
12
36
|
}
|
|
13
|
-
|
|
37
|
+
// Assume it's a UUID
|
|
38
|
+
return { type: 'uuid', value: trimmed };
|
|
14
39
|
}
|
|
15
40
|
export function findTaskById(tasks, identifier) {
|
|
16
41
|
const parsed = parseTaskId(identifier);
|
package/dist/utils/tasks.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tasks.js","sourceRoot":"","sources":["../../src/utils/tasks.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tasks.js","sourceRoot":"","sources":["../../src/utils/tasks.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,MAAM,UAAU,YAAY,CAAC,IAAU;IACtC,OAAO,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;AAC9B,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe,CAAC,KAAa;IAC5C,OAAO,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAa;IACxC,kBAAkB;IAClB,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAE7B,qDAAqD;IACrD,MAAM,aAAa,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IACrD,IAAI,aAAa,EAAE,CAAC;QACnB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;IAClE,CAAC;IAED,sDAAsD;IACtD,MAAM,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACxD,IAAI,cAAc,EAAE,CAAC;QACpB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;IACnE,CAAC;IAED,6BAA6B;IAC7B,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3C,IAAI,WAAW,EAAE,CAAC;QACjB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC;IACzD,CAAC;IAED,qBAAqB;IACrB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,UAAkB;IAC7D,MAAM,MAAM,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;IAEvC,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;IACjE,CAAC;SAAM,CAAC;QACP,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;IAC7D,CAAC;AACF,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC/C,QAAQ,MAAM,EAAE,CAAC;QAChB,KAAK,SAAS;YACb,OAAO,IAAI,CAAC;QACb,KAAK,aAAa;YACjB,OAAO,IAAI,CAAC;QACb,KAAK,WAAW;YACf,OAAO,GAAG,CAAC;QACZ,KAAK,WAAW;YACf,OAAO,GAAG,CAAC;QACZ;YACC,OAAO,IAAI,CAAC;IACd,CAAC;AACF,CAAC"}
|