project-tiny-context-harness 0.2.53 → 0.2.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +122 -69
- package/assets/README.md +113 -62
- package/assets/README.zh-CN.md +8 -6
- package/assets/agents/AGENTS_CORE.md +17 -16
- package/assets/context_templates/product-surface-contract.md +60 -0
- package/assets/github/harness.yml +15 -11
- package/assets/make/ty-context.mk +48 -0
- package/assets/skills/context_development_engineer/SKILL.md +9 -6
- package/assets/skills/context_full_project_export/SKILL.md +13 -13
- package/assets/skills/context_harness_upgrade/SKILL.md +9 -9
- package/assets/skills/context_product_plan/SKILL.md +7 -4
- package/assets/skills/context_surface_contract/SKILL.md +168 -0
- package/assets/skills/context_uiux_design/SKILL.md +7 -4
- package/assets/skills/plan_acceptance_checklist_compiler/SKILL.md +427 -0
- package/assets/tools/validate_context.py +1 -1
- package/dist/cli.js +1 -1
- package/dist/commands/check-modularity.js +14 -6
- package/dist/commands/export-context.js +4 -4
- package/dist/commands/index.js +8 -5
- package/dist/commands/init.js +1 -1
- package/dist/commands/package-source.js +1 -1
- package/dist/commands/upgrade.js +1 -1
- package/dist/lib/config.js +7 -2
- package/dist/lib/constants.d.ts +1 -1
- package/dist/lib/constants.js +1 -1
- package/dist/lib/context-export.js +5 -5
- package/dist/lib/harness-root.d.ts +5 -0
- package/dist/lib/harness-root.js +32 -4
- package/dist/lib/legacy-managed-scan.d.ts +2 -0
- package/dist/lib/legacy-managed-scan.js +79 -0
- package/dist/lib/legacy-sdlc-migration.d.ts +2 -0
- package/dist/lib/legacy-sdlc-migration.js +189 -0
- package/dist/lib/managed-file.d.ts +18 -12
- package/dist/lib/managed-file.js +25 -14
- package/dist/lib/migrations.js +4 -2
- package/dist/lib/modularity.d.ts +9 -0
- package/dist/lib/modularity.js +132 -8
- package/dist/lib/package-json-config.js +3 -3
- package/dist/lib/paths.d.ts +2 -2
- package/dist/lib/paths.js +2 -2
- package/dist/lib/sync-engine.js +33 -31
- package/dist/lib/types.d.ts +12 -0
- package/dist/lib/validators.js +37 -4
- package/package.json +5 -5
- package/source-mappings.yaml +13 -13
- package/assets/make/sdlc-harness.mk +0 -43
|
@@ -2,7 +2,12 @@ export interface HarnessRootConfig {
|
|
|
2
2
|
harnessFolderName: string;
|
|
3
3
|
source: string;
|
|
4
4
|
}
|
|
5
|
+
export interface HarnessRootConfigCandidate extends HarnessRootConfig {
|
|
6
|
+
legacy: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare const LEGACY_HARNESS_JSON_CONFIG_PATH = "sdlc-harness.config.json";
|
|
5
9
|
export declare function readHarnessRootConfig(projectRoot: string): Promise<HarnessRootConfig>;
|
|
10
|
+
export declare function readHarnessRootConfigCandidates(projectRoot: string): Promise<HarnessRootConfigCandidate[]>;
|
|
6
11
|
export declare function harnessRoot(projectRoot: string): Promise<string>;
|
|
7
12
|
export declare function harnessConfigPath(projectRoot: string): Promise<string>;
|
|
8
13
|
export declare function harnessPath(root: string, ...segments: string[]): string;
|
package/dist/lib/harness-root.js
CHANGED
|
@@ -1,19 +1,47 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { DEFAULT_HARNESS_ROOT, HARNESS_JSON_CONFIG_PATH } from "./paths.js";
|
|
3
3
|
import { pathExists, readText } from "./fs.js";
|
|
4
|
+
export const LEGACY_HARNESS_JSON_CONFIG_PATH = "sdlc-harness.config.json";
|
|
4
5
|
export async function readHarnessRootConfig(projectRoot) {
|
|
6
|
+
const candidates = await readHarnessRootConfigCandidates(projectRoot);
|
|
7
|
+
if (candidates.length > 0) {
|
|
8
|
+
const candidate = candidates[0];
|
|
9
|
+
return { harnessFolderName: candidate.harnessFolderName, source: candidate.source };
|
|
10
|
+
}
|
|
11
|
+
return { harnessFolderName: DEFAULT_HARNESS_ROOT, source: "default" };
|
|
12
|
+
}
|
|
13
|
+
export async function readHarnessRootConfigCandidates(projectRoot) {
|
|
14
|
+
const candidates = [];
|
|
5
15
|
const packageJson = await readJsonConfig(path.join(projectRoot, "package.json"));
|
|
6
|
-
const packageConfig = packageJson && typeof packageJson === "object" ? packageJson.
|
|
16
|
+
const packageConfig = packageJson && typeof packageJson === "object" ? packageJson.tyContext : undefined;
|
|
7
17
|
const packageValue = folderNameFromObject(packageConfig);
|
|
8
18
|
if (packageValue) {
|
|
9
|
-
|
|
19
|
+
candidates.push({ harnessFolderName: normalizeHarnessFolderName(packageValue), source: "package.json#tyContext", legacy: false });
|
|
10
20
|
}
|
|
11
21
|
const explicitConfig = await readJsonConfig(path.join(projectRoot, HARNESS_JSON_CONFIG_PATH));
|
|
12
22
|
const explicitValue = folderNameFromObject(explicitConfig);
|
|
13
23
|
if (explicitValue) {
|
|
14
|
-
|
|
24
|
+
candidates.push({ harnessFolderName: normalizeHarnessFolderName(explicitValue), source: HARNESS_JSON_CONFIG_PATH, legacy: false });
|
|
15
25
|
}
|
|
16
|
-
|
|
26
|
+
const legacyPackageConfig = packageJson && typeof packageJson === "object" ? packageJson.sdlcHarness : undefined;
|
|
27
|
+
const legacyPackageValue = folderNameFromObject(legacyPackageConfig);
|
|
28
|
+
if (legacyPackageValue) {
|
|
29
|
+
candidates.push({
|
|
30
|
+
harnessFolderName: normalizeHarnessFolderName(legacyPackageValue),
|
|
31
|
+
source: "package.json#sdlcHarness",
|
|
32
|
+
legacy: true
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
const legacyExplicitConfig = await readJsonConfig(path.join(projectRoot, LEGACY_HARNESS_JSON_CONFIG_PATH));
|
|
36
|
+
const legacyExplicitValue = folderNameFromObject(legacyExplicitConfig);
|
|
37
|
+
if (legacyExplicitValue) {
|
|
38
|
+
candidates.push({
|
|
39
|
+
harnessFolderName: normalizeHarnessFolderName(legacyExplicitValue),
|
|
40
|
+
source: LEGACY_HARNESS_JSON_CONFIG_PATH,
|
|
41
|
+
legacy: true
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return candidates;
|
|
17
45
|
}
|
|
18
46
|
export async function harnessRoot(projectRoot) {
|
|
19
47
|
return (await readHarnessRootConfig(projectRoot)).harnessFolderName;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { listFiles, pathExists, readText } from "./fs.js";
|
|
3
|
+
import { packageAssetPath } from "./paths.js";
|
|
4
|
+
const LEGACY_MANAGED_ROOT = "pjsdlc_managed";
|
|
5
|
+
const CURRENT_MANAGED_ROOT = "ty-context-managed";
|
|
6
|
+
const LEGACY_MAKEFILE = "sdlc-harness.mk";
|
|
7
|
+
const CURRENT_MAKEFILE = "ty-context.mk";
|
|
8
|
+
export async function detectLegacyManagedDirectory(projectRoot, root, migration) {
|
|
9
|
+
const legacyRoot = path.join(projectRoot, root, LEGACY_MANAGED_ROOT);
|
|
10
|
+
const files = await listFiles(legacyRoot);
|
|
11
|
+
const items = [];
|
|
12
|
+
for (const file of files) {
|
|
13
|
+
if (path.basename(file) === ".gitkeep") {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
const relativeToLegacyRoot = path.relative(legacyRoot, file).split(path.sep).join("/");
|
|
17
|
+
const relativeToProject = path.relative(projectRoot, file).split(path.sep).join("/");
|
|
18
|
+
const classification = await classifyLegacyManagedFile(relativeToLegacyRoot);
|
|
19
|
+
if (classification.kind === "override") {
|
|
20
|
+
items.push(item(migration, "manual_required", relativeToProject, "Legacy skill overrides are no longer supported; move rules into a standalone project-local Skill."));
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (classification.kind === "unknown") {
|
|
24
|
+
items.push(item(migration, "manual_required", relativeToProject, "Legacy pjsdlc_managed content is not recognized as package-generated; review it manually."));
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
const target = path.join(projectRoot, root, CURRENT_MANAGED_ROOT, ...classification.targetRelative.split("/"));
|
|
28
|
+
if (!(await pathExists(target))) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const assetContent = await readText(classification.assetPath);
|
|
32
|
+
if ((await readText(target)) !== assetContent) {
|
|
33
|
+
items.push(item(migration, "blocked", path.relative(projectRoot, target).split(path.sep).join("/"), `Cannot refresh legacy generated file because ${classification.targetRelative} already exists with non-package content.`));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return items;
|
|
37
|
+
}
|
|
38
|
+
async function classifyLegacyManagedFile(relative) {
|
|
39
|
+
if (relative.startsWith("override_skills/")) {
|
|
40
|
+
return { kind: "override" };
|
|
41
|
+
}
|
|
42
|
+
const mapped = legacyGeneratedMapping(relative);
|
|
43
|
+
if (!mapped) {
|
|
44
|
+
return { kind: "unknown" };
|
|
45
|
+
}
|
|
46
|
+
const assetPath = packageAssetPath(...mapped.assetSegments);
|
|
47
|
+
if (!(await pathExists(assetPath))) {
|
|
48
|
+
return { kind: "unknown" };
|
|
49
|
+
}
|
|
50
|
+
return { kind: "generated", targetRelative: mapped.targetRelative, assetPath };
|
|
51
|
+
}
|
|
52
|
+
function legacyGeneratedMapping(relative) {
|
|
53
|
+
if (relative === `make/${LEGACY_MAKEFILE}`) {
|
|
54
|
+
return { targetRelative: `make/${CURRENT_MAKEFILE}`, assetSegments: ["make", CURRENT_MAKEFILE] };
|
|
55
|
+
}
|
|
56
|
+
for (const [prefix, assetPrefix] of [
|
|
57
|
+
["agents/", "agents"],
|
|
58
|
+
["context_templates/", "context_templates"],
|
|
59
|
+
["skills/", "skills"],
|
|
60
|
+
["minimal_tools/", "tools"]
|
|
61
|
+
]) {
|
|
62
|
+
if (relative.startsWith(prefix)) {
|
|
63
|
+
const rest = relative.slice(prefix.length);
|
|
64
|
+
return { targetRelative: `${prefix}${rest}`, assetSegments: [assetPrefix, ...rest.split("/")] };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
function item(migration, status, pathLabel, message) {
|
|
70
|
+
return {
|
|
71
|
+
id: migration.id,
|
|
72
|
+
introducedIn: migration.introducedIn,
|
|
73
|
+
description: migration.description,
|
|
74
|
+
scope: migration.scope,
|
|
75
|
+
status,
|
|
76
|
+
path: pathLabel,
|
|
77
|
+
message
|
|
78
|
+
};
|
|
79
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { LEGACY_HARNESS_JSON_CONFIG_PATH, readHarnessRootConfigCandidates } from "./harness-root.js";
|
|
3
|
+
import { pathExists, readText, writeTextIfChanged } from "./fs.js";
|
|
4
|
+
import { detectLegacyManagedDirectory } from "./legacy-managed-scan.js";
|
|
5
|
+
import { HARNESS_JSON_CONFIG_PATH } from "./paths.js";
|
|
6
|
+
const LEGACY_MANAGED_ROOT = "pjsdlc_managed";
|
|
7
|
+
const CURRENT_MANAGED_ROOT = "ty-context-managed";
|
|
8
|
+
const LEGACY_MAKEFILE = "sdlc-harness.mk";
|
|
9
|
+
const CURRENT_MAKEFILE = "ty-context.mk";
|
|
10
|
+
export const legacySdlcHarnessMigration = {
|
|
11
|
+
id: "legacy-sdlc-harness-rename",
|
|
12
|
+
introducedIn: "0.2.54",
|
|
13
|
+
description: "Rename legacy sdlc-harness configuration and pjsdlc_managed package-managed paths.",
|
|
14
|
+
scope: "package.json, sdlc-harness.config.json, <harnessRoot>/config.yaml, old managed markers and pjsdlc_managed/**",
|
|
15
|
+
risk: "safe",
|
|
16
|
+
manualMessage: "Resolve legacy sdlc-harness conflicts or move old override rules into standalone project-local Skills.",
|
|
17
|
+
detect: detectLegacySdlcHarness,
|
|
18
|
+
apply: migrateLegacySdlcHarness,
|
|
19
|
+
verify: async () => undefined
|
|
20
|
+
};
|
|
21
|
+
async function detectLegacySdlcHarness(projectRoot, root, migration) {
|
|
22
|
+
const items = [];
|
|
23
|
+
const candidates = await readHarnessRootConfigCandidates(projectRoot);
|
|
24
|
+
const currentCandidates = candidates.filter((candidate) => !candidate.legacy);
|
|
25
|
+
const legacyCandidates = candidates.filter((candidate) => candidate.legacy);
|
|
26
|
+
const currentRoot = currentCandidates[0]?.harnessFolderName;
|
|
27
|
+
const distinctLegacyRoots = Array.from(new Set(legacyCandidates.map((candidate) => candidate.harnessFolderName)));
|
|
28
|
+
if (currentRoot && distinctLegacyRoots.some((legacyRoot) => legacyRoot !== currentRoot)) {
|
|
29
|
+
items.push(item(migration, "blocked", rootConflictPath(currentCandidates, legacyCandidates), "Current ty-context and legacy sdlc-harness root configuration disagree; choose the harness root manually before upgrade."));
|
|
30
|
+
}
|
|
31
|
+
else if (!currentRoot && distinctLegacyRoots.length > 1) {
|
|
32
|
+
items.push(item(migration, "blocked", rootConflictPath(currentCandidates, legacyCandidates), "Legacy sdlc-harness root sources disagree; choose one harness root manually before upgrade."));
|
|
33
|
+
}
|
|
34
|
+
items.push(...(await detectLegacyManagedDirectory(projectRoot, root, legacySdlcHarnessMigration)));
|
|
35
|
+
if (items.some((entry) => entry.status === "blocked")) {
|
|
36
|
+
return items;
|
|
37
|
+
}
|
|
38
|
+
if (await needsLegacySafeMigration(projectRoot, root, legacyCandidates.length > 0)) {
|
|
39
|
+
items.unshift(item(migration, "safe_pending", "legacy sdlc-harness surfaces", "Legacy sdlc-harness naming can be copied to ty-context configuration and refreshed by sync."));
|
|
40
|
+
}
|
|
41
|
+
return items;
|
|
42
|
+
}
|
|
43
|
+
async function migrateLegacySdlcHarness(projectRoot, root, report) {
|
|
44
|
+
await migratePackageJsonConfig(projectRoot, report);
|
|
45
|
+
await migrateJsonConfig(projectRoot, report);
|
|
46
|
+
await migrateConfigYamlPaths(projectRoot, root, report);
|
|
47
|
+
}
|
|
48
|
+
async function needsLegacySafeMigration(projectRoot, root, hasLegacyRootConfig) {
|
|
49
|
+
if (hasLegacyRootConfig && (await legacyPackageConfigNeedsCopy(projectRoot))) {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
if (await legacyJsonConfigNeedsCopy(projectRoot)) {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
if (await configYamlHasLegacyManagedPaths(projectRoot, root)) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
if (await hasLegacyManagedMarkers(projectRoot)) {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
async function legacyPackageConfigNeedsCopy(projectRoot) {
|
|
64
|
+
const packagePath = path.join(projectRoot, "package.json");
|
|
65
|
+
if (!(await pathExists(packagePath))) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
const packageJson = parseJsonRecord(await readText(packagePath), "package.json");
|
|
69
|
+
return isJsonRecord(packageJson.sdlcHarness) && !isJsonRecord(packageJson.tyContext);
|
|
70
|
+
}
|
|
71
|
+
async function legacyJsonConfigNeedsCopy(projectRoot) {
|
|
72
|
+
const legacyPath = path.join(projectRoot, LEGACY_HARNESS_JSON_CONFIG_PATH);
|
|
73
|
+
const currentPath = path.join(projectRoot, HARNESS_JSON_CONFIG_PATH);
|
|
74
|
+
return (await pathExists(legacyPath)) && !(await pathExists(currentPath));
|
|
75
|
+
}
|
|
76
|
+
async function configYamlHasLegacyManagedPaths(projectRoot, root) {
|
|
77
|
+
const configPath = path.join(projectRoot, root, "config.yaml");
|
|
78
|
+
if (!(await pathExists(configPath))) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
return hasLegacyManagedPath(await readText(configPath));
|
|
82
|
+
}
|
|
83
|
+
async function hasLegacyManagedMarkers(projectRoot) {
|
|
84
|
+
for (const relative of ["AGENTS.md", "Makefile", ".github/workflows/harness.yml"]) {
|
|
85
|
+
const target = path.join(projectRoot, ...relative.split("/"));
|
|
86
|
+
if ((await pathExists(target)) && hasLegacyMarker(await readText(target))) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
async function migratePackageJsonConfig(projectRoot, report) {
|
|
93
|
+
const packagePath = path.join(projectRoot, "package.json");
|
|
94
|
+
if (!(await pathExists(packagePath))) {
|
|
95
|
+
report.skipped.push("package.json#sdlcHarness");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const packageJson = parseJsonRecord(await readText(packagePath), "package.json");
|
|
99
|
+
if (!isJsonRecord(packageJson.sdlcHarness) || isJsonRecord(packageJson.tyContext)) {
|
|
100
|
+
report.skipped.push("package.json#sdlcHarness");
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
packageJson.tyContext = { ...packageJson.sdlcHarness };
|
|
104
|
+
if (await writeTextIfChanged(packagePath, `${JSON.stringify(packageJson, null, 2)}\n`)) {
|
|
105
|
+
report.changed.push("package.json#tyContext");
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
report.skipped.push("package.json#tyContext");
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async function migrateJsonConfig(projectRoot, report) {
|
|
112
|
+
const legacyPath = path.join(projectRoot, LEGACY_HARNESS_JSON_CONFIG_PATH);
|
|
113
|
+
const currentPath = path.join(projectRoot, HARNESS_JSON_CONFIG_PATH);
|
|
114
|
+
if (!(await pathExists(legacyPath))) {
|
|
115
|
+
report.skipped.push(LEGACY_HARNESS_JSON_CONFIG_PATH);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (await pathExists(currentPath)) {
|
|
119
|
+
report.skipped.push(HARNESS_JSON_CONFIG_PATH);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (await writeTextIfChanged(currentPath, await readText(legacyPath))) {
|
|
123
|
+
report.changed.push(HARNESS_JSON_CONFIG_PATH);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
report.skipped.push(HARNESS_JSON_CONFIG_PATH);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
async function migrateConfigYamlPaths(projectRoot, root, report) {
|
|
130
|
+
const relative = `${root}/config.yaml`;
|
|
131
|
+
const configPath = path.join(projectRoot, root, "config.yaml");
|
|
132
|
+
if (!(await pathExists(configPath))) {
|
|
133
|
+
report.skipped.push(relative);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const original = await readText(configPath);
|
|
137
|
+
const next = rewriteLegacyManagedPaths(original);
|
|
138
|
+
if (next === original) {
|
|
139
|
+
report.skipped.push(relative);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (await writeTextIfChanged(configPath, next)) {
|
|
143
|
+
report.changed.push(`${relative}#legacy-managed-paths`);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
report.skipped.push(`${relative}#legacy-managed-paths`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function rewriteLegacyManagedPaths(content) {
|
|
150
|
+
return content.replaceAll(LEGACY_MANAGED_ROOT, CURRENT_MANAGED_ROOT).replaceAll(LEGACY_MAKEFILE, CURRENT_MAKEFILE);
|
|
151
|
+
}
|
|
152
|
+
function hasLegacyManagedPath(content) {
|
|
153
|
+
return content.includes(LEGACY_MANAGED_ROOT) || content.includes(LEGACY_MAKEFILE);
|
|
154
|
+
}
|
|
155
|
+
function hasLegacyMarker(content) {
|
|
156
|
+
return [
|
|
157
|
+
"<!-- pjsdlc:sdlc-harness:begin -->",
|
|
158
|
+
"<!-- sdlc-harness:begin -->",
|
|
159
|
+
"# pjsdlc:sdlc-harness:make:begin",
|
|
160
|
+
"# sdlc-harness:make:begin",
|
|
161
|
+
"# pjsdlc:sdlc-harness:github-workflow:begin"
|
|
162
|
+
].some((marker) => content.includes(marker));
|
|
163
|
+
}
|
|
164
|
+
function rootConflictPath(currentCandidates, legacyCandidates) {
|
|
165
|
+
return [...currentCandidates, ...legacyCandidates]
|
|
166
|
+
.map((candidate) => `${candidate.source}=${candidate.harnessFolderName}`)
|
|
167
|
+
.join(", ");
|
|
168
|
+
}
|
|
169
|
+
function item(migrationId, status, pathLabel, message) {
|
|
170
|
+
return {
|
|
171
|
+
id: legacySdlcHarnessMigration.id,
|
|
172
|
+
introducedIn: legacySdlcHarnessMigration.introducedIn,
|
|
173
|
+
description: legacySdlcHarnessMigration.description,
|
|
174
|
+
scope: legacySdlcHarnessMigration.scope,
|
|
175
|
+
status,
|
|
176
|
+
path: pathLabel,
|
|
177
|
+
message
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
function parseJsonRecord(content, pathLabel) {
|
|
181
|
+
const parsed = JSON.parse(content);
|
|
182
|
+
if (!isJsonRecord(parsed)) {
|
|
183
|
+
throw new Error(`${pathLabel} must contain a JSON object`);
|
|
184
|
+
}
|
|
185
|
+
return parsed;
|
|
186
|
+
}
|
|
187
|
+
function isJsonRecord(value) {
|
|
188
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
189
|
+
}
|
|
@@ -2,18 +2,24 @@ export interface ManagedBlockMarkers {
|
|
|
2
2
|
start: string;
|
|
3
3
|
end: string;
|
|
4
4
|
}
|
|
5
|
-
export declare const MANAGED_BLOCK_START = "<!--
|
|
6
|
-
export declare const MANAGED_BLOCK_END = "<!--
|
|
7
|
-
export declare const
|
|
8
|
-
export declare const
|
|
9
|
-
export declare const
|
|
10
|
-
export declare const
|
|
11
|
-
export declare const
|
|
12
|
-
export declare const
|
|
13
|
-
export declare const
|
|
14
|
-
export declare const
|
|
15
|
-
export declare const
|
|
16
|
-
export declare const
|
|
5
|
+
export declare const MANAGED_BLOCK_START = "<!-- ty-context:managed:begin -->";
|
|
6
|
+
export declare const MANAGED_BLOCK_END = "<!-- ty-context:managed:end -->";
|
|
7
|
+
export declare const LEGACY_PJSDLC_MANAGED_BLOCK_START = "<!-- pjsdlc:sdlc-harness:begin -->";
|
|
8
|
+
export declare const LEGACY_PJSDLC_MANAGED_BLOCK_END = "<!-- pjsdlc:sdlc-harness:end -->";
|
|
9
|
+
export declare const LEGACY_SDLC_MANAGED_BLOCK_START = "<!-- sdlc-harness:begin -->";
|
|
10
|
+
export declare const LEGACY_SDLC_MANAGED_BLOCK_END = "<!-- sdlc-harness:end -->";
|
|
11
|
+
export declare const MAKEFILE_BLOCK_START = "# ty-context:make:begin";
|
|
12
|
+
export declare const MAKEFILE_BLOCK_END = "# ty-context:make:end";
|
|
13
|
+
export declare const LEGACY_PJSDLC_MAKEFILE_BLOCK_START = "# pjsdlc:sdlc-harness:make:begin";
|
|
14
|
+
export declare const LEGACY_PJSDLC_MAKEFILE_BLOCK_END = "# pjsdlc:sdlc-harness:make:end";
|
|
15
|
+
export declare const LEGACY_SDLC_MAKEFILE_BLOCK_START = "# sdlc-harness:make:begin";
|
|
16
|
+
export declare const LEGACY_SDLC_MAKEFILE_BLOCK_END = "# sdlc-harness:make:end";
|
|
17
|
+
export declare const GITHUB_WORKFLOW_BLOCK_START = "# ty-context:github-workflow:begin";
|
|
18
|
+
export declare const GITHUB_WORKFLOW_BLOCK_END = "# ty-context:github-workflow:end";
|
|
19
|
+
export declare const LEGACY_PJSDLC_GITHUB_WORKFLOW_BLOCK_START = "# pjsdlc:sdlc-harness:github-workflow:begin";
|
|
20
|
+
export declare const LEGACY_PJSDLC_GITHUB_WORKFLOW_BLOCK_END = "# pjsdlc:sdlc-harness:github-workflow:end";
|
|
21
|
+
export declare const MANAGED_METADATA_START = "<!-- ty-context-managed";
|
|
17
22
|
export declare const MANAGED_METADATA_END = "-->";
|
|
18
23
|
export declare const AGENTS_BLOCK_MARKERS: ManagedBlockMarkers[];
|
|
19
24
|
export declare const MAKEFILE_BLOCK_MARKERS: ManagedBlockMarkers[];
|
|
25
|
+
export declare const GITHUB_WORKFLOW_BLOCK_MARKERS: ManagedBlockMarkers[];
|
package/dist/lib/managed-file.js
CHANGED
|
@@ -1,21 +1,32 @@
|
|
|
1
|
-
export const MANAGED_BLOCK_START = "<!--
|
|
2
|
-
export const MANAGED_BLOCK_END = "<!--
|
|
3
|
-
export const
|
|
4
|
-
export const
|
|
5
|
-
export const
|
|
6
|
-
export const
|
|
7
|
-
export const
|
|
8
|
-
export const
|
|
9
|
-
export const
|
|
10
|
-
export const
|
|
11
|
-
export const
|
|
12
|
-
export const
|
|
1
|
+
export const MANAGED_BLOCK_START = "<!-- ty-context:managed:begin -->";
|
|
2
|
+
export const MANAGED_BLOCK_END = "<!-- ty-context:managed:end -->";
|
|
3
|
+
export const LEGACY_PJSDLC_MANAGED_BLOCK_START = "<!-- pjsdlc:sdlc-harness:begin -->";
|
|
4
|
+
export const LEGACY_PJSDLC_MANAGED_BLOCK_END = "<!-- pjsdlc:sdlc-harness:end -->";
|
|
5
|
+
export const LEGACY_SDLC_MANAGED_BLOCK_START = "<!-- sdlc-harness:begin -->";
|
|
6
|
+
export const LEGACY_SDLC_MANAGED_BLOCK_END = "<!-- sdlc-harness:end -->";
|
|
7
|
+
export const MAKEFILE_BLOCK_START = "# ty-context:make:begin";
|
|
8
|
+
export const MAKEFILE_BLOCK_END = "# ty-context:make:end";
|
|
9
|
+
export const LEGACY_PJSDLC_MAKEFILE_BLOCK_START = "# pjsdlc:sdlc-harness:make:begin";
|
|
10
|
+
export const LEGACY_PJSDLC_MAKEFILE_BLOCK_END = "# pjsdlc:sdlc-harness:make:end";
|
|
11
|
+
export const LEGACY_SDLC_MAKEFILE_BLOCK_START = "# sdlc-harness:make:begin";
|
|
12
|
+
export const LEGACY_SDLC_MAKEFILE_BLOCK_END = "# sdlc-harness:make:end";
|
|
13
|
+
export const GITHUB_WORKFLOW_BLOCK_START = "# ty-context:github-workflow:begin";
|
|
14
|
+
export const GITHUB_WORKFLOW_BLOCK_END = "# ty-context:github-workflow:end";
|
|
15
|
+
export const LEGACY_PJSDLC_GITHUB_WORKFLOW_BLOCK_START = "# pjsdlc:sdlc-harness:github-workflow:begin";
|
|
16
|
+
export const LEGACY_PJSDLC_GITHUB_WORKFLOW_BLOCK_END = "# pjsdlc:sdlc-harness:github-workflow:end";
|
|
17
|
+
export const MANAGED_METADATA_START = "<!-- ty-context-managed";
|
|
13
18
|
export const MANAGED_METADATA_END = "-->";
|
|
14
19
|
export const AGENTS_BLOCK_MARKERS = [
|
|
15
20
|
{ start: MANAGED_BLOCK_START, end: MANAGED_BLOCK_END },
|
|
16
|
-
{ start:
|
|
21
|
+
{ start: LEGACY_PJSDLC_MANAGED_BLOCK_START, end: LEGACY_PJSDLC_MANAGED_BLOCK_END },
|
|
22
|
+
{ start: LEGACY_SDLC_MANAGED_BLOCK_START, end: LEGACY_SDLC_MANAGED_BLOCK_END }
|
|
17
23
|
];
|
|
18
24
|
export const MAKEFILE_BLOCK_MARKERS = [
|
|
19
25
|
{ start: MAKEFILE_BLOCK_START, end: MAKEFILE_BLOCK_END },
|
|
20
|
-
{ start:
|
|
26
|
+
{ start: LEGACY_PJSDLC_MAKEFILE_BLOCK_START, end: LEGACY_PJSDLC_MAKEFILE_BLOCK_END },
|
|
27
|
+
{ start: LEGACY_SDLC_MAKEFILE_BLOCK_START, end: LEGACY_SDLC_MAKEFILE_BLOCK_END }
|
|
28
|
+
];
|
|
29
|
+
export const GITHUB_WORKFLOW_BLOCK_MARKERS = [
|
|
30
|
+
{ start: GITHUB_WORKFLOW_BLOCK_START, end: GITHUB_WORKFLOW_BLOCK_END },
|
|
31
|
+
{ start: LEGACY_PJSDLC_GITHUB_WORKFLOW_BLOCK_START, end: LEGACY_PJSDLC_GITHUB_WORKFLOW_BLOCK_END }
|
|
21
32
|
];
|
package/dist/lib/migrations.js
CHANGED
|
@@ -7,11 +7,13 @@ import { defaultConfig, readConfig } from "./config.js";
|
|
|
7
7
|
import { createDesignMdIfMissing, DESIGN_MD_PATH } from "./design-md.js";
|
|
8
8
|
import { ensureDir, listFiles, pathExists, readText, writeTextIfChanged } from "./fs.js";
|
|
9
9
|
import { harnessConfigPath, harnessRoot } from "./harness-root.js";
|
|
10
|
+
import { legacySdlcHarnessMigration } from "./legacy-sdlc-migration.js";
|
|
10
11
|
import { stringifyYaml } from "./yaml.js";
|
|
11
12
|
async function verifyNoop() {
|
|
12
13
|
return;
|
|
13
14
|
}
|
|
14
15
|
export const migrations = [
|
|
16
|
+
legacySdlcHarnessMigration,
|
|
15
17
|
{
|
|
16
18
|
id: "schema-v4-config-refresh",
|
|
17
19
|
introducedIn: "0.2.0",
|
|
@@ -71,7 +73,7 @@ export const migrations = [
|
|
|
71
73
|
id: "deprecated-skill-overrides",
|
|
72
74
|
introducedIn: "0.2.0",
|
|
73
75
|
description: "Report deprecated managed skill overrides that must move to standalone project-local Skills.",
|
|
74
|
-
scope: "<harnessRoot>/
|
|
76
|
+
scope: "<harnessRoot>/ty-context-managed/override_skills/**",
|
|
75
77
|
risk: "manual",
|
|
76
78
|
manualMessage: "Move override files into standalone project-local Skills before running sync.",
|
|
77
79
|
detect: detectDeprecatedSkillOverrides,
|
|
@@ -355,7 +357,7 @@ async function migrateConfig(projectRoot, root, report) {
|
|
|
355
357
|
}
|
|
356
358
|
}
|
|
357
359
|
async function detectDeprecatedSkillOverrides(projectRoot, root, migration) {
|
|
358
|
-
const overrideRoot = path.join(projectRoot, root, "
|
|
360
|
+
const overrideRoot = path.join(projectRoot, root, "ty-context-managed", "override_skills");
|
|
359
361
|
if (!(await pathExists(overrideRoot))) {
|
|
360
362
|
return [];
|
|
361
363
|
}
|
package/dist/lib/modularity.d.ts
CHANGED
|
@@ -8,11 +8,20 @@ export interface ModularityFileReport {
|
|
|
8
8
|
relativePath: string;
|
|
9
9
|
lines: number;
|
|
10
10
|
overLimit: boolean;
|
|
11
|
+
waived?: ModularityWaiver;
|
|
11
12
|
}
|
|
12
13
|
export interface ModularityCheckReport {
|
|
13
14
|
limit: number;
|
|
14
15
|
files: ModularityFileReport[];
|
|
15
16
|
warnings: string[];
|
|
17
|
+
waivedWarnings: string[];
|
|
18
|
+
errors: string[];
|
|
19
|
+
}
|
|
20
|
+
export interface ModularityWaiver {
|
|
21
|
+
relativePath: string;
|
|
22
|
+
category: string;
|
|
23
|
+
reason: string;
|
|
24
|
+
futureSplitBoundary: string;
|
|
16
25
|
}
|
|
17
26
|
export declare function runModularityCheck(projectRoot: string, options: ModularityCheckOptions): Promise<ModularityCheckReport>;
|
|
18
27
|
export declare function countPhysicalLines(content: string): number;
|