@laivc/laicode 0.0.1 → 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/README.md +117 -5
- package/bin/laicode.js +2047 -25
- package/package.json +12 -3
- package/scripts/release-check.js +20 -0
- package/scripts/smoke-test.js +116 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@laivc/laicode",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Official Lai.vc CLI for configuring developer tools.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://lai.vc",
|
|
@@ -8,6 +8,12 @@
|
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "git+https://github.com/laivc/laicode.git"
|
|
10
10
|
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/laivc/laicode/issues"
|
|
13
|
+
},
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
11
17
|
"keywords": [
|
|
12
18
|
"lai",
|
|
13
19
|
"laivc",
|
|
@@ -21,10 +27,13 @@
|
|
|
21
27
|
},
|
|
22
28
|
"files": [
|
|
23
29
|
"bin",
|
|
24
|
-
"README.md"
|
|
30
|
+
"README.md",
|
|
31
|
+
"scripts"
|
|
25
32
|
],
|
|
26
33
|
"scripts": {
|
|
27
|
-
"prepublishOnly": "node bin/laicode.js --version"
|
|
34
|
+
"prepublishOnly": "npm test && node bin/laicode.js --version",
|
|
35
|
+
"release:check": "node scripts/release-check.js",
|
|
36
|
+
"test": "node scripts/smoke-test.js"
|
|
28
37
|
},
|
|
29
38
|
"engines": {
|
|
30
39
|
"node": ">=18"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawnSync } = require("child_process")
|
|
4
|
+
|
|
5
|
+
const steps = [
|
|
6
|
+
["node", ["--check", "bin/laicode.js"]],
|
|
7
|
+
["node", ["--check", "scripts/smoke-test.js"]],
|
|
8
|
+
["npm", ["test"]],
|
|
9
|
+
["npm", ["publish", "--dry-run", "--access", "public"]],
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
for (const [cmd, args] of steps) {
|
|
13
|
+
console.log(`\n$ ${cmd} ${args.join(" ")}`)
|
|
14
|
+
const result = spawnSync(cmd, args, { stdio: "inherit", shell: process.platform === "win32" })
|
|
15
|
+
if (result.status !== 0) {
|
|
16
|
+
process.exit(result.status || 1)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
console.log("\nLaicode release check passed.")
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawnSync } = require("child_process")
|
|
4
|
+
const fs = require("fs")
|
|
5
|
+
const os = require("os")
|
|
6
|
+
const path = require("path")
|
|
7
|
+
|
|
8
|
+
const home = path.join(os.tmpdir(), "laicode-npm-smoke-test")
|
|
9
|
+
fs.rmSync(home, { recursive: true, force: true })
|
|
10
|
+
fs.mkdirSync(home, { recursive: true, mode: 0o700 })
|
|
11
|
+
fs.writeFileSync(
|
|
12
|
+
path.join(home, "config.json"),
|
|
13
|
+
JSON.stringify(
|
|
14
|
+
{
|
|
15
|
+
apiBaseUrl: "https://api.lai.vc/v1",
|
|
16
|
+
defaultModel: "gpt-5.5",
|
|
17
|
+
dashboardCache: {
|
|
18
|
+
onlineModels: 8,
|
|
19
|
+
balance: 1,
|
|
20
|
+
requests: 0,
|
|
21
|
+
version: "npm 0.0.1,待发布",
|
|
22
|
+
checkedAt: new Date().toISOString(),
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
null,
|
|
26
|
+
2
|
|
27
|
+
) + "\n",
|
|
28
|
+
{ mode: 0o600 }
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
const env = { ...process.env, LAICODE_HOME: home, LAICODE_PLAIN: "1" }
|
|
32
|
+
|
|
33
|
+
function run(args) {
|
|
34
|
+
const result = spawnSync(process.execPath, args, { encoding: "utf8", env })
|
|
35
|
+
if (result.status !== 0) {
|
|
36
|
+
process.stdout.write(result.stdout || "")
|
|
37
|
+
process.stderr.write(result.stderr || "")
|
|
38
|
+
process.exit(result.status || 1)
|
|
39
|
+
}
|
|
40
|
+
return result.stdout
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function assertIncludes(value, needle, label) {
|
|
44
|
+
if (!value.includes(needle)) {
|
|
45
|
+
console.error(`Smoke assertion failed: ${label}`)
|
|
46
|
+
console.error(`Expected to include: ${needle}`)
|
|
47
|
+
console.error(value)
|
|
48
|
+
process.exit(1)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function assertExcludes(value, needle, label) {
|
|
53
|
+
if (value.includes(needle)) {
|
|
54
|
+
console.error(`Smoke assertion failed: ${label}`)
|
|
55
|
+
console.error(`Expected to exclude: ${needle}`)
|
|
56
|
+
console.error(value)
|
|
57
|
+
process.exit(1)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function parseJson(value, label) {
|
|
62
|
+
try {
|
|
63
|
+
return JSON.parse(value)
|
|
64
|
+
} catch (err) {
|
|
65
|
+
console.error(`Smoke assertion failed: ${label}`)
|
|
66
|
+
console.error(err.message)
|
|
67
|
+
console.error(value)
|
|
68
|
+
process.exit(1)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const help = run(["bin/laicode.js", "--help"])
|
|
73
|
+
assertIncludes(help, "laicode status [--refresh] [--json]", "help lists status")
|
|
74
|
+
assertIncludes(help, "laicode commands [--json]", "help lists commands")
|
|
75
|
+
assertIncludes(help, "laicode completion [bash|zsh|fish|powershell]", "help lists completion")
|
|
76
|
+
assertIncludes(help, "laicode doctor [--model gpt-5.5] [--json]", "help lists doctor json")
|
|
77
|
+
assertIncludes(help, "laicode bench [--model gpt-5.5] [--count 3] [--json]", "help lists bench json")
|
|
78
|
+
assertIncludes(run(["bin/laicode.js", "--version"]), "0.1.0", "long version")
|
|
79
|
+
assertIncludes(run(["bin/laicode.js", "-v"]), "0.1.0", "short version")
|
|
80
|
+
assertIncludes(run(["bin/laicode.js", "--plain", "brand"]), "Lai.vc 终端字标", "plain brand command")
|
|
81
|
+
assertIncludes(run(["bin/laicode.js", "--color", "brand"]), "品牌色板", "color brand command")
|
|
82
|
+
assertIncludes(run(["bin/laicode.js", "status"]), "快照 缓存", "status uses local dashboard cache")
|
|
83
|
+
const statusJson = run(["bin/laicode.js", "status", "--json"])
|
|
84
|
+
assertIncludes(statusJson, '"cached": true', "status json uses local dashboard cache")
|
|
85
|
+
assertExcludes(statusJson, "sk-", "status json hides api keys")
|
|
86
|
+
assertExcludes(statusJson, "lc_at_", "status json hides access tokens")
|
|
87
|
+
const status = parseJson(statusJson, "status json parses")
|
|
88
|
+
if (!Array.isArray(status.nextActions) || !status.nextActions.find((action) => action.command === "laicode login")) {
|
|
89
|
+
console.error("Smoke assertion failed: status json includes first-run next action")
|
|
90
|
+
process.exit(1)
|
|
91
|
+
}
|
|
92
|
+
assertIncludes(run(["bin/laicode.js", "commands", "--json"]), '"name": "commands"', "commands json")
|
|
93
|
+
assertIncludes(run(["bin/laicode.js", "completion", "bash"]), "complete -F _laicode_completion laicode", "bash completion")
|
|
94
|
+
assertIncludes(run(["bin/laicode.js", "completion", "fish"]), "__fish_seen_subcommand_from bench", "fish completion")
|
|
95
|
+
const configJson = run(["bin/laicode.js", "config", "--json"])
|
|
96
|
+
assertIncludes(configJson, '"defaultModel": "gpt-5.5"', "config json")
|
|
97
|
+
assertExcludes(configJson, "sk-", "config json hides api keys")
|
|
98
|
+
assertExcludes(configJson, "lc_at_", "config json hides access tokens")
|
|
99
|
+
const configSetJson = run(["bin/laicode.js", "config", "set", "model", "gpt-5.4-mini", "--json"])
|
|
100
|
+
const configSet = parseJson(configSetJson, "config set json parses")
|
|
101
|
+
if (configSet.config.defaultModel !== "gpt-5.4-mini") {
|
|
102
|
+
console.error("Smoke assertion failed: config set json updates model")
|
|
103
|
+
process.exit(1)
|
|
104
|
+
}
|
|
105
|
+
const configGetSecretJson = run(["bin/laicode.js", "config", "get", "api-key", "--json"])
|
|
106
|
+
const configGetSecret = parseJson(configGetSecretJson, "config get secret json parses")
|
|
107
|
+
if (!configGetSecret.secret || configGetSecret.value !== undefined) {
|
|
108
|
+
console.error("Smoke assertion failed: config get secret json hides value")
|
|
109
|
+
process.exit(1)
|
|
110
|
+
}
|
|
111
|
+
const configUnsetJson = run(["bin/laicode.js", "config", "unset", "model", "--json"])
|
|
112
|
+
const configUnset = parseJson(configUnsetJson, "config unset json parses")
|
|
113
|
+
if (configUnset.config.defaultModel !== undefined) {
|
|
114
|
+
console.error("Smoke assertion failed: config unset json removes model")
|
|
115
|
+
process.exit(1)
|
|
116
|
+
}
|