@miphamai/cli 0.66.0 → 0.69.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.
@@ -0,0 +1,102 @@
1
+ /**
2
+ * PostFlightChecker — 事后检查器(Recuris C 组件)。
3
+ *
4
+ * Recuris M=(E,W,ρ,C) 的 C:检查器。核心原则「调用技能/尝试工具 ≠ 完成证据;
5
+ * 只有工具/env 的观察结果支撑才算」。`PreFlightChecker` 是事前拦截(ErrorSignatureDB
6
+ * + RuleEngine),本模块是事后验证:把「完成谓词 (observation) => boolean」抽象出来,
7
+ * 对工具结果核对,决策写进会话轨迹(供 ① 组件归因 + eval 打分)。
8
+ *
9
+ * 设计约束:
10
+ * - 默认 no-checker 静默、rejected 只记录不阻塞(第一阶段只产证据,不强制拦截)。
11
+ * - 确定性、无 LLM、可单测。
12
+ */
13
+
14
+ import { existsSync, readFileSync, statSync } from 'node:fs'
15
+ import type { ToolResult } from '../shared/types'
16
+
17
+ /** 工具事后观察:工具实际用的参数 + 工具返回结果。 */
18
+ export interface ToolObservation {
19
+ params: Record<string, unknown>
20
+ result: ToolResult
21
+ }
22
+
23
+ export type CheckerDecision =
24
+ | { verdict: 'supported'; checkerId: string }
25
+ | { verdict: 'rejected'; checkerId: string; reason: string }
26
+ | { verdict: 'no-checker' }
27
+
28
+ /** 完成谓词:工具/env 观察是否支撑「该变更已生效」。绝不信任模型自称成功。 */
29
+ export type Checker = (observation: ToolObservation) => boolean
30
+
31
+ export class PostFlightChecker {
32
+ private checkers = new Map<string, { id: string; predicate: Checker }>()
33
+
34
+ register(checkerId: string, toolName: string, predicate: Checker): void {
35
+ this.checkers.set(toolName, { id: checkerId, predicate })
36
+ }
37
+
38
+ /** 事后核对一次工具结果。无匹配 checker 时返回 no-checker(不阻塞)。 */
39
+ check(toolName: string, observation: ToolObservation): CheckerDecision {
40
+ const entry = this.checkers.get(toolName)
41
+ if (!entry) return { verdict: 'no-checker' }
42
+ try {
43
+ return entry.predicate(observation)
44
+ ? { verdict: 'supported', checkerId: entry.id }
45
+ : {
46
+ verdict: 'rejected',
47
+ checkerId: entry.id,
48
+ reason: `post-condition failed (${entry.id})`,
49
+ }
50
+ } catch {
51
+ return { verdict: 'rejected', checkerId: entry.id, reason: `checker threw (${entry.id})` }
52
+ }
53
+ }
54
+ }
55
+
56
+ // ── 首批 checker(最小、确定性、可测) ──
57
+
58
+ /** Bash → exit code 0(对齐 detectViolations 语义,不重复实现)。 */
59
+ function bashExit(o: ToolObservation): boolean {
60
+ return o.result.success === true
61
+ }
62
+
63
+ /** Write → 文件存在且长度一致。 */
64
+ function writeExists(o: ToolObservation): boolean {
65
+ if (!o.result.success) return false
66
+ const filePath = String(o.params.file_path ?? '')
67
+ if (!filePath) return false
68
+ try {
69
+ if (!existsSync(filePath)) return false
70
+ const expected = Buffer.byteLength(String(o.params.content ?? ''), 'utf-8')
71
+ return statSync(filePath).size === expected
72
+ } catch {
73
+ return false
74
+ }
75
+ }
76
+
77
+ /** Edit → 工具返回 applied 且 new_string 已生效(退化为「old_string 无残留」)。 */
78
+ function editApplied(o: ToolObservation): boolean {
79
+ if (!o.result.success) return false
80
+ const filePath = String(o.params.file_path ?? '')
81
+ const newString = String(o.params.new_string ?? '')
82
+ const oldString = String(o.params.old_string ?? '')
83
+ if (!filePath) return false
84
+ try {
85
+ if (!existsSync(filePath)) return false
86
+ const text = readFileSync(filePath, 'utf-8')
87
+ if (newString) return text.includes(newString)
88
+ if (oldString) return !text.includes(oldString)
89
+ return true
90
+ } catch {
91
+ return false
92
+ }
93
+ }
94
+
95
+ /** 默认 checker:Bash/Write/Edit 三件套(工具作用域后置条件)。 */
96
+ export function createDefaultPostFlightChecker(): PostFlightChecker {
97
+ const c = new PostFlightChecker()
98
+ c.register('bash-exit', 'Bash', bashExit)
99
+ c.register('write-exists', 'Write', writeExists)
100
+ c.register('edit-applied', 'Edit', editApplied)
101
+ return c
102
+ }
@@ -1,8 +1,14 @@
1
1
  /**
2
2
  * Mipham Code — Project Scaffold
3
3
  *
4
- * `mipham init` 生成规范的项目文档(CLAUDE.md + MIPHAM.md + README.md),
5
- * 避免用户「冷建立文件」。模板遵循 One Mipham Corporation 规范。
4
+ * `mipham init` 生成规范的项目文档,避免用户「冷建立文件」。
5
+ *
6
+ * 分级:
7
+ * - 基础(默认):CLAUDE.md(简版)+ MIPHAM.md + README.md
8
+ * - 完整(--full):八章 CLAUDE.md + SECURITY/CONTRIBUTING/CODE_OF_CONDUCT/
9
+ * DEVELOPMENT/TRADEMARKS/CHANGELOG/LICENSE + .github 四件套
10
+ *
11
+ * 模板遵循 One Mipham Corporation 规范。
6
12
  */
7
13
  import { existsSync, mkdirSync, writeFileSync, readdirSync } from 'node:fs'
8
14
  import { join, basename } from 'node:path'
@@ -14,6 +20,23 @@ export interface ScaffoldResult {
14
20
  gitInitialized: boolean
15
21
  }
16
22
 
23
+ export type LicenseType = 'proprietary' | 'mit' | 'apache'
24
+
25
+ export interface ScaffoldOptions {
26
+ /** 是否执行 git init(默认 false,由 CLI 传入 true) */
27
+ gitInit?: boolean
28
+ /** 完整脚手架(生成完整 .md 体系 + .github 模板) */
29
+ full?: boolean
30
+ /** 许可证类型,默认 proprietary */
31
+ license?: LicenseType
32
+ }
33
+
34
+ const COPYRIGHT = '© 2026 One Mipham Corporation(北京华安麦逄科技有限公司)— All Rights Reserved.'
35
+
36
+ // ─────────────────────────────────────────────────────────────────────────────
37
+ // 基础模板(mipham init)
38
+ // ─────────────────────────────────────────────────────────────────────────────
39
+
17
40
  export function renderMiphamMd(projectName: string): string {
18
41
  return `---
19
42
  model: mipham-code
@@ -111,6 +134,405 @@ export function renderReadmeMd(projectName: string): string {
111
134
  `
112
135
  }
113
136
 
137
+ // ─────────────────────────────────────────────────────────────────────────────
138
+ // 完整模板(mipham init --full)
139
+ // ─────────────────────────────────────────────────────────────────────────────
140
+
141
+ export function renderFullClaudeMd(projectName: string): string {
142
+ return `# CLAUDE.md
143
+
144
+ > **项目**: ${projectName}
145
+ > **版本**: 0.1.0
146
+ > **初始化**: \`mipham init --full\`
147
+ > **公司**: One Mipham Corporation | 品牌: MiphamAI
148
+ > **维护人**: One Mipham Corporation 技术委员会
149
+ > **审核周期**: 每季度复审一次
150
+
151
+ This file provides guidance to Claude Code when working with code in this repository.
152
+
153
+ ---
154
+
155
+ ## 一、项目概述
156
+
157
+ [简要描述项目目的和定位]
158
+
159
+ | 模块 | 目录 | 框架 | 语言 |
160
+ |------|------|------|------|
161
+ | [模块名] | \`[目录]\` | [框架] | [语言] |
162
+
163
+ ## 二、AI 编码协作原则
164
+
165
+ **原则 1: 编码前先思考 — Think Before Coding**
166
+ - 不确定时必须提问,不得自行假设;存在多种解读时呈现所有选项
167
+ - 有更简单方案时必须指出;有理由时应推回不合理需求
168
+
169
+ **原则 2: 简洁优先 — Simplicity First**
170
+ - 只写解决问题所需的最小代码,不写未要求的功能
171
+ - 不添加未被要求的"灵活性"或"可配置性"
172
+
173
+ **原则 3: 精准修改 — Surgical Changes**
174
+ - 只改被要求修改的内容;匹配现有代码风格
175
+ - 发现无关 dead code 时只提出来,不自行删除
176
+
177
+ **原则 4: 目标驱动执行 — Goal-Driven Execution**
178
+ - 将任务转化为可验证的成功标准;多步骤任务先陈述简要计划
179
+
180
+ ## 三、合规与安全(强制性)
181
+
182
+ - 用户数据:传输层 TLS 1.3,存储层 AES-256-GCM(母公司底线)
183
+ - 禁止在代码、日志、配置文件或提交历史中硬编码凭据、API 密钥、令牌
184
+ - PII 脱敏后进入开发/测试环境
185
+ - 面向用户的 AI 功能上线前通过 prompt injection 与对抗攻击测试
186
+
187
+ ## 四、代码质量标准
188
+
189
+ - 配置自动化 lint + 格式化工具,通过 CI 强制执行
190
+ - 新代码通过测试后合并;至少一名资深工程师 review
191
+ - 禁止直接提交主分支:feature branch + PR 流程
192
+ - 提交信息遵循 [Conventional Commits](https://www.conventionalcommits.org/)
193
+
194
+ ## 五、技术架构原则
195
+
196
+ - 服务间通信通过定义良好的 API,禁止跨服务直接数据库访问
197
+ - 关键业务路径可观测性:结构化日志 + 指标 + 追踪
198
+ - 基础设施即代码(IaC)
199
+
200
+ ## 六、项目结构约定
201
+
202
+ \`\`\`
203
+ ${projectName}/
204
+ ├── CLAUDE.md # AI 编码规范
205
+ ├── SECURITY.md # 安全策略
206
+ ├── README.md # 项目说明
207
+ ├── LICENSE # 许可证
208
+ ├── CHANGELOG.md # 版本变更日志
209
+ ├── .github/ # PR/Issue 模板 + CODEOWNERS
210
+ └── src/ # [源代码目录]
211
+ \`\`\`
212
+
213
+ ## 七、技术决策框架
214
+
215
+ 按优先级评估技术选型:成熟度与社区支持 → 安全合规 → 团队能力匹配 → 技术栈互操作性 → 许可证与供应商风险。
216
+
217
+ ## 八、代码评审检查清单
218
+
219
+ - [ ] 无硬编码凭据、密钥或 Token
220
+ - [ ] 敏感数据已加密/脱敏
221
+ - [ ] 新功能有对应测试
222
+ - [ ] 提交信息符合 Conventional Commits
223
+
224
+ ---
225
+
226
+ ### 修订历史
227
+
228
+ | 版本 | 日期 | 变更内容 | 维护人 |
229
+ |------|------|---------|--------|
230
+ | 0.1.0 | 2026-08-30 | \`mipham init --full\` 初始化 | 技术委员会 |
231
+
232
+ ---
233
+
234
+ > **版权**: ${COPYRIGHT}
235
+ `
236
+ }
237
+
238
+ export function renderSecurityMd(projectName: string): string {
239
+ return `# Security Policy — ${projectName}
240
+
241
+ ## 加密要求
242
+
243
+ - 传输层 TLS 1.3,存储层 AES-256-GCM(母公司底线)
244
+ - 禁止在代码、日志、配置或提交历史中硬编码凭据、API 密钥、令牌
245
+
246
+ ## 依赖安全
247
+
248
+ - 第三方依赖引入前通过许可证合规检查(严禁 copyleft/GPL)
249
+ - 定期升级依赖,响应 Dependabot 告警
250
+
251
+ ## AI 安全
252
+
253
+ - 面向用户的 AI 功能上线前通过 prompt injection 测试、对抗攻击红队评估
254
+ - LLM System Prompt 版本管理,变更记录原因和审批人
255
+
256
+ ## 报告漏洞
257
+
258
+ 安全漏洞请勿公开提交 issue,私密报告至维护人(见 README)。
259
+ `
260
+ }
261
+
262
+ export function renderContributingMd(projectName: string, license: LicenseType): string {
263
+ const isOpen = license !== 'proprietary'
264
+ const header = isOpen
265
+ ? `# Contributing to ${projectName}
266
+
267
+ 感谢你对 **${projectName}** 的关注。本项目采用 **${license === 'apache' ? 'Apache 2.0' : 'MIT'}** 开源许可。
268
+ `
269
+ : `# Contributing to ${projectName}
270
+
271
+ **${projectName} 是专有闭源商业软件**(见 LICENSE)。本文档仅面向**内部团队成员和授权贡献者**,不接受外部 PR。
272
+ `
273
+
274
+ return `${header}
275
+ ## 分支与提交
276
+
277
+ - 分支命名:\`feat/xxx\`、\`fix/xxx\`、\`docs/xxx\`、\`chore/xxx\`
278
+ - 提交信息遵循 [Conventional Commits](https://www.conventionalcommits.org/)
279
+ - \`main\` 受保护,所有变更走 PR + 至少一名资深工程师 review
280
+
281
+ ## Pull Request 指南
282
+
283
+ 请说明:
284
+ - 改了什么、为什么
285
+ - 如何测试
286
+ - UI 变更附截图
287
+ - 涉及环境变量或数据库迁移时,说明兼容性影响
288
+
289
+ ## 安全
290
+
291
+ - 禁止硬编码凭据、密钥或 Token
292
+ - 安全漏洞按 SECURITY.md 渠道私密报告
293
+
294
+ ## 许可证
295
+
296
+ ${isOpen ? `贡献将被纳入项目许可证之下(见 LICENSE)。` : '未经书面授权,禁止复制、修改、分发或使用(见 LICENSE)。'}
297
+ `
298
+ }
299
+
300
+ export function renderCodeOfConductMd(projectName: string): string {
301
+ return `# Code of Conduct — ${projectName}
302
+
303
+ ## 期望行为
304
+
305
+ - 清晰、尊重地沟通
306
+ - 聚焦想法、代码与设计,而非个人
307
+ - 除非确证,否则假设他人善意
308
+ - 保持讨论相关且有建设性
309
+
310
+ ## 不可接受的行为
311
+
312
+ - 任何形式的骚扰、歧视或恐吓
313
+ - 人身攻击、侮辱或贬损性言论
314
+ - 未经许可发布他人隐私信息
315
+
316
+ ## 举报
317
+
318
+ 如遇违反本准则的行为,通过 README.md 中的渠道联系维护者。所有举报严肃、保密处理。
319
+ `
320
+ }
321
+
322
+ export function renderDevelopmentMd(projectName: string): string {
323
+ return `# ${projectName} — 开发指南
324
+
325
+ ## 前置条件
326
+
327
+ | 工具 | 版本 | 说明 |
328
+ |------|------|------|
329
+ | [工具] | [版本] | [说明] |
330
+
331
+ ## 快速开始
332
+
333
+ \`\`\`bash
334
+ # 1. 安装依赖
335
+ # 2. 配置环境
336
+ # 3. 运行
337
+ \`\`\`
338
+
339
+ ## 常用命令
340
+
341
+ \`\`\`bash
342
+ # 构建 / 测试 / lint
343
+ \`\`\`
344
+
345
+ ## 环境变量
346
+
347
+ | 变量 | 必填 | 说明 |
348
+ |------|------|------|
349
+ | [变量名] | [是/否] | [说明] |
350
+
351
+ ## 测试
352
+
353
+ \`\`\`bash
354
+ # 运行测试
355
+ \`\`\`
356
+ `
357
+ }
358
+
359
+ export function renderTrademarksMd(projectName: string): string {
360
+ return `# ${projectName} 商标与品牌政策
361
+
362
+ 本文件规范 **${projectName}** 商标与品牌资产的使用(名称、Logo、视觉识别)。独立于代码许可证。
363
+
364
+ > 说明:本政策仅为清晰起见,不构成法律意见。
365
+
366
+ ## 允许的使用
367
+
368
+ - 讨论官方未修改项目时如实提及"${projectName}"
369
+ - 用名称链接到本仓库
370
+
371
+ ## 禁止的使用(未经书面许可)
372
+
373
+ - 以暗示背书、赞助或官方身份的方式使用商标
374
+ - 修改、重绘、裁剪 Logo 或衍生品牌资产
375
+ - 注册或使用易混淆的名称 / 域名 / 社交账号
376
+
377
+ ## 商业许可与授权
378
+
379
+ 如需白标、OEM、企业部署,联系:\`legal@onemipham.com\`
380
+ `
381
+ }
382
+
383
+ export function renderChangelogMd(projectName: string): string {
384
+ return `# Changelog
385
+
386
+ All notable changes to ${projectName} will be documented in this file.
387
+
388
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
389
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
390
+
391
+ ## [0.1.0] — 2026-08-30
392
+
393
+ ### Added
394
+ - 初始版本(\`mipham init --full\` 脚手架)
395
+ `
396
+ }
397
+
398
+ export function renderLicenseMd(license: LicenseType): string {
399
+ if (license === 'mit') {
400
+ return `MIT License
401
+
402
+ Copyright (c) 2026 One Mipham Corporation(北京华安麦逄科技有限公司)
403
+
404
+ Permission is hereby granted, free of charge, to any person obtaining a copy
405
+ of this software and associated documentation files (the "Software"), to deal
406
+ in the Software without restriction, including without limitation the rights
407
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
408
+ copies of the Software, and to permit persons to whom the Software is
409
+ furnished to do so, subject to the following conditions:
410
+
411
+ The above copyright notice and this permission notice shall be included in all
412
+ copies or substantial portions of the Software.
413
+
414
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
415
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
416
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
417
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
418
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
419
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
420
+ SOFTWARE.
421
+ `
422
+ }
423
+ if (license === 'apache') {
424
+ return `Apache License 2.0
425
+
426
+ Copyright (c) 2026 One Mipham Corporation(北京华安麦逄科技有限公司)
427
+
428
+ Licensed under the Apache License, Version 2.0 (the "License");
429
+ you may not use this file except in compliance with the License.
430
+ You may obtain a copy of the License at:
431
+
432
+ http://www.apache.org/licenses/LICENSE-2.0
433
+
434
+ Unless required by applicable law or agreed to in writing, software
435
+ distributed under the License is distributed on an "AS IS" BASIS,
436
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
437
+ See the License for the specific language governing permissions and
438
+ limitations under the License.
439
+ `
440
+ }
441
+ return `${projectLicenseProprietary()}
442
+ `
443
+ }
444
+
445
+ function projectLicenseProprietary(): string {
446
+ return `Copyright (c) 2026 One Mipham Corporation(北京华安麦逄科技有限公司)
447
+ All rights reserved.
448
+
449
+ Proprietary Software — Closed Source Commercial Software
450
+
451
+ This software and its source code are the proprietary property of
452
+ One Mipham Corporation. Reproduction, modification, distribution,
453
+ or use of this software in any form is prohibited without explicit
454
+ written authorization.
455
+ `
456
+ }
457
+
458
+ export function renderPullRequestTemplate(): string {
459
+ return `## 变更说明
460
+ <!-- 改了什么、为什么 -->
461
+
462
+ ## 变更类型
463
+ - [ ] feat 新功能
464
+ - [ ] fix 修复
465
+ - [ ] docs 文档
466
+ - [ ] chore 维护
467
+
468
+ ## 如何测试
469
+ <!-- 验证步骤与命令 -->
470
+
471
+ ## 截图
472
+ <!-- UI 变更附截图 -->
473
+
474
+ ## 兼容性影响
475
+ <!-- 环境变量、数据库迁移或破坏性变更 -->
476
+ `
477
+ }
478
+
479
+ export function renderBugReportTemplate(): string {
480
+ return `---
481
+ name: Bug 报告
482
+ about: 报告一个 bug
483
+ title: "[Bug] "
484
+ labels: bug
485
+ assignees: ""
486
+ ---
487
+
488
+ ## 描述
489
+ <!-- 清晰描述 bug -->
490
+
491
+ ## 复现步骤
492
+ 1.
493
+ 2.
494
+ 3.
495
+
496
+ ## 期望行为
497
+
498
+ ## 实际行为
499
+
500
+ ## 环境
501
+ - 平台 / 系统:
502
+ - 版本:
503
+ - 日志 / 截图:
504
+ `
505
+ }
506
+
507
+ export function renderFeatureRequestTemplate(): string {
508
+ return `---
509
+ name: 功能请求
510
+ about: 建议一个新功能
511
+ title: "[Feature] "
512
+ labels: enhancement
513
+ assignees: ""
514
+ ---
515
+
516
+ ## 问题背景
517
+ <!-- 这个功能解决什么问题 -->
518
+
519
+ ## 期望方案
520
+ <!-- 描述你期望的功能 -->
521
+
522
+ ## 备选方案
523
+ <!-- 考虑过的其他方案 -->
524
+ `
525
+ }
526
+
527
+ export function renderCodeowners(owner: string): string {
528
+ return `* @${owner.replace(/^@/, '')}
529
+ `
530
+ }
531
+
532
+ // ─────────────────────────────────────────────────────────────────────────────
533
+ // 脚手架
534
+ // ─────────────────────────────────────────────────────────────────────────────
535
+
114
536
  /** 检测目录是否为「愣建文件夹」——无任何条目(忽略 .DS_Store)。目录不存在则视为非空。 */
115
537
  export function isEmptyProject(dir: string): boolean {
116
538
  try {
@@ -121,16 +543,45 @@ export function isEmptyProject(dir: string): boolean {
121
543
  }
122
544
  }
123
545
 
124
- export function scaffoldProject(targetDir: string, opts?: { gitInit?: boolean }): ScaffoldResult {
125
- mkdirSync(targetDir, { recursive: true })
546
+ interface FileSpec {
547
+ path: string
548
+ content: string
549
+ }
126
550
 
127
- const name = basename(targetDir) || 'my-project'
128
- const files = [
129
- { path: 'CLAUDE.md', content: renderClaudeMd(name) },
551
+ function buildFileSpecs(name: string, opts?: ScaffoldOptions): FileSpec[] {
552
+ const full = opts?.full === true
553
+ const license: LicenseType = opts?.license ?? 'proprietary'
554
+
555
+ const specs: FileSpec[] = [
556
+ { path: 'CLAUDE.md', content: full ? renderFullClaudeMd(name) : renderClaudeMd(name) },
130
557
  { path: 'MIPHAM.md', content: renderMiphamMd(name) },
131
558
  { path: 'README.md', content: renderReadmeMd(name) },
132
559
  ]
133
560
 
561
+ if (!full) return specs
562
+
563
+ return [
564
+ ...specs,
565
+ { path: 'SECURITY.md', content: renderSecurityMd(name) },
566
+ { path: 'CONTRIBUTING.md', content: renderContributingMd(name, license) },
567
+ { path: 'CODE_OF_CONDUCT.md', content: renderCodeOfConductMd(name) },
568
+ { path: 'DEVELOPMENT.md', content: renderDevelopmentMd(name) },
569
+ { path: 'TRADEMARKS.md', content: renderTrademarksMd(name) },
570
+ { path: 'CHANGELOG.md', content: renderChangelogMd(name) },
571
+ { path: 'LICENSE', content: renderLicenseMd(license) },
572
+ { path: '.github/pull_request_template.md', content: renderPullRequestTemplate() },
573
+ { path: '.github/ISSUE_TEMPLATE/bug_report.md', content: renderBugReportTemplate() },
574
+ { path: '.github/ISSUE_TEMPLATE/feature_request.md', content: renderFeatureRequestTemplate() },
575
+ { path: '.github/CODEOWNERS', content: renderCodeowners('sarvadaya') },
576
+ ]
577
+ }
578
+
579
+ export function scaffoldProject(targetDir: string, opts?: ScaffoldOptions): ScaffoldResult {
580
+ mkdirSync(targetDir, { recursive: true })
581
+
582
+ const name = basename(targetDir) || 'my-project'
583
+ const files = buildFileSpecs(name, opts)
584
+
134
585
  const created: string[] = []
135
586
  const skipped: string[] = []
136
587
 
@@ -139,6 +590,7 @@ export function scaffoldProject(targetDir: string, opts?: { gitInit?: boolean })
139
590
  if (existsSync(full)) {
140
591
  skipped.push(f.path)
141
592
  } else {
593
+ mkdirSync(join(full, '..'), { recursive: true })
142
594
  writeFileSync(full, f.content, 'utf-8')
143
595
  created.push(f.path)
144
596
  }
@@ -2,7 +2,7 @@
2
2
  // 统一「给一个 policy 打分」:机制哨兵(runEval)与任务表现(runTaskPerformance)
3
3
  // 都 conform 成 RewardFn,自改进环的 verify 阶段可对任意奖励源比分数、判退化。
4
4
  import type { Llm } from '../providers/llm'
5
- import { runEval } from './eval-harness'
5
+ import { runEval, type EvalResult } from './eval-harness'
6
6
  import { runTaskPerformance } from './task-performance'
7
7
 
8
8
  /** 奖励函数统一输出的「分数」形状——所有 RewardFn 的 evaluate 都产出它。 */
@@ -11,6 +11,8 @@ export interface ScoreReport {
11
11
  passed: number
12
12
  score: number // 0-100
13
13
  failures: string[]
14
+ /** 逐契约结果(机制哨兵 runEval 天然携带;任务表现等 reward 可缺省)。 */
15
+ results?: EvalResult[]
14
16
  }
15
17
 
16
18
  /** 奖励函数(reward function = policy→feedback):一个具名、可替换的打分器。 */
@@ -2,6 +2,7 @@ import { appendFileSync, readFileSync, mkdirSync, existsSync } from 'node:fs'
2
2
  import { join } from 'node:path'
3
3
  import { createHash } from 'node:crypto'
4
4
  import type { Message, ToolUseContent, ToolResultContent, ToolResult } from '../shared/types'
5
+ import type { CheckerDecision } from './post-flight-checker'
5
6
 
6
7
  export type SessionEvent =
7
8
  | {
@@ -20,6 +21,7 @@ export type SessionEvent =
20
21
  | { type: 'context/inject'; at: number; source: string; text: string }
21
22
  | { type: 'compaction/summary'; at: number; summary: string; replacedCount: number }
22
23
  | { type: 'compaction/rewrite'; at: number; messages: Message[] }
24
+ | { type: 'checker/decision'; at: number; toolName: string; decision: CheckerDecision }
23
25
 
24
26
  export function messageToEvents(msg: Message, at = 0): SessionEvent[] {
25
27
  if (msg.role === 'user') {
@@ -94,7 +96,7 @@ export function deriveMessages(events: SessionEvent[]): Message[] {
94
96
  // 快照替换:整个投影重建(微压缩/截断等结构性编辑的字节级复现)
95
97
  out = structuredClone(e.messages)
96
98
  }
97
- // 'session/start' → 无消息
99
+ // 'session/start' / 'checker/decision' → 无消息(决策仅记录证据,不进投影,保字节级可逆)
98
100
  }
99
101
  return out
100
102
  }