scene-capability-engine 3.6.63 → 3.6.65
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 +15 -0
- package/README.md +2 -2
- package/README.zh.md +2 -2
- package/docs/README.md +2 -2
- package/docs/command-reference.md +5 -4
- package/docs/magicball-cli-invocation-examples.md +1 -0
- package/docs/magicball-project-portfolio-contract.md +11 -2
- package/docs/releases/README.md +2 -0
- package/docs/releases/v3.6.64.md +35 -0
- package/docs/releases/v3.6.65.md +25 -0
- package/docs/zh/README.md +2 -2
- package/docs/zh/releases/README.md +2 -0
- package/docs/zh/releases/v3.6.64.md +35 -0
- package/docs/zh/releases/v3.6.65.md +25 -0
- package/lib/commands/project.js +1 -0
- package/lib/problem/project-problem-projection.js +82 -9
- package/lib/project/root-onboarding-service.js +49 -1
- package/package.json +1 -1
- package/scripts/release-doc-version-audit.js +24 -0
- package/template/.sce/README.md +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [3.6.65] - 2026-03-22
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Added explicit `publish` step and `publication` metadata to `sce project onboarding import --root <path> --json`, so adapters can distinguish onboarding success from canonical portfolio visibility without keeping a shadow imported-project registry.
|
|
14
|
+
- Added Specs `137-00` through `140-03` to formalize the vendor-neutral external agent runtime direction, local agent checkpoint contract, and staged rollout boundaries.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- Updated MagicBall-facing project contract docs and CLI examples so onboarding now declares portfolio publication semantics directly and phase-1 adapters can refresh the canonical project roster immediately.
|
|
18
|
+
- Expanded `audit:release-docs` coverage to include `docs/command-reference.md`, `docs/README.md`, and `docs/zh/README.md`, reducing the chance of release metadata drifting in active documentation indexes and command docs.
|
|
19
|
+
|
|
20
|
+
## [3.6.64] - 2026-03-21
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
- Stabilized the tracked project-shared problem projection for co-work/publish flows by deriving `source.project` from a stable project identity and reusing prior entry timestamps when only clone-local mtimes drift.
|
|
24
|
+
|
|
10
25
|
## [3.6.63] - 2026-03-21
|
|
11
26
|
|
|
12
27
|
### Fixed
|
package/README.md
CHANGED
package/README.zh.md
CHANGED
package/docs/README.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
> Quick reference for all `sce` commands
|
|
4
4
|
|
|
5
|
-
**Version**: 3.6.
|
|
6
|
-
**Last Updated**: 2026-03-
|
|
5
|
+
**Version**: 3.6.65
|
|
6
|
+
**Last Updated**: 2026-03-22
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -2710,8 +2710,9 @@ sce project onboarding import --root <path> [options]
|
|
|
2710
2710
|
|
|
2711
2711
|
**Behavior:**
|
|
2712
2712
|
- Accepts a local root as the primary onboarding target without app-bundle-first indirection
|
|
2713
|
-
- Reuses the canonical ordered step envelope (`register`, `attach`, `hydrate`, `activate`, `scaffold`)
|
|
2714
|
-
-
|
|
2713
|
+
- Reuses the canonical ordered step envelope (`register`, `attach`, `hydrate`, `publish`, `activate`, `scaffold`)
|
|
2714
|
+
- Publishes explicit `publication` state so adapters can distinguish import success from canonical portfolio visibility
|
|
2715
|
+
- Registers onboarded roots into the workspace-backed portfolio before success returns in the default phase-1 path, without inventing a second registry
|
|
2715
2716
|
|
|
2716
2717
|
#### `sce project target resolve`
|
|
2717
2718
|
|
|
@@ -32,6 +32,7 @@ sce project supervision show --project workspace:customer-order-demo --json
|
|
|
32
32
|
|
|
33
33
|
Expected use:
|
|
34
34
|
- build project switcher from engine-owned roster
|
|
35
|
+
- treat `project onboarding import` `publication.visibleInPortfolio=true` as the signal to refresh the roster immediately
|
|
35
36
|
- preflight cross-project free-text routing before assistant/orchestration actions
|
|
36
37
|
- render one project-scoped health summary without replaying raw event streams
|
|
37
38
|
|
|
@@ -140,8 +140,16 @@ interface ProjectOnboardingImportResult {
|
|
|
140
140
|
generated_at: string
|
|
141
141
|
success: boolean
|
|
142
142
|
preview: LocalProjectCandidateInspection
|
|
143
|
+
publication: {
|
|
144
|
+
status: 'published' | 'pending' | 'not_published'
|
|
145
|
+
visibleInPortfolio: boolean
|
|
146
|
+
rootDir: string | null
|
|
147
|
+
projectId: string | null
|
|
148
|
+
workspaceId: string | null
|
|
149
|
+
publishedAt?: string
|
|
150
|
+
}
|
|
143
151
|
steps: Array<{
|
|
144
|
-
key: 'register' | 'attach' | 'hydrate' | 'activate' | 'scaffold'
|
|
152
|
+
key: 'register' | 'attach' | 'hydrate' | 'publish' | 'activate' | 'scaffold'
|
|
145
153
|
status: 'done' | 'skipped' | 'pending' | 'failed'
|
|
146
154
|
reasonCode?: string
|
|
147
155
|
detail?: string
|
|
@@ -155,6 +163,7 @@ interface ProjectOnboardingImportResult {
|
|
|
155
163
|
- Use `project onboarding import` when the user picks a local root directly; do not fake an app-library item just to enter onboarding.
|
|
156
164
|
- If `kind=workspace-backed`, reuse returned `projectId/workspaceId` directly and avoid synthesizing a second registry identity.
|
|
157
165
|
- If `kind=local-sce-candidate`, present it as a partial local project until onboarding import registers it.
|
|
166
|
+
- Treat `publication.visibleInPortfolio=true` as the engine-owned signal that a follow-up `project portfolio show` refresh should already expose the imported project.
|
|
158
167
|
- Render `reasonCodes` directly in CLI/IDE receipts; do not replace them with frontend-only heuristics.
|
|
159
168
|
|
|
160
169
|
## 2. Target Resolution
|
|
@@ -256,7 +265,7 @@ interface ProjectSupervisionItem {
|
|
|
256
265
|
|
|
257
266
|
1. Load `sce project portfolio show --json` when entering the multi-project shell.
|
|
258
267
|
2. When the user selects a local root manually, preflight it with `sce project candidate inspect --root <path> --json`.
|
|
259
|
-
3. If the root is not yet portfolio-backed, import it through `sce project onboarding import --root <path> --json
|
|
268
|
+
3. If the root is not yet portfolio-backed, import it through `sce project onboarding import --root <path> --json`, then trust `publication` plus a fresh portfolio refresh instead of keeping a shadow imported-project registry.
|
|
260
269
|
4. Store `activeProjectId` and render a project switcher from `projects[]`.
|
|
261
270
|
5. When the user enters a cross-project free-text request, preflight with `sce project target resolve --json`.
|
|
262
271
|
6. After project selection or successful resolution, load `sce project supervision show --project <project-id> --json`.
|
package/docs/releases/README.md
CHANGED
|
@@ -9,6 +9,8 @@ This directory stores release-facing documents:
|
|
|
9
9
|
## Archived Versions
|
|
10
10
|
|
|
11
11
|
- [Release checklist](../release-checklist.md)
|
|
12
|
+
- [v3.6.65 release notes](./v3.6.65.md)
|
|
13
|
+
- [v3.6.64 release notes](./v3.6.64.md)
|
|
12
14
|
- [v3.6.63 release notes](./v3.6.63.md)
|
|
13
15
|
- [v3.6.62 release notes](./v3.6.62.md)
|
|
14
16
|
- [v3.6.61 release notes](./v3.6.61.md)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# v3.6.64 Release Notes
|
|
2
|
+
|
|
3
|
+
Release date: 2026-03-21
|
|
4
|
+
|
|
5
|
+
## Highlights
|
|
6
|
+
|
|
7
|
+
- Fixed the remaining publish blocker in the managed co-work path: `.sce/knowledge/problem/project-shared-problems.json` no longer churns just because a clean clone uses a different folder name or fresh filesystem mtimes.
|
|
8
|
+
- Reused prior projection timestamps when the logical problem entry is unchanged, so `gate:collab-governance` stays idempotent and no longer dirties the worktree right before `gate:git-managed`.
|
|
9
|
+
- Kept the `v3.6.62` OpenHands cleanup and the `v3.6.63` clean-room steering audit fix intact; this patch closes the last publish-path drift uncovered while releasing those changes.
|
|
10
|
+
|
|
11
|
+
## Validation
|
|
12
|
+
|
|
13
|
+
- `npx jest tests/unit/problem/project-problem-projection.test.js --runInBand`
|
|
14
|
+
- `npx jest tests/unit/scripts/steering-content-audit.test.js --runInBand`
|
|
15
|
+
- `npx jest tests/unit/commands/studio.test.js --runInBand`
|
|
16
|
+
- `npm run test:release`
|
|
17
|
+
- `npm run audit:release-docs`
|
|
18
|
+
- `npm run audit:steering`
|
|
19
|
+
- `npm run test:skip-audit`
|
|
20
|
+
- `npm run test:sce-tracking`
|
|
21
|
+
- `npm run gate:npm-runtime-assets`
|
|
22
|
+
- `npm run test:brand-consistency`
|
|
23
|
+
- `npm run audit:clarification-first`
|
|
24
|
+
- `npm run audit:magicball-engineering-contract`
|
|
25
|
+
- `npm run audit:magicball-project-contract`
|
|
26
|
+
- `npm run gate:collab-governance`
|
|
27
|
+
- `npm run gate:errorbook-registry-health`
|
|
28
|
+
- `npm run gate:errorbook-release`
|
|
29
|
+
- `npm run report:interactive-governance -- --fail-on-alert`
|
|
30
|
+
- `npm pack --dry-run`
|
|
31
|
+
|
|
32
|
+
## Release Notes
|
|
33
|
+
|
|
34
|
+
- Use `v3.6.64` if you need the OpenHands cleanup, clean-room steering audit, and a truly idempotent co-work publish path in one published package.
|
|
35
|
+
- This fix keeps shared problem knowledge tracked while removing clone-path and clone-mtime noise from the release gate.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# v3.6.65 Release Notes
|
|
2
|
+
|
|
3
|
+
Release date: 2026-03-22
|
|
4
|
+
|
|
5
|
+
## Highlights
|
|
6
|
+
|
|
7
|
+
- Formalized onboarding-to-portfolio convergence: `sce project onboarding import --root <path> --json` now emits an explicit `publish` step plus `publication` metadata, so IDEs can tell whether the imported project is already visible in the canonical portfolio without inventing a shadow registry.
|
|
8
|
+
- Locked the contract with unit and integration coverage that proves onboarding identity matches the follow-up `sce project portfolio show --json` identity.
|
|
9
|
+
- Published the next runtime-planning line into the main repository through Specs `137-00` to `140-03`, keeping the external agent direction vendor-neutral and split into bounded rollout contracts instead of one oversized implementation spec.
|
|
10
|
+
- Strengthened release metadata hygiene by extending `audit:release-docs` to also check `docs/command-reference.md`, `docs/README.md`, and `docs/zh/README.md`.
|
|
11
|
+
|
|
12
|
+
## Validation
|
|
13
|
+
|
|
14
|
+
- `npx jest tests/unit/commands/project.test.js --runInBand`
|
|
15
|
+
- `npx jest tests/integration/project-cli.integration.test.js --runInBand`
|
|
16
|
+
- `node scripts/magicball-project-contract-audit.js --json`
|
|
17
|
+
- `npm run report:clarification-first-audit`
|
|
18
|
+
- `npm run audit:release-docs`
|
|
19
|
+
- `npm run prepublishOnly`
|
|
20
|
+
- `npm pack --dry-run`
|
|
21
|
+
|
|
22
|
+
## Release Notes
|
|
23
|
+
|
|
24
|
+
- Use `v3.6.65` if you need canonical onboarding publication semantics for IDE project import flows, plus the upstream runtime rollout specs that define the next vendor-neutral external agent integration line.
|
|
25
|
+
- This patch also hardens the release process itself: key docs now fail release metadata audit when their version/date footers drift behind the package version and latest CHANGELOG release date.
|
package/docs/zh/README.md
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# v3.6.64 发布说明
|
|
2
|
+
|
|
3
|
+
发布日期:2026-03-21
|
|
4
|
+
|
|
5
|
+
## 重点变化
|
|
6
|
+
|
|
7
|
+
- 修复了受管 co-work 发布路径里剩余的阻断点:`.sce/knowledge/problem/project-shared-problems.json` 不再因为 clean clone 的目录名不同或文件系统时间戳刷新,就在发布前无意义改写。
|
|
8
|
+
- 当问题条目的逻辑内容没有变化时,投影现在会复用上一次的稳定时间字段,保证 `gate:collab-governance` 真正幂等,不再在 `gate:git-managed` 前把工作区弄脏。
|
|
9
|
+
- `v3.6.62` 的 OpenHands 清理和 `v3.6.63` 的 clean-room steering 审计修复都保持不变;本补丁把发布路径上最后一个实际暴露出来的漂移点补齐。
|
|
10
|
+
|
|
11
|
+
## 验证
|
|
12
|
+
|
|
13
|
+
- `npx jest tests/unit/problem/project-problem-projection.test.js --runInBand`
|
|
14
|
+
- `npx jest tests/unit/scripts/steering-content-audit.test.js --runInBand`
|
|
15
|
+
- `npx jest tests/unit/commands/studio.test.js --runInBand`
|
|
16
|
+
- `npm run test:release`
|
|
17
|
+
- `npm run audit:release-docs`
|
|
18
|
+
- `npm run audit:steering`
|
|
19
|
+
- `npm run test:skip-audit`
|
|
20
|
+
- `npm run test:sce-tracking`
|
|
21
|
+
- `npm run gate:npm-runtime-assets`
|
|
22
|
+
- `npm run test:brand-consistency`
|
|
23
|
+
- `npm run audit:clarification-first`
|
|
24
|
+
- `npm run audit:magicball-engineering-contract`
|
|
25
|
+
- `npm run audit:magicball-project-contract`
|
|
26
|
+
- `npm run gate:collab-governance`
|
|
27
|
+
- `npm run gate:errorbook-registry-health`
|
|
28
|
+
- `npm run gate:errorbook-release`
|
|
29
|
+
- `npm run report:interactive-governance -- --fail-on-alert`
|
|
30
|
+
- `npm pack --dry-run`
|
|
31
|
+
|
|
32
|
+
## 发布说明
|
|
33
|
+
|
|
34
|
+
- 如果你需要同时拿到 OpenHands 清理、clean-room steering 审计修复,以及真正幂等的 co-work 发布链路,请使用 `v3.6.64`。
|
|
35
|
+
- 该修复保留了项目共享问题库的 Git 跟踪能力,同时去掉了由克隆目录名和克隆时间戳引入的发布噪音。
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# v3.6.65 发布说明
|
|
2
|
+
|
|
3
|
+
发布日期:2026-03-22
|
|
4
|
+
|
|
5
|
+
## 重点变化
|
|
6
|
+
|
|
7
|
+
- 正式收敛 onboarding 到 portfolio 的发布语义:`sce project onboarding import --root <path> --json` 现在会返回显式 `publish` step 和 `publication` 字段,IDE 不必再维护一套“导入成功但是否已入项目列表” 的影子状态。
|
|
8
|
+
- 用单测和集成测试把这条契约锁住,确保 onboarding 返回的身份与后续 `sce project portfolio show --json` 里的 canonical 身份一致。
|
|
9
|
+
- 将下一阶段 external agent runtime 规划正式纳入主库:`137-00` 到 `140-03` 这组 spec 保持 vendor-neutral,并按 rollout 子合同拆分,而不是盲目堆成一个超大实现 spec。
|
|
10
|
+
- 补强发布元数据治理:`audit:release-docs` 现在会额外检查 `docs/command-reference.md`、`docs/README.md`、`docs/zh/README.md`,减少活跃文档版本脚注长期漂移。
|
|
11
|
+
|
|
12
|
+
## 验证
|
|
13
|
+
|
|
14
|
+
- `npx jest tests/unit/commands/project.test.js --runInBand`
|
|
15
|
+
- `npx jest tests/integration/project-cli.integration.test.js --runInBand`
|
|
16
|
+
- `node scripts/magicball-project-contract-audit.js --json`
|
|
17
|
+
- `npm run report:clarification-first-audit`
|
|
18
|
+
- `npm run audit:release-docs`
|
|
19
|
+
- `npm run prepublishOnly`
|
|
20
|
+
- `npm pack --dry-run`
|
|
21
|
+
|
|
22
|
+
## 发布说明
|
|
23
|
+
|
|
24
|
+
- 如果你需要 IDE 项目导入后的 canonical 发布语义,以及已经入主库的 vendor-neutral external runtime rollout specs,请使用 `v3.6.65`。
|
|
25
|
+
- 这个补丁同时增强了发布流程本身:关键文档一旦版本号或日期脚注落后于 `package.json` 和 `CHANGELOG`,release doc audit 就会直接报错,而不是继续静默漂移。
|
package/lib/commands/project.js
CHANGED
|
@@ -64,6 +64,7 @@ async function runProjectOnboardingImportCommand(options = {}, dependencies = {}
|
|
|
64
64
|
console.log(chalk.blue('Project Onboarding Import'));
|
|
65
65
|
console.log(` Root: ${payload.preview ? payload.preview.rootDir : options.root}`);
|
|
66
66
|
console.log(` Success: ${payload.success ? 'yes' : 'no'}`);
|
|
67
|
+
console.log(` Portfolio Visibility: ${payload.publication ? payload.publication.status : 'unknown'}`);
|
|
67
68
|
console.log(` Workspace: ${payload.result && payload.result.workspaceId ? payload.result.workspaceId : 'none'}`);
|
|
68
69
|
}
|
|
69
70
|
return payload;
|
|
@@ -115,6 +115,72 @@ function normalizeProjectionAgeDays(value) {
|
|
|
115
115
|
return Math.max(0, Math.floor(numeric));
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
function toComparableEntry(entry) {
|
|
119
|
+
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
const clone = {
|
|
123
|
+
...entry
|
|
124
|
+
};
|
|
125
|
+
delete clone.updated_at;
|
|
126
|
+
delete clone.age_days;
|
|
127
|
+
return sortKeysDeep(clone);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function stabilizeEntriesWithExistingProjection(entries = [], existingProjection = null) {
|
|
131
|
+
const existingEntries = Array.isArray(existingProjection && existingProjection.entries)
|
|
132
|
+
? existingProjection.entries
|
|
133
|
+
: [];
|
|
134
|
+
const existingBySpecId = new Map(
|
|
135
|
+
existingEntries
|
|
136
|
+
.filter((item) => item && typeof item === 'object' && !Array.isArray(item) && normalizeText(item.spec_id))
|
|
137
|
+
.map((item) => [normalizeText(item.spec_id), item])
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
return entries.map((entry) => {
|
|
141
|
+
const previous = existingBySpecId.get(normalizeText(entry.spec_id));
|
|
142
|
+
if (!previous) {
|
|
143
|
+
return entry;
|
|
144
|
+
}
|
|
145
|
+
const previousComparable = toComparableEntry(previous);
|
|
146
|
+
const nextComparable = toComparableEntry(entry);
|
|
147
|
+
if (
|
|
148
|
+
previousComparable
|
|
149
|
+
&& nextComparable
|
|
150
|
+
&& JSON.stringify(previousComparable) === JSON.stringify(nextComparable)
|
|
151
|
+
) {
|
|
152
|
+
return {
|
|
153
|
+
...entry,
|
|
154
|
+
updated_at: previous.updated_at || entry.updated_at || null,
|
|
155
|
+
age_days: normalizeProjectionAgeDays(previous.age_days)
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
return entry;
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async function resolveStableProjectIdentity(projectPath = process.cwd(), fileSystem = fs, fallbackValue = '') {
|
|
163
|
+
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
164
|
+
if (await fileSystem.pathExists(packageJsonPath)) {
|
|
165
|
+
try {
|
|
166
|
+
const packageJson = await fileSystem.readJson(packageJsonPath);
|
|
167
|
+
const packageName = normalizeText(packageJson && packageJson.name);
|
|
168
|
+
if (packageName) {
|
|
169
|
+
return packageName;
|
|
170
|
+
}
|
|
171
|
+
} catch (_error) {
|
|
172
|
+
// Fall through to the remaining stable identity candidates.
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const fallback = normalizeText(fallbackValue);
|
|
177
|
+
if (fallback) {
|
|
178
|
+
return fallback;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return path.basename(projectPath);
|
|
182
|
+
}
|
|
183
|
+
|
|
118
184
|
async function buildProjectSharedProblemProjection(projectPath = process.cwd(), options = {}, dependencies = {}) {
|
|
119
185
|
const fileSystem = dependencies.fileSystem || fs;
|
|
120
186
|
const studioIntakePolicy = dependencies.studioIntakePolicy || await loadStudioIntakePolicy(projectPath, fileSystem);
|
|
@@ -128,6 +194,11 @@ async function buildProjectSharedProblemProjection(projectPath = process.cwd(),
|
|
|
128
194
|
const projectionConfig = normalizeProblemProjectionConfig(
|
|
129
195
|
options.projectSharedProjection || closurePolicy.project_shared_projection
|
|
130
196
|
);
|
|
197
|
+
const projectIdentity = await resolveStableProjectIdentity(
|
|
198
|
+
projectPath,
|
|
199
|
+
fileSystem,
|
|
200
|
+
options.projectIdentity || dependencies.existingProjection?.source?.project
|
|
201
|
+
);
|
|
131
202
|
const scanOptions = {
|
|
132
203
|
staleDays
|
|
133
204
|
};
|
|
@@ -193,26 +264,27 @@ async function buildProjectSharedProblemProjection(projectPath = process.cwd(),
|
|
|
193
264
|
});
|
|
194
265
|
}
|
|
195
266
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const
|
|
199
|
-
const
|
|
267
|
+
const stabilizedEntries = stabilizeEntriesWithExistingProjection(entries, dependencies.existingProjection);
|
|
268
|
+
stabilizedEntries.sort((left, right) => String(right.updated_at || '').localeCompare(String(left.updated_at || '')));
|
|
269
|
+
const activeCount = stabilizedEntries.filter((item) => item.lifecycle_state === 'active').length;
|
|
270
|
+
const staleCount = stabilizedEntries.filter((item) => item.lifecycle_state === 'stale').length;
|
|
271
|
+
const completedCount = stabilizedEntries.filter((item) => item.lifecycle_state === 'completed').length;
|
|
200
272
|
|
|
201
273
|
return {
|
|
202
274
|
api_version: PROJECT_SHARED_PROBLEM_PROJECTION_API_VERSION,
|
|
203
275
|
generated_at: new Date().toISOString(),
|
|
204
276
|
source: {
|
|
205
|
-
project:
|
|
277
|
+
project: projectIdentity,
|
|
206
278
|
stale_days: staleDays,
|
|
207
279
|
scope: projectionConfig.scope
|
|
208
280
|
},
|
|
209
281
|
summary: {
|
|
210
|
-
total_entries:
|
|
282
|
+
total_entries: stabilizedEntries.length,
|
|
211
283
|
active_entries: activeCount,
|
|
212
284
|
stale_entries: staleCount,
|
|
213
285
|
completed_entries: completedCount
|
|
214
286
|
},
|
|
215
|
-
entries
|
|
287
|
+
entries: stabilizedEntries
|
|
216
288
|
};
|
|
217
289
|
}
|
|
218
290
|
|
|
@@ -238,14 +310,15 @@ async function syncProjectSharedProblemProjection(projectPath = process.cwd(), o
|
|
|
238
310
|
};
|
|
239
311
|
}
|
|
240
312
|
|
|
313
|
+
const existing = await readJsonSafe(absolutePath, fileSystem);
|
|
241
314
|
const payload = await buildProjectSharedProblemProjection(projectPath, {
|
|
242
315
|
...options,
|
|
243
316
|
projectSharedProjection: projectionConfig
|
|
244
317
|
}, {
|
|
245
318
|
...dependencies,
|
|
246
|
-
problemClosurePolicyBundle: closurePolicy
|
|
319
|
+
problemClosurePolicyBundle: closurePolicy,
|
|
320
|
+
existingProjection: existing
|
|
247
321
|
});
|
|
248
|
-
const existing = await readJsonSafe(absolutePath, fileSystem);
|
|
249
322
|
const existingComparable = toComparableProjection(existing);
|
|
250
323
|
const nextComparable = toComparableProjection(payload);
|
|
251
324
|
|
|
@@ -17,6 +17,7 @@ const PROJECT_ONBOARDING_REASON_CODES = {
|
|
|
17
17
|
ROOT_ACCEPTED: 'project.onboarding.root_accepted',
|
|
18
18
|
IMPORT_NO_ACTIVATE: 'project.onboarding.import_no_activate',
|
|
19
19
|
REGISTERED: 'project.onboarding.registered',
|
|
20
|
+
PUBLISHED: 'project.onboarding.published',
|
|
20
21
|
ADOPTED: 'project.onboarding.adopted',
|
|
21
22
|
SCAFFOLD_REUSED: 'project.onboarding.scaffold_reused',
|
|
22
23
|
ADOPTION_FAILED: 'project.onboarding.adoption_failed'
|
|
@@ -38,6 +39,19 @@ function buildStep(key, status, detail, reasonCode) {
|
|
|
38
39
|
};
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
function buildPublication(preview = {}, options = {}) {
|
|
43
|
+
const status = normalizeString(options.status) || 'not_published';
|
|
44
|
+
const publishedAt = normalizeString(options.publishedAt);
|
|
45
|
+
return {
|
|
46
|
+
status,
|
|
47
|
+
visibleInPortfolio: options.visibleInPortfolio === true,
|
|
48
|
+
rootDir: preview.rootDir || null,
|
|
49
|
+
projectId: preview.projectId || null,
|
|
50
|
+
workspaceId: preview.workspaceId || null,
|
|
51
|
+
...(publishedAt ? { publishedAt } : {})
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
41
55
|
function buildWorkspaceNameCandidate(rootDir) {
|
|
42
56
|
const base = path.basename(rootDir).trim().toLowerCase();
|
|
43
57
|
const normalized = base.replace(/[^a-z0-9._-]+/g, '-').replace(/^-+|-+$/g, '');
|
|
@@ -67,6 +81,10 @@ function buildFailureEnvelope(rootInspection, steps, detail, reasonCode) {
|
|
|
67
81
|
success: false,
|
|
68
82
|
preview: rootInspection,
|
|
69
83
|
summary: rootInspection,
|
|
84
|
+
publication: buildPublication(rootInspection, {
|
|
85
|
+
status: 'not_published',
|
|
86
|
+
visibleInPortfolio: false
|
|
87
|
+
}),
|
|
70
88
|
steps,
|
|
71
89
|
error: {
|
|
72
90
|
reasonCode,
|
|
@@ -129,6 +147,12 @@ async function runProjectRootOnboardingImport(options = {}, dependencies = {}) {
|
|
|
129
147
|
'Onboarding cannot continue until the root is valid.',
|
|
130
148
|
PROJECT_ONBOARDING_REASON_CODES.BLOCKED_BY_CANDIDATE
|
|
131
149
|
));
|
|
150
|
+
steps.push(buildStep(
|
|
151
|
+
'publish',
|
|
152
|
+
'skipped',
|
|
153
|
+
'Canonical portfolio publication is blocked until the root is valid.',
|
|
154
|
+
PROJECT_ONBOARDING_REASON_CODES.BLOCKED_BY_CANDIDATE
|
|
155
|
+
));
|
|
132
156
|
steps.push(buildStep(
|
|
133
157
|
'activate',
|
|
134
158
|
'skipped',
|
|
@@ -168,6 +192,12 @@ async function runProjectRootOnboardingImport(options = {}, dependencies = {}) {
|
|
|
168
192
|
'Existing project metadata must be repaired before import.',
|
|
169
193
|
PROJECT_CANDIDATE_REASON_CODES.INVALID_PROJECT_METADATA
|
|
170
194
|
));
|
|
195
|
+
steps.push(buildStep(
|
|
196
|
+
'publish',
|
|
197
|
+
'skipped',
|
|
198
|
+
'Canonical portfolio publication is blocked by invalid project metadata.',
|
|
199
|
+
PROJECT_CANDIDATE_REASON_CODES.INVALID_PROJECT_METADATA
|
|
200
|
+
));
|
|
171
201
|
steps.push(buildStep(
|
|
172
202
|
'activate',
|
|
173
203
|
'skipped',
|
|
@@ -220,6 +250,12 @@ async function runProjectRootOnboardingImport(options = {}, dependencies = {}) {
|
|
|
220
250
|
(importResult.errors || []).join('; ') || 'Adoption failed.',
|
|
221
251
|
PROJECT_ONBOARDING_REASON_CODES.ADOPTION_FAILED
|
|
222
252
|
));
|
|
253
|
+
steps.push(buildStep(
|
|
254
|
+
'publish',
|
|
255
|
+
'skipped',
|
|
256
|
+
'Canonical portfolio publication was not attempted because onboarding failed.',
|
|
257
|
+
PROJECT_ONBOARDING_REASON_CODES.ADOPTION_FAILED
|
|
258
|
+
));
|
|
223
259
|
steps.push(buildStep(
|
|
224
260
|
'activate',
|
|
225
261
|
'skipped',
|
|
@@ -298,6 +334,13 @@ async function runProjectRootOnboardingImport(options = {}, dependencies = {}) {
|
|
|
298
334
|
? PROJECT_ONBOARDING_REASON_CODES.ADOPTED
|
|
299
335
|
: PROJECT_CANDIDATE_REASON_CODES.SCE_PRESENT
|
|
300
336
|
));
|
|
337
|
+
const publishedAt = new Date().toISOString();
|
|
338
|
+
steps.push(buildStep(
|
|
339
|
+
'publish',
|
|
340
|
+
'done',
|
|
341
|
+
`Project is visible in the canonical portfolio as ${onboardingPreview.projectId}.`,
|
|
342
|
+
PROJECT_ONBOARDING_REASON_CODES.PUBLISHED
|
|
343
|
+
));
|
|
301
344
|
steps.push(buildStep(
|
|
302
345
|
'activate',
|
|
303
346
|
'skipped',
|
|
@@ -317,10 +360,15 @@ async function runProjectRootOnboardingImport(options = {}, dependencies = {}) {
|
|
|
317
360
|
|
|
318
361
|
return {
|
|
319
362
|
mode: 'import',
|
|
320
|
-
generated_at:
|
|
363
|
+
generated_at: publishedAt,
|
|
321
364
|
success: true,
|
|
322
365
|
preview: onboardingPreview,
|
|
323
366
|
summary: onboardingPreview,
|
|
367
|
+
publication: buildPublication(onboardingPreview, {
|
|
368
|
+
status: 'published',
|
|
369
|
+
visibleInPortfolio: true,
|
|
370
|
+
publishedAt
|
|
371
|
+
}),
|
|
324
372
|
steps,
|
|
325
373
|
result: {
|
|
326
374
|
rootDir: onboardingPreview.rootDir,
|
package/package.json
CHANGED
|
@@ -21,6 +21,30 @@ const RELEASE_DOCS = [
|
|
|
21
21
|
updatedField: '最后更新',
|
|
22
22
|
updatedPattern: /\*\*最后更新\*\*[::]\s*(\d{4}-\d{2}-\d{2})/
|
|
23
23
|
},
|
|
24
|
+
{
|
|
25
|
+
file: 'docs/command-reference.md',
|
|
26
|
+
label: 'docs/command-reference.md',
|
|
27
|
+
versionField: 'Version',
|
|
28
|
+
versionPattern: /\*\*Version\*\*:\s*([^\s]+)/,
|
|
29
|
+
updatedField: 'Last Updated',
|
|
30
|
+
updatedPattern: /\*\*Last Updated\*\*:\s*(\d{4}-\d{2}-\d{2})/
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
file: 'docs/README.md',
|
|
34
|
+
label: 'docs/README.md',
|
|
35
|
+
versionField: 'Version',
|
|
36
|
+
versionPattern: /\*\*Version\*\*:\s*([^\s]+)/,
|
|
37
|
+
updatedField: 'Last Updated',
|
|
38
|
+
updatedPattern: /\*\*Last Updated\*\*:\s*(\d{4}-\d{2}-\d{2})/
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
file: 'docs/zh/README.md',
|
|
42
|
+
label: 'docs/zh/README.md',
|
|
43
|
+
versionField: '版本',
|
|
44
|
+
versionPattern: /\*\*版本\*\*[::]\s*([^\s]+)/,
|
|
45
|
+
updatedField: '最后更新',
|
|
46
|
+
updatedPattern: /\*\*最后更新\*\*[::]\s*(\d{4}-\d{2}-\d{2})/
|
|
47
|
+
},
|
|
24
48
|
{
|
|
25
49
|
file: '.sce/README.md',
|
|
26
50
|
label: '.sce/README.md',
|
package/template/.sce/README.md
CHANGED
|
@@ -243,6 +243,6 @@ A Spec is a complete feature definition with three parts:
|
|
|
243
243
|
---
|
|
244
244
|
|
|
245
245
|
**Project Type**: Spec-driven development
|
|
246
|
-
**sce Version**: 3.6.
|
|
247
|
-
**Last Updated**: 2026-03-
|
|
246
|
+
**sce Version**: 3.6.65
|
|
247
|
+
**Last Updated**: 2026-03-22
|
|
248
248
|
**Purpose**: Guide AI tools to work effectively with this project
|