codeloop-mcp-server 0.1.25 → 0.1.26
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/dist/evidence/interaction_coverage.d.ts +48 -0
- package/dist/evidence/interaction_coverage.d.ts.map +1 -1
- package/dist/evidence/interaction_coverage.js +277 -0
- package/dist/evidence/interaction_coverage.js.map +1 -1
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -1
- package/dist/tools/gate_check.d.ts.map +1 -1
- package/dist/tools/gate_check.js +38 -1
- package/dist/tools/gate_check.js.map +1 -1
- package/dist/tools/plan_user_journey.d.ts +106 -0
- package/dist/tools/plan_user_journey.d.ts.map +1 -0
- package/dist/tools/plan_user_journey.js +375 -0
- package/dist/tools/plan_user_journey.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* codeloop_plan_user_journey
|
|
3
|
+
*
|
|
4
|
+
* This is the missing layer between `codeloop_discover_interactions` (what
|
|
5
|
+
* controls exist) and `codeloop_start_recording` (drive the app). Without
|
|
6
|
+
* it, agents tend to type "abc" into one field, click one button, and call
|
|
7
|
+
* it a session — even when the underlying product is a CRUD app with
|
|
8
|
+
* domain entities the human user would actually CREATE, READ, UPDATE, and
|
|
9
|
+
* DELETE end-to-end.
|
|
10
|
+
*
|
|
11
|
+
* The journey planner reads:
|
|
12
|
+
* 1. The discover_interactions output (forms / buttons / inputs / AI).
|
|
13
|
+
* 2. The project's spec / acceptance / domain docs and source code for
|
|
14
|
+
* ENTITY NOUNS (Product, Component, Order, Project, …) and the
|
|
15
|
+
* USER ACTIONS the product supports (Add Product, Edit Order,
|
|
16
|
+
* Save Configuration, Delete Component, …).
|
|
17
|
+
* 3. Per-field LABEL + UNIT + neighbouring text → realistic example
|
|
18
|
+
* data the agent should type ("4000" for CCT in Kelvin, not "abc").
|
|
19
|
+
*
|
|
20
|
+
* Returns a structured plan the agent uses as its recording script:
|
|
21
|
+
*
|
|
22
|
+
* {
|
|
23
|
+
* entities: [
|
|
24
|
+
* {
|
|
25
|
+
* name: "Product",
|
|
26
|
+
* arc: [
|
|
27
|
+
* { step: "navigate", target: "Luminaires" },
|
|
28
|
+
* { step: "create", target: "Add Product", hint: "click the Add/New/+ button" },
|
|
29
|
+
* { step: "fill", fields: [{ label, example, unit, source_file }] },
|
|
30
|
+
* { step: "commit", target: "Save / Submit", hint: "look for Save/Submit/Apply button" },
|
|
31
|
+
* { step: "verify", target: "list shows Product 'XYZ'" },
|
|
32
|
+
* { step: "edit", target: "click the row to open" },
|
|
33
|
+
* { step: "commit", target: "Save" },
|
|
34
|
+
* { step: "delete", target: "Delete (confirm)" }
|
|
35
|
+
* ],
|
|
36
|
+
* priority: 1
|
|
37
|
+
* },
|
|
38
|
+
* …
|
|
39
|
+
* ],
|
|
40
|
+
* ai_journeys: [
|
|
41
|
+
* { feature: "Photometric prediction", prompt_examples: [...] }
|
|
42
|
+
* ],
|
|
43
|
+
* coverage_targets: {
|
|
44
|
+
* full_crud_arcs: 2, // at least 2 entities exercised top-to-bottom
|
|
45
|
+
* ai_substantive_prompts: 3,
|
|
46
|
+
* upload_actions: 1
|
|
47
|
+
* },
|
|
48
|
+
* advice: [ "do this in order", "fill with realistic values not 'test'", …]
|
|
49
|
+
* }
|
|
50
|
+
*/
|
|
51
|
+
export interface JourneyFieldHint {
|
|
52
|
+
label: string;
|
|
53
|
+
selector?: string;
|
|
54
|
+
example: string;
|
|
55
|
+
unit?: string;
|
|
56
|
+
min?: number;
|
|
57
|
+
max?: number;
|
|
58
|
+
source_file?: string;
|
|
59
|
+
line?: number;
|
|
60
|
+
}
|
|
61
|
+
export interface JourneyStep {
|
|
62
|
+
step: "navigate" | "create" | "fill" | "commit" | "verify" | "edit" | "delete" | "upload" | "ai_prompt";
|
|
63
|
+
target?: string;
|
|
64
|
+
fields?: JourneyFieldHint[];
|
|
65
|
+
hint?: string;
|
|
66
|
+
ai_prompt?: string;
|
|
67
|
+
}
|
|
68
|
+
export interface EntityJourney {
|
|
69
|
+
name: string;
|
|
70
|
+
arc: JourneyStep[];
|
|
71
|
+
priority: number;
|
|
72
|
+
source_files: string[];
|
|
73
|
+
}
|
|
74
|
+
export interface AIJourney {
|
|
75
|
+
feature: string;
|
|
76
|
+
prompt_examples: string[];
|
|
77
|
+
source_files: string[];
|
|
78
|
+
}
|
|
79
|
+
export interface UserJourneyPlan {
|
|
80
|
+
project_summary: string;
|
|
81
|
+
entities: EntityJourney[];
|
|
82
|
+
ai_journeys: AIJourney[];
|
|
83
|
+
coverage_targets: {
|
|
84
|
+
full_crud_arcs: number;
|
|
85
|
+
ai_substantive_prompts: number;
|
|
86
|
+
upload_actions: number;
|
|
87
|
+
datagrid_edits: number;
|
|
88
|
+
};
|
|
89
|
+
advice: string[];
|
|
90
|
+
discovered_interactions_summary: {
|
|
91
|
+
inputs: number;
|
|
92
|
+
submit_buttons: number;
|
|
93
|
+
datagrids: number;
|
|
94
|
+
upload_areas: number;
|
|
95
|
+
ai_features: number;
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
export declare function planUserJourney(projectDir: string, platform?: string, topN?: number): Promise<UserJourneyPlan>;
|
|
99
|
+
export declare function _internal_hintForLabel(label: string): {
|
|
100
|
+
example: string;
|
|
101
|
+
unit?: string;
|
|
102
|
+
min?: number;
|
|
103
|
+
max?: number;
|
|
104
|
+
};
|
|
105
|
+
export declare function _internal_toEntityNoun(s: string): string;
|
|
106
|
+
//# sourceMappingURL=plan_user_journey.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan_user_journey.d.ts","sourceRoot":"","sources":["../../src/tools/plan_user_journey.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EACA,UAAU,GACV,QAAQ,GACR,MAAM,GACN,QAAQ,GACR,QAAQ,GACR,MAAM,GACN,QAAQ,GACR,QAAQ,GACR,WAAW,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,WAAW,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,WAAW,EAAE,SAAS,EAAE,CAAC;IACzB,gBAAgB,EAAE;QAChB,cAAc,EAAE,MAAM,CAAC;QACvB,sBAAsB,EAAE,MAAM,CAAC;QAC/B,cAAc,EAAE,MAAM,CAAC;QACvB,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,+BAA+B,EAAE;QAC/B,MAAM,EAAE,MAAM,CAAC;QACf,cAAc,EAAE,MAAM,CAAC;QACvB,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAsOD,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,QAAQ,GAAE,MAAe,EACzB,IAAI,GAAE,MAAU,GACf,OAAO,CAAC,eAAe,CAAC,CAsI1B;AAqBD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM;aA7KH,MAAM;WAAS,MAAM;UAAQ,MAAM;UAAQ,MAAM;EA+KjG;AACD,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,MAAM,UAE/C"}
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync } from "fs";
|
|
2
|
+
import { join, basename, extname } from "path";
|
|
3
|
+
import { discoverInteractions, } from "./discover_interactions.js";
|
|
4
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
5
|
+
// Entity-noun extraction
|
|
6
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
7
|
+
/**
|
|
8
|
+
* Best-effort entity noun extraction. We look at:
|
|
9
|
+
* 1. Source-file names — class names ending in conceptual nouns
|
|
10
|
+
* (PhotometricDataView, ProductDesignBOMView → Product, BOM).
|
|
11
|
+
* 2. Button labels that start with "Add/New/Create" → the noun after.
|
|
12
|
+
* 3. spec.md / acceptance.md / docs that name entities directly.
|
|
13
|
+
* 4. JSON / YAML schema files for top-level type names.
|
|
14
|
+
*
|
|
15
|
+
* We don't try to be perfect — we pick the top-K nouns by frequency and
|
|
16
|
+
* let the agent's LLM contextualise them when it follows the plan.
|
|
17
|
+
*/
|
|
18
|
+
function extractEntityCandidates(projectDir, discovery) {
|
|
19
|
+
const candidates = new Map();
|
|
20
|
+
function bump(noun, score, source) {
|
|
21
|
+
const norm = noun.trim();
|
|
22
|
+
if (!norm)
|
|
23
|
+
return;
|
|
24
|
+
// Drop obvious non-entities (UI / dialog / view / panel / button …).
|
|
25
|
+
if (UI_NOUN_STOPLIST.has(norm.toLowerCase()))
|
|
26
|
+
return;
|
|
27
|
+
if (norm.length < 3)
|
|
28
|
+
return;
|
|
29
|
+
const existing = candidates.get(norm) ?? { score: 0, source_files: new Set() };
|
|
30
|
+
existing.score += score;
|
|
31
|
+
if (source)
|
|
32
|
+
existing.source_files.add(source);
|
|
33
|
+
candidates.set(norm, existing);
|
|
34
|
+
}
|
|
35
|
+
// 1. Add/New/Create button labels → noun after.
|
|
36
|
+
for (const el of discovery.elements) {
|
|
37
|
+
if (el.kind !== "button" && el.kind !== "submit_button")
|
|
38
|
+
continue;
|
|
39
|
+
const m = el.label.match(/^\s*(?:add|new|create|insert|register|enroll)\s+(?:a\s+|an\s+|the\s+)?(.+?)\s*$/i);
|
|
40
|
+
if (m)
|
|
41
|
+
bump(toEntityNoun(m[1]), 5, el.source_file);
|
|
42
|
+
}
|
|
43
|
+
// 2. View / Page / Form class names → noun before the suffix.
|
|
44
|
+
for (const el of discovery.elements) {
|
|
45
|
+
const fname = basename(el.source_file, extname(el.source_file));
|
|
46
|
+
const m = fname.match(/^(.+?)(View|Page|Form|Dialog|Window|Component)$/);
|
|
47
|
+
if (m)
|
|
48
|
+
bump(toEntityNoun(m[1]), 2, el.source_file);
|
|
49
|
+
}
|
|
50
|
+
// 3. Spec / acceptance / domain docs.
|
|
51
|
+
for (const docPath of findDocCandidates(projectDir)) {
|
|
52
|
+
let txt = "";
|
|
53
|
+
try {
|
|
54
|
+
txt = readFileSync(docPath, "utf-8");
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
// Heading nouns ("## Products", "### LED Engine") get a strong boost.
|
|
60
|
+
for (const m of txt.matchAll(/^#{1,4}\s+(.+?)\s*$/gm)) {
|
|
61
|
+
const heading = m[1].trim();
|
|
62
|
+
// Skip generic section headings.
|
|
63
|
+
if (/^(overview|summary|introduction|getting started|installation|setup|usage|notes|faq|changelog)$/i.test(heading))
|
|
64
|
+
continue;
|
|
65
|
+
// Take last word as the entity noun.
|
|
66
|
+
const last = heading.split(/\s+/).slice(-1)[0];
|
|
67
|
+
bump(toEntityNoun(last), 4, docPath);
|
|
68
|
+
}
|
|
69
|
+
// "Add a product / Create an order" patterns.
|
|
70
|
+
for (const m of txt.matchAll(/\b(?:add|create|new)\s+(?:a\s+|an\s+|the\s+)?([A-Z][a-zA-Z]{2,30})/g)) {
|
|
71
|
+
bump(toEntityNoun(m[1]), 1, docPath);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return candidates;
|
|
75
|
+
}
|
|
76
|
+
const UI_NOUN_STOPLIST = new Set([
|
|
77
|
+
"button", "view", "page", "form", "dialog", "window", "panel", "tab",
|
|
78
|
+
"modal", "popup", "toast", "menu", "list", "row", "card", "screen",
|
|
79
|
+
"navigation", "header", "footer", "sidebar", "field", "input", "control",
|
|
80
|
+
"widget", "section", "component", "container", "item", "icon", "image",
|
|
81
|
+
"data", "info", "details", "settings", "config", "preference", "option",
|
|
82
|
+
"user", "admin", "main", "default", "test", "sample", "demo", "example",
|
|
83
|
+
"the", "a", "an", "and", "or", "for", "with", "from", "to", "of",
|
|
84
|
+
"summary", "list", "table", "grid",
|
|
85
|
+
]);
|
|
86
|
+
/** Common domain acronyms we want to keep upper-cased even when the source typed them lower-case (`led_engines` → "LED Engine"). */
|
|
87
|
+
const ACRONYM_SET = new Set([
|
|
88
|
+
"LED", "PCB", "BOM", "AI", "ML", "API", "URL", "UI", "UX", "CCT", "CRI",
|
|
89
|
+
"SKU", "VAT", "GST", "IP", "DNS", "PDF", "CSV", "JSON", "XML", "HTML",
|
|
90
|
+
"USB", "HDMI", "CPU", "GPU", "RAM", "SSD", "OS", "QA", "QR", "AC", "DC",
|
|
91
|
+
]);
|
|
92
|
+
/** Singularise + TitleCase a phrase. "Products" → "Product"; "led engines" → "LED Engine". */
|
|
93
|
+
function toEntityNoun(raw) {
|
|
94
|
+
let s = raw.trim().replace(/[_-]+/g, " ");
|
|
95
|
+
// Split words, title-case each.
|
|
96
|
+
const words = s
|
|
97
|
+
.split(/\s+/)
|
|
98
|
+
.filter(Boolean)
|
|
99
|
+
.map((w) => {
|
|
100
|
+
// Preserve acronyms (LED, PCB, BOM, AI, …) regardless of input case.
|
|
101
|
+
const upper = w.toUpperCase();
|
|
102
|
+
if (ACRONYM_SET.has(upper))
|
|
103
|
+
return upper;
|
|
104
|
+
if (/^[A-Z]{2,6}$/.test(w))
|
|
105
|
+
return w;
|
|
106
|
+
// Convert camelCase to "Camel Case" tokens.
|
|
107
|
+
const split = w.replace(/([a-z])([A-Z])/g, "$1 $2").split(/\s+/);
|
|
108
|
+
return split
|
|
109
|
+
.map((p) => {
|
|
110
|
+
const up = p.toUpperCase();
|
|
111
|
+
if (ACRONYM_SET.has(up))
|
|
112
|
+
return up;
|
|
113
|
+
if (/^[A-Z]{2,6}$/.test(p))
|
|
114
|
+
return p;
|
|
115
|
+
return p[0].toUpperCase() + p.slice(1).toLowerCase();
|
|
116
|
+
})
|
|
117
|
+
.join(" ");
|
|
118
|
+
});
|
|
119
|
+
s = words.join(" ");
|
|
120
|
+
// Naive singularise on the last word (don't touch acronyms).
|
|
121
|
+
const parts = s.split(" ");
|
|
122
|
+
const last = parts[parts.length - 1];
|
|
123
|
+
if (!/^[A-Z]{2,6}$/.test(last)) {
|
|
124
|
+
if (last.endsWith("ies") && last.length > 3)
|
|
125
|
+
parts[parts.length - 1] = last.slice(0, -3) + "y";
|
|
126
|
+
else if (last.endsWith("ses") && last.length > 3)
|
|
127
|
+
parts[parts.length - 1] = last.slice(0, -2);
|
|
128
|
+
else if (last.endsWith("s") && !last.endsWith("ss") && last.length > 3)
|
|
129
|
+
parts[parts.length - 1] = last.slice(0, -1);
|
|
130
|
+
}
|
|
131
|
+
return parts.join(" ");
|
|
132
|
+
}
|
|
133
|
+
function findDocCandidates(projectDir) {
|
|
134
|
+
const out = [];
|
|
135
|
+
const candidates = [
|
|
136
|
+
"spec.md", "SPEC.md", "specification.md",
|
|
137
|
+
"acceptance.md", "ACCEPTANCE.md",
|
|
138
|
+
"README.md", "readme.md",
|
|
139
|
+
"docs/spec.md", "docs/SPEC.md", "docs/acceptance.md", "docs/ACCEPTANCE.md",
|
|
140
|
+
"docs/PRD.md", "docs/prd.md", "docs/requirements.md",
|
|
141
|
+
"docs/architecture.md", "docs/ARCHITECTURE.md",
|
|
142
|
+
"docs/user-guide.md", "docs/USER_GUIDE.md",
|
|
143
|
+
];
|
|
144
|
+
for (const rel of candidates) {
|
|
145
|
+
const abs = join(projectDir, rel);
|
|
146
|
+
if (existsSync(abs))
|
|
147
|
+
out.push(abs);
|
|
148
|
+
}
|
|
149
|
+
// Also scan docs/ for any .md (capped).
|
|
150
|
+
const docsDir = join(projectDir, "docs");
|
|
151
|
+
if (existsSync(docsDir)) {
|
|
152
|
+
try {
|
|
153
|
+
for (const f of readdirSync(docsDir, { withFileTypes: true })) {
|
|
154
|
+
if (f.isFile && f.isFile() && /\.md$/i.test(f.name)) {
|
|
155
|
+
const abs = join(docsDir, f.name);
|
|
156
|
+
if (!out.includes(abs))
|
|
157
|
+
out.push(abs);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch { /* best-effort */ }
|
|
162
|
+
if (out.length > 12)
|
|
163
|
+
out.length = 12;
|
|
164
|
+
}
|
|
165
|
+
return out;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Domain-agnostic data hints. The list is intentionally broad — it covers
|
|
169
|
+
* lighting / photometric units (CCT, CRI, lumen, beam angle), e-commerce
|
|
170
|
+
* (price, quantity), generic profile fields (name, email, phone), and
|
|
171
|
+
* everyday measurements (length, weight, temperature). The agent's LLM
|
|
172
|
+
* still adapts the value to context; these are just sane defaults so
|
|
173
|
+
* "Drive Current (mA)" doesn't end up with "test".
|
|
174
|
+
*/
|
|
175
|
+
const HINT_RULES = [
|
|
176
|
+
// Photometric / lighting
|
|
177
|
+
{ match: /\bcct\b|colou?r\s*temp/i, example: "4000", unit: "K", min: 1500, max: 12000 },
|
|
178
|
+
{ match: /\bcri\b|colou?r\s*rendering/i, example: "90", unit: "Ra", min: 0, max: 100 },
|
|
179
|
+
{ match: /\bdrive\s*current\b/i, example: "350", unit: "mA", min: 10, max: 5000 },
|
|
180
|
+
{ match: /\blumen\b|luminous\s*flux/i, example: "1200", unit: "lm", min: 1, max: 100000 },
|
|
181
|
+
{ match: /\befficacy\b/i, example: "120", unit: "lm/W" },
|
|
182
|
+
{ match: /\bbeam\s*angle\b/i, example: "24", unit: "°", min: 1, max: 360 },
|
|
183
|
+
{ match: /\bwattage\b|\bpower\b/i, example: "12", unit: "W", min: 0, max: 10000 },
|
|
184
|
+
{ match: /\bvoltage\b|\bvf\b/i, example: "12", unit: "V" },
|
|
185
|
+
{ match: /\bdiameter\b/i, example: "50", unit: "mm" },
|
|
186
|
+
{ match: /\bheight\b/i, example: "70", unit: "mm" },
|
|
187
|
+
// Profile / contact
|
|
188
|
+
{ match: /\b(first|given)\s*name\b/i, example: "Alex" },
|
|
189
|
+
{ match: /\b(last|family|surname)\s*name\b/i, example: "Taylor" },
|
|
190
|
+
{ match: /\bfull\s*name\b|^name$/i, example: "Alex Taylor" },
|
|
191
|
+
{ match: /\bemail\b/i, example: "test+codeloop@example.com" },
|
|
192
|
+
{ match: /\bphone\b|mobile\b/i, example: "+1 555 123 4567" },
|
|
193
|
+
{ match: /\bpassword\b/i, example: "CodeLoopTest!2026" },
|
|
194
|
+
{ match: /\baddress\b/i, example: "1 Test Way, Springfield" },
|
|
195
|
+
{ match: /\bcity\b/i, example: "Springfield" },
|
|
196
|
+
{ match: /\bcountry\b/i, example: "United Kingdom" },
|
|
197
|
+
{ match: /\bpostcode\b|\bzip\b/i, example: "SW1A 1AA" },
|
|
198
|
+
// Commerce
|
|
199
|
+
{ match: /\bprice\b|\bcost\b/i, example: "199.99", unit: "£", min: 0 },
|
|
200
|
+
{ match: /\bquantity\b|\bqty\b/i, example: "3", min: 1 },
|
|
201
|
+
{ match: /\bsku\b|product\s*code\b/i, example: "CL-TEST-001" },
|
|
202
|
+
{ match: /\b(description|notes?|comments?)\b/i, example: "Verified by CodeLoop end-to-end test." },
|
|
203
|
+
{ match: /\btitle\b/i, example: "CodeLoop test record" },
|
|
204
|
+
// Identifiers
|
|
205
|
+
{ match: /\bid\b$/i, example: "CL-001" },
|
|
206
|
+
{ match: /\b(serial|s\/?n)\b/i, example: "CL-SN-20260517-001" },
|
|
207
|
+
// Date / time
|
|
208
|
+
{ match: /\b(date|deadline|due)\b/i, example: "2026-12-31" },
|
|
209
|
+
{ match: /\btime\b/i, example: "14:30" },
|
|
210
|
+
// URLs / search
|
|
211
|
+
{ match: /\burl\b|website|link/i, example: "https://example.com" },
|
|
212
|
+
{ match: /\bsearch\b|query\b/i, example: "test" },
|
|
213
|
+
];
|
|
214
|
+
function hintForLabel(label) {
|
|
215
|
+
for (const rule of HINT_RULES) {
|
|
216
|
+
if (rule.match.test(label)) {
|
|
217
|
+
return { example: rule.example, unit: rule.unit, min: rule.min, max: rule.max };
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// Default: a short, human-looking placeholder.
|
|
221
|
+
return { example: "CodeLoop test value" };
|
|
222
|
+
}
|
|
223
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
224
|
+
// Plan synthesis
|
|
225
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
226
|
+
export async function planUserJourney(projectDir, platform = "auto", topN = 3) {
|
|
227
|
+
const discovery = await discoverInteractions(projectDir, platform);
|
|
228
|
+
const entityScores = extractEntityCandidates(projectDir, discovery);
|
|
229
|
+
// Take top-N by score; tie-break by name.
|
|
230
|
+
const ranked = [...entityScores.entries()]
|
|
231
|
+
.map(([name, v]) => ({ name, score: v.score, source_files: [...v.source_files] }))
|
|
232
|
+
.sort((a, b) => b.score - a.score || a.name.localeCompare(b.name))
|
|
233
|
+
.slice(0, Math.max(1, topN));
|
|
234
|
+
// Helper: pick the input fields likely to belong to entity X. We use a
|
|
235
|
+
// simple "file proximity" heuristic — inputs in the same file as a
|
|
236
|
+
// button labelled "Add <X>" or in a file whose name contains <X>.
|
|
237
|
+
function fieldsForEntity(name) {
|
|
238
|
+
const lower = name.toLowerCase().replace(/\s+/g, "");
|
|
239
|
+
const inputs = discovery.elements.filter((e) => e.kind === "input");
|
|
240
|
+
const matchedFiles = new Set();
|
|
241
|
+
for (const e of discovery.elements) {
|
|
242
|
+
if (e.kind === "button" || e.kind === "submit_button") {
|
|
243
|
+
if (e.label.toLowerCase().includes(name.toLowerCase()))
|
|
244
|
+
matchedFiles.add(e.source_file);
|
|
245
|
+
}
|
|
246
|
+
const fname = basename(e.source_file).toLowerCase().replace(/[\s_-]+/g, "");
|
|
247
|
+
if (fname.includes(lower))
|
|
248
|
+
matchedFiles.add(e.source_file);
|
|
249
|
+
}
|
|
250
|
+
const scoped = inputs.filter((i) => matchedFiles.has(i.source_file));
|
|
251
|
+
const chosen = (scoped.length > 0 ? scoped : inputs).slice(0, 6);
|
|
252
|
+
return chosen.map((c) => {
|
|
253
|
+
const hint = hintForLabel(c.label);
|
|
254
|
+
return {
|
|
255
|
+
label: c.label,
|
|
256
|
+
selector: c.selector,
|
|
257
|
+
example: hint.example,
|
|
258
|
+
unit: hint.unit,
|
|
259
|
+
min: hint.min,
|
|
260
|
+
max: hint.max,
|
|
261
|
+
source_file: c.source_file,
|
|
262
|
+
line: c.line,
|
|
263
|
+
};
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
function commitButtonFor(name) {
|
|
267
|
+
const lower = name.toLowerCase();
|
|
268
|
+
const buttons = discovery.elements.filter((e) => e.kind === "submit_button" || e.kind === "button");
|
|
269
|
+
// Prefer a button whose label mentions the entity (Save Product, Add Component).
|
|
270
|
+
const exact = buttons.find((b) => /\b(save|submit|create|add|update|apply)\b/i.test(b.label) &&
|
|
271
|
+
b.label.toLowerCase().includes(lower));
|
|
272
|
+
if (exact)
|
|
273
|
+
return exact.label;
|
|
274
|
+
const generic = buttons.find((b) => /\b(save|submit|create|add|update|apply)\b/i.test(b.label));
|
|
275
|
+
return generic ? generic.label : "Save / Submit";
|
|
276
|
+
}
|
|
277
|
+
const entities = ranked.map((r, idx) => ({
|
|
278
|
+
name: r.name,
|
|
279
|
+
priority: idx + 1,
|
|
280
|
+
source_files: r.source_files,
|
|
281
|
+
arc: [
|
|
282
|
+
{ step: "navigate", target: r.name, hint: `Open the section/page that lists ${r.name} records.` },
|
|
283
|
+
{ step: "create", target: `Add ${r.name}`, hint: `Click the Add/New/Create/+ control for ${r.name}.` },
|
|
284
|
+
{ step: "fill", fields: fieldsForEntity(r.name), hint: "Fill EVERY field with the suggested realistic example. Do not type 'abc' or 'test' in numeric / unit-bearing fields." },
|
|
285
|
+
{ step: "commit", target: commitButtonFor(r.name), hint: "Click the Save / Submit / Apply button." },
|
|
286
|
+
{ step: "verify", target: `${r.name} appears in the list / detail view`, hint: "Take a screenshot AFTER the commit; confirm the new record shows in the list or persisted view." },
|
|
287
|
+
{ step: "edit", target: `Open the just-created ${r.name}`, hint: "Re-open the record (click the row / drill in) and change at least one field." },
|
|
288
|
+
{ step: "commit", target: commitButtonFor(r.name), hint: "Save the edit." },
|
|
289
|
+
{ step: "verify", target: `Edited ${r.name} reflects the change`, hint: "Screenshot after save to confirm the edit persisted." },
|
|
290
|
+
{ step: "delete", target: `Delete ${r.name}`, hint: "Trigger delete + confirm the dialog. Don't leave test records behind." },
|
|
291
|
+
],
|
|
292
|
+
}));
|
|
293
|
+
// AI journeys — one per detected AI feature, with substantive prompts.
|
|
294
|
+
const aiJourneys = [];
|
|
295
|
+
if (discovery.ai_features_detected) {
|
|
296
|
+
const aiFiles = new Set();
|
|
297
|
+
for (const e of discovery.elements) {
|
|
298
|
+
if (e.kind === "ai_feature")
|
|
299
|
+
aiFiles.add(e.source_file);
|
|
300
|
+
}
|
|
301
|
+
aiJourneys.push({
|
|
302
|
+
feature: "Primary AI surface",
|
|
303
|
+
source_files: [...aiFiles].slice(0, 5),
|
|
304
|
+
prompt_examples: [
|
|
305
|
+
`Walk me through how this product handles ${ranked[0]?.name || "the main workflow"}. Be specific.`,
|
|
306
|
+
"What input fields are required to generate a complete dataset? Explain each unit.",
|
|
307
|
+
`Generate sample values for a new ${ranked[0]?.name || "record"} suitable for an end-to-end smoke test.`,
|
|
308
|
+
"What are the most common mistakes users make on this screen? List 3 and how to avoid each.",
|
|
309
|
+
"Predict the result if I increase the primary numeric input by 20%. Explain the trade-offs.",
|
|
310
|
+
],
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
// Coverage targets — informed by the discovery counts so the gate scales
|
|
314
|
+
// up for richer projects.
|
|
315
|
+
const inputs = discovery.counts.inputs;
|
|
316
|
+
const target = {
|
|
317
|
+
full_crud_arcs: Math.min(ranked.length, 2),
|
|
318
|
+
ai_substantive_prompts: discovery.ai_features_detected ? 3 : 0,
|
|
319
|
+
upload_actions: discovery.counts.upload_areas > 0 ? 1 : 0,
|
|
320
|
+
datagrid_edits: discovery.counts.datagrids > 0 ? 1 : 0,
|
|
321
|
+
};
|
|
322
|
+
const advice = [
|
|
323
|
+
`Drive ${target.full_crud_arcs} entity through a full CRUD arc (create → verify-persisted → edit → verify → delete). Don't stop after the create.`,
|
|
324
|
+
"Fill EVERY discovered input field with the suggested realistic example. Numeric / unit-bearing fields with placeholder text like 'test' or 'abc' are an automatic depth-gate failure.",
|
|
325
|
+
"After each commit, capture a screenshot AND read back the form state via win_ui_automate Value / browser_snapshot — the gate scores `verify_persisted` from those signals.",
|
|
326
|
+
"Use codeloop_interact win_ui_automate / browser_click — not raw osascript / PowerShell / xdotool. The interaction log is the gate's source of truth and only codeloop_interact writes it.",
|
|
327
|
+
"Run the entities in priority order. Lower-priority entities can be skipped if time-boxed but at least 1 entity MUST complete the full arc.",
|
|
328
|
+
];
|
|
329
|
+
if (discovery.ai_features_detected) {
|
|
330
|
+
advice.push(`Exercise the AI feature with at least ${target.ai_substantive_prompts} substantive prompts (>= 30 chars each) — toggling modes, multi-turn follow-ups, and one tool-routing test.`);
|
|
331
|
+
}
|
|
332
|
+
if (discovery.counts.upload_areas > 0) {
|
|
333
|
+
advice.push("At least one file-upload action via the drop zone or 'Choose Files' control.");
|
|
334
|
+
}
|
|
335
|
+
if (discovery.counts.datagrids > 0) {
|
|
336
|
+
advice.push("Edit at least one DataGrid cell, then verify the row reflects the change after committing.");
|
|
337
|
+
}
|
|
338
|
+
return {
|
|
339
|
+
project_summary: summariseProject(projectDir, ranked.map((r) => r.name), discovery),
|
|
340
|
+
entities,
|
|
341
|
+
ai_journeys: aiJourneys,
|
|
342
|
+
coverage_targets: target,
|
|
343
|
+
advice,
|
|
344
|
+
discovered_interactions_summary: {
|
|
345
|
+
inputs,
|
|
346
|
+
submit_buttons: discovery.counts.submit_buttons,
|
|
347
|
+
datagrids: discovery.counts.datagrids,
|
|
348
|
+
upload_areas: discovery.counts.upload_areas,
|
|
349
|
+
ai_features: discovery.counts.ai_features,
|
|
350
|
+
},
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
function summariseProject(projectDir, entities, discovery) {
|
|
354
|
+
let name = basename(projectDir);
|
|
355
|
+
// Prefer the package.json `name` if present.
|
|
356
|
+
try {
|
|
357
|
+
const pkgPath = join(projectDir, "package.json");
|
|
358
|
+
if (existsSync(pkgPath)) {
|
|
359
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
360
|
+
if (pkg.name)
|
|
361
|
+
name = pkg.name;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
catch { /* best-effort */ }
|
|
365
|
+
const aiBit = discovery.ai_features_detected ? "AI-assisted " : "";
|
|
366
|
+
return `${name} is a ${aiBit}${discovery.platform} project with ${discovery.counts.inputs} input fields, ${discovery.counts.submit_buttons} submit/save buttons${discovery.counts.datagrids ? `, ${discovery.counts.datagrids} datagrid(s)` : ""}${discovery.counts.upload_areas ? `, ${discovery.counts.upload_areas} upload zone(s)` : ""}. Top entities to exercise: ${entities.join(", ") || "(none detected — exercise the main forms by hand)"}.`;
|
|
367
|
+
}
|
|
368
|
+
// Re-export for tests.
|
|
369
|
+
export function _internal_hintForLabel(label) {
|
|
370
|
+
return hintForLabel(label);
|
|
371
|
+
}
|
|
372
|
+
export function _internal_toEntityNoun(s) {
|
|
373
|
+
return toEntityNoun(s);
|
|
374
|
+
}
|
|
375
|
+
//# sourceMappingURL=plan_user_journey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan_user_journey.js","sourceRoot":"","sources":["../../src/tools/plan_user_journey.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED