@peterxiaoyang/superspec 0.1.7 → 0.1.8

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.
@@ -0,0 +1,72 @@
1
+ import type { JsonMap, Reason } from "../util.ts";
2
+ export declare const HOOK_ADAPTER_VERSION = "superspec-hook@2";
3
+ export type HookTrust = "trusted" | "audit-only" | "untrusted";
4
+ export type HookStrictProfile = "available" | "unavailable";
5
+ export type HookEvent = JsonMap & {
6
+ hook_event_name?: string;
7
+ session_id?: string;
8
+ turn_id?: string;
9
+ cwd?: string;
10
+ tool_name?: string;
11
+ tool_use_id?: string;
12
+ tool_input?: JsonMap;
13
+ tool_response?: JsonMap;
14
+ agent_id?: string;
15
+ agent_type?: string;
16
+ };
17
+ export type HookDecision = {
18
+ allowed: boolean;
19
+ decision: "allow" | "block" | "status";
20
+ change_id: string;
21
+ gate: string;
22
+ strict_profile: HookStrictProfile;
23
+ enforcement: "pass-through" | "guarded" | "deny" | "audit-only";
24
+ trust: HookTrust;
25
+ block_reasons: Reason[];
26
+ audit_only_reasons: Reason[];
27
+ target_paths?: string[];
28
+ tool_name?: string;
29
+ hook_event_name?: string;
30
+ hook_event_id?: string;
31
+ actions?: JsonMap[];
32
+ next_allowed_actions: string[];
33
+ trust_warnings: string[];
34
+ };
35
+ export type HookSessionRecord = {
36
+ schema_version: 2;
37
+ kind: "hook_active_session";
38
+ trust: HookTrust;
39
+ change_id: string;
40
+ repo_root: string;
41
+ session_id: string;
42
+ workflow: string;
43
+ started_at: string;
44
+ expires_at: string;
45
+ guard_version: string;
46
+ adapter_version: string;
47
+ hook_manifest_hash: string | null;
48
+ strict_profile: HookStrictProfile;
49
+ audit_only_reasons: Reason[];
50
+ };
51
+ export type HookRunlogRecord = {
52
+ schema_version: 2;
53
+ kind: "subagent_start" | "subagent_stop";
54
+ trust: HookTrust;
55
+ hook_event_id: string;
56
+ hook_event_name: string;
57
+ hook_provenance: JsonMap;
58
+ session_id: string;
59
+ turn_id?: string;
60
+ run_id: string;
61
+ agent_id: string;
62
+ agent_type: string;
63
+ cwd?: string;
64
+ prompt_hash?: string;
65
+ prompt_ref?: string;
66
+ output_ref?: string;
67
+ output_hash?: string;
68
+ status?: string;
69
+ error?: string;
70
+ started_at?: string;
71
+ stopped_at?: string;
72
+ };
@@ -0,0 +1 @@
1
+ export const HOOK_ADAPTER_VERSION = "superspec-hook@2";
@@ -0,0 +1,3 @@
1
+ import type { JsonMap, Reason } from "../util.ts";
2
+ export declare function strictRoleRunlogReasons(changeRoot: string, ev: JsonMap): Reason[];
3
+ export declare function strictRuntimeEvidenceReasons(ev: JsonMap): Reason[];
@@ -0,0 +1,70 @@
1
+ import { existsSync, readFileSync, statSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { isObject, reason, safe_within, sha256_file } from "../util.js";
4
+ import { superspec_dir } from "../paths.js";
5
+ function runlogPath(changeRoot) {
6
+ return join(superspec_dir(changeRoot), "subagent-runlog.jsonl");
7
+ }
8
+ export function strictRoleRunlogReasons(changeRoot, ev) {
9
+ if (ev.trust !== "runtime-verified" && ev.requires_hook_runlog !== true)
10
+ return [];
11
+ const problems = [
12
+ reason("hook_runlog_strict_profile_unavailable", `${ev._path}: strict hook runlog validation is unavailable until R-1 deny and hook provenance pass`),
13
+ ];
14
+ const target = runlogPath(changeRoot);
15
+ if (!existsSync(target) || !statSync(target).isFile()) {
16
+ problems.push(reason("hook_runlog_missing", `${ev._path}: strict role evidence requires SuperSpec hook subagent runlog`));
17
+ return problems;
18
+ }
19
+ const records = readFileSync(target, "utf8").split(/\r?\n/u).filter(Boolean).flatMap((line) => {
20
+ try {
21
+ const parsed = JSON.parse(line);
22
+ return isObject(parsed) ? [parsed] : [];
23
+ }
24
+ catch {
25
+ return [];
26
+ }
27
+ });
28
+ const agentId = String(ev.agent_id ?? "");
29
+ const role = String(ev.agent_role ?? "");
30
+ const starts = records.filter((item) => item.kind === "subagent_start" && item.agent_id === agentId && item.agent_type === role && item.trust === "trusted");
31
+ const stops = records.filter((item) => item.kind === "subagent_stop" && item.agent_id === agentId && item.agent_type === role && item.trust === "trusted");
32
+ if (starts.length === 0)
33
+ problems.push(reason("hook_runlog_start_missing", `${ev._path}: strict role evidence has no trusted matching SubagentStart`, [agentId]));
34
+ if (stops.length === 0)
35
+ problems.push(reason("hook_runlog_stop_missing", `${ev._path}: strict role evidence has no trusted matching SubagentStop`, [agentId]));
36
+ const outputRef = typeof ev.output_ref === "string" ? ev.output_ref : "";
37
+ const outputPath = outputRef ? safe_within(changeRoot, outputRef) : null;
38
+ const outputSha = outputPath && existsSync(outputPath) && statSync(outputPath).isFile() ? sha256_file(outputPath) : null;
39
+ if (outputSha && stops.length > 0 && !stops.some((item) => item.output_hash === outputSha || item.output_ref === outputRef)) {
40
+ problems.push(reason("hook_runlog_output_mismatch", `${ev._path}: strict role evidence output_ref does not match trusted SubagentStop output hash/ref`, [agentId]));
41
+ }
42
+ return problems;
43
+ }
44
+ export function strictRuntimeEvidenceReasons(ev) {
45
+ if (ev.trust !== "runtime-verified")
46
+ return [];
47
+ const problems = [
48
+ reason("runtime_evidence_strict_profile_unavailable", `${ev._path}: strict runtime evidence is unavailable until R-1 deny and hook provenance pass`),
49
+ ];
50
+ if (typeof ev.hook_event_id !== "string" || !ev.hook_event_id)
51
+ problems.push(reason("runtime_evidence_missing_hook_event", `${ev._path}: runtime-verified evidence requires hook_event_id`));
52
+ if (!isObject(ev.hook_provenance) || ev.hook_provenance.validation !== "trusted")
53
+ problems.push(reason("runtime_evidence_untrusted_provenance", `${ev._path}: runtime-verified evidence requires trusted hook_provenance`));
54
+ if (!isObject(ev.token_binding))
55
+ problems.push(reason("runtime_evidence_missing_token", `${ev._path}: runtime-verified evidence requires Guard token_binding`));
56
+ if (typeof ev.command_fingerprint !== "string" || !ev.command_fingerprint.startsWith("sha256:"))
57
+ problems.push(reason("runtime_evidence_missing_command_fingerprint", `${ev._path}: runtime-verified evidence requires command_fingerprint`));
58
+ if (!Array.isArray(ev.raw_log_pinned_refs) || ev.raw_log_pinned_refs.length === 0)
59
+ problems.push(reason("runtime_evidence_missing_raw_log_pin", `${ev._path}: runtime-verified evidence requires raw_log_pinned_refs`));
60
+ if (typeof ev.exit_code !== "number") {
61
+ problems.push(reason("runtime_evidence_missing_exit_code", `${ev._path}: runtime-verified evidence requires numeric exit_code`));
62
+ }
63
+ else if ((ev.kind === "final_test" || ev.semantic_status === "expected_success") && ev.exit_code !== 0) {
64
+ problems.push(reason("runtime_evidence_exit_code_mismatch", `${ev._path}: expected_success/final_test runtime evidence requires exit_code=0`));
65
+ }
66
+ else if (ev.semantic_status === "expected_failure" && ev.exit_code === 0) {
67
+ problems.push(reason("runtime_evidence_exit_code_mismatch", `${ev._path}: RED runtime evidence requires non-zero exit_code`));
68
+ }
69
+ return problems;
70
+ }
@@ -1,118 +1,119 @@
1
1
  import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
2
2
  import { tmpdir } from "node:os";
3
3
  import { dirname, join } from "node:path";
4
+ import { load_install_map } from "./install_engine.js";
4
5
  import { dispatch_packet } from "./packet_render.js";
5
- import { GuardError, REQUIRED_SUPERSPEC_AGENT_ROLES, REQUIRED_SUPERSPEC_WORKFLOW_SKILLS, runtime, } from "./util.js";
6
+ import { GuardError, runtime, } from "./util.js";
6
7
  import { file_blob_sha } from "./git.js";
7
8
  const REPRESENTATIVE_SCENARIOS = [
8
9
  {
9
10
  name: "explore_complete",
10
- description: "Post-bridge runtime surface for discovery authoring plus proposal-entry critic review.",
11
+ description: "Package payload surface for discovery authoring plus proposal-entry critic review.",
11
12
  files: [
12
- ".codex/skills/superspec-explore/SKILL.md",
13
- ".codex/prompts/critic.md",
14
- ".codex/agents/critic.toml",
13
+ "templates/workflow/skills/superspec-explore/SKILL.md",
14
+ "templates/workflow/prompts/critic.md",
15
+ "adapters/codex/agents/critic.toml",
15
16
  ],
16
17
  },
17
18
  {
18
19
  name: "proposal_reviewed",
19
- description: "Post-bridge runtime surface for proposal authoring and proposal critic review.",
20
+ description: "Package payload surface for proposal authoring and proposal critic review.",
20
21
  files: [
21
- ".codex/skills/superspec-propose/SKILL.md",
22
- ".codex/prompts/critic.md",
23
- ".codex/agents/critic.toml",
22
+ "templates/workflow/skills/superspec-propose/SKILL.md",
23
+ "templates/workflow/prompts/critic.md",
24
+ "adapters/codex/agents/critic.toml",
24
25
  ],
25
26
  },
26
27
  {
27
28
  name: "design_complete",
28
- description: "Post-bridge runtime surface for design authoring and the architect/critic/test-engineer review bundle.",
29
+ description: "Package payload surface for design authoring and the architect/critic/test-engineer review bundle.",
29
30
  files: [
30
- ".codex/skills/superspec-propose/SKILL.md",
31
- ".codex/prompts/architect.md",
32
- ".codex/prompts/critic.md",
33
- ".codex/prompts/test-engineer.md",
34
- ".codex/agents/architect.toml",
35
- ".codex/agents/critic.toml",
36
- ".codex/agents/test-engineer.toml",
31
+ "templates/workflow/skills/superspec-propose/SKILL.md",
32
+ "templates/workflow/prompts/architect.md",
33
+ "templates/workflow/prompts/critic.md",
34
+ "templates/workflow/prompts/test-engineer.md",
35
+ "adapters/codex/agents/architect.toml",
36
+ "adapters/codex/agents/critic.toml",
37
+ "adapters/codex/agents/test-engineer.toml",
37
38
  ],
38
39
  },
39
40
  {
40
41
  name: "test_contract_drafted",
41
- description: "Post-bridge runtime surface for test-contract authoring and its review lanes.",
42
+ description: "Package payload surface for test-contract authoring and its review lanes.",
42
43
  files: [
43
- ".codex/skills/superspec-propose/SKILL.md",
44
- ".codex/prompts/critic.md",
45
- ".codex/prompts/test-engineer.md",
46
- ".codex/agents/critic.toml",
47
- ".codex/agents/test-engineer.toml",
44
+ "templates/workflow/skills/superspec-propose/SKILL.md",
45
+ "templates/workflow/prompts/critic.md",
46
+ "templates/workflow/prompts/test-engineer.md",
47
+ "adapters/codex/agents/critic.toml",
48
+ "adapters/codex/agents/test-engineer.toml",
48
49
  ],
49
50
  },
50
51
  {
51
52
  name: "apply_ready",
52
- description: "Post-bridge runtime surface for apply orchestration and bounded executor handoff.",
53
+ description: "Package payload surface for apply orchestration and bounded executor handoff.",
53
54
  files: [
54
- ".codex/skills/superspec-apply/SKILL.md",
55
- ".codex/prompts/executor.md",
56
- ".codex/agents/executor.toml",
55
+ "templates/workflow/skills/superspec-apply/SKILL.md",
56
+ "templates/workflow/prompts/executor.md",
57
+ "adapters/codex/agents/executor.toml",
57
58
  ],
58
59
  },
59
60
  {
60
61
  name: "review_complete_allow",
61
- description: "Post-bridge runtime surface for merged review + final verification on the allow path.",
62
+ description: "Package payload surface for merged review + final verification on the allow path.",
62
63
  files: [
63
- ".codex/skills/superspec-review/SKILL.md",
64
- ".codex/prompts/code-reviewer.md",
65
- ".codex/prompts/architect.md",
66
- ".codex/prompts/critic.md",
67
- ".codex/prompts/verifier.md",
68
- ".codex/agents/code-reviewer.toml",
69
- ".codex/agents/architect.toml",
70
- ".codex/agents/critic.toml",
71
- ".codex/agents/verifier.toml",
64
+ "templates/workflow/skills/superspec-review/SKILL.md",
65
+ "templates/workflow/prompts/code-reviewer.md",
66
+ "templates/workflow/prompts/architect.md",
67
+ "templates/workflow/prompts/critic.md",
68
+ "templates/workflow/prompts/verifier.md",
69
+ "adapters/codex/agents/code-reviewer.toml",
70
+ "adapters/codex/agents/architect.toml",
71
+ "adapters/codex/agents/critic.toml",
72
+ "adapters/codex/agents/verifier.toml",
72
73
  ],
73
74
  },
74
75
  {
75
76
  name: "archive_ready",
76
- description: "Post-bridge runtime surface for archive handoff after review passes.",
77
+ description: "Package payload surface for archive handoff after review passes.",
77
78
  files: [
78
- ".codex/skills/superspec-archive/SKILL.md",
79
+ "templates/workflow/skills/superspec-archive/SKILL.md",
79
80
  ],
80
81
  },
81
82
  {
82
83
  name: "round2_reviewer_prompt",
83
- description: "Post-bridge runtime surface for a round>1 reviewer lane.",
84
+ description: "Package payload surface for a round>1 reviewer lane.",
84
85
  files: [
85
- ".codex/prompts/critic.md",
86
- ".codex/agents/critic.toml",
86
+ "templates/workflow/prompts/critic.md",
87
+ "adapters/codex/agents/critic.toml",
87
88
  ],
88
89
  },
89
90
  {
90
91
  name: "request_changes_reopen_tasks",
91
- description: "Post-bridge runtime surface for a review round that routes back to apply via reopen_tasks.",
92
+ description: "Package payload surface for a review round that routes back to apply via reopen_tasks.",
92
93
  files: [
93
- ".codex/skills/superspec-review/SKILL.md",
94
- ".codex/prompts/code-reviewer.md",
95
- ".codex/prompts/architect.md",
96
- ".codex/prompts/critic.md",
97
- ".codex/agents/code-reviewer.toml",
98
- ".codex/agents/architect.toml",
99
- ".codex/agents/critic.toml",
94
+ "templates/workflow/skills/superspec-review/SKILL.md",
95
+ "templates/workflow/prompts/code-reviewer.md",
96
+ "templates/workflow/prompts/architect.md",
97
+ "templates/workflow/prompts/critic.md",
98
+ "adapters/codex/agents/code-reviewer.toml",
99
+ "adapters/codex/agents/architect.toml",
100
+ "adapters/codex/agents/critic.toml",
100
101
  ],
101
102
  },
102
103
  {
103
104
  name: "task_reopen_to_resolved",
104
- description: "Post-bridge runtime surface for reopened apply work from revert through successor executor completion.",
105
+ description: "Package payload surface for reopened apply work from revert through successor executor completion.",
105
106
  files: [
106
- ".codex/skills/superspec-apply/SKILL.md",
107
- ".codex/prompts/executor.md",
108
- ".codex/agents/executor.toml",
107
+ "templates/workflow/skills/superspec-apply/SKILL.md",
108
+ "templates/workflow/prompts/executor.md",
109
+ "adapters/codex/agents/executor.toml",
109
110
  ],
110
111
  },
111
112
  {
112
113
  name: "scope_expansion",
113
- description: "Post-bridge runtime surface for apply-side user confirmation when task scope expands.",
114
+ description: "Package payload surface for apply-side user confirmation when task scope expands.",
114
115
  files: [
115
- ".codex/skills/superspec-apply/SKILL.md",
116
+ "templates/workflow/skills/superspec-apply/SKILL.md",
116
117
  ],
117
118
  },
118
119
  ];
@@ -166,24 +167,6 @@ function ensureReadableTextFile(repoRoot, relPath) {
166
167
  if (existsSync(absPath) && statSync(absPath).isFile()) {
167
168
  return readFileSync(absPath, "utf8");
168
169
  }
169
- const skillMatch = /^\.codex\/skills\/([^/]+)\/SKILL\.md$/u.exec(relPath);
170
- if (skillMatch) {
171
- const fallback = join(repoRoot, "templates", "workflow", "skills", skillMatch[1], "SKILL.md");
172
- if (existsSync(fallback) && statSync(fallback).isFile())
173
- return readFileSync(fallback, "utf8");
174
- }
175
- const promptMatch = /^\.codex\/prompts\/([^/]+)\.md$/u.exec(relPath);
176
- if (promptMatch) {
177
- const fallback = join(repoRoot, "templates", "workflow", "prompts", `${promptMatch[1]}.md`);
178
- if (existsSync(fallback) && statSync(fallback).isFile())
179
- return readFileSync(fallback, "utf8");
180
- }
181
- const agentMatch = /^\.codex\/agents\/([^/]+)\.toml$/u.exec(relPath);
182
- if (agentMatch) {
183
- const fallback = join(repoRoot, "adapters", "codex", "agents", `${agentMatch[1]}.toml`);
184
- if (existsSync(fallback) && statSync(fallback).isFile())
185
- return readFileSync(fallback, "utf8");
186
- }
187
170
  throw new GuardError(`packet_measure_missing_file: ${relPath}`);
188
171
  }
189
172
  function dedupePaths(paths) {
@@ -365,39 +348,21 @@ function measureMaterializedSamples(specs) {
365
348
  ctx.cleanup();
366
349
  }
367
350
  }
368
- function templateWorkflowSkillPaths() {
369
- return REQUIRED_SUPERSPEC_WORKFLOW_SKILLS.map((name) => `templates/workflow/skills/${name}/SKILL.md`);
370
- }
371
- function templatePromptPaths() {
372
- return REQUIRED_SUPERSPEC_AGENT_ROLES.map((name) => `templates/workflow/prompts/${name}.md`);
373
- }
374
- function adapterAgentPaths() {
375
- return REQUIRED_SUPERSPEC_AGENT_ROLES.map((name) => `adapters/codex/agents/${name}.toml`);
376
- }
377
- function repoLocalSkillPaths(repoRoot) {
378
- return REQUIRED_SUPERSPEC_WORKFLOW_SKILLS
379
- .map((name) => join(".codex", "skills", name, "SKILL.md"))
380
- .filter((relPath) => existsSync(join(repoRoot, relPath)));
381
- }
382
- function runtimeBridgeSkillPaths() {
383
- return [];
351
+ function installPayloadSourcePaths(repoRoot) {
352
+ const { mappings, problems } = load_install_map(repoRoot);
353
+ if (problems.length > 0)
354
+ throw new GuardError(`packet_measure_install_map_invalid: ${problems.join("; ")}`);
355
+ return mappings
356
+ .filter((mapping) => mapping.kind === "skill" || mapping.kind === "prompt" || mapping.kind === "agent")
357
+ .map((mapping) => mapping.source);
384
358
  }
385
359
  export function representative_scenarios() {
386
360
  return REPRESENTATIVE_SCENARIOS;
387
361
  }
388
362
  export function measure_packet_surface_report(repoRoot) {
389
- const fixedSurfaceInstallUpperBound = measureSurface(repoRoot, [
390
- ...templateWorkflowSkillPaths(),
391
- ...templatePromptPaths(),
392
- ...adapterAgentPaths(),
393
- ...repoLocalSkillPaths(repoRoot),
394
- ]);
395
- const fixedSurfaceRuntimeRequiredSubset = measureSurface(repoRoot, [
396
- ...templateWorkflowSkillPaths(),
397
- ...templatePromptPaths(),
398
- ...adapterAgentPaths(),
399
- ...runtimeBridgeSkillPaths(),
400
- ]);
363
+ const packagePayloadSourcePaths = installPayloadSourcePaths(repoRoot);
364
+ const fixedSurfaceInstallUpperBound = measureSurface(repoRoot, packagePayloadSourcePaths);
365
+ const fixedSurfaceRuntimeRequiredSubset = measureSurface(repoRoot, packagePayloadSourcePaths);
401
366
  const scenarios = REPRESENTATIVE_SCENARIOS.map((scenario) => ({
402
367
  name: scenario.name,
403
368
  description: scenario.description,
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import "./src/core.ts";
3
+ export * from "./src/hooks/adapter.ts";
4
+ export declare function main_hook(argv?: string[]): number;
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+ import "./src/core.js";
3
+ export * from "./src/hooks/adapter.js";
4
+ import { readFileSync, realpathSync } from "node:fs";
5
+ import { resolve } from "node:path";
6
+ import { runHookAdapter } from "./src/hooks/adapter.js";
7
+ function realpathMaybe(filePath) {
8
+ try {
9
+ return realpathSync(filePath);
10
+ }
11
+ catch {
12
+ return resolve(filePath);
13
+ }
14
+ }
15
+ const currentFile = realpathMaybe(process.argv[1] ?? "");
16
+ export function main_hook(argv = process.argv.slice(2)) {
17
+ const stdin = readStdin();
18
+ const result = runHookAdapter(argv, stdin);
19
+ if (result.stdout)
20
+ process.stdout.write(result.stdout);
21
+ if (result.stderr)
22
+ process.stderr.write(result.stderr);
23
+ return result.code;
24
+ }
25
+ function readStdin() {
26
+ try {
27
+ return readFileSync(0, "utf8");
28
+ }
29
+ catch {
30
+ return "";
31
+ }
32
+ }
33
+ if (currentFile === realpathMaybe(new URL(import.meta.url).pathname)) {
34
+ process.exitCode = main_hook();
35
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peterxiaoyang/superspec",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "SuperSpec workflow package: guard runtime, generic workflow templates, and Codex adapter payload.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,6 +21,7 @@
21
21
  "bin": {
22
22
  "superspec": "bin/superspec.js",
23
23
  "superspec-guard": "bin/superspec-guard.js",
24
+ "superspec-hook": "bin/superspec-hook.js",
24
25
  "superspec-init": "bin/superspec-init.js"
25
26
  },
26
27
  "exports": {
@@ -32,6 +33,10 @@
32
33
  "types": "./dist/superspec_guard.d.ts",
33
34
  "default": "./dist/superspec_guard.js"
34
35
  },
36
+ "./superspec_hook": {
37
+ "types": "./dist/superspec_hook.d.ts",
38
+ "default": "./dist/superspec_hook.js"
39
+ },
35
40
  "./superspec_init": {
36
41
  "types": "./dist/superspec_init.d.ts",
37
42
  "default": "./dist/superspec_init.js"
@@ -51,7 +56,7 @@
51
56
  "scripts": {
52
57
  "build": "node build.js",
53
58
  "typecheck": "tsc --noEmit",
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",
59
+ "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_hooks.test.ts tests/test_superspec_skills.test.ts",
55
60
  "prepack": "npm run build",
56
61
  "prepublishOnly": "npm run build",
57
62
  "pack:dry-run": "npm pack --dry-run"
@@ -0,0 +1,27 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://superspec.local/schemas/hook-event.schema.json",
4
+ "title": "SuperSpec Codex Hook Event",
5
+ "type": "object",
6
+ "required": ["hook_event_name", "cwd"],
7
+ "properties": {
8
+ "session_id": { "type": "string" },
9
+ "turn_id": { "type": "string" },
10
+ "transcript_path": { "type": ["string", "null"] },
11
+ "cwd": { "type": "string" },
12
+ "hook_event_name": {
13
+ "type": "string",
14
+ "enum": ["PreToolUse", "PostToolUse", "SubagentStart", "SubagentStop"]
15
+ },
16
+ "permission_mode": { "type": "string" },
17
+ "tool_name": { "type": "string" },
18
+ "tool_use_id": { "type": "string" },
19
+ "tool_input": { "type": "object" },
20
+ "tool_response": { "type": ["object", "array", "string", "number", "boolean", "null"] },
21
+ "agent_id": { "type": "string" },
22
+ "agent_type": { "type": "string" },
23
+ "agent_transcript_path": { "type": ["string", "null"] },
24
+ "last_assistant_message": { "type": ["string", "null"] }
25
+ },
26
+ "additionalProperties": true
27
+ }
@@ -0,0 +1,61 @@
1
+ {
2
+ "superspec": {
3
+ "managed": true,
4
+ "adapter_version": "superspec-hook@2",
5
+ "strict_profile_default": "audit-only-until-r1-provenance-passes"
6
+ },
7
+ "hooks": {
8
+ "PreToolUse": [
9
+ {
10
+ "matcher": "Bash|apply_patch|Edit|Write|mcp__.*",
11
+ "hooks": [
12
+ {
13
+ "type": "command",
14
+ "command": "superspec-hook --change \"$SUPERSPEC_CHANGE\"",
15
+ "timeout": 10,
16
+ "statusMessage": "SuperSpec hook write policy"
17
+ }
18
+ ]
19
+ }
20
+ ],
21
+ "PostToolUse": [
22
+ {
23
+ "matcher": "Bash",
24
+ "hooks": [
25
+ {
26
+ "type": "command",
27
+ "command": "superspec-hook --change \"$SUPERSPEC_CHANGE\"",
28
+ "timeout": 30,
29
+ "statusMessage": "SuperSpec hook runtime evidence"
30
+ }
31
+ ]
32
+ }
33
+ ],
34
+ "SubagentStart": [
35
+ {
36
+ "matcher": ".*",
37
+ "hooks": [
38
+ {
39
+ "type": "command",
40
+ "command": "superspec-hook --change \"$SUPERSPEC_CHANGE\"",
41
+ "timeout": 30,
42
+ "statusMessage": "SuperSpec hook subagent start"
43
+ }
44
+ ]
45
+ }
46
+ ],
47
+ "SubagentStop": [
48
+ {
49
+ "matcher": ".*",
50
+ "hooks": [
51
+ {
52
+ "type": "command",
53
+ "command": "superspec-hook --change \"$SUPERSPEC_CHANGE\"",
54
+ "timeout": 30,
55
+ "statusMessage": "SuperSpec hook subagent stop"
56
+ }
57
+ ]
58
+ }
59
+ ]
60
+ }
61
+ }
@@ -26,6 +26,13 @@ Apply 按 OpenSpec tasks 执行实现,负责 RED/GREEN 证据、任务勾选
26
26
 
27
27
  ## 第一条必跑命令
28
28
 
29
+ 先尝试建立当前 change 的 SuperSpec hook session。R-1/provenance 未通过时该命令只会记录 audit-only lease 和降级诊断,不代表 mechanical enforcement 已启用:
30
+
31
+ ```text
32
+ superspec guard hook-session-begin --change "<change>" --workflow superspec-apply --entrypoint-token "<fresh-entrypoint-token>" --format agent
33
+ superspec guard hook-session-status --change "<change>" --format agent
34
+ ```
35
+
29
36
  ```text
30
37
  superspec guard workflow-packet --change "<change>" --gate apply_ready --format agent
31
38
  ```
@@ -26,6 +26,13 @@ Archive 在 `review_complete` allowed 后收尾:确认 archive readiness、保
26
26
 
27
27
  ## 第一条必跑命令
28
28
 
29
+ 先尝试建立当前 change 的 SuperSpec hook session。R-1/provenance 未通过时该命令只会记录 audit-only lease 和降级诊断,不代表 mechanical enforcement 已启用:
30
+
31
+ ```text
32
+ superspec guard hook-session-begin --change "<change>" --workflow superspec-archive --entrypoint-token "<fresh-entrypoint-token>" --format agent
33
+ superspec guard hook-session-status --change "<change>" --format agent
34
+ ```
35
+
29
36
  ```text
30
37
  superspec guard workflow-packet --change "<change>" --gate archive_ready --format agent
31
38
  ```
@@ -60,6 +67,7 @@ openspec archive -y "<change>"
60
67
 
61
68
  ```text
62
69
  superspec guard check-archived --change "<change>" --format agent
70
+ superspec guard hook-session-end --change "<change>" --reason archived --format agent
63
71
  ```
64
72
 
65
73
  `.superspec/artifacts/business-invariants.md`、`.superspec/artifacts/test-contract.md`、review/verification evidence、RED/GREEN evidence 和 archive evidence 必须能从 preservation manifest 追溯。
@@ -26,6 +26,13 @@ Explore 只做需求澄清、代码事实调查、范围边界和风险记录。
26
26
 
27
27
  ## 第一条必跑命令
28
28
 
29
+ 先尝试建立当前 change 的 SuperSpec hook session。R-1/provenance 未通过时该命令只会记录 audit-only lease 和降级诊断,不代表 mechanical enforcement 已启用:
30
+
31
+ ```text
32
+ superspec guard hook-session-begin --change "<change>" --workflow superspec-explore --entrypoint-token "<fresh-entrypoint-token>" --format agent
33
+ superspec guard hook-session-status --change "<change>" --format agent
34
+ ```
35
+
29
36
  ```text
30
37
  superspec init --scope project --format agent
31
38
  ```
@@ -26,6 +26,13 @@ Propose 把 discovery 转成 OpenSpec proposal package,并补 SuperSpec 业务
26
26
 
27
27
  ## 第一条必跑命令
28
28
 
29
+ 先尝试建立当前 change 的 SuperSpec hook session。R-1/provenance 未通过时该命令只会记录 audit-only lease 和降级诊断,不代表 mechanical enforcement 已启用:
30
+
31
+ ```text
32
+ superspec guard hook-session-begin --change "<change>" --workflow superspec-propose --entrypoint-token "<fresh-entrypoint-token>" --format agent
33
+ superspec guard hook-session-status --change "<change>" --format agent
34
+ ```
35
+
29
36
  ```text
30
37
  superspec guard workflow-packet --change "<change>" --gate explore_complete --format agent
31
38
  ```