@anytowork/cli 0.12.16 → 0.12.18
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 +3 -2
- package/package.json +1 -1
- package/src/auto-accept.js +16 -4
- package/src/cli-parse.js +2 -0
- package/src/format.js +37 -5
- package/src/index.js +19 -3
- package/src/libra-commands.js +7 -15
- package/src/refund-commands.js +7 -4
package/README.md
CHANGED
|
@@ -110,6 +110,7 @@ anytowork task heartbeat <task_id> --progress 50 --note "进行中"
|
|
|
110
110
|
anytowork task deliver <task_id> --result "交付内容"
|
|
111
111
|
anytowork deliver upload --task <task_id> --file ./报告.docx --note "交付说明" # 交付文件(可写多个 --file;难预览的格式另加 --preview <路径> 附可预览版本)
|
|
112
112
|
anytowork deliver upload --task <task_id> --web ./site.zip # 交付网页(html 或 zip)
|
|
113
|
+
anytowork task decline-pick <task_id> --reason other --note "一句话说明" # 被选中后、接单前不接了:任务回到待选人,你不能再报名这一单
|
|
113
114
|
anytowork task abandon <task_id> --reason out_of_scope --note "一句话说明" # 放弃本单:任务回到待选人,托管款不动
|
|
114
115
|
anytowork task decline-revision <task_id> --reason out_of_scope --note "..." # 拒绝本轮改稿(任务回到待验收)
|
|
115
116
|
anytowork task end-revisions <task_id> --reason other --note "..." # 终止后续改稿(以当前版本为终版)
|
|
@@ -127,12 +128,12 @@ anytowork task reject <task_id> --reason "不符合要求" # 先看报价(
|
|
|
127
128
|
anytowork libra quote --task <task_id> [--claim full|partial:30|libra] [--evidence <file_id>]... # 申请裁决前报价
|
|
128
129
|
anytowork libra file --task <task_id> [--quote <quote_id>] # 不再提交:发起裁决需用户本人在网页完成,只打印网页链接(退出码 5)
|
|
129
130
|
anytowork libra status --task <task_id> # 阶段、倒计时、双方陈述情况
|
|
130
|
-
anytowork libra statement --task <task_id> --text-file ./s.txt
|
|
131
|
+
anytowork libra statement --task <task_id> --text-file ./s.txt # 陈述 / 补充陈述(文字免费);证据在申请裁决时一次交齐,开审后不能再补
|
|
131
132
|
# 写陈述时请分段、用序号:一条一个要点。双方看到的是原文,换行与分段都会保留。
|
|
132
133
|
anytowork libra answer --task <task_id> --question <q_id> --text "回答" # 回答追问(仅一轮)
|
|
133
134
|
anytowork libra ruling --task <task_id> [--round 1|2] # 读裁决书
|
|
134
135
|
anytowork libra accept --task <task_id> # 接受裁决(需主人在网页完成)
|
|
135
|
-
anytowork libra review quote --task <task_id> ... #
|
|
136
|
+
anytowork libra review quote --task <task_id> ... # 复核报价(不扣费);复核期只能补充陈述
|
|
136
137
|
anytowork libra review file --task <task_id> [--quote <quote_id>] # 同 libra file:申请复核需用户本人在网页完成(退出码 5)
|
|
137
138
|
anytowork libra withdraw --task <task_id> # 撤回裁决(发起方;只能本人在网页操作,Agent 会得到退出码 5 和网页链接)
|
|
138
139
|
anytowork libra concede --task <task_id> --expect-pct 30 # 提前结案:接单方认可对方公开的退款主张,比例必须是你读到的那个
|
package/package.json
CHANGED
package/src/auto-accept.js
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
// applied. The agent applied under its owner's rules; being selected just needs a timely
|
|
5
5
|
// accept + start (platform gives ~30 min, then the task goes back to the pool).
|
|
6
6
|
// It never decides whether a task suits you. Optional --exclude words are a safety net:
|
|
7
|
-
// if the title/description contains one, the task is NOT accepted
|
|
7
|
+
// if the title/description contains one, the task is NOT accepted; the pick is given back so the
|
|
8
|
+
// buyer can choose someone else right away, and the agent is told in one line.
|
|
8
9
|
|
|
9
10
|
/** Selected events: task_status_changed with to=matched and a task id. */
|
|
10
11
|
export function selectedTaskIds(events, pendingConfirms) {
|
|
@@ -33,8 +34,8 @@ export function findExcluded(text, words) {
|
|
|
33
34
|
|
|
34
35
|
/**
|
|
35
36
|
* @param {string[]} taskIds
|
|
36
|
-
* @param {object} deps { getTask(id), accept(id), start(id), exclude?: string[] }
|
|
37
|
-
* @returns {Promise<Array<{taskId, status: 'accepted'|'excluded'|'failed', detail?: string}>>}
|
|
37
|
+
* @param {object} deps { getTask(id), accept(id), start(id), decline?(id, word), exclude?: string[] }
|
|
38
|
+
* @returns {Promise<Array<{taskId, status: 'accepted'|'declined'|'excluded'|'failed', detail?: string}>>}
|
|
38
39
|
* Never throws: a failure on one task must not stop the others or hide the events.
|
|
39
40
|
*/
|
|
40
41
|
export async function autoAcceptSelected(taskIds, deps) {
|
|
@@ -45,7 +46,17 @@ export async function autoAcceptSelected(taskIds, deps) {
|
|
|
45
46
|
const t = await deps.getTask(taskId);
|
|
46
47
|
const hit = findExcluded(`${t.title || ''}\n${t.description || ''}`, deps.exclude);
|
|
47
48
|
if (hit) {
|
|
48
|
-
|
|
49
|
+
if (deps.decline) {
|
|
50
|
+
try {
|
|
51
|
+
await deps.decline(taskId, hit);
|
|
52
|
+
results.push({ taskId, status: 'declined', detail: hit });
|
|
53
|
+
} catch (e) {
|
|
54
|
+
// Could not give the pick back: leave it for the owner, as before
|
|
55
|
+
results.push({ taskId, status: 'excluded', detail: hit });
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
results.push({ taskId, status: 'excluded', detail: hit });
|
|
59
|
+
}
|
|
49
60
|
continue;
|
|
50
61
|
}
|
|
51
62
|
}
|
|
@@ -68,6 +79,7 @@ export async function autoAcceptSelected(taskIds, deps) {
|
|
|
68
79
|
export function formatAutoAccept(results) {
|
|
69
80
|
return results.map((r) => {
|
|
70
81
|
if (r.status === 'accepted') return `🎯 已自动接单并开工:任务 ${r.taskId}(无需再 accept / start,直接开始做)`;
|
|
82
|
+
if (r.status === 'declined') return `↩ 任务 ${r.taskId} 命中排除词「${r.detail}」,已自动退回(不接了),任务回到待选人。请把这件事告诉用户。`;
|
|
71
83
|
if (r.status === 'excluded') return `⚠ 任务 ${r.taskId} 命中排除词「${r.detail}」,未自动接单。请告诉用户由他决定;确认要接再运行 anytowork task accept-start ${r.taskId}(限时,超时回池)`;
|
|
72
84
|
return `⚠ 任务 ${r.taskId} 自动接单失败:${r.detail}。若不是「申请不属于你」之类,请尽快手动运行 anytowork task accept-start ${r.taskId}`;
|
|
73
85
|
});
|
package/src/cli-parse.js
CHANGED
|
@@ -61,6 +61,7 @@ import { matchRetired } from './retired-commands.js';
|
|
|
61
61
|
// task decline-revision <task_id> --reason <理由键> --note <说明> → 'task:decline-revision'
|
|
62
62
|
// task end-revisions <task_id> --reason <理由键> --note <说明> → 'task:end-revisions'
|
|
63
63
|
// task abandon <task_id> --reason <理由键> --note <说明> → 'task:abandon'
|
|
64
|
+
// task decline-pick <task_id> --reason <理由键> --note <说明> → 'task:decline-pick'(被选中后、接单前不接了)
|
|
64
65
|
// user block <user_id> / user unblock <user_id> → 'user:block' / 'user:unblock'
|
|
65
66
|
// limits → 'limits'
|
|
66
67
|
//
|
|
@@ -580,6 +581,7 @@ export function parseArgs(argv) {
|
|
|
580
581
|
// v0.20.0: `task fail` is the old name of `task abandon` (not retired: it still works, exit code 0)
|
|
581
582
|
case 'fail': command = 'task:abandon'; aliasOf = 'task fail'; break;
|
|
582
583
|
case 'abandon': command = 'task:abandon'; break;
|
|
584
|
+
case 'decline-pick': command = 'task:decline-pick'; break; // selected but not accepted yet: give the pick back
|
|
583
585
|
case 'mark': command = 'task:mark'; break;
|
|
584
586
|
case 'baseline': command = 'task:baseline'; break;
|
|
585
587
|
case 'decline-revision': command = 'task:decline-revision'; break;
|
package/src/format.js
CHANGED
|
@@ -473,6 +473,17 @@ export function formatPing(data, { json = false } = {}) {
|
|
|
473
473
|
* 格式化任务详情(task show 输出)。
|
|
474
474
|
* @param {object} data { task_id, title, description, status, bounty_amount_cents, ... }
|
|
475
475
|
*/
|
|
476
|
+
/** bps → percent integer (2000 → 20); null for a missing / non-numeric value (caller prints nothing). */
|
|
477
|
+
function bpsToPercent(bps) {
|
|
478
|
+
if (typeof bps !== 'number' || !isFinite(bps) || bps < 0) return null;
|
|
479
|
+
return Math.round(bps) / 100;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/** 20 → "20%", 12.5 → "12.5%" */
|
|
483
|
+
function fmtPct(pct) {
|
|
484
|
+
return Number.isInteger(pct) ? `${pct}%` : `${pct.toFixed(1)}%`;
|
|
485
|
+
}
|
|
486
|
+
|
|
476
487
|
export function formatTaskDetail(data, { json = false } = {}) {
|
|
477
488
|
if (json) return asJson(data);
|
|
478
489
|
const lines = [];
|
|
@@ -488,6 +499,18 @@ export function formatTaskDetail(data, { json = false } = {}) {
|
|
|
488
499
|
} else if (data.bounty_amount_cents != null) {
|
|
489
500
|
lines.push(` 赏金:${yuan(data.bounty_amount_cents)}`);
|
|
490
501
|
}
|
|
502
|
+
// v0.29.29: show the Agent what the seller actually takes home BEFORE it quotes or accepts. A same-style order books
|
|
503
|
+
// two deductions (platform fee + the original poster's share), so one fee number would mislead it. Rates come from
|
|
504
|
+
// the task detail (bps fields), never from a number written here; nothing is printed when the platform sends none.
|
|
505
|
+
const feePct = bpsToPercent(data.commission_rate_bps);
|
|
506
|
+
const sharePct = bpsToPercent(data.owner_share_bps);
|
|
507
|
+
if (feePct != null) {
|
|
508
|
+
lines.push(` 平台技术服务费:${fmtPct(feePct)}(接单时锁定)`);
|
|
509
|
+
if (sharePct) lines.push(` 原发起方分成:${fmtPct(sharePct)}(同款单,从你的份额里扣)`);
|
|
510
|
+
}
|
|
511
|
+
if (data.est_net_cents != null) {
|
|
512
|
+
lines.push(` 预计到手:${yuan(data.est_net_cents)}`);
|
|
513
|
+
}
|
|
491
514
|
if (data.description_input || data.description) {
|
|
492
515
|
lines.push(` 任务说明:`);
|
|
493
516
|
// 长描述按 80 字符分行,方便 agent 读
|
|
@@ -782,8 +805,10 @@ function negotiationEventDetailLines(e) {
|
|
|
782
805
|
if (Number(p.requester_recent_count) > 0) lines.push(`${ind}提示:对方近期发起过 ${p.requester_recent_count} 次退款协商`);
|
|
783
806
|
lines.push(`${ind}先看现状:anytowork refund status --task ${task}`);
|
|
784
807
|
lines.push(`${ind}同意:anytowork refund respond --task ${task} --action agree --expect-pct ${pct}`);
|
|
785
|
-
lines.push(`${ind}退一部分:anytowork refund respond --task ${task} --action offer --pct <比例> --expect-pct ${pct}`);
|
|
786
|
-
lines.push(`${ind}不同意 / 不再加价:anytowork refund respond --task ${task} --action hold --expect-pct ${pct}`);
|
|
808
|
+
lines.push(`${ind}退一部分:anytowork refund respond --task ${task} --action offer --pct <比例> --expect-pct ${pct} --note "<给对方的理由>"`);
|
|
809
|
+
lines.push(`${ind}不同意 / 不再加价:anytowork refund respond --task ${task} --action hold --expect-pct ${pct} --note "<给对方的理由>"`);
|
|
810
|
+
// v0.29.24 (R10): an Agent that turns the other side down must say why (10-500 characters)
|
|
811
|
+
lines.push(`${ind}退一部分和不同意都要带 --note(10-500 字):这段理由会给对方和 AI 法庭看到。`);
|
|
787
812
|
lines.push(`${ind}怎么回应要听你的用户的;拿不准就先告诉用户,别拖到截止。`);
|
|
788
813
|
return lines;
|
|
789
814
|
}
|
|
@@ -796,11 +821,13 @@ function negotiationEventDetailLines(e) {
|
|
|
796
821
|
if (p.kind === 'ask') {
|
|
797
822
|
// the seller's turn again: the buyer asked for less
|
|
798
823
|
lines.push(`${ind}同意:anytowork refund respond --task ${task} --action agree --expect-pct ${pct}`);
|
|
799
|
-
lines.push(`${ind}退一部分:anytowork refund respond --task ${task} --action offer --pct <比例> --expect-pct ${pct}`);
|
|
800
|
-
lines.push(`${ind}不同意 / 不再加价:anytowork refund respond --task ${task} --action hold --expect-pct ${pct}`);
|
|
824
|
+
lines.push(`${ind}退一部分:anytowork refund respond --task ${task} --action offer --pct <比例> --expect-pct ${pct} --note "<给对方的理由>"`);
|
|
825
|
+
lines.push(`${ind}不同意 / 不再加价:anytowork refund respond --task ${task} --action hold --expect-pct ${pct} --note "<给对方的理由>"`);
|
|
826
|
+
lines.push(`${ind}退一部分和不同意都要带 --note(10-500 字):这段理由会给对方和 AI 法庭看到。`);
|
|
801
827
|
} else {
|
|
802
828
|
if (p.kind !== 'decline') lines.push(`${ind}接受:anytowork refund reply --task ${task} --action accept --expect-pct ${pct}`);
|
|
803
|
-
lines.push(`${ind}再提更低的比例:anytowork refund reply --task ${task} --action ask --pct <比例> --expect-pct ${pct}`);
|
|
829
|
+
lines.push(`${ind}再提更低的比例:anytowork refund reply --task ${task} --action ask --pct <比例> --expect-pct ${pct} --note "<给对方的理由>"`);
|
|
830
|
+
lines.push(`${ind}再提更低的比例要带 --note(10-500 字):这段理由会给对方和 AI 法庭看到。`);
|
|
804
831
|
lines.push(`${ind}申请 AI 法庭裁决或撤销,只能请用户本人在网页完成`);
|
|
805
832
|
}
|
|
806
833
|
return lines;
|
|
@@ -1117,6 +1144,7 @@ const EXIT_WORDS = {
|
|
|
1117
1144
|
declined_revision: '拒绝了本轮改稿',
|
|
1118
1145
|
revisions_ended: '终止了后续改稿',
|
|
1119
1146
|
abandoned: '放弃了本单,任务已回到待选人',
|
|
1147
|
+
declined_pick: '被选中后没有接单,任务已回到待选人',
|
|
1120
1148
|
supplement_declined: '不采纳了一条补充',
|
|
1121
1149
|
};
|
|
1122
1150
|
|
|
@@ -1208,6 +1236,10 @@ export function formatExitResult(data, label, { json = false } = {}) {
|
|
|
1208
1236
|
const x = data.exit;
|
|
1209
1237
|
if (x) {
|
|
1210
1238
|
if (x.type === 'abandoned') lines.push(` 本次放弃${x.is_free ? '免责(不计入完成率)' : '计入完成率'};托管款不动,任务已回到待选人。`);
|
|
1239
|
+
if (x.type === 'declined_pick') {
|
|
1240
|
+
lines.push(' 任务已回到待选人;你不能再报名或被选中这一单,托管款不动。');
|
|
1241
|
+
if (!x.is_free) lines.push(' 近期退回和放弃次数偏多,系统会暂停你接新单一段时间(运行 anytowork limits 可查看)。');
|
|
1242
|
+
}
|
|
1211
1243
|
if (x.type === 'declined_revision') {
|
|
1212
1244
|
lines.push(` 已拒绝改稿 ${x.declined_rounds ?? '?'} 轮${x.revisions_closed ? ';改稿入口已关闭' : ''}。`);
|
|
1213
1245
|
}
|
package/src/index.js
CHANGED
|
@@ -356,6 +356,9 @@ const HELP = `${BRAND.name} CLI v${PKG_VERSION}
|
|
|
356
356
|
买家可在交付物页预览;成交后买家可自行生成公开链接(只能由买家生成)。
|
|
357
357
|
发布内容须合法合规并由你承担责任;违法类内容会被自动下架,并可能限制你交付网页一段时间。
|
|
358
358
|
|
|
359
|
+
task decline-pick <task_id> 被选中后、接单前不接了(卖方·任务回到待选人,你不能再报名这一单;托管款不动)
|
|
360
|
+
--reason <理由> --note <一句说明> 同 task abandon,两项都必填
|
|
361
|
+
[--idempotency-key <key>]
|
|
359
362
|
task abandon <task_id> 放弃本单(卖方·任务回到待选人,托管款不动;旧名 task fail 仍可用,等同放弃)
|
|
360
363
|
--reason <理由> 必填,六选一:
|
|
361
364
|
out_of_scope=超出原需求 / off_platform_action=要求平台外操作 / violation=违规 /
|
|
@@ -477,12 +480,12 @@ const HELP = `${BRAND.name} CLI v${PKG_VERSION}
|
|
|
477
480
|
请把链接交给用户;退出码 5(--json: {ok:false, error:"human_required", web_url})
|
|
478
481
|
libra status --task <task_id> 阶段、倒计时、双方是否已陈述、服务费明细
|
|
479
482
|
libra statement --task <task_id> (--text-file <路径> | --text "文字")
|
|
480
|
-
|
|
483
|
+
陈述 / 补充陈述(文字免费);证据在申请裁决时一次交齐,开审后不能再补
|
|
481
484
|
请分段、用序号写清楚:一条一个要点。双方看到的是你的原文(换行保留)
|
|
482
485
|
libra answer --task <task_id> --question <q_id> (--text "回答" | --text-file <路径>) 回答追问(仅一轮,逾期视为放弃)
|
|
483
486
|
libra ruling --task <task_id> [--round 1|2] 读裁决书(初裁 / 复核)
|
|
484
487
|
libra accept --task <task_id> 接受裁决(需主人在网页完成;双方都接受则立即执行,到期无人复核则自动执行)
|
|
485
|
-
libra review quote --task <task_id> [--
|
|
488
|
+
libra review quote --task <task_id> [--points 1,3] 复核报价(每案一次,终局;复核期只能补充陈述,不能再补证据)
|
|
486
489
|
libra review file --task <task_id> [--quote <quote_id>] 同 libra file:申请复核需要用户本人在网页完成,打印网页链接,退出码 5
|
|
487
490
|
提前结案(出裁决书之前,三种方式;libra status 会列出现在能用哪些、区间和待回应的提议):
|
|
488
491
|
libra withdraw --task <task_id> 发起方撤回自己付费立案的裁决(视为确认验收);只能本人在网页操作,Agent 会得到退出码 5 和网页链接
|
|
@@ -1042,6 +1045,7 @@ export async function run(argv, deps = {}) {
|
|
|
1042
1045
|
|
|
1043
1046
|
const EXIT_COMMANDS = {
|
|
1044
1047
|
'task:abandon': { action: 'abandon_job', label: '已放弃本单:任务回到待选人,托管款不动。' },
|
|
1048
|
+
'task:decline-pick': { action: 'abandon_job', label: '已退回:这一单你不接了,任务回到待选人。', extra: { decline_pick: true } },
|
|
1045
1049
|
'task:decline-revision': { action: 'decline_revision_job', label: '已拒绝本轮改稿:任务回到待验收。' },
|
|
1046
1050
|
'task:end-revisions': { action: 'end_revisions_job', label: '已终止后续改稿:以当前版本为终版。' },
|
|
1047
1051
|
};
|
|
@@ -1068,7 +1072,7 @@ export async function run(argv, deps = {}) {
|
|
|
1068
1072
|
return guarded(async () => {
|
|
1069
1073
|
const data = await runtimeAct(
|
|
1070
1074
|
baseUrl, credOpts, EXIT_COMMANDS[command].action,
|
|
1071
|
-
{ job_id: taskId, reason, note }, idemKey, { fetchImpl },
|
|
1075
|
+
{ job_id: taskId, reason, note, ...(EXIT_COMMANDS[command].extra || {}) }, idemKey, { fetchImpl },
|
|
1072
1076
|
);
|
|
1073
1077
|
log(formatExitResult(data, EXIT_COMMANDS[command].label, { json: flags.json }));
|
|
1074
1078
|
return 0;
|
|
@@ -1677,12 +1681,24 @@ export async function run(argv, deps = {}) {
|
|
|
1677
1681
|
let autoLines = [];
|
|
1678
1682
|
if (flags.autoAccept) {
|
|
1679
1683
|
const ids = selectedTaskIds(data.events, data.pending_confirms);
|
|
1684
|
+
// Per-application suffix for the decline key: a later buyer pick of another seller on the same task
|
|
1685
|
+
// must not replay this seller's cached result.
|
|
1686
|
+
const appOf = {};
|
|
1687
|
+
for (const pc of data.pending_confirms || []) if (pc && pc.task_id && pc.application_id) appOf[pc.task_id] = pc.application_id;
|
|
1688
|
+
for (const e of data.events || []) {
|
|
1689
|
+
const ep = e && e.payload;
|
|
1690
|
+
if (ep && ep.task_id && ep.application_id && !appOf[ep.task_id]) appOf[ep.task_id] = ep.application_id;
|
|
1691
|
+
}
|
|
1692
|
+
const applicationIdOf = (id) => appOf[id] || Date.now();
|
|
1680
1693
|
if (ids.length) {
|
|
1681
1694
|
const results = await autoAcceptSelected(ids, {
|
|
1682
1695
|
exclude: flags.exclude,
|
|
1683
1696
|
getTask: (id) => getTaskDetail(baseUrl, credOpts, id, { fetchImpl }),
|
|
1684
1697
|
accept: (id) => runtimeAct(baseUrl, credOpts, 'accept_job', { job_id: id }, `auto-accept-${id}`, { fetchImpl }),
|
|
1685
1698
|
start: (id) => runtimeAct(baseUrl, credOpts, 'start', { job_id: id }, `auto-start-${id}`, { fetchImpl }),
|
|
1699
|
+
decline: (id, word) => runtimeAct(baseUrl, credOpts, 'abandon_job',
|
|
1700
|
+
{ job_id: id, reason: 'other', note: '命中接单方设置的排除条件,自动退回', decline_pick: true },
|
|
1701
|
+
`auto-decline-${id}-${applicationIdOf(id)}`, { fetchImpl }),
|
|
1686
1702
|
});
|
|
1687
1703
|
autoLines = formatAutoAccept(results);
|
|
1688
1704
|
if (flags.json) data.auto_accept = results;
|
package/src/libra-commands.js
CHANGED
|
@@ -24,7 +24,7 @@ import path from 'node:path';
|
|
|
24
24
|
import { atomicWriteFile } from './atomic-write.js';
|
|
25
25
|
import { resolveCredDir } from './profile.js';
|
|
26
26
|
import {
|
|
27
|
-
libraQuote, libraTaskCase, libraStatement,
|
|
27
|
+
libraQuote, libraTaskCase, libraStatement, libraAnswer,
|
|
28
28
|
libraRulings, libraAccept, libraReviewQuote,
|
|
29
29
|
libraGetCase, libraWithdrawCase, libraConcede, libraProposeOffer, libraAcceptOffer, libraRejectOffer, libraWithdrawOffer,
|
|
30
30
|
} from './api.js';
|
|
@@ -38,6 +38,7 @@ const MAX_PAGES_PER_FILE = 5000;
|
|
|
38
38
|
export { EXIT_HUMAN_REQUIRED };
|
|
39
39
|
|
|
40
40
|
/** One generic sentence about how to write a statement (v0.22.x C6). Never names a particular Agent product. */
|
|
41
|
+
export const EVIDENCE_CLOSED_MSG = '已不支持 --evidence:证据在申请裁决时一次交齐,开审后不再补充。陈述期和复核期只能补充文字陈述。';
|
|
41
42
|
export const STATEMENT_TIP = '请分段、用序号写清楚:一条一个要点。';
|
|
42
43
|
|
|
43
44
|
/** Plain-language notices every fee-taking command must show (PRD section 6.2 / 16, docs section 5). */
|
|
@@ -396,9 +397,9 @@ async function cmdStatement(ctx, io) {
|
|
|
396
397
|
if (!flags.task) return io.fail(2, 'missing_task', '缺少 --task <task-id>');
|
|
397
398
|
const st = readText(flags.textFile, flags.text[0], '陈述', io);
|
|
398
399
|
if (st.fail !== undefined) return st.fail;
|
|
399
|
-
|
|
400
|
-
if (
|
|
401
|
-
if (!st.text
|
|
400
|
+
// v0.29.46: evidence is handed in once when the ruling is applied for; no more evidence after the hearing opens.
|
|
401
|
+
if (flags.evidence.length) return io.fail(2, 'evidence_closed', EVIDENCE_CLOSED_MSG);
|
|
402
|
+
if (!st.text) return io.fail(2, 'nothing_to_submit', '没有内容:--text-file <路径> / --text "文字"');
|
|
402
403
|
if (cpLen(st.text) > STATEMENT_MAX_CHARS) return io.fail(2, 'statement_too_long', `单次陈述不能超过 ${STATEMENT_MAX_CHARS} 字(现在 ${cpLen(st.text)} 字)`);
|
|
403
404
|
const lc = await loadCase(ctx, io, flags.task);
|
|
404
405
|
if (lc.fail !== undefined) return lc.fail;
|
|
@@ -411,14 +412,6 @@ async function cmdStatement(ctx, io) {
|
|
|
411
412
|
lines.push(`${STATEMENT_TIP}双方会看到你的原文,换行和分段都会保留。`);
|
|
412
413
|
if (out.statement.review_opened) lines.push('双方都已陈述,审理已提前开始。');
|
|
413
414
|
}
|
|
414
|
-
if (evid.evidence.length) {
|
|
415
|
-
const order = await libraAddEvidence(ctx.baseUrl, ctx.credOpts, caseId, evid.evidence, undefined, { fetchImpl: ctx.fetchImpl });
|
|
416
|
-
out.evidence_order = order;
|
|
417
|
-
const url = cashierUrl(ctx, order);
|
|
418
|
-
lines.push(`补充关键证据需要你支付 ${yuan(order.amount_cents)}(计费证据由补充方承担,不退还),订单号 ${order.order_no || order.order_id}`);
|
|
419
|
-
if (url) lines.push(`收银台:${url}`);
|
|
420
|
-
lines.push('支付成功后证据才会进入案卷。');
|
|
421
|
-
}
|
|
422
415
|
return io.ok({ case_id: caseId, ...out }, lines.join('\n'));
|
|
423
416
|
}
|
|
424
417
|
|
|
@@ -476,11 +469,10 @@ async function cmdAccept(ctx, io) {
|
|
|
476
469
|
async function cmdReviewQuote(ctx, io) {
|
|
477
470
|
const { flags } = ctx;
|
|
478
471
|
if (!flags.task) return io.fail(2, 'missing_task', '缺少 --task <task-id>');
|
|
479
|
-
|
|
480
|
-
if (ev.fail !== undefined) return ev.fail;
|
|
472
|
+
if (flags.evidence.length) return io.fail(2, 'evidence_closed', EVIDENCE_CLOSED_MSG);
|
|
481
473
|
const lc = await loadCase(ctx, io, flags.task);
|
|
482
474
|
if (lc.fail !== undefined) return lc.fail;
|
|
483
|
-
const q = await libraReviewQuote(ctx.baseUrl, ctx.credOpts, lc.caseView.id, {
|
|
475
|
+
const q = await libraReviewQuote(ctx.baseUrl, ctx.credOpts, lc.caseView.id, {}, { fetchImpl: ctx.fetchImpl });
|
|
484
476
|
saveQuote(ctx.credOpts, q.quote_id, {
|
|
485
477
|
kind: 'review', task_id: flags.task, case_id: lc.caseView.id, points: flags.points || null,
|
|
486
478
|
total_cents: q.total_cents, expires_at: q.expires_at,
|
package/src/refund-commands.js
CHANGED
|
@@ -120,12 +120,15 @@ export function nextCommands(view, taskId) {
|
|
|
120
120
|
if (view.viewer === 'seller') {
|
|
121
121
|
const exp = `--expect-pct ${n.buyer_ask_pct}`;
|
|
122
122
|
if (can.agree) out.push({ text: `同意(接单方的 Agent 可以直接同意;要不要先问主人由你们自己约定):anytowork refund respond --task ${taskId} --action agree ${exp}` });
|
|
123
|
-
|
|
124
|
-
if (can.
|
|
123
|
+
// v0.29.24 (R10): offering / holding needs a reason - it goes to the other side and into the case file
|
|
124
|
+
if (can.offer) out.push({ text: `退一部分(比例 ${stepWord(can.offer)}):anytowork refund respond --task ${taskId} --action offer --pct <比例> ${exp} --note "<给对方的理由>"` });
|
|
125
|
+
if (can.hold) out.push({ text: `不同意 / 最多退到现在这个数、不再加价:anytowork refund respond --task ${taskId} --action hold ${exp} --note "<给对方的理由>"` });
|
|
126
|
+
if (can.offer || can.hold) out.push({ text: '退一部分和不同意都要带 --note(10-500 字):这段理由会给对方和 AI 法庭看到。' });
|
|
125
127
|
} else {
|
|
126
128
|
const exp = `--expect-pct ${n.seller_best_pct}`;
|
|
127
129
|
if (can.accept) out.push({ who: 'person', text: `接受对方的报价只能由用户本人在网页完成:${'{WEB}'}` });
|
|
128
|
-
if (can.ask) out.push({ text: `再提一个更低的比例(比例 ${stepWord(can.ask)}):anytowork refund reply --task ${taskId} --action ask --pct <比例> ${exp}` });
|
|
130
|
+
if (can.ask) out.push({ text: `再提一个更低的比例(比例 ${stepWord(can.ask)}):anytowork refund reply --task ${taskId} --action ask --pct <比例> ${exp} --note "<给对方的理由>"` });
|
|
131
|
+
if (can.ask) out.push({ text: '再提一个更低的比例要带 --note(10-500 字):这段理由会给对方和 AI 法庭看到。' });
|
|
129
132
|
if (can.court) out.push({ who: 'person', text: `申请 AI 法庭裁决只能由用户本人在网页完成:${'{WEB}'}` });
|
|
130
133
|
if (can.cancel) out.push({ who: 'person', text: `不退了、撤销协商只能由用户本人在网页完成:${'{WEB}'}` });
|
|
131
134
|
}
|
|
@@ -155,7 +158,7 @@ export function describeNegotiation(ctx, view, taskId) {
|
|
|
155
158
|
} else {
|
|
156
159
|
const c = n.closed || {};
|
|
157
160
|
lines.push(` 状态:已结束(${KIND_WORDS[c.kind] || n.status})`);
|
|
158
|
-
if (c.refund_pct != null) lines.push(` 退还比例:${c.refund_pct}%${n.amounts ? `(退还 ${money(view, n.amounts.refund_cents)},结算给接单方 ${money(view, n.amounts.release_cents)})` : ''}`);
|
|
161
|
+
if (c.refund_pct != null) lines.push(` 退还比例:${c.refund_pct}%${n.amounts ? `(退还 ${money(view, n.amounts.refund_cents)},结算给接单方 ${money(view, n.amounts.release_cents)}${n.amounts.release_net_cents != null ? `,扣掉平台费用和同款分成后接单方预计到手 ${money(view, n.amounts.release_net_cents)}` : ''})` : ''}`);
|
|
159
162
|
if (c.kind === 'court') lines.push(' 已转入 AI 法庭裁决,请用 anytowork libra status 看进展。');
|
|
160
163
|
}
|
|
161
164
|
if ((n.entries || []).length) lines.push(' 记录:', ...n.entries.map((en) => entryLine(view, en)));
|