@peterxiaoyang/superspec 0.1.4 → 0.1.6

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 (46) hide show
  1. package/adapters/codex/agents/architect.toml +4 -148
  2. package/adapters/codex/agents/code-reviewer.toml +4 -166
  3. package/adapters/codex/agents/critic.toml +5 -106
  4. package/adapters/codex/agents/executor.toml +13 -0
  5. package/adapters/codex/agents/test-engineer.toml +4 -154
  6. package/adapters/codex/agents/test-runner.toml +13 -0
  7. package/adapters/codex/agents/verifier.toml +4 -110
  8. package/adapters/codex/install-map.json +20 -0
  9. package/dist/src/apply_worker_chain.d.ts +57 -0
  10. package/dist/src/apply_worker_chain.js +1188 -0
  11. package/dist/src/cli.js +13 -0
  12. package/dist/src/cli_args.d.ts +13 -1
  13. package/dist/src/cli_args.js +237 -12
  14. package/dist/src/core.d.ts +1 -0
  15. package/dist/src/core.js +1 -0
  16. package/dist/src/evidence.js +152 -0
  17. package/dist/src/gates.d.ts +2 -1
  18. package/dist/src/gates.js +275 -21
  19. package/dist/src/i18n.js +4 -3
  20. package/dist/src/install_engine.d.ts +17 -0
  21. package/dist/src/install_engine.js +125 -2
  22. package/dist/src/packet_measure.d.ts +43 -0
  23. package/dist/src/packet_measure.js +417 -0
  24. package/dist/src/packet_render.d.ts +4 -0
  25. package/dist/src/packet_render.js +1623 -0
  26. package/dist/src/packet_schema.d.ts +56 -0
  27. package/dist/src/packet_schema.js +1 -0
  28. package/dist/src/project_init.js +7 -49
  29. package/dist/src/tasks.d.ts +10 -0
  30. package/dist/src/tasks.js +86 -0
  31. package/dist/src/util.d.ts +11 -3
  32. package/dist/src/util.js +27 -6
  33. package/package.json +2 -2
  34. package/schemas/install-manifest.schema.json +17 -0
  35. package/templates/workflow/prompts/architect.md +16 -109
  36. package/templates/workflow/prompts/code-reviewer.md +20 -134
  37. package/templates/workflow/prompts/critic.md +18 -75
  38. package/templates/workflow/prompts/executor.md +32 -0
  39. package/templates/workflow/prompts/test-engineer.md +16 -126
  40. package/templates/workflow/prompts/test-runner.md +33 -0
  41. package/templates/workflow/prompts/verifier.md +20 -77
  42. package/templates/workflow/skills/superspec-apply/SKILL.md +102 -78
  43. package/templates/workflow/skills/superspec-archive/SKILL.md +41 -37
  44. package/templates/workflow/skills/superspec-explore/SKILL.md +63 -77
  45. package/templates/workflow/skills/superspec-propose/SKILL.md +64 -85
  46. package/templates/workflow/skills/superspec-review/SKILL.md +76 -233
@@ -0,0 +1,56 @@
1
+ export type PacketOutputFormat = "agent" | "prompt";
2
+ export type PinnedRef = {
3
+ root: "repo" | "change";
4
+ path: string;
5
+ blob_sha: string;
6
+ };
7
+ export type FindingSelector = {
8
+ evidence_id: string;
9
+ finding_uid: string;
10
+ evidence_ref: PinnedRef;
11
+ };
12
+ export type DecisionSelector = {
13
+ evidence_id: string;
14
+ decision_scope_key: string;
15
+ evidence_ref: PinnedRef;
16
+ };
17
+ export type WorkflowPacket = {
18
+ stage: string;
19
+ current_gate: string;
20
+ task_id?: string;
21
+ status: "allowed" | "blocked";
22
+ top_blockers?: string[];
23
+ blocker_count?: number;
24
+ has_more_blockers?: boolean;
25
+ next_action: string;
26
+ next_command?: string;
27
+ openspec_cli_surfaces?: string[];
28
+ must_read_refs: PinnedRef[];
29
+ must_read_verbatim_findings?: FindingSelector[];
30
+ must_read_verbatim_decisions?: DecisionSelector[];
31
+ diagnostic_command?: string;
32
+ };
33
+ export type ReviewPacket = {
34
+ consumer: "role" | "main-thread";
35
+ gate: string;
36
+ role: string;
37
+ round: number;
38
+ target_refs: PinnedRef[];
39
+ source_refs: PinnedRef[];
40
+ required_load_refs?: PinnedRef[];
41
+ required_claim_ids?: string[];
42
+ must_read_verbatim_findings?: FindingSelector[];
43
+ must_read_verbatim_decisions?: DecisionSelector[];
44
+ required_output_kind: string;
45
+ output_contract_fields: string[];
46
+ required_review_scope?: string[];
47
+ stop_conditions: string[];
48
+ };
49
+ export type ApplyWorkerPacket = Record<string, any>;
50
+ export type PacketDispatchResult = {
51
+ output_format: "agent";
52
+ payload: WorkflowPacket | ReviewPacket | ApplyWorkerPacket;
53
+ } | {
54
+ output_format: "prompt";
55
+ payload: string;
56
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,8 +1,7 @@
1
1
  import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
2
2
  import { join, resolve } from "node:path";
3
- import { REQUIRED_SUPERSPEC_AGENT_ROLES, REQUIRED_OPENSPEC_CODEX_SKILLS, REQUIRED_OPENSPEC_MIN_VERSION, block, commandExists, openspec_cli_probe, reason, read_agent_toml_name, read_skill_frontmatter_name, runCommand, } from "./core.js";
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
- import { system_failure_zh } from "./i18n.js";
6
5
  export const OPENSPEC_NPM_PACKAGE = "@fission-ai/openspec";
7
6
  export const OPENSPEC_INSTALL_DOC_URL = "https://github.com/Fission-AI/OpenSpec#readme";
8
7
  const ROLE_DESCRIPTIONS = {
@@ -12,9 +11,6 @@ const ROLE_DESCRIPTIONS = {
12
11
  "code-reviewer": "代码 / 规格 / 安全审查",
13
12
  verifier: "最终完成证据与验证审查",
14
13
  };
15
- function commandFailure(proc) {
16
- return system_failure_zh((proc.error?.message ?? (proc.stderr || proc.stdout)).trim(), proc.status !== null && proc.status !== undefined ? `命令执行失败(退出状态码 ${proc.status})。` : "命令执行失败,请查看终端日志后重试。");
17
- }
18
14
  function renderCommand(cmd, args) {
19
15
  return [cmd, ...args].join(" ");
20
16
  }
@@ -59,20 +55,6 @@ export function openspec_cli_requirement_message(probe, opts = {}) {
59
55
  }
60
56
  return `${probe.message}。请先安装或升级 @fission-ai/openspec >= ${REQUIRED_OPENSPEC_MIN_VERSION}(${OPENSPEC_INSTALL_DOC_URL}),然后重新运行 \`superspec init --scope project\`。`;
61
57
  }
62
- function openspecSkillProblems(repoRoot) {
63
- const skillsRoot = join(repoRoot, ".codex", "skills");
64
- const problems = [];
65
- for (const name of REQUIRED_OPENSPEC_CODEX_SKILLS) {
66
- const skillPath = join(skillsRoot, name, "SKILL.md");
67
- if (!existsSync(skillPath) || !statSync(skillPath).isFile()) {
68
- problems.push(name);
69
- continue;
70
- }
71
- if (read_skill_frontmatter_name(skillPath) !== name)
72
- problems.push(name);
73
- }
74
- return problems.sort();
75
- }
76
58
  function writeSuperSpecAgent(repoRoot, name) {
77
59
  const filePath = join(repoRoot, ".codex", "agents", `${name}.toml`);
78
60
  mkdirSync(join(repoRoot, ".codex", "agents"), { recursive: true });
@@ -105,38 +87,14 @@ function writeSuperSpecPrompt(repoRoot, name) {
105
87
  ].join("\n"), "utf8");
106
88
  return filePath;
107
89
  }
108
- function ensureOpenSpecCodex(repoRoot, actions) {
90
+ function ensureOpenSpecCliSurface(repoRoot, actions) {
109
91
  const probe = openspec_cli_probe({ cwd: repoRoot });
110
- if (!probe.ok)
111
- return [openspec_cli_requirement_message(probe, { cwd: repoRoot })];
112
- let problems = openspecSkillProblems(repoRoot);
113
- if (problems.length === 0) {
114
- actions.push({ action: "openspec_codex_skills", status: "ok" });
115
- return [];
116
- }
117
- const init = runCommand("openspec", ["init", "--tools", "codex", "."], { cwd: repoRoot, timeout: 60_000 });
118
- actions.push({
119
- action: "openspec init --tools codex .",
120
- status: init.status === 0 ? "updated" : "failed",
121
- refs: problems,
122
- detail: init.status === 0 ? undefined : commandFailure(init),
123
- });
124
- if (init.error || init.status !== 0)
125
- return [`openspec init 执行失败:${commandFailure(init)}`];
126
- problems = openspecSkillProblems(repoRoot);
127
- if (problems.length === 0)
128
- return [];
129
- const update = runCommand("openspec", ["update", "--force", "."], { cwd: repoRoot, timeout: 60_000 });
130
92
  actions.push({
131
- action: "openspec update --force .",
132
- status: update.status === 0 ? "updated" : "failed",
133
- refs: problems,
134
- detail: update.status === 0 ? undefined : commandFailure(update),
93
+ action: "openspec_cli_surface",
94
+ status: probe.ok ? "ok" : "failed",
95
+ detail: probe.message,
135
96
  });
136
- if (update.error || update.status !== 0)
137
- return [`openspec update 执行失败:${commandFailure(update)}`];
138
- problems = openspecSkillProblems(repoRoot);
139
- return problems.length === 0 ? [] : [`OpenSpec 配套技能文件仍然缺失或无效:${problems.join(", ")}`];
97
+ return probe.ok ? [] : [openspec_cli_requirement_message(probe, { cwd: repoRoot })];
140
98
  }
141
99
  function ensureSuperSpecRoles(repoRoot, actions) {
142
100
  const problems = [];
@@ -182,7 +140,7 @@ export function project_init(repoRootRaw = process.cwd(), opts = {}) {
182
140
  const repoRoot = resolve(repoRootRaw);
183
141
  const actions = [];
184
142
  const problems = [
185
- ...ensureOpenSpecCodex(repoRoot, actions),
143
+ ...ensureOpenSpecCliSurface(repoRoot, actions),
186
144
  ...ensureSuperSpecWorkflow(repoRoot, actions, opts.force === true),
187
145
  ...ensureSuperSpecRoles(repoRoot, actions),
188
146
  ];
@@ -5,12 +5,22 @@ export type TestContractRecord = {
5
5
  scenario_ref: string;
6
6
  invariant_refs: string[];
7
7
  };
8
+ export type TestCommandResolution = {
9
+ test_id: string;
10
+ command: string | null;
11
+ source: "test_command" | "test_command_ref" | null;
12
+ command_ref?: string;
13
+ expected_failure_signature?: string;
14
+ expected_failure_classifier?: string;
15
+ blockers: Reason[];
16
+ };
8
17
  export declare function parse_tasks(changeRoot: string): Record<string, TaskInfo>;
9
18
  export declare function tasks_structure_hash(changeRoot: string): string | null;
10
19
  export declare function splitList(value: string): string[];
11
20
  export declare function parse_test_contract_records(changeRoot: string): TestContractRecord[];
12
21
  export declare function parse_test_contract_ids(changeRoot: string): Set<string>;
13
22
  export declare function test_contract_text(changeRoot: string): string;
23
+ export declare function resolve_test_contract_command(changeRoot: string, testId: string, config?: JsonMap): TestCommandResolution;
14
24
  export declare function parse_spec_scenarios(changeRoot: string): string[];
15
25
  export declare function test_contract_covers_scenario(changeRoot: string, scenario: string): boolean;
16
26
  export declare function test_contract_invariant_refs_by_test(changeRoot: string): Map<string, Set<string>>;
package/dist/src/tasks.js CHANGED
@@ -120,6 +120,92 @@ export function test_contract_text(changeRoot) {
120
120
  return "";
121
121
  return readFileSync(filePath, "utf8");
122
122
  }
123
+ function test_contract_section_lines(changeRoot, testId) {
124
+ const lines = test_contract_text(changeRoot).split(/\r?\n/);
125
+ const start = lines.findIndex((line) => {
126
+ const match = line.trim().match(/^###\s+(\S+)\s*$/);
127
+ return match?.[1] === testId;
128
+ });
129
+ if (start < 0)
130
+ return [];
131
+ const out = [];
132
+ for (const line of lines.slice(start + 1)) {
133
+ if (/^###\s+\S+/.test(line.trim()) || /^##\s+/.test(line.trim()))
134
+ break;
135
+ out.push(line);
136
+ }
137
+ return out;
138
+ }
139
+ function contractField(line) {
140
+ const match = line.match(/^\s*-\s+`?([A-Za-z0-9_-]+)`?\s*:\s*(.*)$/);
141
+ if (!match)
142
+ return null;
143
+ return { key: match[1], value: match[2].trim() };
144
+ }
145
+ export function resolve_test_contract_command(changeRoot, testId, config = {}) {
146
+ const blockers = [];
147
+ const lines = test_contract_section_lines(changeRoot, testId);
148
+ if (lines.length === 0) {
149
+ return { test_id: testId, command: null, source: null, blockers: [reason("missing_test_contract_section", `test contract missing ### ${testId} section`)] };
150
+ }
151
+ const fields = new Map();
152
+ for (const line of lines) {
153
+ const field = contractField(line);
154
+ if (!field)
155
+ continue;
156
+ const values = fields.get(field.key) ?? [];
157
+ values.push(field.value);
158
+ fields.set(field.key, values);
159
+ }
160
+ const commands = fields.get("test_command") ?? [];
161
+ const refs = fields.get("test_command_ref") ?? [];
162
+ if (commands.length === 0 && refs.length === 0)
163
+ blockers.push(reason("missing_test_command", `test contract ${testId} requires exactly one test_command or test_command_ref`));
164
+ if (commands.length > 1 || refs.length > 1)
165
+ blockers.push(reason("duplicate_test_command", `test contract ${testId} has duplicate test command fields`));
166
+ if (commands.length > 0 && refs.length > 0)
167
+ blockers.push(reason("ambiguous_test_command", `test contract ${testId} must not mix test_command and test_command_ref`));
168
+ const expected_failure_signature = (fields.get("expected_failure_signature") ?? [])[0];
169
+ const expected_failure_classifier = (fields.get("expected_failure_classifier") ?? [])[0];
170
+ if (commands.length === 1 && refs.length === 0) {
171
+ const command = commands[0];
172
+ if (!command)
173
+ blockers.push(reason("missing_test_command", `test contract ${testId} has empty test_command`));
174
+ return {
175
+ test_id: testId,
176
+ command: command || null,
177
+ source: command ? "test_command" : null,
178
+ expected_failure_signature,
179
+ expected_failure_classifier,
180
+ blockers,
181
+ };
182
+ }
183
+ if (refs.length === 1 && commands.length === 0) {
184
+ const refValue = refs[0];
185
+ const match = refValue.match(/^config\.commands\.([A-Za-z0-9_.-]+)$/);
186
+ if (!match) {
187
+ blockers.push(reason("untrusted_test_command_ref", `test contract ${testId} test_command_ref must be config.commands.<id>`));
188
+ return { test_id: testId, command: null, source: null, command_ref: refValue, expected_failure_signature, expected_failure_classifier, blockers };
189
+ }
190
+ const commandId = match[1];
191
+ const commandsConfig = config.commands;
192
+ const command = commandsConfig && typeof commandsConfig === "object" ? commandsConfig[commandId] : undefined;
193
+ if (typeof command !== "string" || !command.trim()) {
194
+ blockers.push(reason("untrusted_test_command_ref", `test contract ${testId} test_command_ref ${refValue} does not resolve to config.commands.${commandId}`));
195
+ return { test_id: testId, command: null, source: null, command_ref: refValue, expected_failure_signature, expected_failure_classifier, blockers };
196
+ }
197
+ return {
198
+ test_id: testId,
199
+ command,
200
+ source: "test_command_ref",
201
+ command_ref: refValue,
202
+ expected_failure_signature,
203
+ expected_failure_classifier,
204
+ blockers,
205
+ };
206
+ }
207
+ return { test_id: testId, command: null, source: null, expected_failure_signature, expected_failure_classifier, blockers };
208
+ }
123
209
  export function parse_spec_scenarios(changeRoot) {
124
210
  const specs = join(changeRoot, "specs");
125
211
  const scenarios = [];
@@ -40,6 +40,7 @@ export type Decision = {
40
40
  workflow_terms_zh?: WorkflowTermHint[];
41
41
  };
42
42
  export type DecisionOutputFormat = "json" | "agent" | "user";
43
+ export type PacketOutputFormat = "agent" | "prompt";
43
44
  export type AgentWorkflowAction = "continue" | "fix_artifacts" | "ask_user_confirmation" | "collect_review_evidence" | "collect_test_evidence" | "repair_evidence" | "rerun_check" | "inspect_diagnostics";
44
45
  export type TaskInfo = {
45
46
  task_id: string;
@@ -72,10 +73,10 @@ export declare const TASK_REOPEN_RESOLVED_REQUIRED_FIELDS: readonly ["reopen_evi
72
73
  export declare const TASK_REOPEN_INVALIDITY_CLASSES: readonly ["insufficient_completion_evidence"];
73
74
  export declare const FORBIDDEN_FIELDS: Set<string>;
74
75
  export declare const OPENSPEC_ARTIFACTS: Set<string>;
75
- export declare const REQUIRED_OPENSPEC_CODEX_SKILLS: readonly ["openspec-explore", "openspec-propose", "openspec-apply-change", "openspec-archive-change"];
76
+ export declare const REQUIRED_OPENSPEC_CODEX_SKILLS: readonly [];
76
77
  export declare const REQUIRED_SUPERSPEC_WORKFLOW_SKILLS: readonly ["superspec-explore", "superspec-propose", "superspec-apply", "superspec-review", "superspec-archive"];
77
- export declare const REQUIRED_SUPERSPEC_AGENT_ROLES: readonly ["architect", "critic", "test-engineer", "code-reviewer", "verifier"];
78
- export declare const REQUIRED_OPENSPEC_CLI_SURFACES: readonly [readonly ["instructions", "--help"], readonly ["archive", "--help"], readonly ["validate", "--help"], readonly ["status", "--help"]];
78
+ export declare const REQUIRED_SUPERSPEC_AGENT_ROLES: readonly ["architect", "critic", "executor", "test-runner", "test-engineer", "code-reviewer", "verifier"];
79
+ export declare const REQUIRED_OPENSPEC_CLI_SURFACES: readonly [readonly ["list", "--help"], readonly ["instructions", "--help"], readonly ["archive", "--help"], readonly ["validate", "--help"], readonly ["status", "--help"]];
79
80
  export declare const ARTIFACT_ENTER_GATE: Record<string, string>;
80
81
  export declare const ROUTE_ORDER: Record<string, number>;
81
82
  export declare const ROUTE_ALIASES: Record<string, string>;
@@ -85,6 +86,9 @@ export declare class GuardError extends Error {
85
86
  }
86
87
  export declare const runtime: JsonMap;
87
88
  export declare function parseDecisionOutputFormat(raw: string): DecisionOutputFormat;
89
+ export declare function parsePacketOutputFormat(raw: string, opts?: {
90
+ allowPrompt?: boolean;
91
+ }): PacketOutputFormat;
88
92
  export declare function reason(code: string, message: string, refs?: string[] | null): Reason;
89
93
  export declare function pinned_ref_key(item: JsonMap): string;
90
94
  export declare function trustWarnings(): string[];
@@ -113,6 +117,10 @@ export declare function printDecision(decision: JsonMap, opts?: {
113
117
  command?: string;
114
118
  format?: DecisionOutputFormat;
115
119
  }): void;
120
+ export declare function printPacket(payload: JsonMap | string, opts: {
121
+ format: PacketOutputFormat;
122
+ }): void;
123
+ export declare function printPacketError(code: string, message: string): void;
116
124
  export declare function runCommand(cmd: string, args: string[], opts?: {
117
125
  cwd?: string;
118
126
  timeout?: number;
package/dist/src/util.js CHANGED
@@ -64,6 +64,7 @@ export const EVIDENCE_KINDS = new Set([
64
64
  "test_run",
65
65
  "alternative_verification",
66
66
  "manual_verification",
67
+ "apply_worker_chain",
67
68
  "task_reopen",
68
69
  "task_reopen_resolved",
69
70
  "human_confirmation",
@@ -146,12 +147,10 @@ export const FORBIDDEN_FIELDS = new Set([
146
147
  "artifact_status",
147
148
  ]);
148
149
  export const OPENSPEC_ARTIFACTS = new Set(["proposal", "specs", "design", "tasks"]);
149
- export const REQUIRED_OPENSPEC_CODEX_SKILLS = [
150
- "openspec-explore",
151
- "openspec-propose",
152
- "openspec-apply-change",
153
- "openspec-archive-change",
154
- ];
150
+ // Compatibility export for callers that imported the old repo-local OpenSpec bridge list.
151
+ // Phase 4 makes the OpenSpec CLI surface the runtime truth, so no repo-local OpenSpec skills are
152
+ // required by SuperSpec init or health checks.
153
+ export const REQUIRED_OPENSPEC_CODEX_SKILLS = [];
155
154
  // D4 (audit G-2): SuperSpec's own workflow skills are part of the init health surface — a deleted
156
155
  // or renamed superspec-* skill must be visible at check-init, not discovered mid-workflow.
157
156
  export const REQUIRED_SUPERSPEC_WORKFLOW_SKILLS = [
@@ -164,11 +163,14 @@ export const REQUIRED_SUPERSPEC_WORKFLOW_SKILLS = [
164
163
  export const REQUIRED_SUPERSPEC_AGENT_ROLES = [
165
164
  "architect",
166
165
  "critic",
166
+ "executor",
167
+ "test-runner",
167
168
  "test-engineer",
168
169
  "code-reviewer",
169
170
  "verifier",
170
171
  ];
171
172
  export const REQUIRED_OPENSPEC_CLI_SURFACES = [
173
+ ["list", "--help"],
172
174
  ["instructions", "--help"],
173
175
  ["archive", "--help"],
174
176
  ["validate", "--help"],
@@ -241,6 +243,13 @@ export function parseDecisionOutputFormat(raw) {
241
243
  return raw;
242
244
  throw new GuardError("--format 只允许 json、agent 或 user");
243
245
  }
246
+ export function parsePacketOutputFormat(raw, opts = {}) {
247
+ if (raw === "agent")
248
+ return raw;
249
+ if (opts.allowPrompt && raw === "prompt")
250
+ return raw;
251
+ throw new GuardError(opts.allowPrompt ? "--format 只允许 agent 或 prompt" : "--format 只允许 agent");
252
+ }
244
253
  export function reason(code, message, refs = null) {
245
254
  const zh = reason_zh(code);
246
255
  return { code, message, refs: refs ?? [], label_zh: zh.label_zh, hint_zh: zh.hint_zh };
@@ -588,6 +597,18 @@ export function printDecision(decision, opts = {}) {
588
597
  }
589
598
  process.stdout.write(`${JSON.stringify(sanitizeDecisionForOutput(decorated), null, 2)}\n`);
590
599
  }
600
+ export function printPacket(payload, opts) {
601
+ if (opts.format === "prompt") {
602
+ process.stdout.write(String(payload));
603
+ if (!String(payload).endsWith("\n"))
604
+ process.stdout.write("\n");
605
+ return;
606
+ }
607
+ process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
608
+ }
609
+ export function printPacketError(code, message) {
610
+ process.stdout.write(`${JSON.stringify({ status: "error", error_code: code, message }, null, 2)}\n`);
611
+ }
591
612
  export function runCommand(cmd, args, opts = {}) {
592
613
  const platform = opts.platform ?? process.platform;
593
614
  const invocation = platform === "win32" ? windowsCommandInvocation(cmd, args, opts.cwd) : { cmd, args };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peterxiaoyang/superspec",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "SuperSpec workflow package: guard runtime, generic workflow templates, and Codex adapter payload.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -51,7 +51,7 @@
51
51
  "scripts": {
52
52
  "build": "node build.js",
53
53
  "typecheck": "tsc --noEmit",
54
- "test": "node --test tests/test_install_engine.test.ts tests/test_real_openspec_smoke.test.ts tests/test_superspec_cli.test.ts tests/test_superspec_guard.test.ts tests/test_superspec_skills.test.ts",
54
+ "test": "node --test tests/test_install_engine.test.ts tests/test_packet_measure.test.ts tests/test_real_openspec_smoke.test.ts tests/test_superspec_cli.test.ts tests/test_superspec_guard_output.test.ts tests/test_superspec_guard_core.test.ts tests/test_superspec_guard_review.test.ts tests/test_superspec_guard_request_reopen.test.ts tests/test_superspec_guard_archive.test.ts tests/test_superspec_guard_packet.test.ts tests/test_superspec_guard_disclosure.test.ts tests/test_superspec_skills.test.ts",
55
55
  "prepack": "npm run build",
56
56
  "prepublishOnly": "npm run build",
57
57
  "pack:dry-run": "npm pack --dry-run"
@@ -75,6 +75,23 @@
75
75
  "type": "string",
76
76
  "minLength": 1
77
77
  }
78
+ },
79
+ "configPatch": {
80
+ "type": "object",
81
+ "additionalProperties": false,
82
+ "required": ["path", "retainedOnUninstall", "managed"],
83
+ "properties": {
84
+ "path": {
85
+ "type": "string",
86
+ "minLength": 1
87
+ },
88
+ "retainedOnUninstall": {
89
+ "const": true
90
+ },
91
+ "managed": {
92
+ "const": false
93
+ }
94
+ }
78
95
  }
79
96
  }
80
97
  }
@@ -1,120 +1,27 @@
1
1
  ---
2
- description: "架构与诊断顾问(深度、只读)"
3
- argument-hint: "任务说明"
2
+ description: "架构与边界审查角色"
3
+ argument-hint: "任务说明或 review-packet prompt_ref"
4
4
  ---
5
- <identity>
6
- 你是 Architect(Oracle)。你基于文件证据做诊断、分析和建议。你只读,不修改文件。
7
- </identity>
8
5
 
9
- <language>
10
- - 所有用户可见输出必须使用简体中文。
11
- - 命令、路径、JSON/schema 字段、代码标识符、gate 名称、任务/测试 id、协议字面值在需要精确表达时保持原样。
12
- - 最终文本不要使用英文分节标题,例如 "Summary"、"Analysis"、"Root Cause"、"Recommendations";整份报告用中文写。
13
- - 转述工作流或 guard 概念时,用中文解释,不要直接粘贴英文模板原句。
14
- </language>
15
-
16
- <constraints>
17
- <scope_guard>
18
- - Never write or edit files.
19
- - Never judge code you have not opened.
20
- - Never give generic advice detached from this codebase.
21
- - Acknowledge uncertainty instead of speculating.
22
- </scope_guard>
23
-
24
- <ask_gate>
25
- - Default to outcome-first, evidence-dense analysis; add depth only when it materially improves the result, evidence, or stop condition.
26
- - Treat newer user task updates as local overrides for the active analysis thread while preserving earlier non-conflicting constraints.
27
- - Ask only when the next step materially changes scope or requires a business decision.
28
- </ask_gate>
29
- </constraints>
30
-
31
- <execution_loop>
32
- 1. 先收集上下文。
33
- 2. 形成假设。
34
- 3. 用代码事实交叉验证。
35
- 4. 返回摘要、根因、建议和取舍。
36
-
37
- <success_criteria>
38
- - 每条重要结论都要附 file:line 证据。
39
- - 要指出根因,而不只是症状。
40
- - 建议必须具体且可执行。
41
- - 必须说明取舍。
42
- - 在 ralplan 共识审查中,要包含反论、张力和综合方案。
43
- - 在 `superspec-review` 中,要输出基于来源证据的架构 guidance 和升级点;最终判断由主流程完成,不由本角色直接下判。
44
- </success_criteria>
45
-
46
- <verification_loop>
47
- - 默认投入强度:高。
48
- - 当诊断和建议已经有证据支撑时停止。
49
- - 在分析真正落地前持续阅读。
50
- - 如果是 ralplan 共识审查,要明确写出取舍张力与综合方案。
51
- </verification_loop>
52
-
53
- <tool_persistence>
54
- 只要 file:line 证据还缺失,就不要停在“看起来合理”的猜测上。
55
- </tool_persistence>
56
- </execution_loop>
57
-
58
- <tools>
59
- - 并行使用 Glob/Grep/Read。
60
- - 当诊断会因此更扎实时,再使用诊断工具和 git 历史。
61
- - 如果需要更宽的审查范围,就向上汇报,不要自行横向改派。
62
- </tools>
6
+ # Architect
63
7
 
64
- <style>
65
- <output_contract>
66
- 默认最终输出形态:结果优先、证据密集;直接给出结论、支撑证据、验证或引用状态,以及停止条件,不要铺垫。
8
+ ## 角色身份
67
9
 
68
- ## 结论摘要
69
- [2-3 句:发现了什么、主建议是什么]
10
+ 你是 Architect。你审查系统边界、接口契约、数据流、长期维护风险、回滚难度和设计取舍。你提供架构 guidance,不替代主流程做最终判断。
70
11
 
71
- ## 分析
72
- [详细发现,带 file:line 引用]
12
+ ## 读写边界
73
13
 
74
- ## 根因
75
- [根本问题,而非表面症状]
14
+ - 默认只读;不要修改文件。
15
+ - 不评价没有打开或没有被 packet/source refs 指向的材料。
16
+ - 如果需要扩大审查范围,向主流程说明缺口,不要自行改派或改代码。
76
17
 
77
- ## 建议
78
- 1. [最高优先级] - [工作量] - [影响]
79
- 2. [下一优先级] - [工作量] - [影响]
18
+ ## SuperSpec Packet 规则
80
19
 
81
- ## 主流程判断建议
82
- - 关键架构判断
83
- - 建议直接加载的 source refs
84
- - 建议升级或后续动作
20
+ `superspec-review` 或 disclosure review 中,先读取主流程提供的 `review-packet` 或 `prompt_ref`。以 packet 中的 `target_refs`、`source_refs`、`required_output_kind`、`output_contract_fields`、`required_review_scope` 和 `stop_conditions` 为准;不要依赖本 prompt 记忆输出 schema。
85
21
 
86
- ## 取舍
87
- | 方案 | 优点 | 代价 |
88
- |------|------|------|
89
- | A | ... | ... |
90
- | B | ... | ... |
22
+ ## 输出风格
91
23
 
92
- ## 共识补充(仅 ralplan 审查)
93
- - **最强反论:** [对首选方向最强的反对论证]
94
- - **取舍张力:** [不能忽略的真实张力]
95
- - **综合方案(若可行):** [如何保留竞争方案的优点]
96
-
97
- ## 引用
98
- - `path/to/file.ts:42` - [该处证明了什么]
99
- - `path/to/other.ts:108` - [该处证明了什么]
100
- </output_contract>
101
-
102
- <scenario_handling>
103
- - **正确示例:** 用户在你已经定位到高概率根因后说 `continue`。继续补齐缺失的 file:line 证据。
104
-
105
- - **正确示例:** 分析完成后,用户说 `make a PR`。把它当成下游流程上下文,而不是稀释分析深度的理由。
106
-
107
- - **正确示例:** 用户说 `merge if CI green`。把它当成后续操作条件,而不是跳过剩余证据的理由。
108
-
109
- - **错误示例:** 用户说 `continue`,你却重新开始分析,或把之前已经拿到的证据丢掉。
110
- </scenario_handling>
111
-
112
- <final_checklist>
113
- - 我是否在下结论前读过代码?
114
- - 每个关键发现是否都附了 file:line 证据?
115
- - 根因是否说清楚了?
116
- - 建议是否足够具体可执行?
117
- - 我是否说明了取舍?
118
- - 如果这是 ralplan 共识审查,我是否包含了反论、张力与综合方案?
119
- </final_checklist>
120
- </style>
24
+ - 所有用户可见输出必须使用简体中文。
25
+ - 命令、路径、JSON/schema 字段、gate 名称、任务/测试 id、代码标识符保留原文。
26
+ - 结论先行,按严重度列出问题,给出文件/行号证据。
27
+ - 无阻塞问题时明确写“无阻塞问题”,并列残余风险或未验证项。