create-yss-spec 3.5.4 → 3.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/cli-core.lock.json +130 -0
- package/package.json +7 -3
- package/resources/upgrade-skill/SKILL.md +26 -0
- package/resources/upgrade-skill/protocol.md +40 -0
- package/resources/upgrade-skill/references/cli-families.md +14 -0
- package/src/cli/help.js +1 -0
- package/src/cli/index.js +12 -0
- package/src/filesystem/transaction-runner.js +27 -0
- package/src/template/asset-runtime.js +6 -0
- package/src/template/verification-runtime.js +9 -1
- package/template/.agents/skills/.strategic-design-skills-manifest.json +2 -2
- package/template/.agents/skills/yss-harness-upgrade/SKILL.md +26 -0
- package/template/.agents/skills/yss-harness-upgrade/references/cli-families.md +14 -0
- package/template/.agents/skills/yss-implementation-contract-compiler/references/boundaries.md +1 -0
- package/template/.agents/skills/yss-product-lifecycle/SKILL.md +15 -19
- package/template/.agents/skills/yss-stage-decision/SKILL.md +3 -0
- package/template/.agents/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +8 -4
- package/template/.agents/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +8 -4
- package/template/.agents/skills/yss-stage-decision/tests/run-scenarios.mjs +13 -1
- package/template/.codex/skills/yss-harness-upgrade/SKILL.md +26 -0
- package/template/.codex/skills/yss-harness-upgrade/references/cli-families.md +14 -0
- package/template/.codex/skills/yss-implementation-contract-compiler/references/boundaries.md +1 -0
- package/template/.codex/skills/yss-product-lifecycle/SKILL.md +15 -19
- package/template/.codex/skills/yss-stage-decision/SKILL.md +3 -0
- package/template/.codex/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +8 -4
- package/template/.codex/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +8 -4
- package/template/.codex/skills/yss-stage-decision/tests/run-scenarios.mjs +13 -1
- package/template/.cursor/skills/yss-harness-upgrade/SKILL.md +26 -0
- package/template/.cursor/skills/yss-harness-upgrade/references/cli-families.md +14 -0
- package/template/.cursor/skills/yss-implementation-contract-compiler/references/boundaries.md +1 -0
- package/template/.cursor/skills/yss-product-lifecycle/SKILL.md +15 -19
- package/template/.cursor/skills/yss-stage-decision/SKILL.md +3 -0
- package/template/.cursor/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +8 -4
- package/template/.cursor/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +8 -4
- package/template/.cursor/skills/yss-stage-decision/tests/run-scenarios.mjs +13 -1
- package/template/.pi/skills/yss-harness-upgrade/SKILL.md +26 -0
- package/template/.pi/skills/yss-harness-upgrade/references/cli-families.md +14 -0
- package/template/.pi/skills/yss-implementation-contract-compiler/references/boundaries.md +1 -0
- package/template/.pi/skills/yss-product-lifecycle/SKILL.md +15 -19
- package/template/.pi/skills/yss-stage-decision/SKILL.md +3 -0
- package/template/.pi/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +8 -4
- package/template/.pi/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +8 -4
- package/template/.pi/skills/yss-stage-decision/tests/run-scenarios.mjs +13 -1
- package/template/.template-spec/agents/yss-skill-registry.yaml +9 -1
- package/template/.template-spec/process/contract-reading.md +1 -1
- package/template/.template-spec/process/document-writing.md +12 -0
- package/template/.template-spec/process/harness-upgrade.md +40 -0
- package/template/.template-spec/process/lifecycle-artifact-map.md +2 -2
- package/template/.template-spec/process/lifecycle-registry.yaml +3 -1
- package/template/.template-spec/process/schemas/approval-record.schema.json +23 -0
- package/template/.template-spec/process/stage-tracking.md +2 -2
- package/template/.template-spec/process/structured-assets.md +35 -0
- package/template/.template-spec/process/templates/lifecycle-checkpoint-template.json +48 -0
- package/template/.template-spec/templates/approval-record-template.json +23 -0
- package/template/scripts/check-plan-stage-coverage +12 -0
- package/template/scripts/contract +6 -0
- package/template/scripts/lib/approval-record.mjs +4 -3
- package/template/scripts/lib/asset-command.mjs +35 -0
- package/template/scripts/lib/asset-migration.mjs +101 -0
- package/template/scripts/lib/asset-transactions.mjs +235 -0
- package/template/scripts/lib/checkpoint-boundary.mjs +3 -0
- package/template/scripts/lib/contract-views.mjs +7 -1
- package/template/scripts/lib/json-schema.mjs +43 -4
- package/template/scripts/lib/lifecycle-context-query.mjs +7 -0
- package/template/scripts/lib/lifecycle-presentation.mjs +77 -0
- package/template/scripts/lib/lifecycle-status.mjs +16 -1
- package/template/scripts/lib/plan-stage-coverage.mjs +40 -0
- package/template/scripts/lib/reading-view-bundle.mjs +1 -0
- package/template/scripts/lib/reading-view-markdown.mjs +8 -6
- package/template/scripts/lib/stage-tracking-migration.mjs +11 -3
- package/template/scripts/lib/structured-assets.mjs +81 -0
- package/template/scripts/lib/task-package.mjs +4 -1
- package/template/scripts/lifecycle-status +6 -3
- package/template/scripts/verify-lifecycle-checkpoint +8 -5
- package/template/skills-lock.json +21 -9
- package/template.manifest.json +2 -1
- package/template.snapshot.json +5 -5
- package/vendor/cli-core/build.mjs +302 -0
- package/vendor/cli-core/bundle.mjs +198 -0
- package/vendor/cli-core/cli.mjs +182 -0
- package/vendor/cli-core/command-runner.mjs +107 -0
- package/vendor/cli-core/engine.mjs +239 -0
- package/vendor/cli-core/family.mjs +28 -0
- package/vendor/cli-core/gitignore.mjs +15 -0
- package/vendor/cli-core/identity.mjs +274 -0
- package/vendor/cli-core/io.mjs +153 -0
- package/vendor/cli-core/layout-migration.mjs +64 -0
- package/vendor/cli-core/legacy.mjs +19 -0
- package/vendor/cli-core/migrate.mjs +237 -0
- package/vendor/cli-core/migration-adapter.mjs +19 -0
- package/vendor/cli-core/package.json +13 -0
- package/vendor/cli-core/scaffold.mjs +117 -0
- package/vendor/cli-core/spec-migration-adapter.mjs +83 -0
- package/vendor/cli-core/tests/build.test.mjs +40 -0
- package/vendor/cli-core/tests/cli.test.mjs +1065 -0
- package/vendor/cli-core/tests/migration-version.test.mjs +8 -0
- package/vendor/cli-core/tests/package-contract.mjs +75 -0
- package/vendor/cli-core/transaction.mjs +529 -0
- package/vendor/cli-core/update.mjs +79 -0
- package/vendor/cli-core/vendor/NOTICES.md +6 -0
- package/vendor/cli-core/vendor/yaml.LICENSE +13 -0
- package/vendor/cli-core/vendor/yaml.mjs +6311 -0
- package/vendor/cli-core/verification.mjs +131 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { spawnSync } from 'node:child_process';
|
|
5
|
+
import { CHECKS } from './family.mjs';
|
|
6
|
+
import { descriptor, ensure, hash, safe, stat, write, same } from './io.mjs';
|
|
7
|
+
import { identity, gitlinks, guardNestedRepository } from './identity.mjs';
|
|
8
|
+
import { inspectState, recoveryPreview } from './transaction.mjs';
|
|
9
|
+
|
|
10
|
+
function run(root, ref, args = []) {
|
|
11
|
+
const result = spawnSync(process.execPath, [safe(root, ref), ...args], {cwd:root,encoding:'utf8',timeout:120000,maxBuffer:16*1024*1024});
|
|
12
|
+
ensure(!result.error && result.status === 0, `${ref}: ${result.error?.message || result.stderr || result.stdout}`, 'VERIFY');
|
|
13
|
+
return {exitCode:result.status};
|
|
14
|
+
}
|
|
15
|
+
function skillTree(root, ref) {
|
|
16
|
+
const files = [];
|
|
17
|
+
function visit(relative) {
|
|
18
|
+
const s = stat(safe(root, relative));
|
|
19
|
+
ensure(s, `缺少技能目录: ${relative}`, 'VERIFY');
|
|
20
|
+
if (s.isDirectory()) for (const name of fs.readdirSync(safe(root, relative)).sort()) {
|
|
21
|
+
if (name === '.DS_Store' || name === '__pycache__' || /\.(pyc|pyo)$/.test(name)) continue;
|
|
22
|
+
visit(relative + '/' + name);
|
|
23
|
+
} else { const d = descriptor(root, relative); files.push([relative.slice(ref.length), d.digest]); }
|
|
24
|
+
}
|
|
25
|
+
visit(ref);
|
|
26
|
+
return JSON.stringify(files);
|
|
27
|
+
}
|
|
28
|
+
export function verifyInstance(bundle, root) {
|
|
29
|
+
identity(root, bundle, 'doctor');
|
|
30
|
+
const checks = [];
|
|
31
|
+
if (!bundle.files.has('skills-lock.json')) return checks;
|
|
32
|
+
for (const [name, ref, ...args] of CHECKS) checks.push({name,status:'ok',...run(root,ref,args)});
|
|
33
|
+
const lock = JSON.parse(fs.readFileSync(safe(root, 'skills-lock.json')));
|
|
34
|
+
ensure(lock.version === 3 && lock.skills?.shared && Array.isArray(lock.projectionRoots), '技能锁 schema 非法', 'VERIFY');
|
|
35
|
+
for (const name of Object.keys(lock.skills.shared)) {
|
|
36
|
+
const canonical = skillTree(root, `.agents/skills/${name}`);
|
|
37
|
+
for (const projection of lock.projectionRoots) ensure(skillTree(root, `${projection}/${name}`) === canonical, `技能投影漂移: ${projection}/${name}`, 'VERIFY');
|
|
38
|
+
}
|
|
39
|
+
checks.push({name:'skill-projections',status:'ok'});
|
|
40
|
+
return checks;
|
|
41
|
+
}
|
|
42
|
+
// Prepare the generated lock outside the target, with the same candidate bytes
|
|
43
|
+
// that the transaction will apply. Unknown user skills are never auto-enrolled.
|
|
44
|
+
export function prepareGenerated(bundle, target, operations, metadata, observe) {
|
|
45
|
+
if (!bundle.files.has('skills-lock.json')) return;
|
|
46
|
+
const scratch = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-candidate-'));
|
|
47
|
+
try {
|
|
48
|
+
const refs = new Set([...bundle.files.keys(), ...Object.keys(metadata.managedFiles)]);
|
|
49
|
+
const roots = ['.agents/skills','.claude/skills','.codex/skills','.cursor/skills','.pi/skills','.qoder/skills','.trae/skills'];
|
|
50
|
+
function collect(ref) {
|
|
51
|
+
const s = stat(safe(target, ref));
|
|
52
|
+
if (!s) return;
|
|
53
|
+
if (s.isDirectory()) for (const name of fs.readdirSync(safe(target, ref))) {
|
|
54
|
+
if (name !== '.DS_Store' && name !== '__pycache__' && !/\.(pyc|pyo)$/.test(name)) collect(ref + '/' + name);
|
|
55
|
+
}
|
|
56
|
+
else refs.add(ref);
|
|
57
|
+
}
|
|
58
|
+
for (const root of roots) collect(root);
|
|
59
|
+
for (const ref of refs) {
|
|
60
|
+
const d = descriptor(target, ref);
|
|
61
|
+
if (observe.has(ref)) ensure(same(observe.get(ref),d), `候选生成期间发生并发修改: ${ref}`, "CONCURRENT");
|
|
62
|
+
else observe.set(ref, d);
|
|
63
|
+
if (d) write(scratch, ref, fs.readFileSync(safe(target, ref)), d.mode);
|
|
64
|
+
}
|
|
65
|
+
for (const op of operations) {
|
|
66
|
+
if (op.after) write(scratch,op.path,op.bytes,op.after.mode);
|
|
67
|
+
else if (stat(safe(scratch,op.path))) fs.unlinkSync(safe(scratch,op.path));
|
|
68
|
+
}
|
|
69
|
+
// Seed registered project extensions without enrolling unknown directories.
|
|
70
|
+
const oldPath = safe(target, 'skills-lock.json');
|
|
71
|
+
if (stat(oldPath)) {
|
|
72
|
+
const old = JSON.parse(fs.readFileSync(oldPath));
|
|
73
|
+
const seed = JSON.parse(fs.readFileSync(safe(scratch,'skills-lock.json')));
|
|
74
|
+
ensure(old.version === 3 && old.skills?.shared, '现有技能锁非法', 'VERIFY');
|
|
75
|
+
for (const [name, record] of Object.entries(old.skills.shared)) {
|
|
76
|
+
const ref = `.agents/skills/${name}`;
|
|
77
|
+
const wasManaged = Object.keys(metadata.managedFiles).some(p=>p.startsWith(ref+'/'));
|
|
78
|
+
if (!seed.skills.shared[name] && !wasManaged && stat(safe(scratch,ref))) seed.skills.shared[name] = record;
|
|
79
|
+
}
|
|
80
|
+
for (const [root, entries] of Object.entries(old.skills.platform || {})) for (const [name, record] of Object.entries(entries)) {
|
|
81
|
+
if (stat(safe(scratch,`${root}/${name}`))) { seed.skills.platform ||= {}; seed.skills.platform[root] ||= {}; seed.skills.platform[root][name] ||= record; }
|
|
82
|
+
}
|
|
83
|
+
seed.sources={...old.sources,...seed.sources};
|
|
84
|
+
write(scratch,'skills-lock.json',JSON.stringify(seed,null,2)+'\n');
|
|
85
|
+
}
|
|
86
|
+
run(scratch,'scripts/update-skill-lock');
|
|
87
|
+
const ref = 'skills-lock.json', bytes = fs.readFileSync(safe(scratch,ref));
|
|
88
|
+
const before = descriptor(target,ref), after = {type:'file',digest:hash(bytes),mode:0o644};
|
|
89
|
+
const index = operations.findIndex(op=>op.path===ref);
|
|
90
|
+
if (index !== -1) operations.splice(index,1);
|
|
91
|
+
if (!same(before,after)) operations.push({path:ref,before,after,bytes});
|
|
92
|
+
metadata.managedFiles[ref] = {baseline:after,lastApplied:after,ownership:'generated'};
|
|
93
|
+
metadata.baselineDigest=hash(JSON.stringify(metadata.managedFiles));
|
|
94
|
+
write(scratch,bundle.family.metadataFile,JSON.stringify(metadata,null,2)+'\n');
|
|
95
|
+
verifyInstance(bundle,scratch);
|
|
96
|
+
} finally { fs.rmSync(scratch,{recursive:true,force:true}); }
|
|
97
|
+
}
|
|
98
|
+
export function doctor(bundle, target) {
|
|
99
|
+
const report = {schemaVersion:1,command:'doctor',status:'healthy',target,cliVersion:bundle.pkg.version,coreVersion:bundle.core.coreVersion,templateCommit:bundle.snapshot.templateCommit,templateSourceState:bundle.snapshot.sourceState || "committed",coreSourceState:bundle.core.sourceState || "committed",checks:[]};
|
|
100
|
+
function check(name, fn) {
|
|
101
|
+
try { const data = fn(); report.checks.push({name,status:'ok',...data}); return data; }
|
|
102
|
+
catch(error) { report.status='error';report.checks.push({name,status:'error',code:error.code || 'INVALID',message:error.message}); }
|
|
103
|
+
}
|
|
104
|
+
check('target',()=>{ensure(stat(target)?.isDirectory(),'目标目录不存在','PATH');});
|
|
105
|
+
const state = check('transactions',()=>{const s=inspectState(target,bundle.family);if(s.pending.length){const r=recoveryPreview(target,bundle.family,s);throw Object.assign(new Error(`发现 ${s.pending.length} 个未完成事务;运行 recover 查看计划`),{code:'INTERRUPTED',result:r});}return s;});
|
|
106
|
+
const meta = check('identity',()=>({metadata:identity(target,bundle,'doctor')}))?.metadata;
|
|
107
|
+
if(meta) {
|
|
108
|
+
if(meta.legacyRetainedFiles?.length) report.checks.push({name:'legacy-retained',status:'warning',paths:meta.legacyRetainedFiles,message:'旧创建脚本已退出管理,保留原文件;请按项目决定人工移除'});
|
|
109
|
+
check('baseline',()=>{
|
|
110
|
+
const links=gitlinks(target);let modified=0,missing=0;
|
|
111
|
+
for (const [ref,record] of Object.entries(meta.managedFiles)) {
|
|
112
|
+
guardNestedRepository(target,ref);
|
|
113
|
+
ensure(!links.some(p=>p===ref || ref.startsWith(p+'/')),`受管路径进入 gitlink: ${ref}`,'PROTECTED');
|
|
114
|
+
const d=descriptor(target,ref);if(!d)missing++;else if(!same(d,record.lastApplied || record.baseline))modified++;
|
|
115
|
+
}
|
|
116
|
+
return {status:modified||missing?'warning':'ok',modified,missing,migrationRequired:Boolean(meta.legacy)};
|
|
117
|
+
});
|
|
118
|
+
if (state && !state.pending.length) check('instance-contract',()=>({checks:verifyInstance(bundle,target)}));
|
|
119
|
+
if (bundle.family.side === 'design' && bundle.files.has('scripts/verify-strategic-gate-migration')) check('strategic-gate-migration',()=>{
|
|
120
|
+
const result = spawnSync(process.execPath, [safe(target, 'scripts/verify-strategic-gate-migration'), '--root', target], {cwd:target,encoding:'utf8',timeout:120000,maxBuffer:16*1024*1024});
|
|
121
|
+
const message = String(result.error?.message || result.stderr || result.stdout).trim();
|
|
122
|
+
if (result.error || result.status !== 0) throw Object.assign(new Error(`scripts/verify-strategic-gate-migration: ${message}`), {code:message.includes('STRATEGIC_GATE_MIGRATION_REQUIRED')?'STRATEGIC_GATE_MIGRATION_REQUIRED':'VERIFY'});
|
|
123
|
+
return {exitCode:result.status};
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
const git=spawnSync('git',['--no-optional-locks','-c','core.fsmonitor=false','-C',target,'status','--porcelain'],{encoding:'utf8',timeout:5000});
|
|
127
|
+
report.checks.push({name:'git',status:git.status!==0||git.stdout?'warning':'ok',message:git.status!==0?'未建立 Git 工作区':git.stdout?'存在本地改动':'工作区干净'});
|
|
128
|
+
for (const check of report.checks) delete check.metadata;
|
|
129
|
+
report.advice=report.status==='error'?'按失败检查项修复;中断事务使用 recover,禁止删除 metadata 绕过':'使用 diff 查看模板更新';
|
|
130
|
+
return report;
|
|
131
|
+
}
|