@betterdanlins/ai-memory 0.1.0 → 0.3.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.
Files changed (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +108 -14
  3. package/README.zh-CN.md +120 -0
  4. package/bin/cli.js +93 -4
  5. package/package.json +1 -1
  6. package/src/framework.js +259 -0
  7. package/src/legacy-v0.1.js +43 -0
  8. package/src/manifest.js +20 -1
  9. package/src/migrations.js +28 -0
  10. package/src/path-safety.js +51 -0
  11. package/src/scaffold.js +114 -13
  12. package/templates/claude/.claude/commands/delivery-readiness.md +6 -0
  13. package/templates/claude/.claude/commands/design-feature.md +6 -0
  14. package/templates/claude/.claude/commands/finalize-requirement.md +1 -1
  15. package/templates/claude/.claude/commands/project-inception.md +5 -0
  16. package/templates/claude/.claude/settings.json +1 -1
  17. package/templates/claude/.claude/skills/critic/SKILL.md +2 -2
  18. package/templates/claude/.claude/skills/delivery-readiness/SKILL.md +6 -0
  19. package/templates/claude/.claude/skills/feature-design/SKILL.md +6 -0
  20. package/templates/claude/.claude/skills/memory-update/SKILL.md +1 -1
  21. package/templates/claude/.claude/skills/project-inception/SKILL.md +6 -0
  22. package/templates/claude/CLAUDE.md +10 -5
  23. package/templates/codex/.agents/skills/critic/SKILL.md +2 -2
  24. package/templates/codex/.agents/skills/delivery-readiness/SKILL.md +6 -0
  25. package/templates/codex/.agents/skills/feature-design/SKILL.md +6 -0
  26. package/templates/codex/.agents/skills/memory-update/SKILL.md +1 -1
  27. package/templates/codex/.agents/skills/project-inception/SKILL.md +6 -0
  28. package/templates/codex/AGENTS.md +10 -5
  29. package/templates/common/.ai/README.md +2 -1
  30. package/templates/common/.ai/memory/project-state.md +1 -1
  31. package/templates/common/.ai/memory/session-log.md +1 -1
  32. package/templates/common/.ai/skills/architecture.md +24 -14
  33. package/templates/common/.ai/skills/code-review.md +1 -1
  34. package/templates/common/.ai/skills/critic.md +3 -2
  35. package/templates/common/.ai/skills/delivery-readiness.md +32 -0
  36. package/templates/common/.ai/skills/feature-design.md +33 -0
  37. package/templates/common/.ai/skills/memory-update.md +19 -14
  38. package/templates/common/.ai/skills/project-inception.md +33 -0
  39. package/templates/common/.ai/skills/requirements-flow.md +31 -16
  40. package/templates/common/docs/architecture/data-model.md +43 -0
  41. package/templates/common/docs/architecture/deployment.md +40 -0
  42. package/templates/common/docs/architecture/quality-attributes.md +50 -0
  43. package/templates/common/docs/architecture/system-context.md +35 -0
  44. package/templates/common/docs/design/README.md +22 -0
  45. package/templates/common/docs/design/v1.0.0/.gitkeep +0 -0
  46. package/templates/common/docs/requirements/README.md +2 -1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Betterdan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,26 +1,120 @@
1
- # @betterdanlins/ai-memory
1
+ # ai-memory
2
2
 
3
- AI 记忆 + 需求工作流脚手架:一条命令在项目里生成跨 Claude Code / Codex
4
- 记忆层(.ai/memory)、方法论层(.ai/skills)、需求版本目录(docs/requirements)
5
- 与两侧薄适配层。
3
+ > Scaffold a shared AI memory layer and requirements workflow into any project — one command, portable across Claude Code, Codex, and future agents.
6
4
 
7
- ## 用法
5
+ [English](README.md) · [简体中文](README.zh-CN.md)
6
+
7
+ ## Why
8
+
9
+ AI coding agents forget everything between sessions, and every tool (Claude Code, Codex, …) wants its own config format. `ai-memory` fixes both:
10
+
11
+ - **One source of truth.** All real content lives in a single agent-agnostic `.ai/` directory. Tool-specific folders (`.claude/`, `.agents/`) are thin wrappers that just point back to it — so switching or adding tools never forks your knowledge base.
12
+ - **Memory that survives sessions.** A structured memory layer records what the last session finished, overall requirement progress, and user-level preferences, so a fresh agent can pick up exactly where the previous one left off.
13
+ - **A requirements workflow with guardrails.** Human rough drafts and AI-finalized specs live in versioned `draft/` → `final/` directories, with a mandatory "critic" review gate before anything is finalized.
14
+
15
+ ## Quick start
8
16
 
9
17
  ```bash
18
+ # Interactive
10
19
  npx @betterdanlins/ai-memory init
11
- # 非交互:
20
+
21
+ # Non-interactive
12
22
  npx @betterdanlins/ai-memory init --name demo --stack "PHP + Vue" --tools claude,codex --yes
13
- # 从已有项目导入用户级记忆:
23
+
24
+ # Import user-level memory (profile/feedback) from an existing project
14
25
  npx @betterdanlins/ai-memory init --import /path/to/other-project
26
+
27
+ # Inspect an existing project's upgrade plan without writing
28
+ npx @betterdanlins/ai-memory update --dry-run
29
+
30
+ # Apply only conflict-free safe updates; abort entirely on user changes
31
+ npx @betterdanlins/ai-memory update --yes
32
+ ```
33
+
34
+ Nothing is ever overwritten silently: existing files are asked about one by one (interactive) or skipped (`--yes`).
35
+ An invalid, non-directory, or unreadable `--import` project path fails explicitly. If the project directory is valid but an individual memory file is missing, the CLI falls back to its template and reports that fallback in the summary.
36
+ Before writing, the CLI checks for duplicate template destinations, path traversal, and symbolic links, then reads and renders every planned file. If an actual filesystem write fails midway, the error summary lists both written and not-yet-written files.
37
+ An initialized project cannot be initialized again. A newer CLI first uses `update --dry-run` to identify versions and user modifications. `update --yes` applies only additions and baseline-matching safe updates, aborting before any write when merge or review items exist.
38
+
39
+ ## What it generates
40
+
41
+ ```
42
+ .ai/ # single source of truth, shared by all agents
43
+ ├── README.md # session entry protocol
44
+ ├── ai-memory.json # version, schema, tools, ownership, baseline hashes
45
+ ├── memory/
46
+ │ ├── MEMORY.md # index — agents read this first
47
+ │ ├── project-state.md # stack, current version, requirement progress
48
+ │ ├── session-log.md # rolling log of progress & next steps
49
+ │ ├── user-profile.md # background, preferences, communication style
50
+ │ ├── feedback.md # behavioral norms distilled from feedback
51
+ │ └── features/ # per-feature dossiers
52
+ └── skills/ # methodology: requirements-flow, architecture,
53
+ # project-inception, feature-design, delivery-readiness, etc.
54
+
55
+ docs/architecture/ # engineering baseline for 0-to-1 projects
56
+ ├── system-context.md # boundaries, actors, modules, and key flows
57
+ ├── data-model.md # entities, ownership, consistency, and migration
58
+ ├── quality-attributes.md # performance, observability, scalability, reliability
59
+ └── deployment.md # topology, releases, rollback, and operations
60
+
61
+ docs/requirements/vX.Y.Z/
62
+ ├── draft/ # human-written rough requirements
63
+ └── final/ # AI-finalized specs (passes the critic gate)
64
+
65
+ docs/design/vX.Y.Z/ # M/L-risk feature how, technical contracts, deltas
66
+
67
+ # Thin adapters, generated only for the tools you enable:
68
+ CLAUDE.md + .claude/ # Claude Code: commands, skills, agents, settings
69
+ AGENTS.md + .agents/ # Codex: skills
15
70
  ```
16
71
 
17
- `--import` 从已有项目导入 user-profile/feedback;目标文件已存在时按冲突策略处理(--yes 下跳过,交互下询问),绝不静默覆盖。
72
+ ## CLI commands
73
+
74
+ | Command | Description |
75
+ | --- | --- |
76
+ | `init` | Initialize a new project; refuses to run over an existing ai-memory installation |
77
+ | `update --dry-run` | Read-only analysis of the upgrade plan from an existing project to this CLI version |
78
+ | `update --yes` | Apply conflict-free safe updates; refuse user changes, mixed-file conflicts, or missing migration paths |
79
+
80
+ ### `init` options
81
+
82
+ | Option | Description |
83
+ | --- | --- |
84
+ | `--name <name>` | Project name (defaults to the current directory name) |
85
+ | `--stack <desc>` | Tech-stack description |
86
+ | `--tools <list>` | Comma-separated adapters to enable: `claude`, `codex` |
87
+ | `--import <path>` | Import `user-profile` / `feedback` from an existing project |
88
+ | `--yes` | Non-interactive: fill defaults, skip on any conflict |
89
+
90
+ ## How it works
18
91
 
19
- ## 设计
92
+ The generator is a small set of pure functions:
93
+
94
+ - **manifest** — walks the `common` / `claude` / `codex` template groups, keeping only the groups whose tools are enabled, and produces a flat `{src, dest}` list; duplicate destinations fail before writing and list every source.
95
+ - **render** — substitutes `{{variable}}` placeholders and throws on any undefined variable, so a broken template fails loudly instead of shipping `{{...}}`.
96
+ - **scaffold** — validates safe destinations and symbolic links, resolves conflicts, and reads/renders the complete plan in memory before writing; it also validates `--import` and pulls `user-profile` / `feedback` from it (falling back to the template with an explicit report when an individual source file is missing).
97
+ - **framework metadata** — a fresh init records framework/schema versions, ownership, and generated hashes; update uses them to distinguish safe updates from user changes. Metadata-free v0.1 projects are planned conservatively as legacy installations.
98
+
99
+ ## Design principles
100
+
101
+ - **Single source** — content lives only in `.ai/`; `.claude/` and `.agents/` are trigger wrappers.
102
+ - **Engineering-node memory** — write session-log entries for independently verifiable features/phases, durable decisions, status changes, or tool handoffs, avoiding noise from tiny implementation steps.
103
+ - **Dual requirement directories** — human draft (`draft/`) → AI final (`final/`) behind a mandatory critic gate.
104
+ - **Project engineering baseline** — 0-to-1 projects establish language-agnostic system, data, quality-attribute, and deployment baselines once; ordinary features record only deltas.
105
+ - **Risk-tiered design** — S-risk requirements proceed directly to implementation; M/L-risk work uses feature-design for how, technical contracts, and engineering impact, with Superpowers selected only when justified by risk.
106
+ - **Evidence-based delivery** — before release, verify applicable contracts, tests, migration, rollback, performance, observability, and operations, producing an explicit readiness verdict.
107
+ - **Low-noise memory** — persist independently verifiable engineering nodes, durable decisions, status changes, and session handoffs instead of every small coding step.
108
+ - **Idempotent** — existing files are asked about one by one; `--yes` always skips. Never a silent overwrite.
109
+ - **Safe writes** — destinations must remain inside the target project, symbolic-link overwrites are rejected, and write failures retain a diagnostic progress summary.
110
+ - **Explicit compatibility** — newer CLIs can recognize older schemas, user assets are never overwritten from templates, and actual updates only touch baseline-matching files after a dry run rather than re-running init.
111
+
112
+ ## Development
113
+
114
+ ```bash
115
+ npm test # node --test test/*.test.js
116
+ ```
20
117
 
21
- - 单一源:所有正文只在 `.ai/`,`.claude/`、`.agents/` 只是触发包装
22
- - 节点式记忆:完成任务节点立即写 session-log,跨工具切换不断档
23
- - 需求双目录:人工粗稿 `draft/` → AI 定稿 `final/`(强制 critic 门)
24
- - 幂等:已存在的文件逐个询问,绝不静默覆盖(`--yes` 一律跳过)
118
+ ## License
25
119
 
26
- 设计文档:`docs/superpowers/specs/2026-07-05-ai-memory-framework-design.md`
120
+ [MIT](LICENSE) © Betterdan
@@ -0,0 +1,120 @@
1
+ # ai-memory
2
+
3
+ > 一条命令,为任意项目搭建一套共享的 AI 记忆层与需求工作流 —— 跨 Claude Code、Codex 及未来的 agent 通用。
4
+
5
+ [English](README.md) · [简体中文](README.zh-CN.md)
6
+
7
+ ## 为什么
8
+
9
+ AI 编码 agent 在会话之间会丢失全部上下文,而每个工具(Claude Code、Codex……)又各有各的配置格式。`ai-memory` 同时解决这两个问题:
10
+
11
+ - **单一源。** 所有实际内容只存在于一份 agent 无关的 `.ai/` 目录里。工具专属目录(`.claude/`、`.agents/`)只是指回它的薄包装 —— 切换或新增工具都不会让你的知识库分叉。
12
+ - **跨会话不断档的记忆。** 结构化的记忆层记录上个会话完成到哪、需求整体进度、以及用户级偏好,让全新的 agent 能从上一个 agent 停下的地方精确接续。
13
+ - **带护栏的需求工作流。** 人工粗稿与 AI 定稿分别存放在带版本号的 `draft/` → `final/` 目录中,定稿前强制经过一道 “critic” 反驳评审门。
14
+
15
+ ## 快速开始
16
+
17
+ ```bash
18
+ # 交互式
19
+ npx @betterdanlins/ai-memory init
20
+
21
+ # 非交互式
22
+ npx @betterdanlins/ai-memory init --name demo --stack "PHP + Vue" --tools claude,codex --yes
23
+
24
+ # 从已有项目导入用户级记忆(profile/feedback)
25
+ npx @betterdanlins/ai-memory init --import /path/to/other-project
26
+
27
+ # 已初始化项目只读检查升级计划
28
+ npx @betterdanlins/ai-memory update --dry-run
29
+
30
+ # 只应用无冲突的安全更新;有用户修改时整体拒绝
31
+ npx @betterdanlins/ai-memory update --yes
32
+ ```
33
+
34
+ 绝不静默覆盖:已存在的文件会逐个询问(交互式),或直接跳过(`--yes`)。
35
+ `--import` 指向的项目目录不存在、不是目录或不可读时会直接报错;目录有效但某个记忆文件缺失时会回退到默认模板,并在执行摘要中明确提示。
36
+ 生成前会检查重复模板目标、路径越界和符号链接;模板读取与渲染全部通过后才开始写入。若实际磁盘写入中途失败,错误摘要会列出已经写入和尚未写入的文件。
37
+ 已初始化项目不能重新运行 `init`;新版 CLI 先通过 `update --dry-run` 识别版本和用户修改。`update --yes` 只应用新增和基线哈希匹配的安全更新,存在合并/审查项时在写入前整体拒绝。
38
+
39
+ ## 生成什么
40
+
41
+ ```
42
+ .ai/ # 单一源,所有 agent 共享
43
+ ├── README.md # 会话进场协议
44
+ ├── ai-memory.json # 版本、Schema、工具、所有权和生成基线哈希
45
+ ├── memory/
46
+ │ ├── MEMORY.md # 索引 —— agent 进场先读
47
+ │ ├── project-state.md # 技术栈、当前版本、需求进度
48
+ │ ├── session-log.md # 进展与下一步的流水日志
49
+ │ ├── user-profile.md # 背景、偏好、沟通方式
50
+ │ ├── feedback.md # 从反馈提炼的行为规范
51
+ │ └── features/ # 功能档案
52
+ └── skills/ # 方法论:requirements-flow、architecture、
53
+ # project-inception、feature-design、delivery-readiness 等
54
+
55
+ docs/architecture/ # 0→1 项目工程基线
56
+ ├── system-context.md # 系统边界、参与者、模块和关键流程
57
+ ├── data-model.md # 实体、关系、所有权、一致性和迁移
58
+ ├── quality-attributes.md # 性能、可观测性、扩展性、可靠性等
59
+ └── deployment.md # 部署拓扑、发布、回滚和运行保障
60
+
61
+ docs/requirements/vX.Y.Z/
62
+ ├── draft/ # 人工书写的粗稿需求
63
+ └── final/ # AI 定稿(通过 critic 门)
64
+
65
+ docs/design/vX.Y.Z/ # M/L 级功能 how、技术接口与工程增量
66
+
67
+ # 薄适配层,仅为你启用的工具生成:
68
+ CLAUDE.md + .claude/ # Claude Code:commands、skills、agents、settings
69
+ AGENTS.md + .agents/ # Codex:skills
70
+ ```
71
+
72
+ ## CLI 命令
73
+
74
+ | 命令 | 说明 |
75
+ | --- | --- |
76
+ | `init` | 初始化全新项目;检测到已有 ai-memory 安装时拒绝执行 |
77
+ | `update --dry-run` | 只读分析旧项目到当前 CLI 版本的升级计划 |
78
+ | `update --yes` | 应用无冲突安全更新;用户修改、混合文件冲突或缺失迁移路径会拒绝执行 |
79
+
80
+ ### `init` 选项
81
+
82
+ | 选项 | 说明 |
83
+ | --- | --- |
84
+ | `--name <name>` | 项目名(默认取当前目录名) |
85
+ | `--stack <desc>` | 技术栈描述 |
86
+ | `--tools <list>` | 逗号分隔的适配层:`claude`、`codex` |
87
+ | `--import <path>` | 从已有项目导入 `user-profile` / `feedback` |
88
+ | `--yes` | 非交互模式:缺参用默认值,冲突一律跳过 |
89
+
90
+ ## 工作原理
91
+
92
+ 生成器由一组纯函数构成:
93
+
94
+ - **manifest** —— 遍历 `common` / `claude` / `codex` 模板组,只保留已启用工具对应的组,产出一份扁平的 `{src, dest}` 清单;重复目标会在写入前报错并列出来源。
95
+ - **render** —— 替换 `{{变量}}` 占位符,遇到任何未定义变量即抛错,让坏掉的模板大声失败,而不是把 `{{...}}` 发出去。
96
+ - **scaffold** —— 预检安全目标路径和符号链接,处理冲突并在内存中完成全部读取/渲染后再逐个写入;提供 `--import` 时先校验导入目录,再从中拉取 `user-profile` / `feedback`(单个源文件缺失则回退到模板并明确报告)。
97
+ - **framework metadata** —— 全新 init 记录 framework/schema 版本、文件所有权和生成哈希;update 据此区分安全更新与用户修改。无元数据的 v0.1 项目按 legacy 保守规划。
98
+
99
+ ## 设计原则
100
+
101
+ - **单一源** —— 正文只在 `.ai/`;`.claude/`、`.agents/` 只是触发包装。
102
+ - **工程节点记忆** —— 只在可独立验收的功能/阶段、关键决策、状态变化或工具切换时写 session-log,避免细碎步骤制造噪声。
103
+ - **需求双目录** —— 人工粗稿(`draft/`)→ AI 定稿(`final/`),中间隔一道强制 critic 门。
104
+ - **项目工程基线** —— 0→1 项目先建立语言无关的系统、数据、质量属性和部署基线;普通功能只记录增量,不重复设计全局架构。
105
+ - **风险分级设计** —— S 级需求直接实现;M/L 级用 feature-design 补齐 how、技术接口和工程影响,Superpowers 只按风险选择使用。
106
+ - **证据化交付** —— 发布前按风险检查契约、测试、迁移、回滚、性能、可观测性和运行保障,输出明确 ready 状态。
107
+ - **低噪声记忆** —— 只在可验收工程节点、关键决策、状态变化和会话切换时落盘,不记录每个细碎代码步骤。
108
+ - **幂等** —— 已存在的文件逐个询问;`--yes` 一律跳过。绝不静默覆盖。
109
+ - **安全落盘** —— 目标必须位于项目目录内,拒绝跟随符号链接覆盖;写入失败会保留可诊断的进度摘要。
110
+ - **显式兼容** —— 新版 CLI 可识别旧 Schema,用户资产永不由模板覆盖;升级先 dry-run,实际更新只处理基线匹配文件,不把重新 init 当作更新。
111
+
112
+ ## 开发
113
+
114
+ ```bash
115
+ npm test # node --test test/*.test.js
116
+ ```
117
+
118
+ ## 许可证
119
+
120
+ [MIT](LICENSE) © Betterdan
package/bin/cli.js CHANGED
@@ -1,13 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from 'commander';
3
+ import { readFile } from 'node:fs/promises';
3
4
  import path from 'node:path';
4
5
  import { fileURLToPath } from 'node:url';
5
- import { scaffold } from '../src/scaffold.js';
6
+ import { applyFrameworkUpdate, detectInstallation, METADATA_DEST, planFrameworkUpdate, writeFrameworkMetadata } from '../src/framework.js';
7
+ import { ScaffoldError, scaffold } from '../src/scaffold.js';
6
8
 
7
9
  const TEMPLATES = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'templates');
10
+ const PACKAGE = JSON.parse(await readFile(new URL('../package.json', import.meta.url), 'utf8'));
8
11
  const program = new Command();
9
12
 
10
- program.name('ai-memory').description('AI memory + requirements workflow scaffolder');
13
+ program.name('ai-memory').description('AI memory + requirements workflow scaffolder').version(PACKAGE.version);
11
14
 
12
15
  program
13
16
  .command('init')
@@ -19,6 +22,13 @@ program
19
22
  .option('--yes', '非交互模式:缺参用默认值,冲突一律跳过')
20
23
  .action(async (opts) => {
21
24
  const targetDir = process.cwd();
25
+ const existingInstallation = await detectInstallation(targetDir);
26
+ if (existingInstallation.kind !== 'none') {
27
+ const label = existingInstallation.kind === 'legacy'
28
+ ? '检测到无元数据的 v0.1.0 legacy 项目'
29
+ : `项目已由 ai-memory ${existingInstallation.metadata.frameworkVersion} 初始化`;
30
+ throw new Error(`${label};不要重新运行 init,请先执行 ai-memory update --dry-run`);
31
+ }
22
32
  let { name, stack, tools: toolsRaw } = opts;
23
33
 
24
34
  // Validate CLI-supplied --tools before entering interactive prompts
@@ -51,7 +61,7 @@ program
51
61
  stack ??= '(待补充)';
52
62
  toolsRaw ??= 'claude,codex';
53
63
 
54
- const tools = toolsRaw.split(',').map(s => s.trim()).filter(Boolean);
64
+ const tools = [...new Set(toolsRaw.split(',').map(s => s.trim()).filter(Boolean))];
55
65
  if (tools.length === 0) {
56
66
  console.log('未启用任何工具适配,仅生成 .ai/ 通用层');
57
67
  }
@@ -63,18 +73,97 @@ program
63
73
  return (await confirm({ message: `${dest} 已存在,覆盖?`, default: false })) ? 'overwrite' : 'skip';
64
74
  };
65
75
 
66
- const vars = { projectName: name, techStack: stack, date: new Date().toISOString().slice(0, 10) };
76
+ const date = new Date().toISOString().slice(0, 10);
77
+ const vars = { projectName: name, techStack: stack, date };
67
78
  const r = await scaffold({ templatesRoot: TEMPLATES, targetDir, vars, tools, onConflict, importFrom });
79
+ if (r.skipped.length === 0) {
80
+ try {
81
+ await writeFrameworkMetadata({
82
+ targetDir, templatesRoot: TEMPLATES, frameworkVersion: PACKAGE.version,
83
+ tools, projectName: name, techStack: stack, date,
84
+ });
85
+ r.written.push(METADATA_DEST);
86
+ } catch (err) {
87
+ throw new ScaffoldError({
88
+ phase: 'write', dest: METADATA_DEST, destPath: path.join(targetDir, '.ai', 'ai-memory.json'),
89
+ cause: err, summary: r, notWritten: [METADATA_DEST],
90
+ });
91
+ }
92
+ } else {
93
+ console.log('警告:存在冲突跳过项,未创建框架元数据;当前结果不能自动升级');
94
+ }
68
95
  console.log(`完成:写入 ${r.written.length},跳过 ${r.skipped.length}`);
96
+ if (r.imported.length) for (const d of r.imported) console.log(` 已导入 ${d}`);
97
+ if (r.fallback.length) for (const d of r.fallback) console.log(` 导入源缺失,使用模板 ${d}`);
69
98
  if (r.skipped.length) for (const d of r.skipped) console.log(` 跳过 ${d}`);
70
99
  console.log('下一步:打开项目让 agent 读 .ai/memory/MEMORY.md;把项目命令补进 CLAUDE.md/AGENTS.md。');
71
100
  });
72
101
 
102
+ program
103
+ .command('update')
104
+ .description('检查当前项目升级到本 CLI 版本所需的变更')
105
+ .option('--dry-run', '只输出升级计划,不修改任何文件')
106
+ .option('--yes', '应用无冲突的安全更新;存在合并/审查项时拒绝写入')
107
+ .action(async (opts) => {
108
+ if (opts.dryRun === opts.yes) throw new Error('update 必须且只能指定 --dry-run 或 --yes');
109
+ const plan = await planFrameworkUpdate({
110
+ targetDir: process.cwd(), templatesRoot: TEMPLATES, frameworkVersion: PACKAGE.version,
111
+ });
112
+ printUpdatePlan(plan);
113
+ if (opts.yes) {
114
+ const result = await applyFrameworkUpdate({ targetDir: process.cwd(), templatesRoot: TEMPLATES, plan });
115
+ console.log(`安全更新完成:写入 ${result.written.length}`);
116
+ for (const dest of result.written) console.log(` ${dest}`);
117
+ }
118
+ });
119
+
73
120
  program.parseAsync().catch((e) => {
74
121
  if (e.name === 'ExitPromptError') {
75
122
  console.log('已取消');
76
123
  } else {
77
124
  console.error('错误: ' + e.message);
125
+ if (e.name === 'ScaffoldError') {
126
+ console.error(`已写入 ${e.summary.written.length}:`);
127
+ for (const d of e.summary.written) console.error(` ${d}`);
128
+ console.error(`尚未写入 ${e.notWritten.length}:`);
129
+ for (const d of e.notWritten) console.error(` ${d}`);
130
+ if (e.summary.skipped.length) {
131
+ console.error(`已跳过 ${e.summary.skipped.length}:`);
132
+ for (const d of e.summary.skipped) console.error(` ${d}`);
133
+ }
134
+ }
78
135
  }
79
136
  process.exit(1);
80
137
  });
138
+
139
+ function printUpdatePlan(plan) {
140
+ const current = plan.installation.kind === 'legacy'
141
+ ? 'v0.1.0 legacy(无元数据)'
142
+ : `${plan.installation.metadata.frameworkVersion} / schema ${plan.installation.metadata.schemaVersion}`;
143
+ console.log(`当前:${current}`);
144
+ console.log(`目标:${plan.frameworkVersion} / schema ${plan.schemaVersion}`);
145
+ console.log(`工具:${plan.tools.length ? plan.tools.join(',') : '(仅 common)'}`);
146
+
147
+ const groups = [
148
+ ['add', '新增'],
149
+ ['update', '可安全更新'],
150
+ ['merge', '需要合并'],
151
+ ['review', '需要人工审查'],
152
+ ['review-remove', '需要确认移除'],
153
+ ['preserve', '保留用户资产'],
154
+ ['unchanged', '无需变化'],
155
+ ];
156
+ for (const [action, label] of groups) {
157
+ const items = plan.actions.filter(item => item.action === action);
158
+ console.log(`${label} ${items.length}`);
159
+ if (action !== 'unchanged') for (const item of items) console.log(` ${item.dest}`);
160
+ }
161
+ if (plan.migrations.length) {
162
+ console.log(`Schema 迁移 ${plan.migrations.length}(当前仅规划,不执行)`);
163
+ for (const migration of plan.migrations) {
164
+ console.log(` ${migration.id}: ${migration.from} → ${migration.to}`);
165
+ }
166
+ }
167
+ console.log('升级计划完成');
168
+ if (process.argv.includes('--dry-run')) console.log('dry-run:未修改任何文件');
169
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@betterdanlins/ai-memory",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "AI memory + requirements workflow scaffolder for Claude Code & Codex",
5
5
  "type": "module",
6
6
  "bin": {