task-ledger 1.3.6 → 1.3.7

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.6
4
+ version: 1.3.7
5
5
  allowed-tools: Read,Edit,Bash,Grep
6
6
  ---
7
7
 
@@ -13,6 +13,20 @@ allowed-tools: Read,Edit,Bash,Grep
13
13
  - **任务状态**:`待认领(open)` = 建了还没人认领;`进行中(doing)` = 已认领、在做;`已结案` = 用户明确说结束后由 `close` 产生,此后只读。
14
14
  - **操作方式**:台账的状态与归属只经命令改;唯一能手写的是过程文档前五节(见「手写边界」)。台账只记「建 / 做 / 结」和指向过程文档的链接;产出物本身按项目自己的约定落盘。
15
15
 
16
+ ## 身份闸门(未初始化时怎么走)
17
+
18
+ **任何命令返回「这台机器还没有初始化身份」⇒ 一律停下,不许绕。** 身份是用户自己的,不是你的决定。
19
+
20
+ - **查询类**(`list` / `show` / `history` / `validate`):什么都不做。把 init 命令交给用户,等 ta 跑完再重试原命令。
21
+ - **写入类**(`new` / `claim` / `set` / `log` / `close`):不建、不改、不推送。先裸跑一次 `init`(只读,只把名册里已有的身份报出来):
22
+ - **有名单** ⇒ 「名册里已有这些身份:<uuid 名字>。确定哪个是你的,就自己在终端跑 `init --claim <uuid>` 选它;都不是就 `init --new --name <名字>` 新建。」**报给用户,让 ta 选。**
23
+ - **没名单** ⇒ 「名册为空,请在终端 `init --new --name <名字>` 新建。」
24
+ - **禁止(硬规则)**:
25
+ - **不替用户执行** `init --claim` / `init --new` / `init --name` —— 挑哪个身份是用户的事;
26
+ - **不读** `ledger/*.json`、worklog 去"自己看";
27
+ - 未初始化时**不做任何写**。
28
+ - `init` 的写操作只能由用户在终端交互执行(脚本对无终端调用直接报错);agent **唯一**可跑的 `init` 是不带参数、只报名单的只读形式。
29
+
16
30
  ## 手写边界
17
31
 
18
32
  - **唯一能手写的是任务的过程文档(worklog)前五节**(怎么写见「过程文档」节);末节「执行记录」由脚本维护,**禁止手写、禁止手工添加**。
@@ -31,7 +45,7 @@ allowed-tools: Read,Edit,Bash,Grep
31
45
  | `--claim <uuid>` | 认领名册里已有的 uuid(名字一起复制) |
32
46
  | `--new --name "…"` | 新建身份:生成 uuid + 名字 |
33
47
 
34
- 干什么:写本机身份文件(`~/.taskledger/identity.json`),**一台机器只一次**,与台账无关。全新机器或新项目没有名册 ⇒ 直接用 `init --new --name "<名字>"`,裸跑 `init` 会报「新建身份必须输入一个名字」。
48
+ 干什么:写本机身份文件(`~/.taskledger/identity.json`),**一台机器只一次**,与台账无关。**写操作只能由用户在终端里执行**(无终端调用会被脚本拒绝);agent 只许裸跑 `init`(只读、把候选报给用户),不得代跑 `--claim` / `--new` / `--name`。名册为空时裸跑 `init` 会报「新建身份必须输入一个名字」,此时让用户自己 `init --new --name "<名字>"` 新建。
35
49
 
36
50
  ### new — 建任务
37
51
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "task-ledger",
3
- "version": "1.3.6",
3
+ "version": "1.3.7",
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",
@@ -271,6 +271,7 @@ def _lock_dir(repo: Path) -> Path:
271
271
 
272
272
  def _run_init(args: argparse.Namespace) -> int:
273
273
  """init 不进 runner、不解析台账、不碰 git:只写机器身份文件。"""
274
+ from .. import env
274
275
  from ..actions.init_identity import init_identity
275
276
 
276
277
  repo: Path | None = None
@@ -279,13 +280,23 @@ def _run_init(args: argparse.Namespace) -> int:
279
280
  repo = as_root(raw, source="--repo") if raw else root_of(Path.cwd().resolve())
280
281
  except Fail:
281
282
  repo = None
283
+ claim = getattr(args, "claim", None)
284
+ new = bool(getattr(args, "new_id", False))
285
+ name = getattr(args, "name", "") or ""
282
286
  try:
283
- res = init_identity(
284
- repo,
285
- claim=getattr(args, "claim", None),
286
- new=bool(getattr(args, "new_id", False)),
287
- name=getattr(args, "name", "") or "",
288
- )
287
+ # 首次写身份只能由用户在真终端交互完成:agent 的 subprocess 没有 TTY,
288
+ # 放行就等于让它替用户挑一个身份写进本机(2026-10-26 事故)。
289
+ if (
290
+ env.read_identity() is None
291
+ and (claim or new or name.strip())
292
+ and not sys.stdin.isatty()
293
+ ):
294
+ raise Fail(
295
+ "写入身份必须由用户在终端里交互执行(当前没有终端)。\n"
296
+ " 处理:请用户在终端运行 `python3 progress.py init --repo <工作区根>`,\n"
297
+ " 它会列出已有身份供选择,或让 ta 输入一个新名字。"
298
+ )
299
+ res = init_identity(repo, claim=claim, new=new, name=name)
289
300
  except Fail as exc:
290
301
  render.fail_message(exc)
291
302
  return BUSINESS