frontend-harness 0.1.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/AGENTS.md +48 -0
- package/CLAUDE.md +48 -0
- package/README.md +262 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +380 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/runtime/builtin-skills.d.ts +6 -0
- package/dist/runtime/builtin-skills.js +269 -0
- package/dist/runtime/builtin-skills.js.map +1 -0
- package/dist/runtime/clean.d.ts +11 -0
- package/dist/runtime/clean.js +85 -0
- package/dist/runtime/clean.js.map +1 -0
- package/dist/runtime/command-taxonomy.d.ts +12 -0
- package/dist/runtime/command-taxonomy.js +72 -0
- package/dist/runtime/command-taxonomy.js.map +1 -0
- package/dist/runtime/context.d.ts +71 -0
- package/dist/runtime/context.js +153 -0
- package/dist/runtime/context.js.map +1 -0
- package/dist/runtime/graph.d.ts +12 -0
- package/dist/runtime/graph.js +211 -0
- package/dist/runtime/graph.js.map +1 -0
- package/dist/runtime/knowledge.d.ts +48 -0
- package/dist/runtime/knowledge.js +383 -0
- package/dist/runtime/knowledge.js.map +1 -0
- package/dist/runtime/plan.d.ts +18 -0
- package/dist/runtime/plan.js +571 -0
- package/dist/runtime/plan.js.map +1 -0
- package/dist/runtime/policy-provenance.d.ts +17 -0
- package/dist/runtime/policy-provenance.js +195 -0
- package/dist/runtime/policy-provenance.js.map +1 -0
- package/dist/runtime/project-discovery.d.ts +17 -0
- package/dist/runtime/project-discovery.js +166 -0
- package/dist/runtime/project-discovery.js.map +1 -0
- package/dist/runtime/project-paths.d.ts +6 -0
- package/dist/runtime/project-paths.js +47 -0
- package/dist/runtime/project-paths.js.map +1 -0
- package/dist/runtime/protocol-init.d.ts +50 -0
- package/dist/runtime/protocol-init.js +256 -0
- package/dist/runtime/protocol-init.js.map +1 -0
- package/dist/runtime/repair-decision.d.ts +3 -0
- package/dist/runtime/repair-decision.js +195 -0
- package/dist/runtime/repair-decision.js.map +1 -0
- package/dist/runtime/repair-packet.d.ts +7 -0
- package/dist/runtime/repair-packet.js +159 -0
- package/dist/runtime/repair-packet.js.map +1 -0
- package/dist/runtime/skills.d.ts +19 -0
- package/dist/runtime/skills.js +230 -0
- package/dist/runtime/skills.js.map +1 -0
- package/dist/runtime/state-explain.d.ts +2 -0
- package/dist/runtime/state-explain.js +106 -0
- package/dist/runtime/state-explain.js.map +1 -0
- package/dist/runtime/state.d.ts +10 -0
- package/dist/runtime/state.js +237 -0
- package/dist/runtime/state.js.map +1 -0
- package/dist/runtime/units.d.ts +10 -0
- package/dist/runtime/units.js +181 -0
- package/dist/runtime/units.js.map +1 -0
- package/dist/runtime/verification-commands.d.ts +11 -0
- package/dist/runtime/verification-commands.js +89 -0
- package/dist/runtime/verification-commands.js.map +1 -0
- package/dist/runtime/verify.d.ts +7 -0
- package/dist/runtime/verify.js +192 -0
- package/dist/runtime/verify.js.map +1 -0
- package/dist/schemas/types.d.ts +244 -0
- package/dist/schemas/types.js +2 -0
- package/dist/schemas/types.js.map +1 -0
- package/dist/schemas/validation.d.ts +2 -0
- package/dist/schemas/validation.js +21 -0
- package/dist/schemas/validation.js.map +1 -0
- package/dist/storage/json.d.ts +5 -0
- package/dist/storage/json.js +24 -0
- package/dist/storage/json.js.map +1 -0
- package/dist/storage/paths.d.ts +3 -0
- package/dist/storage/paths.js +9 -0
- package/dist/storage/paths.js.map +1 -0
- package/docs/DIRECTION.md +67 -0
- package/package.json +35 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
export type HarnessStatus = "idle" | "planned" | "awaiting_agent_edit" | "verifying" | "passed" | "failed" | "blocked";
|
|
2
|
+
export type VerificationStatus = "not_run" | "not_configured" | "passed" | "failed" | "error";
|
|
3
|
+
export interface TaskUnderstanding {
|
|
4
|
+
intent: string;
|
|
5
|
+
scope: string;
|
|
6
|
+
constraints: string[];
|
|
7
|
+
frontendWorkflow?: FrontendWorkflowPolicy;
|
|
8
|
+
inputs?: {
|
|
9
|
+
prd?: string;
|
|
10
|
+
ui?: string;
|
|
11
|
+
agentDecision?: string;
|
|
12
|
+
};
|
|
13
|
+
reasoningMode?: "deterministic" | "agent_assisted";
|
|
14
|
+
policyProvenance?: PolicyProvenance;
|
|
15
|
+
agentDecision?: {
|
|
16
|
+
summary?: string | null;
|
|
17
|
+
artifactPath?: string | null;
|
|
18
|
+
contractVersion?: 1 | null;
|
|
19
|
+
intentSuggestion?: string | null;
|
|
20
|
+
constraintHints?: string[];
|
|
21
|
+
componentHints?: AgentDecisionComponentHint[];
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export type FrontendWorkflowKind = "ui_implementation" | "prd_knowledge" | "api_integration" | "frontend_test" | "bug_fix" | "requirement_change";
|
|
25
|
+
export interface FrontendWorkflowPolicy {
|
|
26
|
+
kind: FrontendWorkflowKind;
|
|
27
|
+
summary: string;
|
|
28
|
+
requiredKnowledgeActions: string[];
|
|
29
|
+
implementationConstraints: string[];
|
|
30
|
+
verificationFocus: string[];
|
|
31
|
+
}
|
|
32
|
+
export interface PolicyProvenance {
|
|
33
|
+
selectedSkills: string[];
|
|
34
|
+
skillPaths: string[];
|
|
35
|
+
skillRoutes: SkillRouteCandidate[];
|
|
36
|
+
knowledgeReferences: string[];
|
|
37
|
+
knowledgeSha256: Record<string, string>;
|
|
38
|
+
selectionReason: string;
|
|
39
|
+
}
|
|
40
|
+
export interface SkillRouteCandidate {
|
|
41
|
+
name: string;
|
|
42
|
+
path: string;
|
|
43
|
+
score: number;
|
|
44
|
+
source: "metadata" | "workflow" | "keyword";
|
|
45
|
+
reasons: string[];
|
|
46
|
+
}
|
|
47
|
+
export interface AgentDecisionComponentHint {
|
|
48
|
+
name?: string;
|
|
49
|
+
responsibility?: string;
|
|
50
|
+
}
|
|
51
|
+
export interface AgentPlanningDecision {
|
|
52
|
+
contractVersion?: 1;
|
|
53
|
+
intentSuggestion?: string;
|
|
54
|
+
constraintHints?: string[];
|
|
55
|
+
componentHints?: AgentDecisionComponentHint[];
|
|
56
|
+
}
|
|
57
|
+
export interface AgentPlanningDecisionEnvelope {
|
|
58
|
+
contractVersion: 1;
|
|
59
|
+
decision: AgentPlanningDecision;
|
|
60
|
+
}
|
|
61
|
+
export interface AgentDecisionCheckResult {
|
|
62
|
+
status: "passed" | "failed";
|
|
63
|
+
artifactPath: string;
|
|
64
|
+
contractVersion: 1 | null;
|
|
65
|
+
decision: AgentPlanningDecision | null;
|
|
66
|
+
errors: string[];
|
|
67
|
+
}
|
|
68
|
+
export interface PlanningDecisionSummary {
|
|
69
|
+
artifactPath: string | null;
|
|
70
|
+
contractVersion: 1 | null;
|
|
71
|
+
intentSuggestion: string | null;
|
|
72
|
+
constraintHints: string[];
|
|
73
|
+
componentHints: AgentDecisionComponentHint[];
|
|
74
|
+
}
|
|
75
|
+
export interface ComponentItem {
|
|
76
|
+
name: string;
|
|
77
|
+
file: string;
|
|
78
|
+
responsibility: string;
|
|
79
|
+
status: "new" | "existing" | "unknown";
|
|
80
|
+
}
|
|
81
|
+
export interface ExecutionUnit {
|
|
82
|
+
id: string;
|
|
83
|
+
file: string;
|
|
84
|
+
task: string;
|
|
85
|
+
verification: string[];
|
|
86
|
+
dependsOn: string[];
|
|
87
|
+
parallelGroup: string | null;
|
|
88
|
+
}
|
|
89
|
+
export type ExecutionGuidanceAction = "inspect_plan" | "edit_files" | "record_changes" | "verify" | "fix_failed_verification";
|
|
90
|
+
export interface ExecutionGuidanceStep {
|
|
91
|
+
order: number;
|
|
92
|
+
action: ExecutionGuidanceAction;
|
|
93
|
+
description: string;
|
|
94
|
+
command: string | null;
|
|
95
|
+
condition: string | null;
|
|
96
|
+
}
|
|
97
|
+
export type StateNextAction = "plan" | "edit" | "verify" | "fix" | "configure_verification" | "done" | "blocked";
|
|
98
|
+
export interface StateNextResult {
|
|
99
|
+
action: StateNextAction;
|
|
100
|
+
reason: string;
|
|
101
|
+
command: string | null;
|
|
102
|
+
stateStatus: HarnessStatus;
|
|
103
|
+
verificationStatus: VerificationStatus;
|
|
104
|
+
changedFiles: string[];
|
|
105
|
+
guidance: string[];
|
|
106
|
+
artifacts: string[];
|
|
107
|
+
checks: string[];
|
|
108
|
+
stopCondition: string;
|
|
109
|
+
}
|
|
110
|
+
export interface StateExplainResult {
|
|
111
|
+
contractVersion: 1;
|
|
112
|
+
createdAt: string;
|
|
113
|
+
nextAction: StateNextResult;
|
|
114
|
+
summary: string;
|
|
115
|
+
rationale: string[];
|
|
116
|
+
requiredArtifacts: string[];
|
|
117
|
+
repairPacket: {
|
|
118
|
+
path: string;
|
|
119
|
+
markdownPath: string;
|
|
120
|
+
available: boolean;
|
|
121
|
+
};
|
|
122
|
+
repairDecision: {
|
|
123
|
+
path: string;
|
|
124
|
+
available: boolean;
|
|
125
|
+
sourceArtifactPath: string | null;
|
|
126
|
+
repairPacketArtifactPath: string | null;
|
|
127
|
+
repairPacketSha256: string | null;
|
|
128
|
+
verificationArtifactPath: string | null;
|
|
129
|
+
verificationSha256: string | null;
|
|
130
|
+
};
|
|
131
|
+
recommendedCommands: string[];
|
|
132
|
+
stopCondition: string;
|
|
133
|
+
}
|
|
134
|
+
export interface ComponentGraphNode {
|
|
135
|
+
id: string;
|
|
136
|
+
component: string;
|
|
137
|
+
file: string;
|
|
138
|
+
executionUnitId: string;
|
|
139
|
+
}
|
|
140
|
+
export interface ComponentGraphEdge {
|
|
141
|
+
from: string;
|
|
142
|
+
to: string;
|
|
143
|
+
type: "depends_on";
|
|
144
|
+
source: "execution_unit_depends_on";
|
|
145
|
+
}
|
|
146
|
+
export interface ComponentGraphArtifact {
|
|
147
|
+
nodes: ComponentGraphNode[];
|
|
148
|
+
edges: ComponentGraphEdge[];
|
|
149
|
+
}
|
|
150
|
+
export interface HarnessState {
|
|
151
|
+
version: 1;
|
|
152
|
+
status: HarnessStatus;
|
|
153
|
+
task: TaskUnderstanding | null;
|
|
154
|
+
components: ComponentItem[];
|
|
155
|
+
units: ExecutionUnit[];
|
|
156
|
+
changedFiles: string[];
|
|
157
|
+
verification: {
|
|
158
|
+
status: VerificationStatus;
|
|
159
|
+
latestResultPath: string | null;
|
|
160
|
+
};
|
|
161
|
+
errors: string[];
|
|
162
|
+
retryCount: number;
|
|
163
|
+
blockers: string[];
|
|
164
|
+
updatedAt: string;
|
|
165
|
+
}
|
|
166
|
+
export interface VerificationCommandResult {
|
|
167
|
+
name: string;
|
|
168
|
+
command: string | null;
|
|
169
|
+
source: "flag" | "config" | "package" | "none";
|
|
170
|
+
status: VerificationStatus;
|
|
171
|
+
exitCode: number | null;
|
|
172
|
+
durationMs: number;
|
|
173
|
+
logPath: string | null;
|
|
174
|
+
}
|
|
175
|
+
export interface VerificationResult {
|
|
176
|
+
status: VerificationStatus;
|
|
177
|
+
results: VerificationCommandResult[];
|
|
178
|
+
retryGuidance: null | {
|
|
179
|
+
summary: string;
|
|
180
|
+
failedCommands: string[];
|
|
181
|
+
logs: string[];
|
|
182
|
+
nextAgentInstruction: string;
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
export interface RepairPacketArtifact {
|
|
186
|
+
contractVersion: 1;
|
|
187
|
+
createdAt: string;
|
|
188
|
+
status: "ready" | "not_applicable";
|
|
189
|
+
stateStatus: HarnessStatus;
|
|
190
|
+
verificationStatus: VerificationStatus;
|
|
191
|
+
nextAction: StateNextResult;
|
|
192
|
+
artifacts: {
|
|
193
|
+
verification: string;
|
|
194
|
+
repairPacket: string;
|
|
195
|
+
repairPacketMarkdown: string;
|
|
196
|
+
};
|
|
197
|
+
changedFiles: string[];
|
|
198
|
+
failedCommands: Array<{
|
|
199
|
+
name: string;
|
|
200
|
+
command: string | null;
|
|
201
|
+
status: VerificationStatus;
|
|
202
|
+
exitCode: number | null;
|
|
203
|
+
logPath: string | null;
|
|
204
|
+
logExcerpt: string | null;
|
|
205
|
+
logSha256: string | null;
|
|
206
|
+
logSizeBytes: number | null;
|
|
207
|
+
excerptStartByte: number | null;
|
|
208
|
+
excerptEndByte: number | null;
|
|
209
|
+
excerptTruncated: boolean;
|
|
210
|
+
}>;
|
|
211
|
+
retryGuidance: VerificationResult["retryGuidance"];
|
|
212
|
+
instructions: string[];
|
|
213
|
+
}
|
|
214
|
+
export interface RepairDecision {
|
|
215
|
+
intent: string;
|
|
216
|
+
hypothesis: string;
|
|
217
|
+
targetFiles: string[];
|
|
218
|
+
verificationFocus: string[];
|
|
219
|
+
}
|
|
220
|
+
export interface RepairDecisionEnvelope {
|
|
221
|
+
contractVersion: 1;
|
|
222
|
+
decision: RepairDecision;
|
|
223
|
+
}
|
|
224
|
+
export interface RepairDecisionCheckResult {
|
|
225
|
+
status: "passed" | "failed";
|
|
226
|
+
artifactPath: string;
|
|
227
|
+
acceptedArtifactPath: string | null;
|
|
228
|
+
contractVersion: 1 | null;
|
|
229
|
+
decision: RepairDecision | null;
|
|
230
|
+
errors: string[];
|
|
231
|
+
}
|
|
232
|
+
export interface RepairDecisionSummary {
|
|
233
|
+
artifactPath: string;
|
|
234
|
+
sourceArtifactPath: string;
|
|
235
|
+
repairPacketArtifactPath: string | null;
|
|
236
|
+
repairPacketSha256: string | null;
|
|
237
|
+
verificationArtifactPath: string | null;
|
|
238
|
+
verificationSha256: string | null;
|
|
239
|
+
contractVersion: 1;
|
|
240
|
+
intent: string;
|
|
241
|
+
hypothesis: string;
|
|
242
|
+
targetFiles: string[];
|
|
243
|
+
verificationFocus: string[];
|
|
244
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/schemas/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function isHarnessState(value) {
|
|
2
|
+
if (!isRecord(value)) {
|
|
3
|
+
return false;
|
|
4
|
+
}
|
|
5
|
+
const verification = value["verification"];
|
|
6
|
+
return value["version"] === 1
|
|
7
|
+
&& typeof value["status"] === "string"
|
|
8
|
+
&& Array.isArray(value["components"])
|
|
9
|
+
&& Array.isArray(value["units"])
|
|
10
|
+
&& Array.isArray(value["changedFiles"])
|
|
11
|
+
&& isRecord(verification)
|
|
12
|
+
&& typeof verification["status"] === "string"
|
|
13
|
+
&& Array.isArray(value["errors"])
|
|
14
|
+
&& typeof value["retryCount"] === "number"
|
|
15
|
+
&& Array.isArray(value["blockers"])
|
|
16
|
+
&& typeof value["updatedAt"] === "string";
|
|
17
|
+
}
|
|
18
|
+
function isRecord(value) {
|
|
19
|
+
return typeof value === "object" && value !== null;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/schemas/validation.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,YAAY,GAAG,KAAK,CAAC,cAAc,CAAC,CAAC;IAC3C,OAAO,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC;WACxB,OAAO,KAAK,CAAC,QAAQ,CAAC,KAAK,QAAQ;WACnC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;WAClC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;WAC7B,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;WACpC,QAAQ,CAAC,YAAY,CAAC;WACtB,OAAO,YAAY,CAAC,QAAQ,CAAC,KAAK,QAAQ;WAC1C,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;WAC9B,OAAO,KAAK,CAAC,YAAY,CAAC,KAAK,QAAQ;WACvC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;WAChC,OAAO,KAAK,CAAC,WAAW,CAAC,KAAK,QAAQ,CAAC;AAC9C,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;AACrD,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function ensureDir(dir: string): void;
|
|
2
|
+
export declare function writeJson(filePath: string, value: unknown): void;
|
|
3
|
+
export declare function writeJsonExclusive(filePath: string, value: unknown): void;
|
|
4
|
+
export declare function readJson<T>(filePath: string): T | null;
|
|
5
|
+
export declare function writeText(filePath: string, value: string): void;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
export function ensureDir(dir) {
|
|
4
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
5
|
+
}
|
|
6
|
+
export function writeJson(filePath, value) {
|
|
7
|
+
ensureDir(path.dirname(filePath));
|
|
8
|
+
fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
9
|
+
}
|
|
10
|
+
export function writeJsonExclusive(filePath, value) {
|
|
11
|
+
ensureDir(path.dirname(filePath));
|
|
12
|
+
fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, { encoding: "utf8", flag: "wx" });
|
|
13
|
+
}
|
|
14
|
+
export function readJson(filePath) {
|
|
15
|
+
if (!fs.existsSync(filePath)) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
19
|
+
}
|
|
20
|
+
export function writeText(filePath, value) {
|
|
21
|
+
ensureDir(path.dirname(filePath));
|
|
22
|
+
fs.writeFileSync(filePath, value, "utf8");
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/storage/json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,QAAgB,EAAE,KAAc;IACxD,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAClC,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,QAAgB,EAAE,KAAc;IACjE,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAClC,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AACtG,CAAC;AAED,MAAM,UAAU,QAAQ,CAAI,QAAgB;IAC1C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAM,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,QAAgB,EAAE,KAAa;IACvD,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAClC,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
export const HARNESS_DIR = ".frontend-harness";
|
|
3
|
+
export function harnessPath(projectRoot, ...parts) {
|
|
4
|
+
return path.join(projectRoot, HARNESS_DIR, ...parts);
|
|
5
|
+
}
|
|
6
|
+
export function relativeHarnessPath(...parts) {
|
|
7
|
+
return path.posix.join(HARNESS_DIR, ...parts);
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/storage/paths.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,CAAC,MAAM,WAAW,GAAG,mBAAmB,CAAC;AAE/C,MAAM,UAAU,WAAW,CAAC,WAAmB,EAAE,GAAG,KAAe;IACjE,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,GAAG,KAAe;IACpD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frontend-harness Direction
|
|
2
|
+
|
|
3
|
+
`frontend-harness` is a project-level Execution Policy Layer for frontend AI-assisted development.
|
|
4
|
+
|
|
5
|
+
The package should make Codex and Claude Code more predictable inside a frontend repository without replacing their runtime capabilities.
|
|
6
|
+
|
|
7
|
+
## Product Surface
|
|
8
|
+
|
|
9
|
+
The primary product surface is protocol injection:
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
npm install frontend-harness --save-dev
|
|
13
|
+
npx frontend-harness init
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
After that, team members work normally in Codex or Claude Code. The injected `AGENTS.md` and `CLAUDE.md` protocol tells the agent to use the harness loop.
|
|
17
|
+
|
|
18
|
+
## Policy Loop
|
|
19
|
+
|
|
20
|
+
The stable loop is:
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
context -> plan -> implement -> record-change -> verify -> repair -> done
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The CLI should keep these steps deterministic and evidence-backed.
|
|
27
|
+
|
|
28
|
+
`plan --json` should classify the frontend workflow before implementation. The first stable workflow policy classes are:
|
|
29
|
+
|
|
30
|
+
- `ui_implementation`: hand-written UI or generated UI adaptation from MCP/Stitch/Figma/HTML.
|
|
31
|
+
- `prd_knowledge`: PRD digestion into durable project knowledge.
|
|
32
|
+
- `api_integration`: Swagger/API-backed frontend data integration.
|
|
33
|
+
- `frontend_test`: E2E or integration testing.
|
|
34
|
+
- `bug_fix`: scoped bug repair with regression evidence.
|
|
35
|
+
- `requirement_change`: implementation plus knowledge/test synchronization for changed requirements.
|
|
36
|
+
|
|
37
|
+
These classes are policy metadata, not skill routing and not runtime scheduling.
|
|
38
|
+
|
|
39
|
+
## Boundaries
|
|
40
|
+
|
|
41
|
+
`frontend-harness` owns:
|
|
42
|
+
|
|
43
|
+
- project context isolation
|
|
44
|
+
- frontend workflow protocol
|
|
45
|
+
- verification standards
|
|
46
|
+
- state continuity
|
|
47
|
+
- repair evidence
|
|
48
|
+
- project-local knowledge and skills
|
|
49
|
+
|
|
50
|
+
Codex and Claude Code own:
|
|
51
|
+
|
|
52
|
+
- agent loop
|
|
53
|
+
- tool execution
|
|
54
|
+
- permissions
|
|
55
|
+
- retries
|
|
56
|
+
- subagents
|
|
57
|
+
- skill loading
|
|
58
|
+
- runtime orchestration
|
|
59
|
+
|
|
60
|
+
## Directional Decisions
|
|
61
|
+
|
|
62
|
+
- Human-facing commands stay minimal: `init` and `protocol check`.
|
|
63
|
+
- Agent-facing commands stay stable: `context`, `plan`, `state record-change`, `verify`, `repair packet`, and `state next`.
|
|
64
|
+
- Low-level launcher lifecycle commands are removed from the product direction.
|
|
65
|
+
- Phase planning documents are no longer the product documentation model.
|
|
66
|
+
- README is the product entry point.
|
|
67
|
+
- This direction document is the durable project compass.
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "frontend-harness",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist",
|
|
7
|
+
"docs",
|
|
8
|
+
"AGENTS.md",
|
|
9
|
+
"CLAUDE.md",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
12
|
+
"bin": {
|
|
13
|
+
"frontend-harness": "./dist/cli/index.js"
|
|
14
|
+
},
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=20"
|
|
17
|
+
},
|
|
18
|
+
"exports": {
|
|
19
|
+
".": "./dist/cli/index.js"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"clean": "rm -rf dist",
|
|
23
|
+
"build": "npm run clean && tsc",
|
|
24
|
+
"harness": "node dist/cli/index.js",
|
|
25
|
+
"prepare": "npm run build",
|
|
26
|
+
"smoke:phase9": "node scripts/smoke-phase9.mjs",
|
|
27
|
+
"verify": "npm test && npm run typecheck && npm run build && npm run smoke:phase9",
|
|
28
|
+
"typecheck": "tsc --noEmit",
|
|
29
|
+
"test": "npm run build && node --test tests/*.test.mjs"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^22.10.0",
|
|
33
|
+
"typescript": "^5.7.0"
|
|
34
|
+
}
|
|
35
|
+
}
|