@social-data/social-neuron-subscription 1.0.0-beta.2 → 1.0.0-beta.20

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/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
 
4
- // ⚠️ 本文件由 backend/app/cli_spec/gen.py 生成,请勿手改;要改改 gen.py 的 _CLI_JS 后重跑 gen。
4
+ // ⚠️ 本文件由 core/cli/gen.py 生成,请勿手改;要改改 gen.py 的 _CLI_JS 后重跑 gen。
5
5
  //
6
6
  // 能力 CLI —— 通用薄运行时(纯 JS,零依赖):一能力一命令、一包、一配置文件,互不影响。
7
7
  // <cmd> <action> [--flags] 调用一条命令
@@ -40,7 +40,11 @@ function resolveConfig() {
40
40
 
41
41
  function emit(env) {
42
42
  process.stdout.write(JSON.stringify(env) + "\n");
43
- process.exit(env.ok ? 0 : (EXIT[env.error && env.error.type] ?? 1));
43
+ const dataExit = env.ok && env.data && env.data.meta && env.data.meta.exit_code;
44
+ const status = env.ok
45
+ ? ([0, 1, 2].includes(dataExit) ? dataExit : 0)
46
+ : (EXIT[env.error && env.error.type] ?? 1);
47
+ process.exit(status);
44
48
  }
45
49
  function fail(type, code, message, extra) {
46
50
  emit({ ok: false, error: { type, code, message, ...(extra || {}) } });
@@ -61,7 +65,9 @@ function normalize(body) {
61
65
  const type = forgeType(body.code);
62
66
  let message = body.msg || "";
63
67
  if (type === "outdated") message += "(升级后请重新加载 SKILL.md 与 manifest 再调用)";
64
- return { ok: false, error: { type, code: body.code, message } };
68
+ // 网关在 data 里带审计 trace_id 的业务错误(如查询失败):透出供 get-query 回查。
69
+ const extra = body.data && body.data.trace_id ? { trace_id: body.data.trace_id } : {};
70
+ return { ok: false, error: { type, code: body.code, message, ...extra } };
65
71
  }
66
72
  return { ok: false, error: { type: "api_error", code: "UNKNOWN", message: JSON.stringify(body).slice(0, 200) } };
67
73
  }
@@ -109,15 +115,63 @@ function printWelcome() {
109
115
  w("──────────────────────────────────────────────");
110
116
  }
111
117
 
118
+ // ── 嵌套对象形状:object(json) / list[object](json) 这类 flag 光看类型名没法拼 JSON,
119
+ // 这里把 input_schema.$defs 里**被引用到的**对象摊开印出来(与 SKILL.md 同源同内容)。
120
+ // 没有这段时,调用方只能靠 422 报错反推字段名。
121
+ function typeStr(node) {
122
+ if (!node || typeof node !== "object") return "any";
123
+ if (typeof node.$ref === "string") return node.$ref.split("/").pop();
124
+ const union = node.anyOf || node.oneOf;
125
+ if (union) {
126
+ const parts = union.filter((n) => n && n.type !== "null").map(typeStr);
127
+ return parts.length ? parts.join("|") : "any";
128
+ }
129
+ if (Array.isArray(node.enum)) return "enum(" + node.enum.join("|") + ")";
130
+ if (node.type === "array") return "list[" + typeStr(node.items) + "]";
131
+ return node.type || "any";
132
+ }
133
+ function refsOf(node, acc) {
134
+ if (!node || typeof node !== "object") return acc;
135
+ if (Array.isArray(node)) { for (const n of node) refsOf(n, acc); return acc; }
136
+ if (typeof node.$ref === "string") acc.add(node.$ref.split("/").pop());
137
+ for (const k of Object.keys(node)) if (k !== "$defs") refsOf(node[k], acc);
138
+ return acc;
139
+ }
140
+ function objectBlocks(schema) {
141
+ const defs = (schema && schema.$defs) || {};
142
+ const queue = [...refsOf((schema && schema.properties) || {}, new Set())], seen = new Set();
143
+ while (queue.length) { // 递归:GroupLevel 会引用自己、Leaf 会被 AndNode 引用
144
+ const name = queue.shift();
145
+ if (seen.has(name) || !defs[name]) continue;
146
+ seen.add(name);
147
+ for (const r of refsOf(defs[name], new Set())) queue.push(r);
148
+ }
149
+ const out = [];
150
+ for (const name of [...seen].sort()) {
151
+ const d = defs[name], props = d.properties;
152
+ if (!props) continue;
153
+ const required = new Set(d.required || []);
154
+ const rows = Object.keys(props).map((k) => [k, typeStr(props[k]), required.has(k) ? "required" : "optional",
155
+ props[k].description || ""]);
156
+ const w0 = Math.max(...rows.map((r) => r[0].length)), w1 = Math.max(...rows.map((r) => r[1].length));
157
+ out.push("对象 " + name + ":" + (d.description ? " " + d.description.split("\n")[0] : ""));
158
+ for (const r of rows) out.push(" " + r[0].padEnd(w0) + " " + r[1].padEnd(w1) + " " + r[2].padEnd(8) + " " + r[3]);
159
+ }
160
+ return out;
161
+ }
162
+
112
163
  function usageOf(cmd) {
113
164
  const line = (f) => " " + f.flag + " " + f.type + (f.required ? " required" : " optional") + " " + (f.desc || "");
114
165
  const req = cmd.flags.filter((f) => f.required), opt = cmd.flags.filter((f) => !f.required);
166
+ const blocks = objectBlocks(cmd.input_schema);
115
167
  return {
116
168
  command: COMMAND + " " + cmd.action,
117
169
  required: req.map((f) => ({ flag: f.flag, type: f.type, desc: f.desc })),
118
170
  optional: opt.map((f) => ({ flag: f.flag, type: f.type, desc: f.desc })),
171
+ objects: blocks, // 同样带进 INVALID_ARGS 报错里,拼错时直接能看到形状
119
172
  example: (COMMAND + " " + cmd.action + " " + req.map((f) => f.flag + " <v>").join(" ")).trim(),
120
- _text: [COMMAND + " " + cmd.action + " — " + cmd.summary, "Inputs:", ...cmd.flags.map(line)].join("\n"),
173
+ _text: [COMMAND + " " + cmd.action + " — " + cmd.summary, "Inputs:", ...cmd.flags.map(line),
174
+ ...(blocks.length ? ["", ...blocks] : [])].join("\n"),
121
175
  };
122
176
  }
123
177
  function printHelp(action) {
@@ -130,7 +184,7 @@ function printHelp(action) {
130
184
  w(COMMAND + " v" + VERSION + " — Social Neuron 能力 CLI(能力:" + CAPABILITY + ";供 AI agent 调用)");
131
185
  w("");
132
186
  w("用法:" + COMMAND + " <action> [--flags]");
133
- w(" 标量 --flag v;数组 --flag a,b;对象 --flag '<json>';写/删/触发加 -y");
187
+ w(" 标量 --flag v;数组/对象一律 JSON:--flag '[\"a\",\"b\"]' / --flag '{\"k\":\"v\"}';写/删/触发加 -y");
134
188
  w("");
135
189
  w("命令:");
136
190
  for (const c of MANIFEST.tools) w(" " + COMMAND + " " + c.action + " — " + c.summary);
@@ -158,8 +212,17 @@ function parseArgs(cmd, argv) {
158
212
  const raw = argv[++i];
159
213
  if (raw === undefined) return { err: fail("validation", "MISSING_VALUE", a + " 缺少取值") };
160
214
  let val = raw;
161
- if (f.type.startsWith("list")) val = raw.split(",").map((s) => s.trim()).filter(Boolean);
162
- else if (f.type.startsWith("object")) { try { val = JSON.parse(raw); } catch { return { err: fail("validation", "BAD_JSON", a + " 需为合法 JSON") }; } }
215
+ if (f.type.indexOf("(json)") >= 0) {
216
+ // 数组/对象一律按 JSON 解析(与 MCP 入参同形)。不做「逗号分隔」这类特例:
217
+ // 同一份文档要能同时用于两个出口,取值写法就只能有一种。
218
+ try { val = JSON.parse(raw); } catch {
219
+ const hint = f.type.startsWith("list") ? "JSON 数组,如 '[\"a\",\"b\"]'" : "JSON 对象,如 '{\"k\":\"v\"}'";
220
+ return { err: fail("validation", "BAD_JSON", a + " 需为 " + hint + "(当前取值:" + raw + ")") };
221
+ }
222
+ if (f.type.startsWith("list") && !Array.isArray(val)) {
223
+ return { err: fail("validation", "BAD_JSON", a + " 需为 JSON 数组,如 '[\"a\",\"b\"]';单个取值也要写成数组") };
224
+ }
225
+ }
163
226
  else if (f.type === "integer") val = Number(raw);
164
227
  args[f.field] = val;
165
228
  }
@@ -167,7 +230,8 @@ function parseArgs(cmd, argv) {
167
230
  }
168
231
 
169
232
  async function main() {
170
- const argv = process.argv.slice(2);
233
+ let argv = process.argv.slice(2);
234
+ if (argv.length === 0 && MANIFEST.default_action) argv = [MANIFEST.default_action];
171
235
  if (argv.length === 0 || argv[0] === "--help" || argv[0] === "-h") return printHelp();
172
236
  if (argv[0] === "--version" || argv[0] === "-V") { process.stdout.write(VERSION + "\n"); return; }
173
237
  if (argv[0] === "bind") return doBind(argv.slice(1));
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
 
4
- // ⚠️ 本文件由 backend/app/cli_spec/gen.py 生成,请勿手改。
4
+ // ⚠️ 本文件由 core/cli/gen.py 生成,请勿手改。
5
5
  // postinstall:把包内 SKILL.md 覆盖写到 OpenClaw 技能目录(OPENCLAW_SKILLS_DIR 或 ~/.openclaw/skills)。
6
6
 
7
7
  const fs = require("fs");