agent-facets 0.3.0 → 0.3.3

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.
Files changed (60) hide show
  1. package/bin/facet +1 -1
  2. package/package.json +16 -37
  3. package/{scripts/postinstall.mjs → postinstall.mjs} +1 -1
  4. package/.package.json.bak +0 -45
  5. package/.turbo/turbo-build.log +0 -3
  6. package/CHANGELOG.md +0 -95
  7. package/bunfig.toml +0 -2
  8. package/dist/facet +0 -0
  9. package/src/__tests__/cli.test.ts +0 -195
  10. package/src/__tests__/create-build.test.ts +0 -227
  11. package/src/__tests__/edit-integration.test.ts +0 -171
  12. package/src/__tests__/launcher.test.ts +0 -106
  13. package/src/__tests__/postinstall.test.ts +0 -196
  14. package/src/__tests__/resolve-dir.test.ts +0 -95
  15. package/src/commands/build.ts +0 -58
  16. package/src/commands/create/index.ts +0 -76
  17. package/src/commands/create/types.ts +0 -9
  18. package/src/commands/create/wizard.tsx +0 -75
  19. package/src/commands/create-scaffold.ts +0 -184
  20. package/src/commands/edit/index.ts +0 -144
  21. package/src/commands/edit/wizard.tsx +0 -74
  22. package/src/commands/resolve-dir.ts +0 -98
  23. package/src/commands.ts +0 -40
  24. package/src/help.ts +0 -43
  25. package/src/index.ts +0 -10
  26. package/src/run.ts +0 -82
  27. package/src/suggest.ts +0 -35
  28. package/src/tui/components/asset-description.tsx +0 -17
  29. package/src/tui/components/asset-field-picker.tsx +0 -78
  30. package/src/tui/components/asset-inline-input.tsx +0 -91
  31. package/src/tui/components/asset-item.tsx +0 -44
  32. package/src/tui/components/asset-section.tsx +0 -191
  33. package/src/tui/components/button.tsx +0 -92
  34. package/src/tui/components/editable-field.tsx +0 -172
  35. package/src/tui/components/exit-toast.tsx +0 -20
  36. package/src/tui/components/reconciliation-item.tsx +0 -129
  37. package/src/tui/components/stage-row.tsx +0 -45
  38. package/src/tui/components/version-selector.tsx +0 -79
  39. package/src/tui/context/focus-mode-context.ts +0 -36
  40. package/src/tui/context/focus-order-context.ts +0 -68
  41. package/src/tui/context/form-state-context.ts +0 -260
  42. package/src/tui/editor.ts +0 -40
  43. package/src/tui/gradient.ts +0 -1
  44. package/src/tui/hooks/use-exit-keys.ts +0 -75
  45. package/src/tui/hooks/use-navigation-keys.ts +0 -34
  46. package/src/tui/layouts/wizard-layout.tsx +0 -41
  47. package/src/tui/theme.ts +0 -1
  48. package/src/tui/views/build/build-view.tsx +0 -152
  49. package/src/tui/views/create/confirm-view.tsx +0 -74
  50. package/src/tui/views/create/create-view.tsx +0 -158
  51. package/src/tui/views/create/wizard.tsx +0 -97
  52. package/src/tui/views/edit/edit-confirm-view.tsx +0 -93
  53. package/src/tui/views/edit/edit-types.ts +0 -34
  54. package/src/tui/views/edit/edit-view.tsx +0 -140
  55. package/src/tui/views/edit/manifest-to-form.ts +0 -38
  56. package/src/tui/views/edit/reconciliation-view.tsx +0 -170
  57. package/src/tui/views/edit/use-edit-session.ts +0 -125
  58. package/src/tui/views/edit/wizard.tsx +0 -129
  59. package/src/version.ts +0 -3
  60. package/tsconfig.json +0 -4
package/bin/facet CHANGED
@@ -52,7 +52,7 @@ let arch = archMap[os.arch()]
52
52
  if (!arch) {
53
53
  arch = os.arch()
54
54
  }
55
- const base = "agent-facets-" + platform + "-" + arch
55
+ const base = "@agent-facets/cli-" + platform + "-" + arch
56
56
  const binary = platform === "windows" ? "facet.exe" : "facet"
57
57
 
58
58
  function supportsAvx2() {
package/package.json CHANGED
@@ -1,45 +1,24 @@
1
1
  {
2
2
  "name": "agent-facets",
3
- "repository": {
4
- "type": "git",
5
- "url": "https://github.com/agent-facets/facets",
6
- "directory": "packages/cli"
7
- },
8
- "version": "0.3.0",
9
- "type": "module",
3
+ "version": "0.3.3",
10
4
  "bin": {
11
5
  "facet": "./bin/facet"
12
6
  },
13
7
  "scripts": {
14
- "build": "bun build src/index.ts --compile --outfile dist/facet",
15
- "postinstall": "node scripts/postinstall.mjs",
16
- "prepack": "bun ../../scripts/prepack.ts",
17
- "postpack": "bun ../../scripts/postpack.ts",
18
- "types": "tsc --noEmit",
19
- "test": "bun test --timeout 15000"
20
- },
21
- "dependencies": {
22
- "@bomb.sh/args": "0.3.1",
23
- "@types/react": "19.2.14",
24
- "arktype": "2.1.29",
25
- "ink": "6.8.0",
26
- "ink-gradient": "4.0.0",
27
- "ink-spinner": "5.0.0",
28
- "ink-text-input": "6.0.0",
29
- "react": "19.2.4",
30
- "react-devtools-core": "7.0.1"
31
- },
32
- "devDependencies": {
33
- "@agent-facets/brand": "0.2.1",
34
- "@agent-facets/core": "0.2.1",
35
- "@types/bun": "1.3.10",
36
- "ink-testing-library": "4.0.0"
37
- },
38
- "peerDependencies": {
39
- "typescript": "^5 || ^6"
8
+ "postinstall": "node ./postinstall.mjs"
40
9
  },
41
- "publishConfig": {
42
- "access": "public",
43
- "provenance": false
10
+ "optionalDependencies": {
11
+ "@agent-facets/cli-windows-x64-baseline": "0.3.3",
12
+ "@agent-facets/cli-windows-x64": "0.3.3",
13
+ "@agent-facets/cli-windows-arm64": "0.3.3",
14
+ "@agent-facets/cli-darwin-x64-baseline": "0.3.3",
15
+ "@agent-facets/cli-darwin-x64": "0.3.3",
16
+ "@agent-facets/cli-darwin-arm64": "0.3.3",
17
+ "@agent-facets/cli-linux-x64-baseline-musl": "0.3.3",
18
+ "@agent-facets/cli-linux-x64-musl": "0.3.3",
19
+ "@agent-facets/cli-linux-arm64-musl": "0.3.3",
20
+ "@agent-facets/cli-linux-x64-baseline": "0.3.3",
21
+ "@agent-facets/cli-linux-x64": "0.3.3",
22
+ "@agent-facets/cli-linux-arm64": "0.3.3"
44
23
  }
45
- }
24
+ }
@@ -105,7 +105,7 @@ function isMusl() {
105
105
  // ---------------------------------------------------------------------------
106
106
 
107
107
  function buildCandidates(platform, arch, opts = {}) {
108
- const base = `agent-facets-${platform}-${arch}`
108
+ const base = `@agent-facets/cli-${platform}-${arch}`
109
109
  const avx2 = opts.avx2 !== undefined ? opts.avx2 : arch === 'x64' ? supportsAvx2(platform) : false
110
110
  const baseline = arch === 'x64' && !avx2
111
111
 
package/.package.json.bak DELETED
@@ -1,45 +0,0 @@
1
- {
2
- "name": "agent-facets",
3
- "repository": {
4
- "type": "git",
5
- "url": "https://github.com/agent-facets/facets",
6
- "directory": "packages/cli"
7
- },
8
- "version": "0.3.0",
9
- "type": "module",
10
- "bin": {
11
- "facet": "./bin/facet"
12
- },
13
- "scripts": {
14
- "build": "bun build src/index.ts --compile --outfile dist/facet",
15
- "postinstall": "node scripts/postinstall.mjs",
16
- "prepack": "bun ../../scripts/prepack.ts",
17
- "postpack": "bun ../../scripts/postpack.ts",
18
- "types": "tsc --noEmit",
19
- "test": "bun test --timeout 15000"
20
- },
21
- "dependencies": {
22
- "@bomb.sh/args": "0.3.1",
23
- "@types/react": "19.2.14",
24
- "arktype": "2.1.29",
25
- "ink": "6.8.0",
26
- "ink-gradient": "4.0.0",
27
- "ink-spinner": "5.0.0",
28
- "ink-text-input": "6.0.0",
29
- "react": "19.2.4",
30
- "react-devtools-core": "7.0.1"
31
- },
32
- "devDependencies": {
33
- "@agent-facets/brand": "workspace:*",
34
- "@agent-facets/core": "workspace:*",
35
- "@types/bun": "1.3.10",
36
- "ink-testing-library": "4.0.0"
37
- },
38
- "peerDependencies": {
39
- "typescript": "^5 || ^6"
40
- },
41
- "publishConfig": {
42
- "access": "public",
43
- "provenance": false
44
- }
45
- }
@@ -1,3 +0,0 @@
1
- $ bun build src/index.ts --compile --outfile dist/facet
2
- [202ms] bundle 388 modules
3
- [3ms] compile dist/facet
package/CHANGELOG.md DELETED
@@ -1,95 +0,0 @@
1
- # agent-facets
2
-
3
- ## 0.3.0
4
-
5
- ### Minor Changes
6
-
7
- - [#51](https://github.com/agent-facets/facets/pull/51) [`8280bba`](https://github.com/agent-facets/facets/commit/8280bba66d5ab6a132e1b6792bcccce03037a6de) Thanks [@eXamadeus](https://github.com/eXamadeus)! - Support 12 platform binaries (linux, windows, mac and common variants)
8
-
9
- ### Patch Changes
10
-
11
- - [#51](https://github.com/agent-facets/facets/pull/51) [`8280bba`](https://github.com/agent-facets/facets/commit/8280bba66d5ab6a132e1b6792bcccce03037a6de) Thanks [@eXamadeus](https://github.com/eXamadeus)! - Support dev platform "dev" mode via `bun dev` removing the complex build -> link flow
12
-
13
- ## 0.2.2
14
-
15
- ### Patch Changes
16
-
17
- - [#39](https://github.com/agent-facets/facets/pull/39) [`f380b7b`](https://github.com/agent-facets/facets/commit/f380b7bc5115acec1f974ef1401eba199a2f90fb) Thanks [@eXamadeus](https://github.com/eXamadeus)! - Ensure release CI works in isolation
18
- - [#46](https://github.com/agent-facets/facets/pull/46) [`a5cbb89`](https://github.com/agent-facets/facets/commit/a5cbb89a46e14e2f79749ea7eafb5aebbd3504b7) Thanks [@eXamadeus](https://github.com/eXamadeus)! - Ensure all CI runs and provenance is managed correctly across packages
19
-
20
- ## 0.2.1
21
-
22
- ### Patch Changes
23
-
24
- - [#39](https://github.com/agent-facets/facets/pull/39) [`f380b7b`](https://github.com/agent-facets/facets/commit/f380b7bc5115acec1f974ef1401eba199a2f90fb) Thanks [@eXamadeus](https://github.com/eXamadeus)! - Ensure release CI works in isolation
25
-
26
- ## 0.2.0
27
-
28
- ### Minor Changes
29
-
30
- - [#35](https://github.com/agent-facets/facets/pull/35) [`6350718`](https://github.com/agent-facets/facets/commit/63507188f1bb3a7276cd4812f69f7d16d1778fd6) Thanks [@eXamadeus](https://github.com/eXamadeus)! - Ensure proper release isolation
31
-
32
- ### Patch Changes
33
-
34
- - [#37](https://github.com/agent-facets/facets/pull/37) [`1c48260`](https://github.com/agent-facets/facets/commit/1c48260ab77fd27e64be6c5884aa6c447e3639e0) Thanks [@eXamadeus](https://github.com/eXamadeus)! - Better dev & ci dependency management via mise
35
- - [#33](https://github.com/agent-facets/facets/pull/33) [`540e126`](https://github.com/agent-facets/facets/commit/540e126e677de98a9b3d4e39542df37de8756b73) Thanks [@eXamadeus](https://github.com/eXamadeus)! - Ensure CI runs tests before release and notify Slack when failures occur.
36
-
37
- ## 0.1.4
38
-
39
- ### Patch Changes
40
-
41
- - [`098fd08`](https://github.com/agent-facets/facets/commit/098fd08bf5d9970babc5c57bee6a155bffcecd97) Thanks [@eXamadeus](https://github.com/eXamadeus)! - Better CLI parameter validation
42
-
43
- - [`5262cbe`](https://github.com/agent-facets/facets/commit/5262cbe66df02c625430309878e6061ccde183de) Thanks [@eXamadeus](https://github.com/eXamadeus)! - Fix publishing by properly categorizing dev dependencies
44
-
45
- - [`d3b9439`](https://github.com/agent-facets/facets/commit/d3b9439466e0eb65687901426e2ebd6c5a333c60) Thanks [@eXamadeus](https://github.com/eXamadeus)! - Use better github attribution for changesets
46
-
47
- ## 0.1.3
48
-
49
- ### Patch Changes
50
-
51
- - 66b179f: Wire up the facet edit command
52
-
53
- ## 0.1.2
54
-
55
- ### Patch Changes
56
-
57
- - bb87748: This is a CI improvement so we release faster and cleaner
58
- - 95e2f38: Migrate NPM packages from `@ex-machina` to `@agent-facets` org.
59
-
60
- - `@ex-machina/facet-core` is now `@agent-facets/core`
61
- - `@ex-machina/facet` is now `agent-facets`
62
-
63
- - Updated dependencies [bb87748]
64
- - Updated dependencies [95e2f38]
65
- - @agent-facets/brand@0.1.1
66
- - @agent-facets/core@0.1.2
67
-
68
- ## 0.1.1
69
-
70
- ### Patch Changes
71
-
72
- - 5813b90: Small test for change set management in CI
73
- - Updated dependencies [5813b90]
74
- - @agent-facets/core@0.1.1
75
-
76
- ## 0.1.0
77
-
78
- ### Minor Changes
79
-
80
- - 2243bbf: Added basic create command to CLI
81
-
82
- ### Patch Changes
83
-
84
- - Updated dependencies [2243bbf]
85
- - @agent-facets/core@0.1.0
86
-
87
- ## 0.0.1
88
-
89
- ### Patch Changes
90
-
91
- - 74e3d25: Should be 0.0.1 now
92
- - 74e3d25: Initial publishing
93
- - Updated dependencies [74e3d25]
94
- - Updated dependencies [74e3d25]
95
- - @agent-facets/core@0.0.1
package/bunfig.toml DELETED
@@ -1,2 +0,0 @@
1
- [test.reporter]
2
- junit = "../../test-results/cli-junit.xml"
package/dist/facet DELETED
Binary file
@@ -1,195 +0,0 @@
1
- import { describe, expect, test } from 'bun:test'
2
- import { resolve } from 'node:path'
3
-
4
- const CLI_PATH = resolve(import.meta.dir, '../../dist/facet')
5
- const COMMAND_NAMES = ['add', 'build', 'create', 'edit', 'info', 'install', 'list', 'publish', 'remove', 'upgrade']
6
- const STUB_COMMAND_NAMES = ['add', 'info', 'install', 'list', 'publish', 'remove', 'upgrade']
7
-
8
- type ExecResult = {
9
- stdout: string
10
- stderr: string
11
- exitCode: number
12
- }
13
-
14
- async function runCli(...args: string[]): Promise<ExecResult> {
15
- const proc = Bun.spawn([CLI_PATH, ...args], {
16
- stdout: 'pipe',
17
- stderr: 'pipe',
18
- })
19
- const [stdout, stderr] = await Promise.all([new Response(proc.stdout).text(), new Response(proc.stderr).text()])
20
- const exitCode = await proc.exited
21
- return { stdout: stdout.trim(), stderr: stderr.trim(), exitCode }
22
- }
23
-
24
- // --- Help ---
25
-
26
- describe('CLI — help', () => {
27
- test('--help prints command list to stdout and exits 0', async () => {
28
- const result = await runCli('--help')
29
- expect(result.exitCode).toBe(0)
30
- expect(result.stdout).toContain('Usage: facet <command>')
31
- for (const cmd of COMMAND_NAMES) {
32
- expect(result.stdout).toContain(cmd)
33
- }
34
- expect(result.stderr).toBe('')
35
- })
36
-
37
- test('help command produces same output as --help', async () => {
38
- const helpFlag = await runCli('--help')
39
- const helpCommand = await runCli('help')
40
- expect(helpCommand.exitCode).toBe(0)
41
- expect(helpCommand.stdout).toBe(helpFlag.stdout)
42
- expect(helpCommand.stderr).toBe('')
43
- })
44
- })
45
-
46
- // --- Version ---
47
-
48
- describe('CLI — version', () => {
49
- test('--version prints version matching package.json and exits 0', async () => {
50
- const pkg = await Bun.file(resolve(import.meta.dir, '../../package.json')).json()
51
- const result = await runCli('--version')
52
- expect(result.exitCode).toBe(0)
53
- expect(result.stdout).toBe(pkg.version)
54
- expect(result.stderr).toBe('')
55
- })
56
- })
57
-
58
- // --- Bare invocation ---
59
-
60
- describe('CLI — bare invocation', () => {
61
- test('no arguments prints help and exits 0', async () => {
62
- const helpResult = await runCli('--help')
63
- const bareResult = await runCli()
64
- expect(bareResult.exitCode).toBe(0)
65
- expect(bareResult.stdout).toBe(helpResult.stdout)
66
- expect(bareResult.stderr).toBe('')
67
- })
68
- })
69
-
70
- // --- Stub commands ---
71
-
72
- describe('CLI — stub commands', () => {
73
- test.each(STUB_COMMAND_NAMES)('"%s" prints not yet implemented with command name and exits 0', async (cmd) => {
74
- const result = await runCli(cmd)
75
- expect(result.exitCode).toBe(0)
76
- expect(result.stdout).toContain(cmd)
77
- expect(result.stdout).toContain('not yet implemented')
78
- expect(result.stderr).toBe('')
79
- })
80
- })
81
-
82
- // --- Edit command dispatch ---
83
-
84
- describe('CLI — edit command', () => {
85
- test('edit with no manifest prints error and exits 1', async () => {
86
- const result = await runCli('edit', import.meta.dir)
87
- expect(result.exitCode).toBe(1)
88
- expect(result.stderr).toContain('facet.json')
89
- })
90
- })
91
-
92
- // --- Unknown commands ---
93
-
94
- describe('CLI — unknown commands', () => {
95
- test('unknown command prints error to stderr and exits 1', async () => {
96
- const result = await runCli('xyzzy')
97
- expect(result.exitCode).toBe(1)
98
- expect(result.stderr).toContain('Unknown command "xyzzy"')
99
- expect(result.stdout).toBe('')
100
- })
101
-
102
- test('unknown command with close match includes "did you mean?" suggestion', async () => {
103
- const result = await runCli('bild')
104
- expect(result.exitCode).toBe(1)
105
- expect(result.stderr).toContain('Unknown command "bild"')
106
- expect(result.stderr).toContain('Did you mean "build"')
107
- expect(result.stdout).toBe('')
108
- })
109
-
110
- test('unknown command with no close match does not include suggestion', async () => {
111
- const result = await runCli('xyzzy')
112
- expect(result.exitCode).toBe(1)
113
- expect(result.stderr).toContain('Unknown command "xyzzy"')
114
- expect(result.stderr).not.toContain('Did you mean')
115
- expect(result.stdout).toBe('')
116
- })
117
- })
118
-
119
- // --- Per-command help ---
120
-
121
- describe('CLI — per-command help', () => {
122
- test('<command> --help prints command-specific help and exits 0', async () => {
123
- const result = await runCli('build', '--help')
124
- expect(result.exitCode).toBe(0)
125
- expect(result.stdout).toContain('facet build')
126
- expect(result.stdout).toContain('Build a facet from the current directory')
127
- expect(result.stderr).toBe('')
128
- })
129
- })
130
-
131
- // --- Unexpected error ---
132
-
133
- describe('CLI — unexpected error', () => {
134
- test('unexpected error is thrown by run', async () => {
135
- const { run } = await import('../run.ts')
136
-
137
- const crashRegistry = {
138
- crash: {
139
- name: 'crash',
140
- description: 'Throws an error',
141
- run: async (_args: string[], _flags: Record<string, unknown>) => {
142
- throw new Error('boom')
143
- },
144
- },
145
- }
146
-
147
- await expect(run(['crash'], crashRegistry)).rejects.toThrow('boom')
148
- })
149
- })
150
-
151
- // --- Per-command flags ---
152
-
153
- describe('CLI — per-command flags', () => {
154
- test('create --help shows --force flag and usage', async () => {
155
- const result = await runCli('create', '--help')
156
- expect(result.exitCode).toBe(0)
157
- expect(result.stdout).toContain('[directory]')
158
- expect(result.stdout).toContain('--force')
159
- expect(result.stdout).toContain('Overwrite existing facet.json')
160
- })
161
-
162
- test('build --help shows directory usage', async () => {
163
- const result = await runCli('build', '--help')
164
- expect(result.exitCode).toBe(0)
165
- expect(result.stdout).toContain('[directory]')
166
- })
167
-
168
- test('edit --help shows directory usage', async () => {
169
- const result = await runCli('edit', '--help')
170
- expect(result.exitCode).toBe(0)
171
- expect(result.stdout).toContain('[directory]')
172
- })
173
- })
174
-
175
- // --- Directory validation ---
176
-
177
- describe('CLI — directory validation', () => {
178
- test('build with non-existent directory errors', async () => {
179
- const result = await runCli('build', `/tmp/does-not-exist-${Date.now()}`)
180
- expect(result.exitCode).toBe(1)
181
- expect(result.stderr).toContain('does not exist')
182
- })
183
-
184
- test('edit with non-existent directory errors', async () => {
185
- const result = await runCli('edit', `/tmp/does-not-exist-${Date.now()}`)
186
- expect(result.exitCode).toBe(1)
187
- expect(result.stderr).toContain('does not exist')
188
- })
189
-
190
- test('build with file instead of directory errors', async () => {
191
- const result = await runCli('build', import.meta.path)
192
- expect(result.exitCode).toBe(1)
193
- expect(result.stderr).toContain('Expected a directory')
194
- })
195
- })
@@ -1,227 +0,0 @@
1
- import { afterAll, beforeAll, describe, expect, test } from 'bun:test'
2
- import { mkdtemp, rm } from 'node:fs/promises'
3
- import { tmpdir } from 'node:os'
4
- import { join, resolve } from 'node:path'
5
- import { writeScaffold } from '../commands/create/index.ts'
6
- import { DEFAULT_VERSION } from '../commands/create-scaffold.ts'
7
-
8
- let testDir: string
9
-
10
- beforeAll(async () => {
11
- testDir = await mkdtemp(join(tmpdir(), 'cli-create-build-test-'))
12
- })
13
-
14
- afterAll(async () => {
15
- await rm(testDir, { recursive: true, force: true })
16
- })
17
-
18
- async function createFixtureDir(name: string): Promise<string> {
19
- const dir = join(testDir, name)
20
- await Bun.write(join(dir, '.keep'), '')
21
- return dir
22
- }
23
-
24
- const CLI_PATH = resolve(import.meta.dir, '../../dist/facet')
25
-
26
- async function runCli(...args: string[]) {
27
- const proc = Bun.spawn([CLI_PATH, ...args], {
28
- stdout: 'pipe',
29
- stderr: 'pipe',
30
- env: { ...process.env, NO_COLOR: '1' },
31
- })
32
- const stdout = await new Response(proc.stdout).text()
33
- const stderr = await new Response(proc.stderr).text()
34
- const exitCode = await proc.exited
35
-
36
- // Don't let build errors flood test output — capture but don't dump
37
- if (exitCode !== 0 && stderr.trim()) {
38
- const lines = stderr.trim().split('\n')
39
- const summary =
40
- lines.length > 3 ? [...lines.slice(0, 3), `... (${lines.length - 3} more lines)`].join('\n') : stderr.trim()
41
- return { stdout: stdout.trim(), stderr: summary, exitCode }
42
- }
43
-
44
- return { stdout: stdout.trim(), stderr: stderr.trim(), exitCode }
45
- }
46
-
47
- // --- Scaffold generation (unit) ---
48
-
49
- describe('writeScaffold', () => {
50
- test('scaffolds with named assets across all types', async () => {
51
- const dir = await createFixtureDir('scaffold-all')
52
- const files = await writeScaffold(
53
- {
54
- name: 'my-facet',
55
- version: DEFAULT_VERSION,
56
- description: 'A test facet',
57
- skills: ['code-review', 'testing-guide'],
58
- agents: ['reviewer'],
59
- commands: ['deploy'],
60
- },
61
- dir,
62
- )
63
-
64
- expect(files).toContain('facet.json')
65
- expect(files).toContain('skills/code-review/SKILL.md')
66
- expect(files).toContain('skills/testing-guide/SKILL.md')
67
- expect(files).toContain('agents/reviewer.md')
68
- expect(files).toContain('commands/deploy.md')
69
-
70
- // Verify manifest content (JSON)
71
- const manifestText = await Bun.file(join(dir, 'facet.json')).text()
72
- const manifest = JSON.parse(manifestText)
73
- expect(manifest.name).toBe('my-facet')
74
- expect(manifest.version).toBe(DEFAULT_VERSION)
75
- expect(manifest.description).toBe('A test facet')
76
- expect(manifest.skills).toBeDefined()
77
- expect(manifest.skills['code-review']).toBeDefined()
78
- expect(manifest.skills['testing-guide']).toBeDefined()
79
- expect(manifest.agents).toBeDefined()
80
- expect(manifest.agents.reviewer).toBeDefined()
81
- expect(manifest.commands).toBeDefined()
82
- expect(manifest.commands.deploy).toBeDefined()
83
-
84
- // Verify starter files exist and have named template content
85
- const skill = await Bun.file(join(dir, 'skills/code-review/SKILL.md')).text()
86
- expect(skill).toContain('# Code Review')
87
-
88
- const skill2 = await Bun.file(join(dir, 'skills/testing-guide/SKILL.md')).text()
89
- expect(skill2).toContain('# Testing Guide')
90
-
91
- const agent = await Bun.file(join(dir, 'agents/reviewer.md')).text()
92
- expect(agent).toContain('# Reviewer')
93
-
94
- const command = await Bun.file(join(dir, 'commands/deploy.md')).text()
95
- expect(command).toContain('# Deploy')
96
- })
97
-
98
- test('scaffolds with only one skill', async () => {
99
- const dir = await createFixtureDir('scaffold-skills-only')
100
- const files = await writeScaffold(
101
- {
102
- name: 'minimal',
103
- version: DEFAULT_VERSION,
104
- description: '',
105
- skills: ['minimal'],
106
- agents: [],
107
- commands: [],
108
- },
109
- dir,
110
- )
111
-
112
- expect(files).toContain('facet.json')
113
- expect(files).toContain('skills/minimal/SKILL.md')
114
- expect(files).not.toContain('agents/')
115
- expect(files).not.toContain('commands/')
116
-
117
- const manifestText = await Bun.file(join(dir, 'facet.json')).text()
118
- const manifest = JSON.parse(manifestText)
119
- expect(manifest.skills).toBeDefined()
120
- expect(manifest.agents).toBeUndefined()
121
- expect(manifest.commands).toBeUndefined()
122
- })
123
-
124
- test('version defaults to DEFAULT_VERSION (0.0.0)', async () => {
125
- const dir = await createFixtureDir('scaffold-default-version')
126
- await writeScaffold(
127
- {
128
- name: 'default-ver',
129
- version: DEFAULT_VERSION,
130
- description: 'Testing default version',
131
- skills: ['example'],
132
- agents: [],
133
- commands: [],
134
- },
135
- dir,
136
- )
137
-
138
- const manifestText = await Bun.file(join(dir, 'facet.json')).text()
139
- const manifest = JSON.parse(manifestText)
140
- expect(manifest.version).toBe('0.0.0')
141
- })
142
-
143
- test('scaffolded project passes build', async () => {
144
- const dir = await createFixtureDir('scaffold-buildable')
145
- await writeScaffold(
146
- {
147
- name: 'buildable',
148
- version: DEFAULT_VERSION,
149
- description: 'A buildable facet',
150
- skills: ['helper'],
151
- agents: ['assistant'],
152
- commands: [],
153
- },
154
- dir,
155
- )
156
-
157
- // Run facet build against the scaffolded project
158
- const result = await runCli('build', dir)
159
- expect(result.exitCode).toBe(0)
160
- expect(result.stdout).toContain('Built buildable')
161
-
162
- // Verify dist/ output exists — archive + build manifest
163
- const distArchive = await Bun.file(join(dir, `dist/buildable-${DEFAULT_VERSION}.facet`)).exists()
164
- expect(distArchive).toBe(true)
165
-
166
- const distManifest = await Bun.file(join(dir, 'dist/build-manifest.json')).exists()
167
- expect(distManifest).toBe(true)
168
-
169
- // No loose files
170
- const looseManifest = await Bun.file(join(dir, 'dist/facet.json')).exists()
171
- expect(looseManifest).toBe(false)
172
- })
173
- })
174
-
175
- // --- Build command (e2e) ---
176
-
177
- describe('facet build', () => {
178
- test('build succeeds on valid project', async () => {
179
- const dir = await createFixtureDir('build-valid')
180
- await Bun.write(join(dir, 'skills/review/SKILL.md'), '# Review skill content')
181
- await Bun.write(
182
- join(dir, 'facet.json'),
183
- JSON.stringify({
184
- name: 'test-facet',
185
- version: '1.0.0',
186
- skills: {
187
- review: {
188
- description: 'Code review skill',
189
- },
190
- },
191
- }),
192
- )
193
-
194
- const result = await runCli('build', dir)
195
- expect(result.exitCode).toBe(0)
196
- expect(result.stdout).toContain('Built test-facet')
197
- expect(result.stdout).toContain('sha256:')
198
- })
199
-
200
- test('build fails on missing manifest', async () => {
201
- const dir = await createFixtureDir('build-no-manifest')
202
-
203
- const result = await runCli('build', dir)
204
- expect(result.exitCode).toBe(1)
205
- expect(result.stderr).toContain('facet.json')
206
- })
207
-
208
- test('build fails on missing asset file', async () => {
209
- const dir = await createFixtureDir('build-missing-file')
210
- await Bun.write(
211
- join(dir, 'facet.json'),
212
- JSON.stringify({
213
- name: 'test-facet',
214
- version: '1.0.0',
215
- skills: {
216
- review: {
217
- description: 'Code review skill',
218
- },
219
- },
220
- }),
221
- )
222
-
223
- const result = await runCli('build', dir)
224
- expect(result.exitCode).toBe(1)
225
- expect(result.stdout).toContain('Build failed')
226
- })
227
- })