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.
- package/bin/facet +1 -1
- package/package.json +16 -37
- package/{scripts/postinstall.mjs → postinstall.mjs} +1 -1
- package/.package.json.bak +0 -45
- package/.turbo/turbo-build.log +0 -3
- package/CHANGELOG.md +0 -95
- package/bunfig.toml +0 -2
- package/dist/facet +0 -0
- package/src/__tests__/cli.test.ts +0 -195
- package/src/__tests__/create-build.test.ts +0 -227
- package/src/__tests__/edit-integration.test.ts +0 -171
- package/src/__tests__/launcher.test.ts +0 -106
- package/src/__tests__/postinstall.test.ts +0 -196
- package/src/__tests__/resolve-dir.test.ts +0 -95
- package/src/commands/build.ts +0 -58
- package/src/commands/create/index.ts +0 -76
- package/src/commands/create/types.ts +0 -9
- package/src/commands/create/wizard.tsx +0 -75
- package/src/commands/create-scaffold.ts +0 -184
- package/src/commands/edit/index.ts +0 -144
- package/src/commands/edit/wizard.tsx +0 -74
- package/src/commands/resolve-dir.ts +0 -98
- package/src/commands.ts +0 -40
- package/src/help.ts +0 -43
- package/src/index.ts +0 -10
- package/src/run.ts +0 -82
- package/src/suggest.ts +0 -35
- package/src/tui/components/asset-description.tsx +0 -17
- package/src/tui/components/asset-field-picker.tsx +0 -78
- package/src/tui/components/asset-inline-input.tsx +0 -91
- package/src/tui/components/asset-item.tsx +0 -44
- package/src/tui/components/asset-section.tsx +0 -191
- package/src/tui/components/button.tsx +0 -92
- package/src/tui/components/editable-field.tsx +0 -172
- package/src/tui/components/exit-toast.tsx +0 -20
- package/src/tui/components/reconciliation-item.tsx +0 -129
- package/src/tui/components/stage-row.tsx +0 -45
- package/src/tui/components/version-selector.tsx +0 -79
- package/src/tui/context/focus-mode-context.ts +0 -36
- package/src/tui/context/focus-order-context.ts +0 -68
- package/src/tui/context/form-state-context.ts +0 -260
- package/src/tui/editor.ts +0 -40
- package/src/tui/gradient.ts +0 -1
- package/src/tui/hooks/use-exit-keys.ts +0 -75
- package/src/tui/hooks/use-navigation-keys.ts +0 -34
- package/src/tui/layouts/wizard-layout.tsx +0 -41
- package/src/tui/theme.ts +0 -1
- package/src/tui/views/build/build-view.tsx +0 -152
- package/src/tui/views/create/confirm-view.tsx +0 -74
- package/src/tui/views/create/create-view.tsx +0 -158
- package/src/tui/views/create/wizard.tsx +0 -97
- package/src/tui/views/edit/edit-confirm-view.tsx +0 -93
- package/src/tui/views/edit/edit-types.ts +0 -34
- package/src/tui/views/edit/edit-view.tsx +0 -140
- package/src/tui/views/edit/manifest-to-form.ts +0 -38
- package/src/tui/views/edit/reconciliation-view.tsx +0 -170
- package/src/tui/views/edit/use-edit-session.ts +0 -125
- package/src/tui/views/edit/wizard.tsx +0 -129
- package/src/version.ts +0 -3
- 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
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
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 =
|
|
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
|
-
}
|
package/.turbo/turbo-build.log
DELETED
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
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
|
-
})
|