@namewta/speculo 1.0.16 → 1.0.17
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 +17 -5
- package/dist/src/agent-files.d.ts +9 -0
- package/dist/src/agent-files.js +106 -0
- package/dist/src/agent-files.js.map +1 -0
- package/dist/src/cli.js +64 -14
- package/dist/src/cli.js.map +1 -1
- package/dist/src/doctor.d.ts +2 -0
- package/dist/src/doctor.js +120 -53
- package/dist/src/doctor.js.map +1 -1
- package/dist/src/external-files.d.ts +22 -0
- package/dist/src/external-files.js +110 -0
- package/dist/src/external-files.js.map +1 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +29 -182
- package/dist/src/index.js.map +1 -1
- package/dist/src/paths.d.ts +12 -0
- package/dist/src/paths.js +57 -0
- package/dist/src/paths.js.map +1 -0
- package/dist/src/transaction.d.ts +27 -0
- package/dist/src/transaction.js +187 -0
- package/dist/src/transaction.js.map +1 -0
- package/dist/src/utils.js +4 -2
- package/dist/src/utils.js.map +1 -1
- package/dist/src/workflows.js +3 -4
- package/dist/src/workflows.js.map +1 -1
- package/package.json +6 -4
- package/template/.speculo/README.md +9 -3
- package/template/.speculo/refresh-contract.json +6 -2
- package/template/AGENTS.md +1 -1
- package/template/commands/docs-sync.md +13 -11
- package/template/skills/archive-and-consolidate/SKILL.md +2 -4
- package/template/skills/docs-sync/SKILL.md +22 -11
- package/template/skills/docs-sync/references/agents-contract.md +6 -4
- package/template/skills/docs-sync/references/document-lifecycle-contract.md +2 -0
- package/template/skills/docs-sync/references/entry-procedure.md +2 -17
- package/template/skills/docs-sync/references/git-state-contract.md +1 -1
- package/template/skills/docs-sync/references/mode-contract.md +21 -0
- package/template/skills/docs-sync/references/workflow-scope-contract.md +5 -3
- package/template/skills/engineering-standards-builder/SKILL.md +3 -1
- package/template/skills/engineering-standards-builder/scripts/validate-builder.mjs +5 -1
- package/template/skills/git-history-squash/SKILL.md +3 -3
- package/template/skills/github-npm-ops/SKILL.md +2 -4
- package/template/skills/source-code-zip/SKILL.md +0 -1
- package/template/skills/speculo-retro/SKILL.md +2 -4
- package/template/skills/upstream-fork-sync/SKILL.md +1 -3
- package/template/skills/writing-great-skills/SKILL.md +3 -3
- package/template/workflows/learning/A-archive/A-archive.md +2 -0
- package/template/workflows/learning/A-assess-and-plan/A-assess-and-plan.md +2 -0
- package/template/workflows/learning/C-consolidate/C-consolidate.md +2 -0
- package/template/workflows/learning/G-goal/G-goal.md +6 -0
- package/template/workflows/learning/G-goal/references/external-goal-runner.md +4 -0
- package/template/workflows/learning/H-homework/H-homework.md +2 -0
- package/template/workflows/learning/L-lesson/L-lesson.md +2 -0
- package/template/workflows/learning/Q-question/Q-question.md +2 -0
- package/template/workflows/learning/R-review/R-review.md +2 -0
- package/template/workflows/learning/README.md +4 -53
- package/template/workflows/learning/common/rules/artifact-layouts.md +46 -0
- package/template/workflows/learning/common/rules/consolidation-contract.md +5 -0
- package/template/workflows/learning/common/rules/homework-contract.md +3 -0
- package/template/workflows/learning/common/rules/lesson-contract.md +7 -0
- package/template/workflows/learning/common/skills/socratic-questioning/SKILL.md +1 -0
- package/template/workflows/learning/common/skills/topic-synthesis/SKILL.md +1 -0
- package/template/workflows/ops/README.md +7 -3
- package/template/workflows/ops/_state/status.json +2 -1
- package/template/workflows/ops/common/USAGE.md +4 -0
- package/template/workflows/ops/common/rules/persistence-and-secrets.md +4 -2
- package/template/workflows/ops/common/schemas/plan.schema.json +4 -0
- package/template/workflows/ops/common/schemas/spec.schema.json +4 -0
- package/template/workflows/ops/common/schemas/status.schema.json +4 -0
- package/template/workflows/ops/common/tests/test_ops.mjs +33 -2
- package/template/workflows/ops/common/tools/opslib/core.mjs +1 -1
- package/template/workflows/ops/common/tools/opslib/docs.mjs +12 -7
- package/template/workflows/ops/common/tools/opslib/planner.mjs +7 -1
- package/template/workflows/specdev/common/rules/path-reference-contract.md +6 -0
- package/template/workflows/specdev/common/skills/code-review/SKILL.md +3 -1
- package/template/workflows/specdev/common/skills/dev-worktree/SKILL.md +1 -0
- package/template/workflows/specdev/common/skills/plan-quality-review/SKILL.md +3 -1
- package/template/workflows/specdev/common/skills/research/SKILL.md +3 -1
- package/template/workflows/specdev/common/skills/subagent-delivery/SKILL.md +1 -0
|
@@ -274,13 +274,13 @@ export function deploymentReadme(status, dep, runId, generatedAt, { ledger = nul
|
|
|
274
274
|
out.push("## 同项目部署位置\n", replicas.sort((a, b) => a.deployment_id < b.deployment_id ? -1 : 1).map((d) => `- ${d.host_id} / ${d.deployment_id}:${code(d.root)}`).join("\n") + "\n");
|
|
275
275
|
if (controller) out.push("\n本目录是部署机的配置、凭据、运行证据和远端文档记录;不声称自动复制了远端业务数据。数据备份需要独立的备份策略和回执。\n");
|
|
276
276
|
if (includeCredentials) out.push(credentialsText(credentialRefs(status, dep), ledger));
|
|
277
|
-
else out.push("\n## 凭据记录\n\
|
|
277
|
+
else out.push("\n## 凭据记录\n\nsecret_ref: " + credentialRefs(status, dep).map(code).join(", ") + "\n\n本文件默认不写密码。凭据按 ID@版本定位受限 private/credentials.json;真实值仅在批准 plaintext_documentation 后导出。未知值不得编造。\n");
|
|
278
278
|
return out.join("\n") + "\n";
|
|
279
279
|
}
|
|
280
280
|
|
|
281
281
|
export function hostReadme(status, hid, runId, at, { ledger = null, full = false, controller = false } = {}) {
|
|
282
282
|
const host = status.hosts[hid];
|
|
283
|
-
const includeCredentials = Boolean(full && controller && ledger);
|
|
283
|
+
const includeCredentials = Boolean(full && controller && ledger && plaintextDocumentation(status));
|
|
284
284
|
const rows = overviewRows(status, hid, { ledger, includeCredentials });
|
|
285
285
|
const out = [
|
|
286
286
|
`# 主机 ${host.display_name} / ${hid}\n`,
|
|
@@ -368,6 +368,11 @@ const KNOWLEDGE_INDEX = `# 共享知识索引
|
|
|
368
368
|
只收录经用户确认、带来源和最后验证时间的知识,不存密码。
|
|
369
369
|
`;
|
|
370
370
|
|
|
371
|
+
// Legacy absent field retains existing deliberate behavior; init seeds false. Changing policy requires a new approved plan.
|
|
372
|
+
export function plaintextDocumentation(status) {
|
|
373
|
+
return status.policies.plaintext_documentation ?? true;
|
|
374
|
+
}
|
|
375
|
+
|
|
371
376
|
export function deliveryBundle(state, plan, status, ledger, verifiedIds) {
|
|
372
377
|
const at = now();
|
|
373
378
|
const rid = plan.run_id;
|
|
@@ -381,9 +386,9 @@ export function deliveryBundle(state, plan, status, ledger, verifiedIds) {
|
|
|
381
386
|
for (const did of [...new Set(verifiedIds)].sort()) {
|
|
382
387
|
const d = status.deployments[did];
|
|
383
388
|
const hid = d.host_id;
|
|
384
|
-
const readme = deploymentReadme(status, d, rid, at, { ledger, includeCredentials: status.policies.server_readme_credentials });
|
|
389
|
+
const readme = deploymentReadme(status, d, rid, at, { ledger, includeCredentials: Boolean(status.policies.server_readme_credentials && plaintextDocumentation(status)) });
|
|
385
390
|
addRemote(hid, pathFor(status, d, "README.md"), readme);
|
|
386
|
-
const operations = deploymentReadme(status, d, rid, at, { ledger, includeCredentials:
|
|
391
|
+
const operations = deploymentReadme(status, d, rid, at, { ledger, includeCredentials: plaintextDocumentation(status) });
|
|
387
392
|
if (status.policies.server_operations) addRemote(hid, pathFor(status, d, "OPERATIONS.md"), operations);
|
|
388
393
|
addRemote(hid, pathFor(status, d, "project.yaml"), JSON.stringify(d, null, 2) + "\n");
|
|
389
394
|
addRemote(hid, pathFor(status, d, "run/release-state.json"), JSON.stringify({
|
|
@@ -397,7 +402,7 @@ export function deliveryBundle(state, plan, status, ledger, verifiedIds) {
|
|
|
397
402
|
addRemote(hid, targetJoin({ ...status.hosts[hid], root: projectroot }, "README.md"), text);
|
|
398
403
|
}
|
|
399
404
|
const prefix = `hosts/${hid}/deployments/${did}`;
|
|
400
|
-
local[prefix + "/README.md"] = deploymentReadme(status, d, rid, at, { ledger, includeCredentials:
|
|
405
|
+
local[prefix + "/README.md"] = deploymentReadme(status, d, rid, at, { ledger, includeCredentials: plaintextDocumentation(status), controller: true });
|
|
401
406
|
local[prefix + "/OPERATIONS.md"] = operations;
|
|
402
407
|
local[prefix + "/deployment.json"] = JSON.stringify(d, null, 2) + "\n";
|
|
403
408
|
local[prefix + "/server/README.md"] = readme;
|
|
@@ -420,8 +425,8 @@ export function deliveryBundle(state, plan, status, ledger, verifiedIds) {
|
|
|
420
425
|
local[`hosts/${hid}/knowledge/host-services.json`] = hostServicesDocument(h);
|
|
421
426
|
if (ingressJson) local[`hosts/${hid}/knowledge/public-ingress.json`] = ingressJson;
|
|
422
427
|
}
|
|
423
|
-
local["FLEET-DEPLOYMENTS.md"] = fleetDocument(status, Object.keys(status.hosts), rid, at, { ledger, includeCredentials:
|
|
424
|
-
local["README.md"] = "# OPS 控制端\n\n主机记录位于 hosts/<host_id>/;项目关联位于 status.json;项目部署记录位于 hosts/<host_id>/deployments/<deployment_id
|
|
428
|
+
local["FLEET-DEPLOYMENTS.md"] = fleetDocument(status, Object.keys(status.hosts), rid, at, { ledger, includeCredentials: plaintextDocumentation(status) });
|
|
429
|
+
local["README.md"] = "# OPS 控制端\n\n主机记录位于 hosts/<host_id>/;项目关联位于 status.json;项目部署记录位于 hosts/<host_id>/deployments/<deployment_id>/;总册位于 FLEET-DEPLOYMENTS.md(新安装默认仅引用凭据版本);凭据账本位于 private/credentials.json;执行证据按 host runs / release 保存。主机级入口见 hosts/<id>/knowledge/host-services.json,跨主机公网入口见 knowledge/public-ingress.json。\n\n不得清理此运行态目录来替换静态 workflow。双边文档完成由每次运行 docs-receipt.json 证明。\n";
|
|
425
430
|
local["docs/standards/DEPLOYMENT-STANDARD.md"] = STANDARD;
|
|
426
431
|
if (!existsSync(join(state, "knowledge", "INDEX.md"))) {
|
|
427
432
|
local["knowledge/INDEX.md"] = "# 共享知识索引\n\n只收录经用户批准、带来源与最后验证日期的通用知识。运行时环境和密码不自动提升为共享知识。跨主机入口规范见各主机 knowledge/public-ingress.json。\n";
|
|
@@ -237,6 +237,7 @@ export function compilePlan(state, specPath) {
|
|
|
237
237
|
const current = load(state);
|
|
238
238
|
if (current.controller == null) throw new OpsError("initialize the controller first");
|
|
239
239
|
const after = structuredClone(current);
|
|
240
|
+
if (spec.plaintext_documentation !== undefined) after.policies.plaintext_documentation = spec.plaintext_documentation;
|
|
240
241
|
const ledger = ledgerLoad(state);
|
|
241
242
|
const revisions = spec.resource_updates || {};
|
|
242
243
|
for (const [group, idkey, fixed] of [["hosts", "host_id", ["host_id", "root", "identity", "platform"]], ["projects", "project_id", ["project_id", "kind", "service_type"]]]) {
|
|
@@ -277,7 +278,12 @@ export function compilePlan(state, specPath) {
|
|
|
277
278
|
return op;
|
|
278
279
|
};
|
|
279
280
|
const fileOp = (hostId, did, path, { content = undefined, binary = undefined, mode = undefined } = {}) => {
|
|
280
|
-
const
|
|
281
|
+
const secretBearing = credentialsIn(content ?? "").size > 0;
|
|
282
|
+
const selectedMode = mode ?? (secretBearing ? 0o600 : defaultFileMode(path));
|
|
283
|
+
if ((secretBearing || /(?:^|[\\/])env[\\/]/.test(path)) && (selectedMode & 0o077)) {
|
|
284
|
+
throw new OpsError("secret-bearing config/env mode must be 0600 or stricter; use explicit service ownership, not world-readable secrets");
|
|
285
|
+
}
|
|
286
|
+
const data = { path, mode: selectedMode };
|
|
281
287
|
if (content !== undefined) data.content = content;
|
|
282
288
|
else data.content_b64 = Buffer.from(binary).toString("base64");
|
|
283
289
|
return add(hostId, did, "write", data);
|
|
@@ -116,3 +116,9 @@ SpecDev 不假定运行时一定提供项目根变量。Ticket、Evidence、诊
|
|
|
116
116
|
- 目录引用是否以 `/` 结束且文件引用是否不以 `/` 结束。
|
|
117
117
|
|
|
118
118
|
路径检查通过仅表示引用结构正确,不代表工件语义、需求、设计或实现正确。
|
|
119
|
+
|
|
120
|
+
## 9. 与标准 Skill 的分发边界
|
|
121
|
+
|
|
122
|
+
本文件是 SpecDev 内部动态工件协议,不是通用 Agent Skills 的文件格式规范。独立标准 Skill 的静态 references/assets 使用相对路径;workflow 私有 Skill 声明 compatibility 后继续使用本 Path 合同。已有持久化引用不批量迁移。
|
|
123
|
+
|
|
124
|
+
实际执行前可以使用只读 `speculo resolve <project-root> --path '<Path>{roots.workflows}/specdev/common/tools/validate-specdev.mjs</Path>'` 展开单个指针。解析器先打开字面 workspace 路径,拒绝未知 alias、未替换变量、通配符、越界路径与链接跳转;不执行 shell、不授予文件写入权限。完整命令由已获授权调用方使用参数数组构造,不把 Path 标记或用户文本直接交给 shell。
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: code-review
|
|
3
3
|
description: 从不可变固定点对本地 diff 执行隔离的标准轴与规范轴审查,供独立 C Work 和 I Work 最终审查共同调用。
|
|
4
|
+
compatibility: Requires the owning Speculo workflow and its workspace path resolver.
|
|
5
|
+
metadata: {"speculo-legacy-name": "specdev-code-review"}
|
|
4
6
|
---
|
|
5
7
|
|
|
6
8
|
# SpecDev Code Review
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: dev-worktree
|
|
3
3
|
description: 管理 SpecDev required Ticket 的 Git worktree;创建隔离来源 workspace、固定实现 commit,并由 Lead 在 parent-candidate checkout 验证后推进父分支。
|
|
4
|
+
compatibility: Requires the owning Speculo workflow and its workspace path resolver.
|
|
4
5
|
---
|
|
5
6
|
|
|
6
7
|
# Dev Worktree
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: plan-quality-review
|
|
3
3
|
description: T 发布计划型 Ticket 或 P 发布/重规划 Goal 前检查决策完备、Skill 调用和执行门禁;不执行代码审查或代替用户批准。
|
|
4
|
+
compatibility: Requires the owning Speculo workflow and its workspace path resolver.
|
|
5
|
+
metadata: {"speculo-legacy-name": "specdev-plan-quality-review"}
|
|
4
6
|
---
|
|
5
7
|
|
|
6
8
|
# Plan Quality Review
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: research
|
|
3
3
|
description: 为调用 Work 的具体决定研究外部技术、依赖、标准或未知行为,逐声明返回一手来源、限制与不确定性,由调用方写入其拥有的工件。
|
|
4
|
+
compatibility: Requires the owning Speculo workflow and its workspace path resolver.
|
|
5
|
+
metadata: {"speculo-legacy-name": "specdev-research"}
|
|
4
6
|
---
|
|
5
7
|
|
|
6
8
|
# SpecDev Research
|