@peterxiaoyang/superspec 0.1.13 → 0.1.14
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/dist/src/init_cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { block, commandExists, GuardError, printDecision, reason, runCommand, openspec_cli_probe, parseDecisionOutputFormat, REQUIRED_OPENSPEC_MIN_VERSION, } from "./core.js";
|
|
2
|
-
import { forced_openspec_install_plan, project_init, recommended_openspec_install_plan } from "./project_init.js";
|
|
2
|
+
import { ensure_openspec_chinese_context, forced_openspec_install_plan, project_init, recommended_openspec_install_plan } from "./project_init.js";
|
|
3
3
|
import { install_workflow, uninstall_workflow, update_workflow } from "./install_engine.js";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import { resolve } from "node:path";
|
|
@@ -320,6 +320,11 @@ function run_init(args, scope) {
|
|
|
320
320
|
summary = engineDecision(`${gatePrefix}_update`, targetRoot, update_workflow(targetRoot, { scope }), [
|
|
321
321
|
scope === "project" ? "review *.new files for user-modified surfaces, then rerun superspec check check-init" : "review *.new files for user-modified user-level surfaces",
|
|
322
322
|
]);
|
|
323
|
+
if (scope === "project" && summary.allowed) {
|
|
324
|
+
const act = ensure_openspec_chinese_context(targetRoot);
|
|
325
|
+
if (Array.isArray(summary.actions))
|
|
326
|
+
summary.actions.push(act);
|
|
327
|
+
}
|
|
323
328
|
}
|
|
324
329
|
else if (scope === "user") {
|
|
325
330
|
summary = engineDecision("user_install", targetRoot, install_workflow(targetRoot, { force: args.force, scope: "user" }), [
|
|
@@ -10,7 +10,7 @@ import { final_verification_evidences, index_evidence, live_pass, live_user_conf
|
|
|
10
10
|
import { file_blob_sha, dirty_worktree_paths } from "./git.js";
|
|
11
11
|
import { preset_upgrade_reasons, preset_upgrade_required_from_context } from "./archive.js";
|
|
12
12
|
import { state_corrupt_reasons, state_stale_reasons } from "./state.js";
|
|
13
|
-
import { parse_tasks, resolve_test_contract_command, splitList, task_apply_execution_surface, task_apply_execution_surface_reasons, test_contract_invariant_refs_by_test, } from "./tasks.js";
|
|
13
|
+
import { parse_tasks, resolve_test_contract_command, splitList, task_apply_execution_surface, task_apply_execution_surface_reasons, tasks_structure_hash, test_contract_invariant_refs_by_test, } from "./tasks.js";
|
|
14
14
|
import { APPLY_CODE_REVIEW_REPORT_REQUIRED_FIELDS, APPLY_EXECUTOR_REPORT_REQUIRED_FIELDS, APPLY_TEST_RUNNER_REPORT_REQUIRED_FIELDS, APPLY_VERIFIER_REPORT_REQUIRED_FIELDS, apply_worker_implementation_fingerprint, apply_worker_executor_input_ref_digest, apply_worker_protected_path_refs, compute_apply_worker_freshness, fingerprint_digest, fingerprint_matches, pinned_artifact_ref_reasons as shared_pinned_artifact_ref_reasons, pre_edit_evidence_ref_reasons, pre_edit_worker_test_run_reasons, read_pinned_artifact_json, worker_input_ref_digest, worker_test_run_reasons, } from "./apply_worker_chain.js";
|
|
15
15
|
import { apply_worker_chain_lifecycle_state } from "./apply_worker_chain_lifecycle.js";
|
|
16
16
|
import { PACKAGE_ROOT } from "./install_engine.js";
|
|
@@ -400,6 +400,14 @@ function workflow_packet(ctx, gateRaw, taskId) {
|
|
|
400
400
|
diagnostic_command: gate_recheck_command(ctx.change, gate, taskId, true),
|
|
401
401
|
must_read_refs: workflow_gate_refs(ctx, gate),
|
|
402
402
|
};
|
|
403
|
+
// Surface tasks_structure_hash directly in the agent-facing packet so apply_isolation and
|
|
404
|
+
// scope_expansion human confirmations can be constructed without a second status/json detour
|
|
405
|
+
// or source-code inspection to find the current tasks.md structural fingerprint.
|
|
406
|
+
if (gate === "apply_ready" || gate === "task_edit" || gate === "task_complete" || gate === "task_reopen") {
|
|
407
|
+
const currentTasksStructureHash = tasks_structure_hash(ctx.changeRoot);
|
|
408
|
+
if (currentTasksStructureHash)
|
|
409
|
+
packet.tasks_structure_hash = currentTasksStructureHash;
|
|
410
|
+
}
|
|
403
411
|
const cliSurfaces = openspec_cli_surfaces_for_gate(ctx.change, gate);
|
|
404
412
|
if (cliSurfaces.length > 0)
|
|
405
413
|
packet.openspec_cli_surfaces = cliSurfaces;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export type PacketOutputFormat = "agent" | "prompt";
|
|
2
2
|
export type PinnedRef = {
|
|
3
|
-
root: "repo" | "change";
|
|
3
|
+
root: "repo" | "change" | "superspec";
|
|
4
4
|
path: string;
|
|
5
5
|
blob_sha: string;
|
|
6
6
|
};
|
|
@@ -19,6 +19,7 @@ export type WorkflowPacket = {
|
|
|
19
19
|
current_gate: string;
|
|
20
20
|
task_id?: string;
|
|
21
21
|
status: "allowed" | "blocked";
|
|
22
|
+
tasks_structure_hash?: string;
|
|
22
23
|
top_blockers?: string[];
|
|
23
24
|
blocker_count?: number;
|
|
24
25
|
has_more_blockers?: boolean;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type JsonMap, type OpenspecCliProbe } from "./core.ts";
|
|
2
|
+
import { type EngineAction } from "./install_engine.ts";
|
|
2
3
|
export declare const OPENSPEC_NPM_PACKAGE = "@fission-ai/openspec";
|
|
3
4
|
export declare const OPENSPEC_INSTALL_DOC_URL = "https://github.com/Fission-AI/OpenSpec#readme";
|
|
4
5
|
export type OpenspecInstallPlan = {
|
|
@@ -26,6 +27,7 @@ export declare function openspec_cli_requirement_message(probe: OpenspecCliProbe
|
|
|
26
27
|
cwd?: string;
|
|
27
28
|
}) => boolean;
|
|
28
29
|
}): string;
|
|
30
|
+
export declare function ensure_openspec_chinese_context(repoRoot: string): EngineAction;
|
|
29
31
|
export declare function project_init(repoRootRaw?: string, opts?: {
|
|
30
32
|
force?: boolean;
|
|
31
33
|
}): JsonMap;
|
package/dist/src/project_init.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { join, resolve } from "node:path";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
3
|
import { REQUIRED_SUPERSPEC_AGENT_ROLES, REQUIRED_OPENSPEC_MIN_VERSION, block, commandExists, openspec_cli_probe, reason, read_agent_toml_name, } from "./core.js";
|
|
4
4
|
import { install_workflow } from "./install_engine.js";
|
|
5
5
|
export const OPENSPEC_NPM_PACKAGE = "@fission-ai/openspec";
|
|
@@ -136,9 +136,33 @@ function ensureSuperSpecWorkflow(repoRoot, actions, force) {
|
|
|
136
136
|
}
|
|
137
137
|
return result.problems;
|
|
138
138
|
}
|
|
139
|
+
const OPENSPEC_CONFIG_REL = "openspec/config.yaml";
|
|
140
|
+
const ZH_CTX = '所有文档必须使用中文编写。需求描述应使用"应当"或"必须"等词汇。';
|
|
141
|
+
export function ensure_openspec_chinese_context(repoRoot) {
|
|
142
|
+
const p = join(repoRoot, OPENSPEC_CONFIG_REL);
|
|
143
|
+
if (existsSync(p) && statSync(p).isFile()) {
|
|
144
|
+
const t = readFileSync(p, "utf8");
|
|
145
|
+
if (/context:[\s\S]*?所有文档必须使用中文/u.test(t))
|
|
146
|
+
return { action: `configure ${OPENSPEC_CONFIG_REL}`, status: "ok", detail: "OpenSpec 中文语境已存在" };
|
|
147
|
+
if (/^context:/mu.test(t)) {
|
|
148
|
+
const u = t.replace(/^context:\s*[|>]?\s*\n(?:[ \t].*\n)*/mu, `context: |\n ${ZH_CTX}\n`);
|
|
149
|
+
mkdirSync(dirname(p), { recursive: true });
|
|
150
|
+
writeFileSync(p, u, "utf8");
|
|
151
|
+
return { action: `configure ${OPENSPEC_CONFIG_REL}`, status: "updated", detail: "OpenSpec context 已替换为简体中文语境" };
|
|
152
|
+
}
|
|
153
|
+
const s = t.endsWith("\n") ? "\ncontext: |\n" : "\n\ncontext: |\n";
|
|
154
|
+
mkdirSync(dirname(p), { recursive: true });
|
|
155
|
+
writeFileSync(p, `${t}${s} ${ZH_CTX}\n`, "utf8");
|
|
156
|
+
return { action: `configure ${OPENSPEC_CONFIG_REL}`, status: "updated", detail: "OpenSpec context 已追加简体中文语境" };
|
|
157
|
+
}
|
|
158
|
+
mkdirSync(dirname(p), { recursive: true });
|
|
159
|
+
writeFileSync(p, `context: |\n ${ZH_CTX}\n`, "utf8");
|
|
160
|
+
return { action: `configure ${OPENSPEC_CONFIG_REL}`, status: "created", detail: "OpenSpec 输出语言已设为简体中文" };
|
|
161
|
+
}
|
|
139
162
|
export function project_init(repoRootRaw = process.cwd(), opts = {}) {
|
|
140
163
|
const repoRoot = resolve(repoRootRaw);
|
|
141
164
|
const actions = [];
|
|
165
|
+
actions.push(ensure_openspec_chinese_context(repoRoot));
|
|
142
166
|
const problems = [
|
|
143
167
|
...ensureOpenSpecCliSurface(repoRoot, actions),
|
|
144
168
|
...ensureSuperSpecWorkflow(repoRoot, actions, opts.force === true),
|
package/package.json
CHANGED
|
@@ -22,7 +22,7 @@ metadata:
|
|
|
22
22
|
|
|
23
23
|
## 阶段职责
|
|
24
24
|
|
|
25
|
-
Propose 把 discovery 转成 OpenSpec proposal package
|
|
25
|
+
Propose 把 discovery 转成 OpenSpec proposal package,并按阶段生成 SuperSpec 业务约束和测试契约辅助文档。负责产出 `proposal.md`、`specs/**/*.md`、`design.md`、`tasks.md`,以及在需要时新建或更新 `.superspec/artifacts/business-invariants.md`、`.superspec/artifacts/test-contract.md`。本阶段不改实现代码。
|
|
26
26
|
|
|
27
27
|
## 第一条必跑命令
|
|
28
28
|
|
|
@@ -49,7 +49,10 @@ openspec instructions <artifact-id> --change "<change>" --json
|
|
|
49
49
|
1. 运行 `openspec status --change "<change>" --json`,取 artifact 顺序、状态和 `resolvedOutputPath`。
|
|
50
50
|
2. 每个 artifact(proposal/specs/design/tasks)运行 `openspec instructions <artifact-id> --change "<change>" --json`,取回 template/rules/context/instruction/dependencies。
|
|
51
51
|
3. 先读 dependencies 列出的已完成 artifact,再按 template 写到 `resolvedOutputPath`;context/rules 是对作者的约束,不写进产出文件。
|
|
52
|
-
4.
|
|
52
|
+
4. 辅助文档(`.superspec/artifacts/business-invariants.md`、`.superspec/artifacts/test-contract.md`)如果尚不存在,就按 SuperSpec 内置模板在 change 内 `.superspec/artifacts/` 新建;已存在则基于当前阶段要求更新。
|
|
53
|
+
5. `invariants_reviewed` 的 `workflow-packet` 会下发 `business_invariants_template` 与 `business_invariants_rules`;必须按该骨架直接填写,不得改成段落/列表。
|
|
54
|
+
6. `test_contract_drafted` 的 `workflow-packet` 会下发 `test_contract_template` 与 `test_contract_rules`;必须按该骨架直接填写,不得改成段落/列表。
|
|
55
|
+
7. `business-invariants.md` 的 `## Invariants` / `## Mapping` 和 `test-contract.md` 的 `## 测试覆盖矩阵` 必须保持 Markdown 表格,列名原样保留。
|
|
53
56
|
|
|
54
57
|
## Packet 驱动的阶段门
|
|
55
58
|
|