phasegate 0.155.0 → 0.157.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 +6 -0
- package/docs/guide/cli-reference.md +2 -2
- package/docs/guide/troubleshooting.md +2 -0
- package/package.json +1 -1
- package/scripts/harness/installation/application/usecases/run-doctor-diagnostics.ts +42 -1
- package/scripts/harness/installation/presentation/cli/doctor-handler.ts +6 -1
- package/scripts/harness/installation/presentation/formatters/diagnostic-report-formatter.ts +35 -1
- package/scripts/harness/main.ts +29 -5
- package/skills/phasegate-config-doctor/SKILL.md +1 -0
- package/skills/phasegate-toolkit-guide/SKILL.md +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.157.0] - 2026-05-13
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **WI-179 — scoped-out doctor repair guidance** — suppresses `repairHint` and `suggestedSkill` for unselected-agent `scopedOutFindings`, adds explicit repair applicability markers, and updates CLI/troubleshooting/skill guidance so scoped doctor output is harder to misread as repair work.
|
|
15
|
+
|
|
10
16
|
## [0.154.0] - 2026-05-13
|
|
11
17
|
|
|
12
18
|
### Added
|
|
@@ -24,7 +24,7 @@ Command names in this document are split into three surfaces:
|
|
|
24
24
|
|---|---|
|
|
25
25
|
| `init --name <name>` | Legacy-compatible bootstrap for new projects: deploy skills, generate config, and optionally add hooks/CI. Options: `--preset <full\|standard\|minimal\|custom>`, `--skills <core\|all>`, `--agent <claude\|codex\|both>`, `--workflow <standard\|strict>`, `--with-husky`, `--with-ci`, `--yes`. |
|
|
26
26
|
| `install --dry-run` / `--apply` | Idempotently merge PhaseGate into an existing project, preserve user content, add package scripts/devDependency, create selected `AGENTS.md` / `CLAUDE.md` managed sections, and write `.phasegate/manifest.json`. `--agent <claude\|codex\|both>`, `--skills <core\|all>`, and `--workflow <standard\|strict>` affect rendered agent context; `--force` replaces managed targets after backup. |
|
|
27
|
-
| `doctor` | Diagnose silent or partial installations and report repair hints (`--json`, `--strict`, `--report-out <path>`). `--report-out` writes exactly to the supplied path, not to `reporting.outputDir`. |
|
|
27
|
+
| `doctor` | Diagnose silent or partial installations and report repair hints (`--json`, `--strict`, `--agent <claude\|codex\|both>`, `--report-out <path>`). `--agent` defaults to `both`; single-agent scopes keep shared targets applicable and mark the other agent's findings as not applicable. `--report-out` writes exactly to the supplied path, not to `reporting.outputDir`. |
|
|
28
28
|
| `uninstall --dry-run` / `--apply` | Remove PhaseGate-managed files and managed blocks using `.phasegate/manifest.json`; `--force` handles managed conflict cases. |
|
|
29
29
|
| `reconcile --dry-run` / `--apply` | Update PhaseGate-managed files to current package templates and refresh manifest hashes; `--force` allows managed-file replacement with backup. |
|
|
30
30
|
| `setup:agent` | Agent-readable setup planner and optional apply path. Options: `--intent <minimal\|recommended\|strict\|ci-only\|agent-hooks\|retrofit>`, `--agent <claude\|codex\|both>`, `--workflow <standard\|strict>`, `--with-husky`, `--with-ci`, `--dry-run`, `--apply`, `--json`. <!-- @work-item-id WI-172 --> |
|
|
@@ -40,7 +40,7 @@ Command names in this document are split into three surfaces:
|
|
|
40
40
|
|
|
41
41
|
<!-- @work-item-id WI-158 -->
|
|
42
42
|
|
|
43
|
-
Setup lifecycle commands support JSON for automation where shown by help: `install --json`, `reconcile --json`, `uninstall --json`, and `doctor --json`. `doctor --report-out <path>` persists the doctor JSON payload to that exact path. Relative paths are resolved from the project root; absolute paths are used as-is.
|
|
43
|
+
Setup lifecycle commands support JSON for automation where shown by help: `install --json`, `reconcile --json`, `uninstall --json`, and `doctor --json`. `doctor --agent claude --json` and `doctor --agent codex --json` include `scope` and `scopedOutFindings` so agents can distinguish selected-agent readiness from full-install diagnostics. Scoped-out findings suppress immediate repair guidance with `repairHint: null`, `suggestedSkill: null`, and `repairHintApplicability: "only-if-agent-selected"`. `doctor --report-out <path>` persists the doctor JSON payload to that exact path. Relative paths are resolved from the project root; absolute paths are used as-is. <!-- @work-item-id WI-178, WI-179 -->
|
|
44
44
|
|
|
45
45
|
This is separate from `reporting.outputDir`. The configured report directory is used by phase-dependency / phase-gate reporting, while regression-suite result files are fixed under `reports/regression/` and status/drift JSON is emitted to stdout.
|
|
46
46
|
|
|
@@ -63,6 +63,8 @@ The planner output is intentionally agent-readable: detected state, questions, p
|
|
|
63
63
|
|
|
64
64
|
`doctor` green means the local managed setup is consistent for the inspected targets. It does not prove user-level Codex feature flags, hosted GitHub Actions execution, npm registry state, or team policy acceptance.
|
|
65
65
|
|
|
66
|
+
By default, `phasegate doctor` inspects the full Claude + Codex + shared setup. For a deliberate single-agent setup, use `phasegate doctor --agent claude --json` or `phasegate doctor --agent codex --json`. Single-agent reports keep shared targets applicable and place the unselected agent's findings under `scopedOutFindings` with `applicability: "not-applicable"`; those findings are explanatory, not repair targets for the selected agent. Their `repairHint` and `suggestedSkill` fields are intentionally `null`; `repairHintApplicability: "only-if-agent-selected"` means the repair guidance matters only if the user chooses that agent. <!-- @work-item-id WI-178, WI-179 -->
|
|
67
|
+
|
|
66
68
|
Check `plan.completeness` in `setup:agent --json`:
|
|
67
69
|
|
|
68
70
|
- `configured`: PhaseGate found local evidence.
|
package/package.json
CHANGED
|
@@ -1,22 +1,38 @@
|
|
|
1
1
|
// @unit installation
|
|
2
2
|
// @layer application
|
|
3
3
|
// @work-item-id WI-145
|
|
4
|
+
// @work-item-id WI-178
|
|
4
5
|
|
|
5
6
|
import { DiagnosticReport } from "../../domain/diagnostic-report.js";
|
|
7
|
+
import type { CheckId } from "../../domain/check-id.js";
|
|
8
|
+
import type { DiagnosticFinding } from "../../domain/diagnostic-finding.js";
|
|
6
9
|
import type { HeuristicCheck } from "../../domain/ports/heuristic-check.js";
|
|
7
10
|
import type { FileInspectorPort } from "../ports/file-inspector-port.js";
|
|
8
11
|
import type { ManifestRepositoryPort } from "../ports/manifest-repository-port.js";
|
|
9
12
|
|
|
13
|
+
export type DoctorAgentScope = "claude" | "codex" | "both";
|
|
14
|
+
|
|
15
|
+
export interface ScopedOutDiagnosticFinding {
|
|
16
|
+
readonly finding: DiagnosticFinding;
|
|
17
|
+
readonly scopeReason: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
10
20
|
export interface RunDoctorDiagnosticsInput {
|
|
11
21
|
readonly projectRoot: string;
|
|
12
22
|
readonly strict: boolean;
|
|
23
|
+
readonly agent?: DoctorAgentScope;
|
|
13
24
|
}
|
|
14
25
|
|
|
15
26
|
export interface RunDoctorDiagnosticsOutput {
|
|
16
27
|
readonly report: DiagnosticReport;
|
|
28
|
+
readonly agent: DoctorAgentScope;
|
|
29
|
+
readonly scopedOutFindings: readonly ScopedOutDiagnosticFinding[];
|
|
17
30
|
readonly exitCode: number;
|
|
18
31
|
}
|
|
19
32
|
|
|
33
|
+
const CLAUDE_ONLY_CHECKS = new Set<CheckId>(["claude-hook-missing", "claude-skills-symlink"]);
|
|
34
|
+
const CODEX_ONLY_CHECKS = new Set<CheckId>(["codex-hook-missing", "codex-skills-symlink"]);
|
|
35
|
+
|
|
20
36
|
export class RunDoctorDiagnosticsUseCase {
|
|
21
37
|
constructor(
|
|
22
38
|
private readonly checks: readonly HeuristicCheck[],
|
|
@@ -25,17 +41,42 @@ export class RunDoctorDiagnosticsUseCase {
|
|
|
25
41
|
) {}
|
|
26
42
|
|
|
27
43
|
async execute(input: RunDoctorDiagnosticsInput): Promise<RunDoctorDiagnosticsOutput> {
|
|
44
|
+
const agent = input.agent ?? "both";
|
|
28
45
|
await this.manifestRepository.load(input.projectRoot).catch(() => null);
|
|
29
|
-
const
|
|
46
|
+
const rawFindings = (await Promise.all(
|
|
30
47
|
this.checks.map((check) => check.run(input.projectRoot, this.inspector)),
|
|
31
48
|
)).filter((finding) => finding !== null);
|
|
49
|
+
const { findings, scopedOutFindings } = this.applyAgentScope(rawFindings, agent);
|
|
32
50
|
const report = DiagnosticReport.create(findings);
|
|
33
51
|
return {
|
|
34
52
|
report,
|
|
53
|
+
agent,
|
|
54
|
+
scopedOutFindings,
|
|
35
55
|
exitCode: this.decideExitCode(report, input.strict),
|
|
36
56
|
};
|
|
37
57
|
}
|
|
38
58
|
|
|
59
|
+
private applyAgentScope(
|
|
60
|
+
findings: readonly DiagnosticFinding[],
|
|
61
|
+
agent: DoctorAgentScope,
|
|
62
|
+
): { readonly findings: readonly DiagnosticFinding[]; readonly scopedOutFindings: readonly ScopedOutDiagnosticFinding[] } {
|
|
63
|
+
if (agent === "both") return { findings, scopedOutFindings: [] };
|
|
64
|
+
const scopedOutChecks = agent === "claude" ? CODEX_ONLY_CHECKS : CLAUDE_ONLY_CHECKS;
|
|
65
|
+
const applicable: DiagnosticFinding[] = [];
|
|
66
|
+
const scopedOut: ScopedOutDiagnosticFinding[] = [];
|
|
67
|
+
for (const finding of findings) {
|
|
68
|
+
if (scopedOutChecks.has(finding.checkId)) {
|
|
69
|
+
scopedOut.push({
|
|
70
|
+
finding,
|
|
71
|
+
scopeReason: `${finding.checkId} belongs to an unselected agent for doctor --agent ${agent}.`,
|
|
72
|
+
});
|
|
73
|
+
} else {
|
|
74
|
+
applicable.push(finding);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return { findings: applicable, scopedOutFindings: scopedOut };
|
|
78
|
+
}
|
|
79
|
+
|
|
39
80
|
private decideExitCode(report: DiagnosticReport, strict: boolean): number {
|
|
40
81
|
if (report.hasRedFlag()) return 1;
|
|
41
82
|
if (strict && report.hasWarning()) return 1;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// @unit installation
|
|
2
2
|
// @layer presentation
|
|
3
3
|
// @work-item-id WI-145
|
|
4
|
+
// @work-item-id WI-178
|
|
4
5
|
|
|
5
6
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
6
7
|
import { dirname, isAbsolute, join } from "node:path";
|
|
7
|
-
import type { RunDoctorDiagnosticsUseCase } from "../../application/usecases/run-doctor-diagnostics.js";
|
|
8
|
+
import type { DoctorAgentScope, RunDoctorDiagnosticsUseCase } from "../../application/usecases/run-doctor-diagnostics.js";
|
|
8
9
|
import { DiagnosticReportFormatter } from "../formatters/diagnostic-report-formatter.js";
|
|
9
10
|
|
|
10
11
|
export interface DoctorHandlerInput {
|
|
@@ -13,6 +14,7 @@ export interface DoctorHandlerInput {
|
|
|
13
14
|
readonly json: boolean;
|
|
14
15
|
readonly reportOut: string | null;
|
|
15
16
|
readonly phasegateVersion: string;
|
|
17
|
+
readonly agent?: DoctorAgentScope;
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
export interface DoctorHandlerOutput {
|
|
@@ -30,9 +32,12 @@ export class DoctorHandler {
|
|
|
30
32
|
const result = await this.useCase.execute({
|
|
31
33
|
projectRoot: input.projectRoot,
|
|
32
34
|
strict: input.strict,
|
|
35
|
+
agent: input.agent,
|
|
33
36
|
});
|
|
34
37
|
const formatInput = {
|
|
35
38
|
report: result.report,
|
|
39
|
+
agent: result.agent,
|
|
40
|
+
scopedOutFindings: result.scopedOutFindings,
|
|
36
41
|
phasegateVersion: input.phasegateVersion,
|
|
37
42
|
projectRoot: input.projectRoot,
|
|
38
43
|
exitCode: result.exitCode,
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
// @unit installation
|
|
2
2
|
// @layer presentation
|
|
3
3
|
// @work-item-id WI-145
|
|
4
|
+
// @work-item-id WI-178
|
|
5
|
+
// @work-item-id WI-179
|
|
4
6
|
|
|
7
|
+
import type { DoctorAgentScope, ScopedOutDiagnosticFinding } from "../../application/usecases/run-doctor-diagnostics.js";
|
|
5
8
|
import type { DiagnosticReport } from "../../domain/diagnostic-report.js";
|
|
6
9
|
|
|
7
10
|
export interface DiagnosticReportFormatterInput {
|
|
8
11
|
readonly report: DiagnosticReport;
|
|
12
|
+
readonly agent: DoctorAgentScope;
|
|
13
|
+
readonly scopedOutFindings: readonly ScopedOutDiagnosticFinding[];
|
|
9
14
|
readonly phasegateVersion: string;
|
|
10
15
|
readonly projectRoot: string;
|
|
11
16
|
readonly exitCode: number;
|
|
@@ -18,8 +23,27 @@ export class DiagnosticReportFormatter {
|
|
|
18
23
|
schemaVersion: "1.0",
|
|
19
24
|
phasegateVersion: input.phasegateVersion,
|
|
20
25
|
projectRoot: input.projectRoot,
|
|
26
|
+
scope: {
|
|
27
|
+
agent: input.agent,
|
|
28
|
+
description: scopeDescription(input.agent),
|
|
29
|
+
},
|
|
21
30
|
overallStatus: input.report.overallStatus,
|
|
22
|
-
findings: input.report.findings.map((finding) =>
|
|
31
|
+
findings: input.report.findings.map((finding) => ({
|
|
32
|
+
...finding.toJSON(),
|
|
33
|
+
applicability: "applicable",
|
|
34
|
+
repairHintApplicability: "applicable",
|
|
35
|
+
})),
|
|
36
|
+
scopedOutFindings: input.scopedOutFindings.map(({ finding, scopeReason }) => {
|
|
37
|
+
const json = finding.toJSON();
|
|
38
|
+
return {
|
|
39
|
+
...json,
|
|
40
|
+
repairHint: null,
|
|
41
|
+
suggestedSkill: null,
|
|
42
|
+
applicability: "not-applicable",
|
|
43
|
+
repairHintApplicability: "only-if-agent-selected",
|
|
44
|
+
scopeReason,
|
|
45
|
+
};
|
|
46
|
+
}),
|
|
23
47
|
exitCode: input.exitCode,
|
|
24
48
|
},
|
|
25
49
|
null,
|
|
@@ -31,6 +55,7 @@ export class DiagnosticReportFormatter {
|
|
|
31
55
|
const lines = [
|
|
32
56
|
`phasegate doctor v${input.phasegateVersion}`,
|
|
33
57
|
`Project: ${input.projectRoot}`,
|
|
58
|
+
`Scope: ${input.agent} (${scopeDescription(input.agent)})`,
|
|
34
59
|
"",
|
|
35
60
|
];
|
|
36
61
|
for (const finding of input.report.findings) {
|
|
@@ -47,7 +72,16 @@ export class DiagnosticReportFormatter {
|
|
|
47
72
|
const redCount = input.report.findings.filter((finding) => finding.severity === "red").length;
|
|
48
73
|
const warnCount = input.report.findings.filter((finding) => finding.severity === "warn").length;
|
|
49
74
|
lines.push(`Status: ${input.report.overallStatus.toUpperCase()} (${input.report.findings.length} findings: ${redCount} red, ${warnCount} warn)`);
|
|
75
|
+
if (input.scopedOutFindings.length > 0) {
|
|
76
|
+
lines.push(`Scoped out: ${input.scopedOutFindings.length} informational findings not applicable to --agent ${input.agent}; not repair targets for this scope.`);
|
|
77
|
+
}
|
|
50
78
|
lines.push(`Exit: ${input.exitCode}`);
|
|
51
79
|
return lines.join("\n");
|
|
52
80
|
}
|
|
53
81
|
}
|
|
82
|
+
|
|
83
|
+
function scopeDescription(agent: DoctorAgentScope): string {
|
|
84
|
+
if (agent === "claude") return "Claude Code and shared setup targets; Codex-only findings are not applicable.";
|
|
85
|
+
if (agent === "codex") return "Codex and shared setup targets; Claude-only findings are not applicable.";
|
|
86
|
+
return "Full setup diagnostics for Claude, Codex, and shared targets.";
|
|
87
|
+
}
|
package/scripts/harness/main.ts
CHANGED
|
@@ -152,7 +152,7 @@ Setup:
|
|
|
152
152
|
--skills <core|all>, --agent <claude|codex|both>, --workflow <standard|strict>,
|
|
153
153
|
--with-husky, --with-ci, --yes)
|
|
154
154
|
update-skills Alias for reconcile (kept for compatibility)
|
|
155
|
-
doctor Diagnose silent installation failures (--json, --strict, --report-out <path>)
|
|
155
|
+
doctor Diagnose silent installation failures (--json, --strict, --agent <claude|codex|both>, --report-out <path>)
|
|
156
156
|
scaffold-wi <unit> <type> Create docs/inception/{unit}/WI-XXX/description.md
|
|
157
157
|
emit-agent-rules Print AGENTS.md / CLAUDE.md WI workflow rules block
|
|
158
158
|
install Install phasegate managed files (--dry-run|--apply, --force)
|
|
@@ -772,6 +772,16 @@ function parseAgentTarget(value: string | undefined, fallback: AgentTarget = "bo
|
|
|
772
772
|
return fallback;
|
|
773
773
|
}
|
|
774
774
|
|
|
775
|
+
function parseRequiredAgentTarget(value: string | undefined, fallback: AgentTarget = "both"): AgentTarget | null {
|
|
776
|
+
if (value === undefined) return fallback;
|
|
777
|
+
if (value === "claude" || value === "codex" || value === "both") return value;
|
|
778
|
+
return null;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
function doctorValidationCommand(agent: AgentTarget): string {
|
|
782
|
+
return agent === "both" ? "phasegate doctor" : `phasegate doctor --agent ${agent}`;
|
|
783
|
+
}
|
|
784
|
+
|
|
775
785
|
function parseSetupIntent(value: string | undefined): SetupIntent {
|
|
776
786
|
if (
|
|
777
787
|
value === "minimal" ||
|
|
@@ -863,6 +873,7 @@ function buildSetupCompleteness(input: {
|
|
|
863
873
|
}): readonly SetupCompletenessEntry[] {
|
|
864
874
|
const includeClaude = input.agent === "claude" || input.agent === "both";
|
|
865
875
|
const includeCodex = input.agent === "codex" || input.agent === "both";
|
|
876
|
+
const doctorCommand = doctorValidationCommand(input.agent);
|
|
866
877
|
const agentHooksConfigured = (!includeClaude || input.checks.claudeSettings) && (!includeCodex || input.checks.codexHooks);
|
|
867
878
|
const agentContextConfigured = (!includeClaude || input.checks.claudeMd) && (!includeCodex || input.checks.agentsMd);
|
|
868
879
|
const entries: SetupCompletenessEntry[] = [
|
|
@@ -872,7 +883,7 @@ function buildSetupCompleteness(input: {
|
|
|
872
883
|
configured: input.checks.packageJson && input.checks.phasegateConfig,
|
|
873
884
|
configuredEvidence: "package.json and phasegate.config.json are present.",
|
|
874
885
|
plannedEvidence: "setup:agent will create or merge package.json scripts and phasegate.config.json.",
|
|
875
|
-
nextAction:
|
|
886
|
+
nextAction: `Run setup:agent --apply, then ${doctorCommand}.`,
|
|
876
887
|
}),
|
|
877
888
|
setupCompletenessEntry({
|
|
878
889
|
area: "agent-hooks",
|
|
@@ -922,7 +933,7 @@ function buildSetupCompleteness(input: {
|
|
|
922
933
|
configured: input.checks.packageJson && input.checks.phasegateConfig,
|
|
923
934
|
configuredEvidence: "Local validation commands can be run against the configured project.",
|
|
924
935
|
plannedEvidence: "Validation commands are planned after setup apply.",
|
|
925
|
-
nextAction:
|
|
936
|
+
nextAction: `Run ${doctorCommand}, phasegate phasegate:check-ready, and phasegate validate --layer L2 --format human.`,
|
|
926
937
|
}),
|
|
927
938
|
];
|
|
928
939
|
|
|
@@ -994,6 +1005,7 @@ function buildAgentReadiness(input: {
|
|
|
994
1005
|
}): readonly AgentReadinessEntry[] {
|
|
995
1006
|
const includeClaude = input.agent === "claude" || input.agent === "both";
|
|
996
1007
|
const includeCodex = input.agent === "codex" || input.agent === "both";
|
|
1008
|
+
const doctorCommand = doctorValidationCommand(input.agent);
|
|
997
1009
|
const sharedConfigured =
|
|
998
1010
|
input.checks.packageJson &&
|
|
999
1011
|
input.checks.phasegateConfig &&
|
|
@@ -1045,7 +1057,7 @@ function buildAgentReadiness(input: {
|
|
|
1045
1057
|
plannedEvidence: [
|
|
1046
1058
|
"setup:agent will create or refresh package scripts, phasegate.config.json, skills, and selected Husky/CI targets.",
|
|
1047
1059
|
],
|
|
1048
|
-
nextAction:
|
|
1060
|
+
nextAction: `Run setup:agent --apply, then ${doctorCommand}, phasegate phasegate:check-ready, and phasegate validate --layer L2 --format human.`,
|
|
1049
1061
|
risk: input.withCi ? "A hosted CI run remains an external manual check." : undefined,
|
|
1050
1062
|
}),
|
|
1051
1063
|
];
|
|
@@ -1103,7 +1115,7 @@ async function buildAgentSetupPlan(rootDir: string, input: {
|
|
|
1103
1115
|
"Backups are written under .phasegate/backups when force is used on changed managed files.",
|
|
1104
1116
|
],
|
|
1105
1117
|
validation: [
|
|
1106
|
-
|
|
1118
|
+
doctorValidationCommand(input.agent),
|
|
1107
1119
|
"phasegate phasegate:check-ready",
|
|
1108
1120
|
"phasegate validate --layer L2 --format human",
|
|
1109
1121
|
],
|
|
@@ -1728,6 +1740,17 @@ async function main(): Promise<void> {
|
|
|
1728
1740
|
}
|
|
1729
1741
|
|
|
1730
1742
|
case "doctor": {
|
|
1743
|
+
const KNOWN_DOCTOR_FLAGS = ["--json", "--strict", "--agent", "--report-out"];
|
|
1744
|
+
const flagError = validateKnownFlags(args, KNOWN_DOCTOR_FLAGS);
|
|
1745
|
+
if (flagError) {
|
|
1746
|
+
console.error(flagError);
|
|
1747
|
+
process.exit(2);
|
|
1748
|
+
}
|
|
1749
|
+
const agent = parseRequiredAgentTarget(parseFlag(args, "--agent"), "both");
|
|
1750
|
+
if (agent === null) {
|
|
1751
|
+
console.error(`Invalid --agent value: "${parseFlag(args, "--agent")}". Use "claude", "codex", or "both".`);
|
|
1752
|
+
process.exit(2);
|
|
1753
|
+
}
|
|
1731
1754
|
const mod = createInstallationModule();
|
|
1732
1755
|
const phasegateVersion = await getHarnessVersion(harnessRoot);
|
|
1733
1756
|
const result = await mod.doctorHandler.execute({
|
|
@@ -1736,6 +1759,7 @@ async function main(): Promise<void> {
|
|
|
1736
1759
|
json,
|
|
1737
1760
|
reportOut: parseFlag(args, "--report-out") ?? null,
|
|
1738
1761
|
phasegateVersion,
|
|
1762
|
+
agent,
|
|
1739
1763
|
});
|
|
1740
1764
|
console.log(result.stdout);
|
|
1741
1765
|
process.exit(result.exitCode);
|
|
@@ -127,6 +127,7 @@ product-architect で Unit を作り、いくつかの logical_design を書い
|
|
|
127
127
|
#### 観点 9: setup lifecycle と doctor finding
|
|
128
128
|
|
|
129
129
|
- `phasegate doctor --json` の finding に `repairMode: "ai-assisted"` と `suggestedSkill.skillName = "phasegate-config-doctor"` がある → 本 skill が merge 方針、保持する user content、実行すべき `install --apply` / `--force` / `reconcile --apply` を提案する
|
|
130
|
+
- Claude-only / Codex-only 導入後は `phasegate doctor --agent claude --json` または `phasegate doctor --agent codex --json` を使って selected agent の readiness を読む。`scopedOutFindings` は未選択 agent の `not-applicable` 情報なので、ユーザーがその agent を導入したいと言っていない限り repair 提案にしない。`repairHint: null` / `suggestedSkill: null` は意図的な抑制で、`repairHintApplicability: "only-if-agent-selected"` はその agent を選んだ場合だけ修復 guidance が意味を持つという印である。<!-- @work-item-id WI-178, WI-179 -->
|
|
130
131
|
- `repairHint` がある mechanical finding → 原則として hint のコマンドを優先し、実行前に対象ファイルと manifest の差分を確認
|
|
131
132
|
- manifest parse error → `.phasegate/manifest.json` を手で修復する前に backup / uninstall / reinstall の選択肢を提示
|
|
132
133
|
- reconcile / uninstall が refuse → user modified managed target として扱い、`--force` のリスクと backup path を説明して承認を取る
|
|
@@ -132,6 +132,8 @@ docs/guide/ # phasegate リポジトリ自体 (dogfood)
|
|
|
132
132
|
|
|
133
133
|
`setup-artifacts.md` は managed target / generated artifact / runtime state / legacy artifact / user-level setting の分類を持つ。`doctor --report-out` は明示 path への出力で、`.phasegate/last-doctor-report.json` は固定生成物ではない点もここを参照する。<!-- @work-item-id WI-153 -->
|
|
134
134
|
|
|
135
|
+
Claude-only / Codex-only setup の確認では、full `phasegate doctor` と scoped doctor を区別する。ユーザーが `setup:agent --agent claude` を選んだ場合は `phasegate doctor --agent claude --json` を優先し、`scopedOutFindings` の Codex finding は「未選択 agent の not-applicable 情報」であり修復対象ではないと説明する。`repairHint: null` / `suggestedSkill: null` は意図的な抑制で、`repairHintApplicability: "only-if-agent-selected"` はその agent を選んだ場合だけ修復 guidance が意味を持つという印である。full doctor は両 agent を導入したい場合の診断として扱う。<!-- @work-item-id WI-178, WI-179 -->
|
|
136
|
+
|
|
135
137
|
`setup:agent` は初回 setup / retrofit / CI-only / agent hook 有効化の agent-readable planner、`config:plan` は安全な設定変更 intent planner。質問が「次に何を実行するか」「この変更はどの file/validation に対応するか」に寄っている場合は、これらの guide と CLI を案内する。<!-- @work-item-id WI-171, WI-172, WI-173 -->
|
|
136
138
|
|
|
137
139
|
Claude Code readiness の質問では `npx phasegate setup:agent --agent claude --dry-run --json` を案内し、`plan.agentReadiness` の `claude` / `shared` が `configured` なら setup ではなく作業導線へ進める。最短ルートは、WI の確認または起票、`docs/inception/.../{WI-XXX}/` への計画/設計、`docs/product/...` への `@work-item-id WI-XXX` 反映、`phasegate phasegate:check-ready` または該当 `validate` の実行である。`setup:agent --apply --json` の structured `error` は troubleshooting に委譲し、`target` / `operation` / `code` / `recovery` を読ませる。<!-- @work-item-id WI-177 -->
|