@planu/cli 5.3.16 → 5.3.18
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 +21 -0
- package/dist/engine/evidence-gates/evidence-autofill.d.ts +5 -0
- package/dist/engine/evidence-gates/evidence-autofill.js +51 -8
- package/dist/engine/evidence-index/done-drift.d.ts +1 -0
- package/dist/engine/evidence-index/done-drift.js +32 -16
- 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/tools/challenge-spec/scenarios-data.js +15 -2
- package/dist/tools/update-status/evidence-gate.js +6 -1
- package/dist/tools/update-status/index.js +2 -1
- package/dist/types/evidence-autofill.d.ts +2 -0
- package/dist/types/plugin-configs.d.ts +0 -14
- package/package.json +9 -9
- package/planu-native.json +1 -1
- package/planu-plugin.json +1 -1
- package/dist/config/challenge-scenarios.json +0 -114
- package/dist/engine/challenge-scenarios-loader.d.ts +0 -46
- package/dist/engine/challenge-scenarios-loader.js +0 -83
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
## [5.3.18] - 2026-08-11
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
- fix(spec-1476): phrase-bind data-consistency scenario signals and drop dead catalog
|
|
5
|
+
|
|
6
|
+
### Chores
|
|
7
|
+
- chore(spec-1476): record done transition with validation and review evidence
|
|
8
|
+
- chore(spec-1476): approve spec with arbitrated dual-review evidence and start implementing
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## [5.3.17] - 2026-08-11
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
- fix(spec-1487): normalize spec paths in toRepoRelativePath per implementation-review arbitration
|
|
15
|
+
- fix(spec-1487): exclude Planu bookkeeping paths from traceability autofill and done drift gate
|
|
16
|
+
|
|
17
|
+
### Chores
|
|
18
|
+
- chore(specs): record SPEC-1487 done transition
|
|
19
|
+
- chore(spec-1487): record implementation-review round and approved scope amendment
|
|
20
|
+
|
|
21
|
+
|
|
1
22
|
## [5.3.16] - 2026-08-11
|
|
2
23
|
|
|
3
24
|
### Bug Fixes
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { AutofillTraceabilityMatrixArgs, AutofillTraceabilityMatrixResult } from '../../types/evidence-autofill.js';
|
|
2
|
+
/** Exact Planu lifecycle files every spec branch mutates; never counted as implementation drift. */
|
|
3
|
+
export declare const PLANU_BOOKKEEPING_FILES: readonly ['planu/context.md', 'planu/session-context.md', 'planu/session.json', 'planu/status.json', 'planu/releases/pending.json', 'planu/conventions.json'];
|
|
4
|
+
/** Normalizes a spec.md path (absolute or already repo-relative) to a repo-relative,
|
|
5
|
+
* forward-slash path so it can be compared against `git diff` output. */
|
|
6
|
+
export declare function toRepoRelativePath(specPath: string, projectPath?: string): string;
|
|
2
7
|
/**
|
|
3
8
|
* Generate `traceability-matrix.json` in the handoff evidence store when it does
|
|
4
9
|
* not already exist. Never overwrites an existing file — if one is present this
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
// legacy harnesses, etc.).
|
|
20
20
|
import { execFile } from 'node:child_process';
|
|
21
21
|
import { existsSync } from 'node:fs';
|
|
22
|
-
import { isAbsolute, join, resolve } from 'node:path';
|
|
22
|
+
import { isAbsolute, join, relative, resolve } from 'node:path';
|
|
23
23
|
import { promisify } from 'node:util';
|
|
24
24
|
import { extractAcceptanceCriteriaTexts } from '../spec-format/acceptance-criteria.js';
|
|
25
25
|
import { parseFrontmatterScenarios } from '../validator/spec-compliance-runner.js';
|
|
@@ -35,7 +35,28 @@ const defaultExec = async (command, args, options) => {
|
|
|
35
35
|
const { stdout } = await execFileAsync(command, args, { cwd: options.cwd, encoding: 'utf-8' });
|
|
36
36
|
return stdout;
|
|
37
37
|
};
|
|
38
|
-
/**
|
|
38
|
+
/** Exact Planu lifecycle files every spec branch mutates; never counted as implementation drift. */
|
|
39
|
+
export const PLANU_BOOKKEEPING_FILES = [
|
|
40
|
+
'planu/context.md',
|
|
41
|
+
'planu/session-context.md',
|
|
42
|
+
'planu/session.json',
|
|
43
|
+
'planu/status.json',
|
|
44
|
+
'planu/releases/pending.json',
|
|
45
|
+
'planu/conventions.json',
|
|
46
|
+
];
|
|
47
|
+
const OTHER_SPEC_MD_PATTERN = /^planu\/specs\/[^/]+\/spec\.md$/;
|
|
48
|
+
/** Normalizes a spec.md path (absolute or already repo-relative) to a repo-relative,
|
|
49
|
+
* forward-slash path so it can be compared against `git diff` output. */
|
|
50
|
+
export function toRepoRelativePath(specPath, projectPath) {
|
|
51
|
+
if (isAbsolute(specPath) && !projectPath) {
|
|
52
|
+
const normalized = specPath.replace(/\\/g, '/');
|
|
53
|
+
const specsIndex = normalized.lastIndexOf('planu/specs/');
|
|
54
|
+
return specsIndex === -1 ? normalized : normalized.slice(specsIndex);
|
|
55
|
+
}
|
|
56
|
+
const relativePath = isAbsolute(specPath) && projectPath ? relative(projectPath, specPath) : specPath;
|
|
57
|
+
return relativePath.replace(/\\/g, '/').replace(/^(\.\/)+/, '');
|
|
58
|
+
}
|
|
59
|
+
/** Best-effort `git diff --name-status <mergeBase>...HEAD`; never throws. */
|
|
39
60
|
async function computeChangedFilesFromGit(projectPath, exec, baseBranch) {
|
|
40
61
|
try {
|
|
41
62
|
const mergeBaseOut = await exec('git', ['merge-base', 'HEAD', baseBranch], {
|
|
@@ -45,13 +66,20 @@ async function computeChangedFilesFromGit(projectPath, exec, baseBranch) {
|
|
|
45
66
|
if (!mergeBase) {
|
|
46
67
|
return [];
|
|
47
68
|
}
|
|
48
|
-
const diffOut = await exec('git', ['diff', '--name-
|
|
69
|
+
const diffOut = await exec('git', ['diff', '--name-status', `${mergeBase}...HEAD`], {
|
|
49
70
|
cwd: projectPath,
|
|
50
71
|
});
|
|
51
72
|
return diffOut
|
|
52
73
|
.split('\n')
|
|
53
74
|
.map((line) => line.trim())
|
|
54
|
-
.filter((line) => line.length > 0)
|
|
75
|
+
.filter((line) => line.length > 0)
|
|
76
|
+
.map((line) => {
|
|
77
|
+
const fields = line.split('\t');
|
|
78
|
+
const path = fields[fields.length - 1] ?? '';
|
|
79
|
+
const status = (fields[0] ?? '').startsWith('A') ? 'Added' : 'Other';
|
|
80
|
+
return { status, path };
|
|
81
|
+
})
|
|
82
|
+
.filter((entry) => entry.path.length > 0);
|
|
55
83
|
}
|
|
56
84
|
catch (error) {
|
|
57
85
|
/* reliability-optional: EVIDENCE_AUTOFILL_GIT_DIFF — falls back to ## Files ownership */
|
|
@@ -59,6 +87,18 @@ async function computeChangedFilesFromGit(projectPath, exec, baseBranch) {
|
|
|
59
87
|
return [];
|
|
60
88
|
}
|
|
61
89
|
}
|
|
90
|
+
/** Drops Planu bookkeeping paths, this spec's own spec.md, and newly Added other-spec
|
|
91
|
+
* spec.md files — the diff still surfaces unowned src/ paths and Modified other-spec
|
|
92
|
+
* contracts so the done drift gate can flag genuine scope drift. */
|
|
93
|
+
function excludeBookkeepingChanges(entries, ownSpecMdPath) {
|
|
94
|
+
const bookkeeping = new Set(PLANU_BOOKKEEPING_FILES);
|
|
95
|
+
const kept = entries
|
|
96
|
+
.filter((entry) => !bookkeeping.has(entry.path))
|
|
97
|
+
.filter((entry) => entry.path !== ownSpecMdPath)
|
|
98
|
+
.filter((entry) => !(entry.status === 'Added' && OTHER_SPEC_MD_PATTERN.test(entry.path)))
|
|
99
|
+
.map((entry) => entry.path);
|
|
100
|
+
return [...new Set(kept)];
|
|
101
|
+
}
|
|
62
102
|
function filterExistingRepoFiles(projectPath, paths) {
|
|
63
103
|
return paths.filter((path) => {
|
|
64
104
|
if (isAbsolute(path)) {
|
|
@@ -111,15 +151,18 @@ export async function autofillTraceabilityMatrix(args) {
|
|
|
111
151
|
const scenarios = parseFrontmatterScenarios(args.specBody);
|
|
112
152
|
const exec = args.exec ?? defaultExec;
|
|
113
153
|
const baseBranch = args.baseBranch ?? 'main';
|
|
114
|
-
const
|
|
154
|
+
const gitEntries = args.projectPath
|
|
115
155
|
? await computeChangedFilesFromGit(args.projectPath, exec, baseBranch)
|
|
116
156
|
: [];
|
|
157
|
+
const gitChangedFiles = excludeBookkeepingChanges(gitEntries, args.ownSpecMdPath);
|
|
117
158
|
const ownership = extractCanonicalFileOwnership(args.specBody);
|
|
118
159
|
const ownershipFiles = [...ownership.toCreate, ...ownership.toModify, ...ownership.toTest];
|
|
119
160
|
const rawChangedFiles = gitChangedFiles.length > 0 ? gitChangedFiles : ownershipFiles;
|
|
120
|
-
const changedFiles =
|
|
121
|
-
|
|
122
|
-
|
|
161
|
+
const changedFiles = [
|
|
162
|
+
...new Set(args.projectPath
|
|
163
|
+
? filterExistingRepoFiles(args.projectPath, rawChangedFiles)
|
|
164
|
+
: rawChangedFiles),
|
|
165
|
+
];
|
|
123
166
|
const { validationEvidence, reviewerEvidence } = await readValidationReportSummary(args.projectId, args.specId);
|
|
124
167
|
const rows = criteria.map((acceptanceCriterion, index) => {
|
|
125
168
|
const testPaths = scenarios[index]?.tests?.map((test) => test.path) ?? [];
|
|
@@ -2,5 +2,6 @@ import type { EvidenceGateIssue, SpecEvidenceIndex } from '../../types/index.js'
|
|
|
2
2
|
export declare function checkDoneDriftContract(args: {
|
|
3
3
|
index: SpecEvidenceIndex;
|
|
4
4
|
approvedScopePaths: readonly string[];
|
|
5
|
+
ownSpecMdPath?: string;
|
|
5
6
|
}): EvidenceGateIssue[];
|
|
6
7
|
//# sourceMappingURL=done-drift.d.ts.map
|
|
@@ -1,8 +1,38 @@
|
|
|
1
1
|
import { normalizeChangedFilePath } from '../handoff-packager.js';
|
|
2
|
+
import { PLANU_BOOKKEEPING_FILES } from '../evidence-gates/evidence-autofill.js';
|
|
2
3
|
function normalizedChangedFile(value) {
|
|
3
4
|
const normalized = normalizeChangedFilePath(value);
|
|
4
5
|
return normalized.status === 'valid' ? normalized.path : null;
|
|
5
6
|
}
|
|
7
|
+
function buildNeverDriftPaths(ownSpecMdPath) {
|
|
8
|
+
const neverDriftPaths = new Set(PLANU_BOOKKEEPING_FILES);
|
|
9
|
+
const normalizedOwnSpecMdPath = ownSpecMdPath ? normalizedChangedFile(ownSpecMdPath) : null;
|
|
10
|
+
if (normalizedOwnSpecMdPath) {
|
|
11
|
+
neverDriftPaths.add(normalizedOwnSpecMdPath);
|
|
12
|
+
}
|
|
13
|
+
return neverDriftPaths;
|
|
14
|
+
}
|
|
15
|
+
function findUnapprovedChangedFiles(index, approved, neverDriftPaths) {
|
|
16
|
+
return index.criteria.flatMap((entry) => {
|
|
17
|
+
const hasScopeAmendment = entry.evidence.some((record) => record.kind === 'reviewer' && /scope amendment|approved scope/i.test(record.value));
|
|
18
|
+
if (hasScopeAmendment) {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
return entry.evidence.flatMap((record) => {
|
|
22
|
+
if (record.kind !== 'changed-file' ||
|
|
23
|
+
(record.status !== 'valid' && record.status !== 'missing')) {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
const normalized = normalizedChangedFile(record.value);
|
|
27
|
+
if (normalized && neverDriftPaths.has(normalized)) {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
return normalized && approved.has(normalized)
|
|
31
|
+
? []
|
|
32
|
+
: [`${entry.criterion}: ${normalized ?? 'invalid changed-file path'}`];
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
6
36
|
export function checkDoneDriftContract(args) {
|
|
7
37
|
const issues = [];
|
|
8
38
|
const uncovered = args.index.criteria.filter((entry) => {
|
|
@@ -39,22 +69,8 @@ export function checkDoneDriftContract(args) {
|
|
|
39
69
|
return normalized ? [normalized] : [];
|
|
40
70
|
});
|
|
41
71
|
const approved = new Set(approvedScopePaths);
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
if (hasScopeAmendment) {
|
|
45
|
-
return [];
|
|
46
|
-
}
|
|
47
|
-
return entry.evidence.flatMap((record) => {
|
|
48
|
-
if (record.kind !== 'changed-file' ||
|
|
49
|
-
(record.status !== 'valid' && record.status !== 'missing')) {
|
|
50
|
-
return [];
|
|
51
|
-
}
|
|
52
|
-
const normalized = normalizedChangedFile(record.value);
|
|
53
|
-
return normalized && approved.has(normalized)
|
|
54
|
-
? []
|
|
55
|
-
: [`${entry.criterion}: ${normalized ?? 'invalid changed-file path'}`];
|
|
56
|
-
});
|
|
57
|
-
});
|
|
72
|
+
const neverDriftPaths = buildNeverDriftPaths(args.ownSpecMdPath);
|
|
73
|
+
const unapproved = findUnapprovedChangedFiles(args.index, approved, neverDriftPaths);
|
|
58
74
|
if (unapproved.length > 0) {
|
|
59
75
|
const approvedHint = approvedScopePaths.length > 0
|
|
60
76
|
? ` Approved canonical paths: ${approvedScopePaths.join(', ')}.`
|
|
@@ -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.18",
|
|
4
|
+
"engineVersion": "5.3.18",
|
|
5
|
+
"buildId": "1-5.3.18-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": "5fed530a8afc4fe8dca40839db0eae5d27430c21291c7b4152204a67f69a0f07",
|
|
21
21
|
"sbom": {
|
|
22
22
|
"format": "CycloneDX-1.5",
|
|
23
23
|
"path": "planu-core.darwin-arm64.node.sbom.json",
|
|
24
|
-
"sha256": "
|
|
24
|
+
"sha256": "1667d84a334ea1d0a77aaa2a52fe09e4bddabae03012da6b8a60c36719a50eaf"
|
|
25
25
|
},
|
|
26
26
|
"provenance": {
|
|
27
27
|
"builder": "scripts/build-rust-local.sh",
|
|
28
|
-
"sourceCommit": "
|
|
28
|
+
"sourceCommit": "3c1b6c73402a7d249e53f8805fe8429de38e43ac",
|
|
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": "CK7fkEl65ZldoIdkXqxFNABEHNghZ2zt/7aIcmmwP2LiwhuYvYL8H4OHFM6aeojGqpgXoia4MXuC12WcACR3Dw=="
|
|
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.18",
|
|
8
8
|
"type": "library",
|
|
9
9
|
"name": "planu-core",
|
|
10
|
-
"version": "5.3.
|
|
10
|
+
"version": "5.3.18",
|
|
11
11
|
"hashes": [
|
|
12
12
|
{
|
|
13
13
|
"alg": "SHA-256",
|
|
14
|
-
"content": "
|
|
14
|
+
"content": "5fed530a8afc4fe8dca40839db0eae5d27430c21291c7b4152204a67f69a0f07"
|
|
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.18",
|
|
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.18",
|
|
4
|
+
"engineVersion": "5.3.18",
|
|
5
|
+
"buildId": "1-5.3.18-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": "8287182c1b0be484146f92ee90db5423295e1bd00b8384660de534dc6e29c49d",
|
|
21
21
|
"sbom": {
|
|
22
22
|
"format": "CycloneDX-1.5",
|
|
23
23
|
"path": "planu-core.darwin-x64.node.sbom.json",
|
|
24
|
-
"sha256": "
|
|
24
|
+
"sha256": "9514dae23ab932c585e3fec8df947fc144d8f815b2680f2be34291ce97a07f07"
|
|
25
25
|
},
|
|
26
26
|
"provenance": {
|
|
27
27
|
"builder": "scripts/build-rust-local.sh",
|
|
28
|
-
"sourceCommit": "
|
|
28
|
+
"sourceCommit": "3c1b6c73402a7d249e53f8805fe8429de38e43ac",
|
|
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": "jxjKFUe/Z6Rnmk97m9rMwg8b0I7zQwOWmovYV50P0M0EAjQkaId91vUI76QQaY4DM1NeUgsnqvzj4UtUQrdZAQ=="
|
|
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.18",
|
|
8
8
|
"type": "library",
|
|
9
9
|
"name": "planu-core",
|
|
10
|
-
"version": "5.3.
|
|
10
|
+
"version": "5.3.18",
|
|
11
11
|
"hashes": [
|
|
12
12
|
{
|
|
13
13
|
"alg": "SHA-256",
|
|
14
|
-
"content": "
|
|
14
|
+
"content": "8287182c1b0be484146f92ee90db5423295e1bd00b8384660de534dc6e29c49d"
|
|
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.18",
|
|
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.18",
|
|
4
|
+
"engineVersion": "5.3.18",
|
|
5
|
+
"buildId": "1-5.3.18-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": "2fe96f2baf1f4b811d038cb004bdb59436f6bb18c38cbc0936adf2f3d776f1e0",
|
|
20
20
|
"sbom": {
|
|
21
21
|
"format": "CycloneDX-1.5",
|
|
22
22
|
"path": "planu-core.linux-arm64-gnu.node.sbom.json",
|
|
23
|
-
"sha256": "
|
|
23
|
+
"sha256": "aaa7a6dc91c4720a456807fc76edc5293e01bb328d4830866500b197661b00c3"
|
|
24
24
|
},
|
|
25
25
|
"provenance": {
|
|
26
26
|
"builder": "scripts/build-rust-local.sh",
|
|
27
|
-
"sourceCommit": "
|
|
27
|
+
"sourceCommit": "3c1b6c73402a7d249e53f8805fe8429de38e43ac",
|
|
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": "OZu14HADvXX9A0jSQYjeOqU0dI4MczkRXSHbUfGrKKOY/pLLJkfBDsnsLbs5XgSp/V1oSQQDQ0rsDOCRl2WhBg=="
|
|
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.18",
|
|
8
8
|
"type": "library",
|
|
9
9
|
"name": "planu-core",
|
|
10
|
-
"version": "5.3.
|
|
10
|
+
"version": "5.3.18",
|
|
11
11
|
"hashes": [
|
|
12
12
|
{
|
|
13
13
|
"alg": "SHA-256",
|
|
14
|
-
"content": "
|
|
14
|
+
"content": "2fe96f2baf1f4b811d038cb004bdb59436f6bb18c38cbc0936adf2f3d776f1e0"
|
|
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.18",
|
|
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.18",
|
|
4
|
+
"engineVersion": "5.3.18",
|
|
5
|
+
"buildId": "1-5.3.18-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": "5749d44caef4716e9def75bb6d9bf630d6a14bbf2f1630d483036b9a0f7fb244",
|
|
20
20
|
"sbom": {
|
|
21
21
|
"format": "CycloneDX-1.5",
|
|
22
22
|
"path": "planu-core.linux-arm64-musl.node.sbom.json",
|
|
23
|
-
"sha256": "
|
|
23
|
+
"sha256": "206a3e0d16affa390afee3880296b9822d98f31dbd9f2d02e560b14419ecb41c"
|
|
24
24
|
},
|
|
25
25
|
"provenance": {
|
|
26
26
|
"builder": "scripts/build-rust-local.sh",
|
|
27
|
-
"sourceCommit": "
|
|
27
|
+
"sourceCommit": "3c1b6c73402a7d249e53f8805fe8429de38e43ac",
|
|
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": "cJ2vBlGhEl/fnE+iYdmGff9ghJujeqt77VGbZZJeQWfyB3YcZdf298M9REEQfr7QgQeExyjJHE3l9AExHo3aAg=="
|
|
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.18",
|
|
8
8
|
"type": "library",
|
|
9
9
|
"name": "planu-core",
|
|
10
|
-
"version": "5.3.
|
|
10
|
+
"version": "5.3.18",
|
|
11
11
|
"hashes": [
|
|
12
12
|
{
|
|
13
13
|
"alg": "SHA-256",
|
|
14
|
-
"content": "
|
|
14
|
+
"content": "5749d44caef4716e9def75bb6d9bf630d6a14bbf2f1630d483036b9a0f7fb244"
|
|
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.18",
|
|
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.18",
|
|
4
|
+
"engineVersion": "5.3.18",
|
|
5
|
+
"buildId": "1-5.3.18-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": "ddcf0b909005c6dd5b5833ca2380979f50b11a081b883e449ce044476ef4da90",
|
|
20
20
|
"sbom": {
|
|
21
21
|
"format": "CycloneDX-1.5",
|
|
22
22
|
"path": "planu-core.linux-x64-gnu.node.sbom.json",
|
|
23
|
-
"sha256": "
|
|
23
|
+
"sha256": "26c6d0f0dd9558bd863fb3bcdc092cb8821ae6635495503d1ca513595a830ed6"
|
|
24
24
|
},
|
|
25
25
|
"provenance": {
|
|
26
26
|
"builder": "scripts/build-rust-local.sh",
|
|
27
|
-
"sourceCommit": "
|
|
27
|
+
"sourceCommit": "3c1b6c73402a7d249e53f8805fe8429de38e43ac",
|
|
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": "DHqxCc8X0fG9/Obugix+X+KLWWAxiVaw//r9ba1EgVA+kaE2C4nQbFGp+qcYa+XDcjmfHRJudQrf0dTwXI4QCg=="
|
|
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.18",
|
|
8
8
|
"type": "library",
|
|
9
9
|
"name": "planu-core",
|
|
10
|
-
"version": "5.3.
|
|
10
|
+
"version": "5.3.18",
|
|
11
11
|
"hashes": [
|
|
12
12
|
{
|
|
13
13
|
"alg": "SHA-256",
|
|
14
|
-
"content": "
|
|
14
|
+
"content": "ddcf0b909005c6dd5b5833ca2380979f50b11a081b883e449ce044476ef4da90"
|
|
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.18",
|
|
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.18",
|
|
4
|
+
"engineVersion": "5.3.18",
|
|
5
|
+
"buildId": "1-5.3.18-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": "7d251de39b960c7bcdbfd2770c7a778bdb8fe532a45def6206a5ac4ba349bf89",
|
|
20
20
|
"sbom": {
|
|
21
21
|
"format": "CycloneDX-1.5",
|
|
22
22
|
"path": "planu-core.linux-x64-musl.node.sbom.json",
|
|
23
|
-
"sha256": "
|
|
23
|
+
"sha256": "c826c2dabe78e17d3e83788eb69548ff0f06a0c29c1a95d215956562fd63e0ab"
|
|
24
24
|
},
|
|
25
25
|
"provenance": {
|
|
26
26
|
"builder": "scripts/build-rust-local.sh",
|
|
27
|
-
"sourceCommit": "
|
|
27
|
+
"sourceCommit": "3c1b6c73402a7d249e53f8805fe8429de38e43ac",
|
|
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": "W8mvPSxXSz7L0Ce0N+xQeeqMy0Nx87dcW53m1QmdR7dqSo2S5MsB26XVHn/Yn/QmD4bP2vjEdG1RAYVgh4XgCQ=="
|
|
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.18",
|
|
8
8
|
"type": "library",
|
|
9
9
|
"name": "planu-core",
|
|
10
|
-
"version": "5.3.
|
|
10
|
+
"version": "5.3.18",
|
|
11
11
|
"hashes": [
|
|
12
12
|
{
|
|
13
13
|
"alg": "SHA-256",
|
|
14
|
-
"content": "
|
|
14
|
+
"content": "7d251de39b960c7bcdbfd2770c7a778bdb8fe532a45def6206a5ac4ba349bf89"
|
|
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.18",
|
|
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.18",
|
|
4
|
+
"engineVersion": "5.3.18",
|
|
5
|
+
"buildId": "1-5.3.18-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": "43386818ebe7d5acac484fa8e4a38a8508b7b2baa17b421d1720a5133ae25022",
|
|
20
20
|
"sbom": {
|
|
21
21
|
"format": "CycloneDX-1.5",
|
|
22
22
|
"path": "planu-core.win32-arm64-msvc.node.sbom.json",
|
|
23
|
-
"sha256": "
|
|
23
|
+
"sha256": "b4571ec45d947374617a7f4315c1be522111e9ad49f63023febdef3d4c6e3fb1"
|
|
24
24
|
},
|
|
25
25
|
"provenance": {
|
|
26
26
|
"builder": "scripts/build-rust-local.sh",
|
|
27
|
-
"sourceCommit": "
|
|
27
|
+
"sourceCommit": "3c1b6c73402a7d249e53f8805fe8429de38e43ac",
|
|
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": "kWkreQpknVVatNtjxmRVdggvQnemK2iIIrcHwZqwISsdPfmnXLHv+X0LmJlpOs1rqXh85FIAJmm2Z6Dz+9YkAw=="
|
|
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.18",
|
|
8
8
|
"type": "library",
|
|
9
9
|
"name": "planu-core",
|
|
10
|
-
"version": "5.3.
|
|
10
|
+
"version": "5.3.18",
|
|
11
11
|
"hashes": [
|
|
12
12
|
{
|
|
13
13
|
"alg": "SHA-256",
|
|
14
|
-
"content": "
|
|
14
|
+
"content": "43386818ebe7d5acac484fa8e4a38a8508b7b2baa17b421d1720a5133ae25022"
|
|
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.18",
|
|
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.18",
|
|
4
|
+
"engineVersion": "5.3.18",
|
|
5
|
+
"buildId": "1-5.3.18-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": "017329ba941530655f52d8bfda224dc64da19fd998af72a4047e4f8837116b81",
|
|
20
20
|
"sbom": {
|
|
21
21
|
"format": "CycloneDX-1.5",
|
|
22
22
|
"path": "planu-core.win32-x64-msvc.node.sbom.json",
|
|
23
|
-
"sha256": "
|
|
23
|
+
"sha256": "5f6b8d9d3df9dac089f07f3e96c6e8c3d456db7f23fba6f051bea23bdb463e20"
|
|
24
24
|
},
|
|
25
25
|
"provenance": {
|
|
26
26
|
"builder": "scripts/build-rust-local.sh",
|
|
27
|
-
"sourceCommit": "
|
|
27
|
+
"sourceCommit": "3c1b6c73402a7d249e53f8805fe8429de38e43ac",
|
|
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": "n05uJoOniOELxpoTVp25r7wDI1U+Z2hu6VI9mkxXLvBFGcPhWeoGJ1W+igcNkEiOA26Ihn88fGsT04ALFHntCQ=="
|
|
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.18",
|
|
8
8
|
"type": "library",
|
|
9
9
|
"name": "planu-core",
|
|
10
|
-
"version": "5.3.
|
|
10
|
+
"version": "5.3.18",
|
|
11
11
|
"hashes": [
|
|
12
12
|
{
|
|
13
13
|
"alg": "SHA-256",
|
|
14
|
-
"content": "
|
|
14
|
+
"content": "017329ba941530655f52d8bfda224dc64da19fd998af72a4047e4f8837116b81"
|
|
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.18",
|
|
1110
1110
|
"dependsOn": [
|
|
1111
1111
|
"pkg:cargo/core-foundation@0.10.1",
|
|
1112
1112
|
"pkg:cargo/hmac@0.12.1",
|
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
// tools/challenge-spec/scenarios-data.ts — Data consistency and partial write scenarios
|
|
2
2
|
import { contentMentions, hasAnyAffirmedMatch } from './scenarios-utils.js';
|
|
3
|
+
const GIT_CHECKOUT_PREFIX = '(?<!\\b(?:git|branch|worktree|main)\\s)';
|
|
3
4
|
const WRITE_SIGNALS = [
|
|
4
5
|
/\b(transaction|persist|database write|save record|create record|update record|delete record)\b/i,
|
|
5
|
-
/\
|
|
6
|
+
/\bsubmit\s+form\b/i,
|
|
7
|
+
/\bmulti-step\s+write\b/i,
|
|
8
|
+
/\bdata\s+mutation\b/i,
|
|
9
|
+
/\bplaces?\s+an\s+order\b/i,
|
|
10
|
+
new RegExp(`${GIT_CHECKOUT_PREFIX}\\bcheckout\\s+(?:flow|process|order|endpoint)\\b`, 'i'),
|
|
6
11
|
];
|
|
7
12
|
const CACHE_SIGNALS = [/\b(cache|cached|real-time|realtime|websocket|stale data)\b/i];
|
|
8
13
|
const DUPLICATE_OPERATION_SIGNALS = [
|
|
9
|
-
/\
|
|
14
|
+
/\bsubmit(?:s|ted|ting)?\s+(?:a\s+|the\s+)?form\b/i,
|
|
15
|
+
/\bform\s+submission\b/i,
|
|
16
|
+
/\bbutton\s+click\b/i,
|
|
17
|
+
/\bdouble[ -]?click\b/i,
|
|
18
|
+
/\buser\s+submits?\b/i,
|
|
19
|
+
/\b(?:order|submit|checkout|payment|purchase)\s+button\b/i,
|
|
20
|
+
/\bplaces?\s+an\s+order\b/i,
|
|
21
|
+
new RegExp(`${GIT_CHECKOUT_PREFIX}\\bcheckout\\s+(?:flow|page|process|endpoint|order)\\b`, 'i'),
|
|
22
|
+
/\bpayment\s+(?:flow|submission|mutation)\b/i,
|
|
10
23
|
/\bduplicate\s+(?:request|submission|operation|record)\b/i,
|
|
11
24
|
];
|
|
12
25
|
export function generateDataConsistencyScenarios(_spec, content, _knowledge) {
|
|
@@ -57,6 +57,7 @@ import { readEvidenceArtifacts } from '../../engine/evidence-gates/artifact-read
|
|
|
57
57
|
import { checkLifecycleEvidenceGate } from '../../engine/evidence-gates/lifecycle-gate.js';
|
|
58
58
|
import { buildSpecEvidenceIndex } from '../../engine/evidence-index/index-builder.js';
|
|
59
59
|
import { checkDoneDriftContract } from '../../engine/evidence-index/done-drift.js';
|
|
60
|
+
import { toRepoRelativePath } from '../../engine/evidence-gates/evidence-autofill.js';
|
|
60
61
|
import { parseGroundedTechnicalPaths } from '../../engine/spec-grounding/contract.js';
|
|
61
62
|
import { extractAcceptanceCriteriaTexts } from '../../engine/spec-format/acceptance-criteria.js';
|
|
62
63
|
import { formatKeyValue } from '../output-formatter.js';
|
|
@@ -168,7 +169,11 @@ export async function checkLifecycleEvidenceTransitionGate(args) {
|
|
|
168
169
|
message: `Approved canonical ownership is invalid: ${[...new Set(safeBlockers)].join(', ')}.`,
|
|
169
170
|
});
|
|
170
171
|
}
|
|
171
|
-
result.issues.push(...checkDoneDriftContract({
|
|
172
|
+
result.issues.push(...checkDoneDriftContract({
|
|
173
|
+
index,
|
|
174
|
+
approvedScopePaths,
|
|
175
|
+
ownSpecMdPath: toRepoRelativePath(args.spec.specPath, args.projectPath),
|
|
176
|
+
}));
|
|
172
177
|
}
|
|
173
178
|
if (result.issues.length === 0) {
|
|
174
179
|
return null;
|
|
@@ -17,7 +17,7 @@ import { withApprovalSpecLock } from '../../storage/approval-operation-lock.js';
|
|
|
17
17
|
import { isLocked, getLock } from '../../storage/spec-lock-store.js';
|
|
18
18
|
import { checkDoneGates, checkComplianceGate, checkApprovedFormatGate, checkSpecReviewGate, deriveDoneReviewDigest, } from './dod-gates.js';
|
|
19
19
|
import { checkLifecycleEvidenceTransitionGate } from './evidence-gate.js';
|
|
20
|
-
import { autofillTraceabilityMatrix } from '../../engine/evidence-gates/evidence-autofill.js';
|
|
20
|
+
import { autofillTraceabilityMatrix, toRepoRelativePath, } from '../../engine/evidence-gates/evidence-autofill.js';
|
|
21
21
|
import { buildStatusResponse, buildDryRunResponse } from './response-builder.js';
|
|
22
22
|
import { recordDoneMetrics, syncSpecFiles, tryReconcile, recordTerminalTransitionEvent, } from './file-sync.js';
|
|
23
23
|
import { appendEntry, getLastHash } from '../../storage/audit-trail-store.js';
|
|
@@ -165,6 +165,7 @@ async function runTraceabilityAutofillGate(args) {
|
|
|
165
165
|
specId: args.specId,
|
|
166
166
|
projectPath: args.projectPath,
|
|
167
167
|
specBody,
|
|
168
|
+
ownSpecMdPath: toRepoRelativePath(args.spec.specPath, args.projectPath),
|
|
168
169
|
});
|
|
169
170
|
if (!result.written) {
|
|
170
171
|
return null;
|
|
@@ -21,6 +21,8 @@ export interface AutofillTraceabilityMatrixArgs {
|
|
|
21
21
|
exec?: EvidenceAutofillExec;
|
|
22
22
|
/** Branch to diff against for changed-files detection. Defaults to `main`. */
|
|
23
23
|
baseBranch?: string;
|
|
24
|
+
/** Repo-relative path of this spec's own spec.md, excluded from changedFiles as lifecycle bookkeeping. */
|
|
25
|
+
ownSpecMdPath?: string;
|
|
24
26
|
}
|
|
25
27
|
export type AutofillTraceabilityMatrixResult = {
|
|
26
28
|
written: true;
|
|
@@ -5,20 +5,6 @@ export interface AcGapKeywordGroup {
|
|
|
5
5
|
language: string;
|
|
6
6
|
keywords: string[];
|
|
7
7
|
}
|
|
8
|
-
export interface ChallengeScenarioPattern {
|
|
9
|
-
id: string;
|
|
10
|
-
category: string;
|
|
11
|
-
triggerKeywords: string[];
|
|
12
|
-
scenario: string;
|
|
13
|
-
probability: 'low' | 'medium' | 'high';
|
|
14
|
-
impact: 'low' | 'medium' | 'high' | 'critical';
|
|
15
|
-
handlingKeywords: string[];
|
|
16
|
-
handlingFound: string;
|
|
17
|
-
handlingMissing: string;
|
|
18
|
-
requiredHandling: string;
|
|
19
|
-
dataConsistency: string;
|
|
20
|
-
userExperience: string;
|
|
21
|
-
}
|
|
22
8
|
export interface CodeQualityThreshold {
|
|
23
9
|
id: string;
|
|
24
10
|
language: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planu/cli",
|
|
3
|
-
"version": "5.3.
|
|
3
|
+
"version": "5.3.18",
|
|
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.18",
|
|
39
|
+
"@planu/core-darwin-x64": "5.3.18",
|
|
40
|
+
"@planu/core-linux-arm64-gnu": "5.3.18",
|
|
41
|
+
"@planu/core-linux-arm64-musl": "5.3.18",
|
|
42
|
+
"@planu/core-linux-x64-gnu": "5.3.18",
|
|
43
|
+
"@planu/core-linux-x64-musl": "5.3.18",
|
|
44
|
+
"@planu/core-win32-arm64-msvc": "5.3.18",
|
|
45
|
+
"@planu/core-win32-x64-msvc": "5.3.18"
|
|
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.18",
|
|
6
6
|
"icon": "assets/plugin/icon.svg",
|
|
7
7
|
"command": ["npx", "@planu/cli@latest"],
|
|
8
8
|
"packageName": "@planu/cli",
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
[
|
|
2
|
-
{
|
|
3
|
-
"id": "data-partial-write",
|
|
4
|
-
"category": "data-consistency",
|
|
5
|
-
"triggerKeywords": ["transaction", "update", "create", "modify", "save"],
|
|
6
|
-
"scenario": "Partial write: server crashes mid-transaction",
|
|
7
|
-
"probability": "low",
|
|
8
|
-
"impact": "critical",
|
|
9
|
-
"handlingKeywords": ["transaction", "atomic", "rollback"],
|
|
10
|
-
"handlingFound": "Transactions mentioned",
|
|
11
|
-
"handlingMissing": "Not addressed",
|
|
12
|
-
"requiredHandling": "Wrap multi-step writes in database transactions. Implement saga pattern for distributed operations.",
|
|
13
|
-
"dataConsistency": "ACID properties must be maintained. No orphaned records.",
|
|
14
|
-
"userExperience": "Transparent: user sees either success or clean failure with clear error message."
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
"id": "data-stale-cache",
|
|
18
|
-
"category": "data-consistency",
|
|
19
|
-
"triggerKeywords": ["cache", "real-time", "concurrent"],
|
|
20
|
-
"scenario": "Stale data served from cache after underlying data changes",
|
|
21
|
-
"probability": "high",
|
|
22
|
-
"impact": "medium",
|
|
23
|
-
"handlingKeywords": ["invalidat", "ttl", "websocket", "real-time"],
|
|
24
|
-
"handlingFound": "Some cache strategy mentioned",
|
|
25
|
-
"handlingMissing": "Not addressed",
|
|
26
|
-
"requiredHandling": "Implement cache invalidation on writes. Use TTL for time-sensitive data. Consider event-driven invalidation.",
|
|
27
|
-
"dataConsistency": "Define acceptable staleness window per data type. Document cache strategy.",
|
|
28
|
-
"userExperience": "Show \"last updated\" timestamp. Offer manual refresh option."
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
"id": "data-duplicate-submit",
|
|
32
|
-
"category": "data-consistency",
|
|
33
|
-
"triggerKeywords": [],
|
|
34
|
-
"scenario": "User double-clicks submit, causing duplicate records",
|
|
35
|
-
"probability": "high",
|
|
36
|
-
"impact": "medium",
|
|
37
|
-
"handlingKeywords": ["idempoten", "debounce", "disable", "lock"],
|
|
38
|
-
"handlingFound": "Some prevention mentioned",
|
|
39
|
-
"handlingMissing": "Not addressed",
|
|
40
|
-
"requiredHandling": "Implement idempotency keys for mutations. Disable submit button on click. Use unique constraints in DB.",
|
|
41
|
-
"dataConsistency": "No duplicate records from repeated submissions.",
|
|
42
|
-
"userExperience": "Button disabled during submission. Clear success/error feedback."
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
"id": "security-auth-bypass",
|
|
46
|
-
"category": "security",
|
|
47
|
-
"triggerKeywords": ["auth", "login", "user", "permission", "role"],
|
|
48
|
-
"scenario": "Unauthorized access attempt / authentication bypass",
|
|
49
|
-
"probability": "high",
|
|
50
|
-
"impact": "critical",
|
|
51
|
-
"handlingKeywords": ["auth", "jwt", "session", "middleware"],
|
|
52
|
-
"handlingFound": "Authentication mentioned",
|
|
53
|
-
"handlingMissing": "No explicit auth handling",
|
|
54
|
-
"requiredHandling": "Validate auth tokens on every request. Implement RBAC. Never trust client-side auth state.",
|
|
55
|
-
"dataConsistency": "Ensure RLS policies are enabled. No data leak through unauthorized queries.",
|
|
56
|
-
"userExperience": "Redirect to login on 401. Clear error messages without leaking implementation details."
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
"id": "security-injection",
|
|
60
|
-
"category": "security",
|
|
61
|
-
"triggerKeywords": ["input", "form", "query", "search", "user"],
|
|
62
|
-
"scenario": "SQL injection / XSS / command injection via user input",
|
|
63
|
-
"probability": "high",
|
|
64
|
-
"impact": "critical",
|
|
65
|
-
"handlingKeywords": ["sanitiz", "escap", "parameterized", "prepared"],
|
|
66
|
-
"handlingFound": "Some sanitization mentioned",
|
|
67
|
-
"handlingMissing": "Not explicitly addressed",
|
|
68
|
-
"requiredHandling": "Use parameterized queries (never string concatenation). Sanitize HTML output. Use CSP headers.",
|
|
69
|
-
"dataConsistency": "Injection can corrupt or exfiltrate data. Use least-privilege DB connections.",
|
|
70
|
-
"userExperience": "Transparent to user. Invalid input is silently sanitized."
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
"id": "scale-high-traffic",
|
|
74
|
-
"category": "scale",
|
|
75
|
-
"triggerKeywords": ["user", "request", "api", "endpoint"],
|
|
76
|
-
"scenario": "Traffic spike: 10x normal load in 60 seconds",
|
|
77
|
-
"probability": "medium",
|
|
78
|
-
"impact": "critical",
|
|
79
|
-
"handlingKeywords": ["rate-limit", "throttl", "queue", "cache", "cdn", "auto-scal"],
|
|
80
|
-
"handlingFound": "Some scaling strategy mentioned",
|
|
81
|
-
"handlingMissing": "No scaling strategy defined",
|
|
82
|
-
"requiredHandling": "Define rate limits per user and per IP. Implement request queuing for expensive operations. Use CDN for static assets.",
|
|
83
|
-
"dataConsistency": "Eventual consistency acceptable under load. No data loss.",
|
|
84
|
-
"userExperience": "Graceful degradation. Show 'service busy' instead of 500 errors."
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
"id": "failure-network-timeout",
|
|
88
|
-
"category": "failure",
|
|
89
|
-
"triggerKeywords": ["api", "external", "service", "http", "fetch"],
|
|
90
|
-
"scenario": "External API or service becomes unavailable / times out",
|
|
91
|
-
"probability": "medium",
|
|
92
|
-
"impact": "high",
|
|
93
|
-
"handlingKeywords": ["timeout", "retry", "fallback", "circuit-breaker", "circuit breaker"],
|
|
94
|
-
"handlingFound": "Timeout/retry strategy mentioned",
|
|
95
|
-
"handlingMissing": "No timeout or fallback defined",
|
|
96
|
-
"requiredHandling": "Set explicit timeouts on all external calls. Implement exponential backoff. Define fallback behavior (cached data, graceful degradation).",
|
|
97
|
-
"dataConsistency": "Operations that fail mid-way must be idempotent or rolled back.",
|
|
98
|
-
"userExperience": "Show cached/stale data with staleness indicator. Never hang indefinitely."
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
"id": "failure-disk-full",
|
|
102
|
-
"category": "failure",
|
|
103
|
-
"triggerKeywords": ["file", "upload", "storage", "media", "image"],
|
|
104
|
-
"scenario": "Storage exhaustion: disk full or quota exceeded",
|
|
105
|
-
"probability": "low",
|
|
106
|
-
"impact": "high",
|
|
107
|
-
"handlingKeywords": ["quota", "limit", "storage", "disk"],
|
|
108
|
-
"handlingFound": "Storage limits mentioned",
|
|
109
|
-
"handlingMissing": "No storage limit handling",
|
|
110
|
-
"requiredHandling": "Check available space before writes. Implement quota enforcement. Alert when approaching limits.",
|
|
111
|
-
"dataConsistency": "Partial uploads must be cleaned up. No orphaned files.",
|
|
112
|
-
"userExperience": "Clear error: 'Storage quota exceeded. Please free up space.' with actionable next step."
|
|
113
|
-
}
|
|
114
|
-
]
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import type { ChallengeScenarioPattern } from '../types/index.js';
|
|
3
|
-
export declare const ChallengeScenarioPatternSchema: z.ZodObject<{
|
|
4
|
-
id: z.ZodString;
|
|
5
|
-
category: z.ZodString;
|
|
6
|
-
triggerKeywords: z.ZodArray<z.ZodString>;
|
|
7
|
-
scenario: z.ZodString;
|
|
8
|
-
probability: z.ZodEnum<{
|
|
9
|
-
high: "high";
|
|
10
|
-
low: "low";
|
|
11
|
-
medium: "medium";
|
|
12
|
-
}>;
|
|
13
|
-
impact: z.ZodEnum<{
|
|
14
|
-
critical: "critical";
|
|
15
|
-
high: "high";
|
|
16
|
-
low: "low";
|
|
17
|
-
medium: "medium";
|
|
18
|
-
}>;
|
|
19
|
-
handlingKeywords: z.ZodArray<z.ZodString>;
|
|
20
|
-
handlingFound: z.ZodString;
|
|
21
|
-
handlingMissing: z.ZodString;
|
|
22
|
-
requiredHandling: z.ZodString;
|
|
23
|
-
dataConsistency: z.ZodString;
|
|
24
|
-
userExperience: z.ZodString;
|
|
25
|
-
}, z.core.$strip>;
|
|
26
|
-
export type { ChallengeScenarioPattern };
|
|
27
|
-
/**
|
|
28
|
-
* Load all challenge scenario patterns from the 3-layer config system.
|
|
29
|
-
*/
|
|
30
|
-
export declare function loadScenarioPatterns(projectHash?: string): ChallengeScenarioPattern[];
|
|
31
|
-
/**
|
|
32
|
-
* Filter patterns that are triggered by content of the spec.
|
|
33
|
-
* A pattern is triggered if ANY of its triggerKeywords appear in specContent,
|
|
34
|
-
* OR if it has no trigger keywords (always-on scenarios).
|
|
35
|
-
*/
|
|
36
|
-
export declare function getTriggeredPatterns(specContent: string, projectHash?: string): ChallengeScenarioPattern[];
|
|
37
|
-
/**
|
|
38
|
-
* Get patterns filtered by category.
|
|
39
|
-
*/
|
|
40
|
-
export declare function getPatternsByCategory(category: string, projectHash?: string): ChallengeScenarioPattern[];
|
|
41
|
-
/**
|
|
42
|
-
* Determine currentHandling label based on whether the spec content
|
|
43
|
-
* includes any of the pattern's handlingKeywords.
|
|
44
|
-
*/
|
|
45
|
-
export declare function resolveHandlingLabel(pattern: ChallengeScenarioPattern, specContent: string): string;
|
|
46
|
-
//# sourceMappingURL=challenge-scenarios-loader.d.ts.map
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
// engine/challenge-scenarios-loader.ts — Challenge scenario pattern library (SPEC-214)
|
|
2
|
-
//
|
|
3
|
-
// Loads challenge scenario patterns from the 3-layer config system.
|
|
4
|
-
// Source: src/config/challenge-scenarios.json (system defaults)
|
|
5
|
-
// Override: data/global/challenge-scenarios-custom.json
|
|
6
|
-
// data/projects/{hash}/config/challenge-scenarios-overrides.json
|
|
7
|
-
//
|
|
8
|
-
// Scenarios can be extended via JSON without modifying TypeScript source files.
|
|
9
|
-
import { z } from 'zod';
|
|
10
|
-
import { ConfigLoader } from './config-loader.js';
|
|
11
|
-
// ---------------------------------------------------------------------------
|
|
12
|
-
// Schema
|
|
13
|
-
// ---------------------------------------------------------------------------
|
|
14
|
-
export const ChallengeScenarioPatternSchema = z.object({
|
|
15
|
-
id: z.string().min(1).describe('Unique scenario pattern identifier'),
|
|
16
|
-
category: z
|
|
17
|
-
.string()
|
|
18
|
-
.min(1)
|
|
19
|
-
.describe('Scenario category: data-consistency, security, scale, failure, etc.'),
|
|
20
|
-
triggerKeywords: z
|
|
21
|
-
.array(z.string())
|
|
22
|
-
.describe('Keywords in spec content that activate this scenario'),
|
|
23
|
-
scenario: z.string().min(1).describe('Short description of the failure scenario'),
|
|
24
|
-
probability: z.enum(['low', 'medium', 'high']).describe('Probability of this failure occurring'),
|
|
25
|
-
impact: z.enum(['low', 'medium', 'high', 'critical']).describe('Impact if this failure occurs'),
|
|
26
|
-
handlingKeywords: z
|
|
27
|
-
.array(z.string())
|
|
28
|
-
.describe('Keywords that indicate the spec already addresses this scenario'),
|
|
29
|
-
handlingFound: z.string().describe('Message when handling is detected in spec'),
|
|
30
|
-
handlingMissing: z.string().describe('Message when handling is absent from spec'),
|
|
31
|
-
requiredHandling: z.string().describe('What the spec should implement to handle this scenario'),
|
|
32
|
-
dataConsistency: z.string().describe('Data consistency requirements for this scenario'),
|
|
33
|
-
userExperience: z.string().describe('Expected user experience for this scenario'),
|
|
34
|
-
});
|
|
35
|
-
const patternsArraySchema = z.array(ChallengeScenarioPatternSchema);
|
|
36
|
-
// ---------------------------------------------------------------------------
|
|
37
|
-
// Loader singleton
|
|
38
|
-
// ---------------------------------------------------------------------------
|
|
39
|
-
let _loader = null;
|
|
40
|
-
function getLoader() {
|
|
41
|
-
_loader ??= new ConfigLoader('challenge-scenarios', patternsArraySchema);
|
|
42
|
-
return _loader;
|
|
43
|
-
}
|
|
44
|
-
// ---------------------------------------------------------------------------
|
|
45
|
-
// Public API
|
|
46
|
-
// ---------------------------------------------------------------------------
|
|
47
|
-
/**
|
|
48
|
-
* Load all challenge scenario patterns from the 3-layer config system.
|
|
49
|
-
*/
|
|
50
|
-
export function loadScenarioPatterns(projectHash) {
|
|
51
|
-
return getLoader().load(projectHash);
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Filter patterns that are triggered by content of the spec.
|
|
55
|
-
* A pattern is triggered if ANY of its triggerKeywords appear in specContent,
|
|
56
|
-
* OR if it has no trigger keywords (always-on scenarios).
|
|
57
|
-
*/
|
|
58
|
-
export function getTriggeredPatterns(specContent, projectHash) {
|
|
59
|
-
const lower = specContent.toLowerCase();
|
|
60
|
-
const all = loadScenarioPatterns(projectHash);
|
|
61
|
-
return all.filter((pattern) => {
|
|
62
|
-
if (pattern.triggerKeywords.length === 0) {
|
|
63
|
-
return true; // always-on pattern
|
|
64
|
-
}
|
|
65
|
-
return pattern.triggerKeywords.some((kw) => lower.includes(kw.toLowerCase()));
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Get patterns filtered by category.
|
|
70
|
-
*/
|
|
71
|
-
export function getPatternsByCategory(category, projectHash) {
|
|
72
|
-
return loadScenarioPatterns(projectHash).filter((p) => p.category === category);
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Determine currentHandling label based on whether the spec content
|
|
76
|
-
* includes any of the pattern's handlingKeywords.
|
|
77
|
-
*/
|
|
78
|
-
export function resolveHandlingLabel(pattern, specContent) {
|
|
79
|
-
const lower = specContent.toLowerCase();
|
|
80
|
-
const addressed = pattern.handlingKeywords.some((kw) => lower.includes(kw.toLowerCase()));
|
|
81
|
-
return addressed ? pattern.handlingFound : pattern.handlingMissing;
|
|
82
|
-
}
|
|
83
|
-
//# sourceMappingURL=challenge-scenarios-loader.js.map
|