@blod-nm/1kuan-act-01-cli 0.1.3 → 0.1.4

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 CHANGED
@@ -30,15 +30,27 @@ act-01 config import "act01w.v1.xxxx" # prompts for the passphrase used at gen
30
30
 
31
31
  Transfer strings are AES-256-GCM encrypted; the passphrase never travels with the string.
32
32
 
33
+ ## One-shot setup
34
+
35
+ ```bash
36
+ ACT01_EXPORT_PASS="<passphrase>" act-01 setup --install ~/.claude/skills "<config-string>"
37
+ ```
38
+
39
+ Installs the skill doc, imports the config, and prints the balance in one command
40
+ (passphrase via env; config string also accepted on stdin or `ACT01_IMPORT_STRING`).
41
+ `--install <dir>` writes `<dir>/act-01-ops/SKILL.md`.
42
+
33
43
  ## Operations
34
44
 
35
45
  ```bash
36
- act-01 create --mode random --total 10000 --count 50 --per-user 2 --min 100 --max 500
46
+ act-01 redpacket check --mode random --total 10000 --count 50 --per-user 2 --min 100 --max 500
47
+ act-01 redpacket create --mode random --total 10000 --count 50 --per-user 2 --min 100 --max 500 --yes
37
48
  ```
38
49
 
39
50
  - Amounts are integer units, no conversion
40
51
  - Pre-flight balance check runs before execution; insufficient balance is rejected locally
41
52
  - Interactive confirm card lists every parameter before the atomic database function call
53
+ - `create` is non-interactive only with `--yes` (otherwise it asks for confirmation)
42
54
  - `--dry-run` prints the function call without executing; `--json` for machine output
43
55
 
44
56
  ## MCP (AI client integration)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blod-nm/1kuan-act-01-cli",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "description": "Internal operations CLI: invoke preset database functions via a gateway. Zero dependencies, MCP (stdio) support.",
6
6
  "license": "MIT",
package/src/main.js CHANGED
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import { parseArgs } from 'node:util'
6
+ import { mkdirSync, writeFileSync } from 'node:fs'
6
7
  import { VERSION } from './version.js'
7
8
  import { join } from 'node:path'
8
9
  import { configPath, expandPath, loadConfig, saveConfig, decodeConfigString, encryptConfig } from './store.js'
@@ -23,8 +24,9 @@ const USAGE = `act-01 —— operations CLI(invoke preset database functions)
23
24
  config test 连接测试(SELECT 1,验证 envId/apiKey)
24
25
  config export 导出加密配置串(口令交互输入或 ACT01_EXPORT_PASS)
25
26
  config import <串|--stdin> [--pass <口令>] 导入配置串(加密串需口令;自动识别 三种格式)
27
+ setup <串|--stdin> [--install <技能根目录>] 一条命令:装技能 + 导配置 + 查余额
26
28
  mcp 启动 MCP 服务(stdio;接入 Claude 等 AI 客户端)
27
- skill 输出 agent 技能文档(--install <dir> 写入)
29
+ skill 输出 agent 技能文档(--install <技能根目录> 装成 <root>/act-01-ops/SKILL.md)
28
30
  balance account balance
29
31
  redpacket create create a record(pre-flight balance check, atomic deduct)
30
32
  redpacket check validate params(side-effect free)
@@ -150,6 +152,23 @@ async function cmdConfig(argv) {
150
152
  throw err
151
153
  }
152
154
 
155
+ if (sub === 'test') {
156
+ const config = loadConfig()
157
+ const apikey = resolveApikey(config, undefined)
158
+ if (!config.envId || !apikey) {
159
+ const err = new Error('配置不完整:先 config set envId 和 apiKey')
160
+ err.exitCode = 2
161
+ throw err
162
+ }
163
+ const r = await execPgsql(config, apikey, 'SELECT 1 AS ok')
164
+ if (!r.ok) {
165
+ console.error(`error: 连接测试失败 (${r.message})`)
166
+ return 1
167
+ }
168
+ console.log('连接测试通过(SELECT 1)')
169
+ return 0
170
+ }
171
+
153
172
  if (sub === 'export') {
154
173
  const config = loadConfig()
155
174
  if (!config.envId || !config.apiKey) {
@@ -317,6 +336,15 @@ function normalizeFromValues(values) {
317
336
 
318
337
  /* ---------- skill ---------- */
319
338
 
339
+ /** 把 SKILL.md 装到 <root>/<SKILL_NAME>/SKILL.md(目录式,匹配主流 agent 技能布局) */
340
+ function installSkill(root) {
341
+ const dir = join(expandPath(root), SKILL_NAME)
342
+ mkdirSync(dir, { recursive: true, mode: 0o755 })
343
+ const file = join(dir, 'SKILL.md')
344
+ writeFileSync(file, SKILL_MD)
345
+ return file
346
+ }
347
+
320
348
  async function cmdSkill(argv) {
321
349
  const { values, positionals } = parseArgs({
322
350
  strict: false,
@@ -332,13 +360,9 @@ async function cmdSkill(argv) {
332
360
  }
333
361
 
334
362
  if (values.install) {
335
- const { mkdirSync, writeFileSync } = await import('node:fs')
336
- const dir = expandPath(values.install)
337
- mkdirSync(dir, { recursive: true, mode: 0o755 })
338
- const file = join(dir, 'SKILL.md')
339
- writeFileSync(file, SKILL_MD)
363
+ const file = installSkill(values.install)
340
364
  console.log(`SKILL.md 已写入: ${file}`)
341
- console.error('hint: 把该目录加入你的 agent 技能路径')
365
+ console.error(`hint: 已装成 <技能根目录>/${SKILL_NAME}/SKILL.md;根目录指你的 agent 扫描的那个 skills 目录`)
342
366
  return 0
343
367
  }
344
368
 
@@ -346,6 +370,72 @@ async function cmdSkill(argv) {
346
370
  return 0
347
371
  }
348
372
 
373
+ /* ---------- setup(一条命令:装技能 + 导配置 + 查余额) ---------- */
374
+
375
+ /** 解析配置串(明文/加密)、写盘;返回 { envId, apiKey } */
376
+ function importConfig(body, passFlag) {
377
+ const decoded = decodeConfigString(body)
378
+ let cfg = decoded.config
379
+ if (decoded.encrypted) {
380
+ const pass = passFlag ?? process.env.ACT01_EXPORT_PASS
381
+ if (!pass) {
382
+ const err = new Error('加密串需要口令:用 ACT01_EXPORT_PASS 环境变量或 --pass 传入')
383
+ err.exitCode = 2
384
+ throw err
385
+ }
386
+ cfg = decoded.decode(pass)
387
+ }
388
+ if (!cfg.envId || !cfg.apiKey) {
389
+ const err = new Error('配置串内容不完整(缺 envId 或 apiKey)')
390
+ err.exitCode = 2
391
+ throw err
392
+ }
393
+ saveConfig({ envId: cfg.envId, apiKey: cfg.apiKey })
394
+ return cfg
395
+ }
396
+
397
+ async function cmdSetup(argv) {
398
+ const { values, positionals } = parseArgs({
399
+ strict: false,
400
+ allowPositionals: true,
401
+ args: argv,
402
+ options: { install: { type: 'string' }, pass: { type: 'string' }, json: { type: 'boolean', short: 'j' } },
403
+ })
404
+
405
+ let body = positionals[0] ?? process.env.ACT01_IMPORT_STRING
406
+ if (!body && !process.stdin.isTTY) body = await readStdinText()
407
+ if (!body) {
408
+ const err = new Error('setup 需要 <配置串>(位置参数 / stdin / ACT01_IMPORT_STRING)')
409
+ err.exitCode = 2
410
+ throw err
411
+ }
412
+
413
+ const cfg = importConfig(body, str(values, 'pass'))
414
+ const skillPath = values.install ? installSkill(values.install) : null
415
+
416
+ const account = await execPgsql(cfg, resolveApikey(cfg, undefined), ACCOUNT_SQL)
417
+ const wallet =
418
+ account.ok && account.rows?.[0]?.data?.wallet && typeof account.rows[0].data.wallet === 'object'
419
+ ? account.rows[0].data.wallet
420
+ : {}
421
+ const points = account.ok ? Number(wallet.points || 0) : null
422
+ const label = account.ok ? String(wallet.label || 'account') : null
423
+
424
+ if (values.json === true) {
425
+ printJson({ ok: account.ok, envId: cfg.envId, apiKeySet: true, skillPath, balance: points, account: label, error: account.ok ? null : account.message })
426
+ } else {
427
+ console.log('setup 完成:')
428
+ console.log(skillPath ? ` 技能: SKILL.md → ${skillPath}` : ' 技能: (未装;加 --install <技能根目录>)')
429
+ console.log(` 配置: envId ${cfg.envId},apiKey 已打码写入 0600`)
430
+ if (account.ok) console.log(` 余额: ${points}(${label})`)
431
+ else {
432
+ console.error(` 余额: 查询失败 (${account.message})`)
433
+ return 1
434
+ }
435
+ }
436
+ return 0
437
+ }
438
+
349
439
  /* ---------- redpacket check(零副作用参数校验) ---------- */
350
440
 
351
441
  async function cmdCheck(argv) {
@@ -527,6 +617,7 @@ export async function main(argv) {
527
617
  if (cmd === 'balance') return await cmdBalance(argv.slice(1))
528
618
  if (cmd === 'mcp') return await startMcp()
529
619
  if (cmd === 'skill') return await cmdSkill(argv.slice(1))
620
+ if (cmd === 'setup') return await cmdSetup(argv.slice(1))
530
621
  if (cmd === 'redpacket') {
531
622
  const sub = argv[1]
532
623
  if (sub === 'create') return await cmdCreate(argv.slice(2))
package/src/skill.js CHANGED
@@ -23,6 +23,11 @@ const BODY = [
23
23
  '',
24
24
  '所有命令零依赖,Node >= 18。',
25
25
  '',
26
+ '## 一条命令装好(推荐)',
27
+ '',
28
+ B + 'act-01 setup "<配置串>" --install <技能根目录>' + B + ' —— 一次完成:装技能 + 导配置 + 查余额,',
29
+ '口令走 ' + B + 'ACT01_EXPORT_PASS' + B + ' 环境变量;配置串也可走 stdin 或 ' + B + 'ACT01_IMPORT_STRING' + B + '。',
30
+ '',
26
31
  '## 工具面',
27
32
  '',
28
33
  '| 途径 | 命令 / MCP 工具 | 副作用 |',
@@ -54,7 +59,7 @@ const BODY = [
54
59
  '## Agent 行为规则',
55
60
  '',
56
61
  '1. **先 check 后 create**:参数没把握时,先调 redpacket_check,拿到校验报告再执行',
57
- '2. **create 前必须向用户确认参数**(mode/total/count/区间/群归属),MCP 客户端会弹审批',
62
+ '2. **create 前必须向用户确认参数**(mode/total/count/区间/群归属);确认后执行时,**非交互(非 TTY)必须带 --yes**,否则 CLI 会拒绝(MCP 客户端则弹审批)',
58
63
  '3. **结果转述只给摘要**:packet_no、余额变化;不要猜测或编造未返回的字段',
59
64
  '4. **失败处理**:错误信息是人话(余额不足/区间错误/整除错误),原样转告用户并给出修正建议;不要重试同参数的 create',
60
65
  '5. **金额单位**:内部整数单位,不要做 ×100 或 ÷100 的换算,除非用户明确要求',
package/src/version.js CHANGED
@@ -3,4 +3,4 @@
3
3
  * (test/version.test.js 会断言两者一致,防止再漏升)。
4
4
  */
5
5
 
6
- export const VERSION = '0.1.3'
6
+ export const VERSION = '0.1.4'