box0-cli 0.1.0
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/.github/workflows/test.yml +26 -0
- package/AGENTS.md +12 -0
- package/README.md +51 -0
- package/bin/box0.js +5 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/package.json +33 -0
- package/src/commands/ping.ts +10 -0
- package/src/index.ts +41 -0
- package/src/utils/logger.ts +16 -0
- package/tests/cli.test.ts +67 -0
- package/tsconfig.json +17 -0
- package/tsup.config.ts +10 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: Test
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
node-version: [18, 20, 22]
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- uses: actions/setup-node@v4
|
|
20
|
+
with:
|
|
21
|
+
node-version: ${{ matrix.node-version }}
|
|
22
|
+
cache: npm
|
|
23
|
+
|
|
24
|
+
- run: npm ci
|
|
25
|
+
- run: npm run build
|
|
26
|
+
- run: npm test
|
package/AGENTS.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# box0
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## Plan-driven Development
|
|
5
|
+
- Always plan a markdown at plans/ before you code
|
|
6
|
+
- Remember to update the related plans after you finish your work.
|
|
7
|
+
- When every task is completed, make sure you check the task checkbox in the corresponding plan.
|
|
8
|
+
- A plan should at least contain `features`/`show case`, `designs overview`, `TODOS`, `new deps`, `test cases` sections.
|
|
9
|
+
- always use the features/show case to present what you're going to build.
|
|
10
|
+
- use checklist in `TODOS` section, for each checkbox, you must have a clear descripion of what to do and list all the files that will be modified.
|
|
11
|
+
- in `new deps` section, you must list all the new external dependencies that will be added.
|
|
12
|
+
- in `test cases` section, use checklist format to list all the test cases that should be covered.
|
package/README.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# box0-cli
|
|
2
|
+
|
|
3
|
+
Production-ready TypeScript CLI baseline for the box0 project. Command name: **box0**.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- Node.js ≥ 18
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install -g box0-cli
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Or link locally during development:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm run build
|
|
19
|
+
npm link
|
|
20
|
+
box0 <command>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Show help and version
|
|
27
|
+
box0 --help
|
|
28
|
+
box0 --version
|
|
29
|
+
|
|
30
|
+
# Test command (verifies the command system)
|
|
31
|
+
box0 ping # prints: pong
|
|
32
|
+
|
|
33
|
+
# Unknown commands show an error and exit with code 1
|
|
34
|
+
box0 foo
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Development
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install
|
|
41
|
+
npm run build
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Exit codes
|
|
45
|
+
|
|
46
|
+
- `0` — success (help, version, or a successful command like `ping`)
|
|
47
|
+
- `1` — usage error (unknown command or invalid usage)
|
|
48
|
+
|
|
49
|
+
## License
|
|
50
|
+
|
|
51
|
+
MIT
|
package/bin/box0.js
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { createRequire } from "module";
|
|
5
|
+
import { dirname, join } from "path";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
import { Command } from "commander";
|
|
9
|
+
|
|
10
|
+
// src/commands/ping.ts
|
|
11
|
+
function registerPing(program2) {
|
|
12
|
+
program2.command("ping").description("Test command \u2014 prints pong to verify the command system works").action(() => {
|
|
13
|
+
console.log("pong");
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/index.ts
|
|
18
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
var require2 = createRequire(import.meta.url);
|
|
20
|
+
var pkg = require2(join(__dirname, "..", "package.json"));
|
|
21
|
+
var program = new Command();
|
|
22
|
+
program.configureOutput({
|
|
23
|
+
outputError: (str, write) => {
|
|
24
|
+
if (str.includes("unknown command")) {
|
|
25
|
+
const cmd = process.argv[2] ?? "unknown";
|
|
26
|
+
write(chalk.red(`Unknown command '${cmd}'. See box0 --help.
|
|
27
|
+
`));
|
|
28
|
+
} else {
|
|
29
|
+
write(str);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
program.name("box0").description("box0 CLI \u2014 production-ready TypeScript CLI baseline").version(pkg.version);
|
|
34
|
+
registerPing(program);
|
|
35
|
+
program.exitOverride((err) => {
|
|
36
|
+
if (err.code === "commander.unknownCommand") {
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
process.exit(err.exitCode ?? 1);
|
|
40
|
+
});
|
|
41
|
+
program.parse();
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/ping.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { createRequire } from \"module\";\nimport { dirname, join } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport { registerPing } from \"./commands/ping.js\";\nimport { logger } from \"./utils/logger.js\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst require = createRequire(import.meta.url);\nconst pkg = require(join(__dirname, \"..\", \"package.json\")) as { version: string };\n\nconst program = new Command();\n\nprogram.configureOutput({\n outputError: (str, write) => {\n if (str.includes(\"unknown command\")) {\n const cmd = process.argv[2] ?? \"unknown\";\n write(chalk.red(`Unknown command '${cmd}'. See box0 --help.\\n`));\n } else {\n write(str);\n }\n },\n});\n\nprogram\n .name(\"box0\")\n .description(\"box0 CLI — production-ready TypeScript CLI baseline\")\n .version(pkg.version);\n\nregisterPing(program);\n\nprogram.exitOverride((err) => {\n if (err.code === \"commander.unknownCommand\") {\n process.exit(1);\n }\n process.exit(err.exitCode ?? 1);\n});\n\nprogram.parse();","import { Command } from \"commander\";\n\nexport function registerPing(program: Command): void {\n program\n .command(\"ping\")\n .description(\"Test command — prints pong to verify the command system works\")\n .action(() => {\n console.log(\"pong\");\n });\n}\n"],"mappings":";;;AACA,SAAS,qBAAqB;AAC9B,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAC9B,OAAO,WAAW;AAClB,SAAS,eAAe;;;ACHjB,SAAS,aAAaA,UAAwB;AACnD,EAAAA,SACG,QAAQ,MAAM,EACd,YAAY,oEAA+D,EAC3E,OAAO,MAAM;AACZ,YAAQ,IAAI,MAAM;AAAA,EACpB,CAAC;AACL;;;ADAA,IAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AACxD,IAAMC,WAAU,cAAc,YAAY,GAAG;AAC7C,IAAM,MAAMA,SAAQ,KAAK,WAAW,MAAM,cAAc,CAAC;AAEzD,IAAM,UAAU,IAAI,QAAQ;AAE5B,QAAQ,gBAAgB;AAAA,EACtB,aAAa,CAAC,KAAK,UAAU;AAC3B,QAAI,IAAI,SAAS,iBAAiB,GAAG;AACnC,YAAM,MAAM,QAAQ,KAAK,CAAC,KAAK;AAC/B,YAAM,MAAM,IAAI,oBAAoB,GAAG;AAAA,CAAuB,CAAC;AAAA,IACjE,OAAO;AACL,YAAM,GAAG;AAAA,IACX;AAAA,EACF;AACF,CAAC;AAED,QACG,KAAK,MAAM,EACX,YAAY,0DAAqD,EACjE,QAAQ,IAAI,OAAO;AAEtB,aAAa,OAAO;AAEpB,QAAQ,aAAa,CAAC,QAAQ;AAC5B,MAAI,IAAI,SAAS,4BAA4B;AAC3C,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,UAAQ,KAAK,IAAI,YAAY,CAAC;AAChC,CAAC;AAED,QAAQ,MAAM;","names":["program","require"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "box0-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Make your coding agent works like OpenClawd",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"box0": "./bin/box0.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsup",
|
|
12
|
+
"test": "vitest run",
|
|
13
|
+
"start": "box0"
|
|
14
|
+
},
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=18"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"cli",
|
|
20
|
+
"box0"
|
|
21
|
+
],
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"chalk": "^5.3.0",
|
|
25
|
+
"commander": "^12.1.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/node": "^22.10.0",
|
|
29
|
+
"tsup": "^8.3.5",
|
|
30
|
+
"typescript": "^5.7.2",
|
|
31
|
+
"vitest": "^4.0.18"
|
|
32
|
+
}
|
|
33
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from "module";
|
|
3
|
+
import { dirname, join } from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import { Command } from "commander";
|
|
7
|
+
import { registerPing } from "./commands/ping.js";
|
|
8
|
+
import { logger } from "./utils/logger.js";
|
|
9
|
+
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const require = createRequire(import.meta.url);
|
|
12
|
+
const pkg = require(join(__dirname, "..", "package.json")) as { version: string };
|
|
13
|
+
|
|
14
|
+
const program = new Command();
|
|
15
|
+
|
|
16
|
+
program.configureOutput({
|
|
17
|
+
outputError: (str, write) => {
|
|
18
|
+
if (str.includes("unknown command")) {
|
|
19
|
+
const cmd = process.argv[2] ?? "unknown";
|
|
20
|
+
write(chalk.red(`Unknown command '${cmd}'. See box0 --help.\n`));
|
|
21
|
+
} else {
|
|
22
|
+
write(str);
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
program
|
|
28
|
+
.name("box0")
|
|
29
|
+
.description("box0 CLI — production-ready TypeScript CLI baseline")
|
|
30
|
+
.version(pkg.version);
|
|
31
|
+
|
|
32
|
+
registerPing(program);
|
|
33
|
+
|
|
34
|
+
program.exitOverride((err) => {
|
|
35
|
+
if (err.code === "commander.unknownCommand") {
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
process.exit(err.exitCode ?? 1);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
program.parse();
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
|
|
3
|
+
export const logger = {
|
|
4
|
+
info(msg: string): void {
|
|
5
|
+
console.log(chalk.blue(msg));
|
|
6
|
+
},
|
|
7
|
+
success(msg: string): void {
|
|
8
|
+
console.log(chalk.green(msg));
|
|
9
|
+
},
|
|
10
|
+
warn(msg: string): void {
|
|
11
|
+
console.warn(chalk.yellow(msg));
|
|
12
|
+
},
|
|
13
|
+
error(msg: string): void {
|
|
14
|
+
console.error(chalk.red(msg));
|
|
15
|
+
},
|
|
16
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { execFile } from "child_process";
|
|
2
|
+
import { readFileSync } from "fs";
|
|
3
|
+
import { dirname, join } from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
import { describe, expect, it } from "vitest";
|
|
6
|
+
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const BIN = join(__dirname, "..", "bin", "box0.js");
|
|
9
|
+
const PKG = JSON.parse(
|
|
10
|
+
readFileSync(join(__dirname, "..", "package.json"), "utf-8"),
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
interface RunResult {
|
|
14
|
+
stdout: string;
|
|
15
|
+
stderr: string;
|
|
16
|
+
exitCode: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function run(...args: string[]): Promise<RunResult> {
|
|
20
|
+
return new Promise((resolve) => {
|
|
21
|
+
execFile("node", [BIN, ...args], (error, stdout, stderr) => {
|
|
22
|
+
resolve({
|
|
23
|
+
stdout: stdout.trim(),
|
|
24
|
+
stderr: stderr.trim(),
|
|
25
|
+
exitCode: error?.code ? Number(error.code) : 0,
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
describe("box0 --help", () => {
|
|
32
|
+
it("exits 0 and shows program name and commands", async () => {
|
|
33
|
+
const { stdout, exitCode } = await run("--help");
|
|
34
|
+
expect(exitCode).toBe(0);
|
|
35
|
+
expect(stdout).toContain("box0");
|
|
36
|
+
expect(stdout).toContain("ping");
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe("box0 --version", () => {
|
|
41
|
+
it("exits 0 and prints version from package.json", async () => {
|
|
42
|
+
const { stdout, exitCode } = await run("--version");
|
|
43
|
+
expect(exitCode).toBe(0);
|
|
44
|
+
expect(stdout).toBe(PKG.version);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe("box0 ping", () => {
|
|
49
|
+
it("exits 0 and prints pong", async () => {
|
|
50
|
+
const { stdout, exitCode } = await run("ping");
|
|
51
|
+
expect(exitCode).toBe(0);
|
|
52
|
+
expect(stdout).toBe("pong");
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
describe("box0 <unknown command>", () => {
|
|
57
|
+
it("exits 1", async () => {
|
|
58
|
+
const { exitCode } = await run("unknowncmd");
|
|
59
|
+
expect(exitCode).toBe(1);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("shows a helpful error message", async () => {
|
|
63
|
+
const { stderr } = await run("unknowncmd");
|
|
64
|
+
expect(stderr).toContain("Unknown command");
|
|
65
|
+
expect(stderr).toContain("--help");
|
|
66
|
+
});
|
|
67
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"outDir": "dist",
|
|
10
|
+
"rootDir": "src",
|
|
11
|
+
"declaration": true,
|
|
12
|
+
"declarationMap": true,
|
|
13
|
+
"sourceMap": true
|
|
14
|
+
},
|
|
15
|
+
"include": ["src/**/*"],
|
|
16
|
+
"exclude": ["node_modules", "dist"]
|
|
17
|
+
}
|