@shgroup/opencode-serenity-plugin 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +199 -0
- package/bin/opencode-serenity-plugin.js +316 -0
- package/dist/activation.d.ts +40 -0
- package/dist/activation.d.ts.map +1 -0
- package/dist/activation.js +133 -0
- package/dist/activation.js.map +1 -0
- package/dist/bash-override.d.ts +10 -0
- package/dist/bash-override.d.ts.map +1 -0
- package/dist/bash-override.js +24 -0
- package/dist/bash-override.js.map +1 -0
- package/dist/bash-toggle.d.ts +17 -0
- package/dist/bash-toggle.d.ts.map +1 -0
- package/dist/bash-toggle.js +42 -0
- package/dist/bash-toggle.js.map +1 -0
- package/dist/config-schema.d.ts +300 -0
- package/dist/config-schema.d.ts.map +1 -0
- package/dist/config-schema.js +185 -0
- package/dist/config-schema.js.map +1 -0
- package/dist/errors.d.ts +90 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +151 -0
- package/dist/errors.js.map +1 -0
- package/dist/fs/file-system-tool.d.ts +25 -0
- package/dist/fs/file-system-tool.d.ts.map +1 -0
- package/dist/fs/file-system-tool.js +318 -0
- package/dist/fs/file-system-tool.js.map +1 -0
- package/dist/fs/resolve-path.d.ts +53 -0
- package/dist/fs/resolve-path.d.ts.map +1 -0
- package/dist/fs/resolve-path.js +100 -0
- package/dist/fs/resolve-path.js.map +1 -0
- package/dist/hooks/compacting.d.ts +23 -0
- package/dist/hooks/compacting.d.ts.map +1 -0
- package/dist/hooks/compacting.js +90 -0
- package/dist/hooks/compacting.js.map +1 -0
- package/dist/hooks/permission-auto-reply.d.ts +91 -0
- package/dist/hooks/permission-auto-reply.d.ts.map +1 -0
- package/dist/hooks/permission-auto-reply.js +158 -0
- package/dist/hooks/permission-auto-reply.js.map +1 -0
- package/dist/hooks/permission-guards.d.ts +41 -0
- package/dist/hooks/permission-guards.d.ts.map +1 -0
- package/dist/hooks/permission-guards.js +153 -0
- package/dist/hooks/permission-guards.js.map +1 -0
- package/dist/hooks/shell-env.d.ts +20 -0
- package/dist/hooks/shell-env.d.ts.map +1 -0
- package/dist/hooks/shell-env.js +38 -0
- package/dist/hooks/shell-env.js.map +1 -0
- package/dist/hooks/util.d.ts +81 -0
- package/dist/hooks/util.d.ts.map +1 -0
- package/dist/hooks/util.js +172 -0
- package/dist/hooks/util.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -0
- package/dist/init/init-wizard.d.ts +39 -0
- package/dist/init/init-wizard.d.ts.map +1 -0
- package/dist/init/init-wizard.js +297 -0
- package/dist/init/init-wizard.js.map +1 -0
- package/dist/install.d.ts +117 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +255 -0
- package/dist/install.js.map +1 -0
- package/dist/msm-schema.d.ts +76 -0
- package/dist/msm-schema.d.ts.map +1 -0
- package/dist/msm-schema.js +207 -0
- package/dist/msm-schema.js.map +1 -0
- package/dist/msm.d.ts +25 -0
- package/dist/msm.d.ts.map +1 -0
- package/dist/msm.js +317 -0
- package/dist/msm.js.map +1 -0
- package/dist/session/lib.d.ts +33 -0
- package/dist/session/lib.d.ts.map +1 -0
- package/dist/session/lib.js +475 -0
- package/dist/session/lib.js.map +1 -0
- package/dist/session/session-tool.d.ts +17 -0
- package/dist/session/session-tool.d.ts.map +1 -0
- package/dist/session/session-tool.js +109 -0
- package/dist/session/session-tool.js.map +1 -0
- package/dist/skills/install-skill.d.ts +36 -0
- package/dist/skills/install-skill.d.ts.map +1 -0
- package/dist/skills/install-skill.js +91 -0
- package/dist/skills/install-skill.js.map +1 -0
- package/dist/skills/template-loader.d.ts +79 -0
- package/dist/skills/template-loader.d.ts.map +1 -0
- package/dist/skills/template-loader.js +170 -0
- package/dist/skills/template-loader.js.map +1 -0
- package/dist/state.d.ts +35 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +62 -0
- package/dist/state.js.map +1 -0
- package/dist/tui.d.ts +61 -0
- package/dist/tui.d.ts.map +1 -0
- package/dist/tui.js +279 -0
- package/dist/tui.js.map +1 -0
- package/dist/types/index.d.ts +30 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +17 -0
- package/dist/types/index.js.map +1 -0
- package/dist/util/config-patch.d.ts +58 -0
- package/dist/util/config-patch.d.ts.map +1 -0
- package/dist/util/config-patch.js +117 -0
- package/dist/util/config-patch.js.map +1 -0
- package/dist/util/git.d.ts +29 -0
- package/dist/util/git.d.ts.map +1 -0
- package/dist/util/git.js +74 -0
- package/dist/util/git.js.map +1 -0
- package/dist/util/init-check.d.ts +22 -0
- package/dist/util/init-check.d.ts.map +1 -0
- package/dist/util/init-check.js +76 -0
- package/dist/util/init-check.js.map +1 -0
- package/dist/util/init.d.ts +54 -0
- package/dist/util/init.d.ts.map +1 -0
- package/dist/util/init.js +87 -0
- package/dist/util/init.js.map +1 -0
- package/dist/util/log.d.ts +25 -0
- package/dist/util/log.d.ts.map +1 -0
- package/dist/util/log.js +28 -0
- package/dist/util/log.js.map +1 -0
- package/dist/util/msm-call.d.ts +48 -0
- package/dist/util/msm-call.d.ts.map +1 -0
- package/dist/util/msm-call.js +86 -0
- package/dist/util/msm-call.js.map +1 -0
- package/dist/util/msm-exec-runtime.d.ts +123 -0
- package/dist/util/msm-exec-runtime.d.ts.map +1 -0
- package/dist/util/msm-exec-runtime.js +532 -0
- package/dist/util/msm-exec-runtime.js.map +1 -0
- package/dist/util/path.d.ts +10 -0
- package/dist/util/path.d.ts.map +1 -0
- package/dist/util/path.js +21 -0
- package/dist/util/path.js.map +1 -0
- package/dist/util/ready-state.d.ts +43 -0
- package/dist/util/ready-state.d.ts.map +1 -0
- package/dist/util/ready-state.js +104 -0
- package/dist/util/ready-state.js.map +1 -0
- package/dist/util/serenity-file.d.ts +30 -0
- package/dist/util/serenity-file.d.ts.map +1 -0
- package/dist/util/serenity-file.js +69 -0
- package/dist/util/serenity-file.js.map +1 -0
- package/dist/util/tui-install.d.ts +61 -0
- package/dist/util/tui-install.d.ts.map +1 -0
- package/dist/util/tui-install.js +94 -0
- package/dist/util/tui-install.js.map +1 -0
- package/docs/architecture-v0.md +294 -0
- package/docs/contract-v0.md +417 -0
- package/docs/plugin-self-contained-msm-v1.md +182 -0
- package/docs/refactor-direction-v1.11.md +78 -0
- package/docs/requirements-v0-scope.md +104 -0
- package/docs/requirements-v0-summary.md +108 -0
- package/docs/rr7-init-design.md +304 -0
- package/docs/v0.1-candidates.md +132 -0
- package/package.json +54 -0
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 错误类清单(contract-v0.md 附录 B)
|
|
3
|
+
*
|
|
4
|
+
* 设计原则:
|
|
5
|
+
* - 所有错误都是 Error 子类(保证 stack trace 完整)
|
|
6
|
+
* - 错误名以 Error 结尾(grep 友好;不强制 SerenityError 前缀以便精细分类)
|
|
7
|
+
* - 错误传播策略:
|
|
8
|
+
* 1. plugin 入口(index.ts / tui.ts)不抛 — 返回空 hooks 或 toast 通知
|
|
9
|
+
* 2. 大多数 hook 用 safeHook / safeCreateHook 静默(v0.0.1 release 静默原则 + retry-storm 防护)
|
|
10
|
+
* 3. 例外:permission-guards.ts 的 tool.execute.before(RR5 hard block)故意
|
|
11
|
+
* 让 throw 透传 — 中断整条 Effect 链正是 RR5 想要的行为
|
|
12
|
+
*/
|
|
13
|
+
/** 基类:所有 serenity plugin 错误的父类 */
|
|
14
|
+
export declare class SerenityError extends Error {
|
|
15
|
+
constructor(message: string);
|
|
16
|
+
}
|
|
17
|
+
/** RR1 违反:cwd 不在 git repo 内 */
|
|
18
|
+
export declare class NotInGitRepoError extends SerenityError {
|
|
19
|
+
constructor(cwd: string);
|
|
20
|
+
}
|
|
21
|
+
/** RR1 违反:/.serenity 文件不存在 */
|
|
22
|
+
export declare class SerenityFileNotFoundError extends SerenityError {
|
|
23
|
+
constructor(cwdRoot: string);
|
|
24
|
+
}
|
|
25
|
+
/** /.serenity 文件存在但内容为空或无效 */
|
|
26
|
+
export declare class SerenityFileEmptyError extends SerenityError {
|
|
27
|
+
constructor(path: string);
|
|
28
|
+
}
|
|
29
|
+
/** RR2 违反:.opencode/skills/<instanceName>/SKILL.md 不存在 */
|
|
30
|
+
export declare class SkillNotFoundError extends SerenityError {
|
|
31
|
+
constructor(cwdRoot: string, instanceName: string);
|
|
32
|
+
}
|
|
33
|
+
/** msm_exec 失败:MSM 不在注册表中 */
|
|
34
|
+
export declare class MsmNotRegisteredError extends SerenityError {
|
|
35
|
+
constructor(msmName: string);
|
|
36
|
+
}
|
|
37
|
+
/** msm_exec 失败:MSM 子进程超时 */
|
|
38
|
+
export declare class MsmTimeoutError extends SerenityError {
|
|
39
|
+
constructor(msmName: string, timeoutMs: number);
|
|
40
|
+
}
|
|
41
|
+
/** msm_register 失败:name 已被注册 */
|
|
42
|
+
export declare class MsmAlreadyRegisteredError extends SerenityError {
|
|
43
|
+
constructor(msmName: string);
|
|
44
|
+
}
|
|
45
|
+
/** msm_register 失败:脚本文件不存在(拒绝注册空路径)*/
|
|
46
|
+
export declare class MsmScriptNotFoundError extends SerenityError {
|
|
47
|
+
constructor(msmName: string, scriptPath: string);
|
|
48
|
+
}
|
|
49
|
+
/** msm_deregister 失败:name 不在 registry */
|
|
50
|
+
export declare class MsmNotInRegistryError extends SerenityError {
|
|
51
|
+
constructor(msmName: string);
|
|
52
|
+
}
|
|
53
|
+
/** msm_exec 失败:MSM 子进程 exit code != 0
|
|
54
|
+
*
|
|
55
|
+
* v1.15.1:MsmExecutionError 显式持有 stdout/stderr/exitCode 三个字段
|
|
56
|
+
* - 修复 S022 RFC §9 缺陷(plugin 端 msm_exec 吞掉 stdout)
|
|
57
|
+
* - JSON 模式下业务 msm 把错误信息写在 stdout(per S022 §2.3),
|
|
58
|
+
* 错误对象必须能让 LLM 看到 stdout 原文以便重试/诊断
|
|
59
|
+
*/
|
|
60
|
+
export declare class MsmExecutionError extends SerenityError {
|
|
61
|
+
readonly stdout: string;
|
|
62
|
+
readonly stderr: string;
|
|
63
|
+
readonly exitCode: number;
|
|
64
|
+
constructor(msmName: string, exitCode: number, stdout: string, stderr: string);
|
|
65
|
+
}
|
|
66
|
+
/** RR7 触发:/.serenity 创建失败(git add/commit 阶段)*/
|
|
67
|
+
export declare class InitGitCommitError extends SerenityError {
|
|
68
|
+
constructor(reason: string);
|
|
69
|
+
}
|
|
70
|
+
/** v1.10 RR7:用户输入的 prefix 不是 kebab-case */
|
|
71
|
+
export declare class InvalidInstanceNameError extends SerenityError {
|
|
72
|
+
constructor(name: string);
|
|
73
|
+
}
|
|
74
|
+
/** msm_exec 失败:path-arg 解析为 cwdRoot 之外的路径(v0.1-2 path escape guard)*/
|
|
75
|
+
export declare class MsmPathEscapeError extends SerenityError {
|
|
76
|
+
constructor(msmName: string, argName: string, value: string, resolved: string);
|
|
77
|
+
}
|
|
78
|
+
/** msm_exec 失败:path-arg 指向 symlink / symlink 链(v1-1 symlink 防御)*/
|
|
79
|
+
export declare class MsmSymlinkError extends SerenityError {
|
|
80
|
+
constructor(msmName: string, argName: string, value: string, resolved: string, reason: string);
|
|
81
|
+
}
|
|
82
|
+
/** 文件系统操作错误(file-system-tool) */
|
|
83
|
+
export declare class FileSystemError extends SerenityError {
|
|
84
|
+
constructor(message: string);
|
|
85
|
+
}
|
|
86
|
+
/** 会话管理操作错误(session-tool) */
|
|
87
|
+
export declare class SessionError extends SerenityError {
|
|
88
|
+
constructor(message: string);
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,kCAAkC;AAClC,qBAAa,aAAc,SAAQ,KAAK;gBAC1B,OAAO,EAAE,MAAM;CAI5B;AAED,+BAA+B;AAC/B,qBAAa,iBAAkB,SAAQ,aAAa;gBACtC,GAAG,EAAE,MAAM;CAIxB;AAED,8BAA8B;AAC9B,qBAAa,yBAA0B,SAAQ,aAAa;gBAC9C,OAAO,EAAE,MAAM;CAI5B;AAED,8BAA8B;AAC9B,qBAAa,sBAAuB,SAAQ,aAAa;gBAC3C,IAAI,EAAE,MAAM;CAIzB;AAED,0DAA0D;AAC1D,qBAAa,kBAAmB,SAAQ,aAAa;gBACvC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;CAIlD;AAED,6BAA6B;AAC7B,qBAAa,qBAAsB,SAAQ,aAAa;gBAC1C,OAAO,EAAE,MAAM;CAI5B;AAED,4BAA4B;AAC5B,qBAAa,eAAgB,SAAQ,aAAa;gBACpC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;CAI/C;AAED,gCAAgC;AAChC,qBAAa,yBAA0B,SAAQ,aAAa;gBAC9C,OAAO,EAAE,MAAM;CAI5B;AAED,sCAAsC;AACtC,qBAAa,sBAAuB,SAAQ,aAAa;gBAC3C,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;CAIhD;AAED,yCAAyC;AACzC,qBAAa,qBAAsB,SAAQ,aAAa;gBAC1C,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;GAMG;AACH,qBAAa,iBAAkB,SAAQ,aAAa;IAClD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBACd,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAW9E;AAED,+CAA+C;AAC/C,qBAAa,kBAAmB,SAAQ,aAAa;gBACvC,MAAM,EAAE,MAAM;CAI3B;AAED,2CAA2C;AAC3C,qBAAa,wBAAyB,SAAQ,aAAa;gBAC7C,IAAI,EAAE,MAAM;CAOzB;AAED,sEAAsE;AACtE,qBAAa,kBAAmB,SAAQ,aAAa;gBACvC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAO9E;AAED,kEAAkE;AAClE,qBAAa,eAAgB,SAAQ,aAAa;gBACpC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAO9F;AAED,iCAAiC;AACjC,qBAAa,eAAgB,SAAQ,aAAa;gBACpC,OAAO,EAAE,MAAM;CAI5B;AAED,6BAA6B;AAC7B,qBAAa,YAAa,SAAQ,aAAa;gBACjC,OAAO,EAAE,MAAM;CAI5B"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 错误类清单(contract-v0.md 附录 B)
|
|
3
|
+
*
|
|
4
|
+
* 设计原则:
|
|
5
|
+
* - 所有错误都是 Error 子类(保证 stack trace 完整)
|
|
6
|
+
* - 错误名以 Error 结尾(grep 友好;不强制 SerenityError 前缀以便精细分类)
|
|
7
|
+
* - 错误传播策略:
|
|
8
|
+
* 1. plugin 入口(index.ts / tui.ts)不抛 — 返回空 hooks 或 toast 通知
|
|
9
|
+
* 2. 大多数 hook 用 safeHook / safeCreateHook 静默(v0.0.1 release 静默原则 + retry-storm 防护)
|
|
10
|
+
* 3. 例外:permission-guards.ts 的 tool.execute.before(RR5 hard block)故意
|
|
11
|
+
* 让 throw 透传 — 中断整条 Effect 链正是 RR5 想要的行为
|
|
12
|
+
*/
|
|
13
|
+
/** 基类:所有 serenity plugin 错误的父类 */
|
|
14
|
+
export class SerenityError extends Error {
|
|
15
|
+
constructor(message) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = 'SerenityError';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** RR1 违反:cwd 不在 git repo 内 */
|
|
21
|
+
export class NotInGitRepoError extends SerenityError {
|
|
22
|
+
constructor(cwd) {
|
|
23
|
+
super(`cwd "${cwd}" is not inside a git repository; serenity plugin requires RR6 (cwd must be in a git repo)`);
|
|
24
|
+
this.name = 'NotInGitRepoError';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** RR1 违反:/.serenity 文件不存在 */
|
|
28
|
+
export class SerenityFileNotFoundError extends SerenityError {
|
|
29
|
+
constructor(cwdRoot) {
|
|
30
|
+
super(`/.serenity file not found in "${cwdRoot}"; serenity plugin requires RR1 (/.serenity must exist in cwd root)`);
|
|
31
|
+
this.name = 'SerenityFileNotFoundError';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** /.serenity 文件存在但内容为空或无效 */
|
|
35
|
+
export class SerenityFileEmptyError extends SerenityError {
|
|
36
|
+
constructor(path) {
|
|
37
|
+
super(`/.serenity file at "${path}" is empty or contains only whitespace; expected a non-empty instance name`);
|
|
38
|
+
this.name = 'SerenityFileEmptyError';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** RR2 违反:.opencode/skills/<instanceName>/SKILL.md 不存在 */
|
|
42
|
+
export class SkillNotFoundError extends SerenityError {
|
|
43
|
+
constructor(cwdRoot, instanceName) {
|
|
44
|
+
super(`SKILL.md not found at "${cwdRoot}/.opencode/skills/${instanceName}/SKILL.md"; serenity plugin requires RR2 (the instance skill must exist)`);
|
|
45
|
+
this.name = 'SkillNotFoundError';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/** msm_exec 失败:MSM 不在注册表中 */
|
|
49
|
+
export class MsmNotRegisteredError extends SerenityError {
|
|
50
|
+
constructor(msmName) {
|
|
51
|
+
super(`MSM "${msmName}" is not in mech-registry.json; serenity plugin requires registration before use`);
|
|
52
|
+
this.name = 'MsmNotRegisteredError';
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** msm_exec 失败:MSM 子进程超时 */
|
|
56
|
+
export class MsmTimeoutError extends SerenityError {
|
|
57
|
+
constructor(msmName, timeoutMs) {
|
|
58
|
+
super(`MSM "${msmName}" timed out after ${timeoutMs}ms`);
|
|
59
|
+
this.name = 'MsmTimeoutError';
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/** msm_register 失败:name 已被注册 */
|
|
63
|
+
export class MsmAlreadyRegisteredError extends SerenityError {
|
|
64
|
+
constructor(msmName) {
|
|
65
|
+
super(`MSM "${msmName}" is already registered; use msm_deregister first to replace, or pick a different name`);
|
|
66
|
+
this.name = 'MsmAlreadyRegisteredError';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** msm_register 失败:脚本文件不存在(拒绝注册空路径)*/
|
|
70
|
+
export class MsmScriptNotFoundError extends SerenityError {
|
|
71
|
+
constructor(msmName, scriptPath) {
|
|
72
|
+
super(`MSM "${msmName}" script not found at "${scriptPath}"; serenity plugin refuses to register MSMs whose script does not exist`);
|
|
73
|
+
this.name = 'MsmScriptNotFoundError';
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/** msm_deregister 失败:name 不在 registry */
|
|
77
|
+
export class MsmNotInRegistryError extends SerenityError {
|
|
78
|
+
constructor(msmName) {
|
|
79
|
+
super(`MSM "${msmName}" is not in mech-registry.json; nothing to deregister`);
|
|
80
|
+
this.name = 'MsmNotInRegistryError';
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** msm_exec 失败:MSM 子进程 exit code != 0
|
|
84
|
+
*
|
|
85
|
+
* v1.15.1:MsmExecutionError 显式持有 stdout/stderr/exitCode 三个字段
|
|
86
|
+
* - 修复 S022 RFC §9 缺陷(plugin 端 msm_exec 吞掉 stdout)
|
|
87
|
+
* - JSON 模式下业务 msm 把错误信息写在 stdout(per S022 §2.3),
|
|
88
|
+
* 错误对象必须能让 LLM 看到 stdout 原文以便重试/诊断
|
|
89
|
+
*/
|
|
90
|
+
export class MsmExecutionError extends SerenityError {
|
|
91
|
+
stdout;
|
|
92
|
+
stderr;
|
|
93
|
+
exitCode;
|
|
94
|
+
constructor(msmName, exitCode, stdout, stderr) {
|
|
95
|
+
const stdoutSnippet = stdout ? `
|
|
96
|
+
stdout: ${stdout.slice(0, 1000)}` : '';
|
|
97
|
+
const stderrSnippet = stderr ? `
|
|
98
|
+
stderr: ${stderr.slice(0, 500)}` : '';
|
|
99
|
+
super(`MSM "${msmName}" failed with exit code ${exitCode}${stdoutSnippet}${stderrSnippet}`);
|
|
100
|
+
this.name = 'MsmExecutionError';
|
|
101
|
+
this.exitCode = exitCode;
|
|
102
|
+
this.stdout = stdout;
|
|
103
|
+
this.stderr = stderr;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/** RR7 触发:/.serenity 创建失败(git add/commit 阶段)*/
|
|
107
|
+
export class InitGitCommitError extends SerenityError {
|
|
108
|
+
constructor(reason) {
|
|
109
|
+
super(`failed to git add + commit /.serenity: ${reason}`);
|
|
110
|
+
this.name = 'InitGitCommitError';
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/** v1.10 RR7:用户输入的 prefix 不是 kebab-case */
|
|
114
|
+
export class InvalidInstanceNameError extends SerenityError {
|
|
115
|
+
constructor(name) {
|
|
116
|
+
super(`Invalid serenity prefix "${name}"; must be kebab-case ` +
|
|
117
|
+
`(lowercase a-z, 0-9, dashes; no leading or trailing dash)`);
|
|
118
|
+
this.name = 'InvalidInstanceNameError';
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/** msm_exec 失败:path-arg 解析为 cwdRoot 之外的路径(v0.1-2 path escape guard)*/
|
|
122
|
+
export class MsmPathEscapeError extends SerenityError {
|
|
123
|
+
constructor(msmName, argName, value, resolved) {
|
|
124
|
+
super(`MSM "${msmName}" path-arg "${argName}"="${value}" resolves to "${resolved}" ` +
|
|
125
|
+
`which is outside cwdRoot; serenity plugin blocks path traversal (v0.1-2 pre-indexed guard)`);
|
|
126
|
+
this.name = 'MsmPathEscapeError';
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/** msm_exec 失败:path-arg 指向 symlink / symlink 链(v1-1 symlink 防御)*/
|
|
130
|
+
export class MsmSymlinkError extends SerenityError {
|
|
131
|
+
constructor(msmName, argName, value, resolved, reason) {
|
|
132
|
+
super(`MSM "${msmName}" path-arg "${argName}"="${value}" → "${resolved}": ${reason}; ` +
|
|
133
|
+
`serenity plugin blocks symlink attacks (v1-1 symlink guard)`);
|
|
134
|
+
this.name = 'MsmSymlinkError';
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/** 文件系统操作错误(file-system-tool) */
|
|
138
|
+
export class FileSystemError extends SerenityError {
|
|
139
|
+
constructor(message) {
|
|
140
|
+
super(message);
|
|
141
|
+
this.name = 'FileSystemError';
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/** 会话管理操作错误(session-tool) */
|
|
145
|
+
export class SessionError extends SerenityError {
|
|
146
|
+
constructor(message) {
|
|
147
|
+
super(message);
|
|
148
|
+
this.name = 'SessionError';
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* file-system-tool.ts — 宁静号文件系统基础设施工具
|
|
3
|
+
*
|
|
4
|
+
* 提供跨实例的文件系统操作,不依赖任何实例特定的脚本。
|
|
5
|
+
* 所有路径基于 .serenity 向上遍历动态解析。
|
|
6
|
+
*
|
|
7
|
+
* 子命令:
|
|
8
|
+
* root — 寻找并返回宁静号实例根目录
|
|
9
|
+
* resolve — 将相对路径基于根目录解析为绝对路径
|
|
10
|
+
* exists — 检测路径是否存在
|
|
11
|
+
* list — 列出目录内容(含元数据)
|
|
12
|
+
* relative — 返回相对于根的相对路径
|
|
13
|
+
* mkdir — 创建目录(递归,类似 mkdir -p)
|
|
14
|
+
* rm — 删除文件/目录(支持多路径批量,--recursive,--dry-run)
|
|
15
|
+
* mv — 移动/重命名
|
|
16
|
+
* cp — 复制文件/目录(--recursive)
|
|
17
|
+
* touch — 创建空文件或更新时间戳
|
|
18
|
+
*
|
|
19
|
+
* 安全约束:
|
|
20
|
+
* - 写操作(mkdir/rm/mv/cp/touch)自动限制在 .serenity 根内
|
|
21
|
+
* - .serenity 文件本身受保护不可删除
|
|
22
|
+
*/
|
|
23
|
+
import { type ToolDefinition } from '@opencode-ai/plugin';
|
|
24
|
+
export declare const fileSystemTool: ToolDefinition;
|
|
25
|
+
//# sourceMappingURL=file-system-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-system-tool.d.ts","sourceRoot":"","sources":["../../src/fs/file-system-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AASH,OAAO,EAAQ,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAsFhE,eAAO,MAAM,cAAc,EAAE,cA4Q3B,CAAC"}
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* file-system-tool.ts — 宁静号文件系统基础设施工具
|
|
3
|
+
*
|
|
4
|
+
* 提供跨实例的文件系统操作,不依赖任何实例特定的脚本。
|
|
5
|
+
* 所有路径基于 .serenity 向上遍历动态解析。
|
|
6
|
+
*
|
|
7
|
+
* 子命令:
|
|
8
|
+
* root — 寻找并返回宁静号实例根目录
|
|
9
|
+
* resolve — 将相对路径基于根目录解析为绝对路径
|
|
10
|
+
* exists — 检测路径是否存在
|
|
11
|
+
* list — 列出目录内容(含元数据)
|
|
12
|
+
* relative — 返回相对于根的相对路径
|
|
13
|
+
* mkdir — 创建目录(递归,类似 mkdir -p)
|
|
14
|
+
* rm — 删除文件/目录(支持多路径批量,--recursive,--dry-run)
|
|
15
|
+
* mv — 移动/重命名
|
|
16
|
+
* cp — 复制文件/目录(--recursive)
|
|
17
|
+
* touch — 创建空文件或更新时间戳
|
|
18
|
+
*
|
|
19
|
+
* 安全约束:
|
|
20
|
+
* - 写操作(mkdir/rm/mv/cp/touch)自动限制在 .serenity 根内
|
|
21
|
+
* - .serenity 文件本身受保护不可删除
|
|
22
|
+
*/
|
|
23
|
+
import { existsSync, statSync, readdirSync, mkdirSync, unlinkSync, rmdirSync, rmSync, renameSync, cpSync, utimesSync, writeFileSync, } from 'node:fs';
|
|
24
|
+
import { resolve, dirname, normalize } from 'node:path';
|
|
25
|
+
import { tool } from '@opencode-ai/plugin';
|
|
26
|
+
import { z } from 'zod';
|
|
27
|
+
import { FileSystemError } from '../errors.js';
|
|
28
|
+
import { findSerenityRoot, resolveRootPath, isPathInsideSerenity, serenityPathRelative, } from './resolve-path.js';
|
|
29
|
+
import pkg from '../../package.json' with { type: 'json' };
|
|
30
|
+
const VERSION = pkg.version;
|
|
31
|
+
function detectFileType(stat) {
|
|
32
|
+
if (stat.isDirectory())
|
|
33
|
+
return 'dir';
|
|
34
|
+
if (stat.isFile())
|
|
35
|
+
return 'file';
|
|
36
|
+
if (stat.isSymbolicLink())
|
|
37
|
+
return 'symlink';
|
|
38
|
+
return 'other';
|
|
39
|
+
}
|
|
40
|
+
function humanSize(bytes) {
|
|
41
|
+
if (bytes < 1024)
|
|
42
|
+
return `${bytes} B`;
|
|
43
|
+
if (bytes < 1024 * 1024)
|
|
44
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
45
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
46
|
+
}
|
|
47
|
+
function getFileInfo(absPath, name) {
|
|
48
|
+
try {
|
|
49
|
+
const stat = statSync(absPath);
|
|
50
|
+
return {
|
|
51
|
+
name,
|
|
52
|
+
type: detectFileType(stat),
|
|
53
|
+
size: stat.size,
|
|
54
|
+
sizeHuman: humanSize(stat.size),
|
|
55
|
+
mtime: stat.mtime.toISOString(),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return { name, type: 'other', size: 0, sizeHuman: '?', mtime: '?' };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// ── 写操作路径校验 ──
|
|
63
|
+
function validateWritePath(root, target) {
|
|
64
|
+
const absPath = target.startsWith('/') ? normalize(target) : resolveRootPath(root, target);
|
|
65
|
+
if (!isPathInsideSerenity(root, absPath)) {
|
|
66
|
+
throw new FileSystemError(`file-system: path "${target}" resolves to "${absPath}" which is outside serenity root "${root}"`);
|
|
67
|
+
}
|
|
68
|
+
return absPath;
|
|
69
|
+
}
|
|
70
|
+
function assertNotProtected(root, absPath, targetLabel) {
|
|
71
|
+
// Protect .serenity file from deletion
|
|
72
|
+
const serenityMarker = resolve(root, '.serenity');
|
|
73
|
+
if (absPath === serenityMarker) {
|
|
74
|
+
throw new FileSystemError(`file-system: refusing to delete protected path: ${targetLabel} (.serenity is the serenity instance marker)`);
|
|
75
|
+
}
|
|
76
|
+
// Protect the root directory itself
|
|
77
|
+
if (absPath === root) {
|
|
78
|
+
throw new FileSystemError(`file-system: refusing to delete the serenity root directory: ${targetLabel}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// ── Tool 定义 ──
|
|
82
|
+
const SUBCOMMANDS = [
|
|
83
|
+
'root', 'resolve', 'exists', 'list', 'relative',
|
|
84
|
+
'mkdir', 'rm', 'mv', 'cp', 'touch',
|
|
85
|
+
];
|
|
86
|
+
export const fileSystemTool = tool({
|
|
87
|
+
description: `Serenity file-system utility (v${VERSION}). ` +
|
|
88
|
+
'Resolves paths relative to the serenity instance root (the directory containing .serenity). ' +
|
|
89
|
+
'Use this instead of raw read/edit tools when you need to work with serenity instance paths. ' +
|
|
90
|
+
'All subcommands validate that paths stay within the serenity root.',
|
|
91
|
+
args: {
|
|
92
|
+
subcommand: z
|
|
93
|
+
.enum(SUBCOMMANDS)
|
|
94
|
+
.describe('Operation to perform:\n' +
|
|
95
|
+
' root — Find and return the serenity root directory\n' +
|
|
96
|
+
' resolve — Resolve a relative path to absolute (relative to root)\n' +
|
|
97
|
+
' exists — Check if a path exists\n' +
|
|
98
|
+
' list — List directory contents with metadata (JSON)\n' +
|
|
99
|
+
' relative — Get path relative to serenity root\n' +
|
|
100
|
+
' mkdir — Create directory (recursive, like mkdir -p)\n' +
|
|
101
|
+
' rm — Delete files/directories (batch: pass multiple paths via paths arg)\n' +
|
|
102
|
+
' mv — Move or rename a file/directory\n' +
|
|
103
|
+
' cp — Copy a file or directory\n' +
|
|
104
|
+
' touch — Create empty file or update timestamp'),
|
|
105
|
+
path: z
|
|
106
|
+
.string()
|
|
107
|
+
.optional()
|
|
108
|
+
.describe('Single path argument for resolve/exists/list/relative/mkdir/touch subcommands. ' +
|
|
109
|
+
'Can be relative (from serenity root) or absolute (must be inside serenity root for write operations).'),
|
|
110
|
+
paths: z
|
|
111
|
+
.array(z.string())
|
|
112
|
+
.optional()
|
|
113
|
+
.describe('Multiple paths for rm batch delete. ' +
|
|
114
|
+
'Each path can be relative or absolute (must be inside serenity root). ' +
|
|
115
|
+
'Also accepts a single path via the "path" arg for convenience.'),
|
|
116
|
+
src: z
|
|
117
|
+
.string()
|
|
118
|
+
.optional()
|
|
119
|
+
.describe('Source path for mv/cp subcommands.'),
|
|
120
|
+
dst: z
|
|
121
|
+
.string()
|
|
122
|
+
.optional()
|
|
123
|
+
.describe('Destination path for mv/cp subcommands.'),
|
|
124
|
+
recursive: z
|
|
125
|
+
.boolean()
|
|
126
|
+
.optional()
|
|
127
|
+
.default(false)
|
|
128
|
+
.describe('Recursive operation for rm (delete directories) and cp (copy directories).'),
|
|
129
|
+
'dry-run': z
|
|
130
|
+
.boolean()
|
|
131
|
+
.optional()
|
|
132
|
+
.default(false)
|
|
133
|
+
.describe('Preview changes without actually modifying files. Supported by rm.'),
|
|
134
|
+
},
|
|
135
|
+
execute: async (input, ctx) => {
|
|
136
|
+
const cwd = ctx.directory;
|
|
137
|
+
const root = findSerenityRoot(cwd);
|
|
138
|
+
const sub = input.subcommand;
|
|
139
|
+
// ── root ──
|
|
140
|
+
if (sub === 'root') {
|
|
141
|
+
return root;
|
|
142
|
+
}
|
|
143
|
+
// ── resolve ──
|
|
144
|
+
if (sub === 'resolve') {
|
|
145
|
+
if (!input.path)
|
|
146
|
+
throw new FileSystemError('file-system resolve: requires a path argument');
|
|
147
|
+
return resolveRootPath(root, input.path);
|
|
148
|
+
}
|
|
149
|
+
// ── relative ──
|
|
150
|
+
if (sub === 'relative') {
|
|
151
|
+
if (!input.path)
|
|
152
|
+
throw new FileSystemError('file-system relative: requires a path argument');
|
|
153
|
+
const absPath = input.path.startsWith('/')
|
|
154
|
+
? input.path
|
|
155
|
+
: resolveRootPath(root, input.path);
|
|
156
|
+
if (!isPathInsideSerenity(root, absPath)) {
|
|
157
|
+
throw new FileSystemError(`file-system relative: path "${input.path}" resolves to "${absPath}" which is outside serenity root "${root}"`);
|
|
158
|
+
}
|
|
159
|
+
return serenityPathRelative(root, absPath);
|
|
160
|
+
}
|
|
161
|
+
// ── exists ──
|
|
162
|
+
if (sub === 'exists') {
|
|
163
|
+
if (!input.path)
|
|
164
|
+
throw new FileSystemError('file-system exists: requires a path argument');
|
|
165
|
+
const absPath = input.path.startsWith('/')
|
|
166
|
+
? input.path
|
|
167
|
+
: resolveRootPath(root, input.path);
|
|
168
|
+
return existsSync(absPath) ? 'true' : 'false';
|
|
169
|
+
}
|
|
170
|
+
// ── list(增强:返回 JSON 元数据)──
|
|
171
|
+
if (sub === 'list') {
|
|
172
|
+
if (!input.path)
|
|
173
|
+
throw new FileSystemError('file-system list: requires a path argument');
|
|
174
|
+
const absPath = input.path.startsWith('/')
|
|
175
|
+
? input.path
|
|
176
|
+
: resolveRootPath(root, input.path);
|
|
177
|
+
if (!existsSync(absPath)) {
|
|
178
|
+
throw new FileSystemError(`file-system list: path "${absPath}" does not exist`);
|
|
179
|
+
}
|
|
180
|
+
const names = readdirSync(absPath);
|
|
181
|
+
const entries = names.sort().map((name) => getFileInfo(resolve(absPath, name), name));
|
|
182
|
+
return JSON.stringify({ path: absPath, entries, count: entries.length }, null, 2);
|
|
183
|
+
}
|
|
184
|
+
// ── mkdir(递归创建,类似 mkdir -p)──
|
|
185
|
+
if (sub === 'mkdir') {
|
|
186
|
+
if (!input.path)
|
|
187
|
+
throw new FileSystemError('file-system mkdir: requires a path argument');
|
|
188
|
+
const absPath = validateWritePath(root, input.path);
|
|
189
|
+
if (existsSync(absPath)) {
|
|
190
|
+
const stat = statSync(absPath);
|
|
191
|
+
if (stat.isDirectory())
|
|
192
|
+
return `directory already exists: ${input.path}`;
|
|
193
|
+
throw new FileSystemError(`file-system mkdir: path "${input.path}" exists but is not a directory`);
|
|
194
|
+
}
|
|
195
|
+
mkdirSync(absPath, { recursive: true });
|
|
196
|
+
return `created directory: ${input.path}`;
|
|
197
|
+
}
|
|
198
|
+
// ── rm(多路径批量删除)──
|
|
199
|
+
if (sub === 'rm') {
|
|
200
|
+
// 合并单路径和多路径参数
|
|
201
|
+
const targets = [...(input.paths ?? [])];
|
|
202
|
+
if (input.path)
|
|
203
|
+
targets.push(input.path);
|
|
204
|
+
if (targets.length === 0) {
|
|
205
|
+
throw new FileSystemError('file-system rm: requires at least one path argument (path or paths)');
|
|
206
|
+
}
|
|
207
|
+
const dryRun = input['dry-run'] ?? false;
|
|
208
|
+
const recursive = input.recursive ?? false;
|
|
209
|
+
const results = [];
|
|
210
|
+
for (const target of targets) {
|
|
211
|
+
const absPath = validateWritePath(root, target);
|
|
212
|
+
if (!existsSync(absPath)) {
|
|
213
|
+
results.push(`[SKIP] not found: ${target}`);
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
const stat = statSync(absPath);
|
|
217
|
+
const isDir = stat.isDirectory();
|
|
218
|
+
// 保护 .serenity 和根目录
|
|
219
|
+
try {
|
|
220
|
+
assertNotProtected(root, absPath, target);
|
|
221
|
+
}
|
|
222
|
+
catch (e) {
|
|
223
|
+
results.push(`[SKIP] ${e.message}`);
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
const relLabel = serenityPathRelative(root, absPath);
|
|
227
|
+
if (dryRun) {
|
|
228
|
+
const extra = isDir ? (recursive ? ' (recursive)' : '') : '';
|
|
229
|
+
results.push(`[DRY-RUN] ${isDir ? 'directory' : 'file'}: ${relLabel}${extra}`);
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
if (isDir && !recursive) {
|
|
233
|
+
const entries = readdirSync(absPath);
|
|
234
|
+
if (entries.length > 0) {
|
|
235
|
+
results.push(`[SKIP] directory not empty (${entries.length} items), use --recursive: ${relLabel}`);
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
rmdirSync(absPath);
|
|
239
|
+
}
|
|
240
|
+
else if (isDir) {
|
|
241
|
+
rmSync(absPath, { recursive: true, force: false });
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
unlinkSync(absPath);
|
|
245
|
+
}
|
|
246
|
+
results.push(`[OK] deleted: ${relLabel}`);
|
|
247
|
+
}
|
|
248
|
+
return results.join('\n');
|
|
249
|
+
}
|
|
250
|
+
// ── mv(移动/重命名)──
|
|
251
|
+
if (sub === 'mv') {
|
|
252
|
+
if (!input.src || !input.dst) {
|
|
253
|
+
throw new FileSystemError('file-system mv: requires both --src and --dst arguments');
|
|
254
|
+
}
|
|
255
|
+
const srcAbs = validateWritePath(root, input.src);
|
|
256
|
+
const dstAbs = validateWritePath(root, input.dst);
|
|
257
|
+
if (!existsSync(srcAbs)) {
|
|
258
|
+
throw new FileSystemError(`file-system mv: source not found: ${input.src}`);
|
|
259
|
+
}
|
|
260
|
+
if (existsSync(dstAbs)) {
|
|
261
|
+
throw new FileSystemError(`file-system mv: destination already exists: ${input.dst}`);
|
|
262
|
+
}
|
|
263
|
+
// 自动创建目标父目录
|
|
264
|
+
const parentDir = dirname(dstAbs);
|
|
265
|
+
if (!existsSync(parentDir)) {
|
|
266
|
+
mkdirSync(parentDir, { recursive: true });
|
|
267
|
+
}
|
|
268
|
+
renameSync(srcAbs, dstAbs);
|
|
269
|
+
return `moved: ${input.src} \u2192 ${input.dst}`;
|
|
270
|
+
}
|
|
271
|
+
// ── cp(复制)──
|
|
272
|
+
if (sub === 'cp') {
|
|
273
|
+
if (!input.src || !input.dst) {
|
|
274
|
+
throw new FileSystemError('file-system cp: requires both --src and --dst arguments');
|
|
275
|
+
}
|
|
276
|
+
const srcAbs = validateWritePath(root, input.src);
|
|
277
|
+
const dstAbs = validateWritePath(root, input.dst);
|
|
278
|
+
if (!existsSync(srcAbs)) {
|
|
279
|
+
throw new FileSystemError(`file-system cp: source not found: ${input.src}`);
|
|
280
|
+
}
|
|
281
|
+
if (existsSync(dstAbs)) {
|
|
282
|
+
throw new FileSystemError(`file-system cp: destination already exists: ${input.dst}`);
|
|
283
|
+
}
|
|
284
|
+
const stat = statSync(srcAbs);
|
|
285
|
+
if (stat.isDirectory() && !input.recursive) {
|
|
286
|
+
throw new FileSystemError(`file-system cp: source is a directory, use --recursive to copy: ${input.src}`);
|
|
287
|
+
}
|
|
288
|
+
// 自动创建目标父目录
|
|
289
|
+
const parentDir = dirname(dstAbs);
|
|
290
|
+
if (!existsSync(parentDir)) {
|
|
291
|
+
mkdirSync(parentDir, { recursive: true });
|
|
292
|
+
}
|
|
293
|
+
cpSync(srcAbs, dstAbs, { recursive: input.recursive ?? false });
|
|
294
|
+
return `copied: ${input.src} \u2192 ${input.dst}`;
|
|
295
|
+
}
|
|
296
|
+
// ── touch(创建空文件 / 更新时间戳)──
|
|
297
|
+
if (sub === 'touch') {
|
|
298
|
+
if (!input.path)
|
|
299
|
+
throw new FileSystemError('file-system touch: requires a path argument');
|
|
300
|
+
const absPath = validateWritePath(root, input.path);
|
|
301
|
+
if (existsSync(absPath)) {
|
|
302
|
+
// 更新时间戳到当前时间
|
|
303
|
+
const now = new Date();
|
|
304
|
+
utimesSync(absPath, now, now);
|
|
305
|
+
return `updated timestamp: ${input.path}`;
|
|
306
|
+
}
|
|
307
|
+
// 创建空文件,自动创建父目录
|
|
308
|
+
const parentDir = dirname(absPath);
|
|
309
|
+
if (!existsSync(parentDir)) {
|
|
310
|
+
mkdirSync(parentDir, { recursive: true });
|
|
311
|
+
}
|
|
312
|
+
writeFileSync(absPath, '', 'utf8');
|
|
313
|
+
return `created empty file: ${input.path}`;
|
|
314
|
+
}
|
|
315
|
+
throw new FileSystemError(`file-system: unknown subcommand "${sub}"`);
|
|
316
|
+
},
|
|
317
|
+
});
|
|
318
|
+
//# sourceMappingURL=file-system-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-system-tool.js","sourceRoot":"","sources":["../../src/fs/file-system-tool.ts"],"names":[],"mappings":"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"}
|