dsh-task-ledger 0.0.87 → 0.0.89
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/package.json +1 -1
- package/skill/SKILL.md +2 -2
- package/skill/package.json +1 -1
- package/skill/scripts/ledgerkit/shell/cli.py +53 -25
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-task-ledger",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.89",
|
|
4
4
|
"description": "Task ledger board for dsh (DeepSeek Harness): read-only board over task-ledger skill workspaces. The task-ledger skill is bundled — install the plugin, get the skill globally.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek",
|
package/skill/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: task-ledger
|
|
3
3
|
description: 本地任务台账,跨会话记录在办任务的归属、进度与起止。当用户要登记一件新的事(新建任务 / 建个坑 / 这活我领了)、记录已有任务的进展(接着做 / 记一条进展 / 这轮先记下)、查看任务状态或历史(现在该做什么 / 这活谁在做 / 上周做过什么)、给任务结案或退回(做完了 / 验收通过 / 不做了 / 退回待认领)、整理标签或检查台账一致性时加载;只是改代码、讨论方案时不要用。
|
|
4
|
-
version: 1.3.
|
|
4
|
+
version: 1.3.15
|
|
5
5
|
allowed-tools: Read,Edit,Bash,Grep
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -45,7 +45,7 @@ allowed-tools: Read,Edit,Bash,Grep
|
|
|
45
45
|
| `--claim <uuid>` | 认领名册里已有的 uuid(名字一起复制) |
|
|
46
46
|
| `--new --name "…"` | 新建身份:生成 uuid + 名字 |
|
|
47
47
|
|
|
48
|
-
干什么:写本机身份文件(`~/.taskledger/identity.json`),**一台机器只一次**,与台账无关。在终端里**裸跑 `init` 即交互式选择框**:读当前仓库名册,用**上下箭头**移动、**Enter** 认领某个身份,末尾「+
|
|
48
|
+
干什么:写本机身份文件(`~/.taskledger/identity.json`),**一台机器只一次**,与台账无关。在终端里**裸跑 `init` 即交互式选择框**:读当前仓库名册,用**上下箭头**移动、**Enter** 认领某个身份,末尾「+ 新建身份」可输入新用户名自建;名册为空则直接让你输入用户名;选定或输入名字后需 **Y/N 确认**才写入(选 **N** 会返回选择菜单重新选,不会直接退出);**ESC 或 Ctrl-C** 可随时取消。全程要真终端。`--claim <uuid>` / `--new --name "<名字>"` 也只接受真终端,agent 的无终端调用会被脚本拒绝。
|
|
49
49
|
|
|
50
50
|
### new — 建任务
|
|
51
51
|
|
package/skill/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "task-ledger",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.15",
|
|
4
4
|
"description": "Task-ledger skill for coding agents: per-workspace progress tracking (ledger/pool.json + owners/<hash>.json shards + owners.json index, history, worklog) driven by a CLI script. Standalone install for CodeBuddy and other agents; also bundled inside the dsh-task-ledger DSH plugin.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"skill",
|
|
@@ -307,13 +307,15 @@ def _select_identity(opts: list[dict], *, title: str) -> tuple[str, int | None]:
|
|
|
307
307
|
rows.append(
|
|
308
308
|
"\x1b[7m ❯ " + label + " \x1b[0m" if i == sel else " " + label
|
|
309
309
|
)
|
|
310
|
-
rows += ["", "\x1b[2m ↑/↓ 移动 Enter 确认 Ctrl-C 退出\x1b[0m"]
|
|
310
|
+
rows += ["", "\x1b[2m ↑/↓ 移动 Enter 确认 ESC / Ctrl-C 退出\x1b[0m"]
|
|
311
311
|
return rows
|
|
312
312
|
|
|
313
313
|
try:
|
|
314
314
|
fd = sys.stdin.fileno()
|
|
315
315
|
if not sys.stdin.isatty():
|
|
316
316
|
raise OSError("not a tty")
|
|
317
|
+
import os
|
|
318
|
+
import select
|
|
317
319
|
import termios
|
|
318
320
|
import tty
|
|
319
321
|
|
|
@@ -335,21 +337,25 @@ def _select_identity(opts: list[dict], *, title: str) -> tuple[str, int | None]:
|
|
|
335
337
|
sys.stdout.write("\x1b[2K\r" + row + "\n")
|
|
336
338
|
sys.stdout.flush()
|
|
337
339
|
|
|
338
|
-
ch =
|
|
339
|
-
if ch == "\x1b":
|
|
340
|
-
|
|
341
|
-
if
|
|
342
|
-
|
|
343
|
-
|
|
340
|
+
ch = os.read(fd, 1)
|
|
341
|
+
if ch == b"\x1b":
|
|
342
|
+
# 区分「单独 ESC(退出)」与「方向键 ESC [ A/B」:短暂等待后续字节
|
|
343
|
+
if not select.select([fd], [], [], 0.05)[0]:
|
|
344
|
+
result = ("cancel", None)
|
|
345
|
+
break
|
|
346
|
+
nxt = os.read(fd, 1)
|
|
347
|
+
if nxt in (b"[", b"O"):
|
|
348
|
+
k = os.read(fd, 1)
|
|
349
|
+
if k == b"A":
|
|
344
350
|
sel = (sel - 1) % n
|
|
345
|
-
elif k == "B":
|
|
351
|
+
elif k == b"B":
|
|
346
352
|
sel = (sel + 1) % n
|
|
347
|
-
elif ch in ("\r", "\n"):
|
|
353
|
+
elif ch in (b"\r", b"\n"):
|
|
348
354
|
result = (
|
|
349
355
|
("new", None) if entries[sel].get("new") else ("claim", sel)
|
|
350
356
|
)
|
|
351
357
|
break
|
|
352
|
-
elif ch == "\x03": # Ctrl-C
|
|
358
|
+
elif ch == b"\x03": # Ctrl-C
|
|
353
359
|
result = ("cancel", None)
|
|
354
360
|
break
|
|
355
361
|
finally:
|
|
@@ -383,6 +389,17 @@ def _select_identity(opts: list[dict], *, title: str) -> tuple[str, int | None]:
|
|
|
383
389
|
return ("cancel", None)
|
|
384
390
|
|
|
385
391
|
|
|
392
|
+
def _confirm(question: str) -> bool:
|
|
393
|
+
"""Y/N 确认:Y 返回 True,N 返回 False;Ctrl-C/Ctrl-D 向上抛,当作取消退出。"""
|
|
394
|
+
while True:
|
|
395
|
+
ans = input(question + " [Y/N]:").strip().lower()
|
|
396
|
+
if ans in ("y", "yes"):
|
|
397
|
+
return True
|
|
398
|
+
if ans in ("n", "no"):
|
|
399
|
+
return False
|
|
400
|
+
print("请输入 Y 或 N。")
|
|
401
|
+
|
|
402
|
+
|
|
386
403
|
def _run_init(args: argparse.Namespace) -> int:
|
|
387
404
|
"""init 不进 runner、不解析台账、不碰 git:只写机器身份文件。
|
|
388
405
|
|
|
@@ -427,22 +444,33 @@ def _run_init(args: argparse.Namespace) -> int:
|
|
|
427
444
|
"请重跑:init --claim=<uuid> 认领,或 init --new --name=<名字> 新建"
|
|
428
445
|
)
|
|
429
446
|
return 0
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
if kind == "cancel":
|
|
434
|
-
print("\x1b[2m✕ 已取消初始化。随时可重跑 init 重新开始。\x1b[0m")
|
|
435
|
-
return 0
|
|
436
|
-
if kind == "new":
|
|
437
|
-
prompt_name = input("输入用户名:").strip()
|
|
438
|
-
if not prompt_name:
|
|
439
|
-
print("\x1b[2m✕ 未输入用户名,已取消。\x1b[0m")
|
|
440
|
-
return 0
|
|
441
|
-
res = init_identity(repo, claim=None, new=True, name=prompt_name)
|
|
442
|
-
else:
|
|
443
|
-
res = init_identity(
|
|
444
|
-
repo, claim=opts[idx]["uuid"], new=False, name=""
|
|
447
|
+
while True:
|
|
448
|
+
kind, idx = _select_identity(
|
|
449
|
+
opts, title="这台机器还没初始化。选择你的身份,或新建一个:"
|
|
445
450
|
)
|
|
451
|
+
if kind == "cancel":
|
|
452
|
+
print(
|
|
453
|
+
"\x1b[2m✕ 已取消初始化。随时可重跑 init 重新开始。\x1b[0m"
|
|
454
|
+
)
|
|
455
|
+
return 0
|
|
456
|
+
if kind == "new":
|
|
457
|
+
prompt_name = input("输入用户名:").strip()
|
|
458
|
+
if not prompt_name:
|
|
459
|
+
print("\x1b[2m✕ 未输入用户名,已取消。\x1b[0m")
|
|
460
|
+
return 0
|
|
461
|
+
if not _confirm(
|
|
462
|
+
f"您确认要用「{prompt_name}」这个名称新建账户吗?"
|
|
463
|
+
):
|
|
464
|
+
continue # N:回到选择菜单重来
|
|
465
|
+
res = init_identity(
|
|
466
|
+
repo, claim=None, new=True, name=prompt_name
|
|
467
|
+
)
|
|
468
|
+
break
|
|
469
|
+
chosen = opts[idx]
|
|
470
|
+
if not _confirm(f"您确认是要使用「@{chosen['name']}」这个身份吗?"):
|
|
471
|
+
continue # N:回到选择菜单重来
|
|
472
|
+
res = init_identity(repo, claim=chosen["uuid"], new=False, name="")
|
|
473
|
+
break
|
|
446
474
|
else:
|
|
447
475
|
# 名册空:交互输入名字;非终端交给用户去终端跑(init_identity 会报需要名字)
|
|
448
476
|
prompt_name = input("输入用户名:").strip() if tty else ""
|