phasegate 0.145.2 → 0.145.4

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.
@@ -8,7 +8,7 @@
8
8
  * 起動時に config-foundation で設定を解決し、他Unit に注入する(Cross-unit wiring)。
9
9
  */
10
10
 
11
- import { access, readFile as fsReadFile, readlink as fsReadlink, writeFile as fsWriteFile } from "node:fs/promises";
11
+ import { readFile as fsReadFile, readlink as fsReadlink, writeFile as fsWriteFile } from "node:fs/promises";
12
12
  import { dirname, join, resolve } from "node:path";
13
13
  import { createAdrFoundationModule } from "./adr-foundation/composition-root.js";
14
14
  import { createBiomeAstEngineModule } from "./biome-ast-engine/composition-root.js";
@@ -52,7 +52,6 @@ import {
52
52
  deployHuskyPrePushHook,
53
53
  deploySkills,
54
54
  getCategoryForSkill,
55
- getDeployedVersion,
56
55
  getHarnessVersion,
57
56
  initHarnessConfig,
58
57
  } from "./setup/skill-deployer.js";
@@ -78,15 +77,6 @@ function toTraceabilityModelOptions(resolvedConfig: HarnessConfigV2 | undefined)
78
77
  : undefined;
79
78
  }
80
79
 
81
- async function pathExists(path: string): Promise<boolean> {
82
- try {
83
- await access(path);
84
- return true;
85
- } catch {
86
- return false;
87
- }
88
- }
89
-
90
80
  interface PackageJsonDocument {
91
81
  readonly [key: string]: unknown;
92
82
  readonly dependencies?: unknown;
@@ -149,11 +139,11 @@ Setup:
149
139
  init Initialize project: deploy skills + design docs + phasegate.config.json
150
140
  (--name <project-name>, --preset <full|standard|minimal|custom>,
151
141
  --skills <core|all>, --agent <claude|codex|both>, --with-husky, --with-ci, --yes)
152
- update-skills Re-deploy skills from current harness version
142
+ update-skills Alias for reconcile (kept for compatibility)
153
143
  doctor Diagnose silent installation failures (--json, --strict, --report-out <path>)
154
144
  install Install phasegate managed files (--dry-run|--apply, --force)
155
- uninstall Uninstall phasegate managed files (stub until WI-147)
156
- reconcile Reconcile phasegate managed files (stub until WI-148)
145
+ uninstall Uninstall phasegate managed files (--dry-run|--apply, --force)
146
+ reconcile Reconcile phasegate managed files (--dry-run|--apply, --force)
157
147
 
158
148
  Commands:
159
149
  enable-feature <name> Enable a harness feature
@@ -365,11 +355,14 @@ Options:
365
355
  --help, -h Show this help`,
366
356
  "update-skills": `Usage: phasegate update-skills [options]
367
357
 
368
- Redeploy skills in .claude/skills/ from the installed phasegate version. WARNING: overwrites existing skill files.
358
+ Compatibility alias for phasegate reconcile. WARNING: this command no longer redeploys skills directly.
359
+ It updates PhaseGate-managed files from the installed manifest.
369
360
 
370
361
  Options:
371
- --skills <core|all> Skill set to deploy
372
- --agent <claude|codex|both> Agent integration target
362
+ --dry-run Preview target actions without writing (default)
363
+ --apply Write reconcile results and manifest
364
+ --force Force ai-assisted/manual targets after backing up existing files
365
+ --json Output machine-readable JSON
373
366
  --help, -h Show this help`,
374
367
  install: `Usage: phasegate install [options]
375
368
 
@@ -381,6 +374,16 @@ Options:
381
374
  --force Force ai-assisted/manual targets after backing up existing files
382
375
  --json Output machine-readable JSON
383
376
  --help, -h Show this help`,
377
+ reconcile: `Usage: phasegate reconcile [options]
378
+
379
+ Reconcile PhaseGate-managed files with the current bundled templates.
380
+
381
+ Options:
382
+ --dry-run Preview target actions without writing (default)
383
+ --apply Write managed updates and manifest
384
+ --force Force ai-assisted/manual targets after backing up existing files
385
+ --json Output machine-readable JSON
386
+ --help, -h Show this help`,
384
387
  validate: `Usage: phasegate validate [options]
385
388
 
386
389
  Run validators against the project. Without --layer, runs all enabled validator layers (L2/L3/L4).
@@ -771,6 +774,9 @@ async function main(): Promise<void> {
771
774
  switch (command) {
772
775
  // ── harness setup ──
773
776
  case "init": {
777
+ console.log("Warning: phasegate init is deprecated and will be removed in v1.0.");
778
+ console.log("Use phasegate install for idempotent setup with structured merge.");
779
+ console.log("Existing legacy init behavior is preserved. Run phasegate doctor to verify installation state.");
774
780
  const KNOWN_INIT_FLAGS = ["--name", "--preset", "--skills", "--agent", "--with-husky", "--with-ci", "--yes"];
775
781
  const flagError = validateKnownFlags(args, KNOWN_INIT_FLAGS);
776
782
  if (flagError) {
@@ -989,41 +995,28 @@ async function main(): Promise<void> {
989
995
  }
990
996
 
991
997
  case "update-skills": {
992
- const deployed = await getDeployedVersion(rootDir);
993
- const current = await getHarnessVersion(harnessRoot);
994
- const previousSkillSet: SkillSet = deployed?.skillSet ?? "all";
995
- const overrideSkillSet = parseFlag(args, "--skills");
996
- const updateSkillSet: SkillSet =
997
- overrideSkillSet === "core" || overrideSkillSet === "all" ? overrideSkillSet : previousSkillSet;
998
- if (deployed) {
999
- console.log(`Previously deployed: v${deployed.version} (${deployed.deployedAt}, set: ${previousSkillSet})`);
1000
- } else {
1001
- console.log("No previously deployed skills found");
998
+ const KNOWN_RECONCILE_FLAGS = ["--dry-run", "--apply", "--force", "--json"];
999
+ const flagError = validateKnownFlags(args, KNOWN_RECONCILE_FLAGS);
1000
+ if (flagError) {
1001
+ console.error(flagError);
1002
+ process.exit(2);
1002
1003
  }
1003
- console.log(`Current harness version: v${current}`);
1004
- const result = await deploySkills(harnessRoot, rootDir, updateSkillSet);
1005
- const shouldLinkClaude =
1006
- (await pathExists(join(rootDir, ".claude", "settings.json"))) ||
1007
- (await pathExists(join(rootDir, ".claude", "skills")));
1008
- const shouldLinkCodex =
1009
- (await pathExists(join(rootDir, ".codex", "hooks.json"))) ||
1010
- (await pathExists(join(rootDir, ".codex", "skills")));
1011
- await deployAgentSkillLinks(rootDir, {
1012
- claude: shouldLinkClaude,
1013
- codex: shouldLinkCodex,
1004
+ const apply = hasFlag(args, "--apply");
1005
+ const dryRun = hasFlag(args, "--dry-run") || !apply;
1006
+ const mod = createInstallationModule();
1007
+ const phasegateVersion = await getHarnessVersion(harnessRoot);
1008
+ const result = await mod.reconcileHandler.execute({
1009
+ projectRoot: rootDir,
1010
+ harnessRoot,
1011
+ phasegateVersion,
1012
+ dryRun,
1013
+ apply,
1014
+ force: hasFlag(args, "--force"),
1015
+ json,
1014
1016
  });
1015
- await saveInstallationManifest(rootDir, current, [
1016
- ...result.deployedSkills.map((skill) => ({
1017
- path: join("skills", skill),
1018
- mode: "created" as const,
1019
- contentForHash: `${current}:${skill}`,
1020
- })),
1021
- await createFileManifestRecord(rootDir, join("skills", ".harness-version")),
1022
- shouldLinkClaude ? await createSymlinkManifestRecord(rootDir, join(".claude", "skills")) : null,
1023
- shouldLinkCodex ? await createSymlinkManifestRecord(rootDir, join(".codex", "skills")) : null,
1024
- ]);
1025
- console.log(`✓ Skills updated (${result.deployedSkills.length} skills redeployed, set: ${updateSkillSet})`);
1026
- process.exit(0);
1017
+ if (!json) console.log("phasegate update-skills is deprecated; running phasegate reconcile.");
1018
+ console.log(result.stdout);
1019
+ process.exit(result.exitCode);
1027
1020
  break;
1028
1021
  }
1029
1022
 
@@ -1068,14 +1061,50 @@ async function main(): Promise<void> {
1068
1061
  }
1069
1062
 
1070
1063
  case "uninstall": {
1071
- console.error("Not yet implemented: phasegate uninstall is owned by WI-147");
1072
- process.exit(2);
1064
+ const KNOWN_UNINSTALL_FLAGS = ["--dry-run", "--apply", "--force", "--json"];
1065
+ const flagError = validateKnownFlags(args, KNOWN_UNINSTALL_FLAGS);
1066
+ if (flagError) {
1067
+ console.error(flagError);
1068
+ process.exit(2);
1069
+ }
1070
+ const apply = hasFlag(args, "--apply");
1071
+ const dryRun = hasFlag(args, "--dry-run") || !apply;
1072
+ const mod = createInstallationModule();
1073
+ const result = await mod.uninstallHandler.execute({
1074
+ projectRoot: rootDir,
1075
+ harnessRoot,
1076
+ dryRun,
1077
+ apply,
1078
+ force: hasFlag(args, "--force"),
1079
+ json,
1080
+ });
1081
+ console.log(result.stdout);
1082
+ process.exit(result.exitCode);
1073
1083
  break;
1074
1084
  }
1075
1085
 
1076
1086
  case "reconcile": {
1077
- console.error("Not yet implemented: phasegate reconcile is owned by WI-148");
1078
- process.exit(2);
1087
+ const KNOWN_RECONCILE_FLAGS = ["--dry-run", "--apply", "--force", "--json"];
1088
+ const flagError = validateKnownFlags(args, KNOWN_RECONCILE_FLAGS);
1089
+ if (flagError) {
1090
+ console.error(flagError);
1091
+ process.exit(2);
1092
+ }
1093
+ const apply = hasFlag(args, "--apply");
1094
+ const dryRun = hasFlag(args, "--dry-run") || !apply;
1095
+ const mod = createInstallationModule();
1096
+ const phasegateVersion = await getHarnessVersion(harnessRoot);
1097
+ const result = await mod.reconcileHandler.execute({
1098
+ projectRoot: rootDir,
1099
+ harnessRoot,
1100
+ phasegateVersion,
1101
+ dryRun,
1102
+ apply,
1103
+ force: hasFlag(args, "--force"),
1104
+ json,
1105
+ });
1106
+ console.log(result.stdout);
1107
+ process.exit(result.exitCode);
1079
1108
  break;
1080
1109
  }
1081
1110