@planu/cli 5.3.8 → 5.3.9
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 +10 -0
- package/dist/engine/code-scanner/index.d.ts +3 -2
- package/dist/engine/code-scanner/index.js +4 -3
- package/dist/engine/code-scanner/layer-scanner.d.ts +3 -2
- package/dist/engine/code-scanner/layer-scanner.js +38 -45
- package/dist/engine/planu-core.darwin-arm64.node.manifest.json +7 -7
- package/dist/engine/planu-core.darwin-arm64.node.sbom.json +4 -4
- package/dist/engine/planu-core.darwin-x64.node.manifest.json +7 -7
- package/dist/engine/planu-core.darwin-x64.node.sbom.json +4 -4
- package/dist/engine/planu-core.linux-arm64-gnu.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-arm64-gnu.node.sbom.json +4 -4
- package/dist/engine/planu-core.linux-arm64-musl.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-arm64-musl.node.sbom.json +4 -4
- package/dist/engine/planu-core.linux-x64-gnu.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-x64-gnu.node.sbom.json +4 -4
- package/dist/engine/planu-core.linux-x64-musl.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-x64-musl.node.sbom.json +4 -4
- package/dist/engine/planu-core.win32-arm64-msvc.node.manifest.json +7 -7
- package/dist/engine/planu-core.win32-arm64-msvc.node.sbom.json +4 -4
- package/dist/engine/planu-core.win32-x64-msvc.node.manifest.json +7 -7
- package/dist/engine/planu-core.win32-x64-msvc.node.sbom.json +4 -4
- package/dist/engine/spec-format/technical-md-populator.js +34 -12
- package/dist/tools/update-status/index.d.ts +3 -1
- package/dist/tools/update-status/index.js +16 -1
- package/package.json +9 -9
- package/planu-native.json +1 -1
- package/planu-plugin.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
## [5.3.9] - 2026-08-09
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
- fix(spec-format): reject prose bullets in Files-section ownership parsing
|
|
5
|
+
- fix(code-scanner): bound implementation-detection evidence to spec-owned paths
|
|
6
|
+
|
|
7
|
+
### Chores
|
|
8
|
+
- chore(planu): record SPEC-1219 done transition and duplicate-cluster discards
|
|
9
|
+
|
|
10
|
+
|
|
1
11
|
## [5.3.8] - 2026-08-09
|
|
2
12
|
|
|
3
13
|
### Bug Fixes
|
|
@@ -6,7 +6,8 @@ export type { GapScore, ImplementationStatus } from './gap-scorer.js';
|
|
|
6
6
|
import { type GapScore } from './gap-scorer.js';
|
|
7
7
|
/**
|
|
8
8
|
* Run the full code reality check for a spec in a project.
|
|
9
|
-
*
|
|
9
|
+
* Evidence is bounded to the spec's canonical owned paths (SPEC-1219);
|
|
10
|
+
* empty ownership yields the zero-score GapScore instead of a repo-wide scan.
|
|
10
11
|
*/
|
|
11
|
-
export declare function checkCodeReality(projectPath: string, specTitle: string, specDescription?: string): Promise<GapScore>;
|
|
12
|
+
export declare function checkCodeReality(projectPath: string, specTitle: string, ownedPaths: string[], specDescription?: string): Promise<GapScore>;
|
|
12
13
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -7,12 +7,13 @@ import { scanLayers } from './layer-scanner.js';
|
|
|
7
7
|
import { scoreGap } from './gap-scorer.js';
|
|
8
8
|
/**
|
|
9
9
|
* Run the full code reality check for a spec in a project.
|
|
10
|
-
*
|
|
10
|
+
* Evidence is bounded to the spec's canonical owned paths (SPEC-1219);
|
|
11
|
+
* empty ownership yields the zero-score GapScore instead of a repo-wide scan.
|
|
11
12
|
*/
|
|
12
|
-
export async function checkCodeReality(projectPath, specTitle, specDescription) {
|
|
13
|
+
export async function checkCodeReality(projectPath, specTitle, ownedPaths, specDescription) {
|
|
13
14
|
const keywords = extractKeywords(specTitle, specDescription);
|
|
14
15
|
const variants = toSymbolVariants(keywords);
|
|
15
|
-
const layers = await scanLayers(projectPath, keywords, variants);
|
|
16
|
+
const layers = await scanLayers(projectPath, keywords, variants, ownedPaths);
|
|
16
17
|
return scoreGap(layers);
|
|
17
18
|
}
|
|
18
19
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { LayerScanResult } from '../../types/index.js';
|
|
2
2
|
export type { LayerScanResult };
|
|
3
3
|
/**
|
|
4
|
-
* Scan
|
|
4
|
+
* Scan the spec's owned paths for evidence of implementation across 4 layers.
|
|
5
|
+
* Empty ownership yields an empty result — never a repository-wide scan.
|
|
5
6
|
*/
|
|
6
|
-
export declare function scanLayers(projectPath: string, keywords: string[], symbolVariants: string[]): Promise<LayerScanResult>;
|
|
7
|
+
export declare function scanLayers(projectPath: string, keywords: string[], symbolVariants: string[], ownedPaths: string[]): Promise<LayerScanResult>;
|
|
7
8
|
//# sourceMappingURL=layer-scanner.d.ts.map
|
|
@@ -1,42 +1,47 @@
|
|
|
1
1
|
// src/engine/code-scanner/layer-scanner.ts — Scans the 4 implementation layers (SPEC-441)
|
|
2
|
+
// SPEC-1219: evidence is bounded to the spec's canonical owned paths.
|
|
2
3
|
import { stat } from 'node:fs/promises';
|
|
3
|
-
import { join, relative, basename } from 'node:path';
|
|
4
|
-
import {
|
|
4
|
+
import { join, relative, basename, isAbsolute, normalize } from 'node:path';
|
|
5
|
+
import { fastReadFiles } from '../core-bridge.js';
|
|
6
|
+
const CODE_FILE_RE = /\.(ts|js|tsx|jsx)$/;
|
|
5
7
|
/**
|
|
6
|
-
* Scan
|
|
8
|
+
* Scan the spec's owned paths for evidence of implementation across 4 layers.
|
|
9
|
+
* Empty ownership yields an empty result — never a repository-wide scan.
|
|
7
10
|
*/
|
|
8
|
-
export async function scanLayers(projectPath, keywords, symbolVariants) {
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
srcFiles = fastFindFilesByExt(srcDir, ['ts', 'js', 'tsx', 'jsx']).filter((f) => !f.endsWith('.d.ts'));
|
|
16
|
-
}
|
|
17
|
-
if (testsExists) {
|
|
18
|
-
testFiles = fastFindFilesByExt(testsDir, ['ts', 'js', 'tsx', 'jsx']).filter((f) => !f.endsWith('.d.ts'));
|
|
19
|
-
}
|
|
20
|
-
// Layer 1: files whose names match keywords
|
|
21
|
-
const matchedFiles = srcFiles.filter((f) => keywords.some((kw) => basename(f).toLowerCase().includes(kw)));
|
|
22
|
-
// Layer 2: exported symbols in matched files (and register/index files)
|
|
23
|
-
const registerFiles = srcFiles.filter((f) => /register.*\.ts$|index\.ts$/.test(f));
|
|
24
|
-
const filesToScanForSymbols = [...new Set([...matchedFiles, ...registerFiles])];
|
|
25
|
-
const symbols = findSymbols(filesToScanForSymbols, symbolVariants);
|
|
26
|
-
// Layer 3: test files matching keywords
|
|
11
|
+
export async function scanLayers(projectPath, keywords, symbolVariants, ownedPaths) {
|
|
12
|
+
const ownedFiles = await resolveExistingOwnedFiles(projectPath, ownedPaths);
|
|
13
|
+
const testFiles = ownedFiles.filter(isTestPath);
|
|
14
|
+
const sourceFiles = ownedFiles.filter((f) => !isTestPath(f));
|
|
15
|
+
const sourceCodeFiles = sourceFiles.filter((f) => CODE_FILE_RE.test(f) && !f.endsWith('.d.ts'));
|
|
16
|
+
const matchedFiles = sourceFiles.filter((f) => keywords.some((kw) => basename(f).toLowerCase().includes(kw)));
|
|
17
|
+
const symbols = findSymbols(sourceCodeFiles.map((f) => join(projectPath, f)), symbolVariants);
|
|
27
18
|
const matchedTests = testFiles.filter((f) => keywords.some((kw) => basename(f).toLowerCase().includes(kw)));
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return {
|
|
31
|
-
files: matchedFiles.map((f) => relative(projectPath, f)),
|
|
32
|
-
symbols,
|
|
33
|
-
tests: matchedTests.map((f) => relative(projectPath, f)),
|
|
34
|
-
registrations,
|
|
35
|
-
};
|
|
19
|
+
const registrations = findRegistrations(sourceCodeFiles.map((f) => join(projectPath, f)), keywords);
|
|
20
|
+
return { files: matchedFiles, symbols, tests: matchedTests, registrations };
|
|
36
21
|
}
|
|
37
22
|
// ---------------------------------------------------------------------------
|
|
38
23
|
// Internal helpers
|
|
39
24
|
// ---------------------------------------------------------------------------
|
|
25
|
+
async function resolveExistingOwnedFiles(projectPath, ownedPaths) {
|
|
26
|
+
const inRoot = [
|
|
27
|
+
...new Set(ownedPaths
|
|
28
|
+
.map((p) => normalize(p))
|
|
29
|
+
.filter((p) => !isAbsolute(p) && !p.split(/[\\/]/).includes('..'))),
|
|
30
|
+
];
|
|
31
|
+
const existing = await Promise.all(inRoot.map(async (p) => {
|
|
32
|
+
try {
|
|
33
|
+
const s = await stat(join(projectPath, p));
|
|
34
|
+
return s.isFile() ? relative(projectPath, join(projectPath, p)) : null;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}));
|
|
40
|
+
return existing.filter((p) => p !== null);
|
|
41
|
+
}
|
|
42
|
+
function isTestPath(relativePath) {
|
|
43
|
+
return relativePath.startsWith('tests/') || /\.(test|spec)\.[a-z]+$/.test(relativePath);
|
|
44
|
+
}
|
|
40
45
|
function findSymbols(files, variants) {
|
|
41
46
|
const found = new Set();
|
|
42
47
|
if (files.length > 0) {
|
|
@@ -51,16 +56,14 @@ function findSymbols(files, variants) {
|
|
|
51
56
|
}
|
|
52
57
|
EXPORT_RE.lastIndex = 0;
|
|
53
58
|
}
|
|
54
|
-
return [...found];
|
|
55
59
|
}
|
|
56
60
|
return [...found];
|
|
57
61
|
}
|
|
58
|
-
function findRegistrations(
|
|
62
|
+
function findRegistrations(files, keywords) {
|
|
59
63
|
const found = new Set();
|
|
60
|
-
|
|
61
|
-
if (registerFiles.length > 0) {
|
|
64
|
+
if (files.length > 0) {
|
|
62
65
|
const REGISTER_RE = /(?:registerTool\s*\(\s*|name:\s*)['"]([^'"]+)['"]/g;
|
|
63
|
-
for (const file of fastReadFiles(
|
|
66
|
+
for (const file of fastReadFiles(files)) {
|
|
64
67
|
let match;
|
|
65
68
|
while ((match = REGISTER_RE.exec(file.content)) !== null) {
|
|
66
69
|
const toolName = match[1] ?? '';
|
|
@@ -70,17 +73,7 @@ function findRegistrations(_projectPath, srcFiles, keywords) {
|
|
|
70
73
|
}
|
|
71
74
|
REGISTER_RE.lastIndex = 0;
|
|
72
75
|
}
|
|
73
|
-
return [...found];
|
|
74
76
|
}
|
|
75
77
|
return [...found];
|
|
76
78
|
}
|
|
77
|
-
async function dirExists(p) {
|
|
78
|
-
try {
|
|
79
|
-
const s = await stat(p);
|
|
80
|
-
return s.isDirectory();
|
|
81
|
-
}
|
|
82
|
-
catch {
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
79
|
//# sourceMappingURL=layer-scanner.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
|
-
"cliVersion": "5.3.
|
|
4
|
-
"engineVersion": "5.3.
|
|
5
|
-
"buildId": "1-5.3.
|
|
3
|
+
"cliVersion": "5.3.9",
|
|
4
|
+
"engineVersion": "5.3.9",
|
|
5
|
+
"buildId": "1-5.3.9-aarch64-apple-darwin",
|
|
6
6
|
"protocolAbi": 1,
|
|
7
7
|
"capabilityAbi": 2,
|
|
8
8
|
"nodeApiAbi": 4,
|
|
@@ -17,15 +17,15 @@
|
|
|
17
17
|
"platform": "darwin",
|
|
18
18
|
"arch": "arm64",
|
|
19
19
|
"libc": null,
|
|
20
|
-
"artifactSha256": "
|
|
20
|
+
"artifactSha256": "aa89aa3aa05ddb5a068bd24ece7a978ac3eeeeb9168efb4ced87e84df8ca60e1",
|
|
21
21
|
"sbom": {
|
|
22
22
|
"format": "CycloneDX-1.5",
|
|
23
23
|
"path": "planu-core.darwin-arm64.node.sbom.json",
|
|
24
|
-
"sha256": "
|
|
24
|
+
"sha256": "f56eb129e8a2e18ffed9ac9f18fb964baebaa1f8514605f92e444a9d561d7e46"
|
|
25
25
|
},
|
|
26
26
|
"provenance": {
|
|
27
27
|
"builder": "scripts/build-rust-local.sh",
|
|
28
|
-
"sourceCommit": "
|
|
28
|
+
"sourceCommit": "2f21909cad8fb83fdef7355732e371b3bdecd680",
|
|
29
29
|
"sourceTreeDirty": false,
|
|
30
30
|
"sourceDateEpoch": 1,
|
|
31
31
|
"rustToolchain": "rustc 1.95.0 (59807616e 2026-04-14)",
|
|
@@ -34,6 +34,6 @@
|
|
|
34
34
|
"signature": {
|
|
35
35
|
"algorithm": "Ed25519",
|
|
36
36
|
"keyId": "e2ee765cb5ad9fbdc433ece332bce26d746d5e350b3acde0721a4c8c6337ff7b",
|
|
37
|
-
"value": "
|
|
37
|
+
"value": "H3mMgXIwlhiq4j4NuqvE+zTCpOirZu+pzyxZ5wKmpLqbM0s2SaPr/ZaUYB5/MGQjMkizqtKyC2nZgMOvPq53CA=="
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
"version": 1,
|
|
5
5
|
"metadata": {
|
|
6
6
|
"component": {
|
|
7
|
-
"bom-ref": "pkg:cargo/planu-core@5.3.
|
|
7
|
+
"bom-ref": "pkg:cargo/planu-core@5.3.9",
|
|
8
8
|
"type": "library",
|
|
9
9
|
"name": "planu-core",
|
|
10
|
-
"version": "5.3.
|
|
10
|
+
"version": "5.3.9",
|
|
11
11
|
"hashes": [
|
|
12
12
|
{
|
|
13
13
|
"alg": "SHA-256",
|
|
14
|
-
"content": "
|
|
14
|
+
"content": "aa89aa3aa05ddb5a068bd24ece7a978ac3eeeeb9168efb4ced87e84df8ca60e1"
|
|
15
15
|
}
|
|
16
16
|
]
|
|
17
17
|
}
|
|
@@ -1106,7 +1106,7 @@
|
|
|
1106
1106
|
"dependsOn": []
|
|
1107
1107
|
},
|
|
1108
1108
|
{
|
|
1109
|
-
"ref": "pkg:cargo/planu-core@5.3.
|
|
1109
|
+
"ref": "pkg:cargo/planu-core@5.3.9",
|
|
1110
1110
|
"dependsOn": [
|
|
1111
1111
|
"pkg:cargo/core-foundation@0.10.1",
|
|
1112
1112
|
"pkg:cargo/hmac@0.12.1",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
|
-
"cliVersion": "5.3.
|
|
4
|
-
"engineVersion": "5.3.
|
|
5
|
-
"buildId": "1-5.3.
|
|
3
|
+
"cliVersion": "5.3.9",
|
|
4
|
+
"engineVersion": "5.3.9",
|
|
5
|
+
"buildId": "1-5.3.9-x86_64-apple-darwin",
|
|
6
6
|
"protocolAbi": 1,
|
|
7
7
|
"capabilityAbi": 2,
|
|
8
8
|
"nodeApiAbi": 4,
|
|
@@ -17,15 +17,15 @@
|
|
|
17
17
|
"platform": "darwin",
|
|
18
18
|
"arch": "x64",
|
|
19
19
|
"libc": null,
|
|
20
|
-
"artifactSha256": "
|
|
20
|
+
"artifactSha256": "55a9c827e88c3788444c46a0f378b1a5ba50dea089d63ffb78f4951dc1b02d28",
|
|
21
21
|
"sbom": {
|
|
22
22
|
"format": "CycloneDX-1.5",
|
|
23
23
|
"path": "planu-core.darwin-x64.node.sbom.json",
|
|
24
|
-
"sha256": "
|
|
24
|
+
"sha256": "b0be880b86d4a56949a55b04702a1c153b6d2fdf26adfa7d0ed3447163c7af88"
|
|
25
25
|
},
|
|
26
26
|
"provenance": {
|
|
27
27
|
"builder": "scripts/build-rust-local.sh",
|
|
28
|
-
"sourceCommit": "
|
|
28
|
+
"sourceCommit": "2f21909cad8fb83fdef7355732e371b3bdecd680",
|
|
29
29
|
"sourceTreeDirty": false,
|
|
30
30
|
"sourceDateEpoch": 1,
|
|
31
31
|
"rustToolchain": "rustc 1.95.0 (59807616e 2026-04-14)",
|
|
@@ -34,6 +34,6 @@
|
|
|
34
34
|
"signature": {
|
|
35
35
|
"algorithm": "Ed25519",
|
|
36
36
|
"keyId": "e2ee765cb5ad9fbdc433ece332bce26d746d5e350b3acde0721a4c8c6337ff7b",
|
|
37
|
-
"value": "
|
|
37
|
+
"value": "G9fhhvTX/rIxX4ebpVvQR7VSuuhVSrhDJG6tE0uKcLoWSDu0wJ6VCmMriliYjekpYVkx0WPsjFHGP4QQv0n6Bw=="
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
"version": 1,
|
|
5
5
|
"metadata": {
|
|
6
6
|
"component": {
|
|
7
|
-
"bom-ref": "pkg:cargo/planu-core@5.3.
|
|
7
|
+
"bom-ref": "pkg:cargo/planu-core@5.3.9",
|
|
8
8
|
"type": "library",
|
|
9
9
|
"name": "planu-core",
|
|
10
|
-
"version": "5.3.
|
|
10
|
+
"version": "5.3.9",
|
|
11
11
|
"hashes": [
|
|
12
12
|
{
|
|
13
13
|
"alg": "SHA-256",
|
|
14
|
-
"content": "
|
|
14
|
+
"content": "55a9c827e88c3788444c46a0f378b1a5ba50dea089d63ffb78f4951dc1b02d28"
|
|
15
15
|
}
|
|
16
16
|
]
|
|
17
17
|
}
|
|
@@ -1106,7 +1106,7 @@
|
|
|
1106
1106
|
"dependsOn": []
|
|
1107
1107
|
},
|
|
1108
1108
|
{
|
|
1109
|
-
"ref": "pkg:cargo/planu-core@5.3.
|
|
1109
|
+
"ref": "pkg:cargo/planu-core@5.3.9",
|
|
1110
1110
|
"dependsOn": [
|
|
1111
1111
|
"pkg:cargo/core-foundation@0.10.1",
|
|
1112
1112
|
"pkg:cargo/hmac@0.12.1",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
|
-
"cliVersion": "5.3.
|
|
4
|
-
"engineVersion": "5.3.
|
|
5
|
-
"buildId": "1-5.3.
|
|
3
|
+
"cliVersion": "5.3.9",
|
|
4
|
+
"engineVersion": "5.3.9",
|
|
5
|
+
"buildId": "1-5.3.9-aarch64-unknown-linux-gnu",
|
|
6
6
|
"protocolAbi": 1,
|
|
7
7
|
"capabilityAbi": 2,
|
|
8
8
|
"nodeApiAbi": 4,
|
|
@@ -16,15 +16,15 @@
|
|
|
16
16
|
"platform": "linux",
|
|
17
17
|
"arch": "arm64",
|
|
18
18
|
"libc": "glibc",
|
|
19
|
-
"artifactSha256": "
|
|
19
|
+
"artifactSha256": "fb4dbd057464aa65ce83f41e36fe6036d53aaf0bf272c75ccc36f57b2187849c",
|
|
20
20
|
"sbom": {
|
|
21
21
|
"format": "CycloneDX-1.5",
|
|
22
22
|
"path": "planu-core.linux-arm64-gnu.node.sbom.json",
|
|
23
|
-
"sha256": "
|
|
23
|
+
"sha256": "21d45e84874017f0e4d7383b464fc841c18d19766932890c8bb620d8c40c94bd"
|
|
24
24
|
},
|
|
25
25
|
"provenance": {
|
|
26
26
|
"builder": "scripts/build-rust-local.sh",
|
|
27
|
-
"sourceCommit": "
|
|
27
|
+
"sourceCommit": "2f21909cad8fb83fdef7355732e371b3bdecd680",
|
|
28
28
|
"sourceTreeDirty": false,
|
|
29
29
|
"sourceDateEpoch": 1,
|
|
30
30
|
"rustToolchain": "rustc 1.95.0 (59807616e 2026-04-14)",
|
|
@@ -33,6 +33,6 @@
|
|
|
33
33
|
"signature": {
|
|
34
34
|
"algorithm": "Ed25519",
|
|
35
35
|
"keyId": "e2ee765cb5ad9fbdc433ece332bce26d746d5e350b3acde0721a4c8c6337ff7b",
|
|
36
|
-
"value": "
|
|
36
|
+
"value": "lSRsubYOYi3TYQpVCbJh9+c8GFc9TOfTolVpGwaq9JFWAosZK3vIPHgMig9GToDprIvnPUTwcgKAs326tsjKDg=="
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
"version": 1,
|
|
5
5
|
"metadata": {
|
|
6
6
|
"component": {
|
|
7
|
-
"bom-ref": "pkg:cargo/planu-core@5.3.
|
|
7
|
+
"bom-ref": "pkg:cargo/planu-core@5.3.9",
|
|
8
8
|
"type": "library",
|
|
9
9
|
"name": "planu-core",
|
|
10
|
-
"version": "5.3.
|
|
10
|
+
"version": "5.3.9",
|
|
11
11
|
"hashes": [
|
|
12
12
|
{
|
|
13
13
|
"alg": "SHA-256",
|
|
14
|
-
"content": "
|
|
14
|
+
"content": "fb4dbd057464aa65ce83f41e36fe6036d53aaf0bf272c75ccc36f57b2187849c"
|
|
15
15
|
}
|
|
16
16
|
]
|
|
17
17
|
}
|
|
@@ -1106,7 +1106,7 @@
|
|
|
1106
1106
|
"dependsOn": []
|
|
1107
1107
|
},
|
|
1108
1108
|
{
|
|
1109
|
-
"ref": "pkg:cargo/planu-core@5.3.
|
|
1109
|
+
"ref": "pkg:cargo/planu-core@5.3.9",
|
|
1110
1110
|
"dependsOn": [
|
|
1111
1111
|
"pkg:cargo/core-foundation@0.10.1",
|
|
1112
1112
|
"pkg:cargo/hmac@0.12.1",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
|
-
"cliVersion": "5.3.
|
|
4
|
-
"engineVersion": "5.3.
|
|
5
|
-
"buildId": "1-5.3.
|
|
3
|
+
"cliVersion": "5.3.9",
|
|
4
|
+
"engineVersion": "5.3.9",
|
|
5
|
+
"buildId": "1-5.3.9-aarch64-unknown-linux-musl",
|
|
6
6
|
"protocolAbi": 1,
|
|
7
7
|
"capabilityAbi": 2,
|
|
8
8
|
"nodeApiAbi": 4,
|
|
@@ -16,15 +16,15 @@
|
|
|
16
16
|
"platform": "linux",
|
|
17
17
|
"arch": "arm64",
|
|
18
18
|
"libc": "musl",
|
|
19
|
-
"artifactSha256": "
|
|
19
|
+
"artifactSha256": "c8142e5d1cb01493596c7c664d3400849b274d31d7d2289f14c84ac3bd037fe3",
|
|
20
20
|
"sbom": {
|
|
21
21
|
"format": "CycloneDX-1.5",
|
|
22
22
|
"path": "planu-core.linux-arm64-musl.node.sbom.json",
|
|
23
|
-
"sha256": "
|
|
23
|
+
"sha256": "8f1aae983dc5f692f316aab83874489846872a327354ce9dd47d186e1ca0709e"
|
|
24
24
|
},
|
|
25
25
|
"provenance": {
|
|
26
26
|
"builder": "scripts/build-rust-local.sh",
|
|
27
|
-
"sourceCommit": "
|
|
27
|
+
"sourceCommit": "2f21909cad8fb83fdef7355732e371b3bdecd680",
|
|
28
28
|
"sourceTreeDirty": false,
|
|
29
29
|
"sourceDateEpoch": 1,
|
|
30
30
|
"rustToolchain": "rustc 1.95.0 (59807616e 2026-04-14)",
|
|
@@ -33,6 +33,6 @@
|
|
|
33
33
|
"signature": {
|
|
34
34
|
"algorithm": "Ed25519",
|
|
35
35
|
"keyId": "e2ee765cb5ad9fbdc433ece332bce26d746d5e350b3acde0721a4c8c6337ff7b",
|
|
36
|
-
"value": "
|
|
36
|
+
"value": "q7lVG3ZQ6J+0jQTVwf+f7EEzoFiigbfub8e1Jpl/0GYPzB4Py7NNJ8hsjtVGEE+zfWSq38q3pmXevCmljcC6Dw=="
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
"version": 1,
|
|
5
5
|
"metadata": {
|
|
6
6
|
"component": {
|
|
7
|
-
"bom-ref": "pkg:cargo/planu-core@5.3.
|
|
7
|
+
"bom-ref": "pkg:cargo/planu-core@5.3.9",
|
|
8
8
|
"type": "library",
|
|
9
9
|
"name": "planu-core",
|
|
10
|
-
"version": "5.3.
|
|
10
|
+
"version": "5.3.9",
|
|
11
11
|
"hashes": [
|
|
12
12
|
{
|
|
13
13
|
"alg": "SHA-256",
|
|
14
|
-
"content": "
|
|
14
|
+
"content": "c8142e5d1cb01493596c7c664d3400849b274d31d7d2289f14c84ac3bd037fe3"
|
|
15
15
|
}
|
|
16
16
|
]
|
|
17
17
|
}
|
|
@@ -1106,7 +1106,7 @@
|
|
|
1106
1106
|
"dependsOn": []
|
|
1107
1107
|
},
|
|
1108
1108
|
{
|
|
1109
|
-
"ref": "pkg:cargo/planu-core@5.3.
|
|
1109
|
+
"ref": "pkg:cargo/planu-core@5.3.9",
|
|
1110
1110
|
"dependsOn": [
|
|
1111
1111
|
"pkg:cargo/core-foundation@0.10.1",
|
|
1112
1112
|
"pkg:cargo/hmac@0.12.1",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
|
-
"cliVersion": "5.3.
|
|
4
|
-
"engineVersion": "5.3.
|
|
5
|
-
"buildId": "1-5.3.
|
|
3
|
+
"cliVersion": "5.3.9",
|
|
4
|
+
"engineVersion": "5.3.9",
|
|
5
|
+
"buildId": "1-5.3.9-x86_64-unknown-linux-gnu",
|
|
6
6
|
"protocolAbi": 1,
|
|
7
7
|
"capabilityAbi": 2,
|
|
8
8
|
"nodeApiAbi": 4,
|
|
@@ -16,15 +16,15 @@
|
|
|
16
16
|
"platform": "linux",
|
|
17
17
|
"arch": "x64",
|
|
18
18
|
"libc": "glibc",
|
|
19
|
-
"artifactSha256": "
|
|
19
|
+
"artifactSha256": "6ef9e8eec72c0d639a72882c8007943006f6568e4241912892e70cf283c2cefd",
|
|
20
20
|
"sbom": {
|
|
21
21
|
"format": "CycloneDX-1.5",
|
|
22
22
|
"path": "planu-core.linux-x64-gnu.node.sbom.json",
|
|
23
|
-
"sha256": "
|
|
23
|
+
"sha256": "aa483aff74d5db6676c555022d5a5736cc4fb9647bfd0959f331d0a7a8f5d978"
|
|
24
24
|
},
|
|
25
25
|
"provenance": {
|
|
26
26
|
"builder": "scripts/build-rust-local.sh",
|
|
27
|
-
"sourceCommit": "
|
|
27
|
+
"sourceCommit": "2f21909cad8fb83fdef7355732e371b3bdecd680",
|
|
28
28
|
"sourceTreeDirty": false,
|
|
29
29
|
"sourceDateEpoch": 1,
|
|
30
30
|
"rustToolchain": "rustc 1.95.0 (59807616e 2026-04-14)",
|
|
@@ -33,6 +33,6 @@
|
|
|
33
33
|
"signature": {
|
|
34
34
|
"algorithm": "Ed25519",
|
|
35
35
|
"keyId": "e2ee765cb5ad9fbdc433ece332bce26d746d5e350b3acde0721a4c8c6337ff7b",
|
|
36
|
-
"value": "
|
|
36
|
+
"value": "DsgdL5j+z+m+xZz7P0bMjMsNc9r5bHL1vVJUwbhJz62LqHV6nm1PZIVv07h8ghxa2OsB/yZ9EUVyf+RzTX1xDQ=="
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
"version": 1,
|
|
5
5
|
"metadata": {
|
|
6
6
|
"component": {
|
|
7
|
-
"bom-ref": "pkg:cargo/planu-core@5.3.
|
|
7
|
+
"bom-ref": "pkg:cargo/planu-core@5.3.9",
|
|
8
8
|
"type": "library",
|
|
9
9
|
"name": "planu-core",
|
|
10
|
-
"version": "5.3.
|
|
10
|
+
"version": "5.3.9",
|
|
11
11
|
"hashes": [
|
|
12
12
|
{
|
|
13
13
|
"alg": "SHA-256",
|
|
14
|
-
"content": "
|
|
14
|
+
"content": "6ef9e8eec72c0d639a72882c8007943006f6568e4241912892e70cf283c2cefd"
|
|
15
15
|
}
|
|
16
16
|
]
|
|
17
17
|
}
|
|
@@ -1106,7 +1106,7 @@
|
|
|
1106
1106
|
"dependsOn": []
|
|
1107
1107
|
},
|
|
1108
1108
|
{
|
|
1109
|
-
"ref": "pkg:cargo/planu-core@5.3.
|
|
1109
|
+
"ref": "pkg:cargo/planu-core@5.3.9",
|
|
1110
1110
|
"dependsOn": [
|
|
1111
1111
|
"pkg:cargo/core-foundation@0.10.1",
|
|
1112
1112
|
"pkg:cargo/hmac@0.12.1",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
|
-
"cliVersion": "5.3.
|
|
4
|
-
"engineVersion": "5.3.
|
|
5
|
-
"buildId": "1-5.3.
|
|
3
|
+
"cliVersion": "5.3.9",
|
|
4
|
+
"engineVersion": "5.3.9",
|
|
5
|
+
"buildId": "1-5.3.9-x86_64-unknown-linux-musl",
|
|
6
6
|
"protocolAbi": 1,
|
|
7
7
|
"capabilityAbi": 2,
|
|
8
8
|
"nodeApiAbi": 4,
|
|
@@ -16,15 +16,15 @@
|
|
|
16
16
|
"platform": "linux",
|
|
17
17
|
"arch": "x64",
|
|
18
18
|
"libc": "musl",
|
|
19
|
-
"artifactSha256": "
|
|
19
|
+
"artifactSha256": "27f0adf996cc15b639a7de7a3c5f740f8d70689bbd51e1f0a09088c839d37f28",
|
|
20
20
|
"sbom": {
|
|
21
21
|
"format": "CycloneDX-1.5",
|
|
22
22
|
"path": "planu-core.linux-x64-musl.node.sbom.json",
|
|
23
|
-
"sha256": "
|
|
23
|
+
"sha256": "b32256ed9ddb251de718ce576afa775f8eb7c715a9d80f79eca28fc96f9c2c4c"
|
|
24
24
|
},
|
|
25
25
|
"provenance": {
|
|
26
26
|
"builder": "scripts/build-rust-local.sh",
|
|
27
|
-
"sourceCommit": "
|
|
27
|
+
"sourceCommit": "2f21909cad8fb83fdef7355732e371b3bdecd680",
|
|
28
28
|
"sourceTreeDirty": false,
|
|
29
29
|
"sourceDateEpoch": 1,
|
|
30
30
|
"rustToolchain": "rustc 1.95.0 (59807616e 2026-04-14)",
|
|
@@ -33,6 +33,6 @@
|
|
|
33
33
|
"signature": {
|
|
34
34
|
"algorithm": "Ed25519",
|
|
35
35
|
"keyId": "e2ee765cb5ad9fbdc433ece332bce26d746d5e350b3acde0721a4c8c6337ff7b",
|
|
36
|
-
"value": "/
|
|
36
|
+
"value": "oN/U3mL0+OWdeNmELi2M3SaMghwccyheGHzmZqp6MN5NF4lUlSmnnlCzWro4mAOd9xp8pT6D8eFxNgCItv3UBw=="
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
"version": 1,
|
|
5
5
|
"metadata": {
|
|
6
6
|
"component": {
|
|
7
|
-
"bom-ref": "pkg:cargo/planu-core@5.3.
|
|
7
|
+
"bom-ref": "pkg:cargo/planu-core@5.3.9",
|
|
8
8
|
"type": "library",
|
|
9
9
|
"name": "planu-core",
|
|
10
|
-
"version": "5.3.
|
|
10
|
+
"version": "5.3.9",
|
|
11
11
|
"hashes": [
|
|
12
12
|
{
|
|
13
13
|
"alg": "SHA-256",
|
|
14
|
-
"content": "
|
|
14
|
+
"content": "27f0adf996cc15b639a7de7a3c5f740f8d70689bbd51e1f0a09088c839d37f28"
|
|
15
15
|
}
|
|
16
16
|
]
|
|
17
17
|
}
|
|
@@ -1106,7 +1106,7 @@
|
|
|
1106
1106
|
"dependsOn": []
|
|
1107
1107
|
},
|
|
1108
1108
|
{
|
|
1109
|
-
"ref": "pkg:cargo/planu-core@5.3.
|
|
1109
|
+
"ref": "pkg:cargo/planu-core@5.3.9",
|
|
1110
1110
|
"dependsOn": [
|
|
1111
1111
|
"pkg:cargo/core-foundation@0.10.1",
|
|
1112
1112
|
"pkg:cargo/hmac@0.12.1",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
|
-
"cliVersion": "5.3.
|
|
4
|
-
"engineVersion": "5.3.
|
|
5
|
-
"buildId": "1-5.3.
|
|
3
|
+
"cliVersion": "5.3.9",
|
|
4
|
+
"engineVersion": "5.3.9",
|
|
5
|
+
"buildId": "1-5.3.9-aarch64-pc-windows-msvc",
|
|
6
6
|
"protocolAbi": 1,
|
|
7
7
|
"capabilityAbi": 2,
|
|
8
8
|
"nodeApiAbi": 4,
|
|
@@ -16,15 +16,15 @@
|
|
|
16
16
|
"platform": "win32",
|
|
17
17
|
"arch": "arm64",
|
|
18
18
|
"libc": null,
|
|
19
|
-
"artifactSha256": "
|
|
19
|
+
"artifactSha256": "6c202c2aceada6f5c26ed992284a58ae7a9800555b82d9c37b07358e6859c34a",
|
|
20
20
|
"sbom": {
|
|
21
21
|
"format": "CycloneDX-1.5",
|
|
22
22
|
"path": "planu-core.win32-arm64-msvc.node.sbom.json",
|
|
23
|
-
"sha256": "
|
|
23
|
+
"sha256": "86553d4ae3efdb27beab8cb9d6fd4389b0d661d34377a744e2800dcfc44f9191"
|
|
24
24
|
},
|
|
25
25
|
"provenance": {
|
|
26
26
|
"builder": "scripts/build-rust-local.sh",
|
|
27
|
-
"sourceCommit": "
|
|
27
|
+
"sourceCommit": "2f21909cad8fb83fdef7355732e371b3bdecd680",
|
|
28
28
|
"sourceTreeDirty": false,
|
|
29
29
|
"sourceDateEpoch": 1,
|
|
30
30
|
"rustToolchain": "rustc 1.95.0 (59807616e 2026-04-14)",
|
|
@@ -33,6 +33,6 @@
|
|
|
33
33
|
"signature": {
|
|
34
34
|
"algorithm": "Ed25519",
|
|
35
35
|
"keyId": "e2ee765cb5ad9fbdc433ece332bce26d746d5e350b3acde0721a4c8c6337ff7b",
|
|
36
|
-
"value": "
|
|
36
|
+
"value": "pQoY2FWTc46sgixMzb1b335svx0ONg7ByBu1EDYTCHs6BN8geEmAYK6pVb0mOpcEUAY/zliNqa7sadte6RgTAA=="
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
"version": 1,
|
|
5
5
|
"metadata": {
|
|
6
6
|
"component": {
|
|
7
|
-
"bom-ref": "pkg:cargo/planu-core@5.3.
|
|
7
|
+
"bom-ref": "pkg:cargo/planu-core@5.3.9",
|
|
8
8
|
"type": "library",
|
|
9
9
|
"name": "planu-core",
|
|
10
|
-
"version": "5.3.
|
|
10
|
+
"version": "5.3.9",
|
|
11
11
|
"hashes": [
|
|
12
12
|
{
|
|
13
13
|
"alg": "SHA-256",
|
|
14
|
-
"content": "
|
|
14
|
+
"content": "6c202c2aceada6f5c26ed992284a58ae7a9800555b82d9c37b07358e6859c34a"
|
|
15
15
|
}
|
|
16
16
|
]
|
|
17
17
|
}
|
|
@@ -1106,7 +1106,7 @@
|
|
|
1106
1106
|
"dependsOn": []
|
|
1107
1107
|
},
|
|
1108
1108
|
{
|
|
1109
|
-
"ref": "pkg:cargo/planu-core@5.3.
|
|
1109
|
+
"ref": "pkg:cargo/planu-core@5.3.9",
|
|
1110
1110
|
"dependsOn": [
|
|
1111
1111
|
"pkg:cargo/core-foundation@0.10.1",
|
|
1112
1112
|
"pkg:cargo/hmac@0.12.1",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
|
-
"cliVersion": "5.3.
|
|
4
|
-
"engineVersion": "5.3.
|
|
5
|
-
"buildId": "1-5.3.
|
|
3
|
+
"cliVersion": "5.3.9",
|
|
4
|
+
"engineVersion": "5.3.9",
|
|
5
|
+
"buildId": "1-5.3.9-x86_64-pc-windows-msvc",
|
|
6
6
|
"protocolAbi": 1,
|
|
7
7
|
"capabilityAbi": 2,
|
|
8
8
|
"nodeApiAbi": 4,
|
|
@@ -16,15 +16,15 @@
|
|
|
16
16
|
"platform": "win32",
|
|
17
17
|
"arch": "x64",
|
|
18
18
|
"libc": null,
|
|
19
|
-
"artifactSha256": "
|
|
19
|
+
"artifactSha256": "6cef50918eb80b3b1759e7b63970e7a814e5253759e01789b9d1da972a29ed3b",
|
|
20
20
|
"sbom": {
|
|
21
21
|
"format": "CycloneDX-1.5",
|
|
22
22
|
"path": "planu-core.win32-x64-msvc.node.sbom.json",
|
|
23
|
-
"sha256": "
|
|
23
|
+
"sha256": "d7f8a23058675b0fc860c78418126882ef904a25f872b65770ddf7ec5abb4f46"
|
|
24
24
|
},
|
|
25
25
|
"provenance": {
|
|
26
26
|
"builder": "scripts/build-rust-local.sh",
|
|
27
|
-
"sourceCommit": "
|
|
27
|
+
"sourceCommit": "2f21909cad8fb83fdef7355732e371b3bdecd680",
|
|
28
28
|
"sourceTreeDirty": false,
|
|
29
29
|
"sourceDateEpoch": 1,
|
|
30
30
|
"rustToolchain": "rustc 1.95.0 (59807616e 2026-04-14)",
|
|
@@ -33,6 +33,6 @@
|
|
|
33
33
|
"signature": {
|
|
34
34
|
"algorithm": "Ed25519",
|
|
35
35
|
"keyId": "e2ee765cb5ad9fbdc433ece332bce26d746d5e350b3acde0721a4c8c6337ff7b",
|
|
36
|
-
"value": "
|
|
36
|
+
"value": "ow8WRDwYYjXZleoPi7TaesQZg1L063INqzzRYSQCa+qScsRGey0B2X1RZxhgBiEOuu3mCchZ0v6rDKm3XNp0DQ=="
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
"version": 1,
|
|
5
5
|
"metadata": {
|
|
6
6
|
"component": {
|
|
7
|
-
"bom-ref": "pkg:cargo/planu-core@5.3.
|
|
7
|
+
"bom-ref": "pkg:cargo/planu-core@5.3.9",
|
|
8
8
|
"type": "library",
|
|
9
9
|
"name": "planu-core",
|
|
10
|
-
"version": "5.3.
|
|
10
|
+
"version": "5.3.9",
|
|
11
11
|
"hashes": [
|
|
12
12
|
{
|
|
13
13
|
"alg": "SHA-256",
|
|
14
|
-
"content": "
|
|
14
|
+
"content": "6cef50918eb80b3b1759e7b63970e7a814e5253759e01789b9d1da972a29ed3b"
|
|
15
15
|
}
|
|
16
16
|
]
|
|
17
17
|
}
|
|
@@ -1106,7 +1106,7 @@
|
|
|
1106
1106
|
"dependsOn": []
|
|
1107
1107
|
},
|
|
1108
1108
|
{
|
|
1109
|
-
"ref": "pkg:cargo/planu-core@5.3.
|
|
1109
|
+
"ref": "pkg:cargo/planu-core@5.3.9",
|
|
1110
1110
|
"dependsOn": [
|
|
1111
1111
|
"pkg:cargo/core-foundation@0.10.1",
|
|
1112
1112
|
"pkg:cargo/hmac@0.12.1",
|
|
@@ -1,25 +1,45 @@
|
|
|
1
1
|
// engine/spec-format/technical-md-populator.ts — SPEC-586: Parse spec body to populate ## Technical
|
|
2
2
|
import { stat } from 'node:fs/promises';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
|
+
import { findMarkdownSectionRange } from './markdown-sections.js';
|
|
4
5
|
const FILE_PATH_RE = /\b(?:src|tests)\/[a-zA-Z0-9/_.-]+\.[a-z]+\b/g;
|
|
6
|
+
function stripFencedBlocks(content) {
|
|
7
|
+
const kept = [];
|
|
8
|
+
let fence = null;
|
|
9
|
+
for (const line of content.split('\n')) {
|
|
10
|
+
const fenceMatch = /^[ \t]{0,3}(`{3,}|~{3,})/.exec(line);
|
|
11
|
+
if (fenceMatch?.[1]) {
|
|
12
|
+
const marker = fenceMatch[1][0] ?? '`';
|
|
13
|
+
if (fence === null) {
|
|
14
|
+
fence = { marker, length: fenceMatch[1].length };
|
|
15
|
+
}
|
|
16
|
+
else if (fence.marker === marker && fenceMatch[1].length >= fence.length) {
|
|
17
|
+
fence = null;
|
|
18
|
+
}
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (fence === null) {
|
|
22
|
+
kept.push(line);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return kept.join('\n');
|
|
26
|
+
}
|
|
27
|
+
const SLASH_PATH_BULLET_RE = /^-\s+`?((?:[\w.-]+\/)+[\w-][\w.-]*\.[a-zA-Z][a-zA-Z0-9]*)`?(?=[\s`]|$)/;
|
|
28
|
+
const BARE_FILE_BULLET_RE = /^-\s+`?([\w-][\w.-]*\.[a-zA-Z][a-zA-Z0-9]*)`?\s*$/;
|
|
5
29
|
function extractPathsFromSection(sectionText) {
|
|
6
30
|
const paths = [];
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
.replace(/^-\s+`?/, '')
|
|
12
|
-
.replace(/`.*$/, '')
|
|
13
|
-
.trim();
|
|
14
|
-
if (match) {
|
|
15
|
-
paths.push(match);
|
|
31
|
+
for (const line of sectionText.split('\n')) {
|
|
32
|
+
const candidate = SLASH_PATH_BULLET_RE.exec(line)?.[1] ?? BARE_FILE_BULLET_RE.exec(line)?.[1];
|
|
33
|
+
if (candidate !== undefined && !candidate.split('/').includes('..')) {
|
|
34
|
+
paths.push(candidate);
|
|
16
35
|
}
|
|
17
36
|
}
|
|
18
37
|
return paths;
|
|
19
38
|
}
|
|
20
39
|
function parseSectionedFileLists(body) {
|
|
21
|
-
const
|
|
22
|
-
|
|
40
|
+
const filesRange = findMarkdownSectionRange(body, 'Files') ??
|
|
41
|
+
findMarkdownSectionRange(body, 'Files likely to change');
|
|
42
|
+
const scopedBody = stripFencedBlocks(filesRange ? body.slice(filesRange.contentStart, filesRange.end) : body);
|
|
23
43
|
const createSection = /###\s+Create[\s\S]*?(?=\n###|\n##\s|$)/.exec(scopedBody);
|
|
24
44
|
const modifySection = /###\s+Modify[\s\S]*?(?=\n###|\n##\s|$)/.exec(scopedBody);
|
|
25
45
|
const testSection = /###\s+Test[\s\S]*?(?=\n###|\n##\s|$)/.exec(scopedBody);
|
|
@@ -71,7 +91,9 @@ export async function extractFilesFromSpecBody(specBody, projectPath) {
|
|
|
71
91
|
(structured.create.length > 0 || structured.modify.length > 0 || structured.test.length > 0)) {
|
|
72
92
|
return structured;
|
|
73
93
|
}
|
|
74
|
-
const allPaths = [
|
|
94
|
+
const allPaths = [
|
|
95
|
+
...new Set(Array.from(stripFencedBlocks(specBody).matchAll(FILE_PATH_RE), (m) => m[0])),
|
|
96
|
+
];
|
|
75
97
|
if (allPaths.length === 0) {
|
|
76
98
|
return null;
|
|
77
99
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
import type { UpdateStatusInput, ToolResult, Actuals, ReconciliationInvocationContext } from '../../types/index.js';
|
|
2
|
+
import type { UpdateStatusInput, ToolResult, Actuals, Spec, ReconciliationInvocationContext } from '../../types/index.js';
|
|
3
|
+
import { type GapScore } from '../../engine/code-scanner/index.js';
|
|
3
4
|
type LifecycleAuthorityRoute = {
|
|
4
5
|
route: 'ordinary';
|
|
5
6
|
} | {
|
|
@@ -9,6 +10,7 @@ type LifecycleAuthorityRoute = {
|
|
|
9
10
|
result: ToolResult;
|
|
10
11
|
};
|
|
11
12
|
/** Select the lifecycle path before any transition, artifact, receipt, or log mutation. */
|
|
13
|
+
export declare function runOwnershipBoundedCodeReality(spec: Spec, projectPath: string): Promise<GapScore>;
|
|
12
14
|
export declare function classifyLifecycleAuthority(input: UpdateStatusInput, context: ReconciliationInvocationContext, options?: {
|
|
13
15
|
requireDoneDigest?: boolean;
|
|
14
16
|
}): LifecycleAuthorityRoute;
|
|
@@ -28,6 +28,7 @@ import { recordForceUsage } from '../../storage/force-analytics-store.js';
|
|
|
28
28
|
import { maybeSafePushOnDone, queuePostCommitTasks, runCascadeForResponse, } from './side-effects.js';
|
|
29
29
|
import { formatKeyValue } from '../output-formatter.js';
|
|
30
30
|
import { checkCodeReality } from '../../engine/code-scanner/index.js';
|
|
31
|
+
import { extractFilesFromSpecBody } from '../../engine/spec-format/technical-md-populator.js';
|
|
31
32
|
import { isAbsolute, join, resolve } from 'node:path';
|
|
32
33
|
import { readSpecContent } from '../../engine/spec-reader.js';
|
|
33
34
|
import { trackCost } from '../../engine/cost-tracking/operation-tracker.js';
|
|
@@ -51,6 +52,20 @@ function lifecycleAuthorityError(code, message, fixHint) {
|
|
|
51
52
|
};
|
|
52
53
|
}
|
|
53
54
|
/** Select the lifecycle path before any transition, artifact, receipt, or log mutation. */
|
|
55
|
+
export async function runOwnershipBoundedCodeReality(spec, projectPath) {
|
|
56
|
+
const specPath = isAbsolute(spec.specPath) ? spec.specPath : join(projectPath, spec.specPath);
|
|
57
|
+
const specBody = await readSpecContent(specPath);
|
|
58
|
+
const ownership = specBody === null ? null : await extractFilesFromSpecBody(specBody, projectPath);
|
|
59
|
+
const ownedPaths = ownership === null
|
|
60
|
+
? []
|
|
61
|
+
: [
|
|
62
|
+
...new Set([...ownership.create, ...ownership.modify, ...ownership.test].map((e) => e.path)),
|
|
63
|
+
];
|
|
64
|
+
if (ownedPaths.length === 0) {
|
|
65
|
+
reportClassifiedDegradation('CODE_REALITY_OWNERSHIP_MISSING', new Error(`spec ${spec.id} declares no canonical owned paths`));
|
|
66
|
+
}
|
|
67
|
+
return checkCodeReality(projectPath, spec.title, ownedPaths);
|
|
68
|
+
}
|
|
54
69
|
export function classifyLifecycleAuthority(input, context, options = {}) {
|
|
55
70
|
const hasRequestId = input.reconciliationRequestId !== undefined;
|
|
56
71
|
const hasTransitionId = input.expectedImplementingTransitionId !== undefined;
|
|
@@ -1052,7 +1067,7 @@ export async function handleUpdateStatus(params, server) {
|
|
|
1052
1067
|
const [codeRealityResult, doneGatesResult] = await Promise.all([
|
|
1053
1068
|
// Code reality: only relevant for 'implementing'
|
|
1054
1069
|
newStatus === 'implementing' && !reverseTransition && effectiveGatePath
|
|
1055
|
-
?
|
|
1070
|
+
? runOwnershipBoundedCodeReality(spec, effectiveGatePath).catch((error) => {
|
|
1056
1071
|
// reliability-optional: CODE_REALITY_ENRICHMENT — downstream evidence gates remain binding
|
|
1057
1072
|
reportClassifiedDegradation('CODE_REALITY_ENRICHMENT', error);
|
|
1058
1073
|
return null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planu/cli",
|
|
3
|
-
"version": "5.3.
|
|
3
|
+
"version": "5.3.9",
|
|
4
4
|
"description": "Planu — MCP Server for Spec Driven Development with native Rust acceleration for hot paths. Cross-platform (Linux/macOS/Windows, x64/arm64, glibc/musl).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -35,14 +35,14 @@
|
|
|
35
35
|
"packageName": "@planu/core"
|
|
36
36
|
},
|
|
37
37
|
"optionalDependencies": {
|
|
38
|
-
"@planu/core-darwin-arm64": "5.3.
|
|
39
|
-
"@planu/core-darwin-x64": "5.3.
|
|
40
|
-
"@planu/core-linux-arm64-gnu": "5.3.
|
|
41
|
-
"@planu/core-linux-arm64-musl": "5.3.
|
|
42
|
-
"@planu/core-linux-x64-gnu": "5.3.
|
|
43
|
-
"@planu/core-linux-x64-musl": "5.3.
|
|
44
|
-
"@planu/core-win32-arm64-msvc": "5.3.
|
|
45
|
-
"@planu/core-win32-x64-msvc": "5.3.
|
|
38
|
+
"@planu/core-darwin-arm64": "5.3.9",
|
|
39
|
+
"@planu/core-darwin-x64": "5.3.9",
|
|
40
|
+
"@planu/core-linux-arm64-gnu": "5.3.9",
|
|
41
|
+
"@planu/core-linux-arm64-musl": "5.3.9",
|
|
42
|
+
"@planu/core-linux-x64-gnu": "5.3.9",
|
|
43
|
+
"@planu/core-linux-x64-musl": "5.3.9",
|
|
44
|
+
"@planu/core-win32-arm64-msvc": "5.3.9",
|
|
45
|
+
"@planu/core-win32-x64-msvc": "5.3.9"
|
|
46
46
|
},
|
|
47
47
|
"engines": {
|
|
48
48
|
"node": ">=24.0.0"
|
package/planu-native.json
CHANGED
package/planu-plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "dev.planu.cli",
|
|
3
3
|
"displayName": "Planu — Spec Driven Development",
|
|
4
4
|
"description": "Manage software specs, estimations, and autonomous SDD workflows. Language-agnostic MCP server for Claude Code.",
|
|
5
|
-
"version": "5.3.
|
|
5
|
+
"version": "5.3.9",
|
|
6
6
|
"icon": "assets/plugin/icon.svg",
|
|
7
7
|
"command": ["npx", "@planu/cli@latest"],
|
|
8
8
|
"packageName": "@planu/cli",
|