@agentuity/cli 0.1.17 → 0.1.19

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/src/tui.ts CHANGED
@@ -45,7 +45,7 @@ export { maskSecret };
45
45
  // Export new TUI components
46
46
  export { createPrompt, PromptFlow } from './tui/prompt';
47
47
  export { group } from './tui/group';
48
- export { note, drawBox, errorBox } from './tui/box';
48
+ export { note, drawBox, errorBox, warningBox } from './tui/box';
49
49
  export { symbols } from './tui/symbols';
50
50
  export { colors as tuiColors } from './tui/colors';
51
51
  export type {
package/src/types.ts CHANGED
@@ -653,26 +653,37 @@ export const BuildMetadataSchema = ServerBuildMetadataSchema;
653
653
  export type BuildMetadata = zod.infer<typeof BuildMetadataSchema>;
654
654
  export type Project = zod.infer<typeof ProjectSchema>;
655
655
 
656
- export const DeployOptionsSchema = zod.object({
657
- logsUrl: zod.url().optional().describe('The url to the CI build logs'),
658
- trigger: zod
659
- .enum(['cli', 'workflow', 'webhook'])
660
- .default('cli')
661
- .optional()
662
- .describe('The trigger that caused the build'),
663
- commitUrl: zod.url().optional().describe('The url to the CI commit'),
664
- message: zod.string().optional().describe('The message to associate with this deployment'),
665
- commit: zod.string().optional().describe('The commit SHA for this deployment'),
666
- branch: zod.string().optional().describe('The git branch for this deployment'),
667
- provider: zod.string().optional().describe('The CI provider name (attempts to autodetect)'),
668
- repo: zod.string().optional().describe('The repo url'),
669
- event: zod
670
- .enum(['pull_request', 'push', 'manual', 'workflow'])
671
- .default('manual')
672
- .optional()
673
- .describe('The event that triggered the deployment'),
674
- pullRequestNumber: zod.number().optional().describe('the pull request number'),
675
- pullRequestUrl: zod.url().optional().describe('the pull request url'),
656
+ /**
657
+ * Common git options schema for build commands (deploy, snapshot build, etc.)
658
+ * These can be provided via CLI flags to override auto-detected git values.
659
+ */
660
+ export const GitOptionsSchema = zod.object({
661
+ message: zod.string().optional().describe('The message to associate with this build'),
662
+ commit: zod.string().optional().describe('The git commit SHA'),
663
+ branch: zod.string().optional().describe('The git branch'),
664
+ repo: zod.string().optional().describe('The git repo URL'),
665
+ provider: zod.string().optional().describe('The git provider (github, gitlab, bitbucket)'),
666
+ commitUrl: zod.url().optional().describe('The URL to the commit'),
676
667
  });
677
668
 
669
+ export type GitOptions = z.infer<typeof GitOptionsSchema>;
670
+
671
+ export const DeployOptionsSchema = zod
672
+ .object({
673
+ logsUrl: zod.url().optional().describe('The url to the CI build logs'),
674
+ trigger: zod
675
+ .enum(['cli', 'workflow', 'webhook'])
676
+ .default('cli')
677
+ .optional()
678
+ .describe('The trigger that caused the build'),
679
+ event: zod
680
+ .enum(['pull_request', 'push', 'manual', 'workflow'])
681
+ .default('manual')
682
+ .optional()
683
+ .describe('The event that triggered the deployment'),
684
+ pullRequestNumber: zod.number().optional().describe('the pull request number'),
685
+ pullRequestUrl: zod.url().optional().describe('the pull request url'),
686
+ })
687
+ .merge(GitOptionsSchema);
688
+
678
689
  export type DeployOptions = z.infer<typeof DeployOptionsSchema>;
@@ -0,0 +1,209 @@
1
+ import type { Logger } from '@agentuity/core';
2
+ import { existsSync } from 'node:fs';
3
+ import { dirname, join } from 'node:path';
4
+
5
+ /**
6
+ * Git information detected from the repository
7
+ */
8
+ export interface GitInfo {
9
+ branch?: string;
10
+ repo?: string;
11
+ provider?: string;
12
+ tags?: string[];
13
+ commit?: string;
14
+ message?: string;
15
+ }
16
+
17
+ /**
18
+ * Git options that can be provided via CLI flags to override auto-detected values
19
+ */
20
+ export interface GitOptions {
21
+ message?: string;
22
+ commit?: string;
23
+ branch?: string;
24
+ repo?: string;
25
+ provider?: string;
26
+ commitUrl?: string;
27
+ }
28
+
29
+ /**
30
+ * Extended git info that includes CI-related fields
31
+ */
32
+ export interface GitInfoExtended extends GitInfo {
33
+ commitUrl?: string;
34
+ logsUrl?: string;
35
+ trigger?: string;
36
+ event?: string;
37
+ pull_request?: {
38
+ number: number;
39
+ url?: string;
40
+ };
41
+ }
42
+
43
+ /**
44
+ * Detect git information from the repository at the given root directory.
45
+ * Walks up parent directories to find .git directory (supports monorepos).
46
+ *
47
+ * @param rootDir - The root directory to start searching for .git
48
+ * @param logger - Logger instance for trace output
49
+ * @returns Git information or undefined if not in a git repository
50
+ */
51
+ export async function getGitInfo(rootDir: string, logger: Logger): Promise<GitInfo | undefined> {
52
+ if (!Bun.which('git')) {
53
+ logger.trace('git not found in PATH');
54
+ return undefined;
55
+ }
56
+
57
+ try {
58
+ // Find .git directory (may be in parent directories for monorepos)
59
+ let gitDir = join(rootDir, '.git');
60
+ let parentDir = dirname(dirname(gitDir));
61
+ while (!existsSync(gitDir) && parentDir !== dirname(parentDir) && gitDir !== '/') {
62
+ gitDir = join(parentDir, '.git');
63
+ parentDir = dirname(parentDir);
64
+ }
65
+
66
+ if (!existsSync(gitDir)) {
67
+ logger.trace('No .git directory found');
68
+ return undefined;
69
+ }
70
+
71
+ const $ = Bun.$;
72
+ const gitInfo: GitInfo = {
73
+ provider: 'git',
74
+ };
75
+
76
+ // Get git tags pointing to HEAD
77
+ const tagResult = $`git tag -l --points-at HEAD`.nothrow().quiet();
78
+ if (tagResult) {
79
+ const tagText = await tagResult.text();
80
+ if (tagText) {
81
+ gitInfo.tags = tagText
82
+ .trim()
83
+ .split(/\n/)
84
+ .map((s) => s.trim())
85
+ .filter(Boolean);
86
+ }
87
+ }
88
+
89
+ // Get current branch
90
+ const branchResult = $`git branch --show-current`.nothrow().quiet();
91
+ if (branchResult) {
92
+ const branchText = await branchResult.text();
93
+ if (branchText) {
94
+ gitInfo.branch = branchText.trim();
95
+ }
96
+ }
97
+
98
+ // Get commit SHA
99
+ const commitResult = $`git rev-parse HEAD`.nothrow().quiet();
100
+ if (commitResult) {
101
+ const commitText = await commitResult.text();
102
+ if (commitText) {
103
+ gitInfo.commit = commitText.trim();
104
+
105
+ // Get commit message
106
+ const msgResult = $`git log --pretty=format:%s -n1 ${gitInfo.commit}`.nothrow().quiet();
107
+ if (msgResult) {
108
+ const msgText = await msgResult.text();
109
+ if (msgText) {
110
+ gitInfo.message = msgText.trim();
111
+ }
112
+ }
113
+ }
114
+ }
115
+
116
+ // Get remote origin URL and parse
117
+ const originResult = $`git config --get remote.origin.url`.nothrow().quiet();
118
+ if (originResult) {
119
+ const originText = await originResult.text();
120
+ if (originText) {
121
+ const remoteUrl = originText.trim();
122
+
123
+ // Parse provider and repo from URL
124
+ if (remoteUrl.includes('github.com')) {
125
+ gitInfo.provider = 'github';
126
+ const match = remoteUrl.match(/github\.com[:/](.+?)(?:\.git)?$/);
127
+ if (match) {
128
+ gitInfo.repo = `https://github.com/${match[1]}`;
129
+ }
130
+ } else if (remoteUrl.includes('gitlab.com')) {
131
+ gitInfo.provider = 'gitlab';
132
+ const match = remoteUrl.match(/gitlab\.com[:/](.+?)(?:\.git)?$/);
133
+ if (match) {
134
+ gitInfo.repo = `https://gitlab.com/${match[1]}`;
135
+ }
136
+ } else if (remoteUrl.includes('bitbucket.org')) {
137
+ gitInfo.provider = 'bitbucket';
138
+ const match = remoteUrl.match(/bitbucket\.org[:/](.+?)(?:\.git)?$/);
139
+ if (match) {
140
+ gitInfo.repo = `https://bitbucket.org/${match[1]}`;
141
+ }
142
+ } else {
143
+ gitInfo.repo = remoteUrl;
144
+ }
145
+ }
146
+ }
147
+
148
+ return gitInfo;
149
+ } catch (error) {
150
+ logger.trace(`Failed to get git info: ${error}`);
151
+ return undefined;
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Merge auto-detected git info with CLI-provided overrides.
157
+ * CLI options take precedence over auto-detected values.
158
+ *
159
+ * @param autoDetected - Git info auto-detected from the repository
160
+ * @param overrides - CLI options that override auto-detected values
161
+ * @returns Merged git info
162
+ */
163
+ export function mergeGitInfo(
164
+ autoDetected: GitInfo | undefined,
165
+ overrides: GitOptions
166
+ ): GitInfoExtended {
167
+ const result: GitInfoExtended = { ...(autoDetected ?? {}) };
168
+
169
+ // CLI overrides take precedence
170
+ if (overrides.message !== undefined) {
171
+ result.message = overrides.message;
172
+ }
173
+ if (overrides.commit !== undefined) {
174
+ result.commit = overrides.commit;
175
+ }
176
+ if (overrides.branch !== undefined) {
177
+ result.branch = overrides.branch;
178
+ }
179
+ if (overrides.repo !== undefined) {
180
+ result.repo = overrides.repo;
181
+ }
182
+ if (overrides.provider !== undefined) {
183
+ result.provider = overrides.provider;
184
+ }
185
+ if (overrides.commitUrl !== undefined) {
186
+ result.commitUrl = overrides.commitUrl;
187
+ }
188
+
189
+ return result;
190
+ }
191
+
192
+ /**
193
+ * Build an array of tags from git info, including branch and short commit.
194
+ * Used for deployment tagging.
195
+ *
196
+ * @param gitInfo - Git information
197
+ * @returns Array of tags
198
+ */
199
+ export function buildGitTags(gitInfo: GitInfo | undefined): string[] {
200
+ const tags = new Set(gitInfo?.tags ?? []);
201
+ tags.add('latest');
202
+ if (gitInfo?.branch) {
203
+ tags.add(gitInfo.branch);
204
+ }
205
+ if (gitInfo?.commit) {
206
+ tags.add(gitInfo.commit.substring(0, 7));
207
+ }
208
+ return Array.from(tags);
209
+ }