@xluos/dev-assets-cli 0.1.0 → 0.2.0

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 CHANGED
@@ -37,16 +37,27 @@ npx skills add xluos/dev-asset-skill-suite --all -g -y
37
37
  ## Repository Layout
38
38
 
39
39
  ```text
40
+ bin/
41
+ dev-assets.js # `npx dev-assets` CLI entry (hooks + install helpers)
42
+ hooks/
43
+ hooks.json # Claude hook template (.claude/settings.local.json)
44
+ codex-hooks.json # Codex hook template (.codex/hooks.json)
45
+ README.md
46
+ lib/
47
+ dev_asset_common.py # shared library used by hook scripts
48
+ scripts/
49
+ hooks/ # session_start/pre_compact/stop/session_end .py — invoked via `dev-assets hook ...`
50
+ install_codex_hooks.sh # one-shot installer; symlinked as install_claude_hooks.sh
51
+ install_claude_hooks.sh -> install_codex_hooks.sh
52
+ install_suite.py # local symlink-based skill install (dev only)
53
+ npm/ # package check/build helpers
40
54
  skills/
41
55
  using-dev-assets/
42
56
  dev-assets-setup/
43
57
  dev-assets-context/
44
58
  dev-assets-update/
45
59
  dev-assets-sync/
46
- lib/
47
- dev_asset_common.py
48
- scripts/
49
- install_suite.py
60
+ suite-manifest.json # canonical list of suite + legacy skill names
50
61
  ```
51
62
 
52
63
  ## Storage Layout
@@ -74,6 +85,7 @@ By default the suite stores memory outside the repository:
74
85
  - `repo/`: shared memory for the whole Git repository
75
86
  - `branches/<branch>/`: branch-local working memory
76
87
  - `repo-key`: derived from repository identity, not just the folder name
88
+ - `DEV_ASSETS_ROOT`: environment variable that overrides the default storage root (`~/.dev-assets/repos`); honored by the CLI and all bundled skill scripts
77
89
 
78
90
  ## Lifecycle Hooks
79
91
 
@@ -97,29 +109,37 @@ Shared behavior:
97
109
  - `Stop`: persist a lightweight HEAD marker after each response
98
110
  - `SessionEnd`: persist the final HEAD marker at session end
99
111
 
100
- Quick Codex install into the current repository:
112
+ Recommended: install the CLI once globally, then merge hooks per repo.
101
113
 
102
114
  ```bash
103
- sh scripts/install_codex_hooks.sh
115
+ npm install -g @xluos/dev-assets-cli # once
116
+ dev-assets install-hooks codex # in the target repo (defaults to cwd)
117
+ dev-assets install-hooks claude
104
118
  ```
105
119
 
106
- Or run it directly from GitHub in the repository you want to enable:
120
+ Or merge hooks into the agent's **user-level** config instead of per-repo:
107
121
 
108
122
  ```bash
109
- sh -c "$(curl -fsSL https://raw.githubusercontent.com/xluos/dev-asset-skill-suite/main/scripts/install_codex_hooks.sh)"
123
+ dev-assets install-hooks codex --global # writes ~/.codex/hooks.json
124
+ dev-assets install-hooks claude --global # writes ~/.claude/settings.json
110
125
  ```
111
126
 
112
- The installer will:
127
+ Without a global CLI install, run via `npx` (downloads on demand):
128
+
129
+ ```bash
130
+ npx -y @xluos/dev-assets-cli install-hooks codex
131
+ npx -y @xluos/dev-assets-cli install-hooks claude --global
132
+ ```
113
133
 
114
- - install `@xluos/dev-assets-cli` into the target repository
115
- - merge Codex hooks into `.codex/hooks.json`
116
- - make hooks call `npx dev-assets hook ...`, so they no longer depend on repo-local Python paths
134
+ `install-hooks <agent>` merges hooks into the target config. Repo scope writes `.codex/hooks.json` or `.claude/settings.local.json`; `--global` writes `~/.codex/hooks.json` or `~/.claude/settings.json`. Hooks call `dev-assets hook ...`, so the CLI must be reachable on PATH (global install) or resolvable via `npx`. `--repo` defaults to the current working directory when omitted.
117
135
 
118
- You can also merge hooks manually after the CLI is installed:
136
+ Shell installers (`scripts/install_codex_hooks.sh`, `scripts/install_claude_hooks.sh`) are thin wrappers around the same command for environments that prefer a shell entry:
119
137
 
120
138
  ```bash
121
- npx dev-assets install-hooks codex
122
- npx dev-assets install-hooks claude
139
+ sh scripts/install_codex_hooks.sh # Codex, repo-scoped
140
+ sh scripts/install_codex_hooks.sh --agent claude # Claude, repo-scoped
141
+ sh scripts/install_codex_hooks.sh --global # Codex, user-level
142
+ sh scripts/install_claude_hooks.sh --global # Claude, user-level
123
143
  ```
124
144
 
125
145
  Boundary:
@@ -129,6 +149,15 @@ Boundary:
129
149
  - Global skill installs do not auto-load hooks yet, because this project is a skill suite rather than a standalone plugin
130
150
  - Hook execution is now expected to go through `dev-assets` CLI, not raw `python3 scripts/hooks/*.py`
131
151
 
152
+ ## Two Invocation Tracks
153
+
154
+ This suite has two distinct entry surfaces. They look similar but should not be confused.
155
+
156
+ - Lifecycle hooks → `npx dev-assets hook <session-start|pre-compact|stop|session-end>`. These run automatically from `.codex/hooks.json` or `.claude/settings.local.json` and are the only place where the `dev-assets` CLI is the right entry point.
157
+ - In-conversation skill workflows (`dev-assets-setup`, `dev-assets-context`, `dev-assets-update`, `dev-assets-sync`) → invoke each skill's bundled Python script under `<skill-dir>/scripts/`. The CLI does not wrap these because they are interactive workflow steps with skill-specific arguments, not background hook actions.
158
+
159
+ Inside SKILL.md files these script paths appear as `python3 /absolute/path/to/<skill>/scripts/<name>.py`. The agent is expected to substitute the actual on-disk skill directory at call time (the path the harness loaded the skill from), not to pass the literal placeholder string.
160
+
132
161
  ## Notes
133
162
 
134
163
  - The suite no longer stores its primary memory inside the Git worktree by default.
@@ -137,4 +166,8 @@ Boundary:
137
166
  - Shared document entrances can live in repo-level `sources.md`; branch-specific progress and next-step live in branch files.
138
167
  - `dev-assets-setup` can migrate legacy `.dev-assets/<branch>/` content into the new user-home branch directory.
139
168
  - `npx skills` does not need `scripts/install_suite.py`; the repository already follows standard skill discovery rules.
140
- - `scripts/install_suite.py` remains useful for local symlink-based installs during development.
169
+ - `scripts/install_suite.py` remains useful for local symlink-based installs during development. Example — symlink all suite skills into Codex's user-level skill directory and prune legacy aliases:
170
+
171
+ ```bash
172
+ python3 scripts/install_suite.py --target ~/.codex/skills --force --remove-legacy
173
+ ```
package/bin/dev-assets.js CHANGED
@@ -116,6 +116,12 @@ function targetPathForAgent(agent, repoRoot) {
116
116
  fail(`unsupported agent: ${agent}`);
117
117
  }
118
118
 
119
+ function globalTargetPathForAgent(agent) {
120
+ if (agent === "codex") return path.join(os.homedir(), ".codex", "hooks.json");
121
+ if (agent === "claude") return path.join(os.homedir(), ".claude", "settings.json");
122
+ fail(`unsupported agent: ${agent}`);
123
+ }
124
+
119
125
  function mergeHookLists(existingItems, incomingItems) {
120
126
  const merged = existingItems.map((item) => ({ ...item }));
121
127
  const index = new Map();
@@ -145,20 +151,6 @@ function mergeConfig(existingConfig, templateConfig) {
145
151
  return result;
146
152
  }
147
153
 
148
- function installPackage(packageSpec, repoRoot) {
149
- const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
150
- const result = spawnSync(
151
- npmCmd,
152
- ["install", "--save-dev", packageSpec],
153
- { cwd: repoRoot, encoding: "utf8", stdio: ["inherit", "pipe", "pipe"] }
154
- );
155
- if (result.stdout) process.stdout.write(result.stdout);
156
- if (result.stderr) process.stderr.write(result.stderr);
157
- if (result.status !== 0) {
158
- process.exit(result.status || 1);
159
- }
160
- }
161
-
162
154
  function commandHook(positional, options) {
163
155
  const action = positional[0];
164
156
  const repoRoot = path.resolve(options.repo || process.cwd());
@@ -167,28 +159,31 @@ function commandHook(positional, options) {
167
159
 
168
160
  function commandInstallHooks(positional, options) {
169
161
  const agent = positional[0] || options.agent || "codex";
170
- const repoRoot = path.resolve(options.repo || process.cwd());
171
- const targetPath = targetPathForAgent(agent, repoRoot);
162
+ const isGlobal = Boolean(options.global);
172
163
  const template = loadJson(templatePathForAgent(agent));
164
+ let targetPath;
165
+ let scope;
166
+ let repoRoot = null;
167
+ if (isGlobal) {
168
+ targetPath = globalTargetPathForAgent(agent);
169
+ scope = "global";
170
+ } else {
171
+ repoRoot = path.resolve(options.repo || process.cwd());
172
+ targetPath = targetPathForAgent(agent, repoRoot);
173
+ scope = "repo";
174
+ }
173
175
  const existing = fs.existsSync(targetPath) ? loadJson(targetPath) : {};
174
176
  const merged = mergeConfig(existing, template);
175
177
  writeJson(targetPath, merged);
176
- process.stdout.write(
177
- `${JSON.stringify({ repo_root: repoRoot, agent, target: targetPath, events: Object.keys(template.hooks || {}) }, null, 2)}\n`
178
- );
179
- }
180
-
181
- function commandInstallCli(_positional, options) {
182
- const repoRoot = path.resolve(options.repo || process.cwd());
183
- const packageSpec = options.package || "@xluos/dev-assets-cli";
184
- installPackage(packageSpec, repoRoot);
178
+ const report = { agent, scope, target: targetPath, events: Object.keys(template.hooks || {}) };
179
+ if (repoRoot) report.repo_root = repoRoot;
180
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
185
181
  }
186
182
 
187
183
  function printHelp() {
188
184
  process.stdout.write(`Usage:
189
185
  dev-assets hook <session-start|pre-compact|stop|session-end> [--repo PATH]
190
- dev-assets install-hooks <codex|claude> [--repo PATH]
191
- dev-assets install-cli [--repo PATH] [--package SPEC]
186
+ dev-assets install-hooks <codex|claude> [--repo PATH] [--global]
192
187
 
193
188
  Environment:
194
189
  DEV_ASSETS_ROOT defaults to ${DEFAULT_STORAGE_ROOT}
@@ -210,10 +205,6 @@ function main() {
210
205
  commandInstallHooks(positional, options);
211
206
  return;
212
207
  }
213
- if (command === "install-cli") {
214
- commandInstallCli(positional, options);
215
- return;
216
- }
217
208
  fail(`unknown command: ${command}`);
218
209
  }
219
210
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xluos/dev-assets-cli",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "CLI for dev-assets hooks and repo-local setup",
5
5
  "license": "MIT",
6
6
  "scripts": {
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: dev-assets-sync
3
- description: Use when the current conversation reaches a commit-related checkpoint or another clear persistence checkpoint, and Codex should write only this round's durable memory back into the current branch memory while keeping repo-shared metadata in sync.
3
+ description: Use when the current conversation reaches a commit-related checkpoint or another clear persistence checkpoint where this round's progress, risks, next steps, and decisions should now be snapshotted for the next session. Use this skill for commit-time, handoff-ready, lifecycle-hook, or milestone snapshots, not for correcting existing memory or persisting one-off clarifications. Repo-shared source updates here mean shared documents and links, not branch-only hot paths.
4
4
  ---
5
5
 
6
6
  # Dev Assets Sync
@@ -11,9 +11,19 @@ description: Use when the current conversation reaches a commit-related checkpoi
11
11
 
12
12
  ## Workflow
13
13
 
14
- ### Step 1: Decide whether this moment is worth syncing
14
+ ### Step 1: Confirm this is a real checkpoint
15
15
 
16
- 只在当前时点已经形成明确的持久化价值时触发 `sync`。
16
+ 进入 sync 前,确认当前时点确实是检查点:
17
+
18
+ - 刚完成一次提交、准备提交、或刚完成一轮代码/排查检查点
19
+ - 当前进展、阻塞、下一步已经清晰到值得 handoff 或跨会话延续
20
+ - 阶段性方向已经收敛,适合在这个检查点留一份快照
21
+ - 本轮新增了仓库共享层之后还会复用的文档入口、链接或决策结论
22
+ - lifecycle hook 触发
23
+
24
+ 如果只是单次排查里刚确认 root cause / scope / 某条规则,还不到检查点,就别进 sync。具体路由判定(包括 sync 与 update 的关系)以 `using-dev-assets` 为准。
25
+
26
+ 确认是检查点后,sync 是一个"复合动作包":本流程内部如果同时发现需要改写某条旧记忆,先按 `dev-assets-update` 改写对应 section,再回到 Step 2 做 record-session。
17
27
 
18
28
  ### Step 2: Summarize only what this checkpoint should leave behind
19
29
 
@@ -25,7 +35,11 @@ description: Use when the current conversation reaches a commit-related checkpoi
25
35
  - 关键决策与原因
26
36
  - 本次新增的共享资料入口
27
37
 
28
- 然后运行:
38
+ 这里的“共享资料入口”只指仓库共享层应该复用的文档、链接、外部资料,不包括当前分支后续要看的 hot paths、目录或局部代码入口。
39
+
40
+ `record-session` 不接受任意自定义字段名(例如 `current_progress`、`blockers_or_caveats`、`shared_sources` 都会被忽略;`decisions` 必须是 object 数组而不是 string 数组,否则脚本会直接报错)。准备 `summary.json` 之前请先读 `references/commit-sync.md`,里面有完整字段表、别名、最小示例和常见错误模式,不要凭印象脑补 schema。
41
+
42
+ 整理好 summary 后运行:
29
43
 
30
44
  ```bash
31
45
  python3 /absolute/path/to/dev-assets-sync/scripts/dev_asset_sync.py record-session --repo <repo-path> --summary-file <summary.json>
@@ -39,6 +53,11 @@ python3 /absolute/path/to/dev-assets-sync/scripts/dev_asset_sync.py record-sessi
39
53
  - 新增资料入口 → repo `sources.md`
40
54
  - HEAD / 最近访问分支 → manifest
41
55
 
56
+ 额外约束:
57
+
58
+ - 写进 `repo/sources.md` 的必须是 repo 共享资料入口
59
+ - branch-only 导航、hot paths、局部代码入口不属于这里的 `sources`
60
+
42
61
  它默认不做这些事:
43
62
 
44
63
  - 不重建整个 branch memory
@@ -8,3 +8,64 @@ It should:
8
8
  2. update only the branch or repo memory sections directly affected by this commit
9
9
  3. update lightweight commit metadata when needed
10
10
  4. leave detailed implementation history in Git
11
+
12
+ ## `record-session` summary schema
13
+
14
+ `dev_asset_sync.py record-session` expects a JSON object with script-recognized keys. Do not infer field names from the prose bullets alone.
15
+
16
+ Accepted keys:
17
+
18
+ - `title`: string
19
+ - `overview_summary`: string or string array
20
+ - `implementation_notes`: string or string array
21
+ - `changes`: string or string array; alias of `implementation_notes`
22
+ - `risks`: string or string array
23
+ - `next_steps`: string or string array
24
+ - `sources`: string or string array
25
+ - `source_updates`: string or string array; alias of `sources`
26
+ - `decisions`: object array; each item should look like `{ "decision": "...", "reason": "...", "impact": "..." }`
27
+ - `memory`: string or string array
28
+ - `context_updates`: string or string array; alias of `memory`
29
+ - `review_notes`: string or string array
30
+ - `frontend_updates`: string or string array
31
+ - `backend_updates`: string or string array
32
+ - `test_updates`: string or string array
33
+
34
+ Minimal example:
35
+
36
+ ```json
37
+ {
38
+ "title": "本次检查点标题",
39
+ "implementation_notes": [
40
+ "完成了当前轮次最值得留存的进展"
41
+ ],
42
+ "risks": [
43
+ "还有一个已知风险未消除"
44
+ ],
45
+ "next_steps": [
46
+ "下次继续先做什么"
47
+ ],
48
+ "decisions": [
49
+ {
50
+ "decision": "之后优先检查页面入口装配和插件注入",
51
+ "reason": "同批功能整组缺失时,先看单插件显隐容易偏题",
52
+ "impact": "适用于同类插件化页面的排查顺序"
53
+ }
54
+ ],
55
+ "sources": [
56
+ "apps/example/page.tsx - 与这次检查点相关的共享资料入口"
57
+ ]
58
+ }
59
+ ```
60
+
61
+ Common mistakes:
62
+
63
+ - `current_progress` is not recognized; use `implementation_notes`
64
+ - `blockers_or_caveats` is not recognized; use `risks`
65
+ - `shared_sources` is not recognized; use `sources`
66
+ - `decisions` must be an object array, not a string array
67
+
68
+ Failure mode to remember:
69
+
70
+ - Wrong field names such as `shared_sources` are ignored
71
+ - `decisions` as `string[]` will fail when the script evaluates `item.get("decision")`
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: dev-assets-update
3
- description: Use when current development memory needs to be corrected or supplemented, whether explicitly requested by the user or implicitly required because the conversation produced new stable understanding or new shared source entry points for the current repository.
3
+ description: Use when current development memory needs to be corrected, rewritten, or supplemented because the existing dev-assets are wrong, stale, missing a key premise, or the user explicitly wants a durable update. Implicit use is limited to repeated corrections or invalidated conclusions, and to newly provided relevant sources or links that should change future understanding. Do not use this skill for ordinary checkpoint summaries or one-off clarifications; use dev-assets-sync for checkpoint snapshots.
4
4
  ---
5
5
 
6
6
  # Dev Assets Update
@@ -9,6 +9,17 @@ description: Use when current development memory needs to be corrected or supple
9
9
 
10
10
  **Announce at start:** 用一句简短的话说明将先重写相关 section,而不是继续追加历史。
11
11
 
12
+ ## Trigger Hints
13
+
14
+ `update` 是非检查点时刻的零散修正/补充入口。典型触发:
15
+
16
+ - 用户明确要求"记一下"、"同步到 dev-assets"、"把这条经验写进去"
17
+ - 发现之前的工作记忆写错了、过时了、缺少关键前提
18
+ - 会话里反复出现理解偏差、口径被纠正、或先前结论已经失效
19
+ - 用户提供了新的相关资料、链接、文档入口,且这些信息会影响后续理解
20
+
21
+ 检查点时刻(commit / handoff / 阶段收敛 / lifecycle hook)请走 `dev-assets-sync`,由 sync 在其流程内部再决定是否调用 update。完整路由判定见 `using-dev-assets`。
22
+
12
23
  ## Workflow
13
24
 
14
25
  ### Step 1: Locate the current assets
@@ -30,6 +41,11 @@ python3 /absolute/path/to/dev-assets-update/scripts/dev_asset_update.py show --r
30
41
  - branch `context.md`:why / caveat / workaround / decision
31
42
  - repo `sources.md`:共享资料入口
32
43
 
44
+ 补充约束:
45
+
46
+ - `source` / `link` / `shared-source` 这类更新默认面向 repo 共享资料入口
47
+ - 当前分支后续要看的 hot paths、目录、局部代码入口,不要伪装成 repo `sources.md` 更新
48
+
33
49
  如果是显式 repo 共享层更新,使用这些 kind:
34
50
 
35
51
  - `shared-overview`
@@ -88,6 +104,6 @@ python3 /absolute/path/to/dev-assets-update/scripts/dev_asset_update.py touch-ma
88
104
  **Never:**
89
105
 
90
106
  - 把所有新增信息都堆到一个文件里
91
- - 用“之后再整理”为理由跳过沉淀
107
+ - 用"之后再整理"为理由跳过沉淀
92
108
  - 继续把 `update` 当成 append-only 笔记工具
93
109
  - 把 branch-specific 当前工作态写进 repo 共享层
@@ -14,48 +14,38 @@ description: >-
14
14
 
15
15
  ## Routing
16
16
 
17
- ### Route to `dev-assets-context`
17
+ 按下面的顺序判断,命中第一个就走对应 skill:
18
18
 
19
- 当用户是在已有分支上继续开发、排查、解释、修改时:
19
+ | 当前情境 | 走哪个 skill |
20
+ | --- | --- |
21
+ | 当前 repo 还没有当前 branch 的资产目录,或这是新需求/新分支第一次开始 | `dev-assets-setup` |
22
+ | 在已有分支上继续开发、排查、解释、修改(默认情况) | `dev-assets-context` |
23
+ | 已经到了检查点:刚提交 / 准备提交 / handoff / 阶段收敛 / lifecycle hook 触发 | `dev-assets-sync` |
24
+ | 不是检查点,但对话里出现了"现有记忆写错了/缺了/被新资料推翻了" | `dev-assets-update` |
25
+ | 都不命中 | 不进入套件,正常对话 |
20
26
 
21
- - 先恢复当前 branch 记忆
22
- - 还不够时再看 repo 共享层
23
- - 只有需要原始事实时再看 branch / repo `sources.md`
27
+ ### Update Sync 的关系
24
28
 
25
- ### Route to `dev-assets-setup`
29
+ 不是平级互斥的两个触发器,而是:
26
30
 
27
- 当当前仓库还没有当前 branch 的资产目录,或者用户明确表示这是新需求 / 新分支第一次开始时:
31
+ - `sync` 是检查点时刻的**复合动作包**:内部可以包含 0–N 次 update + HEAD marker + manifest 刷新。
32
+ - 检查点时如果同时发现某条旧记忆需要修正,正确路径是"在 sync 流程里先调一次 update,再 record-session",不要两个都跳过、也不要纠结二选一。
33
+ - 非检查点的零散修正/补充才是 update 的独立触发场景。
34
+ - 一次性澄清、普通问答、低价值波动既不该 sync 也不该 update。
28
35
 
29
- - 初始化用户目录下的 repo+branch 存储
30
- - 先搭好当前记忆和共享资料入口,而不是复制完整文档
31
-
32
- ### Route to `dev-assets-sync`
33
-
34
- 当当前对话已经到达明确的检查点,并且本轮产生了需要跨会话保留的稳定记忆时:
35
-
36
- - 把它视为“沉淀本次检查点留下的关键信息”的时刻
37
- - 不是生成流水账,也不是重建整个状态
38
-
39
- ### Route to `dev-assets-update`
40
-
41
- 当当前记忆需要被补充或纠正,并且更新后的内容会明显改善后续恢复上下文或回源效率时:
42
-
43
- - 定位 repo + branch 资产目录
44
- - 选择最合适的目标文件和 section
45
- - 把本轮新信息和相关会话上下文整理后重写进去
36
+ skill 内部不再重复这条边界,统一以本表为准。
46
37
 
47
38
  ## Always / Never
48
39
 
49
40
  **Always:**
50
41
 
51
42
  - 在 Git 仓库开发对话开头先做一次路由判断
52
- - 把“继续开发”“提交检查点”和“阶段性里程碑”都视为高优先级触发场景
53
43
  - 优先维护当前 branch 的有效记忆
54
- - 在新理解会影响后续恢复时,主动判断是否该隐式触发 `update`
44
+ - 把检查点时刻理解为"sync 包含若干 update",而不是二选一
55
45
 
56
46
  **Never:**
57
47
 
58
48
  - 明知道在继续分支开发,却跳过 dev-assets 判断
59
49
  - 把 repo 共享层当成 branch 当前工作态的替代品
60
50
  - 在 branch 资产缺失时直接开始实现
61
- - 因为低价值波动或一次性澄清就频繁触发 `update`
51
+ - 因为低价值波动或一次性澄清就触发任何写入