skill-family-engineering-kit 0.26.0 → 0.27.0
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/CHANGELOG.md +18 -0
- package/CHANGELOG.zh-CN.md +18 -0
- package/README.md +18 -22
- package/README.zh-CN.md +18 -22
- package/data/capability-catalog/capability-catalog.en.json +51 -0
- package/data/capability-catalog/capability-catalog.json +26 -0
- package/data/capability-catalog/capability-catalog.zh-CN.json +51 -0
- package/docs/agents/capability-catalog.en.json +51 -0
- package/docs/agents/capability-catalog.json +26 -0
- package/docs/agents/capability-catalog.zh-CN.json +51 -0
- package/docs/public/status/index.html +4 -4
- package/docs/search/search_index.json +1 -1
- package/package.json +3 -3
- package/release-notes/0.27.0.yaml +21 -0
- package/src/adopt-plan.mjs +1 -1
- package/src/check.mjs +21 -35
- package/src/cli.mjs +55 -0
- package/src/errors.mjs +2 -0
- package/src/index.mjs +9 -1
- package/src/register-existing.mjs +466 -0
- package/src/skeleton.mjs +2 -0
package/package.json
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
"url": "https://github.com/ifoohoo/skill-family-engineering-kit/issues"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"skill-family-contracts": "0.
|
|
12
|
-
"skill-family-harness-node": "0.
|
|
11
|
+
"skill-family-contracts": "0.27.0",
|
|
12
|
+
"skill-family-harness-node": "0.27.0",
|
|
13
13
|
"yaml": "2.9.0"
|
|
14
14
|
},
|
|
15
15
|
"description": "Build-time scaffold, adoption planning, projection, and checks.",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"url": "https://github.com/ifoohoo/skill-family-engineering-kit.git"
|
|
53
53
|
},
|
|
54
54
|
"type": "module",
|
|
55
|
-
"version": "0.
|
|
55
|
+
"version": "0.27.0",
|
|
56
56
|
"scripts": {
|
|
57
57
|
"check": "node --test",
|
|
58
58
|
"test": "node --test"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
version: 0.27.0
|
|
2
|
+
date: 2026-10-21
|
|
3
|
+
locales:
|
|
4
|
+
en:
|
|
5
|
+
summary: "Engineering Kit 0.27.0 adds the public function `runRegisterExisting` and the CLI sub-action `skill-family-kit check register-existing` under the existing `check` command. The four top-level commands remain `scaffold`, `adopt-plan`, `projection`, and `check`. The sub-action is the only legal first write of `.foundation/file-registry.json`, `skill-family.project-manifest.json`, and `skill-family.managed-file-lock.json` into a nonempty root that already has a valid `profile.json`. Relock never seeds. Scaffold still refuses nonempty directories. Adopt-plan remains read-only. Projection still requires an existing legal registry."
|
|
6
|
+
changes:
|
|
7
|
+
changed:
|
|
8
|
+
- "Add the public function `runRegisterExisting` and the CLI `skill-family-kit check register-existing`. The API `root` must be an absolute project working directory; the CLI resolves the current directory or a relative path to an absolute path first. `--handwritten` is required and non-empty."
|
|
9
|
+
- "Missing all three closed-world documents yields exclusive create. All three present and byte-identical yields idempotent success with zero write. Any other combination, class overlap, or drifted bytes refuses with zero overwrite."
|
|
10
|
+
- "Relock still never seeds a missing registry. Scaffold still refuses nonempty directories. Adopt-plan remains strictly read-only. Projection and later relock still require an existing legal registry."
|
|
11
|
+
- "The package moves to 0.27.0 with the other three units. Contracts specification remains 1.20.0. Published 0.26.0 capabilities are unchanged and are not redone."
|
|
12
|
+
upgradeNotes: "Pin the three Foundation npm packages to exactly 0.27.0 and keep the independent Plugin at that release version. Contracts specification 1.20.0 remains a separate coordinate from npm package versions. Consume the actual published version's public interfaces and sources. First nonempty registration does not prove business qualification or completed initialization. This note does not replace post-publish verification."
|
|
13
|
+
zh-CN:
|
|
14
|
+
summary: "Engineering Kit 0.27.0 在既有 `check` 下新增公共函数 `runRegisterExisting` 与 CLI 子动作 `skill-family-kit check register-existing`。四个顶层命令仍为 `scaffold`、`adopt-plan`、`projection`、`check`。该子动作是已有有效 `profile.json` 的非空根首次写入 `.foundation/file-registry.json`、`skill-family.project-manifest.json`、`skill-family.managed-file-lock.json` 的唯一合法入口。`relock` 不为缺锁工程播种。`scaffold` 仍拒绝非空目录。`adopt-plan` 仍只读。`projection` 仍要求已有合法登记。"
|
|
15
|
+
changes:
|
|
16
|
+
changed:
|
|
17
|
+
- "新增公共函数 `runRegisterExisting` 与 CLI `skill-family-kit check register-existing`。API 的 `root` 必须是绝对项目工作目录;CLI 会把当前目录或相对路径先解析成绝对路径。`--handwritten` 必填且非空。"
|
|
18
|
+
- "三份闭域文件均不存在时排他创建;三份均在且字节一致时幂等成功且零写入;任一其他组合、分类重叠或字节漂移均拒绝且零覆盖。"
|
|
19
|
+
- "`relock` 仍不为缺锁工程播种。`scaffold` 仍拒绝非空目录。`adopt-plan` 仍严格只读。`projection` 与后续 `relock` 仍要求已有合法登记。"
|
|
20
|
+
- "包版本与其他三单元锁步到 0.27.0。Contracts 规格仍为 1.20.0。已发布的 0.26.0 能力保持原样,本版本不重做。"
|
|
21
|
+
upgradeNotes: "三个 Foundation npm 包须精确锁定 0.27.0,独立插件与三包保持相同发布版本。Contracts 规格仍为 1.20.0,与 npm 包版本分别处理。消费以实际发布版本的公开接口和源码为准。首次非空登记不证明业务资格或初始化完成。本说明不替代发布后验证。"
|
package/src/adopt-plan.mjs
CHANGED
|
@@ -360,7 +360,7 @@ export function buildProfileDraft({ inputs, migrationManifest, writeSet, entries
|
|
|
360
360
|
ready: incompleteFields.length === 0,
|
|
361
361
|
binding: { targetSetDigest, foundationPlanDigest },
|
|
362
362
|
policyNote:
|
|
363
|
-
"adoption-lock is deprecated (remediation handoff D-8): the kit no longer produces adoption-lock-form artifacts. The adoption proof is this project's adoption declaration, completed with real artifact paths and digests inside the profile write set and machine-verified by verifyProjectProfile (SPE1006 digest discipline, SPE1007 tightening-only overrides).",
|
|
363
|
+
"adoption-lock is deprecated (remediation handoff D-8): the kit no longer produces adoption-lock-form artifacts. The adoption proof is this project's adoption declaration, completed with real artifact paths and digests inside the profile write set and machine-verified by verifyProjectProfile (SPE1006 digest discipline, SPE1007 tightening-only overrides). profileDraft is a proposed draft only; an incomplete or empty draft does not invalidate a current valid profile.json.",
|
|
364
364
|
};
|
|
365
365
|
}
|
|
366
366
|
|
package/src/check.mjs
CHANGED
|
@@ -52,10 +52,12 @@ import { loadEngineeringDeclaration } from "./engineering-declaration.mjs";
|
|
|
52
52
|
* fail-closed semantics are unchanged: it remains a finding);
|
|
53
53
|
* closure — harness resource closure over declared inputs/outputs;
|
|
54
54
|
* version — declared contracts version vs the frozen contracts version,
|
|
55
|
-
* plus version single-source
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
55
|
+
* plus root-only version single-source facts when no
|
|
56
|
+
* engineering.releaseUnits declaration is in force (SG-13/14,
|
|
57
|
+
* VRG-001: package.json is the root version authority; no
|
|
58
|
+
* double-headed VERSION authority). Nested package.json files
|
|
59
|
+
* and historical snapshots are not current release units; actual
|
|
60
|
+
* units are checked only through declared versionSource/versionMirrors;
|
|
59
61
|
* docs — documentation facts (README presence, identity consistency);
|
|
60
62
|
* git — read-only Git pre-state (never a git write);
|
|
61
63
|
* identity — licensing and identity drift checks (FND-045);
|
|
@@ -552,22 +554,27 @@ async function checkClosure(rootAbs, findings) {
|
|
|
552
554
|
}
|
|
553
555
|
|
|
554
556
|
/**
|
|
555
|
-
*
|
|
557
|
+
* Legacy version facts used when engineering.releaseUnits is absent.
|
|
556
558
|
*
|
|
557
|
-
*
|
|
558
|
-
*
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
*
|
|
562
|
-
*
|
|
563
|
-
*
|
|
559
|
+
* Scope is the root package.json and an adjacent VERSION file only
|
|
560
|
+
* (VRG-001: no double-headed VERSION authority next to the root package).
|
|
561
|
+
* Nested package.json files, historical snapshots, and independent release
|
|
562
|
+
* units are not current version authorities; declare releaseUnits with
|
|
563
|
+
* versionSource/versionMirrors to check those objects. Invalid declarations
|
|
564
|
+
* never fall back to this path. Provider lockstep among Foundation's own
|
|
565
|
+
* four release units stays in the workspace check-structure gate.
|
|
564
566
|
*
|
|
565
567
|
* When no root package.json version exists there is no single source to
|
|
566
568
|
* compare against and the sub-check reports nothing (never guesses).
|
|
567
|
-
* Returns { rootVersion, versionFilePresent, drifted }.
|
|
569
|
+
* Returns { rootVersion, versionFilePresent, drifted, note }.
|
|
568
570
|
*/
|
|
569
571
|
async function checkVersionSingleSource(rootAbs, findings) {
|
|
570
|
-
const facts = {
|
|
572
|
+
const facts = {
|
|
573
|
+
rootVersion: null,
|
|
574
|
+
versionFilePresent: false,
|
|
575
|
+
drifted: [],
|
|
576
|
+
note: "legacy version class reads the root package.json and an adjacent VERSION file only; nested package.json files and historical snapshots are not current release units. Declare engineering.releaseUnits to check actual units.",
|
|
577
|
+
};
|
|
571
578
|
const packageDocument = await loadDocument(rootAbs, "package.json");
|
|
572
579
|
if (packageDocument.state !== "ok" || typeof packageDocument.value?.version !== "string") {
|
|
573
580
|
return facts;
|
|
@@ -587,27 +594,6 @@ async function checkVersionSingleSource(rootAbs, findings) {
|
|
|
587
594
|
),
|
|
588
595
|
);
|
|
589
596
|
}
|
|
590
|
-
|
|
591
|
-
const entries = await listTargetEntries(rootAbs);
|
|
592
|
-
for (const entry of entries) {
|
|
593
|
-
if (entry.kind !== "file" || entry.path === "package.json" || !entry.path.endsWith("package.json")) {
|
|
594
|
-
continue;
|
|
595
|
-
}
|
|
596
|
-
const nested = await loadDocument(rootAbs, entry.path);
|
|
597
|
-
if (nested.state !== "ok" || typeof nested.value?.version !== "string") continue;
|
|
598
|
-
if (nested.value.version !== facts.rootVersion) {
|
|
599
|
-
facts.drifted.push({ path: entry.path, version: nested.value.version });
|
|
600
|
-
findings.push(
|
|
601
|
-
finding(
|
|
602
|
-
"version",
|
|
603
|
-
KIT_ERROR_KINDS.VERSION_SINGLE_SOURCE_DRIFT,
|
|
604
|
-
"SFC2004",
|
|
605
|
-
`${entry.path} declares version ${nested.value.version}; the single version source is the root package.json version ${facts.rootVersion} (VRG-002)`,
|
|
606
|
-
{ path: entry.path, declared: nested.value.version, expected: facts.rootVersion },
|
|
607
|
-
),
|
|
608
|
-
);
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
597
|
return facts;
|
|
612
598
|
}
|
|
613
599
|
|
package/src/cli.mjs
CHANGED
|
@@ -8,6 +8,7 @@ import { bundledProfilesRoot } from "./licensing.mjs";
|
|
|
8
8
|
import { checkEntriesAction } from "./entry-check.mjs";
|
|
9
9
|
import { checkHostLoadingAction } from "./host-loading-check.mjs";
|
|
10
10
|
import { relockAction } from "./relock.mjs";
|
|
11
|
+
import { registerExistingAction } from "./register-existing.mjs";
|
|
11
12
|
import { checkReportAction, renderReportAction } from "./report.mjs";
|
|
12
13
|
import {
|
|
13
14
|
COMMAND_SIDE_EFFECTS,
|
|
@@ -77,6 +78,10 @@ const HELP_TEXT = `skill-family-engineering-kit —— 构建期工程工具包
|
|
|
77
78
|
把新手写文件登记进 .foundation/file-registry.json,并以当前字节
|
|
78
79
|
重算 skill-family.managed-file-lock.json(单次 fail-closed 事务;
|
|
79
80
|
只写这两个收容状态文档,任何拒绝都零写入)。
|
|
81
|
+
首次非空登记子动作: check register-existing 为已有非空工程生成
|
|
82
|
+
三份闭世界登记(file-registry / project-manifest / managed-file-lock)。
|
|
83
|
+
消费已确认的 profile 身份与调用方分类/engineering;重复执行幂等,
|
|
84
|
+
冲突拒绝且零覆盖。不走 scaffold,也不把 adopt-plan 写成 apply。
|
|
80
85
|
显式资格子动作: check qualification 仅在显式提供
|
|
81
86
|
capability/request/bindings/native 后适配目录声明的能力特定入口,
|
|
82
87
|
可在预检后调用能力特定的原生宿主。
|
|
@@ -158,6 +163,12 @@ function commandHelp(command) {
|
|
|
158
163
|
" --registration-class <handwritten|trackedToolLocks> 登记类别,默认 handwritten",
|
|
159
164
|
" trackedToolLocks 必须提供非空 --files 清单,只登记路径,不锁定工具锁内容。",
|
|
160
165
|
"",
|
|
166
|
+
"首次非空登记: skill-family-kit check register-existing --root <dir> --handwritten <globs>",
|
|
167
|
+
" --engineering <json> 可选,现有 project-manifest.engineering 对象",
|
|
168
|
+
" --tracked-tool-locks <paths> 可选,已存在的持久工具锁路径",
|
|
169
|
+
" --artifacts <patterns> 可选,额外忽略模式;不得把已跟踪生成物列为忽略运行目录",
|
|
170
|
+
" 目标必须已有合法 profile.json;三份登记全部缺失则独占创建,全部匹配则幂等,其它情况拒绝零覆盖。",
|
|
171
|
+
"",
|
|
161
172
|
"选项:",
|
|
162
173
|
" --root <dir> 目标工作区(默认当前目录)",
|
|
163
174
|
" --only <class> 只运行一个诊断类: contracts|drift|closure|version|docs|git|identity|boundary|platform",
|
|
@@ -347,6 +358,16 @@ const COMMAND_SPECS = {
|
|
|
347
358
|
"--registration-class": { key: "registrationClass", value: true },
|
|
348
359
|
},
|
|
349
360
|
},
|
|
361
|
+
"check register-existing": {
|
|
362
|
+
rejectDuplicates: true,
|
|
363
|
+
flags: {
|
|
364
|
+
"--root": { key: "root", value: true },
|
|
365
|
+
"--handwritten": { key: "handwritten", value: true },
|
|
366
|
+
"--engineering": { key: "engineeringJson", value: true },
|
|
367
|
+
"--tracked-tool-locks": { key: "trackedToolLocks", value: true },
|
|
368
|
+
"--artifacts": { key: "artifacts", value: true },
|
|
369
|
+
},
|
|
370
|
+
},
|
|
350
371
|
"check qualification": {
|
|
351
372
|
rejectDuplicates: true,
|
|
352
373
|
flags: {
|
|
@@ -615,6 +636,37 @@ async function runRelockSubAction(rest) {
|
|
|
615
636
|
}
|
|
616
637
|
}
|
|
617
638
|
|
|
639
|
+
async function runRegisterExistingSubAction(rest) {
|
|
640
|
+
const specName = "check register-existing";
|
|
641
|
+
try {
|
|
642
|
+
const options = parseOptions(rest, { command: specName, flags: COMMAND_SPECS[specName].flags, rejectDuplicates: true });
|
|
643
|
+
if (options.help) {
|
|
644
|
+
process.stdout.write(`${commandHelp("check")}\n`);
|
|
645
|
+
return KIT_EXIT_CODES.ok;
|
|
646
|
+
}
|
|
647
|
+
let engineering;
|
|
648
|
+
if (options.engineeringJson !== undefined) {
|
|
649
|
+
try {
|
|
650
|
+
engineering = JSON.parse(options.engineeringJson);
|
|
651
|
+
} catch {
|
|
652
|
+
throw invalidParamsError("--engineering must be a JSON engineering object", { flag: "--engineering" });
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
const { status, output } = await registerExistingAction({
|
|
656
|
+
root: options.root,
|
|
657
|
+
handwritten: options.handwritten,
|
|
658
|
+
engineering,
|
|
659
|
+
trackedToolLocks: options.trackedToolLocks,
|
|
660
|
+
artifacts: options.artifacts,
|
|
661
|
+
});
|
|
662
|
+
process.stdout.write(`${JSON.stringify(output, null, 2)}\n`);
|
|
663
|
+
return status === "ok" ? KIT_EXIT_CODES.ok : KIT_EXIT_CODES.rejected;
|
|
664
|
+
} catch (error) {
|
|
665
|
+
printError(error);
|
|
666
|
+
return KIT_EXIT_CODES.rejected;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
618
670
|
function requireJsonFlag(options, specName) {
|
|
619
671
|
if (options.json !== true) {
|
|
620
672
|
throw invalidParamsError(`${specName} requires --json`, { reason: "missing-option-value", flag: "--json" });
|
|
@@ -788,6 +840,9 @@ export async function cliMain(argv) {
|
|
|
788
840
|
if (command === "check" && argv[1] === "relock") {
|
|
789
841
|
return runRelockSubAction(argv.slice(2));
|
|
790
842
|
}
|
|
843
|
+
if (command === "check" && argv[1] === "register-existing") {
|
|
844
|
+
return runRegisterExistingSubAction(argv.slice(2));
|
|
845
|
+
}
|
|
791
846
|
if (command === "check" && argv[1] === "qualification") {
|
|
792
847
|
return runQualificationSubAction(argv.slice(2));
|
|
793
848
|
}
|
package/src/errors.mjs
CHANGED
|
@@ -92,6 +92,8 @@ export const KIT_ERROR_KINDS = Object.freeze({
|
|
|
92
92
|
// controlled relock channel (SG-36; audit friction F5): `check relock`
|
|
93
93
|
RELOCK_REGISTRATION_REFUSED: "relock-registration-refused",
|
|
94
94
|
RELOCK_LOCK_DRIFT: "relock-lock-drift",
|
|
95
|
+
// first nonempty closed-world seed (check register-existing)
|
|
96
|
+
REGISTER_EXISTING_REFUSED: "register-existing-refused",
|
|
95
97
|
// read-only host integration slice
|
|
96
98
|
HOST_CONTRACT_INVALID: "host-contract-invalid",
|
|
97
99
|
HOST_PROBE_FAILED: "host-probe-failed",
|
package/src/index.mjs
CHANGED
|
@@ -24,6 +24,11 @@ import {
|
|
|
24
24
|
relockAction,
|
|
25
25
|
runRelock,
|
|
26
26
|
} from "./relock.mjs";
|
|
27
|
+
import {
|
|
28
|
+
REGISTER_EXISTING_REPORT_KIND,
|
|
29
|
+
registerExistingAction,
|
|
30
|
+
runRegisterExisting,
|
|
31
|
+
} from "./register-existing.mjs";
|
|
27
32
|
import {
|
|
28
33
|
invalidParamsError,
|
|
29
34
|
KitError,
|
|
@@ -164,7 +169,7 @@ export const COMMAND_SIDE_EFFECTS = Object.freeze({
|
|
|
164
169
|
check: Object.freeze({
|
|
165
170
|
summary: "契约/漂移/闭包/版本/文档事实/Git 前置状态诊断。",
|
|
166
171
|
sideEffect:
|
|
167
|
-
"none for default diagnosis and the pure runChecks/runEntryContractCheck functions — they never write or auto-fix, and git is probed read-only (one frozen status query at most); with policy declared, only the runCommand('check') and checkEntriesAction wrappers may exclusively create one conclusion when callers explicitly provide an existing output root plus a contained relative path, never creating parent directories or overwriting an existing entry; check proof is read-only proof interpretation and never writes; check proof-create exclusively creates one conclusion from a Skill review-input under the same exclusive-write rules; check host-loading is a strictly read-only sub-action that never writes, spawns, or contacts a network; relock remains a separately explicit controlled write transaction; qualification remains separately explicit and may invoke the capability-specific native host only after its preflight. Foundation itself does not issue network requests, but a bound executable may access the network; sandbox and egress controls remain with callers and the execution environment",
|
|
172
|
+
"none for default diagnosis and the pure runChecks/runEntryContractCheck functions — they never write or auto-fix, and git is probed read-only (one frozen status query at most); with policy declared, only the runCommand('check') and checkEntriesAction wrappers may exclusively create one conclusion when callers explicitly provide an existing output root plus a contained relative path, never creating parent directories or overwriting an existing entry; check proof is read-only proof interpretation and never writes; check proof-create exclusively creates one conclusion from a Skill review-input under the same exclusive-write rules; check host-loading is a strictly read-only sub-action that never writes, spawns, or contacts a network; relock remains a separately explicit controlled write transaction; check register-existing remains a separately explicit first-nonempty registration write of the three closed-world documents and never overwrites mismatched bytes; qualification remains separately explicit and may invoke the capability-specific native host only after its preflight. Foundation itself does not issue network requests, but a bound executable may access the network; sandbox and egress controls remain with callers and the execution environment",
|
|
168
173
|
exitCodes: "0 无发现;1 有发现;2 拒绝/用法/机制错误",
|
|
169
174
|
}),
|
|
170
175
|
});
|
|
@@ -262,6 +267,9 @@ export {
|
|
|
262
267
|
relockAction,
|
|
263
268
|
RELOCK_LOCK_PATH_PATTERN,
|
|
264
269
|
RELOCK_REPORT_KIND,
|
|
270
|
+
runRegisterExisting,
|
|
271
|
+
registerExistingAction,
|
|
272
|
+
REGISTER_EXISTING_REPORT_KIND,
|
|
265
273
|
runChecks,
|
|
266
274
|
CHECK_CLASSES,
|
|
267
275
|
DOCUMENT_STATES,
|