phasegate 0.335.0 → 0.340.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 +4 -0
- package/README.ja.md +22 -9
- package/README.md +28 -17
- package/docs/ADR/038-config-state-operation-permission-policy.md +5 -2
- package/docs/ADR/041-non-excludable-agent-trust-roots.md +68 -0
- package/docs/guide/antigravity-integration.md +26 -0
- package/docs/guide/cli-reference.md +4 -4
- package/docs/guide/codex-integration.md +44 -107
- package/docs/guide/grok-integration.md +26 -0
- package/docs/guide/hooks-integration.md +27 -4
- package/docs/guide/installation.md +4 -2
- package/docs/guide/setup-artifacts.md +4 -4
- package/docs/guide/skills-overview.md +1 -1
- package/package.json +1 -1
- package/scripts/harness/agent-integration/application/dto/handle-pre-tool-use-dto.ts +1 -1
- package/scripts/harness/agent-integration/application/dto/normalized-pre-tool-use-request.ts +32 -0
- package/scripts/harness/agent-integration/application/usecases/handle-pre-tool-use-usecase.ts +2 -2
- package/scripts/harness/agent-integration/domain/ports/full-mode-requirement-query-port.ts +3 -1
- package/scripts/harness/agent-integration/domain/services/apply-patch-write-target-extractor.ts +98 -0
- package/scripts/harness/agent-integration/domain/services/bash-write-target-extractor.ts +6 -52
- package/scripts/harness/agent-integration/domain/value-objects/hook-translation-result.ts +1 -1
- package/scripts/harness/agent-integration/domain/value-objects/protected-file-list.ts +35 -18
- package/scripts/harness/agent-integration/presentation/phasegate-status-context.ts +1 -1
- package/scripts/harness/agent-integration/presentation/post-tool-use-hook.ts +1 -0
- package/scripts/harness/agent-integration/presentation/pre-tool-use-hook.ts +123 -70
- package/scripts/harness/agent-integration/presentation/pre-tool-use-payload-normalizer.ts +228 -0
- package/scripts/harness/agent-integration/presentation/pre-tool-use-response-renderer.ts +38 -0
- package/scripts/harness/ci-governance/domain/value-objects/integrity-target.ts +2 -0
- package/scripts/harness/installation/application/checks/antigravity-hook-missing-check.ts +79 -0
- package/scripts/harness/installation/application/checks/codex-hook-missing-check.ts +70 -6
- package/scripts/harness/installation/application/checks/grok-hook-missing-check.ts +79 -0
- package/scripts/harness/installation/application/checks/husky-runtime-inactive-check.ts +33 -0
- package/scripts/harness/installation/application/named-hook-json.ts +17 -0
- package/scripts/harness/installation/application/operator-notice.ts +42 -0
- package/scripts/harness/installation/application/usecases/run-doctor-diagnostics.ts +18 -7
- package/scripts/harness/installation/application/usecases/run-install.ts +152 -52
- package/scripts/harness/installation/application/usecases/run-reconcile.ts +86 -10
- package/scripts/harness/installation/application/usecases/run-uninstall.ts +149 -25
- package/scripts/harness/installation/composition-root.ts +10 -0
- package/scripts/harness/installation/domain/agent-target.ts +39 -0
- package/scripts/harness/installation/domain/check-id.ts +5 -0
- package/scripts/harness/installation/domain/husky-runtime-state.ts +34 -0
- package/scripts/harness/installation/domain/ports/git-hooks-runtime-probe.ts +9 -0
- package/scripts/harness/installation/domain/repair-table.ts +5 -0
- package/scripts/harness/installation/infrastructure/adapters/git-hooks-runtime-probe-adapter.ts +62 -0
- package/scripts/harness/installation/presentation/cli/install-handler.ts +23 -4
- package/scripts/harness/installation/presentation/cli/reconcile-handler.ts +7 -1
- package/scripts/harness/installation/presentation/formatters/diagnostic-report-formatter.ts +27 -0
- package/scripts/harness/main.ts +100 -39
- package/scripts/harness/quick-mode/application/dto/change-category-classification-contract.ts +1 -1
- package/scripts/harness/quick-mode/application/dto/quick-mode-eligibility-contract.ts +1 -1
- package/scripts/harness/quick-mode/application/usecases/classify-change-category-usecase.ts +3 -1
- package/scripts/harness/quick-mode/domain/services/quick-mode-judgment-engine.ts +13 -2
- package/scripts/harness/quick-mode/domain/types/rejection-rule.ts +1 -1
- package/scripts/harness/regression-suite/infrastructure/adapters/vitest-test-runner-adapter.ts +13 -3
- package/templates/.agents/hooks.json +16 -0
- package/templates/.claude/scripts/analyze-errors-hook.sh +2 -2
- package/templates/.claude/settings.json +5 -3
- package/templates/.codex/hooks.json +2 -2
|
@@ -6,7 +6,15 @@
|
|
|
6
6
|
// @work-item-id WI-180
|
|
7
7
|
// @work-item-id WI-208
|
|
8
8
|
// @work-item-id WI-330
|
|
9
|
+
// @work-item-id WI-384
|
|
10
|
+
// @work-item-id WI-385
|
|
9
11
|
|
|
12
|
+
import {
|
|
13
|
+
ANTIGRAVITY_CLI_ONLY_NOTICE,
|
|
14
|
+
CODEX_HOOK_TRUST_UNVERIFIABLE_NOTICE,
|
|
15
|
+
GROK_HOOK_TRUST_UNVERIFIABLE_NOTICE,
|
|
16
|
+
type OperatorNotice,
|
|
17
|
+
} from "../../application/operator-notice.js";
|
|
10
18
|
import type {
|
|
11
19
|
DoctorAgentScope,
|
|
12
20
|
ScopedOutDiagnosticFinding,
|
|
@@ -27,6 +35,7 @@ export interface DiagnosticReportFormatterInput {
|
|
|
27
35
|
|
|
28
36
|
export class DiagnosticReportFormatter {
|
|
29
37
|
formatJson(input: DiagnosticReportFormatterInput): string {
|
|
38
|
+
const operatorNotices = noticesFor(input.agent);
|
|
30
39
|
return JSON.stringify(
|
|
31
40
|
{
|
|
32
41
|
schemaVersion: "1.0",
|
|
@@ -59,6 +68,7 @@ export class DiagnosticReportFormatter {
|
|
|
59
68
|
scopeReason,
|
|
60
69
|
};
|
|
61
70
|
}),
|
|
71
|
+
operatorNotices,
|
|
62
72
|
exitCode: input.exitCode,
|
|
63
73
|
},
|
|
64
74
|
null,
|
|
@@ -74,6 +84,9 @@ export class DiagnosticReportFormatter {
|
|
|
74
84
|
`Config: ${input.configStatus}`,
|
|
75
85
|
"",
|
|
76
86
|
];
|
|
87
|
+
for (const notice of noticesFor(input.agent)) {
|
|
88
|
+
lines.push(`Notice [${notice.code}]: ${notice.message}`, "");
|
|
89
|
+
}
|
|
77
90
|
for (const finding of input.report.findings) {
|
|
78
91
|
lines.push(`[${finding.severity}] ${finding.checkId}: ${finding.message}`);
|
|
79
92
|
lines.push(` target: ${finding.target}`);
|
|
@@ -107,9 +120,23 @@ function scopeDescription(agent: DoctorAgentScope, installationMode: "project" |
|
|
|
107
120
|
return "Personal Claude Code sandbox; team/project Husky, CI, package, and Codex-only findings are not repair targets.";
|
|
108
121
|
if (agent === "codex")
|
|
109
122
|
return "Personal Codex sandbox; team/project Husky, CI, package, and Claude-only findings are not repair targets.";
|
|
123
|
+
if (agent === "grok") return "Personal Grok-compatible hook diagnostics; external trust remains operator-verified.";
|
|
124
|
+
if (agent === "antigravity") return "Personal Antigravity CLI hook diagnostics; IDE/desktop uses the L2 backstop.";
|
|
125
|
+
if (agent === "all") return "Personal diagnostics for all supported runtime targets.";
|
|
110
126
|
return "Personal sandbox diagnostics; team/project Husky, CI, and package findings are not repair targets.";
|
|
111
127
|
}
|
|
112
128
|
if (agent === "claude") return "Claude Code and shared setup targets; Codex-only findings are not applicable.";
|
|
113
129
|
if (agent === "codex") return "Codex and shared setup targets; Claude-only findings are not applicable.";
|
|
130
|
+
if (agent === "grok") return "Grok-compatible Claude hook diagnostics; other runtime findings are not applicable.";
|
|
131
|
+
if (agent === "antigravity") return "Antigravity CLI hook diagnostics; other runtime findings are not applicable.";
|
|
132
|
+
if (agent === "all") return "Full setup diagnostics for Claude, Codex, Grok, Antigravity, and shared targets.";
|
|
114
133
|
return "Full setup diagnostics for Claude, Codex, and shared targets.";
|
|
115
134
|
}
|
|
135
|
+
|
|
136
|
+
function noticesFor(agent: DoctorAgentScope): readonly OperatorNotice[] {
|
|
137
|
+
return [
|
|
138
|
+
...(agent === "codex" || agent === "both" || agent === "all" ? [CODEX_HOOK_TRUST_UNVERIFIABLE_NOTICE] : []),
|
|
139
|
+
...(agent === "grok" || agent === "all" ? [GROK_HOOK_TRUST_UNVERIFIABLE_NOTICE] : []),
|
|
140
|
+
...(agent === "antigravity" || agent === "all" ? [ANTIGRAVITY_CLI_ONLY_NOTICE] : []),
|
|
141
|
+
];
|
|
142
|
+
}
|
package/scripts/harness/main.ts
CHANGED
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
* @work-item-id WI-300
|
|
26
26
|
* @work-item-id WI-306
|
|
27
27
|
* @work-item-id WI-308
|
|
28
|
+
* @work-item-id WI-384
|
|
29
|
+
* @work-item-id WI-385
|
|
28
30
|
*
|
|
29
31
|
* Phasegate CLI エントリポイント。
|
|
30
32
|
* 各Unitの Composition Root からハンドラーを取得し、コマンドに応じてディスパッチする。
|
|
@@ -63,6 +65,7 @@ import {
|
|
|
63
65
|
SkillDeployerManifestBuilder,
|
|
64
66
|
} from "./installation/application/wrappers/skill-deployer-manifest-builder.js";
|
|
65
67
|
import { createInstallationModule } from "./installation/composition-root.js";
|
|
68
|
+
import { type AgentTarget, isAgentTarget } from "./installation/domain/agent-target.js";
|
|
66
69
|
import { NodeCryptoHashAdapter } from "./installation/infrastructure/adapters/node-crypto-hash-adapter.js";
|
|
67
70
|
import { CheckStoryReflectionUseCase } from "./phase-dependency-model/application/usecases/check-story-reflection-usecase.js";
|
|
68
71
|
import { createPhaseDependencyModelModule } from "./phase-dependency-model/composition-root.js";
|
|
@@ -207,14 +210,14 @@ Usage: phasegate <command> [options]
|
|
|
207
210
|
Setup:
|
|
208
211
|
init Initialize project: deploy skills + design docs + phasegate.config.json
|
|
209
212
|
(--name <project-name>, --preset <full|standard|minimal|custom>,
|
|
210
|
-
--skills <core|all>, --agent <claude|codex|both>, --workflow <standard|strict>,
|
|
213
|
+
--skills <core|all>, --agent <claude|codex|both|grok|antigravity|all>, --workflow <standard|strict>,
|
|
211
214
|
--language <language>, --with-husky, --with-ci, --yes)
|
|
212
215
|
update-skills Alias for reconcile (kept for compatibility)
|
|
213
|
-
doctor Diagnose silent installation failures (--json, --strict, --personal, --agent <claude|codex|both>, --report-out <path>)
|
|
216
|
+
doctor Diagnose silent installation failures (--json, --strict, --personal, --agent <claude|codex|both|grok|antigravity|all>, --report-out <path>)
|
|
214
217
|
scaffold-wi <unit|_cross> <story|issue|fix|refactor|chore>
|
|
215
218
|
Create docs/inception/{unit}/WI-XXX/description.md
|
|
216
219
|
emit-agent-rules Print AGENTS.md / CLAUDE.md WI workflow rules block
|
|
217
|
-
install Install phasegate managed files (--dry-run|--apply, --force, --personal, --agent <claude|codex|both>)
|
|
220
|
+
install Install phasegate managed files (--dry-run|--apply, --force, --personal, --agent <claude|codex|both|grok|antigravity|all>)
|
|
218
221
|
uninstall Uninstall phasegate managed files (--dry-run|--apply, --force)
|
|
219
222
|
reconcile Reconcile phasegate managed files (--dry-run|--apply, --force)
|
|
220
223
|
setup:agent Diagnose repo setup and produce/apply an agent-readable setup plan
|
|
@@ -271,7 +274,7 @@ Gate semantics:
|
|
|
271
274
|
ci:auto-refresh-agent-context Refresh AGENTS.md / CLAUDE.md (--dry-run, --apply, --json)
|
|
272
275
|
refresh-claude-md Refresh CLAUDE.md standard sections (--dry-run, --apply, --json)
|
|
273
276
|
p2:check-agent-context Check AGENTS.md / CLAUDE.md freshness (--threshold-days <n>, --json)
|
|
274
|
-
setup:agent Plan agent-driven setup (--intent <minimal|recommended|strict|ci-only|agent-hooks|retrofit>, --agent <claude|codex|both>, --dry-run|--apply, --json)
|
|
277
|
+
setup:agent Plan agent-driven setup (--intent <minimal|recommended|strict|ci-only|agent-hooks|retrofit>, --agent <claude|codex|both|grok|antigravity|all>, --dry-run|--apply, --json)
|
|
275
278
|
config:plan Plan safe config changes (--intent <l4-strict|codex-hooks|ci-fail-on-warning|baseline-reset|quick-mode-strict|quick-mode-relax|retrofit-bootstrap|planning-mode-relax>, --dry-run|--apply, --json)
|
|
276
279
|
ci:check-repetition Check error repetition (--code <errorCode>, --reset, --json)
|
|
277
280
|
baseline Create retrofit baseline snapshot (--dry-run, --force, --paths <glob,glob,...>, --json)
|
|
@@ -705,7 +708,7 @@ Options:
|
|
|
705
708
|
--name <project-name> Project name (default: "my-project")
|
|
706
709
|
--preset <full|standard|minimal|custom> Phase dependency preset (default: "standard")
|
|
707
710
|
--skills <core|all> Skill set to deploy (default: "all")
|
|
708
|
-
--agent <claude|codex|both> Agent integration target (default: "claude")
|
|
711
|
+
--agent <claude|codex|both|grok|antigravity|all> Agent integration target (default: "claude")
|
|
709
712
|
--workflow <standard|strict> Workflow enforcement defaults (default: "standard")
|
|
710
713
|
--language <language> Project language declaration (default: "typescript")
|
|
711
714
|
--with-husky Install Husky pre-commit hooks
|
|
@@ -731,7 +734,7 @@ Options:
|
|
|
731
734
|
--dry-run Preview target actions without writing (default)
|
|
732
735
|
--apply Write merge results and manifest
|
|
733
736
|
--force Force ai-assisted/manual targets after backing up existing files
|
|
734
|
-
--agent <claude|codex|both> Agent context and hook targets (default: both)
|
|
737
|
+
--agent <claude|codex|both|grok|antigravity|all> Agent context and hook targets (default: both)
|
|
735
738
|
--skills <core|all> Rendered agent context skill mode (default: all)
|
|
736
739
|
--workflow <standard|strict> Rendered agent context workflow mode (default: standard)
|
|
737
740
|
--with-husky Include Husky hook targets (opt-in; omitted by default)
|
|
@@ -740,13 +743,24 @@ Options:
|
|
|
740
743
|
With --agent claude, initializes .phasegate-local config/settings/skills and ignored .claude shims.
|
|
741
744
|
--json Output machine-readable JSON
|
|
742
745
|
--help, -h Show this help`,
|
|
746
|
+
doctor: `Usage: phasegate doctor [options]
|
|
747
|
+
|
|
748
|
+
Diagnose silent installation failures for the selected runtime scope.
|
|
749
|
+
|
|
750
|
+
Options:
|
|
751
|
+
--json Output machine-readable JSON
|
|
752
|
+
--strict Treat warnings as failures
|
|
753
|
+
--personal Diagnose a personal installation
|
|
754
|
+
--agent <claude|codex|both|grok|antigravity|all> Diagnostic scope (default: both)
|
|
755
|
+
--report-out <path> Write the JSON report to a file
|
|
756
|
+
--help, -h Show this help`,
|
|
743
757
|
"setup:agent": `Usage: phasegate setup:agent [options]
|
|
744
758
|
|
|
745
759
|
Diagnose repository setup and produce an agent-readable setup plan.
|
|
746
760
|
|
|
747
761
|
Options:
|
|
748
762
|
--intent <minimal|recommended|strict|ci-only|agent-hooks|retrofit>
|
|
749
|
-
--agent <claude|codex|both>
|
|
763
|
+
--agent <claude|codex|both|grok|antigravity|all>
|
|
750
764
|
--workflow <standard|strict>
|
|
751
765
|
--with-husky
|
|
752
766
|
--with-ci
|
|
@@ -1075,7 +1089,7 @@ function parseCoverageThreshold(raw: string | undefined): number {
|
|
|
1075
1089
|
}
|
|
1076
1090
|
|
|
1077
1091
|
type InitPhasePreset = "full" | "standard" | "minimal" | "custom";
|
|
1078
|
-
|
|
1092
|
+
const AGENT_TARGET_USAGE = "claude|codex|both|grok|antigravity|all";
|
|
1079
1093
|
type SetupIntent = "minimal" | "recommended" | "strict" | "ci-only" | "agent-hooks" | "retrofit";
|
|
1080
1094
|
type ConfigChangeIntent =
|
|
1081
1095
|
| "l4-strict"
|
|
@@ -1097,7 +1111,7 @@ interface SetupCompletenessEntry {
|
|
|
1097
1111
|
}
|
|
1098
1112
|
|
|
1099
1113
|
interface AgentReadinessEntry {
|
|
1100
|
-
readonly agent: "claude" | "codex" | "shared";
|
|
1114
|
+
readonly agent: "claude" | "codex" | "grok" | "antigravity" | "shared";
|
|
1101
1115
|
readonly status: SetupCompletenessStatus;
|
|
1102
1116
|
readonly evidence: readonly string[];
|
|
1103
1117
|
readonly nextAction: string | null;
|
|
@@ -1134,14 +1148,9 @@ function parseInitPhasePreset(value: string | undefined): InitPhasePreset | unde
|
|
|
1134
1148
|
return undefined;
|
|
1135
1149
|
}
|
|
1136
1150
|
|
|
1137
|
-
function parseAgentTarget(value: string | undefined, fallback: AgentTarget = "both"): AgentTarget {
|
|
1138
|
-
if (value === "claude" || value === "codex" || value === "both") return value;
|
|
1139
|
-
return fallback;
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
1151
|
function parseRequiredAgentTarget(value: string | undefined, fallback: AgentTarget = "both"): AgentTarget | null {
|
|
1143
1152
|
if (value === undefined) return fallback;
|
|
1144
|
-
if (value
|
|
1153
|
+
if (isAgentTarget(value)) return value;
|
|
1145
1154
|
return null;
|
|
1146
1155
|
}
|
|
1147
1156
|
|
|
@@ -1234,6 +1243,7 @@ function buildSetupCompleteness(input: {
|
|
|
1234
1243
|
readonly phasegateConfig: boolean;
|
|
1235
1244
|
readonly claudeSettings: boolean;
|
|
1236
1245
|
readonly codexHooks: boolean;
|
|
1246
|
+
readonly antigravityHooks: boolean;
|
|
1237
1247
|
readonly agentsMd: boolean;
|
|
1238
1248
|
readonly claudeMd: boolean;
|
|
1239
1249
|
readonly huskyPreCommit: boolean;
|
|
@@ -1241,12 +1251,19 @@ function buildSetupCompleteness(input: {
|
|
|
1241
1251
|
readonly skillsVersion: boolean;
|
|
1242
1252
|
};
|
|
1243
1253
|
}): readonly SetupCompletenessEntry[] {
|
|
1244
|
-
const includeClaude = input.agent === "claude" || input.agent === "both";
|
|
1245
|
-
const includeCodex = input.agent === "codex" || input.agent === "both";
|
|
1254
|
+
const includeClaude = input.agent === "claude" || input.agent === "both" || input.agent === "all";
|
|
1255
|
+
const includeCodex = input.agent === "codex" || input.agent === "both" || input.agent === "all";
|
|
1256
|
+
const includeGrok = input.agent === "grok" || input.agent === "all";
|
|
1257
|
+
const includeAntigravity = input.agent === "antigravity" || input.agent === "all";
|
|
1258
|
+
const includeClaudeHook = includeClaude || includeGrok;
|
|
1259
|
+
const includeAgentsContext = includeCodex || includeGrok || includeAntigravity;
|
|
1246
1260
|
const doctorCommand = doctorValidationCommand(input.agent);
|
|
1247
1261
|
const agentHooksConfigured =
|
|
1248
|
-
(!
|
|
1249
|
-
|
|
1262
|
+
(!includeClaudeHook || input.checks.claudeSettings) &&
|
|
1263
|
+
(!includeCodex || input.checks.codexHooks) &&
|
|
1264
|
+
(!includeAntigravity || input.checks.antigravityHooks);
|
|
1265
|
+
const agentContextConfigured =
|
|
1266
|
+
(!includeClaude || input.checks.claudeMd) && (!includeAgentsContext || input.checks.agentsMd);
|
|
1250
1267
|
const entries: SetupCompletenessEntry[] = [
|
|
1251
1268
|
setupCompletenessEntry({
|
|
1252
1269
|
area: "local-config",
|
|
@@ -1258,16 +1275,22 @@ function buildSetupCompleteness(input: {
|
|
|
1258
1275
|
}),
|
|
1259
1276
|
setupCompletenessEntry({
|
|
1260
1277
|
area: "agent-hooks",
|
|
1261
|
-
included:
|
|
1278
|
+
included: includeClaudeHook || includeCodex || includeAntigravity,
|
|
1262
1279
|
configured: agentHooksConfigured,
|
|
1263
1280
|
configuredEvidence: "Selected agent hook settings are present.",
|
|
1264
1281
|
plannedEvidence: "setup:agent will create or refresh selected agent hook settings.",
|
|
1265
1282
|
nextAction: "Run setup:agent --apply for selected agents.",
|
|
1266
|
-
risk: includeCodex
|
|
1283
|
+
risk: includeCodex
|
|
1284
|
+
? "Codex user-level hook feature enablement remains a manual external check."
|
|
1285
|
+
: includeGrok
|
|
1286
|
+
? "Grok project-hook trust remains a manual external check."
|
|
1287
|
+
: includeAntigravity
|
|
1288
|
+
? "Antigravity hard blocking is CLI-only; IDE/desktop relies on L2 pre-commit."
|
|
1289
|
+
: undefined,
|
|
1267
1290
|
}),
|
|
1268
1291
|
setupCompletenessEntry({
|
|
1269
1292
|
area: "agent-context",
|
|
1270
|
-
included: includeClaude ||
|
|
1293
|
+
included: includeClaude || includeAgentsContext,
|
|
1271
1294
|
configured: agentContextConfigured,
|
|
1272
1295
|
configuredEvidence: "Selected AGENTS.md / CLAUDE.md managed context files are present.",
|
|
1273
1296
|
plannedEvidence: "setup:agent will create or refresh selected managed agent context sections.",
|
|
@@ -1371,6 +1394,7 @@ function buildAgentReadiness(input: {
|
|
|
1371
1394
|
readonly phasegateConfig: boolean;
|
|
1372
1395
|
readonly claudeSettings: boolean;
|
|
1373
1396
|
readonly codexHooks: boolean;
|
|
1397
|
+
readonly antigravityHooks: boolean;
|
|
1374
1398
|
readonly agentsMd: boolean;
|
|
1375
1399
|
readonly claudeMd: boolean;
|
|
1376
1400
|
readonly huskyPreCommit: boolean;
|
|
@@ -1378,8 +1402,10 @@ function buildAgentReadiness(input: {
|
|
|
1378
1402
|
readonly skillsVersion: boolean;
|
|
1379
1403
|
};
|
|
1380
1404
|
}): readonly AgentReadinessEntry[] {
|
|
1381
|
-
const includeClaude = input.agent === "claude" || input.agent === "both";
|
|
1382
|
-
const includeCodex = input.agent === "codex" || input.agent === "both";
|
|
1405
|
+
const includeClaude = input.agent === "claude" || input.agent === "both" || input.agent === "all";
|
|
1406
|
+
const includeCodex = input.agent === "codex" || input.agent === "both" || input.agent === "all";
|
|
1407
|
+
const includeGrok = input.agent === "grok" || input.agent === "all";
|
|
1408
|
+
const includeAntigravity = input.agent === "antigravity" || input.agent === "all";
|
|
1383
1409
|
const doctorCommand = doctorValidationCommand(input.agent);
|
|
1384
1410
|
const sharedConfigured =
|
|
1385
1411
|
input.checks.packageJson &&
|
|
@@ -1423,6 +1449,24 @@ function buildAgentReadiness(input: {
|
|
|
1423
1449
|
nextAction: "Run setup:agent --agent codex --apply, then enable hooks at user level if needed.",
|
|
1424
1450
|
risk: "Codex user-level hook feature enablement remains a manual external check.",
|
|
1425
1451
|
}),
|
|
1452
|
+
setupReadinessEntry({
|
|
1453
|
+
agent: "grok",
|
|
1454
|
+
included: includeGrok,
|
|
1455
|
+
configured: input.checks.claudeSettings && input.checks.agentsMd,
|
|
1456
|
+
configuredEvidence: [".claude/settings.json and AGENTS.md are present for Grok compatibility."],
|
|
1457
|
+
plannedEvidence: ["setup:agent will deploy the Claude-compatible hook and AGENTS.md without .grok duplication."],
|
|
1458
|
+
nextAction: "Run setup:agent --agent grok --apply, then verify grok inspect and /hooks trust.",
|
|
1459
|
+
risk: "Grok project-hook trust cannot be verified by Phasegate.",
|
|
1460
|
+
}),
|
|
1461
|
+
setupReadinessEntry({
|
|
1462
|
+
agent: "antigravity",
|
|
1463
|
+
included: includeAntigravity,
|
|
1464
|
+
configured: input.checks.antigravityHooks && input.checks.agentsMd,
|
|
1465
|
+
configuredEvidence: [".agents/hooks.json and AGENTS.md are present for Antigravity CLI."],
|
|
1466
|
+
plannedEvidence: ["setup:agent will deploy the Antigravity named hook map and AGENTS.md."],
|
|
1467
|
+
nextAction: "Run setup:agent --agent antigravity --apply, then inspect /hooks in agy.",
|
|
1468
|
+
risk: "IDE/desktop hook execution is not guaranteed; keep the L2 pre-commit backstop.",
|
|
1469
|
+
}),
|
|
1426
1470
|
setupReadinessEntry({
|
|
1427
1471
|
agent: "shared",
|
|
1428
1472
|
included: true,
|
|
@@ -1452,14 +1496,17 @@ async function buildAgentSetupPlan(
|
|
|
1452
1496
|
phasegateConfig: await projectFileExists(rootDir, "phasegate.config.json"),
|
|
1453
1497
|
claudeSettings: await projectFileExists(rootDir, ".claude/settings.json"),
|
|
1454
1498
|
codexHooks: await projectFileExists(rootDir, ".codex/hooks.json"),
|
|
1499
|
+
antigravityHooks: await projectFileExists(rootDir, ".agents/hooks.json"),
|
|
1455
1500
|
agentsMd: await projectFileExists(rootDir, "AGENTS.md"),
|
|
1456
1501
|
claudeMd: await projectFileExists(rootDir, "CLAUDE.md"),
|
|
1457
1502
|
huskyPreCommit: await projectFileExists(rootDir, ".husky/pre-commit"),
|
|
1458
1503
|
ciWorkflow: await projectFileExists(rootDir, ".github/workflows/phasegate-aidlc-gate.yml"),
|
|
1459
1504
|
skillsVersion: await projectFileExists(rootDir, "skills/.harness-version"),
|
|
1460
1505
|
};
|
|
1461
|
-
const includeClaude = input.agent === "claude" || input.agent === "both";
|
|
1462
|
-
const includeCodex = input.agent === "codex" || input.agent === "both";
|
|
1506
|
+
const includeClaude = input.agent === "claude" || input.agent === "both" || input.agent === "all";
|
|
1507
|
+
const includeCodex = input.agent === "codex" || input.agent === "both" || input.agent === "all";
|
|
1508
|
+
const includeGrok = input.agent === "grok" || input.agent === "all";
|
|
1509
|
+
const includeAntigravity = input.agent === "antigravity" || input.agent === "all";
|
|
1463
1510
|
const changes = [
|
|
1464
1511
|
!checks.packageJson
|
|
1465
1512
|
? "Add phasegate devDependency and phasegate scripts to package.json."
|
|
@@ -1469,6 +1516,8 @@ async function buildAgentSetupPlan(
|
|
|
1469
1516
|
: "Keep existing phasegate.config.json; review config:plan before changing policy.",
|
|
1470
1517
|
includeClaude ? "Create or refresh .claude/settings.json and CLAUDE.md managed section." : null,
|
|
1471
1518
|
includeCodex ? "Create or refresh .codex/hooks.json and AGENTS.md managed section." : null,
|
|
1519
|
+
includeGrok ? "Create or refresh the Claude-compatible hook and AGENTS.md without a .grok hook duplicate." : null,
|
|
1520
|
+
includeAntigravity ? "Create or refresh .agents/hooks.json named hook and AGENTS.md managed section." : null,
|
|
1472
1521
|
input.withHusky
|
|
1473
1522
|
? "Create or refresh Husky pre-commit, commit-msg, and pre-push backstops."
|
|
1474
1523
|
: "Leave Husky hooks unmanaged in this setup run.",
|
|
@@ -2100,8 +2149,8 @@ async function main(): Promise<void> {
|
|
|
2100
2149
|
}
|
|
2101
2150
|
const skillSet: SkillSet = skillSetRaw;
|
|
2102
2151
|
const agentRaw = parseFlag(args, "--agent") ?? "claude";
|
|
2103
|
-
if (agentRaw
|
|
2104
|
-
console.error(`Invalid --agent value: "${agentRaw}". Use
|
|
2152
|
+
if (!isAgentTarget(agentRaw)) {
|
|
2153
|
+
console.error(`Invalid --agent value: "${agentRaw}". Use <${AGENT_TARGET_USAGE}>.`);
|
|
2105
2154
|
process.exit(2);
|
|
2106
2155
|
}
|
|
2107
2156
|
const agent = agentRaw;
|
|
@@ -2116,8 +2165,8 @@ async function main(): Promise<void> {
|
|
|
2116
2165
|
console.error("Invalid --language value: value must not be empty.");
|
|
2117
2166
|
process.exit(2);
|
|
2118
2167
|
}
|
|
2119
|
-
const deployClaude = agent === "claude" || agent === "both";
|
|
2120
|
-
const deployCodex = agent === "codex" || agent === "both";
|
|
2168
|
+
const deployClaude = agent === "claude" || agent === "both" || agent === "grok" || agent === "all";
|
|
2169
|
+
const deployCodex = agent === "codex" || agent === "both" || agent === "all";
|
|
2121
2170
|
const result = await deploySkills(harnessRoot, rootDir, skillSet);
|
|
2122
2171
|
const packageResult = await ensurePhasegatePackageDependency(rootDir, result.version);
|
|
2123
2172
|
const skillLinkResult = await deployAgentSkillLinks(rootDir, {
|
|
@@ -2312,11 +2361,15 @@ async function main(): Promise<void> {
|
|
|
2312
2361
|
console.log(" 3. Edit .claude/scripts/hook-config.json to set target directories");
|
|
2313
2362
|
}
|
|
2314
2363
|
if (deployCodex) {
|
|
2315
|
-
console.log(
|
|
2364
|
+
console.log(
|
|
2365
|
+
` ${deployClaude ? "4" : "3"}. Use Codex CLI >= 0.124.0, then open /hooks and trust the current hook definition hash`,
|
|
2366
|
+
);
|
|
2316
2367
|
console.log(
|
|
2317
2368
|
` ${deployClaude ? "5" : "4"}. (Recommended) Install pre-commit backstop: rerun with --with-husky or set up husky manually`,
|
|
2318
2369
|
);
|
|
2319
|
-
console.log(
|
|
2370
|
+
console.log(
|
|
2371
|
+
` See docs/guide/codex-integration.md for native apply_patch coverage and trust troubleshooting.`,
|
|
2372
|
+
);
|
|
2320
2373
|
}
|
|
2321
2374
|
if (skillSet !== "core") {
|
|
2322
2375
|
console.log("");
|
|
@@ -2363,7 +2416,7 @@ async function main(): Promise<void> {
|
|
|
2363
2416
|
}
|
|
2364
2417
|
const agent = parseRequiredAgentTarget(parseFlag(args, "--agent"), "both");
|
|
2365
2418
|
if (agent === null) {
|
|
2366
|
-
console.error(`Invalid --agent value: "${parseFlag(args, "--agent")}". Use
|
|
2419
|
+
console.error(`Invalid --agent value: "${parseFlag(args, "--agent")}". Use <${AGENT_TARGET_USAGE}>.`);
|
|
2367
2420
|
process.exit(2);
|
|
2368
2421
|
}
|
|
2369
2422
|
const mod = createInstallationModule();
|
|
@@ -2434,7 +2487,11 @@ async function main(): Promise<void> {
|
|
|
2434
2487
|
}
|
|
2435
2488
|
const apply = hasFlag(args, "--apply");
|
|
2436
2489
|
const dryRun = hasFlag(args, "--dry-run") || !apply;
|
|
2437
|
-
const agent =
|
|
2490
|
+
const agent = parseRequiredAgentTarget(parseFlag(args, "--agent"), "both");
|
|
2491
|
+
if (agent === null) {
|
|
2492
|
+
console.error(`Invalid --agent value: "${parseFlag(args, "--agent")}". Use <${AGENT_TARGET_USAGE}>.`);
|
|
2493
|
+
process.exit(2);
|
|
2494
|
+
}
|
|
2438
2495
|
const skillSetRaw = parseFlag(args, "--skills") ?? "all";
|
|
2439
2496
|
if (skillSetRaw !== "core" && skillSetRaw !== "all") {
|
|
2440
2497
|
console.error(`Invalid --skills value: "${skillSetRaw}". Use "core" or "all".`);
|
|
@@ -2445,8 +2502,8 @@ async function main(): Promise<void> {
|
|
|
2445
2502
|
console.error(`Invalid --workflow value: "${workflowRaw}". Use "standard" or "strict".`);
|
|
2446
2503
|
process.exit(2);
|
|
2447
2504
|
}
|
|
2448
|
-
const includeClaude = agent === "claude" || agent === "both";
|
|
2449
|
-
const includeCodex = agent === "codex" || agent === "both";
|
|
2505
|
+
const includeClaude = agent === "claude" || agent === "both" || agent === "grok" || agent === "all";
|
|
2506
|
+
const includeCodex = agent === "codex" || agent === "both" || agent === "all";
|
|
2450
2507
|
const personal = hasFlag(args, "--personal");
|
|
2451
2508
|
const mod = createInstallationModule();
|
|
2452
2509
|
const phasegateVersion = await getHarnessVersion(harnessRoot);
|
|
@@ -2490,7 +2547,11 @@ async function main(): Promise<void> {
|
|
|
2490
2547
|
process.exit(2);
|
|
2491
2548
|
}
|
|
2492
2549
|
const intent = parseSetupIntent(parseFlag(args, "--intent"));
|
|
2493
|
-
const agent =
|
|
2550
|
+
const agent = parseRequiredAgentTarget(parseFlag(args, "--agent"), "both");
|
|
2551
|
+
if (agent === null) {
|
|
2552
|
+
console.error(`Invalid --agent value: "${parseFlag(args, "--agent")}". Use <${AGENT_TARGET_USAGE}>.`);
|
|
2553
|
+
process.exit(2);
|
|
2554
|
+
}
|
|
2494
2555
|
const workflow = parseWorkflowMode(
|
|
2495
2556
|
parseFlag(args, "--workflow") ?? (intent === "strict" ? "strict" : "standard"),
|
|
2496
2557
|
);
|
|
@@ -2526,8 +2587,8 @@ async function main(): Promise<void> {
|
|
|
2526
2587
|
dryRun: false,
|
|
2527
2588
|
apply: true,
|
|
2528
2589
|
force: hasFlag(args, "--force"),
|
|
2529
|
-
includeClaude: agent === "claude" || agent === "both",
|
|
2530
|
-
includeCodex: agent === "codex" || agent === "both",
|
|
2590
|
+
includeClaude: agent === "claude" || agent === "both" || agent === "grok" || agent === "all",
|
|
2591
|
+
includeCodex: agent === "codex" || agent === "both" || agent === "all",
|
|
2531
2592
|
includeHusky: withHusky,
|
|
2532
2593
|
includeCi: withCi,
|
|
2533
2594
|
skillSet: "all",
|
package/scripts/harness/quick-mode/application/dto/change-category-classification-contract.ts
CHANGED
|
@@ -11,6 +11,6 @@ export interface ChangeCategoryClassificationContract {
|
|
|
11
11
|
readonly dominantCategory: string | null;
|
|
12
12
|
readonly perFile: readonly ChangeCategoryPerFile[];
|
|
13
13
|
readonly fullModeRequired: boolean;
|
|
14
|
-
readonly rejectionRule?: 'MIXED_CHANGES' | 'NEW_DOMAIN' | 'API_CONTRACT';
|
|
14
|
+
readonly rejectionRule?: 'CATEGORY_NOT_ALLOWED' | 'MIXED_CHANGES' | 'NEW_DOMAIN' | 'API_CONTRACT';
|
|
15
15
|
readonly rejectionReason?: string;
|
|
16
16
|
}
|
|
@@ -8,6 +8,6 @@
|
|
|
8
8
|
export interface QuickModeEligibilityContract {
|
|
9
9
|
readonly eligible: boolean;
|
|
10
10
|
readonly reason: string;
|
|
11
|
-
readonly rejectionRule?: 'MIXED_CHANGES' | 'NEW_DOMAIN' | 'API_CONTRACT';
|
|
11
|
+
readonly rejectionRule?: 'CATEGORY_NOT_ALLOWED' | 'MIXED_CHANGES' | 'NEW_DOMAIN' | 'API_CONTRACT';
|
|
12
12
|
readonly rejectedFiles?: readonly { filePath: string; changeKind: string }[];
|
|
13
13
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* @layer application
|
|
3
3
|
* @unit quick-mode
|
|
4
4
|
* @story H10-05
|
|
5
|
+
* @work-item-id WI-384
|
|
5
6
|
*
|
|
6
7
|
* paths から変更カテゴリを分類し fullModeRequired 判定と理由を返す UseCase
|
|
7
8
|
*/
|
|
@@ -20,6 +21,7 @@ export interface ClassifyChangeCategoryUseCaseInput {
|
|
|
20
21
|
readonly paths: readonly string[];
|
|
21
22
|
readonly targetChanges?: readonly {
|
|
22
23
|
readonly filePath: string;
|
|
24
|
+
readonly changeKind?: ChangeKind;
|
|
23
25
|
readonly beforeContent?: string | null;
|
|
24
26
|
readonly afterContent?: string | null;
|
|
25
27
|
}[];
|
|
@@ -94,7 +96,7 @@ export class ClassifyChangeCategoryUseCase {
|
|
|
94
96
|
// 変更前の内容が無く変更後の内容がある場合は新規作成 (CREATE) とみなす。
|
|
95
97
|
// 以前は無条件で MODIFY 固定だったため、新規 domain/ ファイルが
|
|
96
98
|
// NEW_DOMAIN 判定を回避して quick mode をすり抜けていた。
|
|
97
|
-
changeKind: beforeContent === null && afterContent !== null ? "CREATE" : "MODIFY",
|
|
99
|
+
changeKind: targetChange?.changeKind ?? (beforeContent === null && afterContent !== null ? "CREATE" : "MODIFY"),
|
|
98
100
|
beforeContent,
|
|
99
101
|
afterContent,
|
|
100
102
|
});
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* @work-item-id WI-349
|
|
6
6
|
* @work-item-id WI-352
|
|
7
7
|
* @work-item-id WI-372
|
|
8
|
+
* @work-item-id WI-390
|
|
8
9
|
*
|
|
9
10
|
* ChangedFile[]をChangeClassificationに変換し、3拒否ルールを評価してQuickModeEligibilityを返すドメインサービス
|
|
10
11
|
*/
|
|
@@ -92,6 +93,15 @@ function categorizeFileByBuiltInRules(file: ChangedFile): ChangeCategory {
|
|
|
92
93
|
return ChangeCategory.fromString("test");
|
|
93
94
|
}
|
|
94
95
|
|
|
96
|
+
// Markdown は配置場所にかかわらず文書として扱う。config / API / test の
|
|
97
|
+
// 明示ルールは優先しつつ、domain ディレクトリや CREATE フォールバックより
|
|
98
|
+
// 前に評価して README.md / *.mdx の新規作成を feature/domain に誤分類しない。
|
|
99
|
+
// 信頼境界となる root agent instructions は protected-file 側で別途保護する。
|
|
100
|
+
// @work-item-id WI-390
|
|
101
|
+
if (filePath.endsWith(".md") || filePath.endsWith(".mdx")) {
|
|
102
|
+
return ChangeCategory.fromString("docs");
|
|
103
|
+
}
|
|
104
|
+
|
|
95
105
|
// domain: domain/ 配下
|
|
96
106
|
if (filePath.includes("/domain/") || filePath.startsWith("domain/")) {
|
|
97
107
|
return ChangeCategory.fromString("domain");
|
|
@@ -202,7 +212,7 @@ export class QuickModeJudgmentEngine {
|
|
|
202
212
|
judge(changedFiles: readonly ChangedFile[], config: QuickModeConfig): QuickModeEligibility {
|
|
203
213
|
const classification = this.classify(changedFiles, config);
|
|
204
214
|
|
|
205
|
-
// 1.
|
|
215
|
+
// 1. カテゴリ評価: 不許可カテゴリを含む単一カテゴリ変更と、複数カテゴリ変更を区別する。
|
|
206
216
|
if (config.isFullModeRequiredFor("mixedCategories")) {
|
|
207
217
|
const notAllowedFiles: ChangedFile[] = [];
|
|
208
218
|
const notAllowedDescriptions: string[] = [];
|
|
@@ -216,8 +226,9 @@ export class QuickModeJudgmentEngine {
|
|
|
216
226
|
});
|
|
217
227
|
|
|
218
228
|
if (notAllowedFiles.length > 0) {
|
|
229
|
+
const rejectionRule = classification.categorizedFiles.size >= 2 ? "MIXED_CHANGES" : "CATEGORY_NOT_ALLOWED";
|
|
219
230
|
return QuickModeEligibility.rejected(
|
|
220
|
-
|
|
231
|
+
rejectionRule,
|
|
221
232
|
notAllowedFiles,
|
|
222
233
|
`allowedCategories外のファイルが含まれています: ${notAllowedDescriptions.join(", ")}`,
|
|
223
234
|
);
|
package/scripts/harness/regression-suite/infrastructure/adapters/vitest-test-runner-adapter.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
// @layer infrastructure
|
|
2
|
-
|
|
2
|
+
// @unit regression-suite
|
|
3
|
+
// @work-item-id WI-384
|
|
4
|
+
import { execFileSync } from 'node:child_process';
|
|
3
5
|
import { existsSync } from 'node:fs';
|
|
4
6
|
import { join } from 'node:path';
|
|
7
|
+
import { execPath } from 'node:process';
|
|
5
8
|
import { KRequirementTest } from '../../domain/value-objects/k-requirement-test.js';
|
|
6
9
|
import { GngConditionTest } from '../../domain/value-objects/gng-condition-test.js';
|
|
7
10
|
import { AgentIndependenceTest } from '../../domain/value-objects/agent-independence-test.js';
|
|
@@ -65,8 +68,15 @@ export class VitestTestRunnerAdapter implements TestRunnerPort {
|
|
|
65
68
|
|
|
66
69
|
const testPattern = hasUnitTests ? unitTestDir : unitIntegrationDir;
|
|
67
70
|
try {
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
execFileSync(
|
|
72
|
+
execPath,
|
|
73
|
+
[
|
|
74
|
+
'node_modules/vitest/vitest.mjs',
|
|
75
|
+
'run',
|
|
76
|
+
'--config',
|
|
77
|
+
'scripts/harness/__tests__/vitest.config.ts',
|
|
78
|
+
testPattern,
|
|
79
|
+
],
|
|
70
80
|
{ cwd: this.rootDir, stdio: 'pipe', timeout: 60_000 },
|
|
71
81
|
);
|
|
72
82
|
unitResults.set(unit, true);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"phasegate-gate": {
|
|
3
|
+
"PreToolUse": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "^(write_to_file|replace_file_content|multi_replace_file_content|run_command)$",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "npx phasegate hook pre-tool-use",
|
|
10
|
+
"timeout": 30
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -96,10 +96,10 @@ if command -v npx >/dev/null 2>&1; then
|
|
|
96
96
|
fi
|
|
97
97
|
fi
|
|
98
98
|
|
|
99
|
-
#
|
|
99
|
+
# PhaseGate lint check (uses the target project's PhaseGate/Biome configuration)
|
|
100
100
|
LINT_OUTPUT=""
|
|
101
101
|
if command -v npx >/dev/null 2>&1; then
|
|
102
|
-
LINT_RAW=$(npx
|
|
102
|
+
LINT_RAW=$(npx phasegate lint --json --skip-eslint-removal-check 2>&1)
|
|
103
103
|
if [ $? -ne 0 ] && [ -n "$LINT_RAW" ]; then
|
|
104
104
|
LINT_OUTPUT=$(echo "$LINT_RAW" | head -5)
|
|
105
105
|
fi
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"hooks": {
|
|
3
3
|
"PreToolUse": [
|
|
4
4
|
{
|
|
5
|
-
"matcher": "Bash",
|
|
5
|
+
"matcher": "Bash|apply_patch",
|
|
6
6
|
"hooks": [
|
|
7
7
|
{
|
|
8
8
|
"type": "command",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
12
|
"type": "command",
|
|
13
|
-
"command": "npx phasegate hook pre-tool-use"
|
|
13
|
+
"command": "npx phasegate hook pre-tool-use",
|
|
14
|
+
"timeout": 30
|
|
14
15
|
}
|
|
15
16
|
]
|
|
16
17
|
},
|
|
@@ -19,7 +20,8 @@
|
|
|
19
20
|
"hooks": [
|
|
20
21
|
{
|
|
21
22
|
"type": "command",
|
|
22
|
-
"command": "npx phasegate hook pre-tool-use"
|
|
23
|
+
"command": "npx phasegate hook pre-tool-use",
|
|
24
|
+
"timeout": 30
|
|
23
25
|
}
|
|
24
26
|
]
|
|
25
27
|
}
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
],
|
|
26
26
|
"PreToolUse": [
|
|
27
27
|
{
|
|
28
|
-
"matcher": "Bash",
|
|
28
|
+
"matcher": "Bash|apply_patch",
|
|
29
29
|
"hooks": [
|
|
30
30
|
{
|
|
31
31
|
"type": "command",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
],
|
|
38
38
|
"PostToolUse": [
|
|
39
39
|
{
|
|
40
|
-
"matcher": "Bash",
|
|
40
|
+
"matcher": "Bash|apply_patch",
|
|
41
41
|
"hooks": [
|
|
42
42
|
{
|
|
43
43
|
"type": "command",
|