@whyshu/argent-engine 0.6.0 → 0.6.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/MANIFEST.json +63 -29
- package/engine/VERSION +1 -1
- package/engine/core/contracts/argent.contracts.json +1 -1
- package/engine/scripts/base-bootstrap.sh +2 -1
- package/engine/scripts/billing-mode-daily.sh +2 -1
- package/engine/scripts/build-engine-package.mjs +5 -2
- package/engine/scripts/capability-packs.lock.json +25 -25
- package/engine/scripts/check-billing-mode.sh +2 -1
- package/engine/scripts/collect-evidence.mjs +42 -0
- package/engine/scripts/customer-readiness.sh +2 -1
- package/engine/scripts/daily-report.sh +2 -1
- package/engine/scripts/dev-window.sh +2 -1
- package/engine/scripts/final-check.mjs +43 -0
- package/engine/scripts/flow-requirements.json +24 -9
- package/engine/scripts/flow-timers-plist.sh +2 -1
- package/engine/scripts/flow-timers.sh +3 -1
- package/engine/scripts/flow_config.py +2 -1
- package/engine/scripts/init-ml.sh +5 -2
- package/engine/scripts/invoice-table.sh +2 -1
- package/engine/scripts/lib/argent-datadir.sh +18 -0
- package/engine/scripts/lib/argent_datadir.py +23 -0
- package/engine/scripts/poll-fulfillment.sh +4 -2
- package/engine/scripts/poll-invoice.sh +4 -2
- package/engine/scripts/provider-select.sh +2 -1
- package/engine/scripts/release-argent.sh +1 -1
- package/engine/scripts/retire-inventory.mjs +40 -0
- package/engine/scripts/run-tests.sh +2 -1
- package/engine/scripts/s1-audit.mjs +85 -0
- package/engine/scripts/usage-anchor.sh +3 -2
- package/engine/scripts/wenyao-browser.sh +3 -2
- package/engine/scripts/wenyao-login.sh +3 -2
- package/engine/scripts/ziniao-keepalive.sh +2 -1
- package/engine/scripts/ziniao-post-upgrade-check.sh +2 -1
- package/engine/scripts/ziniao-windows.sh +2 -1
- package/engine/skills/README.md +86 -0
- package/engine/skills/argent-dev/SKILL.md +41 -0
- package/engine/skills/internal.json +37 -0
- package/engine/skills/lktop-pm/SKILL.md +35 -0
- package/engine/skills/lktopapp-dev/SKILL.md +34 -0
- package/engine/skills/ml-config-guide/SKILL.md +50 -0
- package/engine/skills/ml-fulfillment-sop/SKILL.md +178 -0
- package/engine/skills/ml-fulfillment-sop/references/andes-components.md +69 -0
- package/engine/skills/ml-fulfillment-sop/references/cdp-port-mapping.md +35 -0
- package/engine/skills/ml-fulfillment-sop/references/feishu-base-fulfillment-schema.md +136 -0
- package/engine/skills/ml-fulfillment-sop/references/multi-window-concurrency.md +69 -0
- package/engine/skills/ml-fulfillment-sop/references/pitfalls.md +77 -0
- package/engine/skills/ml-fulfillment-sop/references/selectors.md +243 -0
- package/engine/skills/ml-fulfillment-sop/scripts/fulfillment.js +586 -0
- package/engine/skills/ml-fulfillment-sop/scripts/poll-and-execute.sh +271 -0
- package/engine/skills/ml-fulfillment-sop/templates/report.md +55 -0
- package/engine/skills/ml-invoice/SKILL.md +506 -0
- package/engine/skills/ml-invoice/references/pitfalls.md +268 -0
- package/engine/skills/ml-invoice/references/portal-flow.md +360 -0
- package/engine/skills/ml-invoice/references/template-fill-contract.md +133 -0
- package/engine/skills/ml-invoice-xzh/SKILL.md +133 -0
- package/engine/skills/ml-invoice-xzh/references/pitfalls.md +230 -0
- package/engine/skills/ml-store-daily-report/SKILL.md +224 -0
- package/engine/skills/ml-store-daily-report/scripts/README.md +25 -0
- package/engine/skills/ml-store-daily-report/scripts/extract.js +691 -0
- package/engine/skills/ml-store-daily-report/scripts/generate.js +299 -0
- package/engine/skills/pet-dev/SKILL.md +42 -0
- package/engine/skills/whyshu-pm/SKILL.md +35 -0
- package/engine/skills/whyshu-web-dev/SKILL.md +50 -0
- package/engine/version.mjs +1 -1
- package/engine/verticals/mercadolibre/flows.json +37 -5
- package/package.json +3 -2
- package/requirements.txt +5 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// 0.7.0 W8 只读盘点:把"待退役面"逐类定位(⛔ 只读;不改文件、不动生产、不重启)。
|
|
3
|
+
import { readdirSync, readFileSync, statSync, existsSync, writeFileSync } from 'node:fs'
|
|
4
|
+
import { join, relative, dirname } from 'node:path'
|
|
5
|
+
import { fileURLToPath } from 'node:url'
|
|
6
|
+
const REPO = join(dirname(fileURLToPath(import.meta.url)), '..')
|
|
7
|
+
const SKIP = new Set(['.git', 'node_modules', 'dist', '__pycache__', 'attic', '.venv'])
|
|
8
|
+
function walk(dir, out = []) {
|
|
9
|
+
for (const e of readdirSync(dir)) {
|
|
10
|
+
if (SKIP.has(e)) continue
|
|
11
|
+
const p = join(dir, e); const st = statSync(p)
|
|
12
|
+
if (st.isDirectory()) walk(p, out)
|
|
13
|
+
else if (/\.(mjs|js|cjs|py|sh|json|md|plist|ts)$/.test(e) && st.size < 2_000_000) out.push(p)
|
|
14
|
+
}
|
|
15
|
+
return out
|
|
16
|
+
}
|
|
17
|
+
const files = walk(REPO)
|
|
18
|
+
const hits = (re, filter = () => true) => files.filter(filter).map((f) => ({ f: relative(REPO, f), n: (readFileSync(f, 'utf8').match(re) || []).length })).filter((x) => x.n > 0).sort((a, b) => b.n - a.n)
|
|
19
|
+
const patches = existsSync(join(REPO, 'scripts/patches')) ? readdirSync(join(REPO, 'scripts/patches')).filter((f) => f.endsWith('.patch')) : []
|
|
20
|
+
const doc = {
|
|
21
|
+
generatedAt: new Date().toISOString(),
|
|
22
|
+
面: {
|
|
23
|
+
'内核补丁(patch 数 / 引用点)': { patches: patches.length, files: hits(/scripts\/patches\//).slice(0, 10) },
|
|
24
|
+
'旧单文件分发 install-argent.mjs': { files: hits(/install-argent\.mjs/).slice(0, 10) },
|
|
25
|
+
'写死 ~/.dsh 路径': { files: hits(/~\/\.dsh|\.dsh\/argent/, (f) => !f.includes('/docs/') && !f.includes('/patches/')).slice(0, 15) },
|
|
26
|
+
'launchd 双线(flow-trigger / plist / launchctl)': { files: hits(/flow-trigger|launchctl|LaunchAgents|\.plist/).slice(0, 15) },
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
console.log(JSON.stringify(doc, null, 2))
|
|
30
|
+
if (process.argv.includes('--write')) {
|
|
31
|
+
const p = join(REPO, 'docs/Argent-0.7.0-退役面盘点.md')
|
|
32
|
+
const L = ['# Argent 0.7.0 待退役面盘点(只读生成)', '', `生成时间:${doc.generatedAt}`, '', '> 本文件由 `node scripts/retire-inventory.mjs --write` 生成;⛔ 只读盘点,未改动任何被点名的面。', '']
|
|
33
|
+
for (const [k, v] of Object.entries(doc.面)) {
|
|
34
|
+
L.push(`## ${k}`, '')
|
|
35
|
+
if (v.patches !== undefined) L.push(`- patch 文件数:**${v.patches}**`)
|
|
36
|
+
for (const x of v.files) L.push(`- \`${x.f}\`(${x.n} 处)`)
|
|
37
|
+
L.push('')
|
|
38
|
+
}
|
|
39
|
+
writeFileSync(p, L.join('\n')); console.log(`\n✅ 已写 ${relative(REPO, p)}`)
|
|
40
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
. "$(dirname "$0")/lib/argent-datadir.sh" # 0.7.0 W8/S1:数据根唯一判据(⛔ 不再写死 ~/.dsh/argent)
|
|
2
3
|
# 全量测试入口(2026-09-30 补:本仓库此前有 123 个测试却无总入口 ⇒ 门禁无法一键复验)
|
|
3
4
|
#
|
|
4
5
|
# 用法:
|
|
@@ -20,7 +21,7 @@
|
|
|
20
21
|
set -uo pipefail
|
|
21
22
|
REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
22
23
|
cd "$REPO"
|
|
23
|
-
PY="$
|
|
24
|
+
PY="$ARGENT_DATA_DIR_RESOLVED/venv/bin/python3"; [ -x "$PY" ] || PY=python3
|
|
24
25
|
# 测试期间**绝不发遥测**(2026-09-30:夹具流程 flowA 的失败事件曾被推到生产告警)
|
|
25
26
|
export ARGENT_TELEMETRY_OFF=1
|
|
26
27
|
export ARGENT_TESTS_OFFLINE=1 # 测试期**零网络**(2026-10-11):监听类用例(dsh-release-watch 等)见到它就**拒绝**真发请求 ⇒ "夹具回归零网络"由开关兜住,不靠自觉
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// 0.7.0 W8/S1 **精确分类器**(只读):把 `~/.dsh` 字面量分成
|
|
3
|
+
// A 写入点(改它才影响"数据落哪",必须改)| B 回退候选(只读候选链,按分类保留)| C 注释(不动)。
|
|
4
|
+
// 用法:node scripts/s1-audit.mjs [--json] [--only A]
|
|
5
|
+
import { readdirSync, readFileSync, statSync } from 'node:fs'
|
|
6
|
+
import { join, relative, dirname } from 'node:path'
|
|
7
|
+
import { fileURLToPath } from 'node:url'
|
|
8
|
+
const REPO = join(dirname(fileURLToPath(import.meta.url)), '..')
|
|
9
|
+
const SKIP = new Set(['.git', 'node_modules', 'dist', '__pycache__', 'attic', '.venv', 'docs', 'patches', 'tests'])
|
|
10
|
+
const RE = /\.dsh\/argent|~\/\.dsh|\$HOME\/\.dsh|\$\{HOME\}\/\.dsh/
|
|
11
|
+
function walk(dir, out = []) {
|
|
12
|
+
for (const e of readdirSync(dir)) {
|
|
13
|
+
if (SKIP.has(e)) continue
|
|
14
|
+
const p = join(dir, e); const st = statSync(p)
|
|
15
|
+
if (st.isDirectory()) walk(p, out)
|
|
16
|
+
else if (/\.(mjs|js|cjs|py|sh)$/.test(e) && st.size < 2_000_000) out.push(p)
|
|
17
|
+
}
|
|
18
|
+
return out
|
|
19
|
+
}
|
|
20
|
+
// 去注释:整块块注释、行首 # 或 // 、以及行尾 // 之后的片段(⚠️ 本文件注释里别写那对定界符,会提前闭合)
|
|
21
|
+
function stripComments(src, ext) {
|
|
22
|
+
let s = src.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
23
|
+
return s.split('\n').map((line) => {
|
|
24
|
+
const t = line.trimStart()
|
|
25
|
+
if (t.startsWith('#') || t.startsWith('*') || t.startsWith('//')) return ''
|
|
26
|
+
if (ext === '.py' || ext === '.sh') return line.replace(/(^|\s)#.*$/, '')
|
|
27
|
+
return line.replace(/\/\/.*$/, '')
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
const WRITE = /(=|>>?|mkdir|touch|tee|appendFile|writeFile|Path\(|open\(|log|LOG_DIR|LOGDIR|DATA_DIR|DATA_HOME|PAUSE)/i
|
|
31
|
+
const FALLBACK = /(for\s+\w+\s+in|\|\||-f\s|\$\(.*\|\||candidates?|fallback|候选)/i
|
|
32
|
+
const files = walk(REPO).map((f) => ({ f, ext: f.slice(f.lastIndexOf('.')) }))
|
|
33
|
+
const rows = []
|
|
34
|
+
for (const { f, ext } of files) {
|
|
35
|
+
const lines = stripComments(readFileSync(f, 'utf8'), ext)
|
|
36
|
+
const hits = []
|
|
37
|
+
lines.forEach((line, i) => {
|
|
38
|
+
if (!RE.test(line)) return
|
|
39
|
+
const kind = WRITE.test(line) && !FALLBACK.test(line) ? 'A' : FALLBACK.test(line) ? 'B' : 'A?'
|
|
40
|
+
hits.push({ n: i + 1, kind, text: line.trim().slice(0, 100) })
|
|
41
|
+
})
|
|
42
|
+
if (hits.length) rows.push({ file: relative(REPO, f), hits })
|
|
43
|
+
}
|
|
44
|
+
const count = (k) => rows.reduce((n, r) => n + r.hits.filter((h) => h.kind === k).length, 0)
|
|
45
|
+
const doc = { files: rows.length, A: count('A'), 'A?': count('A?'), B: count('B'), rows: rows.sort((a, b) => b.hits.length - a.hits.length) }
|
|
46
|
+
if (process.argv.includes('--writes')) {
|
|
47
|
+
// 「非赋值写入」口径:redirect / mkdir / touch / `-f` 测试 / 内嵌 open —— 这些同样决定"数据落哪"
|
|
48
|
+
const W = /(>>?\s*\S*\.dsh\/argent|mkdir[^\n]*\.dsh\/argent|touch[^\n]*\.dsh\/argent|-f\s+"?\S*\.dsh\/argent|open\([^\n]*\.dsh\/argent|\btee\b[^\n]*\.dsh\/argent)/
|
|
49
|
+
const MSG = /(echo |scp |note\(|\$FIX)/ // 提示语/夹具路径 ⇒ 不算写入
|
|
50
|
+
const hits = []
|
|
51
|
+
for (const r of rows) for (const h of r.hits) if (W.test(h.text) && !MSG.test(h.text)) hits.push({ file: r.file, line: h.n, text: h.text })
|
|
52
|
+
if (process.argv.includes('--json')) { console.log(JSON.stringify({ total: hits.length, hits }, null, 2)); process.exit(0) }
|
|
53
|
+
console.log(`非赋值写入残留:**${hits.length} 处**(目标 0;白名单外的都算红)`)
|
|
54
|
+
for (const h of hits.slice(0, 10)) console.log(` ${h.file}:${h.line} ${h.text.slice(0, 88)}`)
|
|
55
|
+
process.exit(0)
|
|
56
|
+
}
|
|
57
|
+
if (process.argv.includes('--assignments')) {
|
|
58
|
+
// 「只认赋值行」口径:真正决定"数据落哪"的写法(⛔ 不含候选链/提示语/注释)
|
|
59
|
+
const ASSIGN = /^\s*(export\s+)?[A-Za-z_][A-Za-z0-9_]*=(.*)$/
|
|
60
|
+
const out = []
|
|
61
|
+
for (const r of rows) for (const h of r.hits) if (ASSIGN.test(h.text) && RE.test(h.text)) out.push({ file: r.file, line: h.n, text: h.text })
|
|
62
|
+
const argentHits = out.filter((h) => /\.dsh\/argent/.test(h.text))
|
|
63
|
+
const hostHits = out.filter((h) => !/\.dsh\/argent/.test(h.text))
|
|
64
|
+
if (process.argv.includes('--json')) {
|
|
65
|
+
console.log(JSON.stringify({ total: out.length, argentDataDir: argentHits.length, hostOwnedDsh: hostHits.length, hits: out }, null, 2))
|
|
66
|
+
process.exit(0)
|
|
67
|
+
}
|
|
68
|
+
// ⚠️ 必须拆分:`~/.dsh/argent`(= **Argent 数据目录**,W8 要退役的)vs 其它 `.dsh`(dsh 自己的 home:
|
|
69
|
+
// settings.yaml / profiles/ / .agent-presets ⇒ 属宿主,不归 Argent 管)
|
|
70
|
+
const argent = argentHits, hostOwn = hostHits // 与 --json 同源,⛔ 不写两遍拆分
|
|
71
|
+
if (process.argv.includes('--json')) { console.log(JSON.stringify({ total: out.length, argentDataDir: argent.length, hostOwnedDsh: hostOwn.length, hits: out }, null, 2)); process.exit(0) }
|
|
72
|
+
console.log(`赋值行字面量残留:**${out.length} 处**,其中 Argent 数据目录 \`~/.dsh/argent\` **${argent.length} 处**(W8 目标 = 0)`)
|
|
73
|
+
console.log(` 另 ${hostOwn.length} 处是 **dsh 自己的 home**(settings/profiles/presets)⇒ 属宿主面,不归 Argent`)
|
|
74
|
+
for (const h of argent.slice(0, 12)) console.log(` [argent] ${h.file}:${h.line} ${h.text.slice(0, 84)}`)
|
|
75
|
+
process.exit(0)
|
|
76
|
+
}
|
|
77
|
+
if (process.argv.includes('--json')) { console.log(JSON.stringify(doc, null, 2)); process.exit(0) }
|
|
78
|
+
console.log(`非注释字面量:${doc.files} 个文件 | A 写入点 ${doc.A} | A? 待判 ${doc['A?']} | B 回退候选 ${doc.B}`)
|
|
79
|
+
const onlyA = process.argv.includes('--only') && process.argv[process.argv.indexOf('--only') + 1] === 'A'
|
|
80
|
+
for (const r of doc.rows.slice(0, 12)) {
|
|
81
|
+
const hs = onlyA ? r.hits.filter((h) => h.kind.startsWith('A')) : r.hits
|
|
82
|
+
if (!hs.length) continue
|
|
83
|
+
console.log(` ${r.file} (${hs.length})`)
|
|
84
|
+
for (const h of hs.slice(0, 3)) console.log(` [${h.kind}] L${h.n}: ${h.text}`)
|
|
85
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
. "$(dirname "$0")/lib/argent-datadir.sh" # 0.7.0 W8/S1:数据根唯一判据(⛔ 不再写死 ~/.dsh/argent)
|
|
2
3
|
# usage-anchor —— 成本锚点定时器(每天跑一次,把真实模型成本逐日累积下来)。
|
|
3
4
|
#
|
|
4
5
|
# 为什么要有它:定价要以**实跑一段时间的成本**为锚,而不是某一次抽样。这个定时器每天
|
|
@@ -22,7 +23,7 @@ pick_py() {
|
|
|
22
23
|
local c
|
|
23
24
|
# 候选(2026-09-22):ARGENT_PY → DSH_HOME/argent/venv → ~/.dsh/argent/venv → 仓库 .venv → PATH
|
|
24
25
|
for c in "${ARGENT_PY:-}" "${DSH_HOME:-$HOME/.dsh}/argent/venv/bin/python3" \
|
|
25
|
-
"$
|
|
26
|
+
"$ARGENT_DATA_DIR_RESOLVED/venv/bin/python3" "${REPO:-}/.venv/bin/python3" \
|
|
26
27
|
"$(command -v python3 2>/dev/null || true)"; do
|
|
27
28
|
[ -n "$c" ] || continue
|
|
28
29
|
[ -x "$c" ] || continue
|
|
@@ -42,7 +43,7 @@ LABEL="com.whyshu.usage-anchor"
|
|
|
42
43
|
AGENTS="$HOME/Library/LaunchAgents"
|
|
43
44
|
PLIST="$AGENTS/$LABEL.plist"
|
|
44
45
|
LOGDIR="${ARGENT_LOG_DIR:-$HOME/Library/Logs/argent}"
|
|
45
|
-
[ -f "$
|
|
46
|
+
[ -f "$ARGENT_DATA_DIR_RESOLVED/logdir" ] && LOGDIR="$(cat "$ARGENT_DATA_DIR_RESOLVED/logdir")"
|
|
46
47
|
UID_N="$(id -u)"
|
|
47
48
|
|
|
48
49
|
gen_plist() {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
+
. "$(dirname "$0")/lib/argent-datadir.sh" # 0.7.0 W8/S1:数据根唯一判据(⛔ 不再写死 ~/.dsh/argent)
|
|
2
3
|
set -euo pipefail
|
|
3
4
|
# wenyao-browser.sh — 长驻文鳐门户浏览器(登录态可复用,供人工过一次验证 + 自动化复用)
|
|
4
5
|
#
|
|
@@ -15,12 +16,12 @@ set -euo pipefail
|
|
|
15
16
|
# 只读侦察:不导入订单、不导出文件、不改对方任何业务数据。
|
|
16
17
|
|
|
17
18
|
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
18
|
-
DATA="$
|
|
19
|
+
DATA="$ARGENT_DATA_DIR_RESOLVED"
|
|
19
20
|
PROFILE="$DATA/wenyao-profile"
|
|
20
21
|
PORT="${WENYAO_CDP_PORT:-9333}"
|
|
21
22
|
CHROME="${WENYAO_CHROME:-/Applications/Google Chrome.app/Contents/MacOS/Google Chrome}"
|
|
22
23
|
PROBE="$DATA/wenyao-probe"
|
|
23
|
-
PY="${WENYAO_PY:-$
|
|
24
|
+
PY="${WENYAO_PY:-$ARGENT_DATA_DIR_RESOLVED/venv/bin/python3}"
|
|
24
25
|
[ -x "$PY" ] || PY="$(command -v python3 || true)"
|
|
25
26
|
URL="$( [ -f "$DATA/wenyao.env" ] && grep -E '^WENYAO_URL=' "$DATA/wenyao.env" | cut -d= -f2- || echo https://my.ffl-tech.com )"
|
|
26
27
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
+
. "$(dirname "$0")/lib/argent-datadir.sh" # 0.7.0 W8/S1:数据根唯一判据
|
|
2
3
|
set -euo pipefail
|
|
3
4
|
# 上海文鳐门户「人工过验证 + 保存登录态」入口(2026-09-10)
|
|
4
5
|
#
|
|
@@ -13,7 +14,7 @@ set -euo pipefail
|
|
|
13
14
|
# 凭据来自 ~/.dsh/argent/wenyao.env(600,不进仓库)。
|
|
14
15
|
|
|
15
16
|
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
16
|
-
PY="${WENYAO_PY
|
|
17
|
+
PY="${WENYAO_PY:-$ARGENT_DATA_DIR_RESOLVED/venv/bin/python3}"
|
|
17
18
|
if [ ! -x "$PY" ]; then
|
|
18
19
|
PY="$(command -v python3 || true)"
|
|
19
20
|
fi
|
|
@@ -26,7 +27,7 @@ if ! "$PY" -c "import playwright" >/dev/null 2>&1; then
|
|
|
26
27
|
echo " (可用 WENYAO_PY=/path/to/python3 指定)" >&2
|
|
27
28
|
exit 1
|
|
28
29
|
fi
|
|
29
|
-
if [ ! -f "$
|
|
30
|
+
if [ ! -f "$ARGENT_DATA_DIR_RESOLVED/wenyao.env" ]; then
|
|
30
31
|
echo "[wenyao-login] 缺凭据文件 ~/.dsh/argent/wenyao.env(需含 WENYAO_URL/WENYAO_PHONE/WENYAO_PASSWORD,600 权限)" >&2
|
|
31
32
|
exit 1
|
|
32
33
|
fi
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
. "$(dirname "$0")/lib/argent-datadir.sh" # 0.7.0 W8/S1:数据根唯一判据(⛔ 不再写死 ~/.dsh/argent)
|
|
2
3
|
# ziniao-keepalive.sh —— 紫鸟**常驻 WebDriver 模式**的守护(W2 部署件)
|
|
3
4
|
#
|
|
4
5
|
# ## 为什么需要
|
|
@@ -38,7 +39,7 @@ INTERVAL_SEC="${ZINIAO_KEEPALIVE_INTERVAL_SEC:-180}"
|
|
|
38
39
|
log() { echo "[$(date '+%F %T')] $*"; }
|
|
39
40
|
pick_py() {
|
|
40
41
|
local c
|
|
41
|
-
for c in "${ARGENT_PY:-}" "$
|
|
42
|
+
for c in "${ARGENT_PY:-}" "$ARGENT_DATA_DIR_RESOLVED/venv/bin/python3" "$REPO/.venv/bin/python3" \
|
|
42
43
|
"$(command -v python3 2>/dev/null || true)"; do
|
|
43
44
|
[ -n "$c" ] && [ -x "$c" ] && { printf '%s' "$c"; return 0; }
|
|
44
45
|
done
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
. "$(dirname "$0")/lib/argent-datadir.sh" # 0.7.0 W8/S1:数据根唯一判据
|
|
2
3
|
# ziniao-post-upgrade-check.sh —— 紫鸟客户端**升级后**的一键复核(只读 + 幂等;不改业务数据)
|
|
3
4
|
#
|
|
4
5
|
# 背景:2026-09-24 排查"30 天人工登录",定位到根因 = 客户端 6.26.6.6 太旧(Bridge 没有 /login 路由
|
|
@@ -19,7 +20,7 @@ REPO="$(argent_repo_root "${BASH_SOURCE[0]}")"
|
|
|
19
20
|
# ARGENT_PY → PATH 的 python3 → 默认位置的 venv。
|
|
20
21
|
_DATA_PY="${ARGENT_PY:-$(command -v python3 2>/dev/null || true)}"
|
|
21
22
|
if [ -z "$_DATA_PY" ] || [ ! -x "$_DATA_PY" ]; then
|
|
22
|
-
_DATA_PY="$
|
|
23
|
+
_DATA_PY="$ARGENT_DATA_DIR_RESOLVED/venv/bin/python3"
|
|
23
24
|
fi
|
|
24
25
|
DATA="$("$_DATA_PY" "$REPO/scripts/argent-datadir.py" 2>/dev/null || true)"
|
|
25
26
|
if [ -z "$DATA" ]; then
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
. "$(dirname "$0")/lib/argent-datadir.sh" # 0.7.0 W8/S1:数据根唯一判据(⛔ 不再写死 ~/.dsh/argent)
|
|
2
3
|
# ziniao-windows.sh —— 紫鸟**窗口**运维小工具(W5:窗口回收由人显式决定,不自动关)
|
|
3
4
|
#
|
|
4
5
|
# 为什么不做"跑完自动关店"(W5 的原始设想被否):我们刚修好"每轮 startBrowser = 重启窗口"
|
|
@@ -24,7 +25,7 @@ set -uo pipefail
|
|
|
24
25
|
# (克隆在 ~/.argent-dsh)上找不到本仓文件(2026-09-28 实测)
|
|
25
26
|
. "$(dirname "${BASH_SOURCE[0]}")/lib/repo-root.sh"
|
|
26
27
|
REPO="$(argent_repo_root "${BASH_SOURCE[0]}")"
|
|
27
|
-
PY="${ARGENT_PY:-$
|
|
28
|
+
PY="${ARGENT_PY:-$ARGENT_DATA_DIR_RESOLVED/venv/bin/python3}"
|
|
28
29
|
[ -x "$PY" ] || PY="$(command -v python3)"
|
|
29
30
|
|
|
30
31
|
cmd="${1:-list}"; shift || true
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Argent 技能目录
|
|
2
|
+
|
|
3
|
+
本目录存放 Argent 的 DSH 技能(SKILL.md 格式)。运行时落位到 `<dshHome>/skills`
|
|
4
|
+
(preset 零配置挂载 `skill-filesystem` 的默认根,扫描直接子目录)。
|
|
5
|
+
|
|
6
|
+
## 技能目录谁在管(2026-10-04 按现行代码订正)
|
|
7
|
+
|
|
8
|
+
**升级器有角色过滤了(= 外发白名单)。** 三个环节的行为各不相同:
|
|
9
|
+
|
|
10
|
+
| 环节 | 行为 | 证据 |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| **安装**(`install-argent.mjs`) | **完全不碰技能目录**:只 `mkdirSync` 保证存在,不清理、不新增 | `install-argent.mjs:584-590`(注释「KB-061:不再按角色隔离」「已存在的 `<dshHome>/skills` 与仓库技能目录一律不碰」) |
|
|
13
|
+
| **安装**(`install-dsh.sh`) | 旧 bash 安装器,角色只支持 `general` / `hr-office`;`ml-seller` 分支直接 die(企业级订阅专享) | `install-dsh.sh:26-40` |
|
|
14
|
+
| **升级**(`scripts/argent-upgrade.mjs`) | **只同步外发集**(= `verticals/*/manifest.json#skills` 并集,判据复用 `check-skill-classification.mjs#classify()`);**内部角色技能(`skills/internal.json`)不同步**;宿主里既有的内部/旧技能**只报告不删**;内容 sha 一致 ⇒ 幂等跳过 | `argent-upgrade.mjs#syncSkills`(2026-10-04 修:客户机实测旧版 `✓ 技能同步: 11 项` = 5 外发 + 6 内部,违反 D5);回归 `scripts/tests/upgrade-skill-whitelist.test.mjs` |
|
|
15
|
+
| **清理**(`scripts/skill-install.mjs --prune-orphans`) | **人工决策**的收敛动词(默认 dry-run):只列"将删除(点名)/ 未点名 / 拒绝清理",真删要 `--apply` **且逐个 `--allow <name>` 点名**;只删四条件同时满足的目录(不在外发集 / 不在 `internal.json` / 不在安装器清单 / 含 `SKILL.md`),**先备份再删** | 见下「收敛宿主里的旧残留」;回归 `scripts/tests/skill-subset.test.mjs`【F】 |
|
|
16
|
+
|
|
17
|
+
**收敛宿主里的旧残留(客户机实测:6 个内部角色技能 + 12 个旧 hermes 期技能)** —— 升级器**故意不删**,
|
|
18
|
+
所以清理是**人的决定**,命令分两步(`--dir` 写死目标最稳;`~/.dsh/skills` 就是 dsh 宿主的技能根):
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# ① 先看清单(缺省 dry-run,零副作用):哪些会被删、哪些拒绝、为什么
|
|
22
|
+
node ~/Code/argent-dsh/scripts/skill-install.mjs --host dsh --prune-orphans --allow-host-dsh-prune
|
|
23
|
+
# ② 逐个核对名字后**逐个点名**真删(备份到 <dir>/.argent-skills-pruned-<ts>/,审计见 .argent-skills-prune-audit.jsonl)
|
|
24
|
+
node ~/Code/argent-dsh/scripts/skill-install.mjs --host dsh --prune-orphans --allow-host-dsh-prune \
|
|
25
|
+
--apply --allow hermes-era-skill-01 --allow hermes-era-skill-02
|
|
26
|
+
```
|
|
27
|
+
⚠️ **不该自动清的**:`skills/internal.json` 里的 6 个内部角色技能(宿主上它们是**角色包「已装」的判据**,
|
|
28
|
+
清了角色包状态就对不上)、外发集里那 5 个(归升级器/安装器管)、安装器清单里的(用 `--uninstall`)、
|
|
29
|
+
任何**用户自建**(非技能形态一律拒绝;手写技能与旧残留形态无法区分 ⇒ 只能靠逐个点名 + 人眼核对)。
|
|
30
|
+
|
|
31
|
+
**结论**:技能一旦在仓库 `skills/` 下,**必须先在两处声明里归类**(外发 or 内部)——外发的会被同步给
|
|
32
|
+
每一个 agent 的技能目录,内部的**不会**;**未归类的目录不会被同步**,但门禁会判红(`G2`)。
|
|
33
|
+
角色级的技能可见性由**网关群级** `chats[<chatId>].skills` 决定
|
|
34
|
+
(`plugins/argent-gateway/src/index.js:628-629` 拼成「【本群启用技能】…」进 prompt),
|
|
35
|
+
角色级 `skills` 字段只是权益回显。**不要把 `ml-daily` / `ml-fulfillment` 当技能目录名**——
|
|
36
|
+
它们是套餐装配档标识,实际目录是 `ml-store-daily-report` / `ml-fulfillment-sop`。
|
|
37
|
+
|
|
38
|
+
> 历史说明:旧文档写的「角色 → 技能集合(`install-argent.mjs` 的 `ROLE_SKILLS`)」**已无实现**——
|
|
39
|
+
> 该符号在全仓库只剩两处注释提及(`plugins/argent-core/src/index.js:195` 与本文),没有任何代码路径。
|
|
40
|
+
|
|
41
|
+
## 当前技能清单(11 个目录)—— 并且**分成外发 / 内部两半**
|
|
42
|
+
|
|
43
|
+
> ⚠️ 2026-10-03(P3)更正:本节原写「9 个目录」,实际 **11**(漏了 `ml-invoice-xzh` / `ml-config-guide`)。
|
|
44
|
+
> 清单**不再手抄**,判据在两处声明里:外发 = `verticals/<id>/manifest.json#skills`(**唯一真源**),
|
|
45
|
+
> 内部 = `skills/internal.json`(逐条带理由)。跑 `node scripts/check-skill-classification.mjs` 看当前分类。
|
|
46
|
+
|
|
47
|
+
**外发(客户可用的流程技能,5 个)** —— 真源:`verticals/mercadolibre/manifest.json#skills`
|
|
48
|
+
|
|
49
|
+
- `ml-fulfillment-sop/` —— FULL 货件管理(含 references / scripts / template)
|
|
50
|
+
- `ml-store-daily-report/` —— 美客多店铺日报
|
|
51
|
+
- `ml-invoice/` —— 上海文鳐发票全链路
|
|
52
|
+
- `ml-invoice-xzh/` —— 鑫中航发票全链路(同引擎、不同门户)
|
|
53
|
+
- `ml-config-guide/` —— 配置缺口诊断与引导(替代写死 schema 快照的旧校验)
|
|
54
|
+
|
|
55
|
+
**内部(不外发的角色技能,6 个)** —— 真源:`skills/internal.json`(含逐条理由)
|
|
56
|
+
|
|
57
|
+
- `argent-dev/` `pet-dev/` `whyshu-web-dev/` `whyshu-pm/` `lktop-pm/` `lktopapp-dev/`
|
|
58
|
+
(角色包「已装」的硬判据:`plugins/argent-packs/src/index.js` 以 `~/.dsh/skills/<skill>` 是否存在为准)
|
|
59
|
+
|
|
60
|
+
⚠️ **往 `skills/` 丢一个新目录 = 必须先归类**:外发(写进业务线声明)才会同步给客户,
|
|
61
|
+
未归类的目录**不会**被同步,但门禁 `G2` 会判红(升级器只发外发集,见上表)⇒ 必须先做一次决定:
|
|
62
|
+
写进业务线声明(外发)或写进 `skills/internal.json`(内部)。
|
|
63
|
+
安装到非 dsh 宿主用 `node scripts/skill-install.mjs --host <dsh|claude-code|codex|cursor> --apply`(只装外发 5 个;**缺省只预演**,真装要 `--apply`)。
|
|
64
|
+
|
|
65
|
+
## 技能格式
|
|
66
|
+
|
|
67
|
+
```markdown
|
|
68
|
+
---
|
|
69
|
+
name: <skill-id>
|
|
70
|
+
description: <一句话说明,用于技能目录展示与匹配>
|
|
71
|
+
---
|
|
72
|
+
<技能正文指令>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
硬约束(`dsh-skill-filesystem` 的 `parseSkillFile()`):首行 `---` 且**有闭合 `---`**;
|
|
76
|
+
`name` 必须是**严格小写 kebab-case**且等于目录名(**中文名一律非法**,会被静默丢弃);
|
|
77
|
+
frontmatter 必须**同时含 `name` 与 `description`**。
|
|
78
|
+
|
|
79
|
+
改完技能后跑门禁:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
python3 scripts/fix-skill-frontmatter.py --check # 格式(闭合 + kebab name + description)
|
|
83
|
+
node scripts/tests/skills-frontmatter.test.mjs
|
|
84
|
+
node scripts/check-skill-classification.mjs # 归类(外发/内部/未归类即红)
|
|
85
|
+
node scripts/tests/skill-subset.test.mjs # 归类 + 外发安装器回归
|
|
86
|
+
```
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: argent-dev
|
|
3
|
+
description: Argent开发者角色技能:Argent on DSH 开发知识(安装器/插件/preset/脚本)与 dsh 插件三种角色能力设计。接 whyshu-pm 任务,完成后飞书群 @ 汇报。
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
author: 问述科技 (Whyshu)
|
|
6
|
+
license: MIT
|
|
7
|
+
metadata:
|
|
8
|
+
argent:
|
|
9
|
+
role: argent-dev
|
|
10
|
+
tags: [argent, dsh, cordis, plugin]
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Argent开发者(argent-dev)
|
|
14
|
+
|
|
15
|
+
## 角色定位
|
|
16
|
+
|
|
17
|
+
Argent 产品开发者,负责 argent-dsh 仓库(安装器/插件/preset/脚本/skills)与策划文档的落地。
|
|
18
|
+
|
|
19
|
+
## 核心知识入口
|
|
20
|
+
|
|
21
|
+
- **Argent 仓库**:`/Users/chester/Code/argent-dsh`(本机开发仓库,远端 whyshu 裸仓库镜像)
|
|
22
|
+
- `install-argent.mjs`:跨平台安装器(`--role / --dsh-home / --port` 等)
|
|
23
|
+
- `plugins/`:argent-core / argent-skin / argent-files / argent-ml(cordis 插件)
|
|
24
|
+
- `presets/`:各角色 Agent Preset(agent.cordis.yml 组合)
|
|
25
|
+
- `scripts/`:daily-report.mjs / orchestrator.py / feishu-bridge.js 等
|
|
26
|
+
- **策划文档**:`/Users/chester/Code/whyshu/docs/products/argent-*`(含
|
|
27
|
+
`argent-edition-multi-instance-plan.md` 多实例生态策划案 v0.9)
|
|
28
|
+
- **dsh 插件开发**:三种角色能力设计(Service Definition / Provider / Consumer,
|
|
29
|
+
参考 deepseek-harness 官方 practice 文档)。
|
|
30
|
+
|
|
31
|
+
## 协作流
|
|
32
|
+
|
|
33
|
+
1. whyshu-pm 在飞书群 @ 开发者分配任务并附验收标准(旧看板已退场;新任务机制上线前以此为准);
|
|
34
|
+
2. 在飞书群/会话中确认验收标准;
|
|
35
|
+
3. 完成后在飞书群 @whyshu-pm 汇报。
|
|
36
|
+
|
|
37
|
+
## 红线(仓库全局规则)
|
|
38
|
+
|
|
39
|
+
- **严禁重启本机 dsh web 服务**(LaunchAgent com.whyshu.dsh-web,自杀式重启);
|
|
40
|
+
- **严禁擅自升级/重装全局 dsh**(锁定 0.1.1-rc.1,快照安装流程);
|
|
41
|
+
- 客户端插件改动浏览器硬刷新生效;host 端插件改动需用户手动重启服务。
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_doc": "技能归类清单(P3 / §6.1 D5,2026-10-03)。本文件只列**内部角色技能(不外发)**并逐条写理由。",
|
|
3
|
+
"_rule": [
|
|
4
|
+
"① **外发半边不在这里**:外发集 = 所有 `verticals/*/manifest.json#skills` 的并集(今天 = 5 个流程技能)。照抄到这里就是第二份名单 ⇒ 必然漂移,故刻意不抄。",
|
|
5
|
+
"② 判据(门禁 `scripts/check-skill-classification.mjs`):`skills/` 下每个含 SKILL.md 的目录必须 ∈ 外发集 ∪ 本清单;**两边都没有 ⇒ 红**(往 skills/ 丢目录 = 默认发给每个客户,因为升级器无角色过滤)。",
|
|
6
|
+
"③ 本清单的每一条也必须真实存在(过期条目 ⇒ 红),且必须带非空 `reason`。",
|
|
7
|
+
"④ 只有 `reason`(+ 可选的 `since`)是判据字段;其它键是给人看的。"
|
|
8
|
+
],
|
|
9
|
+
"_why": "客户机形态是『陪跑式』:客户已有自己的 agent,我们只交付**流程技能**。内部角色技能讲的是我方研发/PM/项目知识(安装器、插件、preset、问述官网、云宠乐园、LKTOP 需求分发),发给客户既无用又泄露我方工作方式。",
|
|
10
|
+
"_source": "docs/Argent-陪跑式交付-实施方案.md §6.1 D5(用户 2026-10-03 批准:外发 5 / 内部 6)",
|
|
11
|
+
"internal": {
|
|
12
|
+
"argent-dev": {
|
|
13
|
+
"reason": "Argent 自身开发知识:安装器 / 插件 / preset / 脚本内部结构 —— 我方研发知识,客户既不需要也涉及实现细节",
|
|
14
|
+
"since": "2026-09-11"
|
|
15
|
+
},
|
|
16
|
+
"whyshu-pm": {
|
|
17
|
+
"reason": "问述科技 PM 角色流程(策划案接单、飞书群 @ 分发、验收闭环)—— 我方内部工作流",
|
|
18
|
+
"since": "2026-09-11"
|
|
19
|
+
},
|
|
20
|
+
"whyshu-web-dev": {
|
|
21
|
+
"reason": "问述官网(whyshu.com / Next.js)开发与部署 —— 我方自有资产,与客户业务无关",
|
|
22
|
+
"since": "2026-09-11"
|
|
23
|
+
},
|
|
24
|
+
"pet-dev": {
|
|
25
|
+
"reason": "云宠乐园项目开发知识 —— 另一个客户/项目的内部资产,与美客多陪跑交付无关",
|
|
26
|
+
"since": "2026-09-11"
|
|
27
|
+
},
|
|
28
|
+
"lktop-pm": {
|
|
29
|
+
"reason": "LKTOP 需求掌握与任务分发 —— 另一个客户线的内部角色流程",
|
|
30
|
+
"since": "2026-09-11"
|
|
31
|
+
},
|
|
32
|
+
"lktopapp-dev": {
|
|
33
|
+
"reason": "LKTOP APP(uni-app / 微信小游戏)开发知识 —— 另一个客户线的内部角色流程",
|
|
34
|
+
"since": "2026-09-11"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lktop-pm
|
|
3
|
+
description: LKTOPPM角色技能:LKTOP 需求掌握与任务分发(飞书群 @ + 会话),验收闭环。
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
author: 问述科技 (Whyshu)
|
|
6
|
+
license: MIT
|
|
7
|
+
metadata:
|
|
8
|
+
argent:
|
|
9
|
+
role: lktop-pm
|
|
10
|
+
tags: [lktop, pm, task]
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# LKTOPPM(lktop-pm)
|
|
14
|
+
|
|
15
|
+
## 角色定位
|
|
16
|
+
|
|
17
|
+
LKTOP 项目产品经理:掌握 LKTOP 需求,拆解并分发任务给 LKTOPAPP开发者(lktopapp-dev),验收闭环。
|
|
18
|
+
|
|
19
|
+
## 核心知识入口
|
|
20
|
+
|
|
21
|
+
- **LKTOP 需求**:website-next 站点(`/Users/chester/Code/website-next`,LKTOP careers 站,
|
|
22
|
+
部署技能 website-next-deploy)与 LKTOP 产品文档
|
|
23
|
+
- **任务分发**:lark-task / lark-doc / lark-im
|
|
24
|
+
|
|
25
|
+
## 协作流
|
|
26
|
+
|
|
27
|
+
1. 需求拆解 → 在飞书群 @ 开发者派单(必须含:标题、描述、验收标准、优先级、截止时间;旧看板已退场,新任务机制上线前以此为准);
|
|
28
|
+
2. 分配给 LKTOPAPP开发者(lktopapp-dev);
|
|
29
|
+
3. 分配完成后飞书群 @lktopapp-dev Bot 通知;
|
|
30
|
+
4. 开发者完成 @ 汇报 → 查看改动与验证 → 在飞书群/会话中确认验收或打回并说明原因;
|
|
31
|
+
5. 用户会在群中直接指正,及时响应。
|
|
32
|
+
|
|
33
|
+
## 约定
|
|
34
|
+
|
|
35
|
+
- 任务信息在会话与飞书群保持同步;派单信息完整,避免开发者猜测。
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lktopapp-dev
|
|
3
|
+
description: LKTOPAPP开发者角色技能:LKTOP APP 开发(uni-app / wechat-minigame)+ LKTOP 需求文档。接 lktop-pm 任务,完成后飞书群 @ 汇报。
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
author: 问述科技 (Whyshu)
|
|
6
|
+
license: MIT
|
|
7
|
+
metadata:
|
|
8
|
+
argent:
|
|
9
|
+
role: lktopapp-dev
|
|
10
|
+
tags: [lktop, app, uni-app, minigame]
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# LKTOPAPP开发者(lktopapp-dev)
|
|
14
|
+
|
|
15
|
+
## 角色定位
|
|
16
|
+
|
|
17
|
+
LKTOP APP 开发者:需求实现、缺陷修复、版本发布。
|
|
18
|
+
|
|
19
|
+
## 核心知识入口
|
|
20
|
+
|
|
21
|
+
- **技能**:`uni-app`(跨端应用开发)、`wechat-minigame`(微信小游戏)等
|
|
22
|
+
(位于本机 `~/.agents/skills/`,由 preset 的 customSkillDirs 装载)
|
|
23
|
+
- **LKTOP 需求文档**:website-next 站点与 LKTOP 产品文档(与 lktop-pm 同源)
|
|
24
|
+
|
|
25
|
+
## 协作流
|
|
26
|
+
|
|
27
|
+
1. lktop-pm 在飞书群 @ 开发者分配任务并附验收标准(旧看板已退场;新任务机制上线前以此为准);
|
|
28
|
+
2. 在飞书群/会话中确认需求与验收标准;
|
|
29
|
+
3. 完成后在飞书群 @lktop-pm 汇报(改动摘要 + 验证结果)。
|
|
30
|
+
|
|
31
|
+
## 红线
|
|
32
|
+
|
|
33
|
+
- 发布前核对目标环境与回滚预案;
|
|
34
|
+
- 涉及生产数据/凭据的操作先与用户确认。
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ml-config-guide
|
|
3
|
+
description: "ML 流程的**配置缺口诊断与引导**:读数据源的实际字段(live schema),对照流程声明的必需字段集,找出缺口并一步步提醒用户补录;替代原先写死 schema 快照的 init-ml.sh 校验。触发:配置缺口、字段缺失、数据源不满足流程、init-ml 校验失败、新客户接入。"
|
|
4
|
+
tags: [配置, 缺口, 分诊, 数据源, schema, 文鳐, 发票]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# ML 流程配置缺口诊断与引导
|
|
8
|
+
|
|
9
|
+
> 适用:接入新客户 / 新流程,或数据源被运营改动后,**判断某个流程能不能跑、缺什么**。
|
|
10
|
+
> 设计依据:`docs/ml-agent-architecture.md` §5.6(源注册表)、§5.8(live schema + 字段缺口)。
|
|
11
|
+
|
|
12
|
+
## 为什么不用 `init-ml.sh` 那套写死的校验
|
|
13
|
+
|
|
14
|
+
旧做法把**某次表结构的快照**(2026-08-13,12 字段)当成期望值,失败时还指引
|
|
15
|
+
`base-bootstrap.sh --force`(**删表重建**)。表结构一演进(如 lip 表已 +6 系统字段),
|
|
16
|
+
它就必然报 diff 并**把用户引向危险操作**。⇒ 改为:**流程声明必需字段** + **每次读 live schema**。
|
|
17
|
+
|
|
18
|
+
## 三步法(不要跳步)
|
|
19
|
+
|
|
20
|
+
### 1) 拿事实(薄脚本,不做判断)
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
python3 scripts/ml_schema_check.py --flow wenyao-invoice --profile lip-customer
|
|
24
|
+
# 退出码 0 = 字段齐备 ; 1 = 有缺口 ; 2 = 读不到源/参数错(与"有缺口"区分)
|
|
25
|
+
# 加 --json 供程序消费;离线可用 --fields-from-json <字段名数组>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
输出会给出**每个缺口字段的用途**与**应由谁补**(运营 / 我方)。
|
|
29
|
+
|
|
30
|
+
### 2) 判断与引导(你做)
|
|
31
|
+
|
|
32
|
+
- **缺运营字段**(品名/材质/重量/尺寸/产品图…)⇒ 告诉用户"**请在表里补 X、Y**",并说明**为什么需要**;
|
|
33
|
+
一次只提醒**必要的几项**,不要一次丢 20 条。
|
|
34
|
+
- **缺我方字段**(系统字段清单以 `argent gap` 的输出为准,**别在这里背字段名**)⇒ 走**建字段**流程,
|
|
35
|
+
但**先经用户确认**(改客户生产表结构属敏感操作)。
|
|
36
|
+
- **⚠️ HS 编码例外**:属**报关敏感 + 人工维护**(决策 2026-08-19)——
|
|
37
|
+
**系统不预填、不写候选、不自动确认**;缺 HS 只**提示运营补**,且**不得据此推进开票**。
|
|
38
|
+
- **读不到源(退出码 2)** ⇒ **落"源不可读"告警卡**(如 91403 权限不足),**绝不静默跳过**。
|
|
39
|
+
|
|
40
|
+
### 3) 复验
|
|
41
|
+
|
|
42
|
+
补完后**再跑一次第 1 步**;齐备(退出码 0)才把该流程的待办交给对应角色
|
|
43
|
+
(文鳐 ⇒ `ml-invoice-wy`),并**在派单/会话里附上本次检查输出**(作为"当时为什么能跑"的证据)。
|
|
44
|
+
|
|
45
|
+
## 硬性红线
|
|
46
|
+
|
|
47
|
+
- **不改客户表结构**(建字段必须用户确认);**不动**运营业务字段(SKU/店铺/数量/装箱数/材质/HS)。
|
|
48
|
+
- **不要**用"旧快照 diff"或 `--force` 重建表;字段口径真源是 `scripts/flow-requirements.json`
|
|
49
|
+
(由 `scripts/wenyao-template-map.json` 等生成,勿手改生成物)。
|
|
50
|
+
- 新增流程 = **加一条 `flow-requirements.json` 条目** + (如需)源注册表条目,**不改本 SKILL 的判断逻辑**。
|