code-workspace-zhuiyi 0.1.0-beta.1
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/.env.example +3 -0
- package/LICENSE +21 -0
- package/README.md +168 -0
- package/README.zh-CN.md +168 -0
- package/artifacts/manifest.json +183 -0
- package/artifacts/templates/USER_GUIDE.template.md +1 -0
- package/artifacts/templates/agents/WORKSPACE_GUARD.md.template +73 -0
- package/artifacts/templates/agents/skills/code-workspace-resolve-branch/SKILL.md +88 -0
- package/artifacts/templates/agents/skills/code-workspace-resolve-branch/evals/evals.json +45 -0
- package/artifacts/templates/claude/commands/code-workspace/add-projects.md +23 -0
- package/artifacts/templates/codex/hooks.json +86 -0
- package/artifacts/templates/codex/skills/code-workspace-add-projects/SKILL.md +28 -0
- package/artifacts/templates/user-guide/en-US.md +97 -0
- package/artifacts/templates/user-guide/zh-CN.md +97 -0
- package/assets/i18n-icon.svg +1 -0
- package/assets/logo-vector.svg +30 -0
- package/assets/request_tip.mp3 +0 -0
- package/assets/session_finish.mp3 +0 -0
- package/bin/code-workspace.js +11 -0
- package/docs/extension-architecture.zh-CN.md +429 -0
- package/docs/extensions.md +64 -0
- package/docs/extensions.zh-CN.md +64 -0
- package/extensions/openspec-workspace/1.0.0/artifacts/claude/SKILL.md +16 -0
- package/extensions/openspec-workspace/1.0.0/artifacts/codex/SKILL.md +16 -0
- package/extensions/openspec-workspace/1.0.0/init.js +54 -0
- package/extensions/openspec-workspace/1.0.0/manifest.json +27 -0
- package/extensions/zhuiyi-jira-mcp/0.1.0/artifacts/claude/server.json +14 -0
- package/extensions/zhuiyi-jira-mcp/0.1.0/artifacts/codex/config.toml +11 -0
- package/extensions/zhuiyi-jira-mcp/0.1.0/init.js +53 -0
- package/extensions/zhuiyi-jira-mcp/0.1.0/lib/archive.js +196 -0
- package/extensions/zhuiyi-jira-mcp/0.1.0/manifest.json +38 -0
- package/extensions/zhuiyi-jira-mcp/0.1.0/release.json +15 -0
- package/package.json +58 -0
- package/schemas/extension-init-context-v1.json +39 -0
- package/schemas/extension-init-result-v1.json +42 -0
- package/schemas/extension-manifest-v1.json +55 -0
- package/schemas/extension-manifest-v2.json +84 -0
- package/schemas/extension-manifest-v3.json +84 -0
- package/spec/extension/v1/specification.en-US.md +171 -0
- package/spec/extension/v1/specification.zh-CN.md +170 -0
- package/src/cli/commands/completion.js +203 -0
- package/src/cli/commands/extension.js +193 -0
- package/src/cli/commands/help.js +36 -0
- package/src/cli/commands/init.js +200 -0
- package/src/cli/commands/monitor.js +62 -0
- package/src/cli/commands/permissions.js +33 -0
- package/src/cli/commands/project-branch-update.js +107 -0
- package/src/cli/commands/project-branch.js +433 -0
- package/src/cli/commands/project.js +259 -0
- package/src/cli/commands/update.js +146 -0
- package/src/cli/commands/workspace.js +24 -0
- package/src/cli/confirmation.js +22 -0
- package/src/cli/parser.js +108 -0
- package/src/cli/registry.js +108 -0
- package/src/cli/renderer.js +20 -0
- package/src/cli/result.js +118 -0
- package/src/cli.js +76 -0
- package/src/core/assets.js +83 -0
- package/src/core/config.js +378 -0
- package/src/core/diagnostics.js +20 -0
- package/src/core/directory-digest.js +34 -0
- package/src/core/doctor.js +115 -0
- package/src/core/errors.js +10 -0
- package/src/core/extension-artifacts-legacy.js +180 -0
- package/src/core/extension-artifacts.js +310 -0
- package/src/core/extensions.js +1216 -0
- package/src/core/fs.js +32 -0
- package/src/core/init-lock-holder.js +30 -0
- package/src/core/init-lock.js +159 -0
- package/src/core/init.js +160 -0
- package/src/core/initializer.js +233 -0
- package/src/core/language.js +102 -0
- package/src/core/managed-files.js +334 -0
- package/src/core/migration.js +68 -0
- package/src/core/permissions/claude.js +92 -0
- package/src/core/permissions/codex.js +126 -0
- package/src/core/permissions/common.js +44 -0
- package/src/core/permissions/index.js +163 -0
- package/src/core/project-branch-update.js +424 -0
- package/src/core/project-configuration.js +55 -0
- package/src/core/project.js +674 -0
- package/src/core/tools.js +34 -0
- package/src/core/transaction.js +132 -0
- package/src/core/validation.js +186 -0
- package/src/i18n/index.js +11 -0
- package/src/i18n/interpolate.js +7 -0
- package/src/i18n/locales/en-US.js +10 -0
- package/src/i18n/locales/zh-CN.js +11 -0
- package/src/i18n/registry.js +42 -0
- package/src/index.js +25 -0
- package/src/init/plan.js +12 -0
- package/src/init/ui.js +61 -0
- package/src/init/wizard.js +97 -0
- package/src/monitor/i18n/index.js +33 -0
- package/src/monitor/i18n/locales/en-US.js +85 -0
- package/src/monitor/i18n/locales/zh-CN.js +79 -0
- package/src/monitor/index.js +344 -0
- package/src/monitor/page.js +118 -0
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
# Code Workspace 扩展架构
|
|
2
|
+
|
|
3
|
+
> 本文是面向维护者的说明性架构文档。Extension Spec 的规范性定义以 `spec/extension/v1/specification.zh-CN.md` 及其引用的 JSON Schema 为准;本文不单独建立兼容性或一致性规则。
|
|
4
|
+
|
|
5
|
+
本文定义 Code Workspace 扩展的基础架构、核心术语、职责边界和最小生命周期协议。它是后续扩展实现与评审的共同基线。
|
|
6
|
+
|
|
7
|
+
本文追求的是一版基础、稳健、务实且完整闭环的架构。它只覆盖当前已经出现并能够验证的需求,不试图一次解决未知的扩展市场、安全沙箱、任意外部副作用或所有配置格式。
|
|
8
|
+
|
|
9
|
+
## 1. 架构目标
|
|
10
|
+
|
|
11
|
+
扩展架构需要同时满足以下目标:
|
|
12
|
+
|
|
13
|
+
- 新增一个使用既有协议能力的扩展时,不修改扩展核心代码和公共 schema。
|
|
14
|
+
- 扩展自行掌握下载、解压、构建、包校验和内容生成等业务知识。
|
|
15
|
+
- Host 统一管理发现、确认、锁、事务、冲突、状态、回滚、升级和卸载。
|
|
16
|
+
- 扩展失败不能向真实 Workspace 留下未经 Host 提交的半成品。
|
|
17
|
+
- Host 能够仅依赖已安装状态完成验证和卸载,不需要再次执行扩展代码。
|
|
18
|
+
- 共享文件中的扩展贡献可以独立安装、升级和移除,不破坏用户、核心或其他扩展的内容。
|
|
19
|
+
- 协议可以通过版本演进补充新的通用能力,但不预先猜测未来扩展类型。
|
|
20
|
+
|
|
21
|
+
架构的核心边界是:
|
|
22
|
+
|
|
23
|
+
> 扩展负责如何准备内容;Host 负责是否允许、提交到哪里、如何提交以及如何撤销。
|
|
24
|
+
|
|
25
|
+
Host 不理解 Jira、npm、tar.gz 或某个具体 Agent 的业务含义,但必须理解并治理扩展产生的可观察副作用。
|
|
26
|
+
|
|
27
|
+
## 2. 非目标
|
|
28
|
+
|
|
29
|
+
基础版明确不解决以下问题:
|
|
30
|
+
|
|
31
|
+
- 不执行来自任意第三方的不可信扩展。
|
|
32
|
+
- 不提供安全沙箱、容器或操作系统级文件和网络隔离。
|
|
33
|
+
- 不提供扩展市场、动态安装扩展包或远程扩展发现。
|
|
34
|
+
- 不提供任意 Workspace 外部副作用及其补偿机制。
|
|
35
|
+
- 不允许扩展自定义卸载脚本。
|
|
36
|
+
- 不负责管理扩展运行后产生的业务数据,例如 Jira 附件。
|
|
37
|
+
- 不提供通用包管理器、通用归档格式或通用构建系统。
|
|
38
|
+
- 不建立扩展之间的依赖、服务发现或调用协议。
|
|
39
|
+
- 不建立可以合并任意文本、JSON、TOML、YAML 或数据库内容的万能 contribution 引擎。
|
|
40
|
+
- 不提供强制覆盖或强制卸载未知本地修改的模式。
|
|
41
|
+
|
|
42
|
+
出现这些真实需求时,应作为独立能力评估,而不是提前加入基础协议。
|
|
43
|
+
|
|
44
|
+
## 3. 信任模型
|
|
45
|
+
|
|
46
|
+
基础版扩展是随 Code Workspace 发布或由 Code Workspace 明确批准的可信代码。
|
|
47
|
+
|
|
48
|
+
这里的“可信”表示 Host 允许该代码以当前用户身份执行,不表示扩展运行在安全沙箱中。普通 Node.js 子进程即使使用受限环境变量、固定工作目录和 staging 参数,仍然不是安全边界。
|
|
49
|
+
|
|
50
|
+
因此需要区分两类约束:
|
|
51
|
+
|
|
52
|
+
- 协议约束:扩展必须只在 Host 提供的 staging 中准备候选制品,不得直接修改真实 Workspace。
|
|
53
|
+
- Host 保证:Host 不会提交未声明、越界、冲突或校验失败的 staging 内容。
|
|
54
|
+
|
|
55
|
+
Host 可以通过不提供真实 Workspace 路径、限制上下文和环境变量来降低误操作风险,但不能据此宣称能够防御恶意扩展。
|
|
56
|
+
|
|
57
|
+
## 4. 核心术语
|
|
58
|
+
|
|
59
|
+
### 4.1 Host
|
|
60
|
+
|
|
61
|
+
Host 是 Code Workspace 中负责扩展生命周期治理的核心实现。Host 发现扩展、验证协议、执行入口、检查候选制品,并将合法结果提交到 Workspace。
|
|
62
|
+
|
|
63
|
+
### 4.2 扩展仓库
|
|
64
|
+
|
|
65
|
+
扩展仓库是 Code Workspace 发布包中用于保存内置扩展的目录集合。基础版不从网络发现或安装扩展定义。
|
|
66
|
+
|
|
67
|
+
### 4.3 扩展包
|
|
68
|
+
|
|
69
|
+
扩展包是一个符合扩展协议的、具有明确 id 和版本的可执行目录:
|
|
70
|
+
|
|
71
|
+
```text
|
|
72
|
+
extensions/<extension-id>/<version>/
|
|
73
|
+
├── manifest.json
|
|
74
|
+
├── init.js
|
|
75
|
+
└── <扩展私有的模板、元数据和辅助代码>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
扩展包包含“如何初始化”的代码和资源,但它本身不是安装到 Workspace 的制品。
|
|
79
|
+
|
|
80
|
+
### 4.4 静态 manifest
|
|
81
|
+
|
|
82
|
+
`manifest.json` 是扩展执行前可读取和验证的静态合同。扩展与 Host 的兼容性由 Extension Spec 版本决定,而不是由任一方的产品版本决定。它声明:
|
|
83
|
+
|
|
84
|
+
- 扩展实现的 Extension Spec 版本、身份和扩展版本;
|
|
85
|
+
- 初始化入口、入口摘要和执行超时;
|
|
86
|
+
- 扩展有意使用的能力,例如网络目标;
|
|
87
|
+
- 可能产生的输出及其最大目标范围;
|
|
88
|
+
- 不同工具选择下哪些输出适用。
|
|
89
|
+
|
|
90
|
+
Host 明确声明自己支持的 Extension Spec 版本集合,只有 manifest 的 `extensionSpecVersion` 属于该集合时才会执行扩展。静态 manifest 用于发现、规划、冲突预检和用户确认。它不描述扩展业务实现,不包含需要由 Host 理解的下载 URL、npm 包信息或归档格式。
|
|
91
|
+
|
|
92
|
+
入口可能继续读取扩展包内的辅助代码、模板和私有元数据,因此仅校验 `init.js` 不能冻结完整执行输入。Host 在规划时还需要计算整个扩展版本目录的规范摘要,并在执行前重新验证,以防 manifest、入口、辅助代码或模板在计划确认后发生变化。
|
|
93
|
+
|
|
94
|
+
### 4.5 初始化入口
|
|
95
|
+
|
|
96
|
+
初始化入口是扩展包提供的可执行程序。基础版使用 Node.js `init.js`,由 Host 以固定协议启动。
|
|
97
|
+
|
|
98
|
+
初始化入口负责准备候选制品并生成初始化结果,不负责持有 Workspace 锁、提交真实文件或写入已安装状态。
|
|
99
|
+
|
|
100
|
+
### 4.6 staging
|
|
101
|
+
|
|
102
|
+
staging 是 Host 为单次扩展执行创建的临时输出目录。扩展的所有候选制品必须先生成在 staging 中。
|
|
103
|
+
|
|
104
|
+
staging 内容在验证和提交前不属于 Workspace,也不代表扩展已经安装。
|
|
105
|
+
|
|
106
|
+
### 4.7 候选制品
|
|
107
|
+
|
|
108
|
+
候选制品是扩展在 staging 中生成、等待 Host 验证和提交的文件、目录或共享内容片段。
|
|
109
|
+
|
|
110
|
+
候选制品只有在 Host 完成校验、提交和后置验证后,才成为已安装制品。
|
|
111
|
+
|
|
112
|
+
### 4.8 contribution
|
|
113
|
+
|
|
114
|
+
contribution 是安装到共享目标中的、由单个扩展拥有的局部内容。共享目标可能同时包含用户、核心和其他扩展的内容,因此不能按普通独占文件整体覆盖或删除。
|
|
115
|
+
|
|
116
|
+
基础版只引入当前确实需要、具有确定合并和移除语义的 contribution 处理能力。
|
|
117
|
+
|
|
118
|
+
### 4.9 初始化结果
|
|
119
|
+
|
|
120
|
+
初始化结果是扩展执行完成后写出的机器可读结果。它只报告本次实际生成了哪些静态声明输出,以及这些输出在 staging 中的来源。
|
|
121
|
+
|
|
122
|
+
初始化结果是扩展的声明,不是最终安装事实。Host 必须独立验证内容并计算摘要。
|
|
123
|
+
|
|
124
|
+
### 4.10 installed manifest
|
|
125
|
+
|
|
126
|
+
installed manifest 是 Host 持久化的最终安装事实,保存在 Workspace 的扩展状态中。它记录实际版本、所有权、目标、Host 计算的摘要和卸载所需的共享 contribution 信息。
|
|
127
|
+
|
|
128
|
+
安装、幂等判断、升级、漂移检查和卸载均以 installed manifest 为依据。静态 manifest 和初始化结果不能替代它。
|
|
129
|
+
|
|
130
|
+
### 4.11 用户数据
|
|
131
|
+
|
|
132
|
+
用户数据是扩展安装完成并运行后,由用户或扩展业务进程产生的内容,例如 `.jira-attachments/`。
|
|
133
|
+
|
|
134
|
+
除非未来引入独立且明确的用户数据协议,否则用户数据不属于安装制品,不写入初始化结果,也不由扩展卸载流程删除。
|
|
135
|
+
|
|
136
|
+
## 5. 扩展与 Host 的职责边界
|
|
137
|
+
|
|
138
|
+
| 事项 | 扩展负责 | Host 负责 |
|
|
139
|
+
|---|---|---|
|
|
140
|
+
| 业务知识 | 下载地址、归档格式、包结构、构建方式、配置内容 | 不理解具体业务 |
|
|
141
|
+
| 执行 | 在 staging 中准备候选制品 | 创建执行环境、传入上下文、控制超时、收集结果 |
|
|
142
|
+
| 能力 | 静态声明有意使用的能力 | 校验、展示、确认和记录能力;基础版不宣称具备 OS 级强制隔离 |
|
|
143
|
+
| 输出目标 | 在静态 manifest 中声明允许目标 | 规范化路径、禁止越界、保护核心目标、检查所有权冲突 |
|
|
144
|
+
| 完整性 | 可执行扩展私有的业务校验 | 独立枚举输出、拒绝额外内容、计算已安装摘要 |
|
|
145
|
+
| Workspace 写入 | 不直接写入 | 独占提交、共享内容合成、状态写入和后置验证 |
|
|
146
|
+
| 事务 | 不实现 | 锁、备份、提交、补偿回滚和清理 |
|
|
147
|
+
| 升级 | 生成新版本候选制品 | 比较旧状态、检查漂移、替换和移除过期制品 |
|
|
148
|
+
| 卸载 | 不提供卸载脚本 | 仅依据 installed manifest 验证和移除 Host 已拥有内容 |
|
|
149
|
+
| 用户数据 | 业务进程可以在运行期产生 | 默认不拥有、不删除 |
|
|
150
|
+
|
|
151
|
+
以下职责不得下沉到扩展:
|
|
152
|
+
|
|
153
|
+
- 获取或释放 Workspace 操作锁;
|
|
154
|
+
- 直接修改 `.code-workspace/ext-manifest.json`;
|
|
155
|
+
- 决定冲突时覆盖其他扩展或用户内容;
|
|
156
|
+
- 绕过 Host 直接提交真实 Workspace;
|
|
157
|
+
- 在卸载时执行任意脚本;
|
|
158
|
+
- 将 Cookie、Token 等秘密写入结果、状态或日志。
|
|
159
|
+
|
|
160
|
+
## 6. 基础版输出模型
|
|
161
|
+
|
|
162
|
+
基础版只支持已经有明确需求和可验证生命周期语义的输出。
|
|
163
|
+
|
|
164
|
+
### 6.1 独占文件
|
|
165
|
+
|
|
166
|
+
一个扩展独占一个 Workspace 相对文件目标。Host 负责:
|
|
167
|
+
|
|
168
|
+
- 拒绝核心保护目标和已被其他扩展拥有的目标;
|
|
169
|
+
- 安装时写入或替换同一扩展的旧版本;
|
|
170
|
+
- 记录文件摘要;
|
|
171
|
+
- 卸载前验证文件未发生未知修改;
|
|
172
|
+
- 验证成功后删除该文件。
|
|
173
|
+
|
|
174
|
+
### 6.2 独占目录
|
|
175
|
+
|
|
176
|
+
一个扩展独占一个 Workspace 相对目录目标。它用于安装包含多个文件的运行时,例如预构建的 Jira MCP 包。
|
|
177
|
+
|
|
178
|
+
Host 将目录视为一个制品,使用规范化目录摘要检测漂移,并通过 staging、备份和 rename 完成可恢复提交。目录摘要算法必须固定路径规则、排序、文件类型和文件内容计算方式。
|
|
179
|
+
|
|
180
|
+
### 6.3 共享文本块
|
|
181
|
+
|
|
182
|
+
扩展提供一个文本片段,Host 使用稳定的扩展 id 和输出 id 标记,将其合成到声明的共享文本目标中。
|
|
183
|
+
|
|
184
|
+
Host 负责:
|
|
185
|
+
|
|
186
|
+
- 标记的生成、唯一性和顺序;
|
|
187
|
+
- 最终文档的必要格式验证;
|
|
188
|
+
- 安装、升级和卸载时保留标记之外的内容;
|
|
189
|
+
- 检测标记丢失、重复或块内容被修改。
|
|
190
|
+
|
|
191
|
+
该能力覆盖当前 Codex TOML 配置需求,但协议不包含 Codex 或 MCP 业务字段。
|
|
192
|
+
|
|
193
|
+
### 6.4 JSON 对象成员
|
|
194
|
+
|
|
195
|
+
扩展提供一个 JSON 值,并在静态 manifest 中声明目标文件和唯一成员位置。Host 只拥有该成员,不拥有整个 JSON 文件。
|
|
196
|
+
|
|
197
|
+
Host 负责:
|
|
198
|
+
|
|
199
|
+
- 验证目标文档和 selector;
|
|
200
|
+
- 拒绝同一位置的未知内容或其他扩展所有权;
|
|
201
|
+
- 保留其他顶层字段和成员;
|
|
202
|
+
- 记录规范化后的已安装值;
|
|
203
|
+
- 卸载时仅移除仍与安装记录一致的成员。
|
|
204
|
+
|
|
205
|
+
该能力覆盖 `.mcp.json` 中单个 MCP server 的需求,但核心不验证 server 的 Jira 业务含义。
|
|
206
|
+
|
|
207
|
+
### 6.5 暂不增加的输出
|
|
208
|
+
|
|
209
|
+
基础版不增加 `remote-archive` 之类的下载型制品。下载和解压是扩展准备候选目录的实现过程,不是 Host 的安装制品语义。
|
|
210
|
+
|
|
211
|
+
基础版也不增加通用 `external-effect` 或 `user-data` 制品。二者尚不具备可验证、可回滚和可卸载的统一语义。
|
|
212
|
+
|
|
213
|
+
现有其他共享能力在迁移期间可以保留兼容处理,但不能据此继续增加与具体工具或扩展同名的公共 artifact 类型。
|
|
214
|
+
|
|
215
|
+
## 7. 静态 manifest 与动态结果
|
|
216
|
+
|
|
217
|
+
静态 manifest 声明最大权限范围。Host 先根据工具选择得到本次适用输出,初始化结果必须完整返回这组适用输出,既不能扩大范围,也不能静默缺失。工具选择使本次输出成为完整静态声明的确定子集。
|
|
218
|
+
|
|
219
|
+
下面是逻辑示例,具体字段名由对应 JSON Schema 固化:
|
|
220
|
+
|
|
221
|
+
```json
|
|
222
|
+
{
|
|
223
|
+
"schemaVersion": 3,
|
|
224
|
+
"extensionSpecVersion": 1,
|
|
225
|
+
"id": "zhuiyi-jira-mcp",
|
|
226
|
+
"version": "0.1.0",
|
|
227
|
+
"entry": "init.js",
|
|
228
|
+
"entrySha256": "<sha256>",
|
|
229
|
+
"timeoutMs": 120000,
|
|
230
|
+
"capabilities": {
|
|
231
|
+
"networkHosts": ["gitee.com", "raw.giteeusercontent.com"]
|
|
232
|
+
},
|
|
233
|
+
"outputs": [
|
|
234
|
+
{
|
|
235
|
+
"id": "runtime",
|
|
236
|
+
"kind": "directory",
|
|
237
|
+
"ownership": "exclusive",
|
|
238
|
+
"target": ".code-workspace/extensions/zhuiyi-jira-mcp/0.1.0"
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"id": "codex-config",
|
|
242
|
+
"kind": "text-block",
|
|
243
|
+
"ownership": "shared",
|
|
244
|
+
"target": ".codex/config.toml",
|
|
245
|
+
"tools": ["codex"]
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"id": "claude-config",
|
|
249
|
+
"kind": "json-member",
|
|
250
|
+
"ownership": "shared",
|
|
251
|
+
"target": ".mcp.json",
|
|
252
|
+
"selector": "/mcpServers/zhuiyi-jira",
|
|
253
|
+
"tools": ["claude"]
|
|
254
|
+
}
|
|
255
|
+
]
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
下载 URL、远程包 SHA-256、归档根目录和包内入口等内容属于 Jira 扩展的私有实现,可以保存在扩展代码或扩展私有元数据中。Host 不解析这些字段。
|
|
260
|
+
|
|
261
|
+
Host 使用独立的临时路径启动扩展:
|
|
262
|
+
|
|
263
|
+
```text
|
|
264
|
+
node init.js --context <context-file> --output <staging-directory> --result <result-file>
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
初始化结果只引用静态输出 id 和 staging 来源,不重新声明真实目标、所有权或摘要:
|
|
268
|
+
|
|
269
|
+
```json
|
|
270
|
+
{
|
|
271
|
+
"schemaVersion": 1,
|
|
272
|
+
"extension": {
|
|
273
|
+
"id": "zhuiyi-jira-mcp",
|
|
274
|
+
"version": "0.1.0"
|
|
275
|
+
},
|
|
276
|
+
"outputs": [
|
|
277
|
+
{ "id": "runtime", "source": "runtime" },
|
|
278
|
+
{ "id": "codex-config", "source": "codex-config.toml" },
|
|
279
|
+
{ "id": "claude-config", "source": "claude-server.json" }
|
|
280
|
+
]
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
这种设计避免扩展执行完成后再扩大目标范围。摘要由 Host 从 staging 实际内容计算,不信任扩展自报摘要。
|
|
285
|
+
|
|
286
|
+
## 8. 完整生命周期
|
|
287
|
+
|
|
288
|
+
### 8.1 安装
|
|
289
|
+
|
|
290
|
+
```text
|
|
291
|
+
发现扩展并验证静态 manifest
|
|
292
|
+
→ 从 Host 支持的 Extension Spec 实现中解析最高扩展版本和适用输出
|
|
293
|
+
→ 检查声明能力、目标范围和已知冲突
|
|
294
|
+
→ 展示计划并确认
|
|
295
|
+
→ 获取 Workspace 操作锁并重新验证计划
|
|
296
|
+
→ 创建 context、staging 和 result 临时路径
|
|
297
|
+
→ 执行 init.js
|
|
298
|
+
→ 验证初始化结果完整匹配本次适用的静态输出
|
|
299
|
+
→ 枚举 staging,拒绝未声明文件、特殊文件、符号链接和路径逃逸
|
|
300
|
+
→ Host 计算文件或目录摘要并验证 contribution
|
|
301
|
+
→ 检查当前 Workspace 所有权和本地漂移
|
|
302
|
+
→ 在单扩展可恢复事务中提交独占制品、共享 contribution 和 installed manifest
|
|
303
|
+
→ 验证完整后置条件
|
|
304
|
+
→ 提交事务、清理 staging、释放锁
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
扩展在提交前失败时,Host 只清理临时目录,真实 Workspace 保持不变。提交阶段失败时,Host 使用备份和补偿操作恢复原状态。
|
|
308
|
+
|
|
309
|
+
这里的事务是文件系统上的可恢复事务,不承诺数据库级的跨文件原子性。
|
|
310
|
+
|
|
311
|
+
### 8.2 幂等安装
|
|
312
|
+
|
|
313
|
+
只有同时满足以下条件时,Host 才能判定扩展已经是目标状态:
|
|
314
|
+
|
|
315
|
+
- 已安装扩展 id、版本和静态 manifest 身份一致;
|
|
316
|
+
- 已安装输出集合与本次计划一致;
|
|
317
|
+
- 所有独占文件和目录摘要一致;
|
|
318
|
+
- 所有共享 contribution 仍存在且与 installed manifest 一致。
|
|
319
|
+
|
|
320
|
+
仅有成功状态记录,不能证明当前 Workspace 仍然正确。
|
|
321
|
+
|
|
322
|
+
### 8.3 升级
|
|
323
|
+
|
|
324
|
+
升级由 Host 视为同一扩展旧状态到新状态的一次事务转换:
|
|
325
|
+
|
|
326
|
+
- 输出 id 是稳定的逻辑所有权键;
|
|
327
|
+
- 新旧同一输出可以替换内容或目标;
|
|
328
|
+
- 新版本不再声明的旧输出需要在验证未漂移后移除;
|
|
329
|
+
- 新增输出按正常冲突规则安装;
|
|
330
|
+
- 任一步骤失败时恢复旧版本制品和旧 installed manifest。
|
|
331
|
+
|
|
332
|
+
扩展不负责读取或修改旧 installed manifest,也不执行卸载脚本。
|
|
333
|
+
|
|
334
|
+
### 8.4 卸载
|
|
335
|
+
|
|
336
|
+
卸载只读取 installed manifest,不读取当前扩展包,也不执行 `init.js`:
|
|
337
|
+
|
|
338
|
+
```text
|
|
339
|
+
读取并验证 installed manifest
|
|
340
|
+
→ 获取 Workspace 操作锁
|
|
341
|
+
→ 验证独占制品和共享 contribution 未发生未知修改
|
|
342
|
+
→ 创建备份并移除扩展拥有的独占制品
|
|
343
|
+
→ 从共享目标中移除该扩展 contribution
|
|
344
|
+
→ 更新 installed manifest
|
|
345
|
+
→ 验证其他内容和用户数据仍然存在
|
|
346
|
+
→ 提交事务并释放锁
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
如果已安装内容发生未知修改,基础版拒绝卸载并给出稳定诊断,不进行猜测性删除。
|
|
350
|
+
|
|
351
|
+
### 8.5 初始化异常与进程中断
|
|
352
|
+
|
|
353
|
+
- `init.js` 超时、异常退出或未生成结果:安装失败,清理 staging。
|
|
354
|
+
- 结果无法解析或扩展身份不一致:安装失败,不提交。
|
|
355
|
+
- 输出缺失、额外、越界或包含不支持的文件类型:安装失败,不提交。
|
|
356
|
+
- Host 进程在提交阶段失败:通过事务备份恢复;若无法完全恢复,必须报告明确的残留状态,不能写入成功记录。
|
|
357
|
+
|
|
358
|
+
## 9. 所有权与状态原则
|
|
359
|
+
|
|
360
|
+
扩展输出的稳定所有权键是:
|
|
361
|
+
|
|
362
|
+
```text
|
|
363
|
+
<extension-id>/<output-id>
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
所有权遵循以下规则:
|
|
367
|
+
|
|
368
|
+
- 独占目标同时只能由一个扩展拥有。
|
|
369
|
+
- 共享目标由 Host 管理多个局部 contribution 的所有权。
|
|
370
|
+
- 静态 manifest 是安装意图,不是已安装事实。
|
|
371
|
+
- 初始化结果是扩展声明,不是可信事实。
|
|
372
|
+
- installed manifest 是 Host 验证后的事实来源。
|
|
373
|
+
- Host 只删除自己记录且仍能验证的内容。
|
|
374
|
+
- 用户数据和未知内容默认保留。
|
|
375
|
+
|
|
376
|
+
installed manifest 至少需要记录:
|
|
377
|
+
|
|
378
|
+
- 扩展 id、版本、静态 manifest 身份和执行时冻结的扩展包摘要;
|
|
379
|
+
- 输出 id、类型、所有权和真实目标;
|
|
380
|
+
- Host 计算的文件或目录摘要;
|
|
381
|
+
- 共享 contribution 的 selector、规范化内容或可验证摘要;
|
|
382
|
+
- 支持幂等、升级和卸载所需的协议版本。
|
|
383
|
+
|
|
384
|
+
installed manifest、日志和诊断不得记录 Cookie、Token 或其他真实凭证。
|
|
385
|
+
|
|
386
|
+
## 10. 协议演进原则
|
|
387
|
+
|
|
388
|
+
“新增扩展不修改核心和 schema”只适用于新扩展完全使用现有协议能力的情况。
|
|
389
|
+
|
|
390
|
+
当出现新的可观察副作用,且 Host 无法使用现有语义安全提交、验证或卸载时,才允许扩展公共协议。例如未来确实需要管理 Workspace 外部资源,就必须先定义其确认、幂等、补偿和卸载语义,再增加新的 Host 能力。
|
|
391
|
+
|
|
392
|
+
协议演进必须满足:
|
|
393
|
+
|
|
394
|
+
- 新能力是跨扩展可复用的副作用语义,而不是某个产品或扩展名称;
|
|
395
|
+
- Host 对该能力具有完整的安装、验证、升级和卸载闭环;
|
|
396
|
+
- schema、实现、错误码、状态和测试一起版本化;
|
|
397
|
+
- Host 以明确集合声明支持的 Extension Spec,扩展声明唯一规范版本;
|
|
398
|
+
- 产品版本和规范版本之间不存在推测性映射;
|
|
399
|
+
- 未知规范或能力安全失败,不进行数值范围猜测。
|
|
400
|
+
|
|
401
|
+
## 11. 当前实现对应关系
|
|
402
|
+
|
|
403
|
+
当前基础实现已经移除 Host 中曾经草拟的下载归档和 Claude MCP 专用输出分支,按以下边界实现:
|
|
404
|
+
|
|
405
|
+
- Jira 扩展的 `init.js` 自行完成下载、固定 SHA-256 校验、安全解压和包结构校验。
|
|
406
|
+
- Host 只接收并提交初始化后产生的独占目录。
|
|
407
|
+
- Claude MCP 配置使用共享 JSON 成员能力,不在核心中保留 MCP server 专用类型。
|
|
408
|
+
- Codex 配置使用共享文本块能力,不在协议中包含 Jira 字段。
|
|
409
|
+
- 目录摘要、目录事务、状态回滚、共享内容重建和卸载验证等通用能力继续由 Host 管理并复用。
|
|
410
|
+
- 现有 installed manifest 的读取和卸载兼容需要单独验证,不能因重构而遗失用户已经安装的内容。
|
|
411
|
+
|
|
412
|
+
## 12. 基础版验收标准
|
|
413
|
+
|
|
414
|
+
基础架构至少需要通过以下事实性验收:
|
|
415
|
+
|
|
416
|
+
1. 新增另一个使用相同文件、目录或 contribution 能力的扩展时,不修改核心分支和公共 schema。
|
|
417
|
+
2. 扩展在初始化任意阶段失败,真实 Workspace 不出现候选制品或成功状态。
|
|
418
|
+
3. 扩展不能通过初始化结果扩大静态 manifest 声明的目标范围。
|
|
419
|
+
4. staging 中存在未声明输出、符号链接、特殊文件或路径逃逸时,Host 拒绝安装。
|
|
420
|
+
5. 已安装摘要由 Host 计算,而不是直接采用扩展报告值。
|
|
421
|
+
6. 独占目标冲突和共享 selector 冲突在提交前失败。
|
|
422
|
+
7. 提交或状态写入失败能够恢复安装前状态。
|
|
423
|
+
8. 重复安装能验证真实 Workspace 后返回幂等结果。
|
|
424
|
+
9. 升级能同时处理保留、新增、替换和移除的输出,并在失败时恢复旧状态。
|
|
425
|
+
10. 卸载不执行扩展代码,并保留用户、核心、其他扩展和运行期用户数据。
|
|
426
|
+
11. 本地未知修改不会被静默覆盖或删除。
|
|
427
|
+
12. Jira MCP 下载、解压和包校验逻辑全部位于 Jira 扩展内部,核心代码和公共 schema 不出现 Jira、MCP、npm、tar.gz 或下载 URL 等领域字段。
|
|
428
|
+
|
|
429
|
+
满足这些条件后,基础版才形成从声明、执行、验证、提交、状态到卸载的完整闭环。
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Built-in Extension Contract
|
|
2
|
+
|
|
3
|
+
Code Workspace extensions are trusted, versioned packages shipped under `extensions/<id>/<semver>/`. The extension process is fault-isolated, but it is not a security sandbox: bundled extension code runs with the current user's operating-system permissions.
|
|
4
|
+
|
|
5
|
+
Each version contains `manifest.json`, `init.js`, and any private templates, metadata, or helper code it needs. The current Host explicitly supports Extension Spec v1, defined in English at `spec/extension/v1/specification.en-US.md` and in Chinese at `spec/extension/v1/specification.zh-CN.md`, with these component schemas:
|
|
6
|
+
|
|
7
|
+
- `schemas/extension-manifest-v3.json`
|
|
8
|
+
- `schemas/extension-init-context-v1.json`
|
|
9
|
+
- `schemas/extension-init-result-v1.json`
|
|
10
|
+
|
|
11
|
+
The static manifest declares its `extensionSpecVersion`, identity, entry hash and timeout, declarative network hosts, and maximum output scope. The Host executes only explicitly supported specification versions; the Code Workspace product version is not an extension compatibility key. Code Workspace freezes the specification version, manifest, entry, and complete extension-version directory digest before confirmation, then verifies them again before execution.
|
|
12
|
+
|
|
13
|
+
The Host starts the entry with independent temporary paths:
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
node init.js --context <context-file> --output <staging-directory> --result <result-file>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The context contains the specification version, extension identity, Workspace display metadata, and selected tools. It does not expose the real Workspace path. The result echoes the same specification version and contains only the extension identity and `{ id, source }` entries. It must return exactly every manifest output applicable to the selected tools; it cannot redefine target, kind, ownership, selector, or digest.
|
|
20
|
+
|
|
21
|
+
The Host recursively validates staging, rejects undeclared content, path escapes, symbolic links, and special files, and independently computes installed file and directory digests. Extensions never write the real Workspace or installed state directly and never provide uninstall code.
|
|
22
|
+
|
|
23
|
+
## Generic output kinds
|
|
24
|
+
|
|
25
|
+
- `file`: one extension-owned Workspace-relative regular file.
|
|
26
|
+
- `directory`: one extension-owned Workspace-relative directory tree containing only regular files and directories.
|
|
27
|
+
- `text-block`: a Host-marked fragment in a shared text file. `format: "toml"` validates both the fragment and the complete composed document.
|
|
28
|
+
- `json-member`: one JSON value owned at a declared JSON Pointer in a shared object document.
|
|
29
|
+
|
|
30
|
+
Exclusive targets cannot overlap core-managed paths or another extension's targets. Shared text blocks can coexist in the same text target. JSON member ownership rejects equal or parent/child selectors. The Host preserves user, core, and other extension content during install, upgrade, rollback, and uninstall.
|
|
31
|
+
|
|
32
|
+
Download protocols, archive formats, package managers, Jira, MCP, and individual Agent products are not public output kinds. An extension may use those details privately to prepare a candidate file or directory in staging. Declarative `networkHosts` are shown in the plan for review; they are not operating-system-level egress enforcement.
|
|
33
|
+
|
|
34
|
+
The installed manifest is the only installation fact. New records contain the installed-record version, Extension Spec version, extension version, frozen package and manifest digests, generic output ownership, Host-computed digests, and shared contribution data. Idempotency verifies both this state and the real Workspace. Upgrade handles retained, added, replaced, and removed outputs in one per-extension recoverable transaction. Uninstall reads only installed state, so it still works when the bundled package or execution specification is absent. Unknown local changes stop upgrade or uninstall; there is no force mode.
|
|
35
|
+
|
|
36
|
+
Previously published installed protocol-v1/v2 records for files, Codex configuration blocks, and Codex Hooks remain readable and uninstallable. They are compatibility state, not new Extension Spec v1 output kinds.
|
|
37
|
+
|
|
38
|
+
`init`, `extension install`, and `extension uninstall` share one non-blocking per-Workspace operation lock. A multi-extension install uses one confirmation boundary and an independent transaction per extension; a failure does not stop later extensions, but the overall command reports failure.
|
|
39
|
+
|
|
40
|
+
## Zhuiyi Jira MCP
|
|
41
|
+
|
|
42
|
+
Install it with:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
code-w extension install zhuiyi-jira-mcp --yes
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The Jira extension privately downloads the pinned Gitee release, verifies its fixed SHA-256, safely extracts it, and validates the npm package name, version, and `dist/index.js` entry inside staging. The archive already contains `dist` and runtime dependencies; initialization never runs `npm install`, `npm ci`, a build, or an archive script.
|
|
49
|
+
|
|
50
|
+
After validation, the Host installs only generic outputs:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
.code-workspace/extensions/zhuiyi-jira-mcp/0.1.0/ # directory
|
|
54
|
+
.codex/config.toml # text-block when Codex is selected
|
|
55
|
+
.mcp.json#/mcpServers/zhuiyi-jira # json-member when Claude is selected
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The generated configuration contains non-secret defaults only. It never persists a Jira cookie, token, email, or password; provide credentials in the environment that launches the Agent, for example:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
export JIRA_COOKIE='JSESSIONID=...; atlassian.xsrf.token=...'
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Downloaded attachments default to `.jira-attachments/` in the Workspace. They are runtime user data, not installation artifacts, and are retained when the extension is upgraded or uninstalled.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# 内置扩展契约
|
|
2
|
+
|
|
3
|
+
Code Workspace 扩展是随发布包提供、位于 `extensions/<id>/<semver>/` 下的可信版本化软件包。扩展进程具有故障隔离,但不是安全沙箱:内置扩展代码仍以当前用户的操作系统权限运行。
|
|
4
|
+
|
|
5
|
+
每个版本包含 `manifest.json`、`init.js`,以及扩展需要的私有模板、元数据或辅助代码。当前 Host 明确支持 Extension Spec v1;中文规范位于 `spec/extension/v1/specification.zh-CN.md`,英文规范位于 `spec/extension/v1/specification.en-US.md`,其组件 schema 为:
|
|
6
|
+
|
|
7
|
+
- `schemas/extension-manifest-v3.json`
|
|
8
|
+
- `schemas/extension-init-context-v1.json`
|
|
9
|
+
- `schemas/extension-init-result-v1.json`
|
|
10
|
+
|
|
11
|
+
静态 manifest 通过 `extensionSpecVersion` 声明扩展实现的开发规范,并声明扩展身份、入口摘要和超时、声明性网络 host,以及最大输出范围。Host 只执行其明确支持的规范版本;Code Workspace 产品版本不参与扩展兼容判断。Code Workspace 在确认前冻结规范版本、manifest、入口和完整扩展版本目录摘要,并在执行前重新验证。
|
|
12
|
+
|
|
13
|
+
Host 使用相互独立的临时路径启动入口:
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
node init.js --context <context-file> --output <staging-directory> --result <result-file>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
context 只包含规范版本、扩展身份、Workspace 显示元数据和所选工具,不提供真实 Workspace 路径。result 回显同一规范版本,并只包含扩展身份和 `{ id, source }`。它必须完整返回本次工具选择所适用的全部 manifest 输出,不能重新声明 target、kind、ownership、selector 或摘要。
|
|
20
|
+
|
|
21
|
+
Host 递归验证 staging,拒绝未声明内容、路径逃逸、符号链接和特殊文件,并独立计算已安装文件或目录摘要。扩展不直接写入真实 Workspace 或 installed 状态,也不提供卸载脚本。
|
|
22
|
+
|
|
23
|
+
## 通用输出类型
|
|
24
|
+
|
|
25
|
+
- `file`:扩展独占的一个 Workspace 相对普通文件。
|
|
26
|
+
- `directory`:扩展独占的一个 Workspace 相对目录树,其中只能包含普通文件和目录。
|
|
27
|
+
- `text-block`:Host 使用稳定标记管理的共享文本片段;`format: "toml"` 会同时验证片段和合成后的完整文档。
|
|
28
|
+
- `json-member`:扩展在共享 JSON 对象文档的声明 JSON Pointer 位置拥有一个值。
|
|
29
|
+
|
|
30
|
+
独占目标不能与核心管理路径或其他扩展目标重叠。多个共享文本块可以共存于同一文本文件;JSON 成员所有权会拒绝相同 selector 及父子 selector。安装、升级、回滚和卸载均保留用户、核心及其他扩展的内容。
|
|
31
|
+
|
|
32
|
+
下载协议、归档格式、包管理器、Jira、MCP 和具体 Agent 产品都不是公共输出类型。扩展可以在私有实现中使用这些知识,在 staging 中准备候选文件或目录。声明的 `networkHosts` 会展示在计划中供用户确认,但不代表操作系统级网络出口强制隔离。
|
|
33
|
+
|
|
34
|
+
installed manifest 是唯一安装事实。新记录包含 installed record 版本、Extension Spec 版本、扩展版本、冻结的扩展包和 manifest 摘要、通用输出所有权、Host 计算的摘要及共享 contribution 数据。幂等判断同时验证状态和真实 Workspace。升级在单扩展可恢复事务中处理保留、新增、替换和移除的输出。卸载只读取 installed 状态,因此扩展包或执行规范已经不存在时仍可工作。发现未知本地修改时,升级或卸载会停止;基础版不提供强制模式。
|
|
35
|
+
|
|
36
|
+
已经发布的 installed protocol v1/v2 文件、Codex 配置块和 Codex Hooks 记录仍可读取和卸载;它们只属于兼容状态,不再是 Extension Spec v1 的新输出类型。
|
|
37
|
+
|
|
38
|
+
`init`、`extension install` 和 `extension uninstall` 共用同一个非阻塞 Workspace 操作锁。多扩展安装只确认一次,每个扩展使用独立事务;单个失败不会阻止后续扩展,但整体命令会报告失败。
|
|
39
|
+
|
|
40
|
+
## Zhuiyi Jira MCP
|
|
41
|
+
|
|
42
|
+
安装:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
code-w extension install zhuiyi-jira-mcp --yes
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Jira 扩展在私有实现中下载固定的 Gitee 发布包,校验固定 SHA-256,安全解压,并在 staging 中验证 npm 包名称、版本和 `dist/index.js` 入口。归档已经包含 `dist` 和运行依赖;初始化不会执行 `npm install`、`npm ci`、构建或归档内脚本。
|
|
49
|
+
|
|
50
|
+
验证完成后,Host 只安装通用输出:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
.code-workspace/extensions/zhuiyi-jira-mcp/0.1.0/ # directory
|
|
54
|
+
.codex/config.toml # 选择 Codex 时的 text-block
|
|
55
|
+
.mcp.json#/mcpServers/zhuiyi-jira # 选择 Claude 时的 json-member
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
生成配置只包含非敏感默认值,不会持久化 Jira Cookie、Token、邮箱或密码。用户需要在启动 Agent 的环境中提供凭证,例如:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
export JIRA_COOKIE='JSESSIONID=...; atlassian.xsrf.token=...'
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
下载附件默认保存在 Workspace 的 `.jira-attachments/`。它是运行期用户数据,不是安装制品,扩展升级或卸载时都会保留。
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: code-workspace-openspec-propose
|
|
3
|
+
description: Create an OpenSpec change for a selected Code Workspace project after resolving and verifying that project's registered scope.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Code Workspace OpenSpec Propose
|
|
7
|
+
|
|
8
|
+
Use this skill only when the user explicitly asks to create an OpenSpec proposal for a project registered in Code Workspace.
|
|
9
|
+
|
|
10
|
+
1. Resolve exactly one target project with `code-w project show "<project-name>" --json` and retain its `location`, `branch`, `type`, and `context` as the working boundary.
|
|
11
|
+
2. Verify that target with `code-w project verify "<project-name>" --json`. If branch reconciliation is required, stop and use the Code Workspace branch-resolution workflow before creating a change.
|
|
12
|
+
3. Change the working directory to the verified project location. Do not create the OpenSpec change in the Workspace registry directory.
|
|
13
|
+
4. Follow the installed OpenSpec propose workflow in that project. Derive a kebab-case change name, create the change, and generate every artifact required for apply.
|
|
14
|
+
5. Report the project name, change name, artifact paths, validation status, and whether the change is ready to implement.
|
|
15
|
+
|
|
16
|
+
Do not modify `.code-workspace/`, do not broaden the request to other registered projects, and do not implement or archive the change unless the user asks.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: code-workspace-openspec-propose
|
|
3
|
+
description: Create an OpenSpec change for a selected Code Workspace project after resolving and verifying that project's registered scope.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Code Workspace OpenSpec Propose
|
|
7
|
+
|
|
8
|
+
Use this skill only when the user explicitly asks to create an OpenSpec proposal for a project registered in Code Workspace.
|
|
9
|
+
|
|
10
|
+
1. Resolve exactly one target project with `code-w project show "<project-name>" --json` and retain its `location`, `branch`, `type`, and `context` as the working boundary.
|
|
11
|
+
2. Verify that target with `code-w project verify "<project-name>" --json`. If branch reconciliation is required, stop and use the Code Workspace branch-resolution workflow before creating a change.
|
|
12
|
+
3. Change the working directory to the verified project location. Do not create the OpenSpec change in the Workspace registry directory.
|
|
13
|
+
4. Follow the installed OpenSpec propose workflow in that project. Derive a kebab-case change name, create the change, and generate every artifact required for apply.
|
|
14
|
+
5. Report the project name, change name, artifact paths, validation status, and whether the change is ready to implement.
|
|
15
|
+
|
|
16
|
+
Do not modify `.code-workspace/`, do not broaden the request to other registered projects, and do not implement or archive the change unless the user asks.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("node:fs");
|
|
4
|
+
const path = require("node:path");
|
|
5
|
+
|
|
6
|
+
function fail(message) {
|
|
7
|
+
process.stderr.write(`${message}\n`);
|
|
8
|
+
process.exitCode = 1;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function option(name) {
|
|
12
|
+
const index = process.argv.indexOf(name);
|
|
13
|
+
return index >= 0 ? process.argv[index + 1] : null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
const contextFile = option("--context");
|
|
18
|
+
const outputRoot = option("--output");
|
|
19
|
+
const resultFile = option("--result");
|
|
20
|
+
if (!contextFile || !outputRoot || !resultFile) throw new Error("Usage: init.js --context <file> --output <directory> --result <file>");
|
|
21
|
+
const context = JSON.parse(fs.readFileSync(contextFile, "utf8"));
|
|
22
|
+
if (context.schemaVersion !== 1 || context.extensionSpecVersion !== 1 || context.extension?.id !== "openspec-workspace" || !Array.isArray(context.tools)) {
|
|
23
|
+
throw new Error("Invalid extension context");
|
|
24
|
+
}
|
|
25
|
+
const definitions = {
|
|
26
|
+
codex: {
|
|
27
|
+
id: "codex-propose-skill",
|
|
28
|
+
source: path.join(__dirname, "artifacts", "codex", "SKILL.md"),
|
|
29
|
+
target: ".codex/skills/code-workspace-openspec-propose/SKILL.md",
|
|
30
|
+
},
|
|
31
|
+
claude: {
|
|
32
|
+
id: "claude-propose-skill",
|
|
33
|
+
source: path.join(__dirname, "artifacts", "claude", "SKILL.md"),
|
|
34
|
+
target: ".claude/skills/code-workspace-openspec-propose/SKILL.md",
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
const outputs = [];
|
|
38
|
+
for (const tool of context.tools) {
|
|
39
|
+
const definition = definitions[tool];
|
|
40
|
+
if (!definition) continue;
|
|
41
|
+
const target = path.join(outputRoot, ...definition.target.split("/"));
|
|
42
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
43
|
+
fs.copyFileSync(definition.source, target);
|
|
44
|
+
outputs.push({ id: definition.id, source: definition.target });
|
|
45
|
+
}
|
|
46
|
+
fs.writeFileSync(resultFile, `${JSON.stringify({
|
|
47
|
+
schemaVersion: 1,
|
|
48
|
+
extensionSpecVersion: 1,
|
|
49
|
+
extension: { id: "openspec-workspace", version: "1.0.0" },
|
|
50
|
+
outputs,
|
|
51
|
+
}, null, 2)}\n`, { mode: 0o600 });
|
|
52
|
+
} catch (error) {
|
|
53
|
+
fail(error.message);
|
|
54
|
+
}
|