@namewta/speculo 0.7.5 → 0.8.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 +4 -5
- package/dist/src/cli.js +18 -13
- package/dist/src/cli.js.map +1 -1
- package/dist/src/config.d.ts +20 -0
- package/dist/src/config.js +94 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.js +56 -27
- package/dist/src/index.js.map +1 -1
- package/dist/src/manifest.d.ts +20 -0
- package/dist/src/manifest.js +57 -0
- package/dist/src/manifest.js.map +1 -0
- package/dist/src/refresh.d.ts +30 -0
- package/dist/src/refresh.js +465 -0
- package/dist/src/refresh.js.map +1 -0
- package/dist/src/structured.d.ts +12 -0
- package/dist/src/structured.js +236 -0
- package/dist/src/structured.js.map +1 -0
- package/package.json +2 -2
- package/template/.speculo/README.md +12 -11
- package/template/.speculo/refresh-contract.json +30 -0
- package/template/canonical/canonical-specdev-goal-plan.md +436 -68
- package/template/skills/github-npm-ops/references/preflight-checklist.md +1 -1
- package/template/skills/source-code-zip/SKILL.md +568 -0
- package/template/skills/source-code-zip/scripts/zip_source_code.js +1363 -0
- package/template/workflows/person/runtime-contract.json +9 -0
- package/template/workflows/specdev/I-init-setup/I-init-setup.md +1 -1
- package/template/workflows/specdev/INDEX.md +7 -8
- package/template/workflows/specdev/common/skills/subagent-delivery/SKILL.md +88 -27
- package/template/workflows/specdev/common/skills/subagent-delivery/references/external-web-subagent.md +121 -9
- package/template/workflows/specdev/common/skills/subagent-delivery/references/native-subagent.md +10 -7
- package/template/workflows/specdev/common/skills/subagent-delivery/references/source-package.md +229 -9
- package/template/workflows/specdev/runtime-contract.json +26 -0
- package/dist/src/migrations.d.ts +0 -23
- package/dist/src/migrations.js +0 -1202
- package/dist/src/migrations.js.map +0 -1
- package/template/commands/migrate-runtime-state.md +0 -43
- package/template/skills/migrate-runtime-state/SKILL.md +0 -93
- package/template/skills/migrate-runtime-state/references/migration-contract.md +0 -64
- package/template/skills/migrate-runtime-state/scripts/migrate-runtime-state.mjs +0 -916
- package/template/skills/source-code-zip-skill/SKILL.md +0 -343
- package/template/skills/source-code-zip-skill/scripts/zip_source_code.py +0 -638
- package/template/workflows/specdev/common/skills/subagent-delivery/references/github-checkpoints.md +0 -24
package/template/workflows/specdev/common/skills/subagent-delivery/references/source-package.md
CHANGED
|
@@ -1,17 +1,237 @@
|
|
|
1
|
-
#
|
|
1
|
+
# External ZIP Package
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
选择 `delivery_channel=external-web` 时加载。本 reference 规定 outbound 与 return ZIP 的目录、内容、打包和持久化合同。它引用 `<Path>{roots.skills}/source-code-zip/SKILL.md</Path>` 及其单文件脚本 `<Path>{roots.skills}/source-code-zip/scripts/zip_source_code.js</Path>`;不得为打包执行 `npm install`,不得用另一套默认归档规则替换它。
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 1. 根目录持久化不变量
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
所有外部交付 ZIP 必须位于项目根目录 `<Path>temp/</Path>` 下,使用以下可迁移布局:
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
```text
|
|
10
|
+
temp/subagent-delivery/{scope-id}/{task-id}/{dispatch-id}/
|
|
11
|
+
├── outbound/
|
|
12
|
+
│ ├── staging/
|
|
13
|
+
│ │ ├── DISPATCH.md
|
|
14
|
+
│ │ ├── MANIFEST.json
|
|
15
|
+
│ │ ├── context/
|
|
16
|
+
│ │ └── source/
|
|
17
|
+
│ ├── {dispatch-id}.outbound.zip
|
|
18
|
+
│ └── {dispatch-id}.outbound.sha256
|
|
19
|
+
├── SESSION.md
|
|
20
|
+
└── inbound/
|
|
21
|
+
└── {attempt-id}/
|
|
22
|
+
├── raw/
|
|
23
|
+
├── staging/
|
|
24
|
+
├── extracted/
|
|
25
|
+
├── {dispatch-id}.return.{attempt-id}.zip
|
|
26
|
+
├── {dispatch-id}.return.{attempt-id}.sha256
|
|
27
|
+
└── ACCEPTANCE.md
|
|
28
|
+
```
|
|
10
29
|
|
|
11
|
-
|
|
30
|
+
`scope-id`、`task-id`、`dispatch-id` 和 `attempt-id` 只使用 `[A-Za-z0-9._-]`,不得包含 `/`、`\`、`..`、盘符、控制字符或用户提供的未清洗路径。
|
|
12
31
|
|
|
13
|
-
|
|
32
|
+
以下位置不能作为最终 locator:操作系统临时目录、`os.tmpdir()`、`/tmp`、`%TEMP%`、浏览器默认瞬时下载目录、provider 会话缓存或聊天附件 URL。可以使用这些机制完成传输,但必须在 dispatch/accept 结束前把原始字节持久化到上述项目内目录。
|
|
14
33
|
|
|
15
|
-
|
|
34
|
+
同一 locator 永不覆盖。发现目标已存在时创建新的 dispatch/attempt;不得使用 source-code-zip 的 `--force` 掩盖标识冲突。dispatch/accept 不自动清理旧包。
|
|
16
35
|
|
|
17
|
-
|
|
36
|
+
## 2. Outbound staging 内容
|
|
37
|
+
|
|
38
|
+
`outbound/staging/` 是由 Lead 主动整理的最小授权树,不是 repository 的无差别镜像。
|
|
39
|
+
|
|
40
|
+
### 必需文件
|
|
41
|
+
|
|
42
|
+
`DISPATCH.md` 至少包含:
|
|
43
|
+
|
|
44
|
+
- dispatch identity、task kind、目标与成功定义;
|
|
45
|
+
- 固定 checkpoint、repository label、branch/workspace label;
|
|
46
|
+
- IN/OUT、已锁定决定、适用合同和依赖 Evidence 摘要;
|
|
47
|
+
- writable/read-only/shared 路径语义;外部通道没有本地写入所有权;
|
|
48
|
+
- 允许的联网域、URL 类型、工具、调用预算和停止条件;
|
|
49
|
+
- 禁止动作、敏感数据边界和 prompt-injection 规则;
|
|
50
|
+
- 按 task kind 定义的返回文件、字段、引用与未验证声明要求;
|
|
51
|
+
- Lead 本地验收将重新执行的检查。
|
|
52
|
+
|
|
53
|
+
`MANIFEST.json` 至少包含:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"schema": "speculo.subagent-delivery.packet/v1",
|
|
58
|
+
"dispatch_id": "...",
|
|
59
|
+
"task_id": "...",
|
|
60
|
+
"task_kind": "implementation|review|research|test-observation",
|
|
61
|
+
"delivery_channel": "external-web",
|
|
62
|
+
"created_at": "RFC-3339",
|
|
63
|
+
"repository_label": "...",
|
|
64
|
+
"branch": "...",
|
|
65
|
+
"base_checkpoint": "...",
|
|
66
|
+
"workspace_state": "clean|authorized-diff|snapshot",
|
|
67
|
+
"authorized_data": [],
|
|
68
|
+
"included": [],
|
|
69
|
+
"excluded": [],
|
|
70
|
+
"source_diff": null,
|
|
71
|
+
"secret_scan": {
|
|
72
|
+
"tool": "...",
|
|
73
|
+
"result": "pass|blocked",
|
|
74
|
+
"notes": "..."
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
归档 SHA-256 不写入归档内部的 `MANIFEST.json`,避免自引用;它写入相邻 `.sha256` 文件并记录到 Dispatch Packet/Evidence。
|
|
80
|
+
|
|
81
|
+
### 可选内容
|
|
82
|
+
|
|
83
|
+
- `context/`:相关 Spec/Ticket/ADR/CONTEXT 摘要、项目 Agent 指令、接口合同、研究问题、已授权网页列表和无秘密的环境说明;
|
|
84
|
+
- `source/`:保持 repository-relative 路径的最小完整源码、直接依赖、schema、测试、构建配置和必要样例;
|
|
85
|
+
- `context/workspace.diff`:仅在用户明确授权发送受保护未提交改动时包含,并在 manifest 记录基线和差异范围;
|
|
86
|
+
- `context/expected-output/`:返回模板或 schema。
|
|
87
|
+
|
|
88
|
+
纯公开网页 research 可以不含 `source/`,但仍需 `DISPATCH.md`、`MANIFEST.json` 和必要 `context/`。implementation/review 若缺少足以独立判断的源码或合同,不得靠 provider 猜测,应返回 blocked 或改用原生通道。
|
|
89
|
+
|
|
90
|
+
## 3. 范围与排除
|
|
91
|
+
|
|
92
|
+
只包含完成任务所需的最小完整信息。默认排除:
|
|
93
|
+
|
|
94
|
+
- 版本控制内部数据与远端凭据;
|
|
95
|
+
- 依赖缓存、虚拟环境、构建产物、覆盖率、日志、数据库、转储和临时文件;
|
|
96
|
+
- 浏览器 profile、cookie、local storage、会话 token、下载历史和截图缓存;
|
|
97
|
+
- 真实用户数据、生产数据、支持工单、邮件、聊天记录和未经授权的内部文档;
|
|
98
|
+
- `.env`、token、API key、cookie、私钥、证书私钥、keystore、验证码、恢复码和密码;
|
|
99
|
+
- 无关源码、无关测试、大型二进制、既有归档和可执行产物。
|
|
100
|
+
|
|
101
|
+
环境说明只保留无真实值的示例。若 source-code-zip 默认安全规则会排除一个确有必要的 YAML、锁文件、媒体或其他文件,优先创建已脱敏的 Markdown/文本摘录并记录原始路径与遗漏影响;不得默认使用 `--no-default-ignore`。无法在不发送敏感/被排除内容的情况下完成任务时,不选择外部通道。
|
|
102
|
+
|
|
103
|
+
使用 repository 已有或可用的 secret scanner 检查 staging;同时人工核对 manifest 与实际文件。无法合理确认没有秘密或真实用户数据时返回 blocked。
|
|
104
|
+
|
|
105
|
+
## 4. 使用 source-code-zip 生成 outbound ZIP
|
|
106
|
+
|
|
107
|
+
先确认 Node.js,再从项目根目录运行。以下示例中的变量必须替换为本次不可变标识:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
node --version
|
|
111
|
+
|
|
112
|
+
DELIVERY_ROOT="temp/subagent-delivery/${SCOPE_ID}/${TASK_ID}/${DISPATCH_ID}"
|
|
113
|
+
STAGING="${DELIVERY_ROOT}/outbound/staging"
|
|
114
|
+
ARCHIVE="${DELIVERY_ROOT}/outbound/${DISPATCH_ID}.outbound.zip"
|
|
115
|
+
ZIP_SCRIPT="speculo/skills/source-code-zip/scripts/zip_source_code.js"
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
若当前执行环境仍位于 template 源树而不是安装后的 workspace,按 `workspace.json` 中 `skills` 根别名的实际解析结果定位脚本,不硬编码另一个根。先创建 `outbound/staging/`、`outbound/` 与后续 inbound attempt 目录,并确认目标 ZIP 不存在。
|
|
119
|
+
|
|
120
|
+
必须先预览:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
node "${ZIP_SCRIPT}" "${STAGING}" \
|
|
124
|
+
--all-files \
|
|
125
|
+
--contents-only \
|
|
126
|
+
--output "${ARCHIVE}" \
|
|
127
|
+
--dry-run \
|
|
128
|
+
--verbose
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
核对预览后,用完全相同的选择参数正式生成:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
node "${ZIP_SCRIPT}" "${STAGING}" \
|
|
135
|
+
--all-files \
|
|
136
|
+
--contents-only \
|
|
137
|
+
--output "${ARCHIVE}"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
这里使用 `--all-files`,因为 staging 已由 Lead 精选,且必须纳入 `DISPATCH.md`、`MANIFEST.json`、patch 和普通项目文件;source-code-zip 的默认 IGNORE 仍然生效。使用 `--contents-only` 使 provider 在 ZIP 根目录直接看到权威文件。
|
|
141
|
+
|
|
142
|
+
禁止:
|
|
143
|
+
|
|
144
|
+
- `--no-default-ignore`;
|
|
145
|
+
- `--force`;
|
|
146
|
+
- 正式命令与 dry-run 使用不同的 include/ignore 选择;
|
|
147
|
+
- 把输出 ZIP 放进 staging;
|
|
148
|
+
- 为运行脚本执行 npm/pnpm/yarn install;
|
|
149
|
+
- 在生成后手工修改 ZIP 而不生成新 dispatch/hash。
|
|
150
|
+
|
|
151
|
+
生成后验证 ZIP 可读取、文件数、总字节数和清单,并计算 SHA-256。可以使用当前平台的可信 SHA-256 工具;仅有 Node.js 时可使用:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
node -e 'const fs=require("fs"),c=require("crypto");const p=process.argv[1],h=c.createHash("sha256"),s=fs.createReadStream(p);s.on("data",d=>h.update(d));s.on("error",e=>{console.error(e.message);process.exit(1)});s.on("end",()=>console.log(h.digest("hex")));' "${ARCHIVE}" \
|
|
155
|
+
> "${DELIVERY_ROOT}/outbound/${DISPATCH_ID}.outbound.sha256"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
在 Packet、`SESSION.md` 和后续 Evidence 中记录 project-relative ZIP locator、size、SHA-256、secret scan、included/excluded 摘要和 workspace diff 摘要。只有完成这些记录后才能上传。
|
|
159
|
+
|
|
160
|
+
## 5. Provider 返回与 return ZIP
|
|
161
|
+
|
|
162
|
+
### Provider 直接下载 ZIP
|
|
163
|
+
|
|
164
|
+
将下载的原始字节保存到唯一的:
|
|
165
|
+
|
|
166
|
+
```text
|
|
167
|
+
temp/subagent-delivery/{scope-id}/{task-id}/{dispatch-id}/inbound/{attempt-id}/raw/
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
先计算原始下载 SHA-256,再检查归档目录。不要在保存前让浏览器自动解压,不要重用 provider 文件名覆盖旧文件。每个 attempt 仍必须产生确定名称的 `{dispatch-id}.return.{attempt-id}.zip`:若原始 ZIP 通过安全检查且已经符合返回结构,保持原始 ZIP 不变并把同一字节复制到确定名称;若结构不符合,先在隔离目录安全解包,只把允许的返回文件放入 inbound staging,再使用 source-code-zip 生成标准 return ZIP。两种情况都保留 `raw/` 中的原始字节、原始 hash 与标准 return ZIP/hash。
|
|
171
|
+
|
|
172
|
+
### Provider 只返回文本或散列文件
|
|
173
|
+
|
|
174
|
+
先原样保存到 `raw/`,再由 Lead 构建 `inbound/{attempt-id}/staging/`:
|
|
175
|
+
|
|
176
|
+
```text
|
|
177
|
+
RETURN.md
|
|
178
|
+
candidate/ # implementation 可选
|
|
179
|
+
PATCH.diff # implementation 可选
|
|
180
|
+
FINDINGS.md # review 可选
|
|
181
|
+
RESEARCH.md # research 可选
|
|
182
|
+
SOURCES.json # research 可选
|
|
183
|
+
CHECKS.md # implementation/test-observation 可选
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
`RETURN.md` 必须标明 `dispatch_id`、`attempt-id`、provider/session locator、原始响应 locator、捕获方式、provider 原始字段与 Lead 补写字段。Lead 补写使用 `captured_by_lead` 标识。
|
|
187
|
+
|
|
188
|
+
使用同一个 source-code-zip Skill 预览并生成:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
RETURN_STAGING="${DELIVERY_ROOT}/inbound/${ATTEMPT_ID}/staging"
|
|
192
|
+
RETURN_ZIP="${DELIVERY_ROOT}/inbound/${ATTEMPT_ID}/${DISPATCH_ID}.return.${ATTEMPT_ID}.zip"
|
|
193
|
+
|
|
194
|
+
node "${ZIP_SCRIPT}" "${RETURN_STAGING}" \
|
|
195
|
+
--all-files \
|
|
196
|
+
--contents-only \
|
|
197
|
+
--output "${RETURN_ZIP}" \
|
|
198
|
+
--dry-run \
|
|
199
|
+
--verbose
|
|
200
|
+
|
|
201
|
+
node "${ZIP_SCRIPT}" "${RETURN_STAGING}" \
|
|
202
|
+
--all-files \
|
|
203
|
+
--contents-only \
|
|
204
|
+
--output "${RETURN_ZIP}"
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
随后生成相邻 `.sha256`。不得用本地重打包抹掉 provider 原始响应或补造其未给出的事实。
|
|
208
|
+
|
|
209
|
+
## 6. 安全检查与解包
|
|
210
|
+
|
|
211
|
+
外部 ZIP 是不可信输入。Lead 必须先枚举中央目录并验证,再解压到本 attempt 的 `extracted/`,绝不直接解压到 repository/worktree。
|
|
212
|
+
|
|
213
|
+
至少拒绝:
|
|
214
|
+
|
|
215
|
+
- 绝对路径、盘符路径、UNC 路径、NUL、空文件名;
|
|
216
|
+
- 规范化后包含 `..`、逃出 extraction root 或使用混淆分隔符的路径;
|
|
217
|
+
- 符号链接、硬链接、设备文件和其他非常规条目;
|
|
218
|
+
- 重复路径、Unicode/大小写规范化冲突、文件与目录同名冲突;
|
|
219
|
+
- 超过 Packet 上限的条目数、单文件大小、总解压大小或压缩比;
|
|
220
|
+
- 未授权的嵌套归档、可执行文件、脚本副作用或秘密材料。
|
|
221
|
+
|
|
222
|
+
安全解包只证明归档结构可接受,不证明内容正确。Lead 仍需对照 dispatch identity、outbound manifest、checkpoint、IN/OUT、返回 schema 和实际 diff;任何外部命令/测试声明保持 `unverified`,直到本地复现。
|
|
223
|
+
|
|
224
|
+
## 7. 版本、修正与清理
|
|
225
|
+
|
|
226
|
+
以下任一变化都生成新的 `dispatch-id`、staging、outbound ZIP 和 hash:
|
|
227
|
+
|
|
228
|
+
- base/source checkpoint;
|
|
229
|
+
- IN/OUT、合同、目标或返回 schema;
|
|
230
|
+
- 发送内容或用户授权范围;
|
|
231
|
+
- provider、数据保留边界、允许域或工具权限。
|
|
232
|
+
|
|
233
|
+
固定输入不变但重新请求答案时生成新的 `attempt-id` 和 return ZIP。任何包都不得覆盖;`ACCEPTANCE.md` 记录 accepted/rejected/blocked、Lead 本地验证、未验证项和恢复条件。
|
|
234
|
+
|
|
235
|
+
`temp/subagent-delivery/` 是持久化交付证据,不在 dispatch/accept 中自动删除。清理必须由 Lead 在任务外显式决定,并确保调用方 Evidence 不再依赖唯一 locator。
|
|
236
|
+
|
|
237
|
+
**完成标准**:每个外部输入与返回都能由 project-relative locator、manifest、size、SHA-256、dispatch/attempt identity 和 Lead 验收记录唯一定位;所有 ZIP 均持久化在项目根目录 `temp/` 下。
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"workflow": "specdev",
|
|
4
|
+
"config": {
|
|
5
|
+
"path": ".speculo/specdev/config.json",
|
|
6
|
+
"template": "workflows/specdev/I-init-setup/config-template.json",
|
|
7
|
+
"baseline": ".speculo/baselines/workflows/specdev/config.json",
|
|
8
|
+
"schema_version": 5,
|
|
9
|
+
"optional": true,
|
|
10
|
+
"additional_properties": {
|
|
11
|
+
"": false,
|
|
12
|
+
"git": false,
|
|
13
|
+
"execution": false,
|
|
14
|
+
"verification": true,
|
|
15
|
+
"planning": true
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"structured_state": [
|
|
19
|
+
".speculo/specdev/status.json",
|
|
20
|
+
".speculo/specdev/changes/*/.status.json",
|
|
21
|
+
".speculo/specdev/archive/*/*/.status.json",
|
|
22
|
+
".speculo/specdev/changes/*/goal-plan.md",
|
|
23
|
+
".speculo/specdev/archive/*/*/goal-plan.md"
|
|
24
|
+
],
|
|
25
|
+
"opaque_default": "preserve-byte-for-byte"
|
|
26
|
+
}
|
package/dist/src/migrations.d.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
export type MigrationStatus = "not-required" | "migrated" | "pending";
|
|
2
|
-
export type MigrationBlocker = {
|
|
3
|
-
code: string;
|
|
4
|
-
path: string;
|
|
5
|
-
message: string;
|
|
6
|
-
};
|
|
7
|
-
export type RuntimeMigrationResult = {
|
|
8
|
-
status: MigrationStatus;
|
|
9
|
-
sourceVersion: string | null;
|
|
10
|
-
targetVersion: string;
|
|
11
|
-
backupPath: string | null;
|
|
12
|
-
blockers: MigrationBlocker[];
|
|
13
|
-
};
|
|
14
|
-
export type RuntimeMigrationOptions = {
|
|
15
|
-
packageRoot: string;
|
|
16
|
-
previousRoot: string;
|
|
17
|
-
stagedRoot: string;
|
|
18
|
-
selectedWorkflowIds: string[];
|
|
19
|
-
unselectedWorkflowIds: string[];
|
|
20
|
-
};
|
|
21
|
-
export declare function assertNoPendingMigration(previousRoot: string): Promise<void>;
|
|
22
|
-
export declare function migrateRuntimeState(options: RuntimeMigrationOptions): Promise<RuntimeMigrationResult>;
|
|
23
|
-
export declare function initializeRuntimeManifest(packageRoot: string, stagedRoot: string, workflowIds: string[]): Promise<RuntimeMigrationResult>;
|