Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions docs/commands/agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ netlify agents

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

---
## `agents:archive`

Archive an agent run

**Usage**

```bash
netlify agents:archive
```

**Arguments**

- id - agent run ID

**Flags**

- `filter` (*string*) - For monorepos, specify the name of the application to run the command in
- `json` (*boolean*) - output result as JSON
- `project` (*string*) - project ID or name (if not in a linked directory)
- `yes` (*boolean*) - skip confirmation prompt
- `debug` (*boolean*) - Print debugging information
- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in

**Examples**

```bash
netlify agents:archive 60c7c3b3e7b4a0001f5e4b3a
netlify agents:archive 60c7c3b3e7b4a0001f5e4b3a --yes
```

---
## `agents:commit`

Expand Down Expand Up @@ -322,6 +355,36 @@ netlify agents:redeploy 60c7c3b3e7b4a0001f5e4b3a
netlify agents:redeploy 60c7c3b3e7b4a0001f5e4b3a --session 70d8...
```

---
## `agents:rename`

Rename an agent run

**Usage**

```bash
netlify agents:rename
```

**Arguments**

- id - agent run ID
- title - new title for the agent run

**Flags**

- `filter` (*string*) - For monorepos, specify the name of the application to run the command in
- `json` (*boolean*) - output result as JSON
- `project` (*string*) - project ID or name (if not in a linked directory)
- `debug` (*boolean*) - Print debugging information
- `auth` (*string*) - Netlify auth token - can be used to run this command without logging in

**Examples**

```bash
netlify agents:rename 60c7c3b3e7b4a0001f5e4b3a "Add dark mode toggle"
```

---
## `agents:revert`

Expand Down
2 changes: 2 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Manage Netlify AI agent runs

| Subcommand | description |
|:--------------------------- |:-----|
| [`agents:archive`](/commands/agents#agentsarchive) | Archive an agent run |
| [`agents:commit`](/commands/agents#agentscommit) | Commit an agent run’s changes directly to a branch |
| [`agents:create`](/commands/agents#agentscreate) | Create and start a new agent run on your site |
| [`agents:diff`](/commands/agents#agentsdiff) | Print the code changes produced by an agent run |
Expand All @@ -32,6 +33,7 @@ Manage Netlify AI agent runs
| [`agents:pr`](/commands/agents#agentspr) | Open a pull request for an agent run |
| [`agents:publish`](/commands/agents#agentspublish) | Publish an agent run’s changes to production |
| [`agents:redeploy`](/commands/agents#agentsredeploy) | Redeploy an agent run by reapplying its existing changes (no AI inference) |
| [`agents:rename`](/commands/agents#agentsrename) | Rename an agent run |
| [`agents:revert`](/commands/agents#agentsrevert) | Revert an agent run to a specific session (sessions after it are discarded) |
| [`agents:show`](/commands/agents#agentsshow) | Show details of a specific agent run |
| [`agents:stop`](/commands/agents#agentsstop) | Stop a running agent run |
Expand Down
54 changes: 54 additions & 0 deletions src/commands/agents/agents-archive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type { OptionValues } from 'commander'
import inquirer from 'inquirer'

import { chalk, exit, log, logAndThrowError, logJson } from '../../utils/command-helpers.js'
import { startSpinner, stopSpinner } from '../../lib/spinner.js'
import type BaseCommand from '../base-command.js'
import { createAgentsApi } from './api.js'

interface AgentArchiveOptions extends OptionValues {
json?: boolean
yes?: boolean
}

export const agentsArchive = async (id: string, options: AgentArchiveOptions, command: BaseCommand) => {
if (!id) return logAndThrowError('Agent run ID is required')
await command.authenticate()
const api = createAgentsApi(command.netlify)

if (!options.yes && !options.json) {
if (!process.stdin.isTTY) {
return logAndThrowError('Refusing to archive without --yes when stdin is not a TTY')
}
const { confirmed } = await inquirer.prompt<{ confirmed: boolean }>([
{
type: 'confirm',
name: 'confirmed',
message: `Archive agent run ${id}?`,
default: false,
},
])
if (!confirmed) return exit()
}

const spinner = startSpinner({ text: 'Archiving agent run...' })
try {
await api.archiveAgentRunner(id)
stopSpinner({ spinner })

const result = { success: true, id }
if (options.json) {
logJson(result)
return result
}

log(`${chalk.green('✓')} Agent run archived.`)
log(` Run ID: ${chalk.cyan(id)}`)
return result
} catch (error_) {
stopSpinner({ spinner, error: true })
const error = error_ as Error & { status?: number }
if (error.status === 404) return logAndThrowError(`Agent run not found: ${id}`)
return logAndThrowError(`Failed to archive: ${error.message}`)
}
}
42 changes: 42 additions & 0 deletions src/commands/agents/agents-rename.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { OptionValues } from 'commander'

import { chalk, log, logAndThrowError, logJson } from '../../utils/command-helpers.js'
import { startSpinner, stopSpinner } from '../../lib/spinner.js'
import type BaseCommand from '../base-command.js'
import { createAgentsApi } from './api.js'
import { sanitizeRunnerTitle, validateRunnerTitle } from './utils.js'

interface AgentRenameOptions extends OptionValues {
json?: boolean
}

export const agentsRename = async (id: string, title: string, options: AgentRenameOptions, command: BaseCommand) => {
if (!id) return logAndThrowError('Agent run ID is required')
const valid = validateRunnerTitle(title)
if (valid !== true) return logAndThrowError(valid)
const sanitized = sanitizeRunnerTitle(title)

await command.authenticate()
const api = createAgentsApi(command.netlify)

const spinner = startSpinner({ text: 'Renaming agent run...' })
try {
const runner = await api.updateAgentRunner(id, { title: sanitized })
stopSpinner({ spinner })

if (options.json) {
logJson(runner)
return runner
}

log(`${chalk.green('✓')} Agent run renamed.`)
log(` Run ID: ${chalk.cyan(runner.id)}`)
log(` Title: ${chalk.cyan(runner.title ?? sanitized)}`)
return runner
} catch (error_) {
stopSpinner({ spinner, error: true })
const error = error_ as Error & { status?: number }
if (error.status === 404) return logAndThrowError(`Agent run not found: ${id}`)
return logAndThrowError(`Failed to rename: ${error.message}`)
}
}
31 changes: 31 additions & 0 deletions src/commands/agents/agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,23 @@ export const createAgentsCommand = (program: BaseCommand) => {
await agentsRevert(id, options, command)
})

program
.command('agents:archive')
.argument('<id>', 'agent run ID')
.description('Archive an agent run')
.option('-y, --yes', 'skip confirmation prompt')
.option('--json', 'output result as JSON')
.option('--project <project>', 'project ID or name (if not in a linked directory)')
.hook('preAction', requiresSiteInfoWithProject)
.addExamples([
'netlify agents:archive 60c7c3b3e7b4a0001f5e4b3a',
'netlify agents:archive 60c7c3b3e7b4a0001f5e4b3a --yes',
])
.action(async (id: string, options: OptionValues, command: BaseCommand) => {
const { agentsArchive } = await import('./agents-archive.js')
await agentsArchive(id, options, command)
})

program
.command('agents:redeploy')
.argument('<id>', 'agent run ID')
Expand All @@ -218,6 +235,20 @@ export const createAgentsCommand = (program: BaseCommand) => {
await agentsRedeploy(id, options, command)
})

program
.command('agents:rename')
.argument('<id>', 'agent run ID')
.argument('<title>', 'new title for the agent run')
.description('Rename an agent run')
.option('--json', 'output result as JSON')
.option('--project <project>', 'project ID or name (if not in a linked directory)')
.hook('preAction', requiresSiteInfoWithProject)
.addExamples(['netlify agents:rename 60c7c3b3e7b4a0001f5e4b3a "Add dark mode toggle"'])
.action(async (id: string, title: string, options: OptionValues, command: BaseCommand) => {
const { agentsRename } = await import('./agents-rename.js')
await agentsRename(id, title, options, command)
})

program
.command('agents:sync')
.argument('<id>', 'agent run ID')
Expand Down
Loading
Loading