@agentuity/cli 1.0.13 → 1.0.15
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/bin/cli.ts +8 -0
- package/dist/agent-detection.js +2 -2
- package/dist/agent-detection.js.map +1 -1
- package/dist/banner.js +2 -2
- package/dist/banner.js.map +1 -1
- package/dist/bun-path.d.ts.map +1 -1
- package/dist/bun-path.js +2 -1
- package/dist/bun-path.js.map +1 -1
- package/dist/cmd/build/ast.d.ts.map +1 -1
- package/dist/cmd/build/ast.js +87 -14
- package/dist/cmd/build/ast.js.map +1 -1
- package/dist/cmd/build/vite/agent-discovery.d.ts.map +1 -1
- package/dist/cmd/build/vite/agent-discovery.js +3 -2
- package/dist/cmd/build/vite/agent-discovery.js.map +1 -1
- package/dist/cmd/build/vite/metadata-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/metadata-generator.js +2 -1
- package/dist/cmd/build/vite/metadata-generator.js.map +1 -1
- package/dist/cmd/build/vite/registry-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/registry-generator.js +9 -7
- package/dist/cmd/build/vite/registry-generator.js.map +1 -1
- package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
- package/dist/cmd/build/vite/route-discovery.js +3 -2
- package/dist/cmd/build/vite/route-discovery.js.map +1 -1
- package/dist/cmd/cloud/deploy.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy.js +19 -21
- package/dist/cmd/cloud/deploy.js.map +1 -1
- package/dist/cmd/cloud/env/delete.d.ts.map +1 -1
- package/dist/cmd/cloud/env/delete.js +3 -26
- package/dist/cmd/cloud/env/delete.js.map +1 -1
- package/dist/cmd/cloud/env/import.d.ts.map +1 -1
- package/dist/cmd/cloud/env/import.js +3 -16
- package/dist/cmd/cloud/env/import.js.map +1 -1
- package/dist/cmd/cloud/env/set.d.ts.map +1 -1
- package/dist/cmd/cloud/env/set.js +3 -19
- package/dist/cmd/cloud/env/set.js.map +1 -1
- package/dist/cmd/cloud/sandbox/cp.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/cp.js +2 -1
- package/dist/cmd/cloud/sandbox/cp.js.map +1 -1
- package/dist/cmd/git/account/add.d.ts +6 -8
- package/dist/cmd/git/account/add.d.ts.map +1 -1
- package/dist/cmd/git/account/add.js +37 -151
- package/dist/cmd/git/account/add.js.map +1 -1
- package/dist/cmd/git/account/index.d.ts +0 -1
- package/dist/cmd/git/account/index.d.ts.map +1 -1
- package/dist/cmd/git/account/index.js +3 -4
- package/dist/cmd/git/account/index.js.map +1 -1
- package/dist/cmd/git/account/list.d.ts.map +1 -1
- package/dist/cmd/git/account/list.js +35 -67
- package/dist/cmd/git/account/list.js.map +1 -1
- package/dist/cmd/git/account/remove.d.ts.map +1 -1
- package/dist/cmd/git/account/remove.js +42 -84
- package/dist/cmd/git/account/remove.js.map +1 -1
- package/dist/cmd/git/api.d.ts +19 -23
- package/dist/cmd/git/api.d.ts.map +1 -1
- package/dist/cmd/git/api.js +38 -56
- package/dist/cmd/git/api.js.map +1 -1
- package/dist/cmd/git/identity/connect.d.ts +15 -0
- package/dist/cmd/git/identity/connect.d.ts.map +1 -0
- package/dist/cmd/git/identity/connect.js +135 -0
- package/dist/cmd/git/identity/connect.js.map +1 -0
- package/dist/cmd/git/identity/disconnect.d.ts +2 -0
- package/dist/cmd/git/identity/disconnect.d.ts.map +1 -0
- package/dist/cmd/git/identity/disconnect.js +83 -0
- package/dist/cmd/git/identity/disconnect.js.map +1 -0
- package/dist/cmd/git/identity/index.d.ts +2 -0
- package/dist/cmd/git/identity/index.d.ts.map +1 -0
- package/dist/cmd/git/identity/index.js +10 -0
- package/dist/cmd/git/identity/index.js.map +1 -0
- package/dist/cmd/git/identity/status.d.ts +2 -0
- package/dist/cmd/git/identity/status.d.ts.map +1 -0
- package/dist/cmd/git/identity/status.js +77 -0
- package/dist/cmd/git/identity/status.js.map +1 -0
- package/dist/cmd/git/index.d.ts +0 -1
- package/dist/cmd/git/index.d.ts.map +1 -1
- package/dist/cmd/git/index.js +3 -2
- package/dist/cmd/git/index.js.map +1 -1
- package/dist/cmd/git/link.d.ts +2 -3
- package/dist/cmd/git/link.d.ts.map +1 -1
- package/dist/cmd/git/link.js +22 -28
- package/dist/cmd/git/link.js.map +1 -1
- package/dist/cmd/git/list.d.ts.map +1 -1
- package/dist/cmd/git/list.js +42 -55
- package/dist/cmd/git/list.js.map +1 -1
- package/dist/cmd/git/status.d.ts.map +1 -1
- package/dist/cmd/git/status.js +51 -38
- package/dist/cmd/git/status.js.map +1 -1
- package/dist/cmd/upgrade/npm-availability.d.ts +6 -7
- package/dist/cmd/upgrade/npm-availability.d.ts.map +1 -1
- package/dist/cmd/upgrade/npm-availability.js +9 -18
- package/dist/cmd/upgrade/npm-availability.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +14 -4
- package/dist/config.js.map +1 -1
- package/dist/utils/detectSubagent.d.ts.map +1 -1
- package/dist/utils/detectSubagent.js +3 -0
- package/dist/utils/detectSubagent.js.map +1 -1
- package/dist/utils/normalize-path.d.ts +11 -0
- package/dist/utils/normalize-path.d.ts.map +1 -0
- package/dist/utils/normalize-path.js +13 -0
- package/dist/utils/normalize-path.js.map +1 -0
- package/dist/utils/zip.d.ts.map +1 -1
- package/dist/utils/zip.js +2 -1
- package/dist/utils/zip.js.map +1 -1
- package/package.json +6 -6
- package/src/agent-detection.ts +2 -2
- package/src/banner.ts +2 -2
- package/src/bun-path.ts +2 -1
- package/src/cmd/build/ast.ts +96 -15
- package/src/cmd/build/vite/agent-discovery.ts +3 -2
- package/src/cmd/build/vite/metadata-generator.ts +2 -1
- package/src/cmd/build/vite/registry-generator.ts +9 -7
- package/src/cmd/build/vite/route-discovery.ts +3 -2
- package/src/cmd/cloud/deploy.ts +54 -61
- package/src/cmd/cloud/env/delete.ts +3 -34
- package/src/cmd/cloud/env/import.ts +2 -18
- package/src/cmd/cloud/env/set.ts +2 -21
- package/src/cmd/cloud/sandbox/cp.ts +2 -1
- package/src/cmd/git/account/add.ts +51 -190
- package/src/cmd/git/account/index.ts +3 -5
- package/src/cmd/git/account/list.ts +51 -82
- package/src/cmd/git/account/remove.ts +45 -95
- package/src/cmd/git/api.ts +49 -111
- package/src/cmd/git/identity/connect.ts +178 -0
- package/src/cmd/git/identity/disconnect.ts +103 -0
- package/src/cmd/git/identity/index.ts +10 -0
- package/src/cmd/git/identity/status.ts +96 -0
- package/src/cmd/git/index.ts +3 -3
- package/src/cmd/git/link.ts +32 -35
- package/src/cmd/git/list.ts +48 -59
- package/src/cmd/git/status.ts +55 -40
- package/src/cmd/upgrade/npm-availability.ts +14 -23
- package/src/config.ts +14 -5
- package/src/utils/detectSubagent.ts +5 -0
- package/src/utils/normalize-path.ts +12 -0
- package/src/utils/zip.ts +2 -1
package/src/cmd/cloud/env/set.ts
CHANGED
|
@@ -3,8 +3,6 @@ import { createSubcommand } from '../../../types';
|
|
|
3
3
|
import * as tui from '../../../tui';
|
|
4
4
|
import { projectEnvUpdate, orgEnvUpdate } from '@agentuity/server';
|
|
5
5
|
import {
|
|
6
|
-
findExistingEnvFile,
|
|
7
|
-
writeEnvFile,
|
|
8
6
|
looksLikeSecret,
|
|
9
7
|
isReservedAgentuityKey,
|
|
10
8
|
isPublicVarKey,
|
|
@@ -75,10 +73,6 @@ function parseEnvArgs(rawArgs: string[]): ParsedEnvPair[] {
|
|
|
75
73
|
const EnvSetResponseSchema = z.object({
|
|
76
74
|
success: z.boolean().describe('Whether the operation succeeded'),
|
|
77
75
|
keys: z.array(z.string()).describe('Environment variable keys that were set'),
|
|
78
|
-
path: z
|
|
79
|
-
.string()
|
|
80
|
-
.optional()
|
|
81
|
-
.describe('Local file path where env vars were saved (project scope only)'),
|
|
82
76
|
secretKeys: z.array(z.string()).describe('Keys that were stored as secrets'),
|
|
83
77
|
envKeys: z.array(z.string()).describe('Keys that were stored as env vars'),
|
|
84
78
|
scope: z.enum(['project', 'org']).describe('The scope where the variables were set'),
|
|
@@ -134,7 +128,7 @@ export const setSubcommand = createSubcommand({
|
|
|
134
128
|
},
|
|
135
129
|
|
|
136
130
|
async handler(ctx) {
|
|
137
|
-
const { args: cmdArgs, opts, apiClient, project,
|
|
131
|
+
const { args: cmdArgs, opts, apiClient, project, config } = ctx;
|
|
138
132
|
const useOrgScope = isOrgScope(opts?.org);
|
|
139
133
|
const forceSecret = opts?.secret ?? false;
|
|
140
134
|
|
|
@@ -262,26 +256,13 @@ export const setSubcommand = createSubcommand({
|
|
|
262
256
|
}
|
|
263
257
|
);
|
|
264
258
|
|
|
265
|
-
// Update local .env file only if we have a project directory
|
|
266
|
-
let envFilePath: string | undefined;
|
|
267
|
-
if (projectDir) {
|
|
268
|
-
envFilePath = await findExistingEnvFile(projectDir);
|
|
269
|
-
const allPairsForLocal: Record<string, string> = {
|
|
270
|
-
...envPairs,
|
|
271
|
-
...secretPairs,
|
|
272
|
-
};
|
|
273
|
-
await writeEnvFile(envFilePath, allPairsForLocal);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
const locationMsg = envFilePath ? ` (cloud + ${envFilePath})` : ' (cloud only)';
|
|
277
259
|
tui.success(
|
|
278
|
-
`Variable${totalCount !== 1 ? 's' : ''} set successfully: ${allKeys.join(', ')}${secretSuffix}
|
|
260
|
+
`Variable${totalCount !== 1 ? 's' : ''} set successfully: ${allKeys.join(', ')}${secretSuffix}`
|
|
279
261
|
);
|
|
280
262
|
|
|
281
263
|
return {
|
|
282
264
|
success: true,
|
|
283
265
|
keys: allKeys,
|
|
284
|
-
path: envFilePath,
|
|
285
266
|
secretKeys: secretKeysList,
|
|
286
267
|
envKeys: envKeysList,
|
|
287
268
|
scope: 'project' as const,
|
|
@@ -2,6 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
import { readFileSync, writeFileSync, mkdirSync, statSync, readdirSync } from 'node:fs';
|
|
3
3
|
import { dirname, resolve, basename, join, relative } from 'node:path';
|
|
4
4
|
import { createCommand } from '../../../types';
|
|
5
|
+
import { toForwardSlash } from '../../../utils/normalize-path';
|
|
5
6
|
import * as tui from '../../../tui';
|
|
6
7
|
import { createSandboxClient } from './util';
|
|
7
8
|
import { getCommand } from '../../../command-prefix';
|
|
@@ -265,7 +266,7 @@ async function uploadDirectory(
|
|
|
265
266
|
: effectiveRemotePath;
|
|
266
267
|
|
|
267
268
|
for (const filePath of allFiles) {
|
|
268
|
-
const relativePath = relative(localDir, filePath);
|
|
269
|
+
const relativePath = toForwardSlash(relative(localDir, filePath));
|
|
269
270
|
const targetPath = `${baseRemotePath}/${relativePath}`;
|
|
270
271
|
const buffer = readFileSync(filePath);
|
|
271
272
|
files.push({ path: targetPath, content: buffer });
|
|
@@ -1,119 +1,62 @@
|
|
|
1
|
-
import { createSubcommand } from '../../../types';
|
|
2
|
-
import type { Config } from '../../../types';
|
|
3
|
-
import * as tui from '../../../tui';
|
|
4
|
-
import { getCommand } from '../../../command-prefix';
|
|
5
|
-
import { getAPIBaseURL } from '../../../api';
|
|
6
|
-
import type { APIClient } from '../../../api';
|
|
7
|
-
import { ErrorCode } from '../../../errors';
|
|
8
|
-
import { listOrganizations } from '@agentuity/server';
|
|
9
|
-
import enquirer from 'enquirer';
|
|
10
1
|
import type { Logger } from '@agentuity/core';
|
|
11
2
|
import { z } from 'zod';
|
|
3
|
+
import type { APIClient } from '../../../api';
|
|
4
|
+
import { getAPIBaseURL } from '../../../api';
|
|
5
|
+
import { getCommand } from '../../../command-prefix';
|
|
6
|
+
import { ErrorCode } from '../../../errors';
|
|
7
|
+
import * as tui from '../../../tui';
|
|
8
|
+
import type { Config } from '../../../types';
|
|
9
|
+
import { createSubcommand } from '../../../types';
|
|
12
10
|
import {
|
|
13
|
-
startGithubIntegration,
|
|
14
|
-
pollForGithubIntegration,
|
|
15
11
|
getGithubIntegrationStatus,
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
pollForGithubIntegration,
|
|
13
|
+
startGithubIntegration,
|
|
18
14
|
} from '../api';
|
|
19
15
|
|
|
20
|
-
export interface
|
|
16
|
+
export interface RunGitAccountAddOptions {
|
|
21
17
|
apiClient: APIClient;
|
|
22
|
-
orgId: string;
|
|
23
|
-
orgName?: string;
|
|
24
18
|
logger: Logger;
|
|
25
19
|
config?: Config | null;
|
|
26
20
|
}
|
|
27
21
|
|
|
28
|
-
export interface
|
|
29
|
-
|
|
22
|
+
export interface RunGitAccountAddResult {
|
|
23
|
+
added: boolean;
|
|
30
24
|
cancelled?: boolean;
|
|
31
25
|
}
|
|
32
26
|
|
|
33
|
-
export async function
|
|
34
|
-
options:
|
|
35
|
-
): Promise<
|
|
36
|
-
const { apiClient,
|
|
37
|
-
const orgDisplay = orgName ?? orgId;
|
|
27
|
+
export async function runGitAccountAdd(
|
|
28
|
+
options: RunGitAccountAddOptions
|
|
29
|
+
): Promise<RunGitAccountAddResult> {
|
|
30
|
+
const { apiClient, logger, config } = options;
|
|
38
31
|
|
|
39
32
|
try {
|
|
40
|
-
const currentStatus = await getGithubIntegrationStatus(apiClient
|
|
41
|
-
const initialCount = currentStatus.integrations?.length ?? 0;
|
|
42
|
-
|
|
43
|
-
const existingIntegrations = await tui.spinner({
|
|
44
|
-
message: 'Checking for existing GitHub connections...',
|
|
45
|
-
clearOnSuccess: true,
|
|
46
|
-
callback: () => getExistingGithubIntegrations(apiClient, orgId),
|
|
47
|
-
});
|
|
33
|
+
const currentStatus = await getGithubIntegrationStatus(apiClient);
|
|
48
34
|
|
|
49
|
-
|
|
50
|
-
currentStatus.integrations?.map((i) => i.githubAccountName) ?? []
|
|
51
|
-
);
|
|
52
|
-
const availableIntegrations = existingIntegrations.filter(
|
|
53
|
-
(i) => !alreadyConnectedNames.has(i.githubAccountName)
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
if (availableIntegrations.length > 0) {
|
|
57
|
-
tui.newline();
|
|
58
|
-
|
|
59
|
-
const integrationChoices = availableIntegrations.map((i) => ({
|
|
60
|
-
name: i.id,
|
|
61
|
-
message: `${i.githubAccountName} ${tui.muted(`(from ${i.orgName})`)}`,
|
|
62
|
-
}));
|
|
63
|
-
|
|
64
|
-
console.log(tui.muted('Press enter with none selected to add a new account'));
|
|
35
|
+
if (!currentStatus.connected || !currentStatus.identity) {
|
|
65
36
|
tui.newline();
|
|
37
|
+
tui.error(
|
|
38
|
+
`No GitHub identity connected. Run ${tui.bold('agentuity git identity connect')} first.`
|
|
39
|
+
);
|
|
40
|
+
return { added: false };
|
|
41
|
+
}
|
|
66
42
|
|
|
67
|
-
|
|
68
|
-
type: 'multiselect',
|
|
69
|
-
name: 'integrationIds',
|
|
70
|
-
message: 'Select GitHub accounts to add',
|
|
71
|
-
choices: integrationChoices,
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
if (selectResponse.integrationIds.length > 0) {
|
|
75
|
-
const selectedIntegrations = availableIntegrations.filter((i) =>
|
|
76
|
-
selectResponse.integrationIds.includes(i.id)
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
const accountNames = selectedIntegrations.map((i) => i.githubAccountName).join(', ');
|
|
80
|
-
|
|
81
|
-
const confirmResponse = await enquirer.prompt<{ confirm: boolean }>({
|
|
82
|
-
type: 'confirm',
|
|
83
|
-
name: 'confirm',
|
|
84
|
-
message: `Add ${tui.bold(accountNames)} to ${tui.bold(orgDisplay)}?`,
|
|
85
|
-
initial: true,
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
if (confirmResponse.confirm) {
|
|
89
|
-
await tui.spinner({
|
|
90
|
-
message: `Adding ${selectedIntegrations.length} GitHub account${selectedIntegrations.length > 1 ? 's' : ''}...`,
|
|
91
|
-
clearOnSuccess: true,
|
|
92
|
-
callback: async () => {
|
|
93
|
-
for (const integration of selectedIntegrations) {
|
|
94
|
-
await copyGithubIntegration(apiClient, integration.orgId, orgId);
|
|
95
|
-
}
|
|
96
|
-
},
|
|
97
|
-
});
|
|
43
|
+
const initialCount = currentStatus.installations?.length ?? 0;
|
|
98
44
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
45
|
+
tui.newline();
|
|
46
|
+
tui.info(
|
|
47
|
+
`Connected as ${tui.bold(currentStatus.identity.githubUsername)}. Opening GitHub to install the app on a new account...`
|
|
48
|
+
);
|
|
49
|
+
tui.newline();
|
|
107
50
|
|
|
108
51
|
const startResult = await tui.spinner({
|
|
109
|
-
message: 'Getting GitHub
|
|
52
|
+
message: 'Getting GitHub installation URL...',
|
|
110
53
|
clearOnSuccess: true,
|
|
111
|
-
callback: () => startGithubIntegration(apiClient
|
|
54
|
+
callback: () => startGithubIntegration(apiClient),
|
|
112
55
|
});
|
|
113
56
|
|
|
114
57
|
if (!startResult) {
|
|
115
|
-
tui.error('Failed to start GitHub
|
|
116
|
-
return {
|
|
58
|
+
tui.error('Failed to start GitHub installation flow');
|
|
59
|
+
return { added: false };
|
|
117
60
|
}
|
|
118
61
|
|
|
119
62
|
const { shortId } = startResult;
|
|
@@ -124,19 +67,19 @@ export async function runGitAccountConnect(
|
|
|
124
67
|
|
|
125
68
|
tui.newline();
|
|
126
69
|
if (copied) {
|
|
127
|
-
|
|
70
|
+
tui.output('GitHub installation URL copied to clipboard! Open it in your browser:');
|
|
128
71
|
} else {
|
|
129
|
-
|
|
72
|
+
tui.output('Open this URL in your browser to install the GitHub App:');
|
|
130
73
|
}
|
|
131
74
|
tui.newline();
|
|
132
|
-
|
|
75
|
+
tui.output(` ${tui.link(url)}`);
|
|
133
76
|
tui.newline();
|
|
134
|
-
|
|
77
|
+
tui.output(tui.muted('Press Enter to open in your browser, or Ctrl+C to cancel'));
|
|
135
78
|
tui.newline();
|
|
136
79
|
|
|
137
80
|
const result = await tui.spinner({
|
|
138
81
|
type: 'countdown',
|
|
139
|
-
message: 'Waiting for GitHub
|
|
82
|
+
message: 'Waiting for GitHub App installation',
|
|
140
83
|
timeoutMs: 600000,
|
|
141
84
|
clearOnSuccess: true,
|
|
142
85
|
onEnterPress: () => {
|
|
@@ -152,17 +95,17 @@ export async function runGitAccountConnect(
|
|
|
152
95
|
}
|
|
153
96
|
},
|
|
154
97
|
callback: async () => {
|
|
155
|
-
return await pollForGithubIntegration(apiClient,
|
|
98
|
+
return await pollForGithubIntegration(apiClient, initialCount);
|
|
156
99
|
},
|
|
157
100
|
});
|
|
158
101
|
|
|
159
102
|
tui.newline();
|
|
160
103
|
if (result.connected) {
|
|
161
|
-
tui.success(
|
|
162
|
-
return {
|
|
104
|
+
tui.success('GitHub App installed on new account');
|
|
105
|
+
return { added: true };
|
|
163
106
|
}
|
|
164
107
|
|
|
165
|
-
return {
|
|
108
|
+
return { added: false };
|
|
166
109
|
} catch (error) {
|
|
167
110
|
const isCancel =
|
|
168
111
|
error === '' ||
|
|
@@ -171,7 +114,7 @@ export async function runGitAccountConnect(
|
|
|
171
114
|
if (isCancel) {
|
|
172
115
|
tui.newline();
|
|
173
116
|
tui.info('Cancelled');
|
|
174
|
-
return {
|
|
117
|
+
return { added: false, cancelled: true };
|
|
175
118
|
}
|
|
176
119
|
|
|
177
120
|
logger.trace(error);
|
|
@@ -179,18 +122,15 @@ export async function runGitAccountConnect(
|
|
|
179
122
|
}
|
|
180
123
|
}
|
|
181
124
|
|
|
182
|
-
const AddOptionsSchema = z.object({
|
|
183
|
-
org: z.string().optional().describe('Organization ID to add the account to'),
|
|
184
|
-
});
|
|
125
|
+
const AddOptionsSchema = z.object({});
|
|
185
126
|
|
|
186
127
|
const AddResponseSchema = z.object({
|
|
187
|
-
|
|
188
|
-
orgId: z.string().optional().describe('Organization ID'),
|
|
128
|
+
added: z.boolean().describe('Whether the installation was added'),
|
|
189
129
|
});
|
|
190
130
|
|
|
191
131
|
export const addSubcommand = createSubcommand({
|
|
192
132
|
name: 'add',
|
|
193
|
-
description: '
|
|
133
|
+
description: 'Install the GitHub App on a new account or organization',
|
|
194
134
|
tags: ['mutating', 'creates-resource', 'slow', 'api-intensive'],
|
|
195
135
|
idempotent: false,
|
|
196
136
|
requires: { auth: true, apiClient: true },
|
|
@@ -201,100 +141,21 @@ export const addSubcommand = createSubcommand({
|
|
|
201
141
|
examples: [
|
|
202
142
|
{
|
|
203
143
|
command: getCommand('git account add'),
|
|
204
|
-
description: '
|
|
205
|
-
},
|
|
206
|
-
{
|
|
207
|
-
command: getCommand('git account add --org org_abc123'),
|
|
208
|
-
description: 'Add to a specific organization',
|
|
144
|
+
description: 'Install the GitHub App on a new account',
|
|
209
145
|
},
|
|
210
146
|
],
|
|
211
147
|
|
|
212
148
|
async handler(ctx) {
|
|
213
|
-
const { logger, apiClient, config
|
|
149
|
+
const { logger, apiClient, config } = ctx;
|
|
214
150
|
|
|
215
151
|
try {
|
|
216
|
-
const
|
|
217
|
-
message: 'Fetching organizations...',
|
|
218
|
-
clearOnSuccess: true,
|
|
219
|
-
callback: () => listOrganizations(apiClient),
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
if (orgs.length === 0) {
|
|
223
|
-
tui.fatal('No organizations found for your account');
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
let orgId = opts.org;
|
|
227
|
-
let selectedOrg: (typeof orgs)[0] | undefined;
|
|
228
|
-
|
|
229
|
-
if (orgId) {
|
|
230
|
-
selectedOrg = orgs.find((o) => o.id === orgId);
|
|
231
|
-
if (!selectedOrg) {
|
|
232
|
-
tui.fatal(`Organization ${orgId} not found`);
|
|
233
|
-
}
|
|
234
|
-
} else {
|
|
235
|
-
const orgStatuses = await tui.spinner({
|
|
236
|
-
message: 'Checking GitHub integration status...',
|
|
237
|
-
clearOnSuccess: true,
|
|
238
|
-
callback: async () => {
|
|
239
|
-
const statuses = await Promise.all(
|
|
240
|
-
orgs.map(async (org) => {
|
|
241
|
-
const status = await getGithubIntegrationStatus(apiClient, org.id);
|
|
242
|
-
return {
|
|
243
|
-
...org,
|
|
244
|
-
connected: status.connected,
|
|
245
|
-
integrations: status.integrations,
|
|
246
|
-
};
|
|
247
|
-
})
|
|
248
|
-
);
|
|
249
|
-
return statuses;
|
|
250
|
-
},
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
const sortedOrgs = [...orgStatuses].sort((a, b) => a.name.localeCompare(b.name));
|
|
254
|
-
|
|
255
|
-
const firstOrg = orgs[0];
|
|
256
|
-
if (orgs.length === 1 && firstOrg) {
|
|
257
|
-
orgId = firstOrg.id;
|
|
258
|
-
selectedOrg = firstOrg;
|
|
259
|
-
} else {
|
|
260
|
-
const choices = sortedOrgs.map((org) => {
|
|
261
|
-
const count = org.integrations.length;
|
|
262
|
-
const suffix =
|
|
263
|
-
count > 0
|
|
264
|
-
? tui.muted(` (${count} GitHub account${count > 1 ? 's' : ''})`)
|
|
265
|
-
: '';
|
|
266
|
-
return {
|
|
267
|
-
name: org.name,
|
|
268
|
-
message: `${org.name}${suffix}`,
|
|
269
|
-
value: org.id,
|
|
270
|
-
};
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
const response = await enquirer.prompt<{ orgName: string }>({
|
|
274
|
-
type: 'select',
|
|
275
|
-
name: 'orgName',
|
|
276
|
-
message: 'Select an organization',
|
|
277
|
-
choices,
|
|
278
|
-
result(name: string) {
|
|
279
|
-
// @ts-expect-error - this.map exists at runtime
|
|
280
|
-
return this.map(name)[name];
|
|
281
|
-
},
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
orgId = response.orgName;
|
|
285
|
-
selectedOrg = sortedOrgs.find((o) => o.id === orgId);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
const result = await runGitAccountConnect({
|
|
152
|
+
const result = await runGitAccountAdd({
|
|
290
153
|
apiClient,
|
|
291
|
-
orgId: orgId!,
|
|
292
|
-
orgName: selectedOrg?.name,
|
|
293
154
|
logger,
|
|
294
155
|
config,
|
|
295
156
|
});
|
|
296
157
|
|
|
297
|
-
return {
|
|
158
|
+
return { added: result.added };
|
|
298
159
|
} catch (error) {
|
|
299
160
|
const isCancel =
|
|
300
161
|
error === '' ||
|
|
@@ -304,7 +165,7 @@ export const addSubcommand = createSubcommand({
|
|
|
304
165
|
if (isCancel) {
|
|
305
166
|
tui.newline();
|
|
306
167
|
tui.info('Cancelled');
|
|
307
|
-
return {
|
|
168
|
+
return { added: false };
|
|
308
169
|
}
|
|
309
170
|
|
|
310
171
|
logger.trace(error);
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { createCommand } from '../../../types';
|
|
2
2
|
import { addSubcommand } from './add';
|
|
3
|
-
import { removeSubcommand } from './remove';
|
|
4
3
|
import { listSubcommand } from './list';
|
|
4
|
+
import { removeSubcommand } from './remove';
|
|
5
5
|
|
|
6
6
|
export const accountCommand = createCommand({
|
|
7
7
|
name: 'account',
|
|
8
|
-
description: 'Manage GitHub
|
|
9
|
-
subcommands: [addSubcommand,
|
|
8
|
+
description: 'Manage GitHub App installations',
|
|
9
|
+
subcommands: [addSubcommand, listSubcommand, removeSubcommand],
|
|
10
10
|
});
|
|
11
|
-
|
|
12
|
-
export default accountCommand;
|
|
@@ -1,28 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import * as tui from '../../../tui';
|
|
1
|
+
import { z } from 'zod';
|
|
3
2
|
import { getCommand } from '../../../command-prefix';
|
|
4
3
|
import { ErrorCode } from '../../../errors';
|
|
5
|
-
import
|
|
4
|
+
import * as tui from '../../../tui';
|
|
5
|
+
import { createSubcommand } from '../../../types';
|
|
6
6
|
import { getGithubIntegrationStatus } from '../api';
|
|
7
|
-
import { z } from 'zod';
|
|
8
7
|
|
|
9
|
-
const ListResponseSchema = z.
|
|
10
|
-
z.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
z.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
})
|
|
19
|
-
),
|
|
20
|
-
})
|
|
21
|
-
);
|
|
8
|
+
const ListResponseSchema = z.object({
|
|
9
|
+
installations: z.array(
|
|
10
|
+
z.object({
|
|
11
|
+
installationId: z.string().describe('Installation ID'),
|
|
12
|
+
accountName: z.string().describe('GitHub account name'),
|
|
13
|
+
accountType: z.enum(['User', 'Organization']).describe('Account type'),
|
|
14
|
+
})
|
|
15
|
+
),
|
|
16
|
+
});
|
|
22
17
|
|
|
23
18
|
export const listSubcommand = createSubcommand({
|
|
24
19
|
name: 'list',
|
|
25
|
-
description: 'List GitHub
|
|
20
|
+
description: 'List GitHub App installations',
|
|
26
21
|
aliases: ['ls'],
|
|
27
22
|
tags: ['read-only'],
|
|
28
23
|
idempotent: true,
|
|
@@ -33,11 +28,11 @@ export const listSubcommand = createSubcommand({
|
|
|
33
28
|
examples: [
|
|
34
29
|
{
|
|
35
30
|
command: getCommand('git account list'),
|
|
36
|
-
description: 'List
|
|
31
|
+
description: 'List GitHub App installations',
|
|
37
32
|
},
|
|
38
33
|
{
|
|
39
34
|
command: getCommand('--json git account list'),
|
|
40
|
-
description: 'List
|
|
35
|
+
description: 'List installations in JSON format',
|
|
41
36
|
},
|
|
42
37
|
],
|
|
43
38
|
|
|
@@ -45,92 +40,66 @@ export const listSubcommand = createSubcommand({
|
|
|
45
40
|
const { logger, apiClient, options } = ctx;
|
|
46
41
|
|
|
47
42
|
try {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
message: 'Fetching organizations...',
|
|
43
|
+
const status = await tui.spinner({
|
|
44
|
+
message: 'Checking GitHub connection...',
|
|
51
45
|
clearOnSuccess: true,
|
|
52
|
-
callback: () =>
|
|
46
|
+
callback: () => getGithubIntegrationStatus(apiClient),
|
|
53
47
|
});
|
|
54
48
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const orgStatuses = await tui.spinner({
|
|
61
|
-
message: 'Checking GitHub integration status...',
|
|
62
|
-
clearOnSuccess: true,
|
|
63
|
-
callback: async () => {
|
|
64
|
-
const statuses = await Promise.all(
|
|
65
|
-
orgs.map(async (org) => {
|
|
66
|
-
const status = await getGithubIntegrationStatus(apiClient, org.id);
|
|
67
|
-
return {
|
|
68
|
-
...org,
|
|
69
|
-
connected: status.connected,
|
|
70
|
-
integrations: status.integrations,
|
|
71
|
-
};
|
|
72
|
-
})
|
|
73
|
-
);
|
|
74
|
-
return statuses;
|
|
75
|
-
},
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
// Sort orgs alphabetically
|
|
79
|
-
const sortedOrgs = [...orgStatuses].sort((a, b) => a.name.localeCompare(b.name));
|
|
80
|
-
|
|
81
|
-
const result = sortedOrgs.map((org) => ({
|
|
82
|
-
orgId: org.id,
|
|
83
|
-
orgName: org.name,
|
|
84
|
-
integrations: org.integrations.map((i) => ({
|
|
85
|
-
id: i.id,
|
|
86
|
-
githubAccountName: i.githubAccountName,
|
|
87
|
-
githubAccountType: i.githubAccountType,
|
|
49
|
+
const result = {
|
|
50
|
+
installations: status.installations.map((i) => ({
|
|
51
|
+
installationId: i.installationId,
|
|
52
|
+
accountName: i.accountName,
|
|
53
|
+
accountType: i.accountType,
|
|
88
54
|
})),
|
|
89
|
-
}
|
|
55
|
+
};
|
|
90
56
|
|
|
91
57
|
if (options.json) {
|
|
92
58
|
return result;
|
|
93
59
|
}
|
|
94
60
|
|
|
95
61
|
tui.newline();
|
|
96
|
-
console.log(tui.bold('GitHub Accounts'));
|
|
97
|
-
tui.newline();
|
|
98
|
-
|
|
99
|
-
let totalCount = 0;
|
|
100
62
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
` ${tui.colorSuccess('✓')} ${integration.githubAccountName} ${tui.muted(`(${typeLabel})`)}`
|
|
110
|
-
);
|
|
111
|
-
totalCount++;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
63
|
+
if (!status.connected || !status.identity) {
|
|
64
|
+
tui.output(
|
|
65
|
+
tui.muted(
|
|
66
|
+
`No GitHub identity connected. Run ${tui.bold('agentuity git identity connect')} to connect one.`
|
|
67
|
+
)
|
|
68
|
+
);
|
|
69
|
+
tui.newline();
|
|
70
|
+
return result;
|
|
114
71
|
}
|
|
115
72
|
|
|
73
|
+
tui.output(tui.bold('GitHub App Installations'));
|
|
116
74
|
tui.newline();
|
|
117
|
-
|
|
118
|
-
|
|
75
|
+
|
|
76
|
+
if (status.installations.length === 0) {
|
|
77
|
+
tui.output(
|
|
119
78
|
tui.muted(
|
|
120
|
-
`No
|
|
79
|
+
`No installations found. Run ${tui.bold('agentuity git account add')} to install the GitHub App.`
|
|
121
80
|
)
|
|
122
81
|
);
|
|
123
82
|
} else {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
83
|
+
for (const installation of status.installations) {
|
|
84
|
+
const typeLabel = installation.accountType === 'Organization' ? 'org' : 'user';
|
|
85
|
+
tui.output(
|
|
86
|
+
` ${tui.colorSuccess('✓')} ${installation.accountName} ${tui.muted(`(${typeLabel})`)}`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
127
89
|
}
|
|
128
90
|
|
|
91
|
+
tui.newline();
|
|
92
|
+
tui.output(
|
|
93
|
+
tui.muted(
|
|
94
|
+
`${status.installations.length} installation${status.installations.length !== 1 ? 's' : ''}`
|
|
95
|
+
)
|
|
96
|
+
);
|
|
97
|
+
|
|
129
98
|
return result;
|
|
130
99
|
} catch (error) {
|
|
131
100
|
logger.trace(error);
|
|
132
101
|
return logger.fatal(
|
|
133
|
-
'Failed to list GitHub
|
|
102
|
+
'Failed to list GitHub installations: %s',
|
|
134
103
|
error,
|
|
135
104
|
ErrorCode.INTEGRATION_FAILED
|
|
136
105
|
);
|