phasegate 0.135.0 → 0.137.0
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 +26 -0
- package/README.ja.md +7 -5
- package/README.md +7 -4
- package/docs/guide/cli-reference.md +3 -0
- package/docs/templates/agent-context/CLAUDE.md.template.md +29 -0
- package/docs/templates/ci/agent-context-refresh.yml +59 -0
- package/docs/templates/ci/aidlc-gate.yml +97 -0
- package/docs/templates/ci/consistency-check.yml +117 -0
- package/docs/templates/hooks/commit-msg +13 -0
- package/docs/templates/hooks/pre-commit +62 -0
- package/package.json +2 -1
- package/scripts/harness/ci-governance/application/dto/check-agent-context-input.ts +8 -0
- package/scripts/harness/ci-governance/application/dto/check-agent-context-output.ts +17 -0
- package/scripts/harness/ci-governance/application/dto/refresh-agent-context-input.ts +8 -0
- package/scripts/harness/ci-governance/application/dto/refresh-agent-context-output.ts +15 -0
- package/scripts/harness/ci-governance/application/dto/refresh-claude-md-input.ts +8 -0
- package/scripts/harness/ci-governance/application/dto/refresh-claude-md-output.ts +13 -0
- package/scripts/harness/ci-governance/application/usecases/check-agent-context-usecase.ts +48 -0
- package/scripts/harness/ci-governance/application/usecases/refresh-agent-context-usecase.ts +31 -0
- package/scripts/harness/ci-governance/application/usecases/refresh-claude-md-usecase.ts +73 -0
- package/scripts/harness/ci-governance/composition-root.ts +23 -1
- package/scripts/harness/ci-governance/domain/aggregates/ci-template.ts +1 -1
- package/scripts/harness/ci-governance/domain/ports/agent-context-document-port.ts +17 -0
- package/scripts/harness/ci-governance/domain/services/claude-md-composer.ts +39 -0
- package/scripts/harness/ci-governance/domain/services/template-generator.ts +1 -0
- package/scripts/harness/ci-governance/domain/types/template-type.ts +2 -1
- package/scripts/harness/ci-governance/infrastructure/adapters/agent-context-file-adapter.ts +55 -0
- package/scripts/harness/ci-governance/infrastructure/adapters/yaml-template-renderer-adapter.ts +16 -31
- package/scripts/harness/ci-governance/presentation/handlers/check-agent-context-handler.ts +33 -0
- package/scripts/harness/ci-governance/presentation/handlers/generate-ci-template-handler.ts +19 -1
- package/scripts/harness/ci-governance/presentation/handlers/refresh-agent-context-handler.ts +44 -0
- package/scripts/harness/ci-governance/presentation/handlers/refresh-claude-md-handler.ts +38 -0
- package/scripts/harness/main.ts +57 -8
- package/scripts/harness/setup/skill-deployer.ts +52 -2
- package/scripts/harness/traceability-model/domain/value-objects/work-item-frontmatter.ts +3 -1
- package/scripts/harness/validator-system/infrastructure/adapters/phase-dependency-phase-gate-policy-adapter.ts +4 -0
package/scripts/harness/main.ts
CHANGED
|
@@ -41,6 +41,7 @@ import type { SkillSet } from "./setup/skill-deployer.js";
|
|
|
41
41
|
import {
|
|
42
42
|
deployAgentSkillLinks,
|
|
43
43
|
deployCodexHooks,
|
|
44
|
+
deployCiWorkflows,
|
|
44
45
|
deployDesignDocs,
|
|
45
46
|
deployHookScripts,
|
|
46
47
|
deployHuskyCommitMsgHook,
|
|
@@ -89,7 +90,7 @@ Usage: phasegate <command> [options]
|
|
|
89
90
|
Setup:
|
|
90
91
|
init Initialize project: deploy skills + design docs + phasegate.config.json
|
|
91
92
|
(--name <project-name>, --preset <full|standard|minimal|custom>,
|
|
92
|
-
--skills <core|all>, --agent <claude|codex|both>, --with-husky, --yes)
|
|
93
|
+
--skills <core|all>, --agent <claude|codex|both>, --with-husky, --with-ci, --yes)
|
|
93
94
|
update-skills Re-deploy skills from current harness version
|
|
94
95
|
|
|
95
96
|
Commands:
|
|
@@ -122,8 +123,11 @@ Commands:
|
|
|
122
123
|
phasegate:complete-check Complete L2-L4 check (--json)
|
|
123
124
|
phasegate:impact-analysis Impact analysis for story (<storyId>, --json)
|
|
124
125
|
|
|
125
|
-
ci:generate-template Generate CI template (--preset <id>, --type <aidlc-gate|consistency-check|pre-commit>, --render, --json)
|
|
126
|
+
ci:generate-template Generate CI template (--preset <id>, --type <aidlc-gate|consistency-check|pre-commit|agent-context-refresh>, --render, --json)
|
|
126
127
|
ci:migrate-agents-md Migrate AGENTS.md (--dry-run, --validate-only, --json)
|
|
128
|
+
ci:auto-refresh-agent-context Refresh AGENTS.md / CLAUDE.md (--dry-run, --apply, --json)
|
|
129
|
+
refresh-claude-md Refresh CLAUDE.md standard sections (--dry-run, --apply, --json)
|
|
130
|
+
p2:check-agent-context Check AGENTS.md / CLAUDE.md freshness (--threshold-days <n>, --json)
|
|
127
131
|
ci:check-repetition Check error repetition (--code <errorCode>, --reset, --json)
|
|
128
132
|
baseline Create retrofit baseline snapshot (--dry-run, --force, --paths <glob,glob,...>, --json)
|
|
129
133
|
scaffold-design Scaffold a design doc (--unit <id>, --phase <logical|domain|uiux|unit-test|it-test>, --force, --json)
|
|
@@ -251,6 +255,7 @@ Options:
|
|
|
251
255
|
--skills <core|all> Skill set to deploy (default: "all")
|
|
252
256
|
--agent <claude|codex|both> Agent integration target (default: "claude")
|
|
253
257
|
--with-husky Install Husky pre-commit hooks
|
|
258
|
+
--with-ci Install GitHub Actions workflows
|
|
254
259
|
--yes Skip confirmation prompts
|
|
255
260
|
--help, -h Show this help`,
|
|
256
261
|
"update-skills": `Usage: phasegate update-skills [options]
|
|
@@ -344,6 +349,7 @@ Options:
|
|
|
344
349
|
aidlc-gate — AIDLC phase gate checks
|
|
345
350
|
consistency-check — Doc/code consistency checks
|
|
346
351
|
pre-commit — Pre-commit hook template
|
|
352
|
+
agent-context-refresh — AGENTS.md / CLAUDE.md refresh workflow
|
|
347
353
|
--render Render the template to stdout
|
|
348
354
|
--json Output in JSON format
|
|
349
355
|
|
|
@@ -636,7 +642,7 @@ async function main(): Promise<void> {
|
|
|
636
642
|
switch (command) {
|
|
637
643
|
// ── harness setup ──
|
|
638
644
|
case "init": {
|
|
639
|
-
const KNOWN_INIT_FLAGS = ["--name", "--preset", "--skills", "--agent", "--with-husky", "--yes"];
|
|
645
|
+
const KNOWN_INIT_FLAGS = ["--name", "--preset", "--skills", "--agent", "--with-husky", "--with-ci", "--yes"];
|
|
640
646
|
const flagError = validateKnownFlags(args, KNOWN_INIT_FLAGS);
|
|
641
647
|
if (flagError) {
|
|
642
648
|
console.error(flagError);
|
|
@@ -674,7 +680,8 @@ async function main(): Promise<void> {
|
|
|
674
680
|
claude: deployClaude,
|
|
675
681
|
codex: deployCodex,
|
|
676
682
|
});
|
|
677
|
-
const
|
|
683
|
+
const withCi = hasFlag(args, "--with-ci");
|
|
684
|
+
const configResult = await initHarnessConfig(rootDir, projectName, phasePreset, { ciEnabled: withCi });
|
|
678
685
|
const hooksResult = deployClaude
|
|
679
686
|
? await deployHookScripts(harnessRoot, rootDir)
|
|
680
687
|
: {
|
|
@@ -689,6 +696,7 @@ async function main(): Promise<void> {
|
|
|
689
696
|
const withHusky = hasFlag(args, "--with-husky");
|
|
690
697
|
const huskyResult = withHusky ? await deployHuskyHook(harnessRoot, rootDir) : null;
|
|
691
698
|
const huskyCommitMsgResult = withHusky ? await deployHuskyCommitMsgHook(harnessRoot, rootDir) : null;
|
|
699
|
+
const ciWorkflowResult = withCi ? await deployCiWorkflows(harnessRoot, rootDir) : null;
|
|
692
700
|
console.log(
|
|
693
701
|
`✓ Skills deployed to ${result.targetDir} (${result.deployedSkills.length} skills, set: ${skillSet})`,
|
|
694
702
|
);
|
|
@@ -753,6 +761,14 @@ async function main(): Promise<void> {
|
|
|
753
761
|
console.log(` .husky/commit-msg already exists, skipped`);
|
|
754
762
|
}
|
|
755
763
|
}
|
|
764
|
+
if (ciWorkflowResult !== null) {
|
|
765
|
+
if (ciWorkflowResult.copiedFiles.length > 0) {
|
|
766
|
+
console.log(`✓ CI workflows deployed (${ciWorkflowResult.copiedFiles.length} files)`);
|
|
767
|
+
}
|
|
768
|
+
for (const skipped of ciWorkflowResult.skippedFiles) {
|
|
769
|
+
console.log(` ${skipped} already exists, skipped`);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
756
772
|
console.log(`✓ Harness v${result.version} initialized (agent: ${agent})`);
|
|
757
773
|
console.log("");
|
|
758
774
|
console.log("Next steps:");
|
|
@@ -1199,7 +1215,7 @@ Examples:
|
|
|
1199
1215
|
phasegate ci:generate-template --preset strict --type pre-commit --render`);
|
|
1200
1216
|
process.exit(0);
|
|
1201
1217
|
}
|
|
1202
|
-
const mod = buildCiGovernance(rootDir);
|
|
1218
|
+
const mod = buildCiGovernance(rootDir, harnessRoot);
|
|
1203
1219
|
const presetId = parseFlag(args, "--preset") ?? "default";
|
|
1204
1220
|
const templateType = parseFlag(args, "--type") ?? "aidlc-gate";
|
|
1205
1221
|
const render = hasFlag(args, "--render");
|
|
@@ -1211,7 +1227,7 @@ Examples:
|
|
|
1211
1227
|
}
|
|
1212
1228
|
|
|
1213
1229
|
case "ci:migrate-agents-md": {
|
|
1214
|
-
const mod = buildCiGovernance(rootDir);
|
|
1230
|
+
const mod = buildCiGovernance(rootDir, harnessRoot);
|
|
1215
1231
|
const dryRun = hasFlag(args, "--dry-run");
|
|
1216
1232
|
const validateOnly = hasFlag(args, "--validate-only");
|
|
1217
1233
|
const format = json ? "json" : "human";
|
|
@@ -1221,8 +1237,41 @@ Examples:
|
|
|
1221
1237
|
break;
|
|
1222
1238
|
}
|
|
1223
1239
|
|
|
1240
|
+
case "ci:auto-refresh-agent-context": {
|
|
1241
|
+
const mod = buildCiGovernance(rootDir, harnessRoot);
|
|
1242
|
+
const dryRun = hasFlag(args, "--dry-run");
|
|
1243
|
+
const apply = hasFlag(args, "--apply");
|
|
1244
|
+
const format = json ? "json" : "human";
|
|
1245
|
+
const result = await mod.refreshAgentContextHandler.handle({ dryRun, apply, format });
|
|
1246
|
+
console.log(result.output);
|
|
1247
|
+
process.exit(result.exitCode);
|
|
1248
|
+
break;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
case "refresh-claude-md": {
|
|
1252
|
+
const mod = buildCiGovernance(rootDir, harnessRoot);
|
|
1253
|
+
const dryRun = hasFlag(args, "--dry-run");
|
|
1254
|
+
const apply = hasFlag(args, "--apply");
|
|
1255
|
+
const format = json ? "json" : "human";
|
|
1256
|
+
const result = await mod.refreshClaudeMdHandler.handle({ dryRun, apply, format });
|
|
1257
|
+
console.log(result.output);
|
|
1258
|
+
process.exit(result.exitCode);
|
|
1259
|
+
break;
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
case "p2:check-agent-context": {
|
|
1263
|
+
const mod = buildCiGovernance(rootDir, harnessRoot);
|
|
1264
|
+
const thresholdRaw = parseFlag(args, "--threshold-days");
|
|
1265
|
+
const thresholdDays = thresholdRaw === undefined ? undefined : Number(thresholdRaw);
|
|
1266
|
+
const format = json ? "json" : "human";
|
|
1267
|
+
const result = await mod.checkAgentContextHandler.handle({ thresholdDays, format });
|
|
1268
|
+
console.log(result.output);
|
|
1269
|
+
process.exit(result.exitCode);
|
|
1270
|
+
break;
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1224
1273
|
case "ci:check-repetition": {
|
|
1225
|
-
const mod = buildCiGovernance(rootDir);
|
|
1274
|
+
const mod = buildCiGovernance(rootDir, harnessRoot);
|
|
1226
1275
|
const errorCode = parseFlag(args, "--code") ?? "";
|
|
1227
1276
|
const reset = hasFlag(args, "--reset");
|
|
1228
1277
|
const format = json ? "json" : "human";
|
|
@@ -1233,7 +1282,7 @@ Examples:
|
|
|
1233
1282
|
}
|
|
1234
1283
|
|
|
1235
1284
|
case "baseline": {
|
|
1236
|
-
const mod = buildCiGovernance(rootDir);
|
|
1285
|
+
const mod = buildCiGovernance(rootDir, harnessRoot);
|
|
1237
1286
|
const dryRun = hasFlag(args, "--dry-run");
|
|
1238
1287
|
const force = hasFlag(args, "--force");
|
|
1239
1288
|
const pathsFlag = parseFlag(args, "--paths");
|
|
@@ -420,10 +420,15 @@ export async function deployHookScripts(harnessRoot: string, projectRoot: string
|
|
|
420
420
|
};
|
|
421
421
|
}
|
|
422
422
|
|
|
423
|
+
export interface InitHarnessConfigOptions {
|
|
424
|
+
ciEnabled?: boolean;
|
|
425
|
+
}
|
|
426
|
+
|
|
423
427
|
export async function initHarnessConfig(
|
|
424
428
|
projectRoot: string,
|
|
425
429
|
projectName: string,
|
|
426
430
|
phasePreset?: "full" | "standard" | "minimal" | "custom",
|
|
431
|
+
options: InitHarnessConfigOptions = {},
|
|
427
432
|
): Promise<{ created: boolean; path: string }> {
|
|
428
433
|
const configPath = join(projectRoot, HARNESS_CONFIG_FILE);
|
|
429
434
|
try {
|
|
@@ -461,6 +466,7 @@ export async function initHarnessConfig(
|
|
|
461
466
|
format: "json",
|
|
462
467
|
outputDir: "reports",
|
|
463
468
|
},
|
|
469
|
+
...(options.ciEnabled ? { ci: { enabled: true } } : {}),
|
|
464
470
|
};
|
|
465
471
|
|
|
466
472
|
await fs.writeFile(configPath, JSON.stringify(template, null, 2) + "\n", "utf-8");
|
|
@@ -532,6 +538,50 @@ export interface DeployHuskyHookResult {
|
|
|
532
538
|
path: string;
|
|
533
539
|
}
|
|
534
540
|
|
|
541
|
+
export interface DeployCiWorkflowsResult {
|
|
542
|
+
copiedFiles: string[];
|
|
543
|
+
skippedFiles: string[];
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
export async function deployCiWorkflows(harnessRoot: string, projectRoot: string): Promise<DeployCiWorkflowsResult> {
|
|
547
|
+
const copiedFiles: string[] = [];
|
|
548
|
+
const skippedFiles: string[] = [];
|
|
549
|
+
const workflows = [
|
|
550
|
+
{
|
|
551
|
+
relativeSource: join("docs", "templates", "ci", "aidlc-gate.yml"),
|
|
552
|
+
relativeTarget: join(".github", "workflows", "aidlc-gate.yml"),
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
relativeSource: join("docs", "templates", "ci", "consistency-check.yml"),
|
|
556
|
+
relativeTarget: join(".github", "workflows", "consistency-check.yml"),
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
relativeSource: join("docs", "templates", "ci", "agent-context-refresh.yml"),
|
|
560
|
+
relativeTarget: join(".github", "workflows", "agent-context-refresh.yml"),
|
|
561
|
+
},
|
|
562
|
+
];
|
|
563
|
+
|
|
564
|
+
await fs.mkdir(join(projectRoot, ".github", "workflows"), { recursive: true });
|
|
565
|
+
|
|
566
|
+
for (const workflow of workflows) {
|
|
567
|
+
const sourcePath = join(harnessRoot, workflow.relativeSource);
|
|
568
|
+
const targetPath = join(projectRoot, workflow.relativeTarget);
|
|
569
|
+
|
|
570
|
+
try {
|
|
571
|
+
await fs.access(targetPath);
|
|
572
|
+
skippedFiles.push(workflow.relativeTarget);
|
|
573
|
+
continue;
|
|
574
|
+
} catch {
|
|
575
|
+
// ファイルが存在しない場合のみコピーする
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
await fs.copyFile(sourcePath, targetPath);
|
|
579
|
+
copiedFiles.push(workflow.relativeTarget);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
return { copiedFiles, skippedFiles };
|
|
583
|
+
}
|
|
584
|
+
|
|
535
585
|
export async function deployHuskyHook(harnessRoot: string, projectRoot: string): Promise<DeployHuskyHookResult> {
|
|
536
586
|
const targetPath = join(projectRoot, ".husky", "pre-commit");
|
|
537
587
|
|
|
@@ -540,7 +590,7 @@ export async function deployHuskyHook(harnessRoot: string, projectRoot: string):
|
|
|
540
590
|
return { created: false, path: targetPath };
|
|
541
591
|
} catch {}
|
|
542
592
|
|
|
543
|
-
const sourcePath = join(harnessRoot, "templates", "
|
|
593
|
+
const sourcePath = join(harnessRoot, "docs", "templates", "hooks", "pre-commit");
|
|
544
594
|
await fs.mkdir(join(projectRoot, ".husky"), { recursive: true });
|
|
545
595
|
await fs.copyFile(sourcePath, targetPath);
|
|
546
596
|
await fs.chmod(targetPath, 0o755);
|
|
@@ -559,7 +609,7 @@ export async function deployHuskyCommitMsgHook(
|
|
|
559
609
|
return { created: false, path: targetPath };
|
|
560
610
|
} catch {}
|
|
561
611
|
|
|
562
|
-
const sourcePath = join(harnessRoot, "templates", "
|
|
612
|
+
const sourcePath = join(harnessRoot, "docs", "templates", "hooks", "commit-msg");
|
|
563
613
|
await fs.mkdir(join(projectRoot, ".husky"), { recursive: true });
|
|
564
614
|
await fs.copyFile(sourcePath, targetPath);
|
|
565
615
|
await fs.chmod(targetPath, 0o755);
|
|
@@ -13,7 +13,8 @@ export type WorkItemStatus =
|
|
|
13
13
|
| 'drafted'
|
|
14
14
|
| 'reflected'
|
|
15
15
|
| 'implemented'
|
|
16
|
-
| 'tested'
|
|
16
|
+
| 'tested'
|
|
17
|
+
| 'completed';
|
|
17
18
|
|
|
18
19
|
export interface WorkItemFrontmatter {
|
|
19
20
|
readonly id: string;
|
|
@@ -54,4 +55,5 @@ export const WORK_ITEM_STATUSES: ReadonlySet<WorkItemStatus> = new Set([
|
|
|
54
55
|
'reflected',
|
|
55
56
|
'implemented',
|
|
56
57
|
'tested',
|
|
58
|
+
'completed',
|
|
57
59
|
]);
|
|
@@ -12,6 +12,10 @@ export class PhaseDependencyPhaseGatePolicyAdapter implements PhaseGatePolicyPor
|
|
|
12
12
|
satisfied: boolean;
|
|
13
13
|
violations: readonly HarnessErrorLike[];
|
|
14
14
|
}> {
|
|
15
|
+
if (context.unitName.trim().length === 0) {
|
|
16
|
+
return { satisfied: true, violations: [] };
|
|
17
|
+
}
|
|
18
|
+
|
|
15
19
|
try {
|
|
16
20
|
// WI-085: paths config を phase-dependency-model に流入させる
|
|
17
21
|
const { createConfigFoundationModule } = await import('../../../config-foundation/composition-root.js');
|