@peterxiaoyang/superspec 0.1.13 → 0.1.15-alpha
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/cli.d.ts +2 -0
- package/dist/cli.js +302 -0
- package/dist/format.d.ts +29 -0
- package/dist/format.js +141 -0
- package/dist/next.d.ts +3 -0
- package/dist/next.js +161 -0
- package/dist/openspec.d.ts +9 -0
- package/dist/openspec.js +41 -0
- package/dist/record.d.ts +20 -0
- package/dist/record.js +211 -0
- package/dist/skill_loop.d.ts +23 -0
- package/dist/skill_loop.js +58 -0
- package/dist/store.d.ts +31 -0
- package/dist/store.js +213 -0
- package/dist/sync.d.ts +3 -0
- package/dist/sync.js +135 -0
- package/dist/task.d.ts +7 -0
- package/dist/task.js +44 -0
- package/dist/transition.d.ts +34 -0
- package/dist/transition.js +400 -0
- package/dist/types.d.ts +138 -0
- package/dist/types.js +3 -0
- package/package.json +8 -53
- package/templates/workflow/skills/superspec-apply/SKILL.md +46 -118
- package/templates/workflow/skills/superspec-archive/SKILL.md +22 -47
- package/templates/workflow/skills/superspec-explore/SKILL.md +38 -69
- package/templates/workflow/skills/superspec-propose/SKILL.md +58 -57
- package/templates/workflow/skills/superspec-review/SKILL.md +36 -81
- package/adapters/codex/agents/architect.toml +0 -13
- package/adapters/codex/agents/code-reviewer.toml +0 -13
- package/adapters/codex/agents/critic.toml +0 -13
- package/adapters/codex/agents/executor.toml +0 -13
- package/adapters/codex/agents/explore.toml +0 -13
- package/adapters/codex/agents/test-engineer.toml +0 -13
- package/adapters/codex/agents/test-runner.toml +0 -13
- package/adapters/codex/agents/verifier.toml +0 -13
- package/adapters/codex/install-map.json +0 -116
- package/bin/launch.js +0 -37
- package/bin/superspec-check.js +0 -4
- package/bin/superspec-hook.js +0 -4
- package/bin/superspec-init.js +0 -4
- package/bin/superspec.js +0 -4
- package/dist/src/apply_worker_chain.d.ts +0 -60
- package/dist/src/apply_worker_chain.js +0 -1283
- package/dist/src/apply_worker_chain_lifecycle.d.ts +0 -21
- package/dist/src/apply_worker_chain_lifecycle.js +0 -409
- package/dist/src/archive.d.ts +0 -23
- package/dist/src/archive.js +0 -430
- package/dist/src/cli.d.ts +0 -1
- package/dist/src/cli.js +0 -33
- package/dist/src/cli_args.d.ts +0 -32
- package/dist/src/cli_args.js +0 -454
- package/dist/src/core.d.ts +0 -20
- package/dist/src/core.js +0 -394
- package/dist/src/disclosure.d.ts +0 -35
- package/dist/src/disclosure.js +0 -671
- package/dist/src/doctor.d.ts +0 -44
- package/dist/src/doctor.js +0 -230
- package/dist/src/evidence.d.ts +0 -29
- package/dist/src/evidence.js +0 -1107
- package/dist/src/gates.d.ts +0 -19
- package/dist/src/gates.js +0 -1631
- package/dist/src/git.d.ts +0 -8
- package/dist/src/git.js +0 -112
- package/dist/src/hooks/adapter.d.ts +0 -5
- package/dist/src/hooks/adapter.js +0 -347
- package/dist/src/hooks/guard_api.d.ts +0 -12
- package/dist/src/hooks/guard_api.js +0 -797
- package/dist/src/hooks/health.d.ts +0 -4
- package/dist/src/hooks/health.js +0 -86
- package/dist/src/hooks/policy_event.d.ts +0 -41
- package/dist/src/hooks/policy_event.js +0 -2634
- package/dist/src/hooks/types.d.ts +0 -72
- package/dist/src/hooks/types.js +0 -1
- package/dist/src/hooks/validation.d.ts +0 -3
- package/dist/src/hooks/validation.js +0 -70
- package/dist/src/i18n.d.ts +0 -21
- package/dist/src/i18n.js +0 -720
- package/dist/src/init_cli.d.ts +0 -28
- package/dist/src/init_cli.js +0 -399
- package/dist/src/install_engine.d.ts +0 -71
- package/dist/src/install_engine.js +0 -538
- package/dist/src/invariants.d.ts +0 -16
- package/dist/src/invariants.js +0 -363
- package/dist/src/openspec.d.ts +0 -37
- package/dist/src/openspec.js +0 -274
- package/dist/src/packet_render.d.ts +0 -5
- package/dist/src/packet_render.js +0 -1759
- package/dist/src/packet_schema.d.ts +0 -58
- package/dist/src/packet_schema.js +0 -1
- package/dist/src/paths.d.ts +0 -22
- package/dist/src/paths.js +0 -203
- package/dist/src/project_init.d.ts +0 -31
- package/dist/src/project_init.js +0 -167
- package/dist/src/self_update.d.ts +0 -14
- package/dist/src/self_update.js +0 -56
- package/dist/src/state.d.ts +0 -37
- package/dist/src/state.js +0 -464
- package/dist/src/tasks.d.ts +0 -38
- package/dist/src/tasks.js +0 -373
- package/dist/src/util.d.ts +0 -163
- package/dist/src/util.js +0 -792
- package/dist/superspec.d.ts +0 -6
- package/dist/superspec.js +0 -97
- package/dist/superspec_guard.d.ts +0 -4
- package/dist/superspec_guard.js +0 -19
- package/dist/superspec_hook.d.ts +0 -4
- package/dist/superspec_hook.js +0 -35
- package/dist/superspec_init.d.ts +0 -2
- package/dist/superspec_init.js +0 -17
- package/schemas/hook-event.schema.json +0 -27
- package/schemas/install-manifest.schema.json +0 -97
- package/templates/hooks/codex-hooks.json +0 -35
- package/templates/sidecar/archive-preservation.json +0 -11
- package/templates/sidecar/business-invariants.md +0 -38
- package/templates/sidecar/config.yaml +0 -13
- package/templates/sidecar/discovery.md +0 -33
- package/templates/sidecar/test-contract.md +0 -27
- package/templates/workflow/prompts/architect.md +0 -27
- package/templates/workflow/prompts/code-reviewer.md +0 -34
- package/templates/workflow/prompts/critic.md +0 -30
- package/templates/workflow/prompts/executor.md +0 -32
- package/templates/workflow/prompts/explore.md +0 -27
- package/templates/workflow/prompts/test-engineer.md +0 -28
- package/templates/workflow/prompts/test-runner.md +0 -35
- package/templates/workflow/prompts/verifier.md +0 -35
|
@@ -1,58 +0,0 @@
|
|
|
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
|
-
discovery_template?: string;
|
|
33
|
-
discovery_rules?: string[];
|
|
34
|
-
};
|
|
35
|
-
export type ReviewPacket = {
|
|
36
|
-
consumer: "role" | "main-thread";
|
|
37
|
-
gate: string;
|
|
38
|
-
role: string;
|
|
39
|
-
round: number;
|
|
40
|
-
target_refs: PinnedRef[];
|
|
41
|
-
source_refs: PinnedRef[];
|
|
42
|
-
required_load_refs?: PinnedRef[];
|
|
43
|
-
required_claim_ids?: string[];
|
|
44
|
-
must_read_verbatim_findings?: FindingSelector[];
|
|
45
|
-
must_read_verbatim_decisions?: DecisionSelector[];
|
|
46
|
-
required_output_kind: string;
|
|
47
|
-
output_contract_fields: string[];
|
|
48
|
-
required_review_scope?: string[];
|
|
49
|
-
stop_conditions: string[];
|
|
50
|
-
};
|
|
51
|
-
export type ApplyWorkerPacket = Record<string, any>;
|
|
52
|
-
export type PacketDispatchResult = {
|
|
53
|
-
output_format: "agent";
|
|
54
|
-
payload: WorkflowPacket | ReviewPacket | ApplyWorkerPacket;
|
|
55
|
-
} | {
|
|
56
|
-
output_format: "prompt";
|
|
57
|
-
payload: string;
|
|
58
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/src/paths.d.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { JsonMap, Reason } from "./util.ts";
|
|
2
|
-
export declare function superspec_dir(changeRoot: string): string;
|
|
3
|
-
export declare function project_superspec_dir(repoRoot: string): string;
|
|
4
|
-
export declare function sidecar_artifacts_dir(changeRoot: string): string;
|
|
5
|
-
export declare function sidecar_test_contract_path(changeRoot: string): string;
|
|
6
|
-
export declare function sidecar_business_invariants_path(changeRoot: string): string;
|
|
7
|
-
export declare function sidecar_discovery_path(changeRoot: string): string;
|
|
8
|
-
export declare function sidecar_output_path(changeRoot: string, relPath: string): string;
|
|
9
|
-
export declare function write_sidecar_text(changeRoot: string, relPath: string, text: string): string;
|
|
10
|
-
export declare function write_sidecar_json(changeRoot: string, relPath: string, data: JsonMap): string;
|
|
11
|
-
export declare function config_file(changeRoot: string): string;
|
|
12
|
-
export declare function project_config_file(repoRoot: string): string;
|
|
13
|
-
export declare function required_sidecar_paths(changeRoot: string): string[];
|
|
14
|
-
export declare function ensure_sidecar_layout(changeRoot: string): void;
|
|
15
|
-
export declare function ensure_state_layout(changeRoot: string): void;
|
|
16
|
-
export declare function find_forbidden_aliases(repoRoot: string, changeRoot: string): string[];
|
|
17
|
-
export declare function read_skill_frontmatter_name(skillPath: string): string | null;
|
|
18
|
-
export declare function read_agent_toml_name(agentPath: string): string | null;
|
|
19
|
-
export declare function parse_simple_yaml(filePath: string): JsonMap;
|
|
20
|
-
export declare function merge_config(base: JsonMap, override: JsonMap): JsonMap;
|
|
21
|
-
export declare function validate_config_keys(config: JsonMap, source: string): Reason[];
|
|
22
|
-
export declare function load_config(repoRoot: string, changeRoot: string): [JsonMap, Reason[]];
|
package/dist/src/paths.js
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { dirname, join } from "node:path";
|
|
3
|
-
import { ALLOWED_CONFIG_KEYS, BUILTIN_CONFIG, CHANGE_CONFIG_ALIASES, CONFIG_FILENAME, GuardError, PROJECT_CONFIG_ALIASES, REQUIRED_SIDECAR_DIRS, STATE_ALIASES, isObject, reason, repr, safe_within, } from "./util.js";
|
|
4
|
-
export function superspec_dir(changeRoot) {
|
|
5
|
-
return join(changeRoot, ".superspec");
|
|
6
|
-
}
|
|
7
|
-
export function project_superspec_dir(repoRoot) {
|
|
8
|
-
return join(repoRoot, ".superspec");
|
|
9
|
-
}
|
|
10
|
-
export function sidecar_artifacts_dir(changeRoot) {
|
|
11
|
-
return join(superspec_dir(changeRoot), "artifacts");
|
|
12
|
-
}
|
|
13
|
-
export function sidecar_test_contract_path(changeRoot) {
|
|
14
|
-
return join(sidecar_artifacts_dir(changeRoot), "test-contract.md");
|
|
15
|
-
}
|
|
16
|
-
export function sidecar_business_invariants_path(changeRoot) {
|
|
17
|
-
return join(sidecar_artifacts_dir(changeRoot), "business-invariants.md");
|
|
18
|
-
}
|
|
19
|
-
export function sidecar_discovery_path(changeRoot) {
|
|
20
|
-
return join(sidecar_artifacts_dir(changeRoot), "discovery.md");
|
|
21
|
-
}
|
|
22
|
-
export function sidecar_output_path(changeRoot, relPath) {
|
|
23
|
-
const target = safe_within(superspec_dir(changeRoot), relPath);
|
|
24
|
-
if (target === null)
|
|
25
|
-
throw new GuardError(`sidecar_path_invalid: ${relPath}`);
|
|
26
|
-
return target;
|
|
27
|
-
}
|
|
28
|
-
export function write_sidecar_text(changeRoot, relPath, text) {
|
|
29
|
-
const filePath = sidecar_output_path(changeRoot, relPath);
|
|
30
|
-
mkdirSync(dirname(filePath), { recursive: true });
|
|
31
|
-
writeFileSync(filePath, text, "utf8");
|
|
32
|
-
return filePath;
|
|
33
|
-
}
|
|
34
|
-
export function write_sidecar_json(changeRoot, relPath, data) {
|
|
35
|
-
return write_sidecar_text(changeRoot, relPath, `${JSON.stringify(data, null, 2)}\n`);
|
|
36
|
-
}
|
|
37
|
-
export function config_file(changeRoot) {
|
|
38
|
-
return join(superspec_dir(changeRoot), CONFIG_FILENAME);
|
|
39
|
-
}
|
|
40
|
-
export function project_config_file(repoRoot) {
|
|
41
|
-
return join(project_superspec_dir(repoRoot), CONFIG_FILENAME);
|
|
42
|
-
}
|
|
43
|
-
export function required_sidecar_paths(changeRoot) {
|
|
44
|
-
return REQUIRED_SIDECAR_DIRS.map((relPath) => join(superspec_dir(changeRoot), relPath));
|
|
45
|
-
}
|
|
46
|
-
export function ensure_sidecar_layout(changeRoot) {
|
|
47
|
-
ensure_state_layout(changeRoot);
|
|
48
|
-
for (const dirPath of required_sidecar_paths(changeRoot))
|
|
49
|
-
mkdirSync(dirPath, { recursive: true });
|
|
50
|
-
}
|
|
51
|
-
export function ensure_state_layout(changeRoot) {
|
|
52
|
-
const base = superspec_dir(changeRoot);
|
|
53
|
-
mkdirSync(base, { recursive: true });
|
|
54
|
-
const ledger = join(base, "ledger.jsonl");
|
|
55
|
-
if (!existsSync(ledger))
|
|
56
|
-
writeFileSync(ledger, "");
|
|
57
|
-
}
|
|
58
|
-
export function find_forbidden_aliases(repoRoot, changeRoot) {
|
|
59
|
-
const aliases = [];
|
|
60
|
-
for (const relPath of PROJECT_CONFIG_ALIASES) {
|
|
61
|
-
const candidate = join(repoRoot, relPath);
|
|
62
|
-
if (existsSync(candidate))
|
|
63
|
-
aliases.push(candidate);
|
|
64
|
-
}
|
|
65
|
-
for (const relPath of CHANGE_CONFIG_ALIASES) {
|
|
66
|
-
const candidate = join(changeRoot, relPath);
|
|
67
|
-
if (existsSync(candidate))
|
|
68
|
-
aliases.push(candidate);
|
|
69
|
-
}
|
|
70
|
-
for (const relPath of STATE_ALIASES) {
|
|
71
|
-
const candidate = join(changeRoot, relPath);
|
|
72
|
-
if (existsSync(candidate))
|
|
73
|
-
aliases.push(candidate);
|
|
74
|
-
}
|
|
75
|
-
return aliases;
|
|
76
|
-
}
|
|
77
|
-
export function read_skill_frontmatter_name(skillPath) {
|
|
78
|
-
let lines;
|
|
79
|
-
try {
|
|
80
|
-
lines = readFileSync(skillPath, "utf8").split(/\r?\n/);
|
|
81
|
-
}
|
|
82
|
-
catch {
|
|
83
|
-
return null;
|
|
84
|
-
}
|
|
85
|
-
if (lines.length === 0 || lines[0].trim() !== "---")
|
|
86
|
-
return null;
|
|
87
|
-
for (const raw of lines.slice(1)) {
|
|
88
|
-
const stripped = raw.trim();
|
|
89
|
-
if (stripped === "---")
|
|
90
|
-
return null;
|
|
91
|
-
if (stripped.startsWith("name:"))
|
|
92
|
-
return stripped.split(":", 2)[1].trim().replace(/^['"]|['"]$/g, "");
|
|
93
|
-
}
|
|
94
|
-
return null;
|
|
95
|
-
}
|
|
96
|
-
export function read_agent_toml_name(agentPath) {
|
|
97
|
-
let lines;
|
|
98
|
-
try {
|
|
99
|
-
lines = readFileSync(agentPath, "utf8").split(/\r?\n/);
|
|
100
|
-
}
|
|
101
|
-
catch {
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
for (const raw of lines) {
|
|
105
|
-
const match = raw.match(/^\s*name\s*=\s*["']([^"']+)["']\s*$/);
|
|
106
|
-
if (match)
|
|
107
|
-
return match[1];
|
|
108
|
-
}
|
|
109
|
-
return null;
|
|
110
|
-
}
|
|
111
|
-
function parseScalar(raw) {
|
|
112
|
-
const value = raw.trim();
|
|
113
|
-
if (!value)
|
|
114
|
-
return "";
|
|
115
|
-
if (value === "true")
|
|
116
|
-
return true;
|
|
117
|
-
if (value === "false")
|
|
118
|
-
return false;
|
|
119
|
-
if (value === "null" || value === "None")
|
|
120
|
-
return null;
|
|
121
|
-
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'")))
|
|
122
|
-
return value.slice(1, -1);
|
|
123
|
-
if (/^-?\d+$/.test(value))
|
|
124
|
-
return Number.parseInt(value, 10);
|
|
125
|
-
return value;
|
|
126
|
-
}
|
|
127
|
-
export function parse_simple_yaml(filePath) {
|
|
128
|
-
const data = {};
|
|
129
|
-
let currentKey = null;
|
|
130
|
-
const lines = readFileSync(filePath, "utf8").split(/\r?\n/);
|
|
131
|
-
lines.forEach((raw, idx) => {
|
|
132
|
-
const stripped = raw.trim();
|
|
133
|
-
if (!stripped || stripped.startsWith("#"))
|
|
134
|
-
return;
|
|
135
|
-
const indent = raw.length - raw.trimStart().length;
|
|
136
|
-
if (!stripped.includes(":"))
|
|
137
|
-
throw new GuardError(`config_parse_error: ${filePath}:${idx + 1}: expected key: value`);
|
|
138
|
-
const [keyRaw, ...rest] = stripped.split(":");
|
|
139
|
-
const key = keyRaw.trim();
|
|
140
|
-
const value = rest.join(":");
|
|
141
|
-
if (!key)
|
|
142
|
-
throw new GuardError(`config_parse_error: ${filePath}:${idx + 1}: empty key`);
|
|
143
|
-
if (indent === 0) {
|
|
144
|
-
if (value.trim()) {
|
|
145
|
-
data[key] = parseScalar(value);
|
|
146
|
-
currentKey = null;
|
|
147
|
-
}
|
|
148
|
-
else {
|
|
149
|
-
data[key] = {};
|
|
150
|
-
currentKey = key;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
else if (indent === 2 && currentKey) {
|
|
154
|
-
const parent = data[currentKey];
|
|
155
|
-
if (!isObject(parent))
|
|
156
|
-
throw new GuardError(`config_parse_error: ${filePath}:${idx + 1}: parent is not mapping`);
|
|
157
|
-
parent[key] = parseScalar(value);
|
|
158
|
-
}
|
|
159
|
-
else {
|
|
160
|
-
throw new GuardError(`config_parse_error: ${filePath}:${idx + 1}: unsupported indentation`);
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
return data;
|
|
164
|
-
}
|
|
165
|
-
export function merge_config(base, override) {
|
|
166
|
-
const merged = JSON.parse(JSON.stringify(base));
|
|
167
|
-
for (const [key, value] of Object.entries(override)) {
|
|
168
|
-
if (isObject(value) && isObject(merged[key]))
|
|
169
|
-
merged[key] = { ...merged[key], ...value };
|
|
170
|
-
else
|
|
171
|
-
merged[key] = value;
|
|
172
|
-
}
|
|
173
|
-
return merged;
|
|
174
|
-
}
|
|
175
|
-
export function validate_config_keys(config, source) {
|
|
176
|
-
const problems = [];
|
|
177
|
-
for (const key of Object.keys(config)) {
|
|
178
|
-
if (ALLOWED_CONFIG_KEYS.has(key) || key.startsWith("x-"))
|
|
179
|
-
continue;
|
|
180
|
-
problems.push(reason("unknown_config_key", `${source}: unknown config key ${repr(key)}`));
|
|
181
|
-
}
|
|
182
|
-
return problems;
|
|
183
|
-
}
|
|
184
|
-
export function load_config(repoRoot, changeRoot) {
|
|
185
|
-
const problems = [];
|
|
186
|
-
for (const aliasPath of find_forbidden_aliases(repoRoot, changeRoot)) {
|
|
187
|
-
problems.push(reason("forbidden_alias_path", `forbidden superspec alias exists: ${aliasPath}`));
|
|
188
|
-
}
|
|
189
|
-
let config = JSON.parse(JSON.stringify(BUILTIN_CONFIG));
|
|
190
|
-
const projectCfg = project_config_file(repoRoot);
|
|
191
|
-
if (existsSync(projectCfg) && statSync(projectCfg).isFile()) {
|
|
192
|
-
const parsed = parse_simple_yaml(projectCfg);
|
|
193
|
-
problems.push(...validate_config_keys(parsed, projectCfg));
|
|
194
|
-
config = merge_config(config, parsed);
|
|
195
|
-
}
|
|
196
|
-
const changeCfg = config_file(changeRoot);
|
|
197
|
-
if (existsSync(changeCfg) && statSync(changeCfg).isFile()) {
|
|
198
|
-
const parsed = parse_simple_yaml(changeCfg);
|
|
199
|
-
problems.push(...validate_config_keys(parsed, changeCfg));
|
|
200
|
-
config = merge_config(config, parsed);
|
|
201
|
-
}
|
|
202
|
-
return [config, problems];
|
|
203
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { type JsonMap, type OpenspecCliProbe } from "./core.ts";
|
|
2
|
-
export declare const OPENSPEC_NPM_PACKAGE = "@fission-ai/openspec";
|
|
3
|
-
export declare const OPENSPEC_INSTALL_DOC_URL = "https://github.com/Fission-AI/OpenSpec#readme";
|
|
4
|
-
export type OpenspecInstallPlan = {
|
|
5
|
-
manager: "npm" | "pnpm" | "yarn" | "bun";
|
|
6
|
-
cmd: string;
|
|
7
|
-
args: string[];
|
|
8
|
-
rendered: string;
|
|
9
|
-
};
|
|
10
|
-
export declare function recommended_openspec_install_plan(opts?: {
|
|
11
|
-
cwd?: string;
|
|
12
|
-
commandExistsFn?: (cmd: string, meta?: {
|
|
13
|
-
cwd?: string;
|
|
14
|
-
}) => boolean;
|
|
15
|
-
}): OpenspecInstallPlan | null;
|
|
16
|
-
export declare function forced_openspec_install_plan(plan: OpenspecInstallPlan): OpenspecInstallPlan;
|
|
17
|
-
export declare function missing_openspec_cli_message(opts?: {
|
|
18
|
-
cwd?: string;
|
|
19
|
-
commandExistsFn?: (cmd: string, meta?: {
|
|
20
|
-
cwd?: string;
|
|
21
|
-
}) => boolean;
|
|
22
|
-
}): string;
|
|
23
|
-
export declare function openspec_cli_requirement_message(probe: OpenspecCliProbe, opts?: {
|
|
24
|
-
cwd?: string;
|
|
25
|
-
commandExistsFn?: (cmd: string, meta?: {
|
|
26
|
-
cwd?: string;
|
|
27
|
-
}) => boolean;
|
|
28
|
-
}): string;
|
|
29
|
-
export declare function project_init(repoRootRaw?: string, opts?: {
|
|
30
|
-
force?: boolean;
|
|
31
|
-
}): JsonMap;
|
package/dist/src/project_init.js
DELETED
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { join, resolve } from "node:path";
|
|
3
|
-
import { REQUIRED_SUPERSPEC_AGENT_ROLES, REQUIRED_OPENSPEC_MIN_VERSION, block, commandExists, openspec_cli_probe, reason, read_agent_toml_name, } from "./core.js";
|
|
4
|
-
import { install_workflow } from "./install_engine.js";
|
|
5
|
-
export const OPENSPEC_NPM_PACKAGE = "@fission-ai/openspec";
|
|
6
|
-
export const OPENSPEC_INSTALL_DOC_URL = "https://github.com/Fission-AI/OpenSpec#readme";
|
|
7
|
-
const ROLE_DESCRIPTIONS = {
|
|
8
|
-
architect: "系统设计、边界、接口与长期取舍",
|
|
9
|
-
critic: "严格审查计划、证据、假设与范围漂移",
|
|
10
|
-
"test-engineer": "测试策略、覆盖率与 RED/GREEN 证据审查",
|
|
11
|
-
"code-reviewer": "代码 / 规格 / 安全审查",
|
|
12
|
-
verifier: "最终完成证据与验证审查",
|
|
13
|
-
};
|
|
14
|
-
function renderCommand(cmd, args) {
|
|
15
|
-
return [cmd, ...args].join(" ");
|
|
16
|
-
}
|
|
17
|
-
export function recommended_openspec_install_plan(opts = {}) {
|
|
18
|
-
const commandExistsFn = opts.commandExistsFn ?? ((cmd, meta) => commandExists(cmd, { cwd: meta?.cwd }));
|
|
19
|
-
const versionedPackage = `${OPENSPEC_NPM_PACKAGE}@latest`;
|
|
20
|
-
const candidates = [
|
|
21
|
-
{ manager: "npm", cmd: "npm", args: ["install", "-g", versionedPackage] },
|
|
22
|
-
{ manager: "pnpm", cmd: "pnpm", args: ["add", "-g", versionedPackage] },
|
|
23
|
-
{ manager: "yarn", cmd: "yarn", args: ["global", "add", versionedPackage] },
|
|
24
|
-
{ manager: "bun", cmd: "bun", args: ["add", "-g", versionedPackage] },
|
|
25
|
-
];
|
|
26
|
-
for (const candidate of candidates) {
|
|
27
|
-
if (!commandExistsFn(candidate.cmd, { cwd: opts.cwd }))
|
|
28
|
-
continue;
|
|
29
|
-
return { ...candidate, rendered: renderCommand(candidate.cmd, candidate.args) };
|
|
30
|
-
}
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
export function forced_openspec_install_plan(plan) {
|
|
34
|
-
const versionedPackage = `${OPENSPEC_NPM_PACKAGE}@latest`;
|
|
35
|
-
const forced = {
|
|
36
|
-
npm: ["install", "-g", "--force", versionedPackage],
|
|
37
|
-
pnpm: ["add", "-g", "--force", versionedPackage],
|
|
38
|
-
yarn: ["global", "add", versionedPackage, "--force"],
|
|
39
|
-
bun: ["add", "-g", "--force", versionedPackage],
|
|
40
|
-
};
|
|
41
|
-
return { ...plan, args: forced[plan.manager], rendered: renderCommand(plan.cmd, forced[plan.manager]) };
|
|
42
|
-
}
|
|
43
|
-
export function missing_openspec_cli_message(opts = {}) {
|
|
44
|
-
return openspec_cli_requirement_message({
|
|
45
|
-
ok: false,
|
|
46
|
-
state: "missing",
|
|
47
|
-
version: null,
|
|
48
|
-
message: "PATH 中缺少 OpenSpec CLI(openspec)",
|
|
49
|
-
}, opts);
|
|
50
|
-
}
|
|
51
|
-
export function openspec_cli_requirement_message(probe, opts = {}) {
|
|
52
|
-
const plan = recommended_openspec_install_plan(opts);
|
|
53
|
-
if (plan) {
|
|
54
|
-
return `${probe.message}。需要 @fission-ai/openspec >= ${REQUIRED_OPENSPEC_MIN_VERSION}。可先运行 \`${plan.rendered}\` 安装或升级,然后重新运行 \`superspec init --scope project\`。`;
|
|
55
|
-
}
|
|
56
|
-
return `${probe.message}。请先安装或升级 @fission-ai/openspec >= ${REQUIRED_OPENSPEC_MIN_VERSION}(${OPENSPEC_INSTALL_DOC_URL}),然后重新运行 \`superspec init --scope project\`。`;
|
|
57
|
-
}
|
|
58
|
-
function writeSuperSpecAgent(repoRoot, name) {
|
|
59
|
-
const filePath = join(repoRoot, ".codex", "agents", `${name}.toml`);
|
|
60
|
-
mkdirSync(join(repoRoot, ".codex", "agents"), { recursive: true });
|
|
61
|
-
writeFileSync(filePath, [
|
|
62
|
-
`name = "${name}"`,
|
|
63
|
-
`description = "${ROLE_DESCRIPTIONS[name] ?? `superspec ${name} role`}"`,
|
|
64
|
-
'model_reasoning_effort = "high"',
|
|
65
|
-
'developer_instructions = """',
|
|
66
|
-
`你是仓库本地的 superspec ${name} native subagent。`,
|
|
67
|
-
"遵循分配给你的 superspec gate 证据任务,引用具体文件,并把未通过的问题上报主流程。",
|
|
68
|
-
"不要用主流程自审替代必须的角色证据。",
|
|
69
|
-
'"""',
|
|
70
|
-
"",
|
|
71
|
-
].join("\n"), "utf8");
|
|
72
|
-
return filePath;
|
|
73
|
-
}
|
|
74
|
-
function writeSuperSpecPrompt(repoRoot, name) {
|
|
75
|
-
const filePath = join(repoRoot, ".codex", "prompts", `${name}.md`);
|
|
76
|
-
mkdirSync(join(repoRoot, ".codex", "prompts"), { recursive: true });
|
|
77
|
-
writeFileSync(filePath, [
|
|
78
|
-
"---",
|
|
79
|
-
`description: "${ROLE_DESCRIPTIONS[name] ?? `superspec ${name} role`}"`,
|
|
80
|
-
'argument-hint: "superspec gate evidence task"',
|
|
81
|
-
"---",
|
|
82
|
-
"",
|
|
83
|
-
`你是仓库本地的 superspec ${name} 角色。`,
|
|
84
|
-
"",
|
|
85
|
-
"请基于具体文件证据审查提供的 superspec gate 上下文,输出简洁的通过 / 未通过报告,引用 source anchors 与 target refs,并且不要用主流程自审替代必须的 native-subagent 证据。",
|
|
86
|
-
"",
|
|
87
|
-
].join("\n"), "utf8");
|
|
88
|
-
return filePath;
|
|
89
|
-
}
|
|
90
|
-
function ensureOpenSpecCliSurface(repoRoot, actions) {
|
|
91
|
-
const probe = openspec_cli_probe({ cwd: repoRoot });
|
|
92
|
-
actions.push({
|
|
93
|
-
action: "openspec_cli_surface",
|
|
94
|
-
status: probe.ok ? "ok" : "failed",
|
|
95
|
-
detail: probe.message,
|
|
96
|
-
});
|
|
97
|
-
return probe.ok ? [] : [openspec_cli_requirement_message(probe, { cwd: repoRoot })];
|
|
98
|
-
}
|
|
99
|
-
function ensureSuperSpecRoles(repoRoot, actions) {
|
|
100
|
-
const problems = [];
|
|
101
|
-
const created = [];
|
|
102
|
-
for (const name of REQUIRED_SUPERSPEC_AGENT_ROLES) {
|
|
103
|
-
const agentPath = join(repoRoot, ".codex", "agents", `${name}.toml`);
|
|
104
|
-
if (!existsSync(agentPath) || !statSync(agentPath).isFile()) {
|
|
105
|
-
created.push(writeSuperSpecAgent(repoRoot, name));
|
|
106
|
-
}
|
|
107
|
-
else if (read_agent_toml_name(agentPath) !== name) {
|
|
108
|
-
problems.push(`agent 文件无效:${agentPath}`);
|
|
109
|
-
}
|
|
110
|
-
const promptPath = join(repoRoot, ".codex", "prompts", `${name}.md`);
|
|
111
|
-
if (!existsSync(promptPath) || !statSync(promptPath).isFile()) {
|
|
112
|
-
created.push(writeSuperSpecPrompt(repoRoot, name));
|
|
113
|
-
}
|
|
114
|
-
else if (!readFileSync(promptPath, "utf8").trim()) {
|
|
115
|
-
problems.push(`prompt 文件为空:${promptPath}`);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
actions.push({
|
|
119
|
-
action: "superspec_repo_local_roles",
|
|
120
|
-
status: problems.length > 0 ? "failed" : created.length > 0 ? "created" : "ok",
|
|
121
|
-
refs: created.length > 0 ? created : undefined,
|
|
122
|
-
});
|
|
123
|
-
return problems;
|
|
124
|
-
}
|
|
125
|
-
// D4 (audit G-1): SuperSpec's own surfaces are installed manifest-driven from the install map;
|
|
126
|
-
// it runs before the role fallback generator so canonical templates win on fresh installs.
|
|
127
|
-
function ensureSuperSpecWorkflow(repoRoot, actions, force) {
|
|
128
|
-
const result = install_workflow(repoRoot, { force, scope: "project" });
|
|
129
|
-
for (const item of result.actions) {
|
|
130
|
-
actions.push({
|
|
131
|
-
action: item.action,
|
|
132
|
-
status: item.status === "removed" || item.status === "would_remove" ? "updated" : item.status,
|
|
133
|
-
refs: item.refs,
|
|
134
|
-
detail: item.detail,
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
return result.problems;
|
|
138
|
-
}
|
|
139
|
-
export function project_init(repoRootRaw = process.cwd(), opts = {}) {
|
|
140
|
-
const repoRoot = resolve(repoRootRaw);
|
|
141
|
-
const actions = [];
|
|
142
|
-
const problems = [
|
|
143
|
-
...ensureOpenSpecCliSurface(repoRoot, actions),
|
|
144
|
-
...ensureSuperSpecWorkflow(repoRoot, actions, opts.force === true),
|
|
145
|
-
...ensureSuperSpecRoles(repoRoot, actions),
|
|
146
|
-
];
|
|
147
|
-
if (problems.length > 0) {
|
|
148
|
-
const decision = block("project", "project_init", problems.map((item) => reason("project_init_failed", item)));
|
|
149
|
-
return {
|
|
150
|
-
...decision,
|
|
151
|
-
project_root: repoRoot,
|
|
152
|
-
actions,
|
|
153
|
-
next_allowed_actions: ["fix project_init_failed reasons, then rerun superspec init --scope project"],
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
return {
|
|
157
|
-
allowed: true,
|
|
158
|
-
decision: "allow",
|
|
159
|
-
change_id: null,
|
|
160
|
-
gate: "project_init",
|
|
161
|
-
project_root: repoRoot,
|
|
162
|
-
actions,
|
|
163
|
-
block_reasons: [],
|
|
164
|
-
next_allowed_actions: ["create/select a change during superspec-explore, then run change-scoped guard checks"],
|
|
165
|
-
trust_warnings: ["project init installs project surfaces only; change sidecars are created lazily by later superspec phases"],
|
|
166
|
-
};
|
|
167
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { runCommand } from "./util.ts";
|
|
2
|
-
type RunFn = typeof runCommand;
|
|
3
|
-
type CommandExistsFn = (cmd: string, meta?: {
|
|
4
|
-
cwd?: string;
|
|
5
|
-
}) => boolean;
|
|
6
|
-
export declare function update_self_then_rerun(opts: {
|
|
7
|
-
args: string[];
|
|
8
|
-
cwd?: string;
|
|
9
|
-
run?: RunFn;
|
|
10
|
-
commandExistsFn?: CommandExistsFn;
|
|
11
|
-
writeStdout?: (text: string) => void;
|
|
12
|
-
writeStderr?: (text: string) => void;
|
|
13
|
-
}): number;
|
|
14
|
-
export {};
|
package/dist/src/self_update.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { commandExists, runCommand } from "./util.js";
|
|
2
|
-
const SUPERSPEC_NPM_PACKAGE = "@peterxiaoyang/superspec";
|
|
3
|
-
function renderCommand(cmd, args) {
|
|
4
|
-
return [cmd, ...args].join(" ");
|
|
5
|
-
}
|
|
6
|
-
function commandFailure(proc) {
|
|
7
|
-
const output = (proc.error?.message ?? (proc.stderr || proc.stdout)).trim();
|
|
8
|
-
if (output)
|
|
9
|
-
return output;
|
|
10
|
-
return proc.status === null ? "command failed" : `command exited with status ${proc.status}`;
|
|
11
|
-
}
|
|
12
|
-
function shouldRetrySuperSpecInstallWithForce(proc) {
|
|
13
|
-
const output = `${proc.error?.message ?? ""}\n${proc.stderr}\n${proc.stdout}`;
|
|
14
|
-
const binConflict = /\bEEXIST\b|already exists|file exists|Refusing to delete|will not overwrite|would overwrite/iu.test(output);
|
|
15
|
-
const superspecBin = /\bsuperspec(?:\.(?:cmd|ps1))?\b/iu.test(output);
|
|
16
|
-
return binConflict && superspecBin;
|
|
17
|
-
}
|
|
18
|
-
export function update_self_then_rerun(opts) {
|
|
19
|
-
const cwd = opts.cwd ?? process.cwd();
|
|
20
|
-
const run = opts.run ?? runCommand;
|
|
21
|
-
const commandExistsFn = opts.commandExistsFn ?? ((cmd, meta) => commandExists(cmd, { cwd: meta?.cwd }));
|
|
22
|
-
const writeStdout = opts.writeStdout ?? ((text) => process.stdout.write(text));
|
|
23
|
-
const writeStderr = opts.writeStderr ?? ((text) => process.stderr.write(text));
|
|
24
|
-
if (!commandExistsFn("npm", { cwd })) {
|
|
25
|
-
writeStderr("SuperSpec update requires npm on PATH to install @peterxiaoyang/superspec@latest. Use `superspec update --local-only` to update surfaces from the currently installed package.\n");
|
|
26
|
-
return 1;
|
|
27
|
-
}
|
|
28
|
-
const installArgs = ["install", "-g", `${SUPERSPEC_NPM_PACKAGE}@latest`];
|
|
29
|
-
writeStderr(`Updating SuperSpec CLI: ${renderCommand("npm", installArgs)}\n`);
|
|
30
|
-
let install = run("npm", installArgs, { cwd, timeout: 300_000 });
|
|
31
|
-
if ((install.error || install.status !== 0) && shouldRetrySuperSpecInstallWithForce(install)) {
|
|
32
|
-
const forcedArgs = ["install", "-g", "--force", `${SUPERSPEC_NPM_PACKAGE}@latest`];
|
|
33
|
-
writeStderr(`SuperSpec CLI install hit a global bin conflict; retrying with: ${renderCommand("npm", forcedArgs)}\n`);
|
|
34
|
-
install = run("npm", forcedArgs, { cwd, timeout: 300_000 });
|
|
35
|
-
}
|
|
36
|
-
if (install.error || install.status !== 0) {
|
|
37
|
-
writeStderr(`SuperSpec CLI update failed: ${commandFailure(install)}\n`);
|
|
38
|
-
return 1;
|
|
39
|
-
}
|
|
40
|
-
if (!commandExistsFn("superspec", { cwd })) {
|
|
41
|
-
writeStderr("SuperSpec CLI update completed, but `superspec` is not resolvable from PATH. Reopen the shell or check npm global bin configuration.\n");
|
|
42
|
-
return 1;
|
|
43
|
-
}
|
|
44
|
-
const rerunArgs = ["update", ...opts.args, "--skip-self-update"];
|
|
45
|
-
const rerun = run("superspec", rerunArgs, { cwd, timeout: 300_000 });
|
|
46
|
-
if (rerun.stdout)
|
|
47
|
-
writeStdout(rerun.stdout);
|
|
48
|
-
if (rerun.stderr)
|
|
49
|
-
writeStderr(rerun.stderr);
|
|
50
|
-
if (rerun.error || rerun.status !== 0) {
|
|
51
|
-
if (rerun.error && !rerun.stderr)
|
|
52
|
-
writeStderr(`SuperSpec update rerun failed: ${rerun.error.message}\n`);
|
|
53
|
-
return rerun.status ?? 1;
|
|
54
|
-
}
|
|
55
|
-
return 0;
|
|
56
|
-
}
|
package/dist/src/state.d.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import type { JsonMap, Reason } from "./util.ts";
|
|
2
|
-
export declare function state_file(changeRoot: string): string;
|
|
3
|
-
export declare function ledger_file(changeRoot: string): string;
|
|
4
|
-
export declare function load_state(changeRoot: string): JsonMap | null;
|
|
5
|
-
export declare function state_file_corrupt(changeRoot: string): boolean;
|
|
6
|
-
export declare function state_corrupt_reasons(changeRoot: string): Reason[];
|
|
7
|
-
export declare function read_ledger_text(changeRoot: string): string;
|
|
8
|
-
export declare function compute_fingerprints(changeRoot: string, status: JsonMap): JsonMap;
|
|
9
|
-
export declare function state_stale_reasons(changeRoot: string, status: JsonMap): Reason[];
|
|
10
|
-
export declare function materialize_ledger_event(event: JsonMap): JsonMap;
|
|
11
|
-
export declare function ledger_event_line(event: JsonMap): string;
|
|
12
|
-
export declare function with_state_lock<T>(changeRoot: string, fn: () => T): T;
|
|
13
|
-
export declare function force_unlock_state(changeRoot: string): boolean;
|
|
14
|
-
export declare function prepare_recomputed_state_write(change: string, changeRoot: string, status: JsonMap, guardRoutePhase: string, activeGate: string, decision: JsonMap, opts?: {
|
|
15
|
-
config?: JsonMap | null;
|
|
16
|
-
preset_upgrade_required?: boolean;
|
|
17
|
-
fingerprints?: JsonMap | null;
|
|
18
|
-
}): JsonMap;
|
|
19
|
-
export declare function write_prepared_state_locked(changeRoot: string, prepared: JsonMap): void;
|
|
20
|
-
export declare function restore_state_snapshot_locked(changeRoot: string, snapshot: {
|
|
21
|
-
state_text: string | null;
|
|
22
|
-
ledger_text: string;
|
|
23
|
-
}): void;
|
|
24
|
-
export declare function write_state_atomic(changeRoot: string, state: JsonMap, opts?: {
|
|
25
|
-
expected_state_fingerprints?: JsonMap | null;
|
|
26
|
-
ledger_event?: JsonMap | null;
|
|
27
|
-
}): void;
|
|
28
|
-
export declare function append_ledger(changeRoot: string, event: JsonMap): void;
|
|
29
|
-
export declare function record_supersede_ledger_events(change: string, changeRoot: string, evidences: JsonMap[]): void;
|
|
30
|
-
export declare function recompute_and_write_state_locked(change: string, changeRoot: string, status: JsonMap, guardRoutePhase: string, activeGate: string, decision: JsonMap, opts?: {
|
|
31
|
-
config?: JsonMap | null;
|
|
32
|
-
preset_upgrade_required?: boolean;
|
|
33
|
-
}): JsonMap;
|
|
34
|
-
export declare function recompute_and_write_state(change: string, changeRoot: string, status: JsonMap, guardRoutePhase: string, activeGate: string, decision: JsonMap, opts?: {
|
|
35
|
-
config?: JsonMap | null;
|
|
36
|
-
preset_upgrade_required?: boolean;
|
|
37
|
-
}): JsonMap;
|