@frontera-sdk/cli 1.49.0 → 1.50.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frontera-sdk/cli",
3
- "version": "1.49.0",
3
+ "version": "1.50.1",
4
4
  "description": "The frontera CLI — scaffold, pull, save and deploy Frontera apps and automations.",
5
5
  "keywords": [
6
6
  "frontera",
@@ -39,14 +39,14 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@anthropic-ai/claude-agent-sdk": "^0.3.251",
42
- "@frontera-sdk/automation": "1.49.0",
43
- "@frontera-sdk/core": "1.49.0",
42
+ "@frontera-sdk/functions": "1.50.1",
43
+ "@frontera-sdk/core": "1.50.1",
44
44
  "ai": "^6.0.116",
45
45
  "gray-matter": "^4.0.3",
46
46
  "yaml": "^2.9.0"
47
47
  },
48
48
  "devDependencies": {
49
- "@frontera-sdk/forge-contracts": "1.49.0",
49
+ "@frontera-sdk/forge-contracts": "1.50.1",
50
50
  "@types/bun": "^1.3.14",
51
51
  "typescript": "^5.9.3"
52
52
  }
@@ -3,7 +3,7 @@ import { FronteraError } from '@frontera-sdk/core/errors'
3
3
 
4
4
  import { CliError } from '../errors'
5
5
 
6
- /** A row of `GET /v1/automations/` — the shell, not any one version of it. */
6
+ /** A row of `GET /v1/functions/` — the shell, not any one version of it. */
7
7
  export interface AutomationSummary {
8
8
  id: string
9
9
  slug: string
@@ -73,7 +73,7 @@ export interface AutomationDeployResult {
73
73
  runnerLastSeenAt?: string | null
74
74
  }
75
75
 
76
- /** A row of `GET /v1/automations/<slug>/runs`. */
76
+ /** A row of `GET /v1/functions/<slug>/runs`. */
77
77
  export interface AutomationRunSummary {
78
78
  id: string
79
79
  status: string
@@ -103,7 +103,7 @@ export interface AutomationRunSummary {
103
103
  input?: Record<string, unknown> | null
104
104
  }
105
105
 
106
- /** A row of `GET /v1/automations/runs/<id>/steps`. */
106
+ /** A row of `GET /v1/functions/runs/<id>/steps`. */
107
107
  export interface AutomationRunStep {
108
108
  id: string
109
109
  seq: number
@@ -127,7 +127,7 @@ export interface AutomationRunStep {
127
127
  detail?: Record<string, unknown>
128
128
  }
129
129
 
130
- /** `GET /v1/automations/registry-status`. */
130
+ /** `GET /v1/functions/registry-status`. */
131
131
  export interface RegistryStatus {
132
132
  /** The generation the service has. */
133
133
  generation: number
@@ -174,18 +174,18 @@ export class AutomationApi {
174
174
  }
175
175
 
176
176
  list(): Promise<AutomationSummary[]> {
177
- return this.client.request<AutomationSummary[]>('/v1/automations/')
177
+ return this.client.request<AutomationSummary[]>('/v1/functions/')
178
178
  }
179
179
 
180
180
  versions(slug: string): Promise<AutomationVersionSummary[]> {
181
181
  return this.client.request<AutomationVersionSummary[]>(
182
- `/v1/automations/${encodeURIComponent(slug)}/versions`,
182
+ `/v1/functions/${encodeURIComponent(slug)}/versions`,
183
183
  )
184
184
  }
185
185
 
186
186
  promote(slug: string, version: number): Promise<{ slug: string; version: number }> {
187
187
  return this.client.request<{ slug: string; version: number }>(
188
- `/v1/automations/${encodeURIComponent(slug)}/promote/${version}`,
188
+ `/v1/functions/${encodeURIComponent(slug)}/promote/${version}`,
189
189
  { method: 'POST' },
190
190
  )
191
191
  }
@@ -220,7 +220,7 @@ export class AutomationApi {
220
220
  : version === undefined && input === undefined
221
221
  ? undefined
222
222
  : { ...(version === undefined ? {} : { version }), ...(input === undefined ? {} : { input }) }
223
- return this.client.request(`/v1/automations/${encodeURIComponent(slug)}/run`, {
223
+ return this.client.request(`/v1/functions/${encodeURIComponent(slug)}/run`, {
224
224
  method: 'POST',
225
225
  body,
226
226
  })
@@ -241,7 +241,7 @@ export class AutomationApi {
241
241
  leaseMs: number
242
242
  }> {
243
243
  return this.client.request(
244
- `/v1/automations/${encodeURIComponent(slug)}/dev/session`,
244
+ `/v1/functions/${encodeURIComponent(slug)}/dev/session`,
245
245
  { method: 'POST', body: { entryFile, holderId } },
246
246
  )
247
247
  }
@@ -278,7 +278,7 @@ export class AutomationApi {
278
278
  }> {
279
279
  const q = `sessionId=${encodeURIComponent(sessionId)}&holderId=${encodeURIComponent(holderId)}`
280
280
  return this.client.request(
281
- `/v1/automations/${encodeURIComponent(slug)}/dev/poll?${q}`,
281
+ `/v1/functions/${encodeURIComponent(slug)}/dev/poll?${q}`,
282
282
  { method: 'POST', body: { manifest } },
283
283
  )
284
284
  }
@@ -290,13 +290,13 @@ export class AutomationApi {
290
290
  ): Promise<{ closed: boolean }> {
291
291
  const q = `sessionId=${encodeURIComponent(sessionId)}&holderId=${encodeURIComponent(holderId)}`
292
292
  return this.client.request(
293
- `/v1/automations/${encodeURIComponent(slug)}/dev/session?${q}`,
293
+ `/v1/functions/${encodeURIComponent(slug)}/dev/session?${q}`,
294
294
  { method: 'DELETE' },
295
295
  )
296
296
  }
297
297
 
298
298
  registryStatus(): Promise<RegistryStatus> {
299
- return this.client.request<RegistryStatus>('/v1/automations/registry-status')
299
+ return this.client.request<RegistryStatus>('/v1/functions/registry-status')
300
300
  }
301
301
 
302
302
  /**
@@ -317,7 +317,7 @@ export class AutomationApi {
317
317
  if (mode === 'dev') params.set('mode', 'dev')
318
318
  const query = params.size > 0 ? `?${params}` : ''
319
319
  return this.client.request<AutomationRunSummary[]>(
320
- `/v1/automations/${encodeURIComponent(slug)}/runs${query}`,
320
+ `/v1/functions/${encodeURIComponent(slug)}/runs${query}`,
321
321
  )
322
322
  }
323
323
 
@@ -332,7 +332,7 @@ export class AutomationApi {
332
332
  */
333
333
  runById(slug: string, runId: string): Promise<AutomationRunSummary> {
334
334
  return this.client.request<AutomationRunSummary>(
335
- `/v1/automations/${encodeURIComponent(slug)}/runs/${encodeURIComponent(runId)}`,
335
+ `/v1/functions/${encodeURIComponent(slug)}/runs/${encodeURIComponent(runId)}`,
336
336
  )
337
337
  }
338
338
 
@@ -340,7 +340,7 @@ export class AutomationApi {
340
340
  * nothing. */
341
341
  runSteps(runId: string): Promise<AutomationRunStep[]> {
342
342
  return this.client.request<AutomationRunStep[]>(
343
- `/v1/automations/runs/${encodeURIComponent(runId)}/steps`,
343
+ `/v1/functions/runs/${encodeURIComponent(runId)}/steps`,
344
344
  )
345
345
  }
346
346
 
@@ -353,7 +353,7 @@ export class AutomationApi {
353
353
  */
354
354
  bindings(slug: string): Promise<AgentAutomationBinding[]> {
355
355
  return this.client.request<AgentAutomationBinding[]>(
356
- `/v1/automations/${encodeURIComponent(slug)}/bindings`,
356
+ `/v1/functions/${encodeURIComponent(slug)}/bindings`,
357
357
  )
358
358
  }
359
359
 
@@ -363,7 +363,7 @@ export class AutomationApi {
363
363
  options: { enabled?: boolean; requiresApproval?: boolean; waitSeconds?: number } = {},
364
364
  ): Promise<AgentAutomationBinding> {
365
365
  return this.client.request<AgentAutomationBinding>(
366
- `/v1/automations/${encodeURIComponent(slug)}/bindings/${encodeURIComponent(agentSlug)}`,
366
+ `/v1/functions/${encodeURIComponent(slug)}/bindings/${encodeURIComponent(agentSlug)}`,
367
367
  { method: 'PUT', body: options },
368
368
  )
369
369
  }
@@ -371,20 +371,20 @@ export class AutomationApi {
371
371
  /** The same question from the agent's side: what may this agent start? */
372
372
  agentBindings(agentSlug: string): Promise<AgentBindingView[]> {
373
373
  return this.client.request<AgentBindingView[]>(
374
- `/v1/automations/agent-bindings/${encodeURIComponent(agentSlug)}`,
374
+ `/v1/functions/agent-bindings/${encodeURIComponent(agentSlug)}`,
375
375
  )
376
376
  }
377
377
 
378
378
  unbind(slug: string, agentSlug: string): Promise<{ unbound: boolean }> {
379
379
  return this.client.request<{ unbound: boolean }>(
380
- `/v1/automations/${encodeURIComponent(slug)}/bindings/${encodeURIComponent(agentSlug)}`,
380
+ `/v1/functions/${encodeURIComponent(slug)}/bindings/${encodeURIComponent(agentSlug)}`,
381
381
  { method: 'DELETE' },
382
382
  )
383
383
  }
384
384
 
385
385
  setEnabled(slug: string, enabled: boolean): Promise<{ slug: string; enabled: boolean }> {
386
386
  return this.client.request<{ slug: string; enabled: boolean }>(
387
- `/v1/automations/${encodeURIComponent(slug)}/enabled`,
387
+ `/v1/functions/${encodeURIComponent(slug)}/enabled`,
388
388
  { method: 'POST', body: { enabled } },
389
389
  )
390
390
  }
@@ -401,7 +401,7 @@ export class AutomationApi {
401
401
  async downloadSource(slug: string, version: number): Promise<Uint8Array> {
402
402
  const credential = this.client.config.credential
403
403
  const res = await fetch(
404
- `${this.client.config.apiBaseUrl}/v1/automations/${encodeURIComponent(slug)}`
404
+ `${this.client.config.apiBaseUrl}/v1/functions/${encodeURIComponent(slug)}`
405
405
  + `/versions/${version}/source`,
406
406
  {
407
407
  headers: {
@@ -432,8 +432,8 @@ export class AutomationApi {
432
432
  throw new CliError(message, {
433
433
  code: res.status === 404 ? 'NOT_FOUND' : 'REQUEST_FAILED',
434
434
  hint: res.status === 404
435
- ? `frontera automation deploy <file> (from a local copy of ${slug})`
436
- : `frontera automation versions ${slug}`,
435
+ ? `frontera function deploy <file> (from a local copy of ${slug})`
436
+ : `frontera function versions ${slug}`,
437
437
  })
438
438
  }
439
439
  return new Uint8Array(await res.arrayBuffer())
@@ -457,7 +457,7 @@ export class AutomationApi {
457
457
 
458
458
  const credential = this.client.config.credential
459
459
  const res = await fetch(
460
- `${this.client.config.apiBaseUrl}/v1/automations/${encodeURIComponent(slug)}/versions`,
460
+ `${this.client.config.apiBaseUrl}/v1/functions/${encodeURIComponent(slug)}/versions`,
461
461
  {
462
462
  method: 'POST',
463
463
  headers: {
@@ -48,7 +48,7 @@ export const AUTOMATION_SDK_FILES = [
48
48
  * The files a new automation project contains.
49
49
  *
50
50
  * The SDK is written into `src/frontera/` rather than declared as a dependency:
51
- * `@frontera-sdk/automation` is `private: true` and `workspace:*`, so it resolves
51
+ * `@frontera-sdk/functions` is `private: true` and `workspace:*`, so it resolves
52
52
  * nowhere outside this monorepo — which is the entire problem Phase B exists to
53
53
  * solve. `package.json` therefore asks for nothing but public npm.
54
54
  */
@@ -77,7 +77,7 @@ export function automationScaffoldFiles(name: string): Record<string, string> {
77
77
  // A handler is testable without deploying — `createTestContext` is what
78
78
  // the starter test uses — so the project ships with somewhere to run it.
79
79
  test: 'bun test',
80
- deploy: 'frontera automation deploy src/index.ts',
80
+ deploy: 'frontera function deploy src/index.ts',
81
81
  },
82
82
  dependencies: {
83
83
  // The vendored `frontera/automation/manifest.ts` imports it to validate
@@ -107,8 +107,8 @@ export function automationScaffoldFiles(name: string): Record<string, string> {
107
107
  // detail, so publishing the packages later is deleting these lines.
108
108
  baseUrl: '.',
109
109
  paths: {
110
- '@frontera-sdk/automation': ['./src/frontera/automation/index.ts'],
111
- '@frontera-sdk/automation/*': ['./src/frontera/automation/*'],
110
+ '@frontera-sdk/functions': ['./src/frontera/automation/index.ts'],
111
+ '@frontera-sdk/functions/*': ['./src/frontera/automation/*'],
112
112
  '@frontera-sdk/blueprint/types': ['./src/frontera/blueprint/types.ts'],
113
113
  '@frontera-sdk/blueprint/*': ['./src/frontera/blueprint/*'],
114
114
  },
@@ -116,7 +116,7 @@ export function automationScaffoldFiles(name: string): Record<string, string> {
116
116
  include: ['src'],
117
117
  }, null, 2) + '\n'
118
118
 
119
- out['src/index.ts'] = `import { automation } from '@frontera-sdk/automation'
119
+ out['src/index.ts'] = `import { automation } from '@frontera-sdk/functions'
120
120
 
121
121
  /**
122
122
  * The object type this reads. CHANGE THIS to one of yours —
@@ -177,7 +177,7 @@ export default automation(
177
177
  `
178
178
 
179
179
  out['src/index.test.ts'] = `import { expect, test } from 'bun:test'
180
- import { createTestContext } from '@frontera-sdk/automation'
180
+ import { createTestContext } from '@frontera-sdk/functions'
181
181
 
182
182
  import automation, { OBJECT_TYPE } from './index'
183
183
 
@@ -215,7 +215,7 @@ test('handles rows', async () => {
215
215
  \`\`\`bash
216
216
  bun install
217
217
  bun run typecheck
218
- frontera automation deploy src/index.ts
218
+ frontera function deploy src/index.ts
219
219
  \`\`\`
220
220
 
221
221
  The SDK is vendored into \`src/frontera/\` and resolved by the \`paths\` in
@@ -223,7 +223,7 @@ The SDK is vendored into \`src/frontera/\` and resolved by the \`paths\` in
223
223
  packages are unpublished, and the vendored copy is what makes this project build
224
224
  on a machine that has never seen the Frontera monorepo.
225
225
 
226
- \`frontera automation pull ${name}\` recovers this project from any deployed
226
+ \`frontera function pull ${name}\` recovers this project from any deployed
227
227
  version. A \`.env\` here is never uploaded.
228
228
  `
229
229
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `frontera automation bind|unbind|bindings` — the operator's half of making an
2
+ * `frontera function bind|unbind|bindings` — the operator's half of making an
3
3
  * automation callable from a conversation.
4
4
  *
5
5
  * The author's half is in the manifest (`trigger: { agent: true }`, plus a
@@ -21,7 +21,7 @@ function requireSlug(ctx: CommandContext): string {
21
21
  if (!slug) {
22
22
  throw new UsageError(
23
23
  'missing <slug>',
24
- 'run `frontera automation list` — then pass the slug of the one you mean',
24
+ 'run `frontera function list` — then pass the slug of the one you mean',
25
25
  )
26
26
  }
27
27
  return slug
@@ -40,15 +40,15 @@ function requireAgent(ctx: CommandContext): string {
40
40
 
41
41
  const bind: Command = {
42
42
  meta: {
43
- noun: 'automation',
43
+ noun: 'function',
44
44
  verb: 'bind',
45
45
  args: [{ name: 'slug', required: true, description: 'automation slug' }],
46
46
  flags: { agent: 'string', approval: 'string', wait: 'string' },
47
47
  summary: 'Let one agent run this automation from a conversation',
48
48
  examples: [
49
- 'frontera automation bind reconcile-invoices --agent finance-analyst',
50
- 'frontera automation bind reconcile-invoices --agent analyst --approval auto',
51
- 'frontera automation bind reconcile-invoices --agent analyst --wait 120',
49
+ 'frontera function bind reconcile-invoices --agent finance-analyst',
50
+ 'frontera function bind reconcile-invoices --agent analyst --approval auto',
51
+ 'frontera function bind reconcile-invoices --agent analyst --wait 120',
52
52
  ],
53
53
  },
54
54
 
@@ -93,12 +93,12 @@ const bind: Command = {
93
93
 
94
94
  const unbind: Command = {
95
95
  meta: {
96
- noun: 'automation',
96
+ noun: 'function',
97
97
  verb: 'unbind',
98
98
  args: [{ name: 'slug', required: true, description: 'automation slug' }],
99
99
  flags: { agent: 'string' },
100
100
  summary: 'Stop one agent being able to run this automation',
101
- examples: ['frontera automation unbind reconcile-invoices --agent finance-analyst'],
101
+ examples: ['frontera function unbind reconcile-invoices --agent finance-analyst'],
102
102
  },
103
103
 
104
104
  async run(ctx) {
@@ -117,7 +117,7 @@ const unbind: Command = {
117
117
  */
118
118
  const bindings: Command = {
119
119
  meta: {
120
- noun: 'automation',
120
+ noun: 'function',
121
121
  verb: 'bindings',
122
122
  args: [
123
123
  {
@@ -129,8 +129,8 @@ const bindings: Command = {
129
129
  flags: { agent: 'string' },
130
130
  summary: 'List the agents that may run an automation, or what one agent may run',
131
131
  examples: [
132
- 'frontera automation bindings reconcile-invoices',
133
- 'frontera automation bindings --agent finance-analyst',
132
+ 'frontera function bindings reconcile-invoices',
133
+ 'frontera function bindings --agent finance-analyst',
134
134
  ],
135
135
  },
136
136
 
@@ -2,15 +2,15 @@ import { mkdtempSync, statSync } from 'node:fs'
2
2
  import { tmpdir } from 'node:os'
3
3
  import { join, resolve } from 'node:path'
4
4
 
5
- import { buildContext } from '@frontera-sdk/automation/runtime'
5
+ import { buildContext } from '@frontera-sdk/functions/runtime'
6
6
  import { AutomationApi } from '../../api/automation-api'
7
7
  import { CliError, UsageError } from '../../errors'
8
8
  import { type Command, type CommandContext } from '../types'
9
- import { validateInputValue, validateManifest, type InputsSchema } from '@frontera-sdk/automation'
9
+ import { validateInputValue, validateManifest, type InputsSchema } from '@frontera-sdk/functions'
10
10
  import { buildAndExtract } from './build-entry'
11
11
 
12
12
  /**
13
- * `frontera automation dev` — run the handler in THIS file, from this machine,
13
+ * `frontera function dev` — run the handler in THIS file, from this machine,
14
14
  * triggered from the Console.
15
15
  *
16
16
  * The loop it replaces is a deploy: build, upload, mint a version, bump the
@@ -272,7 +272,7 @@ async function finishDevRun(
272
272
  runToken: string,
273
273
  body: { status: 'succeeded' | 'failed'; result?: unknown; errorMessage?: string },
274
274
  ): Promise<void> {
275
- await fetch(`${apiUrl}/v1/automations/runner/runs/${runId}/finish`, {
275
+ await fetch(`${apiUrl}/v1/functions/runner/runs/${runId}/finish`, {
276
276
  method: 'POST',
277
277
  headers: { 'content-type': 'application/json', 'x-automation-run-token': runToken },
278
278
  body: JSON.stringify(body),
@@ -322,7 +322,7 @@ export function devStartupManifestGate(errors: string[]): { blocking: string[];
322
322
 
323
323
  export const automationDev: Command = {
324
324
  meta: {
325
- noun: 'automation',
325
+ noun: 'function',
326
326
  verb: 'dev',
327
327
  args: [
328
328
  {
@@ -333,13 +333,13 @@ export const automationDev: Command = {
333
333
  ],
334
334
  flags: {},
335
335
  summary: 'Serve this file to dev runs — no deploy, no version',
336
- examples: ['frontera automation dev src/index.ts'],
336
+ examples: ['frontera function dev src/index.ts'],
337
337
  },
338
338
 
339
339
  async run(ctx: CommandContext) {
340
340
  const file = ctx.positional[0]
341
341
  if (!file) {
342
- throw new UsageError('missing <file>', 'frontera automation dev <file>')
342
+ throw new UsageError('missing <file>', 'frontera function dev <file>')
343
343
  }
344
344
  const entry = resolve(file)
345
345
  const out = ctx.output
@@ -403,7 +403,7 @@ export const automationDev: Command = {
403
403
  // came back empty.
404
404
  out.note('[dev] runs are DRY — ctx.agent, ctx.plugin, ctx.http and ctx.blueprint return empty and send nothing')
405
405
  if (session.created) out.note(`[dev] created the automation "${slug}" (no version yet)`)
406
- out.note(`[dev] waiting — press Run dev in the Console, or \`frontera automation run ${slug} --dev\``)
406
+ out.note(`[dev] waiting — press Run dev in the Console, or \`frontera function run ${slug} --dev\``)
407
407
 
408
408
  const workDir = mkdtempSync(join(tmpdir(), 'frontera-dev-'))
409
409
  let builds = 0
@@ -2,7 +2,7 @@ import { existsSync, mkdtempSync, rmSync } from 'node:fs'
2
2
  import { tmpdir } from 'node:os'
3
3
  import { join, resolve } from 'node:path'
4
4
 
5
- import { validateManifest } from '@frontera-sdk/automation'
5
+ import { validateManifest } from '@frontera-sdk/functions'
6
6
 
7
7
  import { AutomationApi } from '../../api/automation-api'
8
8
  import { UsageError } from '../../errors'
@@ -26,7 +26,7 @@ function requireSlug(ctx: CommandContext): string {
26
26
  if (!slug) {
27
27
  throw new UsageError(
28
28
  'missing <slug>',
29
- 'run `frontera automation list` — then pass the slug of the one you mean',
29
+ 'run `frontera function list` — then pass the slug of the one you mean',
30
30
  )
31
31
  }
32
32
  return slug
@@ -64,7 +64,7 @@ export function runnerWarningFor(
64
64
 
65
65
  const deploy: Command = {
66
66
  meta: {
67
- noun: 'automation',
67
+ noun: 'function',
68
68
  verb: 'deploy',
69
69
  args: [
70
70
  {
@@ -76,15 +76,15 @@ const deploy: Command = {
76
76
  flags: { 'no-promote': 'boolean' },
77
77
  summary: 'Build and deploy an automation, promoting it live by default',
78
78
  examples: [
79
- 'frontera automation deploy src/daily-digest.ts',
80
- 'frontera automation deploy src/daily-digest.ts --no-promote',
79
+ 'frontera function deploy src/daily-digest.ts',
80
+ 'frontera function deploy src/daily-digest.ts --no-promote',
81
81
  ],
82
82
  },
83
83
 
84
84
  async run(ctx) {
85
85
  const file = ctx.positional[0]
86
86
  if (!file) {
87
- throw new UsageError('missing <file>', 'frontera automation deploy <file>')
87
+ throw new UsageError('missing <file>', 'frontera function deploy <file>')
88
88
  }
89
89
 
90
90
  const { manifest, code } = await buildAndExtract(file)
@@ -128,8 +128,8 @@ const deploy: Command = {
128
128
  ctx.output.note(
129
129
  ' warning: no automation project found (no package.json above '
130
130
  + `${file}, or the nearest one is a workspace root) — deploying WITHOUT `
131
- + 'source, so `frontera automation pull` will not work for this version. '
132
- + 'Run `frontera automation init` to author in a project.',
131
+ + 'source, so `frontera function pull` will not work for this version. '
132
+ + 'Run `frontera function init` to author in a project.',
133
133
  )
134
134
  }
135
135
 
@@ -158,19 +158,19 @@ const deploy: Command = {
158
158
  `Deployed ${slug} v${result.version}` +
159
159
  (result.promoted
160
160
  ? ' and promoted it'
161
- : ` (not promoted — use \`frontera automation promote ${slug} ${result.version}\`)`),
161
+ : ` (not promoted — use \`frontera function promote ${slug} ${result.version}\`)`),
162
162
  }
163
163
  },
164
164
  }
165
165
 
166
166
  const list: Command = {
167
167
  meta: {
168
- noun: 'automation',
168
+ noun: 'function',
169
169
  verb: 'list',
170
170
  args: [],
171
171
  flags: {},
172
172
  summary: 'List automations in this workspace',
173
- examples: ['frontera automation list', 'frontera automation list --json'],
173
+ examples: ['frontera function list', 'frontera function list --json'],
174
174
  },
175
175
 
176
176
  async run(ctx) {
@@ -200,12 +200,12 @@ const list: Command = {
200
200
 
201
201
  const versions: Command = {
202
202
  meta: {
203
- noun: 'automation',
203
+ noun: 'function',
204
204
  verb: 'versions',
205
- args: [{ name: 'slug', required: true, description: 'automation slug, from `frontera automation list`' }],
205
+ args: [{ name: 'slug', required: true, description: 'automation slug, from `frontera function list`' }],
206
206
  flags: {},
207
207
  summary: 'List deployed versions, newest first; * marks the live one',
208
- examples: ['frontera automation versions daily-digest'],
208
+ examples: ['frontera function versions daily-digest'],
209
209
  },
210
210
 
211
211
  async run(ctx) {
@@ -245,15 +245,15 @@ const versions: Command = {
245
245
 
246
246
  const promote: Command = {
247
247
  meta: {
248
- noun: 'automation',
248
+ noun: 'function',
249
249
  verb: 'promote',
250
250
  args: [
251
251
  { name: 'slug', required: true, description: 'automation slug' },
252
- { name: 'version', required: true, description: 'version number, from `frontera automation versions`' },
252
+ { name: 'version', required: true, description: 'version number, from `frontera function versions`' },
253
253
  ],
254
254
  flags: {},
255
255
  summary: 'Move the live pointer to an already-deployed version',
256
- examples: ['frontera automation promote daily-digest 3'],
256
+ examples: ['frontera function promote daily-digest 3'],
257
257
  },
258
258
 
259
259
  async run(ctx) {
@@ -265,7 +265,7 @@ const promote: Command = {
265
265
  if (raw === undefined || !Number.isInteger(version)) {
266
266
  throw new UsageError(
267
267
  `version must be an integer, got ${raw === undefined ? '(none)' : `"${raw}"`}`,
268
- `run \`frontera automation versions ${slug}\` to see the versions that exist`,
268
+ `run \`frontera function versions ${slug}\` to see the versions that exist`,
269
269
  )
270
270
  }
271
271
 
@@ -283,12 +283,12 @@ function enabledCommand(verb: 'enable' | 'disable', summary: string): Command {
283
283
  const enabled = verb === 'enable'
284
284
  return {
285
285
  meta: {
286
- noun: 'automation',
286
+ noun: 'function',
287
287
  verb,
288
288
  args: [{ name: 'slug', required: true, description: 'automation slug' }],
289
289
  flags: {},
290
290
  summary,
291
- examples: [`frontera automation ${verb} daily-digest`],
291
+ examples: [`frontera function ${verb} daily-digest`],
292
292
  },
293
293
 
294
294
  async run(ctx) {
@@ -6,7 +6,7 @@ import type { Command } from '../types'
6
6
 
7
7
  export const automationInit: Command = {
8
8
  meta: {
9
- noun: 'automation',
9
+ noun: 'function',
10
10
  verb: 'init',
11
11
  args: [{
12
12
  name: 'name',
@@ -15,14 +15,14 @@ export const automationInit: Command = {
15
15
  }],
16
16
  flags: { dir: 'string' },
17
17
  summary: 'Scaffold a new automation project',
18
- examples: ['frontera automation init daily-digest'],
18
+ examples: ['frontera function init daily-digest'],
19
19
  // Scaffolding must work before a credential exists.
20
20
  offline: true,
21
21
  },
22
22
 
23
23
  async run(ctx) {
24
24
  const name = ctx.positional[0]
25
- if (!name) throw new UsageError('missing <name>', 'frontera automation init <name>')
25
+ if (!name) throw new UsageError('missing <name>', 'frontera function init <name>')
26
26
 
27
27
  const base = typeof ctx.flags.dir === 'string' ? ctx.flags.dir : ctx.cwd
28
28
  const target = join(base, name)
@@ -45,7 +45,7 @@ export const automationInit: Command = {
45
45
  ` cd ${name}`,
46
46
  ' bun install',
47
47
  ' bun run typecheck',
48
- ' frontera automation deploy src/index.ts',
48
+ ' frontera function deploy src/index.ts',
49
49
  ].join('\n'),
50
50
  }
51
51
  },
@@ -10,18 +10,18 @@ import { flagBool, type Command } from '../types'
10
10
  export function parseTarget(raw: string): { slug: string; version: number | null } {
11
11
  const at = raw.lastIndexOf('@')
12
12
  if (at === -1) {
13
- if (!raw) throw new UsageError('missing slug', 'frontera automation pull <slug>[@version]')
13
+ if (!raw) throw new UsageError('missing slug', 'frontera function pull <slug>[@version]')
14
14
  return { slug: raw, version: null }
15
15
  }
16
16
  const slug = raw.slice(0, at)
17
17
  const rest = raw.slice(at + 1)
18
- if (!slug) throw new UsageError('missing slug', 'frontera automation pull <slug>[@version]')
18
+ if (!slug) throw new UsageError('missing slug', 'frontera function pull <slug>[@version]')
19
19
  if (!/^\d+$/.test(rest)) {
20
20
  // Not silently falling back to latest: handing back a different version than
21
21
  // the one named is the failure mode this phase exists to prevent.
22
22
  throw new UsageError(
23
23
  `version must be a number, got "${rest}"`,
24
- 'frontera automation pull <slug>@3',
24
+ 'frontera function pull <slug>@3',
25
25
  )
26
26
  }
27
27
  return { slug, version: Number(rest) }
@@ -65,7 +65,7 @@ export function resolveTargetDir(
65
65
 
66
66
  export const automationPull: Command = {
67
67
  meta: {
68
- noun: 'automation',
68
+ noun: 'function',
69
69
  verb: 'pull',
70
70
  args: [{
71
71
  name: 'slug[@version]',
@@ -75,14 +75,14 @@ export const automationPull: Command = {
75
75
  flags: { dir: 'string', force: 'boolean' },
76
76
  summary: 'Hydrate an editable project from a deployed version',
77
77
  examples: [
78
- 'frontera automation pull daily-digest',
79
- 'frontera automation pull daily-digest@3 --dir ./recovered',
78
+ 'frontera function pull daily-digest',
79
+ 'frontera function pull daily-digest@3 --dir ./recovered',
80
80
  ],
81
81
  },
82
82
 
83
83
  async run(ctx) {
84
84
  const raw = ctx.positional[0]
85
- if (!raw) throw new UsageError('missing <slug>', 'frontera automation pull <slug>[@version]')
85
+ if (!raw) throw new UsageError('missing <slug>', 'frontera function pull <slug>[@version]')
86
86
  const { slug, version } = parseTarget(raw)
87
87
 
88
88
  const client = new AutomationApi(ctx.apiUrl, ctx.token, ctx.workspaceId)
@@ -117,7 +117,7 @@ export const automationPull: Command = {
117
117
  '',
118
118
  ` cd ${target}`,
119
119
  ' bun install',
120
- ' frontera automation deploy src/index.ts',
120
+ ' frontera function deploy src/index.ts',
121
121
  ].join('\n'),
122
122
  }
123
123
  },