openfeel 1.3.2 → 1.3.3
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.en.md +1 -0
- package/README.md +2 -1
- package/README.zh-CN.md +1 -0
- package/dist/commands/flow.d.ts.map +1 -1
- package/dist/commands/flow.js +98 -14
- package/dist/commands/flow.js.map +1 -1
- package/dist/commands/instructions.js +1 -1
- package/dist/commands/instructions.js.map +1 -1
- package/dist/commands/plan.d.ts.map +1 -1
- package/dist/commands/plan.js +9 -1
- package/dist/commands/plan.js.map +1 -1
- package/dist/core/archive/merge.js +8 -8
- package/dist/core/archive/merge.js.map +1 -1
- package/dist/core/artifact-graph/resolver.d.ts.map +1 -1
- package/dist/core/artifact-graph/resolver.js +8 -0
- package/dist/core/artifact-graph/resolver.js.map +1 -1
- package/dist/core/config.d.ts +12 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +25 -3
- package/dist/core/config.js.map +1 -1
- package/dist/core/flow-manager.d.ts +26 -1
- package/dist/core/flow-manager.d.ts.map +1 -1
- package/dist/core/flow-manager.js +112 -9
- package/dist/core/flow-manager.js.map +1 -1
- package/dist/core/i18n-data/en.d.ts.map +1 -1
- package/dist/core/i18n-data/en.js +12 -0
- package/dist/core/i18n-data/en.js.map +1 -1
- package/dist/core/i18n-data/zh-CN.d.ts.map +1 -1
- package/dist/core/i18n-data/zh-CN.js +12 -0
- package/dist/core/i18n-data/zh-CN.js.map +1 -1
- package/dist/core/plan/stage.d.ts.map +1 -1
- package/dist/core/plan/stage.js +3 -1
- package/dist/core/plan/stage.js.map +1 -1
- package/dist/core/template-loader.d.ts.map +1 -1
- package/dist/core/template-loader.js +29 -18
- package/dist/core/template-loader.js.map +1 -1
- package/dist/core/update.d.ts.map +1 -1
- package/dist/core/update.js +16 -5
- package/dist/core/update.js.map +1 -1
- package/dist/core/view/entry.d.ts +13 -4
- package/dist/core/view/entry.d.ts.map +1 -1
- package/dist/core/view/entry.js +40 -16
- package/dist/core/view/entry.js.map +1 -1
- package/dist/core/workspace/structure.d.ts +21 -1
- package/dist/core/workspace/structure.d.ts.map +1 -1
- package/dist/core/workspace/structure.js +30 -11
- package/dist/core/workspace/structure.js.map +1 -1
- package/dsh/ADAPTER.md +14 -7
- package/dsh/README.md +3 -3
- package/dsh/lib/adapters/dashboard.js +2 -2
- package/dsh/lib/guard.js +78 -11
- package/dsh/lib/tools/shared.js +28 -14
- package/dsh/package.json +2 -2
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry.js","sourceRoot":"","sources":["../../../src/core/view/entry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,WAAW,EAAmB,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAKnD;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,WAAmB;IAClD,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,WAAW,CAAC,CAAC;IACzC,MAAM,eAAe,GAAG,GAAG,CAAC,cAAc,EAAE,CAAC;IAC7C,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,CAAC,IAAI,eAAe,EAAE,CAAC;QAChC,MAAM,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACnC,IAAI,CAAC,EAAE,CAAC;YACN,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC7B,IAAI,CAAC,GAAG,MAAM,EAAE,CAAC;gBACf,MAAM,GAAG,CAAC,CAAC;YACb,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AACtD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAC/B,WAAmB,EACnB,IAAY,EACZ,KAAa,EACb,WAAsC,QAAQ;IAE9C,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,WAAW,CAAC,CAAC;IAEzC,yBAAyB;IACzB,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;IAED,cAAc;IACd,MAAM,KAAK,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;IAE5C,iFAAiF;IACjF,MAAM,MAAM,GAAe;QACzB,EAAE,EAAE,KAAK;QACT,EAAE,EAAE,IAAI;QACR,MAAM,EAAE,MAAM;QACd,QAAQ;QACR,KAAK;QACL,QAAQ,EAAE,mBAAmB;QAC7B,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACnC,CAAC;IAEF,0BAA0B;IAC1B,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAEtB,OAAO;IACP,GAAG,CAAC,SAAS,CAAC;QACZ,IAAI,EAAE,EAAE;QACR,KAAK,EAAE,mBAAmB;QAC1B,MAAM,EAAE,YAAY;QACpB,MAAM,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE;KACnD,CAAC,CAAC;IAEH,MAAM;IACN,GAAG,CAAC,IAAI,EAAE,CAAC;IAEX,OAAO,MAAM,CAAC;AAChB,CAAC;
|
|
1
|
+
{"version":3,"file":"entry.js","sourceRoot":"","sources":["../../../src/core/view/entry.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,27 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export declare function ensureDir(path: string): void;
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* 核心必需目录(init 时创建;被 flow / plan / kb / dev 模板直接依赖)。
|
|
7
|
+
* v1.3.3 P2-4:由 10 个固定目录瘦身为 4 核心 + 6 惰性,降低冷启动前置开销。
|
|
8
|
+
*/
|
|
9
|
+
export declare const CORE_WORKSPACE_DIRS: readonly ["plan", "kb", "dev", "log"];
|
|
10
|
+
/**
|
|
11
|
+
* 惰性目录:首次使用时按需 `mkdir -p`(写路径已有/新增 `ensureLazyDir` 兜底)。
|
|
12
|
+
* 不参与 init 冷启动;缺失不视为工作区损坏。
|
|
13
|
+
*/
|
|
14
|
+
export declare const LAZY_WORKSPACE_DIRS: readonly ["code_review", "bugs", "users", "tmp", "manual", "update_conflicts"];
|
|
15
|
+
/**
|
|
16
|
+
* 惰性目录清单(导出供 lint / 文档 / 测试复用)。
|
|
17
|
+
*/
|
|
18
|
+
export declare const WORKSPACE_LAZY_DIRS: readonly string[];
|
|
19
|
+
/**
|
|
20
|
+
* 按需确保 `.openfeel/{name}` 惰性目录存在(幂等;仅接受 LAZY_WORKSPACE_DIRS 内的名字)。
|
|
21
|
+
* 供写路径在首次落盘前调用;未知目录名直接忽略(防御,不建任意目录)。
|
|
22
|
+
*/
|
|
23
|
+
export declare function ensureLazyDir(projectPath: string, name: string): void;
|
|
24
|
+
/**
|
|
25
|
+
* 创建 .openfeel/ 目录结构(核心必需 + dev 子目录;惰性目录不建)。
|
|
26
|
+
* @returns 本次新建的目录相对路径列表(既有目录不重复计入)
|
|
7
27
|
*/
|
|
8
28
|
export declare function createWorkspace(projectPath: string): string[];
|
|
9
29
|
//# sourceMappingURL=structure.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"structure.d.ts","sourceRoot":"","sources":["../../../src/core/workspace/structure.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAI5C;
|
|
1
|
+
{"version":3,"file":"structure.d.ts","sourceRoot":"","sources":["../../../src/core/workspace/structure.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAI5C;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,uCAAwC,CAAC;AAEzE;;;GAGG;AACH,eAAO,MAAM,mBAAmB,gFAOtB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAAwB,CAAC;AAS1E;;;GAGG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAKrE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CA8B7D"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 工作区目录创建
|
|
3
|
-
* 负责创建项目下的 .openfeel/
|
|
3
|
+
* 负责创建项目下的 .openfeel/ 目录结构(v1.3.3 P2-4:核心必需 + 其余惰性)。
|
|
4
4
|
*/
|
|
5
5
|
import { mkdirSync, existsSync } from 'node:fs';
|
|
6
6
|
import { resolve } from 'node:path';
|
|
@@ -12,19 +12,27 @@ export function ensureDir(path) {
|
|
|
12
12
|
mkdirSync(path, { recursive: true });
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
-
/**
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
/**
|
|
16
|
+
* 核心必需目录(init 时创建;被 flow / plan / kb / dev 模板直接依赖)。
|
|
17
|
+
* v1.3.3 P2-4:由 10 个固定目录瘦身为 4 核心 + 6 惰性,降低冷启动前置开销。
|
|
18
|
+
*/
|
|
19
|
+
export const CORE_WORKSPACE_DIRS = ['plan', 'kb', 'dev', 'log'];
|
|
20
|
+
/**
|
|
21
|
+
* 惰性目录:首次使用时按需 `mkdir -p`(写路径已有/新增 `ensureLazyDir` 兜底)。
|
|
22
|
+
* 不参与 init 冷启动;缺失不视为工作区损坏。
|
|
23
|
+
*/
|
|
24
|
+
export const LAZY_WORKSPACE_DIRS = [
|
|
21
25
|
'code_review',
|
|
22
26
|
'bugs',
|
|
23
27
|
'users',
|
|
24
28
|
'tmp',
|
|
25
29
|
'manual',
|
|
26
|
-
'update_conflicts',
|
|
30
|
+
'update_conflicts',
|
|
27
31
|
];
|
|
32
|
+
/**
|
|
33
|
+
* 惰性目录清单(导出供 lint / 文档 / 测试复用)。
|
|
34
|
+
*/
|
|
35
|
+
export const WORKSPACE_LAZY_DIRS = LAZY_WORKSPACE_DIRS;
|
|
28
36
|
/**
|
|
29
37
|
* dev/ 下的子目录清单
|
|
30
38
|
* - `note`:团队共享开发笔记
|
|
@@ -32,7 +40,18 @@ const WORKSPACE_DIRS = [
|
|
|
32
40
|
*/
|
|
33
41
|
const DEV_SUB_DIRS = ['note', 'current_archive'];
|
|
34
42
|
/**
|
|
35
|
-
*
|
|
43
|
+
* 按需确保 `.openfeel/{name}` 惰性目录存在(幂等;仅接受 LAZY_WORKSPACE_DIRS 内的名字)。
|
|
44
|
+
* 供写路径在首次落盘前调用;未知目录名直接忽略(防御,不建任意目录)。
|
|
45
|
+
*/
|
|
46
|
+
export function ensureLazyDir(projectPath, name) {
|
|
47
|
+
if (!LAZY_WORKSPACE_DIRS.includes(name)) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
ensureDir(resolve(projectPath, '.openfeel', name));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 创建 .openfeel/ 目录结构(核心必需 + dev 子目录;惰性目录不建)。
|
|
54
|
+
* @returns 本次新建的目录相对路径列表(既有目录不重复计入)
|
|
36
55
|
*/
|
|
37
56
|
export function createWorkspace(projectPath) {
|
|
38
57
|
const base = resolve(projectPath, '.openfeel');
|
|
@@ -42,8 +61,8 @@ export function createWorkspace(projectPath) {
|
|
|
42
61
|
mkdirSync(base, { recursive: true });
|
|
43
62
|
created.push('.openfeel/');
|
|
44
63
|
}
|
|
45
|
-
//
|
|
46
|
-
for (const dir of
|
|
64
|
+
// 创建核心子目录
|
|
65
|
+
for (const dir of CORE_WORKSPACE_DIRS) {
|
|
47
66
|
const fullPath = resolve(base, dir);
|
|
48
67
|
if (!existsSync(fullPath)) {
|
|
49
68
|
mkdirSync(fullPath, { recursive: true });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"structure.js","sourceRoot":"","sources":["../../../src/core/workspace/structure.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,CAAC;AACH,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"structure.js","sourceRoot":"","sources":["../../../src/core/workspace/structure.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAU,CAAC;AAEzE;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,aAAa;IACb,MAAM;IACN,OAAO;IACP,KAAK;IACL,QAAQ;IACR,kBAAkB;CACV,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAsB,mBAAmB,CAAC;AAE1E;;;;GAIG;AACH,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;AAEjD;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,WAAmB,EAAE,IAAY;IAC7D,IAAI,CAAE,mBAAyC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/D,OAAO;IACT,CAAC;IACD,SAAS,CAAC,OAAO,CAAC,WAAW,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC;AACrD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,WAAmB;IACjD,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,UAAU;IACV,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC7B,CAAC;IAED,UAAU;IACV,KAAK,MAAM,GAAG,IAAI,mBAAmB,EAAE,CAAC;QACtC,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACpC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACzC,OAAO,CAAC,IAAI,CAAC,aAAa,GAAG,GAAG,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,eAAe;IACf,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACrC,KAAK,MAAM,MAAM,IAAI,YAAY,EAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACzC,OAAO,CAAC,IAAI,CAAC,iBAAiB,MAAM,GAAG,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dsh/ADAPTER.md
CHANGED
|
@@ -28,16 +28,23 @@ OpenFeel 采用「核心层 + 适配器层」架构(`claude/`、`kilo/`、`.op
|
|
|
28
28
|
- **不解析**中文文本:优先消费 `--json`;失败读 `error.kind` / `error.code` / `error.detail`。
|
|
29
29
|
- **不 shadow** 既有能力:DSH 已有的 `subagent` / `workflow` / `todo_write` 照常使用;
|
|
30
30
|
`feel_next` 只给「该谁做」,实际派发交给 DSH。
|
|
31
|
-
- **写入门禁**(v1.3.
|
|
32
|
-
`str_replace_editor`;`.openfeel/**` 流程产物任意阶段可写(flow.json / `status.md`
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
- **写入门禁**(v1.3.3):用 DSH `ctx.tools.guard()` 同步拒绝 `edit` / `write` / `apply_patch` /
|
|
32
|
+
`str_replace_editor`;`.openfeel/**` 流程产物任意阶段可写(flow.json / `status.md` 除外)。
|
|
33
|
+
v1.3.3 起按**风险分层**:
|
|
34
|
+
- **bootstrap 例外**:工作区无 `.openfeel/` 时,全部目标为「新增文件」(`apply_patch` 还要求全部为
|
|
35
|
+
`*** Add File:`)→ 放行并提示补账本;已存在文件、`.openfeel/**`、Update/Delete/Move 仍拒绝;
|
|
36
|
+
- **doc/note 不绑相位**:`docs/**` 与 `.md/.mdx/.txt/.rst/.adoc` 在无活跃阶段或非 `exec_running`
|
|
37
|
+
相位也可写;**混合目标从严**(任一源码 → 按源码规则);
|
|
38
|
+
- 源码(`src/**` 等)仍要求 `exec_running`;`pwsh` / `bash` 默认不守,是显式逃生通道;
|
|
39
|
+
- `enforce=always`(默认)对非 OpenFeel 工作区也拦截,可用 `project` / `off` opt-out。
|
|
40
|
+
- **审查归属**(v1.3.3):REV 可挂 op(`stageId.op-xxx`)或挂 stage(`op = stageId`,无 op 的 fast 场景);
|
|
41
|
+
stage 级 REV 参与 blocking 门,但**不参与** `flow attempt` / `flow retry`。
|
|
35
42
|
|
|
36
43
|
## 目录
|
|
37
44
|
|
|
38
45
|
| 路径 | 内容 |
|
|
39
46
|
|---|---|
|
|
40
|
-
| `lib/guard.js` | 写入门禁:`enforce`、`.openfeel/**`
|
|
47
|
+
| `lib/guard.js` | 写入门禁:`enforce`、`.openfeel/**` 产物区、bootstrap 新增放行、doc/note 分层、apply_patch 目标解析 |
|
|
41
48
|
| [`ACTION-GUIDE.md`](ACTION-GUIDE.md) | **给 OpenFeel 本体的操作指南**:剩余 5 项待办、验收标准、边界约定 |
|
|
42
49
|
| `lib/index.js` | 插件入口(`name` / `inject` / `apply` / `normalizeConfig`) |
|
|
43
50
|
| `lib/adapters/cli.js` | CLI 执行器:可执行文件解析、UTF-8/无色/无日志、退出码与 envelope 语义 |
|
|
@@ -47,7 +54,7 @@ OpenFeel 采用「核心层 + 适配器层」架构(`claude/`、`kilo/`、`.op
|
|
|
47
54
|
| `lib/tools/shared.js` | 输出封装、参数编译、渲染 |
|
|
48
55
|
| `lib/surface/command.js` | `/feel` 人类命令 |
|
|
49
56
|
| `lib/surface/prompt.js` | `<feel_mode>` 系统提示段 |
|
|
50
|
-
| `test/` | 契约 / 行为 / 门禁 / 真实注册表 四套验证(42 + 83 +
|
|
57
|
+
| `test/` | 契约 / 行为 / 门禁 / 真实注册表 四套验证(42 + 83 + 46 + 10 = 181 断言) |
|
|
51
58
|
| `docs/compat/` | OpenFeel v1.2.1 逆向兼容性契约(6 份;仅供回归参照,权威以 [docs/json-contract.md](https://github.com/Liuary/OpenFeel/blob/master/docs/json-contract.md) 为准) |
|
|
52
59
|
|
|
53
60
|
## 验证
|
|
@@ -56,7 +63,7 @@ OpenFeel 采用「核心层 + 适配器层」架构(`claude/`、`kilo/`、`.op
|
|
|
56
63
|
cd dsh
|
|
57
64
|
node test/contract.js # 42 — DSH schema 契约(真实 assertSupportedJsonSchema)
|
|
58
65
|
node test/verify.js # 83 — 行为(真实 CLI + 真实 .openfeel 副本)
|
|
59
|
-
node test/guard.js #
|
|
66
|
+
node test/guard.js # 46 — 写入门禁(fake ToolExecution + 临时工作区)
|
|
60
67
|
node test/integration.js # 10 — 真实 cordis + 真实 ToolRuntime 挂载
|
|
61
68
|
```
|
|
62
69
|
|
package/dsh/README.md
CHANGED
|
@@ -196,14 +196,14 @@ provider 桥接层会把「只有 description、没有 type」的节点转成 `t
|
|
|
196
196
|
|
|
197
197
|
---
|
|
198
198
|
|
|
199
|
-
## 6.5 写入门禁(v1.3.
|
|
199
|
+
## 6.5 写入门禁(v1.3.3)
|
|
200
200
|
|
|
201
201
|
适配器在 `apply()` 中用 DSH 的 `ctx.tools.guard()` 注册同步守卫(`dsh/lib/guard.js`):
|
|
202
202
|
|
|
203
203
|
- **只守** `edit` / `write` / `apply_patch` / `str_replace_editor`。`feel_*`、`pwsh`、`read`、`todo_write` 等不受影响。
|
|
204
204
|
- `.openfeel/**` 是**流程产物区**:plan / scheme / review 产物在任意阶段可写;但 `.openfeel/flow.json` 与 `.openfeel/**/status.md` **始终拒绝**(用 `feel_*`)。受保护路径按**会话工作区 `<cwd>`** 判定;执行阶段仍可编辑其他项目的 `.openfeel/`(不做跨项目全局保护)。
|
|
205
|
-
-
|
|
206
|
-
-
|
|
205
|
+
- **v1.3.3 风险分层**——源码(`src/**` 等)仍要求存在 `exec_running` 阶段;**doc/note**(`docs/**` 与 `.md/.mdx/.txt/.rst/.adoc`)在无活跃阶段或非 `exec_running` 相位也放行;**混合目标从严**(任一源码 → 按源码规则)。
|
|
206
|
+
- **bootstrap 例外(v1.3.3)**:无 `.openfeel/` 时,全部目标为**新增文件**(`apply_patch` 须全部 `*** Add File:`)→ 放行并提示补账本;已存在文件、`.openfeel/**`、Update/Delete/Move 仍拒绝(`enforce=always` 下)。`project`/`off` 放行。
|
|
207
207
|
- `apply_patch` 解析所有 patch 头(`*** Update/Add/Delete File:`、`*** Move to:`、`---/+++`);全部目标在 `.openfeel/**` 才内部放行,混合/无头保守拒绝。
|
|
208
208
|
- `enforce=off` **完全不注册 guard**(连 flow.json/status.md 也不拦)。
|
|
209
209
|
- `ctx.tools.guard` 缺失时记警告并降级;`ctx.effect` 负责 disposer,避免 HMR 累积。
|
|
@@ -191,7 +191,7 @@ export async function readSnapshot(cli, options = {}) {
|
|
|
191
191
|
/** 相位标签由 `flow next` 下发;无权威值时退化为相位名(不维护本地映射)。 */
|
|
192
192
|
phaseLabel: typeof next?.phaseLabel === 'string' ? next.phaseLabel : focusPhase,
|
|
193
193
|
status: focusStage?.status ?? '',
|
|
194
|
-
deps: Array.isArray(focusStage?.deps) ? focusStage.deps : [],
|
|
194
|
+
deps: Array.isArray(focusStage?.deps) ? [...focusStage.deps] : [],
|
|
195
195
|
ops: focusStage?.ops ?? {},
|
|
196
196
|
checkpoint: CHECKPOINT_OF_PHASE[focusPhase] ?? '',
|
|
197
197
|
/** 负责该相位的 Agent(CLI 权威字段;无 flow next 时为 unknown)。 */
|
|
@@ -229,7 +229,7 @@ export async function readSnapshot(cli, options = {}) {
|
|
|
229
229
|
id: stage.id ?? stage.name ?? '',
|
|
230
230
|
phase: stage.phase ?? '',
|
|
231
231
|
status: stage.status ?? '',
|
|
232
|
-
deps: Array.isArray(stage.deps) ? stage.deps : [],
|
|
232
|
+
deps: Array.isArray(stage.deps) ? [...stage.deps] : [],
|
|
233
233
|
workflowMode: stage.workflowMode ?? stage.workflow_mode ?? null,
|
|
234
234
|
requirementId: stage.requirementId ?? null,
|
|
235
235
|
reviewTier: stage.reviewTier ?? null,
|
package/dsh/lib/guard.js
CHANGED
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
* @module openfeel-dsh/guard
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { readFileSync, statSync } from 'node:fs';
|
|
18
|
-
import { basename, join, resolve } from 'node:path';
|
|
17
|
+
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
18
|
+
import { basename, extname, join, resolve } from 'node:path';
|
|
19
19
|
|
|
20
20
|
import { isProjectWorkspace, OPENFEEL_DIR } from './adapters/workspace.js';
|
|
21
21
|
|
|
@@ -40,6 +40,35 @@ export function normalizeForComparison(value, platform = process.platform) {
|
|
|
40
40
|
return platform === 'win32' || platform === 'darwin' ? value.toLowerCase() : value;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
/** 文档/笔记类扩展名(写门禁按产物类型分层:doc/note 不绑相位)。 */
|
|
44
|
+
export const DOC_EXTENSIONS = Object.freeze(['.md', '.mdx', '.txt', '.rst', '.adoc']);
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 是否为文档/笔记类目标(P0-4):扩展名命中,或位于**工作区根级 `docs/`** 下。
|
|
48
|
+
* v1.3.3 复核:`docs` 必须直接位于会话工作区下(`src/docs/x.ts` 不算文档,防源码借名绕过相位门)。
|
|
49
|
+
* 仅用于「放行 doc/note」;源代码仍按 `exec_running` 严格判定。
|
|
50
|
+
* @param {string} absolute 已归一化绝对路径
|
|
51
|
+
* @param {string} cwd 已归一化工作区
|
|
52
|
+
* @returns {boolean}
|
|
53
|
+
*/
|
|
54
|
+
function isDocPath(absolute, cwd) {
|
|
55
|
+
if (DOC_EXTENSIONS.includes(extname(absolute).toLowerCase())) return true;
|
|
56
|
+
const docsRoot = normalizeTarget(cwd, 'docs');
|
|
57
|
+
return absolute === docsRoot
|
|
58
|
+
|| absolute.startsWith(`${docsRoot}\\`)
|
|
59
|
+
|| absolute.startsWith(`${docsRoot}/`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 是否位于工作区内(bootstrap 例外边界;防 `..`/绝对路径写出工作区)。
|
|
64
|
+
* @param {string} absolute 已归一化绝对路径
|
|
65
|
+
* @param {string} cwd 已归一化工作区
|
|
66
|
+
* @returns {boolean}
|
|
67
|
+
*/
|
|
68
|
+
function isUnderWorkspace(absolute, cwd) {
|
|
69
|
+
return absolute === cwd || absolute.startsWith(`${cwd}\\`) || absolute.startsWith(`${cwd}/`);
|
|
70
|
+
}
|
|
71
|
+
|
|
43
72
|
/** flow.json 读取缓存(path → { mtimeMs, size, value })。 */
|
|
44
73
|
const flowCache = new Map();
|
|
45
74
|
|
|
@@ -120,22 +149,32 @@ function extractPatchText(args) {
|
|
|
120
149
|
}
|
|
121
150
|
|
|
122
151
|
/**
|
|
123
|
-
* 解析 apply_patch
|
|
152
|
+
* 解析 apply_patch 的全部目标路径与变更类型。
|
|
124
153
|
*
|
|
125
154
|
* 只认 patch 头,避免正文里出现 `.openfeel/` 被误判。支持:
|
|
126
155
|
* - `*** Update File:`, `*** Add File:`, `*** Delete File:`
|
|
127
156
|
* - `*** Move to:`(要求同块 `*** Update File:` 源,否则拒绝)
|
|
128
157
|
* - `--- a/path`, `+++ b/path`;忽略 `/dev/null`
|
|
129
158
|
*
|
|
159
|
+
* 返回 `entries`(路径 + kind)供 bootstrap 例外判定「是否纯新增」:
|
|
160
|
+
* kind ∈ `add | update | delete | move`;同一路径出现多种 kind 时从严记 `update`。
|
|
161
|
+
*
|
|
130
162
|
* @param {string} patch
|
|
131
|
-
* @returns {{ ok: true, paths: string[] } | { ok: false, reason: string }}
|
|
163
|
+
* @returns {{ ok: true, paths: string[], entries: Array<{ path: string, kind: string }> } | { ok: false, reason: string }}
|
|
132
164
|
*/
|
|
133
165
|
export function parsePatchTargets(patch) {
|
|
134
166
|
const paths = [];
|
|
167
|
+
const kinds = new Map();
|
|
135
168
|
const seen = new Set();
|
|
136
|
-
const add = (raw) => {
|
|
169
|
+
const add = (raw, kind) => {
|
|
137
170
|
const value = cleanPatchPath(raw);
|
|
138
171
|
if (value === '' || value === '/dev/null') return;
|
|
172
|
+
const prev = kinds.get(value);
|
|
173
|
+
if (prev === undefined) {
|
|
174
|
+
kinds.set(value, kind);
|
|
175
|
+
} else if (prev !== kind) {
|
|
176
|
+
kinds.set(value, 'update'); // 同路径混合 kind → 从严(bootstrap 例外不成立)
|
|
177
|
+
}
|
|
139
178
|
if (seen.has(value)) return;
|
|
140
179
|
seen.add(value);
|
|
141
180
|
paths.push(value);
|
|
@@ -147,19 +186,19 @@ export function parsePatchTargets(patch) {
|
|
|
147
186
|
const update = /^\*\*\* Update File:\s*(.+?)\s*$/.exec(line);
|
|
148
187
|
if (update !== null) {
|
|
149
188
|
currentBlock = 'update';
|
|
150
|
-
add(update[1]);
|
|
189
|
+
add(update[1], 'update');
|
|
151
190
|
continue;
|
|
152
191
|
}
|
|
153
192
|
const addFile = /^\*\*\* Add File:\s*(.+?)\s*$/.exec(line);
|
|
154
193
|
if (addFile !== null) {
|
|
155
194
|
currentBlock = 'add';
|
|
156
|
-
add(addFile[1]);
|
|
195
|
+
add(addFile[1], 'add');
|
|
157
196
|
continue;
|
|
158
197
|
}
|
|
159
198
|
const deleteFile = /^\*\*\* Delete File:\s*(.+?)\s*$/.exec(line);
|
|
160
199
|
if (deleteFile !== null) {
|
|
161
200
|
currentBlock = 'delete';
|
|
162
|
-
add(deleteFile[1]);
|
|
201
|
+
add(deleteFile[1], 'delete');
|
|
163
202
|
continue;
|
|
164
203
|
}
|
|
165
204
|
const move = /^\*\*\* Move to:\s*(.+?)\s*$/.exec(line);
|
|
@@ -167,7 +206,7 @@ export function parsePatchTargets(patch) {
|
|
|
167
206
|
if (currentBlock !== 'update') {
|
|
168
207
|
return { ok: false, reason: '*** Move to: 缺少同块 *** Update File: 源路径' };
|
|
169
208
|
}
|
|
170
|
-
add(move[1]);
|
|
209
|
+
add(move[1], 'move');
|
|
171
210
|
continue;
|
|
172
211
|
}
|
|
173
212
|
if (/^\*\*\* (?:Begin|End) Patch/.test(line)) {
|
|
@@ -175,13 +214,13 @@ export function parsePatchTargets(patch) {
|
|
|
175
214
|
continue;
|
|
176
215
|
}
|
|
177
216
|
const diff = /^(?:---|\+\+\+) [ab]\/(.+?)\s*$/.exec(line);
|
|
178
|
-
if (diff !== null) add(diff[1]);
|
|
217
|
+
if (diff !== null) add(diff[1], 'update');
|
|
179
218
|
}
|
|
180
219
|
|
|
181
220
|
if (paths.length === 0) {
|
|
182
221
|
return { ok: false, reason: '无法从 patch 头确定目标路径' };
|
|
183
222
|
}
|
|
184
|
-
return { ok: true, paths };
|
|
223
|
+
return { ok: true, paths, entries: paths.map((path) => ({ path, kind: kinds.get(path) })) };
|
|
185
224
|
}
|
|
186
225
|
|
|
187
226
|
/**
|
|
@@ -253,6 +292,8 @@ export function createOpenFeelGuard(options = {}) {
|
|
|
253
292
|
const fallbackCwd = typeof options.cwd === 'string' && options.cwd !== '' ? options.cwd : undefined;
|
|
254
293
|
|
|
255
294
|
const t = (zh, en) => (english ? en : zh);
|
|
295
|
+
/** bootstrap 例外提示去重(按工作区路径)。 */
|
|
296
|
+
const bootstrapHinted = new Set();
|
|
256
297
|
|
|
257
298
|
if (enforce === 'off') {
|
|
258
299
|
// 完全关闭:连 flow.json/status.md 也不拦。
|
|
@@ -270,6 +311,7 @@ export function createOpenFeelGuard(options = {}) {
|
|
|
270
311
|
const normalizedCwd = normalizeForComparison(resolvedCwd);
|
|
271
312
|
|
|
272
313
|
let rawTargets;
|
|
314
|
+
let patchEntries = null;
|
|
273
315
|
if (name === 'apply_patch') {
|
|
274
316
|
const patch = extractPatchText(execution?.arguments);
|
|
275
317
|
if (patch === undefined) {
|
|
@@ -286,6 +328,7 @@ export function createOpenFeelGuard(options = {}) {
|
|
|
286
328
|
);
|
|
287
329
|
}
|
|
288
330
|
rawTargets = parsed.paths;
|
|
331
|
+
patchEntries = parsed.entries;
|
|
289
332
|
} else {
|
|
290
333
|
rawTargets = extractArgumentPaths(execution?.arguments);
|
|
291
334
|
if (rawTargets.length === 0) {
|
|
@@ -297,6 +340,7 @@ export function createOpenFeelGuard(options = {}) {
|
|
|
297
340
|
}
|
|
298
341
|
|
|
299
342
|
const targets = rawTargets.map((target) => normalizeTarget(resolvedCwd, target));
|
|
343
|
+
const allDoc = targets.every((target) => isDocPath(target, normalizedCwd));
|
|
300
344
|
|
|
301
345
|
// 受保护路径:guard 启用时始终拒绝(enforce=off 已提前返回)。
|
|
302
346
|
if (targets.some((target) => isProtectedPath(target, normalizedCwd))) {
|
|
@@ -309,6 +353,25 @@ export function createOpenFeelGuard(options = {}) {
|
|
|
309
353
|
const initialized = isProjectWorkspace(resolvedCwd);
|
|
310
354
|
if (!initialized) {
|
|
311
355
|
if (enforce === 'always') {
|
|
356
|
+
// P0-1 bootstrap 例外:空工作区 + 全部为「新增文件」→ 放行(最高风险等级不成立)。
|
|
357
|
+
// apply_patch 额外要求全部 block 为 `*** Add File:`(Update/Delete/Move/混合一律从严)。
|
|
358
|
+
// `.openfeel/**` 不适用:流程产物仍要求先 init(B8)。
|
|
359
|
+
const allNew = targets.every((target) => !existsSync(target));
|
|
360
|
+
const anyInternal = targets.some((target) => isUnderOpenFeel(target, normalizedCwd));
|
|
361
|
+
const allInside = targets.every((target) => isUnderWorkspace(target, normalizedCwd));
|
|
362
|
+
const addOnly = patchEntries === null || patchEntries.every((entry) => entry.kind === 'add');
|
|
363
|
+
if (allNew && addOnly && !anyInternal && allInside) {
|
|
364
|
+
if (!bootstrapHinted.has(normalizedCwd)) {
|
|
365
|
+
bootstrapHinted.add(normalizedCwd);
|
|
366
|
+
process.stderr.write(
|
|
367
|
+
`${t(
|
|
368
|
+
'OpenFeel 写入门禁:[bootstrap] 工作区尚未初始化,已放行本次新增文件;建议稍后运行 `openfeel init` 补账本。',
|
|
369
|
+
'OpenFeel write guard: [bootstrap] workspace not initialized; this new-file write was allowed. Run `openfeel init` later to record it.',
|
|
370
|
+
)}\n`,
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
return undefined;
|
|
374
|
+
}
|
|
312
375
|
return t(
|
|
313
376
|
'OpenFeel 写入门禁:当前工作区尚未初始化 OpenFeel(无 `.openfeel/`)。请先运行 `openfeel init` 并建立需求/阶段;或让用户把 profile 的 `enforce` 改为 `project` / `off`。',
|
|
314
377
|
'OpenFeel write guard: this workspace is not OpenFeel-initialized (no `.openfeel/`). Run `openfeel init` and create a requirement/stage first; or ask the user to set `enforce` to `project` / `off`.',
|
|
@@ -331,6 +394,8 @@ export function createOpenFeelGuard(options = {}) {
|
|
|
331
394
|
const active = activeStages(flow.value);
|
|
332
395
|
if (active.length === 0) {
|
|
333
396
|
if (allowGeneral && hasGeneralRequirement(flow.value)) return undefined;
|
|
397
|
+
// P0-4:doc/note 类产物不要求活跃阶段(收口后仍可写文档);混合目标从严。
|
|
398
|
+
if (allDoc) return undefined;
|
|
334
399
|
return t(
|
|
335
400
|
'OpenFeel 写入门禁:当前无活跃阶段,不能修改源码/文档。请先 feel_req add → claim → feel_stage add 建立阶段。',
|
|
336
401
|
'OpenFeel write guard: no active stage, so source/docs are read-only. Create a stage via feel_req add → claim → feel_stage add.',
|
|
@@ -338,6 +403,8 @@ export function createOpenFeelGuard(options = {}) {
|
|
|
338
403
|
}
|
|
339
404
|
|
|
340
405
|
if (active.some((stage) => stage.phase === 'exec_running')) return undefined;
|
|
406
|
+
// P0-4:非 exec 相位仍允许 doc/note(研究记录、设计文档等);代码仍严格。
|
|
407
|
+
if (allDoc) return undefined;
|
|
341
408
|
|
|
342
409
|
const summary = active
|
|
343
410
|
.map((stage) => `${stage.id ?? '(unknown)'}=${stage.phase ?? '(unknown)'}`)
|
package/dsh/lib/tools/shared.js
CHANGED
|
@@ -188,26 +188,40 @@ export function toWireEnvelope(action, payload) {
|
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
/**
|
|
191
|
-
*
|
|
191
|
+
* 安全序列化:只对**真环**(祖先路径上出现过的对象)写 `[循环引用]`;
|
|
192
|
+
* 同一对象的**重复引用**(DAG,如 focus.deps 与 stages[i].deps 指向同一数组)正常复制(P1-2)。
|
|
193
|
+
* 兼处理 BigInt / 不可序列化值,永不抛错。
|
|
192
194
|
* @param {unknown} value
|
|
193
195
|
* @returns {string}
|
|
194
196
|
*/
|
|
195
197
|
export function stringifySafe(value) {
|
|
196
198
|
try {
|
|
197
|
-
/**
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
199
|
+
/**
|
|
200
|
+
* @param {unknown} item
|
|
201
|
+
* @param {WeakSet<object>} ancestors
|
|
202
|
+
* @returns {unknown}
|
|
203
|
+
*/
|
|
204
|
+
const clone = (item, ancestors) => {
|
|
205
|
+
if (typeof item === 'bigint') return item.toString();
|
|
206
|
+
if (typeof item === 'function' || typeof item === 'symbol') return undefined;
|
|
207
|
+
if (typeof item !== 'object' || item === null) return item;
|
|
208
|
+
// 保留 Date / URL 等自带 toJSON 的语义(与 JSON.stringify 一致)
|
|
209
|
+
if (typeof item.toJSON === 'function') return item.toJSON();
|
|
210
|
+
if (ancestors.has(item)) return '[循环引用]';
|
|
211
|
+
ancestors.add(item);
|
|
212
|
+
let out;
|
|
213
|
+
if (Array.isArray(item)) {
|
|
214
|
+
out = item.map((entry) => clone(entry, ancestors));
|
|
215
|
+
} else {
|
|
216
|
+
out = {};
|
|
217
|
+
for (const [key, entry] of Object.entries(item)) {
|
|
218
|
+
out[key] = clone(entry, ancestors);
|
|
205
219
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
);
|
|
220
|
+
}
|
|
221
|
+
ancestors.delete(item);
|
|
222
|
+
return out;
|
|
223
|
+
};
|
|
224
|
+
return JSON.stringify(clone(value, new WeakSet()), null, 2);
|
|
211
225
|
} catch {
|
|
212
226
|
return String(value);
|
|
213
227
|
}
|
package/dsh/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openfeel-dsh",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.3",
|
|
4
4
|
"description": "OpenFeel × DSH — Feel 模式适配器:把 OpenFeel 的流水线、需求分发、版本归档与知识库接入 DeepSeek Harness",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": true,
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"openfeel": {
|
|
34
34
|
"adapter": "dsh",
|
|
35
|
-
"requiresCli": ">=1.3.
|
|
35
|
+
"requiresCli": ">=1.3.3"
|
|
36
36
|
},
|
|
37
37
|
"keywords": [
|
|
38
38
|
"openfeel",
|