Skip to content

Commit 8007f7d

Browse files
feat(agents): add rename and archive commands
- agents:rename sets a run's title, sanitized and capped at 200 chars - agents:archive archives a run, with --yes to skip confirmation Part 7/8 of splitting #8237.
1 parent 81b8098 commit 8007f7d

7 files changed

Lines changed: 503 additions & 0 deletions

File tree

docs/commands/agents.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ netlify agents
2727

2828
| Subcommand | description |
2929
|:--------------------------- |:-----|
30+
| [`agents:archive`](/commands/agents#agentsarchive) | Archive an agent run |
3031
| [`agents:commit`](/commands/agents#agentscommit) | Commit an agent run’s changes directly to a branch |
3132
| [`agents:create`](/commands/agents#agentscreate) | Create and start a new agent run on your site |
3233
| [`agents:diff`](/commands/agents#agentsdiff) | Print the code changes produced by an agent run |
@@ -35,6 +36,7 @@ netlify agents
3536
| [`agents:pr`](/commands/agents#agentspr) | Open a pull request for an agent run |
3637
| [`agents:publish`](/commands/agents#agentspublish) | Publish an agent run’s changes to production |
3738
| [`agents:redeploy`](/commands/agents#agentsredeploy) | Redeploy an agent run by reapplying its existing changes (no AI inference) |
39+
| [`agents:rename`](/commands/agents#agentsrename) | Rename an agent run |
3840
| [`agents:revert`](/commands/agents#agentsrevert) | Revert an agent run to a specific session (sessions after it are discarded) |
3941
| [`agents:show`](/commands/agents#agentsshow) | Show details of a specific agent run |
4042
| [`agents:stop`](/commands/agents#agentsstop) | Stop a running agent run |
@@ -51,6 +53,37 @@ netlify agents:diff 60c7c3b3e7b4a0001f5e4b3a
5153
netlify agents:open 60c7c3b3e7b4a0001f5e4b3a
5254
```
5355

56+
---
57+
## `agents:archive`
58+
59+
Archive an agent run
60+
61+
**Usage**
62+
63+
```bash
64+
netlify agents:archive
65+
```
66+
67+
**Arguments**
68+
69+
- id - agent run ID
70+
71+
**Flags**
72+
73+
- `filter` (*string*) - For monorepos, specify the name of the application to run the command in
74+
- `json` (*boolean*) - output result as JSON
75+
- `project` (*string*) - project ID or name (if not in a linked directory)
76+
- `yes` (*boolean*) - skip confirmation prompt
77+
- `debug` (*boolean*) - Print debugging information
78+
- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in
79+
80+
**Examples**
81+
82+
```bash
83+
netlify agents:archive 60c7c3b3e7b4a0001f5e4b3a
84+
netlify agents:archive 60c7c3b3e7b4a0001f5e4b3a --yes
85+
```
86+
5487
---
5588
## `agents:commit`
5689

@@ -322,6 +355,36 @@ netlify agents:redeploy 60c7c3b3e7b4a0001f5e4b3a
322355
netlify agents:redeploy 60c7c3b3e7b4a0001f5e4b3a --session 70d8...
323356
```
324357

358+
---
359+
## `agents:rename`
360+
361+
Rename an agent run
362+
363+
**Usage**
364+
365+
```bash
366+
netlify agents:rename
367+
```
368+
369+
**Arguments**
370+
371+
- id - agent run ID
372+
- title - new title for the agent run
373+
374+
**Flags**
375+
376+
- `filter` (*string*) - For monorepos, specify the name of the application to run the command in
377+
- `json` (*boolean*) - output result as JSON
378+
- `project` (*string*) - project ID or name (if not in a linked directory)
379+
- `debug` (*boolean*) - Print debugging information
380+
- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in
381+
382+
**Examples**
383+
384+
```bash
385+
netlify agents:rename 60c7c3b3e7b4a0001f5e4b3a "Add dark mode toggle"
386+
```
387+
325388
---
326389
## `agents:revert`
327390

docs/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Manage Netlify AI agent runs
2424

2525
| Subcommand | description |
2626
|:--------------------------- |:-----|
27+
| [`agents:archive`](/commands/agents#agentsarchive) | Archive an agent run |
2728
| [`agents:commit`](/commands/agents#agentscommit) | Commit an agent run’s changes directly to a branch |
2829
| [`agents:create`](/commands/agents#agentscreate) | Create and start a new agent run on your site |
2930
| [`agents:diff`](/commands/agents#agentsdiff) | Print the code changes produced by an agent run |
@@ -32,6 +33,7 @@ Manage Netlify AI agent runs
3233
| [`agents:pr`](/commands/agents#agentspr) | Open a pull request for an agent run |
3334
| [`agents:publish`](/commands/agents#agentspublish) | Publish an agent run’s changes to production |
3435
| [`agents:redeploy`](/commands/agents#agentsredeploy) | Redeploy an agent run by reapplying its existing changes (no AI inference) |
36+
| [`agents:rename`](/commands/agents#agentsrename) | Rename an agent run |
3537
| [`agents:revert`](/commands/agents#agentsrevert) | Revert an agent run to a specific session (sessions after it are discarded) |
3638
| [`agents:show`](/commands/agents#agentsshow) | Show details of a specific agent run |
3739
| [`agents:stop`](/commands/agents#agentsstop) | Stop a running agent run |
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import type { OptionValues } from 'commander'
2+
import inquirer from 'inquirer'
3+
4+
import { chalk, exit, log, logAndThrowError, logJson } from '../../utils/command-helpers.js'
5+
import { startSpinner, stopSpinner } from '../../lib/spinner.js'
6+
import type BaseCommand from '../base-command.js'
7+
import { createAgentsApi } from './api.js'
8+
9+
interface AgentArchiveOptions extends OptionValues {
10+
json?: boolean
11+
yes?: boolean
12+
}
13+
14+
export const agentsArchive = async (id: string, options: AgentArchiveOptions, command: BaseCommand) => {
15+
if (!id) return logAndThrowError('Agent run ID is required')
16+
await command.authenticate()
17+
const api = createAgentsApi(command.netlify)
18+
19+
if (!options.yes && !options.json) {
20+
if (!process.stdin.isTTY) {
21+
return logAndThrowError('Refusing to archive without --yes when stdin is not a TTY')
22+
}
23+
const { confirmed } = await inquirer.prompt<{ confirmed: boolean }>([
24+
{
25+
type: 'confirm',
26+
name: 'confirmed',
27+
message: `Archive agent run ${id}?`,
28+
default: false,
29+
},
30+
])
31+
if (!confirmed) return exit()
32+
}
33+
34+
const spinner = startSpinner({ text: 'Archiving agent run...' })
35+
try {
36+
await api.archiveAgentRunner(id)
37+
stopSpinner({ spinner })
38+
39+
const result = { success: true, id }
40+
if (options.json) {
41+
logJson(result)
42+
return result
43+
}
44+
45+
log(`${chalk.green('✓')} Agent run archived.`)
46+
log(` Run ID: ${chalk.cyan(id)}`)
47+
return result
48+
} catch (error_) {
49+
stopSpinner({ spinner, error: true })
50+
const error = error_ as Error & { status?: number }
51+
if (error.status === 404) return logAndThrowError(`Agent run not found: ${id}`)
52+
return logAndThrowError(`Failed to archive: ${error.message}`)
53+
}
54+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import type { OptionValues } from 'commander'
2+
3+
import { chalk, log, logAndThrowError, logJson } from '../../utils/command-helpers.js'
4+
import { startSpinner, stopSpinner } from '../../lib/spinner.js'
5+
import type BaseCommand from '../base-command.js'
6+
import { createAgentsApi } from './api.js'
7+
import { sanitizeRunnerTitle, validateRunnerTitle } from './utils.js'
8+
9+
interface AgentRenameOptions extends OptionValues {
10+
json?: boolean
11+
}
12+
13+
export const agentsRename = async (id: string, title: string, options: AgentRenameOptions, command: BaseCommand) => {
14+
if (!id) return logAndThrowError('Agent run ID is required')
15+
const valid = validateRunnerTitle(title)
16+
if (valid !== true) return logAndThrowError(valid)
17+
const sanitized = sanitizeRunnerTitle(title)
18+
19+
await command.authenticate()
20+
const api = createAgentsApi(command.netlify)
21+
22+
const spinner = startSpinner({ text: 'Renaming agent run...' })
23+
try {
24+
const runner = await api.updateAgentRunner(id, { title: sanitized })
25+
stopSpinner({ spinner })
26+
27+
if (options.json) {
28+
logJson(runner)
29+
return runner
30+
}
31+
32+
log(`${chalk.green('✓')} Agent run renamed.`)
33+
log(` Run ID: ${chalk.cyan(runner.id)}`)
34+
log(` Title: ${chalk.cyan(runner.title ?? sanitized)}`)
35+
return runner
36+
} catch (error_) {
37+
stopSpinner({ spinner, error: true })
38+
const error = error_ as Error & { status?: number }
39+
if (error.status === 404) return logAndThrowError(`Agent run not found: ${id}`)
40+
return logAndThrowError(`Failed to rename: ${error.message}`)
41+
}
42+
}

src/commands/agents/agents.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,23 @@ export const createAgentsCommand = (program: BaseCommand) => {
201201
await agentsRevert(id, options, command)
202202
})
203203

204+
program
205+
.command('agents:archive')
206+
.argument('<id>', 'agent run ID')
207+
.description('Archive an agent run')
208+
.option('-y, --yes', 'skip confirmation prompt')
209+
.option('--json', 'output result as JSON')
210+
.option('--project <project>', 'project ID or name (if not in a linked directory)')
211+
.hook('preAction', requiresSiteInfoWithProject)
212+
.addExamples([
213+
'netlify agents:archive 60c7c3b3e7b4a0001f5e4b3a',
214+
'netlify agents:archive 60c7c3b3e7b4a0001f5e4b3a --yes',
215+
])
216+
.action(async (id: string, options: OptionValues, command: BaseCommand) => {
217+
const { agentsArchive } = await import('./agents-archive.js')
218+
await agentsArchive(id, options, command)
219+
})
220+
204221
program
205222
.command('agents:redeploy')
206223
.argument('<id>', 'agent run ID')
@@ -218,6 +235,20 @@ export const createAgentsCommand = (program: BaseCommand) => {
218235
await agentsRedeploy(id, options, command)
219236
})
220237

238+
program
239+
.command('agents:rename')
240+
.argument('<id>', 'agent run ID')
241+
.argument('<title>', 'new title for the agent run')
242+
.description('Rename an agent run')
243+
.option('--json', 'output result as JSON')
244+
.option('--project <project>', 'project ID or name (if not in a linked directory)')
245+
.hook('preAction', requiresSiteInfoWithProject)
246+
.addExamples(['netlify agents:rename 60c7c3b3e7b4a0001f5e4b3a "Add dark mode toggle"'])
247+
.action(async (id: string, title: string, options: OptionValues, command: BaseCommand) => {
248+
const { agentsRename } = await import('./agents-rename.js')
249+
await agentsRename(id, title, options, command)
250+
})
251+
221252
program
222253
.command('agents:sync')
223254
.argument('<id>', 'agent run ID')

0 commit comments

Comments
 (0)