@wirecat/cli-template 0.0.0-stage → 0.1.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/.github/dependabot.yml +23 -0
- package/.github/workflows/changelog-guard.yml +12 -0
- package/.github/workflows/ci.yml +88 -0
- package/.github/workflows/main.yml +17 -0
- package/.github/workflows/monthly.yml +28 -0
- package/.github/workflows/pr.yml +19 -0
- package/.github/workflows/release.yml +191 -0
- package/.github/workflows/standards.yml +51 -0
- package/.gitleaks.toml +5 -0
- package/.markdownlint-cli2.jsonc +7 -0
- package/.vale.ini +5 -0
- package/AGENTS.md +27 -0
- package/CHANGELOG.md +31 -0
- package/CLAUDE.md +17 -0
- package/LICENSE +204 -0
- package/README.md +52 -2
- package/SECURITY.md +15 -0
- package/bin/release +139 -0
- package/biome.json +6 -0
- package/config/wirecat/LICENSE +204 -0
- package/config/wirecat/biome.base.json +157 -0
- package/config/wirecat/check.mjs +41 -0
- package/config/wirecat/cspell.json +80 -0
- package/config/wirecat/lefthook.yml +26 -0
- package/config/wirecat/manifest.json +37 -0
- package/config/wirecat/markdownlint.json +10 -0
- package/config/wirecat/no-deep-wirecat-import.grit +15 -0
- package/config/wirecat/no-exec-interpolation.grit +17 -0
- package/config/wirecat/no-new-function.grit +8 -0
- package/config/wirecat/no-shell-true.grit +8 -0
- package/config/wirecat/no-sqlite-driver.grit +15 -0
- package/config/wirecat/no-unbounded-spread.grit +10 -0
- package/config/wirecat/release-lock-info.mjs +71 -0
- package/config/wirecat/release-lock.sh +34 -0
- package/config/wirecat/rumdl.toml +9 -0
- package/contracts/help.snap +16 -0
- package/contracts/mcp-tools.json +922 -0
- package/contracts/no-leak.json +3 -0
- package/contracts/plan.json +50 -0
- package/cspell.json +10 -0
- package/dist/bin/app.d.ts +3 -0
- package/dist/bin/app.d.ts.map +1 -0
- package/dist/bin/app.js +14 -0
- package/dist/bin/app.js.map +1 -0
- package/dist/commands/doctor.d.ts +23 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +44 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/mcp.d.ts +3 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +36 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +4 -0
- package/dist/config.js.map +1 -0
- package/dist/identity.d.ts +5 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +12 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp.d.ts +19 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +62 -0
- package/dist/mcp.js.map +1 -0
- package/dist/program.d.ts +6 -0
- package/dist/program.d.ts.map +1 -0
- package/dist/program.js +37 -0
- package/dist/program.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/docs/commands.md +227 -0
- package/docs/configuration.md +18 -0
- package/docs/dev/DESIGN.md +13 -0
- package/docs/dev/TESTING.md +16 -0
- package/docs/dev/design-questions.md +24 -0
- package/docs/dev/reference-clis.md +15 -0
- package/docs/dev/skills/design-interview/SKILL.md +34 -0
- package/docs/dev/skills/release/SKILL.md +24 -0
- package/docs/dev/test-matrix.md +52 -0
- package/docs/index.md +7 -0
- package/docs/installation.md +17 -0
- package/docs/meta.json +18 -0
- package/docs/security.md +8 -0
- package/docs/troubleshooting.md +14 -0
- package/docs/usage.md +31 -0
- package/gitignore +44 -0
- package/kit/README.md +127 -0
- package/kit/dist/interview.js +170 -0
- package/kit/dist/main.js +70 -0
- package/kit/dist/manifest.js +111 -0
- package/kit/dist/new.js +256 -0
- package/kit/dist/rename.js +36 -0
- package/kit/dist/source.js +98 -0
- package/kit/dist/upgrade.js +230 -0
- package/kit/tsconfig.json +17 -0
- package/kit/tsconfig.test.json +5 -0
- package/lefthook.yml +2 -0
- package/lint/baseline/.gitkeep +0 -0
- package/lint/overrides.json +1 -0
- package/package.json +106 -4
- package/pnpm-workspace.yaml +6 -0
- package/scripts/audit.sh +22 -0
- package/scripts/command-program.ts +1 -0
- package/scripts/commands.ts +39 -0
- package/scripts/smoke.ts +56 -0
- package/scripts/test-matrix-untested.ts +12 -0
- package/skills/app-cli/SKILL.md +21 -0
- package/src/bin/app.ts +13 -0
- package/src/commands/doctor.ts +45 -0
- package/src/commands/mcp.ts +38 -0
- package/src/config.ts +4 -0
- package/src/identity.ts +15 -0
- package/src/index.ts +2 -0
- package/src/mcp.test.ts +84 -0
- package/src/mcp.ts +82 -0
- package/src/program.test.ts +66 -0
- package/src/program.ts +53 -0
- package/src/roots.test.ts +80 -0
- package/src/testing/argv-log.ts +1 -0
- package/src/testing/sandbox.ts +25 -0
- package/src/version.ts +1 -0
- package/template.json +40 -0
- package/tsconfig.json +9 -0
- package/tsconfig.scripts.json +1 -0
- package/tsconfig.test.json +1 -0
- package/vitest.config.ts +19 -0
package/src/program.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { join } from "node:path"
|
|
2
|
+
import { resolvePaths } from "@wirecat/cli-base"
|
|
3
|
+
import {
|
|
4
|
+
commandsCommand,
|
|
5
|
+
configCommand,
|
|
6
|
+
createProgram as createSharedProgram,
|
|
7
|
+
outputFor,
|
|
8
|
+
type ProgramDefinition,
|
|
9
|
+
type ProgramOptions,
|
|
10
|
+
type RunOptions,
|
|
11
|
+
run as runShared,
|
|
12
|
+
skillCommand,
|
|
13
|
+
upgradeCommand,
|
|
14
|
+
} from "@wirecat/cli-core/cli"
|
|
15
|
+
import { appUpdate } from "@wirecat/cli-core/update"
|
|
16
|
+
import type { Command } from "commander"
|
|
17
|
+
import { doctorCommand } from "./commands/doctor.js"
|
|
18
|
+
import { mcpCommand } from "./commands/mcp.js"
|
|
19
|
+
import { configuration } from "./config.js"
|
|
20
|
+
import { IDENTITY, PACKAGE, SKILL } from "./identity.js"
|
|
21
|
+
|
|
22
|
+
const update = appUpdate({
|
|
23
|
+
packageName: PACKAGE,
|
|
24
|
+
command: IDENTITY.command,
|
|
25
|
+
version: IDENTITY.version,
|
|
26
|
+
entry: import.meta.url,
|
|
27
|
+
statePath: (env) =>
|
|
28
|
+
join(resolvePaths({ appName: IDENTITY.appName, prefix: IDENTITY.envPrefix, env }).state, "update-check.json"),
|
|
29
|
+
enabled: (env) => configuration.resolveSettings({}, { env, needsProfile: false }).updateCheck,
|
|
30
|
+
offVariables: [`${IDENTITY.envPrefix}_NO_UPDATE_CHECK`],
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
export const definition = (): ProgramDefinition => ({
|
|
34
|
+
app: IDENTITY,
|
|
35
|
+
configuration: { resolveSettings: configuration.resolveSettings },
|
|
36
|
+
commands: () => [
|
|
37
|
+
commandsCommand(IDENTITY),
|
|
38
|
+
doctorCommand(),
|
|
39
|
+
skillCommand(IDENTITY, SKILL),
|
|
40
|
+
mcpCommand(),
|
|
41
|
+
upgradeCommand(IDENTITY, PACKAGE, (command) => ({
|
|
42
|
+
...outputFor(command),
|
|
43
|
+
installer: () => update.installer({}),
|
|
44
|
+
latest: () => update.latest({}),
|
|
45
|
+
install: (argv) => update.runUpdate(argv, {}),
|
|
46
|
+
})),
|
|
47
|
+
configCommand(IDENTITY, configuration),
|
|
48
|
+
],
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
export const createProgram = (options?: ProgramOptions): Command => createSharedProgram(definition(), options)
|
|
52
|
+
|
|
53
|
+
export const run = (argv: string[], options?: RunOptions): Promise<number> => runShared(argv, definition(), options)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { existsSync } from "node:fs"
|
|
2
|
+
import { homedir } from "node:os"
|
|
3
|
+
import { join } from "node:path"
|
|
4
|
+
import { expect, it } from "vitest"
|
|
5
|
+
import { run } from "./program.js"
|
|
6
|
+
|
|
7
|
+
const ran = async (argv: string[]) => {
|
|
8
|
+
const out: string[] = []
|
|
9
|
+
const err: string[] = []
|
|
10
|
+
const code = await run(argv, {
|
|
11
|
+
streams: { data: (text) => out.push(text), diagnostic: (text) => err.push(text) },
|
|
12
|
+
tty: false,
|
|
13
|
+
})
|
|
14
|
+
return { code, out: out.join("\n"), err: err.join("\n") }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
it.each([
|
|
18
|
+
["--verbose"],
|
|
19
|
+
["--quiet"],
|
|
20
|
+
["--trace"],
|
|
21
|
+
["--debug"],
|
|
22
|
+
["--timeout", "30s"],
|
|
23
|
+
["--offline"],
|
|
24
|
+
["--no-input"],
|
|
25
|
+
["--max-input-bytes", "1024"],
|
|
26
|
+
["--max-output-bytes", "0"],
|
|
27
|
+
["--brief"],
|
|
28
|
+
["--full"],
|
|
29
|
+
["--yes"],
|
|
30
|
+
["--record"],
|
|
31
|
+
["--no-record"],
|
|
32
|
+
])("doctor runs with the global option %s", async (...flag) => {
|
|
33
|
+
const { code, out } = await ran([...flag, "doctor", "--json"])
|
|
34
|
+
expect(code).toBe(0)
|
|
35
|
+
expect(JSON.parse(out).item.version).toEqual(expect.any(String))
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it("--jsonl prints one object per line", async () => {
|
|
39
|
+
const { code, out } = await ran(["--jsonl", "personal", "config", "show"])
|
|
40
|
+
expect(code).toBe(0)
|
|
41
|
+
for (const line of out.split("\n").filter(Boolean)) expect(() => JSON.parse(line)).not.toThrow()
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it("--dry-run previews a write without making it", async () => {
|
|
45
|
+
const { code } = await ran(["--dry-run", "personal", "config", "set", "limit", "5", "--json"])
|
|
46
|
+
expect(code).toBe(0)
|
|
47
|
+
const { out } = await ran(["personal", "config", "show", "--json"])
|
|
48
|
+
expect(JSON.parse(out).item.settings).toContainEqual(expect.objectContaining({ setting: "limit", value: 20 }))
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it("config set and unset change one setting and put it back", async () => {
|
|
52
|
+
for (const scope of [[], ["--defaults"], ["--personal"], ["--bot"]]) {
|
|
53
|
+
expect((await ran(["personal", "config", "set", "limit", "7", ...scope, "--json"])).code).toBe(0)
|
|
54
|
+
expect((await ran(["personal", "config", "unset", "limit", ...scope, "--json"])).code).toBe(0)
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it("config show --bot shows what a bot command would get", async () => {
|
|
59
|
+
const { code, out } = await ran(["personal", "config", "show", "--bot", "--json"])
|
|
60
|
+
expect(code).toBe(0)
|
|
61
|
+
expect(JSON.parse(out).item.profile).toBe("personal")
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it("commands info exports the schemas and reasons", async () => {
|
|
65
|
+
const { code, out } = await ran(["commands", "info", "--json"])
|
|
66
|
+
expect(code).toBe(0)
|
|
67
|
+
expect(out.length).toBeGreaterThan(0)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it("skill install writes the skill for Claude Code", async () => {
|
|
71
|
+
const { code } = await ran(["skill", "install", "--for", "claude", "--json"])
|
|
72
|
+
expect(code).toBe(0)
|
|
73
|
+
expect(existsSync(join(homedir(), ".claude", "skills", "app-cli", "SKILL.md"))).toBe(true)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it("help prints the first screen", async () => {
|
|
77
|
+
const { code, out } = await ran(["help"])
|
|
78
|
+
expect(code).toBe(0)
|
|
79
|
+
expect(out).toContain("app")
|
|
80
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ARGV_LOG, argvLogSetup as default } from "@wirecat/cli-core/testing"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { tmpdir } from "node:os"
|
|
2
|
+
import { join } from "node:path"
|
|
3
|
+
import { afterAll } from "vitest"
|
|
4
|
+
import { ARGV_LOG } from "./argv-log.js"
|
|
5
|
+
|
|
6
|
+
const saved = { ...process.env }
|
|
7
|
+
|
|
8
|
+
// cli-base's setup already gave this file a fresh TMPDIR and HOME, a keyring that throws and no network.
|
|
9
|
+
const sandbox = tmpdir()
|
|
10
|
+
process.env.APP_CONFIG_DIR = join(sandbox, "config")
|
|
11
|
+
process.env.APP_STATE_DIR = join(sandbox, "state")
|
|
12
|
+
process.env.APP_CACHE_DIR = join(sandbox, "cache")
|
|
13
|
+
process.env.MESSAGING_STORE = join(sandbox, "messages.db")
|
|
14
|
+
process.env.WIRECAT_STATE_DIR = join(sandbox, "wirecat")
|
|
15
|
+
process.env.APP_NO_UPDATE_CHECK = "1"
|
|
16
|
+
process.env.APP_TEST_ARGV_LOG = ARGV_LOG
|
|
17
|
+
delete process.env.APP_PROFILE
|
|
18
|
+
delete process.env.APP_READ_ONLY
|
|
19
|
+
delete process.env.AI_AGENT
|
|
20
|
+
delete process.env.CLAUDECODE
|
|
21
|
+
|
|
22
|
+
afterAll(() => {
|
|
23
|
+
for (const key of Object.keys(process.env)) if (!(key in saved)) delete process.env[key]
|
|
24
|
+
Object.assign(process.env, saved)
|
|
25
|
+
})
|
package/src/version.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const VERSION = "0.1.1"
|
package/template.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"files": [
|
|
3
|
+
".github/",
|
|
4
|
+
".gitignore",
|
|
5
|
+
".gitleaks.toml",
|
|
6
|
+
".vale.ini",
|
|
7
|
+
"AGENTS.md",
|
|
8
|
+
"bin/release",
|
|
9
|
+
"docs/dev/design-questions.md",
|
|
10
|
+
"docs/dev/reference-clis.md",
|
|
11
|
+
"docs/dev/skills/",
|
|
12
|
+
"docs/dev/TESTING.md",
|
|
13
|
+
"lefthook.yml",
|
|
14
|
+
"scripts/audit.sh",
|
|
15
|
+
"tsconfig.json",
|
|
16
|
+
"tsconfig.scripts.json",
|
|
17
|
+
"tsconfig.test.json"
|
|
18
|
+
],
|
|
19
|
+
"seeds": [
|
|
20
|
+
".markdownlint-cli2.jsonc",
|
|
21
|
+
"CHANGELOG.md",
|
|
22
|
+
"CLAUDE.md",
|
|
23
|
+
"LICENSE",
|
|
24
|
+
"README.md",
|
|
25
|
+
"SECURITY.md",
|
|
26
|
+
"biome.json",
|
|
27
|
+
"config/wirecat/",
|
|
28
|
+
"contracts/",
|
|
29
|
+
"cspell.json",
|
|
30
|
+
"docs/",
|
|
31
|
+
"lint/",
|
|
32
|
+
"package.json",
|
|
33
|
+
"pnpm-workspace.yaml",
|
|
34
|
+
"scripts/",
|
|
35
|
+
"skills/",
|
|
36
|
+
"src/",
|
|
37
|
+
"vitest.config.ts"
|
|
38
|
+
],
|
|
39
|
+
"placeholders": { "command": "app", "package": "@wirecat/app-cli", "repository": "WireCatLabs/app-cli" }
|
|
40
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "extends": ["./tsconfig.json", "@wirecat/cli-base/tsconfig.scripts.json"] }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "extends": ["./tsconfig.json", "@wirecat/cli-base/tsconfig.test.json"] }
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { defineConfig } from "vitest/config"
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
// Oxc does not resolve TypeScript package exports; tsc still checks the project configs.
|
|
5
|
+
tsconfig: "./node_modules/@wirecat/cli-base/config/tsconfig.base.json",
|
|
6
|
+
test: {
|
|
7
|
+
include: ["src/**/*.test.ts", "scripts/**/*.test.ts", "kit/test/**/*.test.ts"],
|
|
8
|
+
maxWorkers: 4,
|
|
9
|
+
setupFiles: ["@wirecat/cli-base/testing/setup", "src/testing/sandbox.ts"],
|
|
10
|
+
globalSetup: ["src/testing/argv-log.ts"],
|
|
11
|
+
coverage: {
|
|
12
|
+
provider: "v8",
|
|
13
|
+
include: ["src/**/*.ts"],
|
|
14
|
+
exclude: ["src/**/*.test.ts", "src/testing/**", "src/bin/**"],
|
|
15
|
+
reporter: ["text-summary", "json-summary"],
|
|
16
|
+
thresholds: { lines: 90, statements: 90, functions: 80, branches: 70 },
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
})
|