the-frame-ai 0.2.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.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  FRAME — Framework for AI-Assisted Solo Development
4
4
 
5
- [🇺🇸 English](README.md) | [🇪🇸 Español](README.es.md) | [🇷🇺 Русский](README.ru.md) | [🇨🇳 中文](README.zh.md) | [🇧🇷 Português](README.pt.md)
5
+ [🇺🇸 English](README.md) | [🇨🇳 中文](README.zh.md) | [🇮🇳 हिंदी](README.hi.md) | [🇯🇵 日本語](README.ja.md) | [🇩🇪 Deutsch](README.de.md) | [🇪🇸 Español](README.es.md) | [🇷🇺 Русский](README.ru.md)
6
6
 
7
7
  ## What is FRAME?
8
8
 
package/README.ru.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # THE Frame
2
2
 
3
- [🇺🇸 English](README.md) | [🇪🇸 Español](README.es.md) | [🇷🇺 Русский](README.ru.md) | [🇨🇳 中文](README.zh.md) | [🇧🇷 Português](README.pt.md)
3
+ [🇺🇸 English](README.md) | [🇨🇳 中文](README.zh.md) | [🇮🇳 हिंदी](README.hi.md) | [🇯🇵 日本語](README.ja.md) | [🇩🇪 Deutsch](README.de.md) | [🇪🇸 Español](README.es.md) | [🇷🇺 Русский](README.ru.md)
4
4
 
5
5
  ## Что такое THE FRAME?
6
6
 
package/README.zh.md ADDED
@@ -0,0 +1,335 @@
1
+ # THE Frame
2
+
3
+ FRAME — 面向 AI 辅助独立开发的框架
4
+
5
+ [🇺🇸 English](README.md) | [🇨🇳 中文](README.zh.md) | [🇮🇳 हिंदी](README.hi.md) | [🇯🇵 日本語](README.ja.md) | [🇩🇪 Deutsch](README.de.md) | [🇪🇸 Español](README.es.md) | [🇷🇺 Русский](README.ru.md)
6
+
7
+ ## 什么是 FRAME?
8
+
9
+ **FRAME(面向 AI 辅助独立开发的框架)** 是一个专为使用 Claude Code 独立构建产品的开发者设计的框架。它将混乱的 AI 辅助开发转变为可预测的流程——从想法到部署——具备记忆、结构和防错保护。
10
+
11
+ 如果你正在独自使用 Claude Code 构建产品,并希望像团队一样工作——FRAME 就是为你准备的。
12
+
13
+ ## FRAME 解决哪些问题?
14
+
15
+ | 问题 | FRAME 提供的解决方案 |
16
+ |------|-------------------|
17
+ | 会话之间丢失上下文 | 项目记忆和会话开始时自动状态转储 |
18
+ | 任务和优先级混乱 | 6 阶段工作流:研究 → 计划 → 构建 → 审查 → 发布 → 反思 |
19
+ | 害怕破坏重要内容 | 安全钩子在运行前阻止破坏性命令 |
20
+ | 重复性日常任务 | 34 个现成命令覆盖完整开发周期 |
21
+ | 具有依赖关系的复杂功能 | 并行子代理处理独立任务 |
22
+ | 独立工作缺乏结构 | Roadmap、STATE.md、MAP.md——始终知道你在哪里以及下一步是什么 |
23
+
24
+ ## 如何使用 FRAME
25
+
26
+ ```
27
+ 研究 → 计划 → 构建 → 审查 → 发布 → 反思
28
+ ```
29
+
30
+ 每个会话是一个周期。从 `/frame:daily` 开始,以 `/frame:ship` 结束。
31
+
32
+ **研究** — 构建前先理解
33
+ 运行 `/frame:research <主题>` — Claude 探索代码库、外部资源,并为下一步构建上下文。
34
+
35
+ **计划** — 分解为任务
36
+ `/frame:plan <功能>` 将研究转化为带有估算的具体任务列表。
37
+
38
+ **构建** — 实现
39
+ `/frame:build` 按顺序执行任务(每次 1–3 个),采用 TDD。对于许多独立任务——`/frame:wave` 以并行批次运行它们。卡住了——`/frame:unstuck`。发现 bug——`/frame:debug`。
40
+
41
+ **审查** — 部署前检查
42
+ `/frame:review` 运行自动化检查并提供清单:测试、类型、安全性、性能。
43
+
44
+ **发布** — 部署并记录
45
+ `/frame:ship` 提交,可选推送/PR,并更新项目记忆。
46
+
47
+ **反思** — 学习并改进
48
+ 部署后运行 `/frame:retrospective` 更新指标并捕获未来会话的模式。
49
+
50
+ ## 示例
51
+
52
+ ### 新功能:添加 Google 身份验证
53
+
54
+ ```
55
+ /frame:daily
56
+ # → 查看当前项目状态和计划内容
57
+
58
+ /frame:research "Google OAuth"
59
+ # → Claude 研究代码库:当前身份验证如何工作,
60
+ # 已使用哪些模式,需要添加什么
61
+
62
+ /frame:plan "Google OAuth"
63
+ # → 获取具体任务列表:
64
+ # 1. 配置 Google OAuth 凭据
65
+ # 2. 添加回调路由
66
+ # 3. 连接到会话
67
+ # 4. 在 UI 中添加按钮
68
+
69
+ /frame:checkpoint
70
+ # → 保存还原点——如果出错,可以回滚
71
+
72
+ /frame:wave
73
+ # → 任务 1–4 是独立的,Claude 并行运行它们
74
+
75
+ /frame:review
76
+ # → 自动化检查:测试、类型、安全性
77
+
78
+ /frame:ship
79
+ # → 提交,可选推送/PR,项目记忆已更新
80
+ ```
81
+
82
+ ### Bug:用户在密码重置后无法登录
83
+
84
+ ```
85
+ /frame:daily
86
+ # → 恢复上下文,查看 bug 是否已在计划中或添加它
87
+
88
+ /frame:debug "login after reset"
89
+ # → Claude 系统性检查:日志、重置流程、会话、令牌
90
+ # → 你会得到一个带有代码中具体位置的假设
91
+
92
+ # 如果立即找到原因:
93
+ /frame:checkpoint # 修复前的还原点
94
+ /frame:fast "fix: invalidate old session after password reset"
95
+ # → Claude 进行有针对性的修复,编写回归测试
96
+
97
+ # 如果原因不清楚——深入挖掘:
98
+ /frame:forensics
99
+ # → 分析该区域变更的 git 历史,
100
+ # 找到破坏行为的提交
101
+
102
+ /frame:checkpoint
103
+ /frame:fast "fix: ..." # 修复找到的原因
104
+
105
+ /frame:review
106
+ # → 确认修复没有破坏其他登录场景
107
+
108
+ /frame:ship
109
+ ```
110
+
111
+ ### 改进:加速仪表板加载
112
+
113
+ ```
114
+ /frame:daily
115
+
116
+ /frame:performance
117
+ # → 获取基准:bundle 大小、加载时间、Lighthouse 分数
118
+ # 记住这些数字——最后需要用于比较
119
+
120
+ /frame:research "dashboard performance"
121
+ # → Claude 分析仪表板代码:重型组件,
122
+ # 冗余请求,什么可以缓存或懒加载
123
+
124
+ /frame:plan "dashboard optimization"
125
+ # → 带有影响估算的任务列表:
126
+ # 1. 懒加载重型图表
127
+ # 2. 缓存 API 请求
128
+ # 3. 删除挂载时的重复请求
129
+
130
+ /frame:build
131
+ # → 顺序执行,每个任务都有测试
132
+
133
+ /frame:performance
134
+ # → 与基准比较:查看实际改进
135
+
136
+ /frame:ship
137
+ ```
138
+
139
+ ## 内部包含什么
140
+
141
+ FRAME 提供:
142
+
143
+ - **6 阶段工作流**:研究 → 计划 → 构建 → 审查 → 发布 → 反思
144
+ - **34 个命令**:从快速任务到完整功能开发周期
145
+ - **5 个 AI 代理**:研究员、规划师、构建者、审查员、魔鬼代言人
146
+ - **安全钩子**:阻止破坏性操作,强制执行质量门控
147
+ - **Git 安全**:检查点、回滚、工作树、暂停/恢复
148
+
149
+ ## 前提条件
150
+
151
+ - Node.js >= 18
152
+ - Git(项目必须是 git 仓库)
153
+
154
+ ## 快速开始
155
+
156
+ ```bash
157
+ # 如果需要,初始化 git 仓库
158
+ git init && git commit --allow-empty -m "init"
159
+
160
+ # 安装 FRAME
161
+ npx the-frame-ai init
162
+
163
+ # 在此项目中打开 Claude Code 并运行:
164
+ /frame:init # 扫描代码库,填充 MAP.md
165
+ /frame:daily # 每天的入口点
166
+ ```
167
+
168
+ ## 命令
169
+
170
+ ### 核心——从这里开始
171
+
172
+ 这 7 个命令覆盖了 90% 的独立开发工作:
173
+
174
+ | 命令 | 使用时机 |
175
+ |------|---------|
176
+ | `/frame:daily` | **从这里开始**,任何休息后——完成了什么,下一步是什么 |
177
+ | `/frame:research <主题>` | 在规划新功能之前 |
178
+ | `/frame:plan <功能>` | 将研究转化为可操作的任务列表 |
179
+ | `/frame:build` | 使用 TDD 实现 1–3 个任务(顺序) |
180
+ | `/frame:wave` | 实现 4+ 个独立任务(并行子代理) |
181
+ | `/frame:review` | 部署前——自动化检查 + 清单 |
182
+ | `/frame:ship` | 提交,可选推送/PR,更新记忆 |
183
+
184
+ ### 按阶段的所有命令
185
+
186
+ <details>
187
+ <summary>研究</summary>
188
+
189
+ | 命令 | 使用时机 |
190
+ |------|---------|
191
+ | `/frame:research <主题>` | 在规划新功能之前 |
192
+ | `/frame:explain <文件>` | 为什么这段代码看起来是这样的? |
193
+ | `/frame:why <主题>` | 搜索决策历史 |
194
+ </details>
195
+
196
+ <details>
197
+ <summary>计划</summary>
198
+
199
+ | 命令 | 使用时机 |
200
+ |------|---------|
201
+ | `/frame:plan <功能>` | 将研究转化为可操作的任务列表 |
202
+ | `/frame:add-task` | 在不中断工作的情况下向计划添加任务 |
203
+ </details>
204
+
205
+ <details>
206
+ <summary>构建</summary>
207
+
208
+ | 命令 | 使用时机 |
209
+ |------|---------|
210
+ | `/frame:build` | 使用 TDD 实现计划(1–3 个任务,顺序) |
211
+ | `/frame:wave` | 以并行批次实现 4+ 个独立任务 |
212
+ | `/frame:fast <任务>` | 30 分钟内的快速任务 |
213
+ | `/frame:debug <问题>` | 系统性 bug 调查 |
214
+ | `/frame:forensics` | 深入研究为什么某些东西坏了 |
215
+ | `/frame:refactor` | 使用 TDD 安全网进行重构 |
216
+ | `/frame:migrate` | 带有回滚计划的 DB/API/依赖迁移 |
217
+ </details>
218
+
219
+ <details>
220
+ <summary>审查</summary>
221
+
222
+ | 命令 | 使用时机 |
223
+ |------|---------|
224
+ | `/frame:review` | 部署前——自动化检查 + 清单 |
225
+ | `/frame:health` | 完整项目健康检查 |
226
+ | `/frame:check-deps` | 安全审计 + 过时包 |
227
+ | `/frame:performance` | Bundle 大小和 Lighthouse 审计 |
228
+ </details>
229
+
230
+ <details>
231
+ <summary>发布</summary>
232
+
233
+ | 命令 | 使用时机 |
234
+ |------|---------|
235
+ | `/frame:ship` | 提交,可选推送/PR,更新记忆 |
236
+ | `/frame:checkpoint` | 在风险变更前保存 git 标签 |
237
+ | `/frame:rollback` | 回滚到检查点 |
238
+ </details>
239
+
240
+ <details>
241
+ <summary>反思</summary>
242
+
243
+ | 命令 | 使用时机 |
244
+ |------|---------|
245
+ | `/frame:retrospective` | 部署后——更新记忆和指标 |
246
+ | `/frame:sprint-check` | 每周进度与路线图对比 |
247
+ | `/frame:cleanup-memory` | 修剪和归档过时记忆 |
248
+ </details>
249
+
250
+ <details>
251
+ <summary>日常 & 工具</summary>
252
+
253
+ | 命令 | 使用时机 |
254
+ |------|---------|
255
+ | `/frame:daily` | 一天开始——完成了什么,下一步是什么 |
256
+ | `/frame:status` | 完整状态转储(git、记忆、阻塞项) |
257
+ | `/frame:note` | 捕获模式、决策或反模式 |
258
+ | `/frame:unstuck` | 卡住了?获取 3 个具体的解锁选项 |
259
+ | `/frame:context` | 显示当前工作上下文 |
260
+ | `/frame:init` | 首次运行——扫描代码库,填充 MAP.md |
261
+ | `/frame:doctor` | 验证 FRAME 安装 |
262
+ | `/frame:pause` / `/frame:resume` | 保存和恢复任务中状态 |
263
+ </details>
264
+
265
+ <details>
266
+ <summary>高级</summary>
267
+
268
+ | 命令 | 使用时机 |
269
+ |------|---------|
270
+ | `/frame:worktree` | 用于并行实验的隔离 git 工作树 |
271
+ | `/frame:headless` | 自主 CI 模式(无交互) |
272
+ | `/frame:estimate <任务>` | 开始前的范围和时间估算 |
273
+ </details>
274
+
275
+ ## 钩子
276
+
277
+ FRAME 在 `.claude/hooks/` 中安装 4 个钩子。它们自动运行。
278
+
279
+ | 钩子 | 触发器 | 功能 | 禁用方法 |
280
+ |------|--------|------|---------|
281
+ | `safety-net.sh` | Bash 之前 | 阻止 `rm -rf` 和 `DROP TABLE/DATABASE` | 从 `.claude/settings.local.json` 中删除 |
282
+ | `git-safety.sh` | Bash 之前 | 阻止强制推送、`reset --hard`,警告 `git add -A` | 从 `.claude/settings.local.json` 中删除 |
283
+ | `quality-gate.sh` | 文件写入后 | 对更改的文件运行类型检查 + lint | 从 `.claude/settings.local.json` 中删除 |
284
+ | `session-init.sh` | 会话开始 | 显示当前阶段/任务;离开 > 24h 时完整上下文转储 | 从 `.claude/settings.local.json` 中删除 |
285
+
286
+ ## 配置
287
+
288
+ FRAME 通过 `.frame/config.json` 配置。关键设置:
289
+
290
+ ```json
291
+ {
292
+ "quality": {
293
+ "commands": {
294
+ "typecheck": "npx tsc --noEmit",
295
+ "test": "npx vitest run",
296
+ "lint": "npx eslint .",
297
+ "build": "npm run build"
298
+ }
299
+ }
300
+ }
301
+ ```
302
+
303
+ ## CLI
304
+
305
+ ```bash
306
+ npx the-frame-ai init [target-dir] # 安装 FRAME
307
+ npx the-frame-ai update [target-dir] # 更新命令、代理、钩子
308
+ npx the-frame-ai doctor [target-dir] # 检查安装健康状况
309
+ npx the-frame-ai version # 显示 CLI 版本
310
+ ```
311
+
312
+ `update` 只更新命令、代理和钩子。项目文件(STATE.md、MAP.md、memory/ 等)永远不会被覆盖。
313
+
314
+ ## 安装后的项目结构
315
+
316
+ ```
317
+ .claude/
318
+ commands/ # 34 个 FRAME 命令
319
+ agents/ # 5 个 AI 代理
320
+ hooks/ # 4 个安全钩子
321
+ .frame/
322
+ config.json # FRAME 配置
323
+ .planning/
324
+ STATE.md # 当前位置
325
+ MAP.md # 项目地图
326
+ ROADMAP.md # 路线图
327
+ memory/ # 项目记忆
328
+ specs/ # 功能规格
329
+ reviews/ # 审查结果
330
+ reports/ # 报告(日常、依赖、质量、冲刺)
331
+ ```
332
+
333
+ ## 许可证
334
+
335
+ MIT
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "the-frame-ai",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "FRAME — Framework for AI-Assisted Solo Development",
5
5
  "type": "module",
6
6
  "bin": {
7
- "the-frame-ai": "./bin/the-frame-ai"
7
+ "the-frame-ai": "bin/the-frame-ai"
8
8
  },
9
9
  "files": [
10
10
  "bin/",
@@ -22,7 +22,7 @@
22
22
  "license": "MIT",
23
23
  "repository": {
24
24
  "type": "git",
25
- "url": "https://github.com/andrey-chmerev/the-frame-ai.git"
25
+ "url": "git+https://github.com/andrey-chmerev/the-frame-ai.git"
26
26
  },
27
27
  "homepage": "https://github.com/andrey-chmerev/the-frame-ai#readme",
28
28
  "engines": {
package/src/cli.js CHANGED
@@ -17,6 +17,7 @@ Usage:
17
17
  Options:
18
18
  --lang <code> Set response language (e.g. en, ru, zh). Overrides FRAME_LANG env var.
19
19
  --dry-run (update only) Show what would be updated without making changes.
20
+ --copilot (update only) Enable GitHub Copilot Chat support (adds .vscode/*.prompt.md).
20
21
 
21
22
  Examples:
22
23
  npx the-frame init Install in current directory
@@ -24,11 +25,12 @@ Examples:
24
25
  npx the-frame init --lang ru Install with Russian language preset
25
26
  npx the-frame update Update in current directory
26
27
  npx the-frame update --dry-run Preview update without applying
28
+ npx the-frame update --copilot Enable Copilot Chat support on existing install
27
29
  npx the-frame doctor Check health in current directory
28
30
  `;
29
31
 
30
32
  function parseFlags(args) {
31
- const flags = { lang: null, dryRun: false, yes: false };
33
+ const flags = { lang: null, dryRun: false, yes: false, copilot: false };
32
34
  const rest = [];
33
35
  for (let i = 0; i < args.length; i++) {
34
36
  if (args[i] === '--lang' && args[i + 1]) {
@@ -37,6 +39,8 @@ function parseFlags(args) {
37
39
  flags.dryRun = true;
38
40
  } else if (args[i] === '--yes' || args[i] === '-y') {
39
41
  flags.yes = true;
42
+ } else if (args[i] === '--copilot') {
43
+ flags.copilot = true;
40
44
  } else {
41
45
  rest.push(args[i]);
42
46
  }
package/src/init.js CHANGED
@@ -9,8 +9,9 @@ import {
9
9
  listFilesRecursive,
10
10
  writeFile,
11
11
  applyVars,
12
+ mergeVscodeSettings,
12
13
  } from './utils.js';
13
- import { LANGUAGES, getLanguageInstruction, promptLanguage, promptConfig } from './languages.js';
14
+ import { LANGUAGES, getLanguageInstruction, promptLanguage, promptConfig, promptCopilot } from './languages.js';
14
15
  import { doctor } from './doctor.js';
15
16
 
16
17
  const PLANNING_DIRS = [
@@ -84,6 +85,18 @@ export async function init(target, flags = {}) {
84
85
  const commandCount = readdirSync(commandsSrc).filter((f) => f.endsWith('.md')).length;
85
86
  logSuccess(`${commandCount} commands → .claude/commands/`);
86
87
 
88
+ // 2b. Copilot Chat support
89
+ const copilot = await promptCopilot(flags.yes);
90
+ if (copilot) {
91
+ const vscodeDest = join(target, '.vscode');
92
+ ensureDir(vscodeDest);
93
+ for (const f of readdirSync(commandsDest).filter((f) => f.endsWith('.md'))) {
94
+ writeFile(join(vscodeDest, f.replace(/\.md$/, '.prompt.md')), readFileSync(join(commandsDest, f), 'utf-8'));
95
+ }
96
+ mergeVscodeSettings(join(vscodeDest, 'settings.json'));
97
+ logSuccess(`${commandCount} Copilot prompts → .vscode/`);
98
+ }
99
+
87
100
  // 3. Copy agents and apply quality.commands substitution
88
101
  const agentsSrc = join(TEMPLATES_DIR, 'agents');
89
102
  const agentsDest = join(target, '.claude', 'agents');
@@ -147,6 +160,7 @@ export async function init(target, flags = {}) {
147
160
  const configPath = join(target, '.frame', 'config.json');
148
161
  if (fileExists(configPath)) {
149
162
  resolvedConfig.language = language;
163
+ resolvedConfig.copilot = copilot;
150
164
  writeFile(configPath, JSON.stringify(resolvedConfig, null, 2));
151
165
  }
152
166
 
@@ -167,12 +181,16 @@ export async function init(target, flags = {}) {
167
181
  log(` Hooks: ${hookFiles.length} in .claude/hooks/`);
168
182
  log(` Planning: files in .planning/`);
169
183
  log(` Config: .frame/config.json`);
184
+ if (copilot) log(` Copilot: ${commandCount} prompts in .vscode/`);
170
185
  log('');
171
186
 
172
187
  // 11. Auto-run doctor
173
188
  log('\n--- Проверка установки ---');
174
189
  await doctor(target);
175
190
 
176
- log(' Next step: open Claude Code and run `/frame:daily`');
191
+ log(' Next steps:');
192
+ log(' 1. Open Claude Code in this project');
193
+ log(' 2. Run `/frame:init` — scans codebase, fills MAP.md');
194
+ log(' 3. Run `/frame:daily` — your entry point every day');
177
195
  log('');
178
196
  }
package/src/languages.js CHANGED
@@ -139,3 +139,14 @@ export async function promptConfig(defaultConfig, yes = false) {
139
139
  rl.close();
140
140
  return config;
141
141
  }
142
+
143
+ export async function promptCopilot(yes = false) {
144
+ if (!process.stdin.isTTY || yes) return false;
145
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
146
+ return new Promise((resolve) => {
147
+ rl.question('\n? Add GitHub Copilot Chat support? (y/N): ', (answer) => {
148
+ rl.close();
149
+ resolve(answer.trim().toLowerCase() === 'y');
150
+ });
151
+ });
152
+ }
package/src/update.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { join } from 'node:path';
2
2
  import { readdirSync, writeFileSync, readFileSync } from 'node:fs';
3
3
  import { TEMPLATES_DIR, VERSION, log, logSuccess } from './manifest.js';
4
- import { copyDir, makeExecutable, fileExists, applyVars, writeFile } from './utils.js';
4
+ import { copyDir, makeExecutable, fileExists, applyVars, writeFile, ensureDir, mergeVscodeSettings } from './utils.js';
5
5
 
6
6
 
7
7
  export async function update(target, flags = {}) {
@@ -17,6 +17,12 @@ export async function update(target, flags = {}) {
17
17
  installedVersion = readFileSync(versionPath, 'utf-8').trim();
18
18
  }
19
19
 
20
+ const config = JSON.parse(readFileSync(join(target, '.frame', 'config.json'), 'utf-8'));
21
+ const vars = { PROJECT_NAME: config.project ?? '', LANGUAGE: config.language ?? '' };
22
+ const qualityVars = Object.fromEntries(
23
+ Object.entries(config.quality?.commands ?? {}).map(([k, v]) => [`quality.commands.${k}`, v])
24
+ );
25
+
20
26
  if (flags.dryRun) {
21
27
  log(`\nFRAME dry-run: ${installedVersion} → ${VERSION}\n`);
22
28
  log('Files that would be updated:');
@@ -32,6 +38,11 @@ export async function update(target, flags = {}) {
32
38
  files.forEach((f) => log(` ~ ${label}${f}`));
33
39
  total += files.length;
34
40
  }
41
+ if (config.copilot || flags.copilot) {
42
+ const files = readdirSync(join(TEMPLATES_DIR, 'commands')).filter((f) => f.endsWith('.md'));
43
+ files.forEach((f) => log(` ~ .vscode/${f.replace(/\.md$/, '.prompt.md')}`));
44
+ total += files.length;
45
+ }
35
46
  log(`\n Note: project files (STATE.md, MAP.md, memory/, etc.) are never updated`);
36
47
  log(`\nTotal: ${total} files would be updated. Run without --dry-run to apply.\n`);
37
48
  return;
@@ -39,13 +50,6 @@ export async function update(target, flags = {}) {
39
50
 
40
51
  log(`\nFRAME update: ${installedVersion} → ${VERSION}\n`);
41
52
 
42
- // Read project config for variable substitution
43
- const config = JSON.parse(readFileSync(join(target, '.frame', 'config.json'), 'utf-8'));
44
- const vars = { PROJECT_NAME: config.project ?? '', LANGUAGE: config.language ?? '' };
45
- const qualityVars = Object.fromEntries(
46
- Object.entries(config.quality?.commands ?? {}).map(([k, v]) => [`quality.commands.${k}`, v])
47
- );
48
-
49
53
  let updated = 0;
50
54
 
51
55
  // 1. Update commands
@@ -78,7 +82,22 @@ export async function update(target, flags = {}) {
78
82
  }
79
83
  updated += hookFiles.length;
80
84
 
81
- // 4. Write new version
85
+ // 4. Update Copilot prompts
86
+ if (config.copilot || flags.copilot) {
87
+ const vscodeDest = join(target, '.vscode');
88
+ ensureDir(vscodeDest);
89
+ for (const f of readdirSync(commandsDest).filter((f) => f.endsWith('.md'))) {
90
+ writeFile(join(vscodeDest, f.replace(/\.md$/, '.prompt.md')), readFileSync(join(commandsDest, f), 'utf-8'));
91
+ }
92
+ mergeVscodeSettings(join(vscodeDest, 'settings.json'));
93
+ updated += readdirSync(commandsDest).filter((f) => f.endsWith('.md')).length;
94
+ if (flags.copilot && !config.copilot) {
95
+ config.copilot = true;
96
+ writeFileSync(join(target, '.frame', 'config.json'), JSON.stringify(config, null, 2), 'utf-8');
97
+ }
98
+ }
99
+
100
+ // 5. Write new version
82
101
  writeFileSync(join(target, '.frame', '.frame-version'), VERSION, 'utf-8');
83
102
 
84
103
  logSuccess(`Updated: ${updated} framework files`);
package/src/utils.js CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  writeFileSync,
8
8
  chmodSync,
9
9
  } from 'node:fs';
10
+
10
11
  import { join } from 'node:path';
11
12
 
12
13
  export function ensureDir(dir) {
@@ -53,3 +54,12 @@ export function listFilesRecursive(dir) {
53
54
  export function fileExists(path) {
54
55
  return existsSync(path);
55
56
  }
57
+
58
+ export function mergeVscodeSettings(settingsPath) {
59
+ let settings = {};
60
+ if (existsSync(settingsPath)) {
61
+ try { settings = JSON.parse(readFileSync(settingsPath, 'utf-8')); } catch {}
62
+ }
63
+ settings['chat.promptFiles'] = true;
64
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf-8');
65
+ }