@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.
Files changed (151) hide show
  1. package/README.md +199 -0
  2. package/bin/opencode-serenity-plugin.js +316 -0
  3. package/dist/activation.d.ts +40 -0
  4. package/dist/activation.d.ts.map +1 -0
  5. package/dist/activation.js +133 -0
  6. package/dist/activation.js.map +1 -0
  7. package/dist/bash-override.d.ts +10 -0
  8. package/dist/bash-override.d.ts.map +1 -0
  9. package/dist/bash-override.js +24 -0
  10. package/dist/bash-override.js.map +1 -0
  11. package/dist/bash-toggle.d.ts +17 -0
  12. package/dist/bash-toggle.d.ts.map +1 -0
  13. package/dist/bash-toggle.js +42 -0
  14. package/dist/bash-toggle.js.map +1 -0
  15. package/dist/config-schema.d.ts +300 -0
  16. package/dist/config-schema.d.ts.map +1 -0
  17. package/dist/config-schema.js +185 -0
  18. package/dist/config-schema.js.map +1 -0
  19. package/dist/errors.d.ts +90 -0
  20. package/dist/errors.d.ts.map +1 -0
  21. package/dist/errors.js +151 -0
  22. package/dist/errors.js.map +1 -0
  23. package/dist/fs/file-system-tool.d.ts +25 -0
  24. package/dist/fs/file-system-tool.d.ts.map +1 -0
  25. package/dist/fs/file-system-tool.js +318 -0
  26. package/dist/fs/file-system-tool.js.map +1 -0
  27. package/dist/fs/resolve-path.d.ts +53 -0
  28. package/dist/fs/resolve-path.d.ts.map +1 -0
  29. package/dist/fs/resolve-path.js +100 -0
  30. package/dist/fs/resolve-path.js.map +1 -0
  31. package/dist/hooks/compacting.d.ts +23 -0
  32. package/dist/hooks/compacting.d.ts.map +1 -0
  33. package/dist/hooks/compacting.js +90 -0
  34. package/dist/hooks/compacting.js.map +1 -0
  35. package/dist/hooks/permission-auto-reply.d.ts +91 -0
  36. package/dist/hooks/permission-auto-reply.d.ts.map +1 -0
  37. package/dist/hooks/permission-auto-reply.js +158 -0
  38. package/dist/hooks/permission-auto-reply.js.map +1 -0
  39. package/dist/hooks/permission-guards.d.ts +41 -0
  40. package/dist/hooks/permission-guards.d.ts.map +1 -0
  41. package/dist/hooks/permission-guards.js +153 -0
  42. package/dist/hooks/permission-guards.js.map +1 -0
  43. package/dist/hooks/shell-env.d.ts +20 -0
  44. package/dist/hooks/shell-env.d.ts.map +1 -0
  45. package/dist/hooks/shell-env.js +38 -0
  46. package/dist/hooks/shell-env.js.map +1 -0
  47. package/dist/hooks/util.d.ts +81 -0
  48. package/dist/hooks/util.d.ts.map +1 -0
  49. package/dist/hooks/util.js +172 -0
  50. package/dist/hooks/util.js.map +1 -0
  51. package/dist/index.d.ts +26 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +63 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/init/init-wizard.d.ts +39 -0
  56. package/dist/init/init-wizard.d.ts.map +1 -0
  57. package/dist/init/init-wizard.js +297 -0
  58. package/dist/init/init-wizard.js.map +1 -0
  59. package/dist/install.d.ts +117 -0
  60. package/dist/install.d.ts.map +1 -0
  61. package/dist/install.js +255 -0
  62. package/dist/install.js.map +1 -0
  63. package/dist/msm-schema.d.ts +76 -0
  64. package/dist/msm-schema.d.ts.map +1 -0
  65. package/dist/msm-schema.js +207 -0
  66. package/dist/msm-schema.js.map +1 -0
  67. package/dist/msm.d.ts +25 -0
  68. package/dist/msm.d.ts.map +1 -0
  69. package/dist/msm.js +317 -0
  70. package/dist/msm.js.map +1 -0
  71. package/dist/session/lib.d.ts +33 -0
  72. package/dist/session/lib.d.ts.map +1 -0
  73. package/dist/session/lib.js +475 -0
  74. package/dist/session/lib.js.map +1 -0
  75. package/dist/session/session-tool.d.ts +17 -0
  76. package/dist/session/session-tool.d.ts.map +1 -0
  77. package/dist/session/session-tool.js +109 -0
  78. package/dist/session/session-tool.js.map +1 -0
  79. package/dist/skills/install-skill.d.ts +36 -0
  80. package/dist/skills/install-skill.d.ts.map +1 -0
  81. package/dist/skills/install-skill.js +91 -0
  82. package/dist/skills/install-skill.js.map +1 -0
  83. package/dist/skills/template-loader.d.ts +79 -0
  84. package/dist/skills/template-loader.d.ts.map +1 -0
  85. package/dist/skills/template-loader.js +170 -0
  86. package/dist/skills/template-loader.js.map +1 -0
  87. package/dist/state.d.ts +35 -0
  88. package/dist/state.d.ts.map +1 -0
  89. package/dist/state.js +62 -0
  90. package/dist/state.js.map +1 -0
  91. package/dist/tui.d.ts +61 -0
  92. package/dist/tui.d.ts.map +1 -0
  93. package/dist/tui.js +279 -0
  94. package/dist/tui.js.map +1 -0
  95. package/dist/types/index.d.ts +30 -0
  96. package/dist/types/index.d.ts.map +1 -0
  97. package/dist/types/index.js +17 -0
  98. package/dist/types/index.js.map +1 -0
  99. package/dist/util/config-patch.d.ts +58 -0
  100. package/dist/util/config-patch.d.ts.map +1 -0
  101. package/dist/util/config-patch.js +117 -0
  102. package/dist/util/config-patch.js.map +1 -0
  103. package/dist/util/git.d.ts +29 -0
  104. package/dist/util/git.d.ts.map +1 -0
  105. package/dist/util/git.js +74 -0
  106. package/dist/util/git.js.map +1 -0
  107. package/dist/util/init-check.d.ts +22 -0
  108. package/dist/util/init-check.d.ts.map +1 -0
  109. package/dist/util/init-check.js +76 -0
  110. package/dist/util/init-check.js.map +1 -0
  111. package/dist/util/init.d.ts +54 -0
  112. package/dist/util/init.d.ts.map +1 -0
  113. package/dist/util/init.js +87 -0
  114. package/dist/util/init.js.map +1 -0
  115. package/dist/util/log.d.ts +25 -0
  116. package/dist/util/log.d.ts.map +1 -0
  117. package/dist/util/log.js +28 -0
  118. package/dist/util/log.js.map +1 -0
  119. package/dist/util/msm-call.d.ts +48 -0
  120. package/dist/util/msm-call.d.ts.map +1 -0
  121. package/dist/util/msm-call.js +86 -0
  122. package/dist/util/msm-call.js.map +1 -0
  123. package/dist/util/msm-exec-runtime.d.ts +123 -0
  124. package/dist/util/msm-exec-runtime.d.ts.map +1 -0
  125. package/dist/util/msm-exec-runtime.js +532 -0
  126. package/dist/util/msm-exec-runtime.js.map +1 -0
  127. package/dist/util/path.d.ts +10 -0
  128. package/dist/util/path.d.ts.map +1 -0
  129. package/dist/util/path.js +21 -0
  130. package/dist/util/path.js.map +1 -0
  131. package/dist/util/ready-state.d.ts +43 -0
  132. package/dist/util/ready-state.d.ts.map +1 -0
  133. package/dist/util/ready-state.js +104 -0
  134. package/dist/util/ready-state.js.map +1 -0
  135. package/dist/util/serenity-file.d.ts +30 -0
  136. package/dist/util/serenity-file.d.ts.map +1 -0
  137. package/dist/util/serenity-file.js +69 -0
  138. package/dist/util/serenity-file.js.map +1 -0
  139. package/dist/util/tui-install.d.ts +61 -0
  140. package/dist/util/tui-install.d.ts.map +1 -0
  141. package/dist/util/tui-install.js +94 -0
  142. package/dist/util/tui-install.js.map +1 -0
  143. package/docs/architecture-v0.md +294 -0
  144. package/docs/contract-v0.md +417 -0
  145. package/docs/plugin-self-contained-msm-v1.md +182 -0
  146. package/docs/refactor-direction-v1.11.md +78 -0
  147. package/docs/requirements-v0-scope.md +104 -0
  148. package/docs/requirements-v0-summary.md +108 -0
  149. package/docs/rr7-init-design.md +304 -0
  150. package/docs/v0.1-candidates.md +132 -0
  151. package/package.json +54 -0
@@ -0,0 +1,104 @@
1
+ /**
2
+ * ReadyStateMachine — 两阶段 init 的状态机
3
+ *
4
+ * 参考 skillful 的 ReadyStateMachine.ts(91 行)。
5
+ *
6
+ * 阶段 1(同步):plugin 入口立即返回 hooks;tools 立即可调用
7
+ * 阶段 2(异步):后台做 IO 验证(RR1+RR2);验证完成前 tool execute 阻塞等待
8
+ *
9
+ * 状态流转:
10
+ * idle → loading → ready (成功)
11
+ * → error (IO 失败)
12
+ * → disabled (条件不满足)
13
+ *
14
+ * 一次性 Promise:`whenReady()` 多次调用返回同一 Promise(不重复创建)。
15
+ */
16
+ export class ReadyStateMachine {
17
+ current = "idle";
18
+ promise = null;
19
+ resolveFn = null;
20
+ rejectFn = null;
21
+ errorValue = null;
22
+ /** 当前状态(同步读)*/
23
+ get state() {
24
+ return this.current;
25
+ }
26
+ /** 状态对应的 reason(error/disabled 时)*/
27
+ get reason() {
28
+ return this.errorValue;
29
+ }
30
+ /**
31
+ * 启动后台验证。
32
+ * 多次调用安全:只有第一次会真正启动(之后的调用复用同一 Promise)。
33
+ */
34
+ start(loader) {
35
+ if (this.current === "loading") {
36
+ return this.promise;
37
+ }
38
+ if (this.current !== "idle") {
39
+ // 已 settled,直接 resolve 或 reject
40
+ return this.current === "ready"
41
+ ? Promise.resolve()
42
+ : Promise.reject(this.errorValue ?? new Error("unknown"));
43
+ }
44
+ this.current = "loading";
45
+ this.promise = new Promise((resolve, reject) => {
46
+ this.resolveFn = resolve;
47
+ this.rejectFn = reject;
48
+ });
49
+ loader()
50
+ .then(() => {
51
+ this.current = "ready";
52
+ this.resolveFn?.();
53
+ })
54
+ .catch((err) => {
55
+ this.current = "error";
56
+ this.errorValue =
57
+ err instanceof Error ? err : new Error(String(err));
58
+ this.rejectFn?.(this.errorValue);
59
+ });
60
+ return this.promise;
61
+ }
62
+ /** 工具执行前的阻塞等待 */
63
+ whenReady() {
64
+ if (this.current === "ready") {
65
+ return Promise.resolve();
66
+ }
67
+ if (this.current === "error" || this.current === "disabled") {
68
+ return Promise.reject(this.errorValue ?? new Error(`Serenity not active: ${this.current}`));
69
+ }
70
+ if (this.current === "loading" && this.promise) {
71
+ return this.promise;
72
+ }
73
+ // idle(未 start)— 视为 disabled
74
+ return Promise.reject(new Error("Serenity plugin not initialized: state=idle"));
75
+ }
76
+ /** 同步状态查询(不阻塞) */
77
+ isReady() {
78
+ return this.current === "ready";
79
+ }
80
+ /** 强制标记 disabled(不依赖 loader 完成;用于 plugin 入口短路 RR6 失败场景) */
81
+ markDisabled(reason) {
82
+ if (this.current !== "idle")
83
+ return; // 已 settled 不变
84
+ this.current = "disabled";
85
+ this.errorValue = new Error(reason);
86
+ // 不会 resolve 任何 promise(p1 用户可能永远不调用 whenReady)
87
+ }
88
+ /** 外部显式标记 ready(v0 同步激活完成后用;保留 start() 的 Promise 兼容性) */
89
+ markAsReady() {
90
+ if (this.current !== "loading" && this.current !== "idle")
91
+ return;
92
+ this.current = "ready";
93
+ this.resolveFn?.();
94
+ }
95
+ /** 重置(仅测试用) */
96
+ reset() {
97
+ this.current = "idle";
98
+ this.promise = null;
99
+ this.resolveFn = null;
100
+ this.rejectFn = null;
101
+ this.errorValue = null;
102
+ }
103
+ }
104
+ //# sourceMappingURL=ready-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ready-state.js","sourceRoot":"","sources":["../../src/util/ready-state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * /.serenity 文件工具 — RR1 验证 + 实例名读写
3
+ *
4
+ * 文件格式:纯文本,单行,内容 = 实例名
5
+ * 例:文件内容 "home-serenity" → 实例名 = "home-serenity"
6
+ *
7
+ * v1.10:新增 write/remove(RR7 init 用)
8
+ */
9
+ export declare const SERENITY_FILENAME = ".serenity";
10
+ /**
11
+ * 从 git root 读取 /.serenity 文件,trim 后返回实例名
12
+ * @throws SerenityFileNotFoundError 文件不存在
13
+ * @throws SerenityFileEmptyError 文件内容为空
14
+ */
15
+ export declare function readSerenityFile(cwdRoot: string): string;
16
+ /** 判断文件是否存在(不抛错版本,用于 chat.message hook 探测) */
17
+ export declare function serenityFileExists(cwdRoot: string): boolean;
18
+ /**
19
+ * 写 `/.serenity`(创建或覆盖)。
20
+ * 内容 = instanceName + '\n'(保持文件以换行结尾)。
21
+ * v1.10:RR7 init 主路径使用。
22
+ * @throws 如果 cwdRoot 不可写则透传 fs 错误
23
+ */
24
+ export declare function writeSerenityFile(cwdRoot: string, instanceName: string): void;
25
+ /**
26
+ * 删 `/.serenity`(v1.10:RR7 init rollback 用)。
27
+ * 文件不存在(ENOENT)静默忽略;其他错误透传。
28
+ */
29
+ export declare function removeSerenityFile(cwdRoot: string): void;
30
+ //# sourceMappingURL=serenity-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serenity-file.d.ts","sourceRoot":"","sources":["../../src/util/serenity-file.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAE7C;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAgBxD;AAED,8CAA8C;AAC9C,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAO3D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAG7E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAMxD"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * /.serenity 文件工具 — RR1 验证 + 实例名读写
3
+ *
4
+ * 文件格式:纯文本,单行,内容 = 实例名
5
+ * 例:文件内容 "home-serenity" → 实例名 = "home-serenity"
6
+ *
7
+ * v1.10:新增 write/remove(RR7 init 用)
8
+ */
9
+ import { readFileSync, writeFileSync, unlinkSync } from 'node:fs';
10
+ import { join } from 'node:path';
11
+ import { SerenityFileEmptyError, SerenityFileNotFoundError } from '../errors.js';
12
+ export const SERENITY_FILENAME = '.serenity';
13
+ /**
14
+ * 从 git root 读取 /.serenity 文件,trim 后返回实例名
15
+ * @throws SerenityFileNotFoundError 文件不存在
16
+ * @throws SerenityFileEmptyError 文件内容为空
17
+ */
18
+ export function readSerenityFile(cwdRoot) {
19
+ const path = join(cwdRoot, SERENITY_FILENAME);
20
+ let content;
21
+ try {
22
+ content = readFileSync(path, 'utf8');
23
+ }
24
+ catch (err) {
25
+ if (err.code === 'ENOENT') {
26
+ throw new SerenityFileNotFoundError(cwdRoot);
27
+ }
28
+ throw err;
29
+ }
30
+ const name = content.trim();
31
+ if (name === '') {
32
+ throw new SerenityFileEmptyError(path);
33
+ }
34
+ return name;
35
+ }
36
+ /** 判断文件是否存在(不抛错版本,用于 chat.message hook 探测) */
37
+ export function serenityFileExists(cwdRoot) {
38
+ try {
39
+ readFileSync(join(cwdRoot, SERENITY_FILENAME), 'utf8');
40
+ return true;
41
+ }
42
+ catch {
43
+ return false;
44
+ }
45
+ }
46
+ /**
47
+ * 写 `/.serenity`(创建或覆盖)。
48
+ * 内容 = instanceName + '\n'(保持文件以换行结尾)。
49
+ * v1.10:RR7 init 主路径使用。
50
+ * @throws 如果 cwdRoot 不可写则透传 fs 错误
51
+ */
52
+ export function writeSerenityFile(cwdRoot, instanceName) {
53
+ const path = join(cwdRoot, SERENITY_FILENAME);
54
+ writeFileSync(path, instanceName + '\n', 'utf8');
55
+ }
56
+ /**
57
+ * 删 `/.serenity`(v1.10:RR7 init rollback 用)。
58
+ * 文件不存在(ENOENT)静默忽略;其他错误透传。
59
+ */
60
+ export function removeSerenityFile(cwdRoot) {
61
+ try {
62
+ unlinkSync(join(cwdRoot, SERENITY_FILENAME));
63
+ }
64
+ catch (err) {
65
+ if (err.code !== 'ENOENT')
66
+ throw err;
67
+ }
68
+ }
69
+ //# sourceMappingURL=serenity-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serenity-file.js","sourceRoot":"","sources":["../../src/util/serenity-file.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAEjF,MAAM,CAAC,MAAM,iBAAiB,GAAG,WAAW,CAAC;AAE7C;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;IAC9C,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,MAAM,IAAI,yBAAyB,CAAC,OAAO,CAAC,CAAC;QAC/C,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;QAChB,MAAM,IAAI,sBAAsB,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,IAAI,CAAC;QACH,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC,CAAC;QACvD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,YAAoB;IACrE,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;IAC9C,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;AACnD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,IAAI,CAAC;QACH,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAC/C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,GAAG,CAAC;IAClE,CAAC;AACH,CAAC"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Global TUI config auto-registration utility (v1.10.1)
3
+ *
4
+ * 背景:TUI plugin 只在 tui.json 文件里登记的路径下被加载。默认登记在
5
+ * 项目 tui.json(`<project-root>/tui.json`),
6
+ * 这意味着非 serenity 目录下 opencode 找不到 tui.json → plugin 不加载
7
+ * → `Tui(api)` 永不调 → `/serenity-init` slash command 不出现。
8
+ *
9
+ * 修复思路:plugin 在 `Tui(api)` 入口**自检并自安装**到 global TUI config
10
+ * (`$XDG_CONFIG_HOME/opencode/tui.json` 或 `~/.config/opencode/tui.json`)。
11
+ * 之后 opencode 在**任何**目录启动都会加载 plugin → slash command 全局可见。
12
+ *
13
+ * v1.18 统一:薄包装 install.ts 的 writePluginEntry + getGlobalConfigPath
14
+ * - install.ts 已是 XDG + Windows APPDATA 兼容(detectGlobalConfigHome)
15
+ * - install.ts 的 writePluginEntry 原子写、幂等、_plugin_origins 追踪
16
+ * - tui-install.ts 保留 toPluginSpec / getGlobalTuiConfigPath /
17
+ * ensureGlobalTuiPluginRegistration 三个 public 名字(向后兼容 — tests
18
+ * 依赖这些 export 名)
19
+ *
20
+ * 行为差异(v1.18 收口):
21
+ * - 之前 tui-install.ts 仅 XDG;现在 Windows 上走 APPDATA
22
+ * - 这是正确的:tui auto-install 与 bin install 行为对齐
23
+ * - 写盘时 install.ts 会更新 _plugin_origins(opencode 忽略未知 key)
24
+ */
25
+ import { type InstallResult } from '../install.js';
26
+ export type { InstallResult };
27
+ export type InstallOptions = {
28
+ /** Override the config path (for tests). */
29
+ configPath?: string;
30
+ };
31
+ /** 解析 global TUI config 路径(薄包装到 install.ts#getGlobalConfigPath)
32
+ *
33
+ * 优先 `$XDG_CONFIG_HOME/opencode/tui.json`(respects XDG 规范),
34
+ * 回退到 `~/.config/opencode/tui.json`(或 Windows APPDATA)。
35
+ */
36
+ export declare function getGlobalTuiConfigPath(): string;
37
+ /**
38
+ * 把 plugin 文件路径或 `file://` URL 规范化为 `file://` spec。
39
+ *
40
+ * - `file://` URL → realpath → 重新编码
41
+ * - 绝对路径 → realpath → 编码
42
+ * - 相对路径 → 抛错(global registration 必须用绝对路径)
43
+ *
44
+ * 与 opencode `ConfigPlugin.resolvePluginSpec` 对齐,保证两边都把同一个文件
45
+ * 解析到同一个 `file://` URL。
46
+ */
47
+ export declare function toPluginSpec(input: string): string;
48
+ /**
49
+ * 把 plugin path 写入 global tui.json 的 `plugin` 数组(如果尚未存在)。
50
+ *
51
+ * 幂等:plugin path 已在 list 中则 no-op。保留 tui.json 其他字段。
52
+ * 失败返回 `{ changed: false, error }`,**不抛**。
53
+ *
54
+ * v1.18 内部:委托给 install.ts#writePluginEntry(原子写、_plugin_origins 追踪、
55
+ * XDG + APPDATA 兼容),本函数只做 plugin spec 规范化 + 错误包装。
56
+ *
57
+ * @param pluginPath 绝对文件路径或 `file://` URL(如 `dist/tui.js`)
58
+ * @param options configPath 覆盖(仅测试用)
59
+ */
60
+ export declare function ensureGlobalTuiPluginRegistration(pluginPath: string, options?: InstallOptions): InstallResult;
61
+ //# sourceMappingURL=tui-install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui-install.d.ts","sourceRoot":"","sources":["../../src/util/tui-install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,eAAe,CAAC;AAEvB,YAAY,EAAE,aAAa,EAAE,CAAC;AAE9B,MAAM,MAAM,cAAc,GAAG;IAC3B,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUlD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iCAAiC,CAC/C,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,cAAmB,GAC3B,aAAa,CAuBf"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Global TUI config auto-registration utility (v1.10.1)
3
+ *
4
+ * 背景:TUI plugin 只在 tui.json 文件里登记的路径下被加载。默认登记在
5
+ * 项目 tui.json(`<project-root>/tui.json`),
6
+ * 这意味着非 serenity 目录下 opencode 找不到 tui.json → plugin 不加载
7
+ * → `Tui(api)` 永不调 → `/serenity-init` slash command 不出现。
8
+ *
9
+ * 修复思路:plugin 在 `Tui(api)` 入口**自检并自安装**到 global TUI config
10
+ * (`$XDG_CONFIG_HOME/opencode/tui.json` 或 `~/.config/opencode/tui.json`)。
11
+ * 之后 opencode 在**任何**目录启动都会加载 plugin → slash command 全局可见。
12
+ *
13
+ * v1.18 统一:薄包装 install.ts 的 writePluginEntry + getGlobalConfigPath
14
+ * - install.ts 已是 XDG + Windows APPDATA 兼容(detectGlobalConfigHome)
15
+ * - install.ts 的 writePluginEntry 原子写、幂等、_plugin_origins 追踪
16
+ * - tui-install.ts 保留 toPluginSpec / getGlobalTuiConfigPath /
17
+ * ensureGlobalTuiPluginRegistration 三个 public 名字(向后兼容 — tests
18
+ * 依赖这些 export 名)
19
+ *
20
+ * 行为差异(v1.18 收口):
21
+ * - 之前 tui-install.ts 仅 XDG;现在 Windows 上走 APPDATA
22
+ * - 这是正确的:tui auto-install 与 bin install 行为对齐
23
+ * - 写盘时 install.ts 会更新 _plugin_origins(opencode 忽略未知 key)
24
+ */
25
+ import { realpathSync } from 'node:fs';
26
+ import { isAbsolute } from 'node:path';
27
+ import { fileURLToPath, pathToFileURL } from 'node:url';
28
+ import { writePluginEntry, getGlobalConfigPath, PLUGIN_ID, } from '../install.js';
29
+ /** 解析 global TUI config 路径(薄包装到 install.ts#getGlobalConfigPath)
30
+ *
31
+ * 优先 `$XDG_CONFIG_HOME/opencode/tui.json`(respects XDG 规范),
32
+ * 回退到 `~/.config/opencode/tui.json`(或 Windows APPDATA)。
33
+ */
34
+ export function getGlobalTuiConfigPath() {
35
+ return getGlobalConfigPath('tui.json');
36
+ }
37
+ /**
38
+ * 把 plugin 文件路径或 `file://` URL 规范化为 `file://` spec。
39
+ *
40
+ * - `file://` URL → realpath → 重新编码
41
+ * - 绝对路径 → realpath → 编码
42
+ * - 相对路径 → 抛错(global registration 必须用绝对路径)
43
+ *
44
+ * 与 opencode `ConfigPlugin.resolvePluginSpec` 对齐,保证两边都把同一个文件
45
+ * 解析到同一个 `file://` URL。
46
+ */
47
+ export function toPluginSpec(input) {
48
+ let absPath;
49
+ if (input.startsWith('file://')) {
50
+ absPath = realpathSync(fileURLToPath(input));
51
+ }
52
+ else if (isAbsolute(input)) {
53
+ absPath = realpathSync(input);
54
+ }
55
+ else {
56
+ throw new Error(`plugin path must be absolute: ${input}`);
57
+ }
58
+ return pathToFileURL(absPath).href;
59
+ }
60
+ /**
61
+ * 把 plugin path 写入 global tui.json 的 `plugin` 数组(如果尚未存在)。
62
+ *
63
+ * 幂等:plugin path 已在 list 中则 no-op。保留 tui.json 其他字段。
64
+ * 失败返回 `{ changed: false, error }`,**不抛**。
65
+ *
66
+ * v1.18 内部:委托给 install.ts#writePluginEntry(原子写、_plugin_origins 追踪、
67
+ * XDG + APPDATA 兼容),本函数只做 plugin spec 规范化 + 错误包装。
68
+ *
69
+ * @param pluginPath 绝对文件路径或 `file://` URL(如 `dist/tui.js`)
70
+ * @param options configPath 覆盖(仅测试用)
71
+ */
72
+ export function ensureGlobalTuiPluginRegistration(pluginPath, options = {}) {
73
+ const configPath = options.configPath ?? getGlobalTuiConfigPath();
74
+ let spec;
75
+ try {
76
+ spec = toPluginSpec(pluginPath);
77
+ }
78
+ catch (err) {
79
+ const reason = err instanceof Error ? err.message : String(err);
80
+ return { changed: false, configPath, error: `bad plugin path: ${reason}` };
81
+ }
82
+ const absPath = fileURLToPath(spec);
83
+ const result = writePluginEntry(configPath, [{
84
+ id: PLUGIN_ID,
85
+ path: spec,
86
+ absPath,
87
+ }]);
88
+ return {
89
+ changed: result.changed,
90
+ configPath: result.configPath,
91
+ ...(result.error !== undefined ? { error: result.error } : {}),
92
+ };
93
+ }
94
+ //# sourceMappingURL=tui-install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui-install.js","sourceRoot":"","sources":["../../src/util/tui-install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,SAAS,GAEV,MAAM,eAAe,CAAC;AASvB;;;;GAIG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO,mBAAmB,CAAC,UAAU,CAAC,CAAC;AACzC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,IAAI,OAAe,CAAC;IACpB,IAAI,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAChC,OAAO,GAAG,YAAY,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;IAC/C,CAAC;SAAM,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,KAAK,CAAC,iCAAiC,KAAK,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,aAAa,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,iCAAiC,CAC/C,UAAkB,EAClB,UAA0B,EAAE;IAE5B,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,sBAAsB,EAAE,CAAC;IAElE,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,oBAAoB,MAAM,EAAE,EAAE,CAAC;IAC7E,CAAC;IAED,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,gBAAgB,CAAC,UAAU,EAAE,CAAC;YAC3C,EAAE,EAAE,SAAS;YACb,IAAI,EAAE,IAAI;YACV,OAAO;SACR,CAAC,CAAC,CAAC;IAEJ,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,GAAG,CAAC,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/D,CAAC;AACJ,CAAC"}