task-ledger 1.3.11 → 1.3.12

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/SKILL.md CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: task-ledger
3
3
  description: 本地任务台账,跨会话记录在办任务的归属、进度与起止。当用户要登记一件新的事(新建任务 / 建个坑 / 这活我领了)、记录已有任务的进展(接着做 / 记一条进展 / 这轮先记下)、查看任务状态或历史(现在该做什么 / 这活谁在做 / 上周做过什么)、给任务结案或退回(做完了 / 验收通过 / 不做了 / 退回待认领)、整理标签或检查台账一致性时加载;只是改代码、讨论方案时不要用。
4
- version: 1.3.11
4
+ version: 1.3.12
5
5
  allowed-tools: Read,Edit,Bash,Grep
6
6
  ---
7
7
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "task-ledger",
3
- "version": "1.3.11",
3
+ "version": "1.3.12",
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",
@@ -286,12 +286,29 @@ def _print_init_result(res: dict) -> None:
286
286
 
287
287
 
288
288
  def _select_identity(opts: list[dict], *, title: str) -> tuple[str, int | None]:
289
- """交互选身份:箭头上下移动,末尾「+ 新建身份」,Enter 确认,Ctrl-C 取消。
289
+ """交互式选身份:↑/↓ 移动、Enter 确认、Ctrl-C 取消,末尾「+ 新建身份」。
290
+
290
291
  返回 (kind, index):kind∈{claim,new,cancel};claim/new 时 index 为候选项下标。
291
- TTY 下走 raw 光标选择;不支持 raw(非 Unix / 无 TTY)时退回编号输入。仅在 TTY 调用。
292
+ TTY 下用 raw 键盘 + 原地重绘(不整屏清屏、不动滚动条);不支持时退回编号输入。
293
+ 仅在 TTY 调用。
292
294
  """
293
295
  entries = list(opts) + [{"new": True}]
294
296
  n = len(entries)
297
+ height = n + 4 # 标题 + 空行 + n 个选项 + 空行 + 提示
298
+
299
+ def _frame(sel: int) -> list[str]:
300
+ rows = ["\x1b[1;36m" + title + "\x1b[0m", ""]
301
+ for i, e in enumerate(entries):
302
+ label = (
303
+ "+ 新建身份(自己输入名字)"
304
+ if e.get("new")
305
+ else f"@{e['name']} {e['uuid']}"
306
+ )
307
+ rows.append(
308
+ "\x1b[7m ❯ " + label + " \x1b[0m" if i == sel else " " + label
309
+ )
310
+ rows += ["", "\x1b[2m ↑/↓ 移动 Enter 确认 Ctrl-C 退出\x1b[0m"]
311
+ return rows
295
312
 
296
313
  try:
297
314
  fd = sys.stdin.fileno()
@@ -302,27 +319,23 @@ def _select_identity(opts: list[dict], *, title: str) -> tuple[str, int | None]:
302
319
 
303
320
  old = termios.tcgetattr(fd)
304
321
  sel = 0
322
+ drew = False
323
+ result: tuple[str, int | None] = ("cancel", None)
305
324
  try:
306
325
  tty.setraw(fd)
307
326
  sys.stdout.write("\x1b[?25l") # 隐藏光标
308
327
  while True:
309
- # 每帧整屏重绘(2J 清屏 + H 回家),位置无关,避免折行/行数错位
310
- sys.stdout.write("\x1b[2J\x1b[H")
311
- sys.stdout.write("\x1b[1;36m" + title + "\x1b[0m\n\n")
312
- for i, e in enumerate(entries):
313
- label = (
314
- "+ 新建身份(自己输入名字)"
315
- if e.get("new")
316
- else f"@{e['name']} {e['uuid']}"
317
- )
318
- if i == sel:
319
- sys.stdout.write("\x1b[7m ❯ " + label + " \x1b[0m\n")
320
- else:
321
- sys.stdout.write(" " + label + "\n")
322
- sys.stdout.write(
323
- "\n\x1b[2m ↑/↓ 移动 Enter 确认 Ctrl-C 退出\x1b[0m"
324
- )
328
+ rows = _frame(sel)
329
+ if drew:
330
+ sys.stdout.write(f"\x1b[{height}A") # 回到本块第一行
331
+ else:
332
+ sys.stdout.write("\r\n") # 从新行开始,避开 shell 提示
333
+ drew = True
334
+ for row in rows:
335
+ # raw 模式下 \n 不回行首,必须显式 \r\n,否则逐行右移
336
+ sys.stdout.write("\r\x1b[K" + row + "\r\n")
325
337
  sys.stdout.flush()
338
+
326
339
  ch = sys.stdin.read(1)
327
340
  if ch == "\x1b":
328
341
  nxt = sys.stdin.read(1)
@@ -333,14 +346,21 @@ def _select_identity(opts: list[dict], *, title: str) -> tuple[str, int | None]:
333
346
  elif k == "B":
334
347
  sel = (sel + 1) % n
335
348
  elif ch in ("\r", "\n"):
336
- return ("new", None) if entries[sel].get("new") else ("claim", sel)
349
+ result = (
350
+ ("new", None) if entries[sel].get("new") else ("claim", sel)
351
+ )
352
+ break
337
353
  elif ch == "\x03": # Ctrl-C
338
- return ("cancel", None)
354
+ result = ("cancel", None)
355
+ break
339
356
  finally:
340
357
  sys.stdout.write("\x1b[?25h") # 显示光标
341
- sys.stdout.write("\x1b[2J\x1b[H") # 退出时清掉选择框,结果从顶部打印
358
+ if drew:
359
+ # 原地擦掉菜单块(不滚动主屏),光标留在块首,结果从这里打印
360
+ sys.stdout.write(f"\x1b[{height}A\r\x1b[J")
342
361
  termios.tcsetattr(fd, termios.TCSADRAIN, old)
343
362
  sys.stdout.flush()
363
+ return result
344
364
  except (OSError, ImportError):
345
365
  print(title)
346
366
  for i, o in enumerate(opts, 1):
@@ -351,7 +371,7 @@ def _select_identity(opts: list[dict], *, title: str) -> tuple[str, int | None]:
351
371
  c = input(f"选编号(1-{n}):").strip()
352
372
  except (EOFError, KeyboardInterrupt):
353
373
  return ("cancel", None)
354
- if c.lower() == "n":
374
+ if c.lower() in ("n", "new"):
355
375
  return ("new", None)
356
376
  try:
357
377
  idx = int(c) - 1