feat(P03): multi-project support, NFR milestone versioning, phase context reset, install scripts (v0.3.0)

This commit is contained in:
CI
2026-05-29 15:13:45 +00:00
parent e4bb3a9970
commit ddf04792c7
57 changed files with 1748 additions and 59 deletions
+43 -3
View File
@@ -27,9 +27,19 @@ export interface BranchInfo {
export class GitContext {
private projectPath: string;
private projectSlug?: string;
constructor(projectPath: string) {
constructor(projectPath: string, projectSlug?: string) {
this.projectPath = projectPath;
this.projectSlug = projectSlug;
}
setProjectSlug(slug: string | undefined): void {
this.projectSlug = slug;
}
getProjectSlug(): string | undefined {
return this.projectSlug;
}
private git(args: string): string {
@@ -98,14 +108,21 @@ export class GitContext {
merged: mergedBranches.has(cleanName),
};
const phaseMatch = cleanName.match(/^phase\/(\d+)-(.+)/);
let branchName = cleanName;
const projectPrefix = this.projectSlug ? `${this.projectSlug}/` : "";
if (projectPrefix && cleanName.startsWith(projectPrefix)) {
branchName = cleanName.slice(projectPrefix.length);
}
const phaseMatch = branchName.match(/^phase\/(\d+)-(.+)/);
if (phaseMatch) {
info.type = "phase";
info.phaseNumber = parseInt(phaseMatch[1], 10);
return info;
}
const milestoneMatch = cleanName.match(/^milestone\/(.+)/);
const milestoneMatch = branchName.match(/^milestone\/(.+)/);
if (milestoneMatch) {
info.type = "milestone";
info.milestone = milestoneMatch[1];
@@ -311,4 +328,27 @@ export class GitContext {
return commits;
}
detectProjectFromCommit(): string | null {
const commit = this.getLatestCiCommit();
if (commit?.ci?.project) return commit.ci.project;
const branches = this.getBranches();
for (const branch of branches) {
const projectMatch = branch.name.match(/^([a-z0-9-]+)\/(?:phase|milestone)\//);
if (projectMatch) return projectMatch[1];
}
return null;
}
isNfrMilestone(): boolean {
const commits = this.getRecentCommits(100);
for (const commit of commits) {
if (commit.type === "feat" && commit.ci) {
return false;
}
}
return true;
}
}